/** * @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 { 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 { 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) })