chore(8.0): final pre-RC1 sweep — API consistency, named errors, orphans, zero-cast codebase

This commit is contained in:
David Snelling 2026-06-11 14:51:00 -07:00
parent 970e08c466
commit 1f7e365a4e
237 changed files with 1951 additions and 49413 deletions

View file

@ -52,7 +52,7 @@ import type {
Entity,
FindParams,
GetOptions,
GetRelationsParams,
RelatedParams,
Relation,
Result
} from '../types/brainy.types.js'
@ -61,6 +61,7 @@ import {
splitVerbMetadataRecord
} from '../types/reservedFields.js'
import { v4 as uuidv4 } from '../universal/uuid.js'
import { EntityNotFoundError } from '../errors/notFound.js'
import { SpeculativeOverlayError } from './errors.js'
import type { GenerationStore } from './generationStore.js'
import type { ChangedIds, TransactReceipt, TxOperation } from './types.js'
@ -76,8 +77,8 @@ import { entityMatchesFind, resolveEntityField, UnsupportedWhereOperatorError }
export interface HistoricalQueryHandle<T = any> {
/** Full `find()` surface (vector/semantic/graph/cursor/aggregate) at the pinned generation. */
find(query: string | FindParams<T>): Promise<Result<T>[]>
/** Full `getRelations()` surface (including cursor pagination) at the pinned generation. */
getRelations(paramsOrId?: string | GetRelationsParams): Promise<Relation<T>[]>
/** Full `related()` surface (including cursor pagination) at the pinned generation. */
related(paramsOrId?: string | RelatedParams): Promise<Relation<T>[]>
/** Free the materialized indexes (closes the ephemeral reader). Idempotent. */
close(): Promise<void>
}
@ -108,8 +109,8 @@ export interface DbHost<T = any> {
get(id: string, options?: GetOptions): Promise<Entity<T> | null>
/** Live `brain.find()` (current-generation fast path). */
find(query: string | FindParams<T>): Promise<Result<T>[]>
/** Live `brain.getRelations()` (current-generation fast path). */
getRelations(paramsOrId?: string | GetRelationsParams): Promise<Relation<T>[]>
/** Live `brain.related()` (current-generation fast path). */
related(paramsOrId?: string | RelatedParams): Promise<Relation<T>[]>
/** Materialize an entity from a generation record's raw stored objects. */
entityFromRecord(
id: string,
@ -410,7 +411,7 @@ export class Db<T = any> {
/**
* @description Relationships **as of this view's generation** the `Db`
* counterpart of `brain.getRelations()` (same string-id shorthand and
* counterpart of `brain.related()` (same string-id shorthand and
* filter surface). Relations whose edges changed after the pin are
* resolved from generation records; overlay relations (speculative
* `relate`/`unrelate`) and cascade tombstones (relations touching a
@ -420,18 +421,18 @@ export class Db<T = any> {
* speculative overlay it throws {@link SpeculativeOverlayError}.
*
* @param paramsOrId - An entity id (shorthand for `{ from: id }`) or a
* `GetRelationsParams` filter object.
* `RelatedParams` filter object.
* @returns Relations as of this generation.
*/
async related(paramsOrId?: string | GetRelationsParams): Promise<Relation<T>[]> {
async related(paramsOrId?: string | RelatedParams): Promise<Relation<T>[]> {
this.assertUsable('related')
const params: GetRelationsParams =
const params: RelatedParams =
typeof paramsOrId === 'string' ? { from: paramsOrId } : (paramsOrId ?? {})
const historical = this.isHistorical()
if (!historical && !this.overlay) {
return this.host.getRelations(paramsOrId)
return this.host.related(paramsOrId)
}
if (params.cursor !== undefined) {
@ -439,7 +440,7 @@ export class Db<T = any> {
throw new SpeculativeOverlayError('cursor pagination on related()', this.gen)
}
const materialized = await this.materialize()
return materialized.getRelations(params)
return materialized.related(params)
}
const limit = params.limit ?? 100
@ -451,7 +452,7 @@ export class Db<T = any> {
const overlayVerbs = this.overlay?.verbs ?? new Map<string, Relation<T> | null>()
const excluded = new Set<string>([...changedVerbs, ...overlayVerbs.keys()])
const base = await this.host.getRelations({
const base = await this.host.related({
...params,
limit: limit + offset + excluded.size,
offset: 0
@ -480,7 +481,7 @@ export class Db<T = any> {
// Cascade semantics for speculative deletes: a relation whose endpoint
// is tombstoned in the overlay is gone in this view, exactly as
// brain.delete() cascades on the durable path.
// brain.remove() cascades on the durable path.
if (this.overlay) {
const tombstoned = new Set<string>()
for (const [id, entity] of this.overlay.nouns) {
@ -524,8 +525,8 @@ export class Db<T = any> {
*
* @param ops - The same declarative operations `brain.transact()` accepts.
* @returns A new speculative `Db` over this view.
* @throws Error when an operation references a missing entity/relation,
* mirroring the durable path's planning errors.
* @throws EntityNotFoundError when an operation references a missing
* entity, mirroring the durable path's planning errors.
*/
async with(ops: TxOperation<T>[]): Promise<Db<T>> {
this.assertUsable('with')
@ -587,7 +588,10 @@ export class Db<T = any> {
case 'update': {
const base = await speculativeGet(op.id)
if (!base) {
throw new Error(`with(): entity ${op.id} not found at generation ${this.gen}`)
throw new EntityNotFoundError(
op.id,
`with(): entity ${op.id} not found at generation ${this.gen}`
)
}
// Same reserved-field normalization as the committed update path.
const { reserved, custom } = splitNounMetadataRecord(
@ -631,8 +635,12 @@ export class Db<T = any> {
case 'relate': {
const from = await speculativeGet(op.from)
const to = await speculativeGet(op.to)
if (!from) throw new Error(`with(): source entity ${op.from} not found`)
if (!to) throw new Error(`with(): target entity ${op.to} not found`)
if (!from) {
throw new EntityNotFoundError(op.from, `with(): source entity ${op.from} not found`)
}
if (!to) {
throw new EntityNotFoundError(op.to, `with(): target entity ${op.to} not found`)
}
// Dedupe against the view (overlay first, then the edges visible
// at this generation via the record layer) — mirror of relate().
@ -934,11 +942,11 @@ function sortResultsBy<T>(results: Result<T>[], orderBy: string, order: 'asc' |
}
/**
* @description Filter one relation against `GetRelationsParams`, mirroring
* the storage-level filter `brain.getRelations()` builds (`from` sourceId,
* @description Filter one relation against `RelatedParams`, mirroring
* the storage-level filter `brain.related()` builds (`from` sourceId,
* `to` targetId, type/subtype set membership, service equality).
*/
function relationMatchesParams<T>(relation: Relation<T>, params: GetRelationsParams): boolean {
function relationMatchesParams<T>(relation: Relation<T>, params: RelatedParams): boolean {
if (params.from !== undefined && relation.from !== params.from) return false
if (params.to !== undefined && relation.to !== params.to) return false
if (params.type !== undefined) {

View file

@ -53,14 +53,14 @@ export interface TxUpdateOperation<T = any> extends UpdateParams<T> {
}
/**
* @description Delete an entity (and, exactly like `brain.delete()`, every
* @description Remove an entity (and, exactly like `brain.remove()`, every
* relationship where it is source or target the cascade is part of the
* same atomic batch).
*/
export interface TxRemoveOperation {
/** Discriminator. */
op: 'remove'
/** Id of the entity to delete. */
/** Id of the entity to remove. */
id: string
}