Skip to content

Commit dee462f

Browse files
committed
test(objectql): pay the two farm reds — registerObject arity, and un-erased engine option bags (#7872)
The door suite's registerObject(deal) call was missing the required packageId (the +1 over objectql's frozen TEST_DEBT 355); and its option bags used bare 'as any', which the query-options-erasure ratchet counts (240 -> 245). The bags now type-check uncast — FilterCondition's index signature admits the deliberately off-contract comparands, which is the point of the door — except the one FilterArray case, which carries the sanctioned 'as unknown as EngineQueryOptions' naming the contract it bypasses (not counted). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0123k4cam2jEAkPmbJeoaY3r
1 parent 81f6752 commit dee462f

1 file changed

Lines changed: 18 additions & 9 deletions

File tree

packages/objectql/src/engine-comparand-type-door.test.ts

Lines changed: 18 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
*/
2424

2525
import { describe, it, expect, beforeEach } from 'vitest';
26+
import type { EngineQueryOptions } from '@objectstack/spec/data';
2627
import { ObjectQL } from './engine.js';
2728

2829
const deal = {
@@ -109,7 +110,7 @@ describe('[#7872] the comparand-type door at the engine collection point', () =>
109110
engine = new ObjectQL();
110111
engine.registerDriver(rec.driver, true);
111112
await engine.init();
112-
engine.registry.registerObject(deal);
113+
engine.registry.registerObject(deal, 'test');
113114
await engine.insert('deal', { id: 'd1', stage: 'won', amount: 10, owner_id: 'u1' });
114115
await engine.insert('deal', { id: 'd2', stage: 'lost', amount: 20, owner_id: 'u2' });
115116
reads.length = 0;
@@ -130,7 +131,10 @@ describe('[#7872] the comparand-type door at the engine collection point', () =>
130131
['a plain object in a scalar slot', { amount: { $eq: { v: 10 } } }],
131132
['an oversized bigint', { amount: { $eq: 2n ** 53n + 1n } }],
132133
])('refuses %s with the envelope, and NO driver read runs', async (_label, where) => {
133-
const err = await refusalOf(engine.find('deal', { where } as any));
134+
// NOT erased: `FilterCondition`'s index signature admits these values, so
135+
// the call type-checks as written — that a type-legal filter still has to
136+
// be refused at runtime is exactly why the door exists (#5869's note).
137+
const err = await refusalOf(engine.find('deal', { where }));
134138
expect(err).not.toBeNull();
135139
expect(err).toMatchObject({ status: 400, code: 'INVALID_FILTER' });
136140
// The engine's wording contract: the refusal names the entry point…
@@ -141,13 +145,13 @@ describe('[#7872] the comparand-type door at the engine collection point', () =>
141145
});
142146

143147
it('covers every engine verb that collects a filter — read and write sides', async () => {
144-
const where = { stage: undefined } as any;
148+
const where = { stage: undefined };
145149
for (const call of [
146150
() => engine.find('deal', { where }),
147151
() => engine.findOne('deal', { where }),
148152
() => engine.count('deal', { where }),
149-
() => engine.update('deal', { stage: 'x' }, { where, multi: true } as any),
150-
() => engine.delete('deal', { where, multi: true } as any),
153+
() => engine.update('deal', { stage: 'x' }, { where, multi: true }),
154+
() => engine.delete('deal', { where, multi: true }),
151155
]) {
152156
const err = await refusalOf(call());
153157
expect(err).not.toBeNull();
@@ -160,15 +164,20 @@ describe('[#7872] the comparand-type door at the engine collection point', () =>
160164
// ── the ARRAY form inherits the door through parseFilterAST ─────────────
161165

162166
it('refuses a bad comparand arriving in a FilterArray triple', async () => {
163-
const err = await refusalOf(engine.find('deal', { where: ['stage', '=', new Map()] } as any));
167+
// The cast names the contract being bypassed: `FilterArray` is INPUT-ONLY
168+
// sugar `EngineQueryOptions.where` deliberately excludes (#5285), and this
169+
// case exists to prove the lowered triple inherits the door.
170+
const err = await refusalOf(
171+
engine.find('deal', { where: ['stage', '=', new Map()] } as unknown as EngineQueryOptions),
172+
);
164173
expect(err).toMatchObject({ status: 400, code: 'INVALID_FILTER' });
165174
expect(reads).toHaveLength(0);
166175
});
167176

168177
// ── bigint: accepted, narrowed, copy-on-write ───────────────────────────
169178

170179
it('narrows an exact-range bigint before the driver — the memory crash cell dies here', async () => {
171-
const rows = await engine.find('deal', { where: { amount: { $gt: BigInt(15) } } } as any);
180+
const rows = await engine.find('deal', { where: { amount: { $gt: BigInt(15) } } });
172181
expect(rows.map((r: any) => r.id)).toEqual(['d2']);
173182
const seen = reads[0]?.ast?.where?.amount?.$gt;
174183
expect(seen).toBe(15);
@@ -177,12 +186,12 @@ describe('[#7872] the comparand-type door at the engine collection point', () =>
177186

178187
it('the narrowing is copy-on-write — the caller’s bag is not edited under them', async () => {
179188
const where = { amount: { $gt: BigInt(15) } };
180-
await engine.find('deal', { where } as any);
189+
await engine.find('deal', { where });
181190
expect(typeof where.amount.$gt).toBe('bigint');
182191
});
183192

184193
it('a clean object filter still reaches the driver untouched', async () => {
185-
await engine.find('deal', { where: { stage: 'won', amount: { $gt: 5 } } } as any);
194+
await engine.find('deal', { where: { stage: 'won', amount: { $gt: 5 } } });
186195
expect(reads[0]?.ast?.where).toEqual({ stage: 'won', amount: { $gt: 5 } });
187196
});
188197
});

0 commit comments

Comments
 (0)