open-brainy/tests/integration/find-matchall-cold.test.ts

185 lines
7.9 KiB
TypeScript
Raw Permalink Normal View History

2026-08-10 10:55:11 -07:00
/**
* @module tests/integration/find-matchall-cold
* @description THE MATCH-ALL SILENT-EMPTY PIN: `find({ where: {} })` is a
* match-all query zero predicates constrain nothing yet it used to route
* through the index-filter branch, where `getIdsForFilter({})` answers `[]`
* by contract. Result: 0 rows while storage held rows (worst on a freshly
* reopened brain, where it masqueraded as data loss), the forbidden answer
* class a silent empty instead of served-or-refused. These tests pin the
* law: an empty `where` routes exactly like an absent `where`, serving from
* truth-complete sources (a storage page bounded to the offset+limit window,
* or the column store's top-K sort under orderBy) warm AND cold, on the
* live brain, the Db pin path, pagination.count, streaming.entities, and the
* semantic path (`{ query, where: {} }` must not short-circuit to `[]`).
* The one deliberate refusal: `removeMany({ where: {} })` throws a
* match-all BULK DELETE must be asked for explicitly, never inherited.
*/
import { describe, it, expect, afterEach } from 'vitest'
import { mkdtempSync, rmSync } from 'node:fs'
import { tmpdir } from 'node:os'
import { join } from 'node:path'
import { Brainy } from '../../src/index.js'
import { NounType } from '../../src/types/graphTypes.js'
const dirs: string[] = []
const brains: Brainy[] = []
afterEach(async () => {
for (const b of brains.splice(0)) await b.close().catch(() => {})
for (const d of dirs.splice(0)) rmSync(d, { recursive: true, force: true })
})
async function open(dir: string): Promise<Brainy> {
const b = new Brainy({ storage: { type: 'filesystem', path: dir }, requireSubtype: false })
await b.init()
brains.push(b)
return b
}
/** Seed three plain documents with a sortable numeric field. */
async function seed(brain: Brainy): Promise<string[]> {
const ids: string[] = []
ids.push(await brain.add({ data: 'alpha row', type: NounType.Document, metadata: { n: 1 } }))
ids.push(await brain.add({ data: 'beta row', type: NounType.Document, metadata: { n: 2 } }))
ids.push(await brain.add({ data: 'gamma row', type: NounType.Document, metadata: { n: 3 } }))
await brain.flush()
return ids
}
describe('find({ where: {} }) — match-all serves, warm and cold', () => {
it('the repro: a freshly reopened filesystem brain serves match-all (not a silent 0)', async () => {
const dir = mkdtempSync(join(tmpdir(), 'brainy-matchall-cold-'))
dirs.push(dir)
const brain = await open(dir)
await seed(brain)
await brain.close()
brains.pop()
const reopened = await open(dir)
const rows = await reopened.find({ where: {}, limit: 10 })
expect(rows.length, 'match-all serves every stored row on the cold brain').toBe(3)
// The predicate paths that always worked cold stay working — same brain.
expect((await reopened.find({ where: { n: 1 }, limit: 10 })).length).toBe(1)
expect((await reopened.find({ where: { 'system.type': 'document' }, limit: 10 })).length).toBe(3)
}, 120000)
it('match-all + orderBy on a metadata field serves sorted after reopen', async () => {
const dir = mkdtempSync(join(tmpdir(), 'brainy-matchall-order-'))
dirs.push(dir)
const brain = await open(dir)
await seed(brain)
await brain.close()
brains.pop()
const reopened = await open(dir)
const rows = await reopened.find({ where: {}, orderBy: 'n', order: 'desc', limit: 10 })
expect(rows.length, 'sorted match-all serves every stored row cold').toBe(3)
expect(
rows.map((r) => (r.metadata as { n: number }).n),
'orderBy is honored on the cold match-all page'
).toEqual([3, 2, 1])
}, 120000)
it('warm brain unchanged: match-all, sorted match-all, and predicates all serve in-session', async () => {
const dir = mkdtempSync(join(tmpdir(), 'brainy-matchall-warm-'))
dirs.push(dir)
const brain = await open(dir)
await seed(brain)
expect((await brain.find({ where: {}, limit: 10 })).length).toBe(3)
const sorted = await brain.find({ where: {}, orderBy: 'n', order: 'asc', limit: 2 })
expect(sorted.map((r) => (r.metadata as { n: number }).n)).toEqual([1, 2])
expect((await brain.find({ where: { n: 2 }, limit: 10 })).length).toBe(1)
// Pagination window respected: match-all never over-serves the page.
expect((await brain.find({ where: {}, limit: 2, offset: 2 })).length).toBe(1)
}, 120000)
it('the semantic path: find({ query, where: {} }) must not short-circuit to []', async () => {
const dir = mkdtempSync(join(tmpdir(), 'brainy-matchall-query-'))
dirs.push(dir)
const brain = await open(dir)
await seed(brain)
await brain.close()
brains.pop()
const reopened = await open(dir)
// Before the fix, the pre-resolved empty filter matched nothing and the
// vector search was skipped entirely — a silent [] for every such query.
const rows = await reopened.find({ query: 'alpha row', where: {}, limit: 10 })
expect(rows.length, 'an unconstraining where must not empty a semantic query').toBeGreaterThan(0)
}, 120000)
it('the Db pin path: asOf(g).find({ where: {} }) serves at the pinned generation after reopen', async () => {
const dir = mkdtempSync(join(tmpdir(), 'brainy-matchall-asof-'))
dirs.push(dir)
const brain = await open(dir)
await brain.add({ data: 'first', type: NounType.Document, metadata: { n: 1 } })
await brain.add({ data: 'second', type: NounType.Document, metadata: { n: 2 } })
await brain.flush()
const gTwo = brain.generation()
await brain.add({ data: 'third', type: NounType.Document, metadata: { n: 3 } })
await brain.flush()
await brain.close()
brains.pop()
const reopened = await open(dir)
// Current-generation pin (delegates to the live find fast path).
const now = reopened.now()
expect((await now.find({ where: {}, limit: 10 })).length).toBe(3)
// Historical pin: the record-overlay path must serve match-all too.
const past = await reopened.asOf(gTwo)
try {
const rows = await past.find({ where: {}, limit: 10 })
expect(rows.length, 'match-all at the pinned generation sees exactly the rows of that generation').toBe(2)
} finally {
await past.release()
}
}, 120000)
it('pagination.count({ where: {} }) counts every row instead of a silent 0', async () => {
const dir = mkdtempSync(join(tmpdir(), 'brainy-matchall-count-'))
dirs.push(dir)
const brain = await open(dir)
await seed(brain)
await brain.close()
brains.pop()
const reopened = await open(dir)
// The law: an empty where counts exactly like an absent where (the
// unfiltered total — which by long-standing count semantics includes
// system entities such as the VFS root, hence >= the 3 user rows).
const emptyWhere = await reopened.pagination.count({ where: {} })
expect(emptyWhere).toBe(await reopened.pagination.count({}))
expect(emptyWhere).toBeGreaterThanOrEqual(3)
}, 120000)
it('streaming.entities({ where: {} }) streams every row instead of nothing', async () => {
const dir = mkdtempSync(join(tmpdir(), 'brainy-matchall-stream-'))
dirs.push(dir)
const brain = await open(dir)
await seed(brain)
await brain.close()
brains.pop()
const reopened = await open(dir)
const streamed: string[] = []
for await (const entity of reopened.streaming.entities({ where: {} })) {
streamed.push(entity.id)
}
expect(streamed.length, 'an unconstraining where streams the full store').toBeGreaterThanOrEqual(3)
}, 120000)
it('removeMany({ where: {} }) refuses loudly — match-all bulk delete is never implicit', async () => {
const dir = mkdtempSync(join(tmpdir(), 'brainy-matchall-remove-'))
dirs.push(dir)
const brain = await open(dir)
await seed(brain)
await expect(brain.removeMany({ where: {} })).rejects.toThrow(/matches EVERYTHING/)
// Nothing was deleted by the refused call.
expect((await brain.find({ where: {}, limit: 10 })).length).toBe(3)
}, 120000)
})