diff --git a/packages/objectql/src/bulk-write-per-row-hooks.test.ts b/packages/objectql/src/bulk-write-per-row-hooks.test.ts index 778eb0db47..a5847b7a53 100644 --- a/packages/objectql/src/bulk-write-per-row-hooks.test.ts +++ b/packages/objectql/src/bulk-write-per-row-hooks.test.ts @@ -468,7 +468,7 @@ async function seedTasks(engine: ObjectQL, rows: Record[]): Pro return Array.isArray(written) ? written : [written]; } -function makeMemoryDriver(): any { +function makeStubDriver(): any { const stores = new Map>>(); const storeFor = (o: string) => { let s = stores.get(o); @@ -528,7 +528,7 @@ function makeMemoryDriver(): any { async function boot(hooks: Hook[]): Promise<{ engine: ObjectQL; driver: any }> { const engine = new ObjectQL(); - const driver = makeMemoryDriver(); + const driver = makeStubDriver(); engine.registerDriver(driver, true); await engine.init(); engine.registry.registerObject(taskObject as any); diff --git a/packages/objectql/src/engine-audit-anchor-write.test.ts b/packages/objectql/src/engine-audit-anchor-write.test.ts index 7083b4ce3c..778b2b2b1d 100644 --- a/packages/objectql/src/engine-audit-anchor-write.test.ts +++ b/packages/objectql/src/engine-audit-anchor-write.test.ts @@ -4,7 +4,7 @@ * [#4447] `created_at` is engine-owned: a client-supplied value on an ordinary * write is DROPPED, not persisted. * - * Reproduction harness: a REAL {@link ObjectQL} engine over a minimal in-memory + * Reproduction harness: a REAL {@link ObjectQL} engine over a minimal stub * driver whose `update` lets incoming data win (`{...cur, ...data}`) — the same * shape driver-sql has, which is why a value that survives the engine's strip * reaches the row. @@ -23,7 +23,7 @@ const taskObject = { }, }; -function makeMemoryDriver() { +function makeStubDriver() { const stores = new Map>>(); const storeFor = (obj: string) => { let s = stores.get(obj); @@ -106,7 +106,7 @@ describe('[#4447] created_at is engine-owned on an ordinary write', () => { beforeEach(async () => { engine = new ObjectQL(); - const { driver } = makeMemoryDriver(); + const { driver } = makeStubDriver(); engine.registerDriver(driver, true); await engine.init(); engine.registry.registerObject(taskObject as any); @@ -252,7 +252,7 @@ describe('[#4447] a declared audit field cannot loosen the platform posture', () let engine: ObjectQL; beforeEach(async () => { engine = new ObjectQL(); - const { driver } = makeMemoryDriver(); + const { driver } = makeStubDriver(); engine.registerDriver(driver, true); await engine.init(); engine.registry.registerObject(shadowed as any); diff --git a/packages/objectql/src/engine-autonumber-runtime-owned.test.ts b/packages/objectql/src/engine-autonumber-runtime-owned.test.ts index 57be2578f1..1344a436ef 100644 --- a/packages/objectql/src/engine-autonumber-runtime-owned.test.ts +++ b/packages/objectql/src/engine-autonumber-runtime-owned.test.ts @@ -54,7 +54,7 @@ const ACCOUNT = { }, }; -function makeMemoryDriver(opts: { nativeAutonumber?: boolean } = {}) { +function makeStubDriver(opts: { nativeAutonumber?: boolean } = {}) { const stores = new Map>>(); const createdRows: Array> = []; const updatedPayloads: Array> = []; @@ -153,7 +153,7 @@ function makeMemoryDriver(opts: { nativeAutonumber?: boolean } = {}) { async function makeEngine(opts: { nativeAutonumber?: boolean } = {}) { const engine = new ObjectQL(); - const rig = makeMemoryDriver(opts); + const rig = makeStubDriver(opts); engine.registerDriver(rig.driver, true); await engine.init(); engine.registry.registerObject(ACCOUNT as any); diff --git a/packages/objectql/src/engine-cascade-delete.test.ts b/packages/objectql/src/engine-cascade-delete.test.ts index f0fcfea9b5..858fec53e2 100644 --- a/packages/objectql/src/engine-cascade-delete.test.ts +++ b/packages/objectql/src/engine-cascade-delete.test.ts @@ -2,7 +2,7 @@ /** * Cascade-on-delete behavior for parent→child foreign keys, with a REAL - * {@link ObjectQL} engine + in-memory driver. + * {@link ObjectQL} engine + stub driver. * * Regression: deleting a parent whose child has a *required* lookup FK used to * default to `set_null`, issuing an UPDATE that cleared the required FK — which @@ -56,7 +56,7 @@ const taskCascade = { }, }; -function makeMemoryDriver() { +function makeStubDriver() { const stores = new Map>>(); const storeFor = (o: string) => { let s = stores.get(o); if (!s) { s = new Map(); stores.set(o, s); } return s; }; let nextId = 0; @@ -96,7 +96,7 @@ describe('cascadeDeleteRelations — required FK escalates set_null → restrict beforeEach(async () => { engine = new ObjectQL(); - const { driver } = makeMemoryDriver(); + const { driver } = makeStubDriver(); engine.registerDriver(driver, true); await engine.init(); for (const o of [acct, oppRequired, noteOptional, taskCascade]) engine.registry.registerObject(o as any); diff --git a/packages/objectql/src/engine-dangling-reference-audit.test.ts b/packages/objectql/src/engine-dangling-reference-audit.test.ts index 8dee2a776f..a661a0dd04 100644 --- a/packages/objectql/src/engine-dangling-reference-audit.test.ts +++ b/packages/objectql/src/engine-dangling-reference-audit.test.ts @@ -61,7 +61,7 @@ const history = { }, }; -function makeMemoryDriver() { +function makeStubDriver() { const stores = new Map>>(); const storeFor = (obj: string) => { let s = stores.get(obj); @@ -140,9 +140,9 @@ describe('[#4551] the engine reports the dangling rows its own `isSystem` exempt beforeEach(async () => { engine = new ObjectQL(); - const mem = makeMemoryDriver(); - stores = mem.stores; - engine.registerDriver(mem.driver, true); + const stub = makeStubDriver(); + stores = stub.stores; + engine.registerDriver(stub.driver, true); await engine.init(); engine.registry.registerObject(permissionSet as any); engine.registry.registerObject(binding as any); diff --git a/packages/objectql/src/engine-data-events.bench.ts b/packages/objectql/src/engine-data-events.bench.ts index e9de563a89..89be419ab8 100644 --- a/packages/objectql/src/engine-data-events.bench.ts +++ b/packages/objectql/src/engine-data-events.bench.ts @@ -15,7 +15,7 @@ * Each pair below is the SAME write with and without a realtime service * attached, so the delta is exactly the event-publishing work: uuid generation, * schema validation, envelope construction, and the (no-op) publish. The - * in-memory driver keeps driver cost near zero, which flatters the event cost — + * stub driver keeps driver cost near zero, which flatters the event cost — * i.e. the relative overhead measured here is an upper bound on what a real * SQL/HTTP driver would show. */ @@ -34,7 +34,7 @@ const task = { }, }; -function makeMemoryDriver() { +function makeStubDriver() { const stores = new Map>>(); const storeFor = (o: string) => { let s = stores.get(o); @@ -102,7 +102,7 @@ const nullRealtime: IRealtimeService = { async function makeEngine(withRealtime: boolean): Promise { const engine = new ObjectQL(); - engine.registerDriver(makeMemoryDriver(), true); + engine.registerDriver(makeStubDriver(), true); await engine.init(); engine.registry.registerObject(task as any, 'bench'); if (withRealtime) engine.setRealtimeService(nullRealtime); diff --git a/packages/objectql/src/engine-data-events.test.ts b/packages/objectql/src/engine-data-events.test.ts index 554f86f1bb..21eca1b1b6 100644 --- a/packages/objectql/src/engine-data-events.test.ts +++ b/packages/objectql/src/engine-data-events.test.ts @@ -43,7 +43,7 @@ const task = { }, }; -function makeMemoryDriver() { +function makeStubDriver() { const stores = new Map>>(); const storeFor = (o: string) => { let s = stores.get(o); @@ -118,7 +118,7 @@ describe('#4626 — engine writes publish true DataEvents', () => { unsubscribe: vi.fn(async () => undefined), }; engine = new ObjectQL(); - const { driver } = makeMemoryDriver(); + const { driver } = makeStubDriver(); engine.registerDriver(driver, true); await engine.init(); engine.registry.registerObject(task as any); @@ -216,7 +216,7 @@ describe('#4626 — engine writes publish true DataEvents', () => { it('publishes nothing at all when no realtime service is configured', async () => { const bare = new ObjectQL(); - const { driver } = makeMemoryDriver(); + const { driver } = makeStubDriver(); bare.registerDriver(driver, true); await bare.init(); bare.registry.registerObject(task as any); @@ -253,7 +253,7 @@ describe('#4639 — predicate writes publish aggregate BulkDataEvents', () => { unsubscribe: vi.fn(async () => undefined), }; engine = new ObjectQL(); - const { driver } = makeMemoryDriver(); + const { driver } = makeStubDriver(); engine.registerDriver(driver, true); await engine.init(); engine.registry.registerObject(task as any); @@ -351,7 +351,7 @@ describe('#4639 — predicate writes publish aggregate BulkDataEvents', () => { it('publishes NOTHING when the driver breaks its count contract — and says so', async () => { const offContract = new ObjectQL(); - const { driver } = makeMemoryDriver(); + const { driver } = makeStubDriver(); // `updateMany` is contracted to resolve the affected count. A driver that // resolves something else leaves `matched` unknowable, and `matched` is the // entire substance of a bulk event — so none is published. diff --git a/packages/objectql/src/engine-default-value-tokens.test.ts b/packages/objectql/src/engine-default-value-tokens.test.ts index 4ea1f4cadb..02349972c7 100644 --- a/packages/objectql/src/engine-default-value-tokens.test.ts +++ b/packages/objectql/src/engine-default-value-tokens.test.ts @@ -33,7 +33,7 @@ import { DEFAULT_VALUE_TOKEN_CURRENT_USER, DEFAULT_VALUE_TOKEN_NOW } from '@obje /** `YYYY-MM-DDTHH:MM:SS.sssZ` — the canonical stored instant (ADR-0053). */ const ISO_INSTANT = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{3}Z$/; -function makeMemoryDriver() { +function makeStubDriver() { const stores = new Map>>(); const storeFor = (obj: string) => { let s = stores.get(obj); @@ -88,7 +88,7 @@ describe('[#4560] the `current_user` defaultValue token is engine-owned', () => beforeEach(async () => { engine = new ObjectQL(); - engine.registerDriver(makeMemoryDriver().driver, true); + engine.registerDriver(makeStubDriver().driver, true); await engine.init(); engine.registry.registerObject(owned as any); }); @@ -145,7 +145,7 @@ describe('[#4597] the `NOW()` defaultValue token is engine-owned too', () => { beforeEach(async () => { engine = new ObjectQL(); - engine.registerDriver(makeMemoryDriver().driver, true); + engine.registerDriver(makeStubDriver().driver, true); await engine.init(); engine.registry.registerObject(stamped as any); }); @@ -154,7 +154,8 @@ describe('[#4597] the `NOW()` defaultValue token is engine-owned too', () => { // Before the fix this threw `ValidationError: seen_at must be a valid // datetime (ISO-8601)`: the engine filled the field with the literal // string 'NOW()' and its own validator then rejected the insert. The - // memory driver has no `formatInput` safety net to hide it behind. + // stub driver, like every non-SQL driver, has no `formatInput` safety net + // to hide it behind. const row: any = await engine.insert('probe_now', {}, { context: { isSystem: true } } as any); expect(row.seen_at).not.toBe('NOW()'); expect(row.seen_at).toMatch(ISO_INSTANT); diff --git a/packages/objectql/src/engine-filter-alias.test.ts b/packages/objectql/src/engine-filter-alias.test.ts index 059170db5d..12289896b4 100644 --- a/packages/objectql/src/engine-filter-alias.test.ts +++ b/packages/objectql/src/engine-filter-alias.test.ts @@ -2,7 +2,7 @@ /** * #4346 — the `filter` → `where` alias folds on EVERY engine entry point, not - * just `find()`, with a REAL {@link ObjectQL} engine + in-memory driver. + * just `find()`, with a REAL {@link ObjectQL} engine + stub driver. * * Regression: the DataEngine contract (`DataEngine*OptionsSchema`) declares * `filter` as a legitimate option on every read and write method, but only @@ -37,7 +37,7 @@ const task = { }, }; -function makeMemoryDriver() { +function makeStubDriver() { const stores = new Map>>(); const storeFor = (o: string) => { let s = stores.get(o); if (!s) { s = new Map(); stores.set(o, s); } return s; }; let nextId = 0; @@ -99,9 +99,9 @@ describe('filter → where folds on every engine method (#4346)', () => { beforeEach(async () => { engine = new ObjectQL(); - const mem = makeMemoryDriver(); - stores = mem.stores; - engine.registerDriver(mem.driver, true); + const stub = makeStubDriver(); + stores = stub.stores; + engine.registerDriver(stub.driver, true); await engine.init(); engine.registry.registerObject(task as any); // The issue's repro set: one open row, two done rows. diff --git a/packages/objectql/src/engine-lookup-referential-integrity.test.ts b/packages/objectql/src/engine-lookup-referential-integrity.test.ts index fb044983cd..3c8326e17d 100644 --- a/packages/objectql/src/engine-lookup-referential-integrity.test.ts +++ b/packages/objectql/src/engine-lookup-referential-integrity.test.ts @@ -67,7 +67,7 @@ const task = { }, }; -function makeMemoryDriver() { +function makeStubDriver() { const stores = new Map>>(); const storeFor = (obj: string) => { let s = stores.get(obj); @@ -150,9 +150,9 @@ describe('[#4441] a lookup id that resolves to nothing is refused', () => { beforeEach(async () => { engine = new ObjectQL(); - const mem = makeMemoryDriver(); - stores = mem.stores; - engine.registerDriver(mem.driver, true); + const stub = makeStubDriver(); + stores = stub.stores; + engine.registerDriver(stub.driver, true); await engine.init(); engine.registry.registerObject(permissionSet as any); engine.registry.registerObject(binding as any); diff --git a/packages/objectql/src/engine-write-formula-hydration.test.ts b/packages/objectql/src/engine-write-formula-hydration.test.ts index 537a453465..c430c6077d 100644 --- a/packages/objectql/src/engine-write-formula-hydration.test.ts +++ b/packages/objectql/src/engine-write-formula-hydration.test.ts @@ -125,7 +125,7 @@ const MEMO = { }, }; -function makeMemoryDriver() { +function makeStubDriver() { const stores = new Map>>(); const storeFor = (obj: string) => { let s = stores.get(obj); @@ -154,14 +154,15 @@ function makeMemoryDriver() { async disconnect() {}, async checkHealth() { return true; }, async execute() { return null; }, - // Shallow COPIES, never live references into the backing table — the - // contract `driver-memory` states in as many words, and the SQL driver gets - // for free from knex. It is load-bearing for this file specifically: the - // READ path hydrates formulas by mutating the rows a driver hands back, so - // a harness leaking references would write `display_title` into its own - // store on the first GET and every later write response would echo it — - // these tests would then pass with the write-path hydration deleted, which - // is the "green because nothing is produced" failure mode, inverted. + // Shallow COPIES, never live references into the backing table — the shape + // every real backend hands back (a SQL driver gets it for free from knex; an + // in-process store has to copy explicitly). It is load-bearing for this + // file specifically: the READ path hydrates formulas by mutating the rows a + // driver hands back, so a harness leaking references would write + // `display_title` into its own store on the first GET and every later + // write response would echo it — these tests would then pass with the + // write-path hydration deleted, which is the "green because nothing is + // produced" failure mode, inverted. async find(object: string, ast: { where?: unknown }) { return Array.from(storeFor(object).values()) .filter((r) => matchesWhere(r, ast?.where)) @@ -222,7 +223,7 @@ function makeMemoryDriver() { async function makeEngine() { const engine = new ObjectQL(); - const rig = makeMemoryDriver(); + const rig = makeStubDriver(); engine.registerDriver(rig.driver as never, true); await engine.init(); for (const obj of [ACCOUNT, FORECAST, PLAIN, MEMO]) { diff --git a/packages/objectql/src/hook-condition-bulk-previous.test.ts b/packages/objectql/src/hook-condition-bulk-previous.test.ts index c4d5d38e72..5ff85c81a3 100644 --- a/packages/objectql/src/hook-condition-bulk-previous.test.ts +++ b/packages/objectql/src/hook-condition-bulk-previous.test.ts @@ -479,7 +479,7 @@ describe('[#5038] the diagnostic is RETIRED for after-type hooks', () => { * Real-engine harness (mirrors hook-condition-fail-loud.test.ts) * ──────────────────────────────────────────────────────────────────────────── */ -function makeMemoryDriver(): any { +function makeStubDriver(): any { const stores = new Map>>(); const storeFor = (o: string) => { let s = stores.get(o); @@ -534,7 +534,7 @@ function makeMemoryDriver(): any { async function bootEngine(hooks: Hook[]): Promise { const engine = new ObjectQL(); - engine.registerDriver(makeMemoryDriver(), true); + engine.registerDriver(makeStubDriver(), true); await engine.init(); engine.registry.registerObject(taskObject as any); bindHooksToEngine(engine, hooks, { packageId: 'app:test', logger: silentLogger }); diff --git a/packages/objectql/src/hook-condition-fail-loud.test.ts b/packages/objectql/src/hook-condition-fail-loud.test.ts index 648dad7077..c60f9e0b1a 100644 --- a/packages/objectql/src/hook-condition-fail-loud.test.ts +++ b/packages/objectql/src/hook-condition-fail-loud.test.ts @@ -458,7 +458,7 @@ describe('[#4775] a condition that does not compile aborts too', () => { * Real-engine harness * ──────────────────────────────────────────────────────────────────────────── */ -function makeMemoryDriver(): any { +function makeStubDriver(): any { const stores = new Map>>(); const storeFor = (o: string) => { let s = stores.get(o); @@ -508,7 +508,7 @@ function makeMemoryDriver(): any { async function bootEngine(hooks: Hook[]): Promise { const engine = new ObjectQL(); - engine.registerDriver(makeMemoryDriver(), true); + engine.registerDriver(makeStubDriver(), true); await engine.init(); engine.registry.registerObject(taskObject as any); bindHooksToEngine(engine, hooks, { packageId: 'app:test', logger: silentLogger }); diff --git a/packages/objectql/src/hook-condition-merged-record.test.ts b/packages/objectql/src/hook-condition-merged-record.test.ts index 2622cda987..a4e7a2116d 100644 --- a/packages/objectql/src/hook-condition-merged-record.test.ts +++ b/packages/objectql/src/hook-condition-merged-record.test.ts @@ -226,12 +226,12 @@ describe('[#4770] hook condition evaluates against stored ⊕ payload', () => { * * `rm -rf examples/app-showcase/.objectstack && pnpm dev` printed ten * `condition evaluation failed` lines for `showcase_audit_task_completion`. - * This is the same object/hook shape driven through a REAL engine over an - * in-memory driver that — like a SQL driver — stores only the columns a write + * This is the same object/hook shape driven through a REAL engine over a + * stub driver that — like a SQL driver — stores only the columns a write * actually touched. * ──────────────────────────────────────────────────────────────────────────── */ -function makeMemoryDriver() { +function makeStubDriver() { const stores = new Map>>(); const storeFor = (obj: string) => { let s = stores.get(obj); @@ -309,7 +309,7 @@ describe('[#4770] showcase repro — showcase_audit_task_completion over a real beforeEach(async () => { engine = new ObjectQL(); - const { driver } = makeMemoryDriver(); + const { driver } = makeStubDriver(); engine.registerDriver(driver, true); await engine.init(); engine.registry.registerObject(taskObject as any); diff --git a/packages/objectql/src/hook-condition-previous-scope.test.ts b/packages/objectql/src/hook-condition-previous-scope.test.ts index 0c39a684ec..9820482d8f 100644 --- a/packages/objectql/src/hook-condition-previous-scope.test.ts +++ b/packages/objectql/src/hook-condition-previous-scope.test.ts @@ -268,11 +268,11 @@ describe('[#4784] hook condition binds `previous` alongside `record`', () => { }); /* ──────────────────────────────────────────────────────────────────────────── - * Through a REAL engine, over an in-memory driver that — like a SQL driver — + * Through a REAL engine, over a stub driver that — like a SQL driver — * stores only the columns a write actually touched. * ──────────────────────────────────────────────────────────────────────────── */ -function makeMemoryDriver() { +function makeStubDriver() { const stores = new Map>>(); /** Every read the engine performs, so "no extra fetch" is measurable. */ const reads = { findOne: 0, find: 0 }; @@ -355,9 +355,9 @@ describe('[#4784] transition condition over a real engine', () => { async function boot(hooks: Hook[]) { engine = new ObjectQL(); - const mem = makeMemoryDriver(); - reads = mem.reads; - engine.registerDriver(mem.driver, true); + const stub = makeStubDriver(); + reads = stub.reads; + engine.registerDriver(stub.driver, true); await engine.init(); engine.registry.registerObject(taskObject as any); @@ -446,15 +446,15 @@ describe('[#4784] a condition that never mentions `previous` costs zero extra fe */ async function bootWith(hooks: Hook[]) { const engine = new ObjectQL(); - const mem = makeMemoryDriver(); - engine.registerDriver(mem.driver, true); + const stub = makeStubDriver(); + engine.registerDriver(stub.driver, true); await engine.init(); engine.registry.registerObject(taskObject as any); bindHooksToEngine(engine, hooks, { packageId: 'app:pin', logger: { debug: () => {}, info: () => {}, warn: () => {}, error: () => {} }, }); - return { engine, reads: mem.reads }; + return { engine, reads: stub.reads }; } it('reads no prior row at all for a before-hook condition over `record` only', async () => { @@ -518,8 +518,8 @@ describe('[#4784] a condition that never mentions `previous` costs zero extra fe describe('[#5272] a single-record delete binds `previous` through the real engine', () => { async function bootDelete(hooks: Hook[]) { const engine = new ObjectQL(); - const mem = makeMemoryDriver(); - engine.registerDriver(mem.driver, true); + const stub = makeStubDriver(); + engine.registerDriver(stub.driver, true); await engine.init(); engine.registry.registerObject(taskObject as any); const warn = vi.fn(); @@ -529,7 +529,7 @@ describe('[#5272] a single-record delete binds `previous` through the real engin }); return { engine, - reads: mem.reads, + reads: stub.reads, conditionWarnings: () => warn.mock.calls.filter(([msg]) => String(msg).includes('condition evaluation failed')), }; diff --git a/packages/objectql/src/hook-input-shape-contract.test.ts b/packages/objectql/src/hook-input-shape-contract.test.ts index 961bf1312c..9695fcbbbf 100644 --- a/packages/objectql/src/hook-input-shape-contract.test.ts +++ b/packages/objectql/src/hook-input-shape-contract.test.ts @@ -251,7 +251,7 @@ describe('[#5273] a metadata-declared hook reads the same shape', () => { }); /* ──────────────────────────────────────────────────────────────────────────── - * Harness — a memory driver just wide enough for the dispatch paths above. + * Harness — a stub driver just wide enough for the dispatch paths above. * ──────────────────────────────────────────────────────────────────────────── */ async function seedTasks(engine: ObjectQL, rows: Record[]): Promise { @@ -259,7 +259,7 @@ async function seedTasks(engine: ObjectQL, rows: Record[]): Pro return Array.isArray(written) ? written : [written]; } -function makeMemoryDriver(): any { +function makeStubDriver(): any { const stores = new Map>>(); const storeFor = (o: string) => { let s = stores.get(o); @@ -316,7 +316,7 @@ function makeMemoryDriver(): any { async function boot(): Promise<{ engine: ObjectQL; driver: any }> { const engine = new ObjectQL(); - const driver = makeMemoryDriver(); + const driver = makeStubDriver(); engine.registerDriver(driver, true); await engine.init(); engine.registry.registerObject(taskObject as any); diff --git a/packages/objectql/src/protocol-clone-real-engine.test.ts b/packages/objectql/src/protocol-clone-real-engine.test.ts index f7bf2b645c..ecc44e8f70 100644 --- a/packages/objectql/src/protocol-clone-real-engine.test.ts +++ b/packages/objectql/src/protocol-clone-real-engine.test.ts @@ -2,7 +2,7 @@ /** * Integration test for `protocol.cloneData` driving a REAL {@link ObjectQL} - * engine + a minimal in-memory driver. The unit suite in + * engine + a minimal stub driver. The unit suite in * `protocol-data.test.ts` stubs the engine; this exercises the production * path — registry.getObject (enable.clone + field defs), engine.findOne for * the source, and engine.insert for the copy — so the strongest real-engine @@ -39,7 +39,7 @@ const lockedObject = { }, }; -function makeMemoryDriver() { +function makeStubDriver() { const stores = new Map>>(); const storeFor = (obj: string) => { let s = stores.get(obj); @@ -113,7 +113,7 @@ describe('cloneData — real ObjectQL engine', () => { beforeEach(async () => { engine = new ObjectQL(); - const { driver } = makeMemoryDriver(); + const { driver } = makeStubDriver(); engine.registerDriver(driver, true); await engine.init(); engine.registry.registerObject(accountObject as any); diff --git a/packages/objectql/src/protocol-recorded-by-null.test.ts b/packages/objectql/src/protocol-recorded-by-null.test.ts index 98699969a6..4b43e85587 100644 --- a/packages/objectql/src/protocol-recorded-by-null.test.ts +++ b/packages/objectql/src/protocol-recorded-by-null.test.ts @@ -76,8 +76,8 @@ const sysMetadataHistoryObject = { }, }; -/** Minimal in-memory driver; equality-only WHERE. */ -function makeMemoryDriver() { +/** Minimal stub driver; equality-only WHERE. */ +function makeStubDriver() { const stores = new Map>>(); const storeFor = (obj: string) => { let s = stores.get(obj); @@ -157,7 +157,7 @@ describe('#4556 — protocol write paths store NULL, not the sentinel string', ( beforeEach(async () => { engine = new ObjectQL(); - const { driver } = makeMemoryDriver(); + const { driver } = makeStubDriver(); engine.registerDriver(driver, true); await engine.init(); engine.registry.registerObject(sysUserObject as any); diff --git a/packages/objectql/src/protocol-registry-shadow.test.ts b/packages/objectql/src/protocol-registry-shadow.test.ts index 7735eaa393..22515d1bf2 100644 --- a/packages/objectql/src/protocol-registry-shadow.test.ts +++ b/packages/objectql/src/protocol-registry-shadow.test.ts @@ -68,8 +68,8 @@ const sysMetadataHistoryObject = { }, }; -/** Equality-only in-memory driver — same shape as the PR-10d.4 suite. */ -function makeMemoryDriver() { +/** Equality-only stub driver — same shape as the PR-10d.4 suite. */ +function makeStubDriver() { const stores = new Map>>(); const storeFor = (obj: string) => { let s = stores.get(obj); @@ -171,7 +171,7 @@ describe('registry shadow — control-plane PUT → GET → DELETE keeps the art beforeEach(async () => { engine = new ObjectQL(); - const { driver } = makeMemoryDriver(); + const { driver } = makeStubDriver(); engine.registerDriver(driver, true); await engine.init(); engine.registry.registerObject(sysMetadataObject as any); diff --git a/packages/objectql/src/protocol-save-meta-repo-path-real-engine.test.ts b/packages/objectql/src/protocol-save-meta-repo-path-real-engine.test.ts index 5acdc09da1..eca218be8f 100644 --- a/packages/objectql/src/protocol-save-meta-repo-path-real-engine.test.ts +++ b/packages/objectql/src/protocol-save-meta-repo-path-real-engine.test.ts @@ -2,7 +2,7 @@ /** * PR-10d.4 — Integration test for the repository write path using a REAL - * {@link ObjectQL} engine driving a minimal in-memory driver. The PR-10d.3 + * {@link ObjectQL} engine driving a minimal stub driver. The PR-10d.3 * unit suite uses a hand-rolled stub at the *engine* level; the rubber-duck * review flagged that as a drift risk because production semantics * (especially the strict `where: { id }` requirement for `engine.update`) @@ -32,10 +32,10 @@ const sysMetadataObject = { }; /** - * Minimal in-memory driver covering only what `SysMetadataRepository` + * Minimal stub driver covering only what `SysMetadataRepository` * exercises. Equality-only WHERE evaluation; one record store per object. */ -function makeMemoryDriver() { +function makeStubDriver() { const stores = new Map>>(); const storeFor = (obj: string) => { let s = stores.get(obj); @@ -124,7 +124,7 @@ describe('saveMetaItem — repository write path against real ObjectQL (PR-10d.4 beforeEach(async () => { engine = new ObjectQL(); - const { driver } = makeMemoryDriver(); + const { driver } = makeStubDriver(); engine.registerDriver(driver, true); await engine.init(); engine.registry.registerObject(sysMetadataObject as any); @@ -224,7 +224,7 @@ describe('deleteMetaItem — repository write path against real ObjectQL (PR-10d beforeEach(async () => { engine = new ObjectQL(); - const { driver } = makeMemoryDriver(); + const { driver } = makeStubDriver(); engine.registerDriver(driver, true); await engine.init(); engine.registry.registerObject(sysMetadataObject as any); diff --git a/packages/objectql/src/protocol-unknown-query-param.test.ts b/packages/objectql/src/protocol-unknown-query-param.test.ts index e7b3c0b7aa..293129582d 100644 --- a/packages/objectql/src/protocol-unknown-query-param.test.ts +++ b/packages/objectql/src/protocol-unknown-query-param.test.ts @@ -35,7 +35,7 @@ const taskObject = { }, }; -function makeMemoryDriver() { +function makeStubDriver() { const stores = new Map>>(); const storeFor = (obj: string) => { let s = stores.get(obj); @@ -121,7 +121,7 @@ describe('#4134 — unknown list query params (real ObjectQL engine)', () => { beforeEach(async () => { engine = new ObjectQL(); - const { driver, stores } = makeMemoryDriver(); + const { driver, stores } = makeStubDriver(); engine.registerDriver(driver, true); await engine.init(); engine.registry.registerObject(taskObject as any, 'test-package'); diff --git a/packages/objectql/src/protocol-unregistered-object.test.ts b/packages/objectql/src/protocol-unregistered-object.test.ts index d347b63066..f481474532 100644 --- a/packages/objectql/src/protocol-unregistered-object.test.ts +++ b/packages/objectql/src/protocol-unregistered-object.test.ts @@ -20,7 +20,7 @@ * after `syncObjectSchema` ran, a registration race — the exposure gate was * silently skipped AND nothing turned it into a 404. The rows were served. * - * These tests drive a REAL {@link ObjectQL} engine + a minimal in-memory driver + * These tests drive a REAL {@link ObjectQL} engine + a minimal stub driver * (the same shape `protocol-clone-real-engine.test.ts` uses), because the point * is precisely what happens when metadata and physical storage disagree — which * an engine double cannot show. @@ -42,7 +42,7 @@ const registeredObject = { /** The object nobody registered. A table by this name exists anyway (case B). */ const UNREGISTERED = 'gate_ghost'; -function makeMemoryDriver() { +function makeStubDriver() { const stores = new Map>>(); const storeFor = (obj: string) => { let s = stores.get(obj); @@ -122,7 +122,7 @@ describe('#3770 — data-plane object-existence gate (real ObjectQL engine)', () beforeEach(async () => { engine = new ObjectQL(); - const made = makeMemoryDriver(); + const made = makeStubDriver(); stores = made.stores; engine.registerDriver(made.driver, true); await engine.init(); diff --git a/packages/objectql/src/query-expression-conformance.test.ts b/packages/objectql/src/query-expression-conformance.test.ts index 1487537776..40e200f2fa 100644 --- a/packages/objectql/src/query-expression-conformance.test.ts +++ b/packages/objectql/src/query-expression-conformance.test.ts @@ -82,13 +82,13 @@ const taskObject = { }; /** - * An in-memory driver that really sorts, really projects and really paginates. + * A stub driver that really sorts, really projects and really paginates. * * This matters more than usual here: a driver that ignored `orderBy` would make * every "a real sort field works" control vacuously true, and the pins above it * would then pass against a completely broken sort axis. */ -function makeMemoryDriver() { +function makeStubDriver() { const stores = new Map>>(); const storeFor = (obj: string) => { let s = stores.get(obj); @@ -210,7 +210,7 @@ describe('#4226 — sort / select / expand on the list path (real ObjectQL engin beforeEach(async () => { engine = new ObjectQL(); - const made = makeMemoryDriver(); + const made = makeStubDriver(); const driver = made.driver; stores = made.stores; engine.registerDriver(driver, true); @@ -795,7 +795,7 @@ describe('#4254 — searchFields / groupBy / aggregations on the list path (real beforeEach(async () => { engine = new ObjectQL(); - const { driver, stores } = makeMemoryDriver(); + const { driver, stores } = makeStubDriver(); // The issue's transcript runs on the engine's IN-MEMORY aggregation // fallback — the path `engine.aggregate` takes for drivers with no // native `aggregate` (driver-rest, driver-memory, partial SQL diff --git a/packages/objectql/src/secret-fields.test.ts b/packages/objectql/src/secret-fields.test.ts index cf70800246..adc09dc38d 100644 --- a/packages/objectql/src/secret-fields.test.ts +++ b/packages/objectql/src/secret-fields.test.ts @@ -2,7 +2,7 @@ /** * Secret-field channel — end-to-end against a REAL {@link ObjectQL} engine + a - * minimal in-memory driver. Verifies the core encryption chain: + * minimal stub driver. Verifies the core encryption chain: * - encrypt-on-write: plaintext → sys_secret ciphertext + opaque ref on the row * - mask-on-read: the generic read path never returns plaintext or the ref * - resolveSecret: privileged dereference round-trips back to plaintext @@ -15,8 +15,8 @@ import { ObjectQL } from './engine.js'; import { SECRET_MASK, isSecretRef } from './secret-fields.js'; import type { ICryptoProvider, CryptoHandle, CryptoContext } from '@objectstack/spec/contracts'; -// ---- minimal in-memory driver (equality-only WHERE) ----------------------- -function makeMemoryDriver() { +// ---- minimal stub driver (equality-only WHERE) ---------------------------- +function makeStubDriver() { const stores = new Map>>(); const storeFor = (obj: string) => { let s = stores.get(obj); @@ -130,7 +130,7 @@ const dsObject = { async function buildEngine(withCrypto: boolean) { const engine = new ObjectQL(); - const { driver, stores } = makeMemoryDriver(); + const { driver, stores } = makeStubDriver(); engine.registerDriver(driver, true); await engine.init(); engine.registry.registerObject(sysSecretObject as any); @@ -216,7 +216,7 @@ describe('objectql secret-field channel', () => { it('non-secret objects are untouched (no crypto cost)', async () => { engineWithoutSecretField: { const engine = new ObjectQL(); - const { driver, stores } = makeMemoryDriver(); + const { driver, stores } = makeStubDriver(); engine.registerDriver(driver, true); await engine.init(); engine.registry.registerObject({ @@ -256,7 +256,7 @@ const authUserObject = { async function buildPasswordEngine() { // Deliberately NO CryptoProvider — a password field must not require one. const engine = new ObjectQL(); - const { driver, stores } = makeMemoryDriver(); + const { driver, stores } = makeStubDriver(); engine.registerDriver(driver, true); await engine.init(); engine.registry.registerObject(deviceObject as any); diff --git a/packages/runtime/src/sandbox/nested-write.canary.test.ts b/packages/runtime/src/sandbox/nested-write.canary.test.ts index c8a3424dbb..db3eebf224 100644 --- a/packages/runtime/src/sandbox/nested-write.canary.test.ts +++ b/packages/runtime/src/sandbox/nested-write.canary.test.ts @@ -55,7 +55,7 @@ const child = { }, }; -function makeMemoryDriver() { +function makeStubDriver() { const stores = new Map>>(); const storeFor = (o: string) => { let s = stores.get(o); @@ -128,7 +128,7 @@ describe('#3259 flake canary — nested writes stay green at the stock 250ms CPU async function rollupChain(n: number) { const engine = new ObjectQL(); - const { driver } = makeMemoryDriver(); + const { driver } = makeStubDriver(); engine.registerDriver(driver, true); await engine.init(); for (const o of [parent, child]) engine.registry.registerObject(o as any); diff --git a/packages/runtime/src/sandbox/nested-write.integration.test.ts b/packages/runtime/src/sandbox/nested-write.integration.test.ts index 2ff9cc3d45..8bbde74aeb 100644 --- a/packages/runtime/src/sandbox/nested-write.integration.test.ts +++ b/packages/runtime/src/sandbox/nested-write.integration.test.ts @@ -8,7 +8,7 @@ * hook, so the child's nested write fires a SECOND sandbox VM while the child's * hook is still in flight — the exact re-entrancy that used to crash the process * with `memory access out of bounds` under the old single-suspended-asyncify - * model. This wires a REAL {@link ObjectQL} engine (in-memory driver) to the + * model. This wires a REAL {@link ObjectQL} engine (stub driver) to the * real {@link QuickJSScriptRunner} through {@link hookBodyRunnerFactory}, so the * whole hook → sandbox → nested-write → nested-hook path is exercised. * @@ -41,7 +41,7 @@ const child = { }, }; -function makeMemoryDriver() { +function makeStubDriver() { const stores = new Map>>(); const storeFor = (o: string) => { let s = stores.get(o); @@ -85,7 +85,7 @@ describe('#1867 nested cross-object write from a hook (real engine + sandbox)', beforeEach(async () => { engine = new ObjectQL(); - const { driver } = makeMemoryDriver(); + const { driver } = makeStubDriver(); engine.registerDriver(driver, true); await engine.init(); for (const o of [parent, child]) engine.registry.registerObject(o as any); diff --git a/packages/runtime/src/sandbox/undeclared-field-write-driver-split.integration.test.ts b/packages/runtime/src/sandbox/undeclared-field-write-driver-split.integration.test.ts index d2be4c6913..a6b2a20aee 100644 --- a/packages/runtime/src/sandbox/undeclared-field-write-driver-split.integration.test.ts +++ b/packages/runtime/src/sandbox/undeclared-field-write-driver-split.integration.test.ts @@ -41,6 +41,35 @@ * add the flat-input envelope to the thing under test. */ +/** + * ⚠️ `@objectstack/driver-memory` is imported here ON PURPOSE, and this is the + * ONLY place in the repository that still consumes it from a test. It is NOT a + * migration leftover — do not "finish the job" by deleting or replacing it. + * + * Why it has to stay: the whole point of this file is a PRODUCT divergence + * between two driver families — writing an undeclared field is rejected as a + * WHOLE statement by the SQL family, and accepted verbatim by the schemaless + * family. Pinning a divergence needs both arms. The SQL arm is `SqlDriver`; the + * schemaless arm needs a backend that has no schema to check the key against, + * and `InMemoryDriver` is the cheapest honest one (MongoDB behaves the same on + * the same `...data` spread, but would put a real database in CI's path). + * Delete this arm and the guardrail silently becomes a one-sided assertion + * about SQL — the divergence stops being pinned at all. + * + * Why the freeze does not forbid it: #5499 froze *investment* in driver-memory + * (defect fixes, feature work). Using it as a reference implementation is not + * investment, and nothing here fixes or extends it. Ruling: #5704, maintainer + * 2026-08-06, Q2 = B ("keep, in this one place, with a comment saying so"). + * Consequence, also ruled there: `packages/runtime`'s `driver-memory` devDep + * stays for the long term — this import is its one and only consumer. + * + * Everything else that used to look like a driver-memory test consumer was a + * hand-written local stub whose NAME merely said "memory" — in packages that + * do not even depend on the driver. #5704/#5784 renamed them all to + * `makeStubDriver`, precisely so that grepping for the driver lands here, and + * only here. + */ + import { describe, it, expect, afterEach } from 'vitest'; import { mkdtempSync, rmSync } from 'node:fs'; import { tmpdir } from 'node:os';