fix(find): the projection seam is ES-private, and document the projection
TypeScript's `private` is compile-time only, so the seam's helpers were real prototype methods and the generated contract manifest listed them as public DOORS — which would have obliged every other engine to implement an internal detail. They are `#`-private now and the manifest is unchanged by this branch. Found while checking that: docs/api-contract.json was ALREADY stale at v10.4.11 — promoteQueuedFlush and startFlushLeader are in src and absent from the manifest, so they leaked the same way and were never re-emitted. Left alone here rather than folded into this branch; it is someone's to fix deliberately, and the fix is the same # conversion. docs/FIND_SYSTEM.md gains the projection: the rules, why a missing field is absent rather than an error, where the values come from and what a field the column cannot serve costs.
This commit is contained in:
parent
ad0f493f7a
commit
be77a10bfe
3 changed files with 117 additions and 29 deletions
|
|
@ -4199,7 +4199,7 @@ export class Brainy<T = any> implements BrainyInterface<T> {
|
|||
// construction: a projection returns the named fields, and a vector is not
|
||||
// one of them unless it was named.
|
||||
if (options?.fields !== undefined && options.fields.length > 0) {
|
||||
const page = await this.hydratePage([id], options.fields)
|
||||
const page = await this.#hydratePage([id], options.fields)
|
||||
return page.get(id) ?? null
|
||||
}
|
||||
|
||||
|
|
@ -4294,7 +4294,7 @@ export class Brainy<T = any> implements BrainyInterface<T> {
|
|||
* @param params - The find params.
|
||||
* @returns Index keys to carry through hydration.
|
||||
*/
|
||||
private guardFieldsFor(params: FindParams<T>): string[] {
|
||||
#guardFieldsFor(params: FindParams<T>): string[] {
|
||||
const keys: string[] = []
|
||||
if (params.where && typeof params.where === 'object') {
|
||||
// Top-level where keys only: nested `anyOf`/`allOf` branches are carried
|
||||
|
|
@ -4313,7 +4313,7 @@ export class Brainy<T = any> implements BrainyInterface<T> {
|
|||
return keys
|
||||
}
|
||||
|
||||
private async hydratePage(
|
||||
async #hydratePage(
|
||||
ids: string[],
|
||||
fields?: readonly string[],
|
||||
guardFields: readonly string[] = []
|
||||
|
|
@ -4346,7 +4346,7 @@ export class Brainy<T = any> implements BrainyInterface<T> {
|
|||
const record = records.get(id)
|
||||
// An id neither the index nor storage knows is not a row.
|
||||
if (fromIndex === undefined && record === undefined) continue
|
||||
out.set(id, this.projectEntity(id, wanted, fromIndex, record))
|
||||
out.set(id, this.#projectEntity(id, wanted, fromIndex, record))
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
|
@ -4367,7 +4367,7 @@ export class Brainy<T = any> implements BrainyInterface<T> {
|
|||
* @param record - The canonical entity, if one had to be read.
|
||||
* @returns The projected entity.
|
||||
*/
|
||||
private projectEntity(
|
||||
#projectEntity(
|
||||
id: string,
|
||||
fields: readonly string[],
|
||||
fromIndex: Record<string, unknown> | undefined,
|
||||
|
|
@ -8211,7 +8211,7 @@ export class Brainy<T = any> implements BrainyInterface<T> {
|
|||
|
||||
// Batch-load entities for 10x faster cloud storage performance
|
||||
// GCS: 10 entities = 1×50ms vs 10×50ms = 500ms (10x faster)
|
||||
const entitiesMap = await this.hydratePage(pageIds, params.fields, this.guardFieldsFor(params))
|
||||
const entitiesMap = await this.#hydratePage(pageIds, params.fields, this.#guardFieldsFor(params))
|
||||
for (const id of pageIds) {
|
||||
const entity = entitiesMap.get(id)
|
||||
if (entity) {
|
||||
|
|
@ -8248,7 +8248,7 @@ export class Brainy<T = any> implements BrainyInterface<T> {
|
|||
if (hiddenIds.size > 0) allUuids = allUuids.filter((id) => !hiddenIds.has(id))
|
||||
const pageIds = allUuids.slice(offset, offset + limit)
|
||||
|
||||
const entitiesMap = await this.hydratePage(pageIds, params.fields, this.guardFieldsFor(params))
|
||||
const entitiesMap = await this.#hydratePage(pageIds, params.fields, this.#guardFieldsFor(params))
|
||||
for (const id of pageIds) {
|
||||
const entity = entitiesMap.get(id)
|
||||
if (entity) {
|
||||
|
|
@ -8276,7 +8276,7 @@ export class Brainy<T = any> implements BrainyInterface<T> {
|
|||
const pageIds = filteredIds.slice(offset, offset + limit)
|
||||
|
||||
// Batch-load entities for 10x faster cloud storage performance
|
||||
const entitiesMap = await this.hydratePage(pageIds, params.fields, this.guardFieldsFor(params))
|
||||
const entitiesMap = await this.#hydratePage(pageIds, params.fields, this.#guardFieldsFor(params))
|
||||
for (const id of pageIds) {
|
||||
const entity = entitiesMap.get(id)
|
||||
if (entity) {
|
||||
|
|
@ -8511,7 +8511,7 @@ export class Brainy<T = any> implements BrainyInterface<T> {
|
|||
|
||||
// Batch-load entities for current page - O(page_size) instead of O(total_results)
|
||||
// GCS: 10 entities = 1×50ms vs 10×50ms = 500ms (10x faster)
|
||||
const entitiesMap = await this.hydratePage(pageIds, params.fields, this.guardFieldsFor(params))
|
||||
const entitiesMap = await this.#hydratePage(pageIds, params.fields, this.#guardFieldsFor(params))
|
||||
for (const id of pageIds) {
|
||||
const entity = entitiesMap.get(id)
|
||||
if (entity) {
|
||||
|
|
@ -8539,7 +8539,7 @@ export class Brainy<T = any> implements BrainyInterface<T> {
|
|||
|
||||
// Batch-load entities for paginated results (10x faster on GCS)
|
||||
const sortedResults: Result<T>[] = []
|
||||
const entitiesMap = await this.hydratePage(pageIds, params.fields, this.guardFieldsFor(params))
|
||||
const entitiesMap = await this.#hydratePage(pageIds, params.fields, this.#guardFieldsFor(params))
|
||||
for (const id of pageIds) {
|
||||
const entity = entitiesMap.get(id)
|
||||
if (entity) {
|
||||
|
|
@ -8656,7 +8656,7 @@ export class Brainy<T = any> implements BrainyInterface<T> {
|
|||
if (params.fields !== undefined && params.fields.length > 0 && result.length > 0) {
|
||||
const named = [...new Set(params.fields)]
|
||||
result = result.map((r) => {
|
||||
const projected = this.projectEntity(
|
||||
const projected = this.#projectEntity(
|
||||
r.id,
|
||||
named,
|
||||
undefined,
|
||||
|
|
@ -17038,7 +17038,7 @@ export class Brainy<T = any> implements BrainyInterface<T> {
|
|||
ordered = valued.map((v) => v.id)
|
||||
}
|
||||
const pageIds = ordered.slice(offset, offset + limit)
|
||||
const entitiesMap = await this.hydratePage(pageIds, params.fields, this.guardFieldsFor(params))
|
||||
const entitiesMap = await this.#hydratePage(pageIds, params.fields, this.#guardFieldsFor(params))
|
||||
const results: Result<T>[] = []
|
||||
for (const id of pageIds) {
|
||||
const entity = entitiesMap.get(id)
|
||||
|
|
|
|||
Reference in a new issue