Skip to content

Commit 3b6b5e7

Browse files
committed
fix(objectql): make the data-event benchmark typecheck and actually collect samples
The benchmark was added after the local typecheck run, so two real errors rode into CI: - `registry.registerObject` requires a `packageId`. The sibling `.test.ts` calls it with one argument and gets away with it only because this package's tsconfig excludes `**/*.test.ts` (measured test debt); a `.bench.ts` is not excluded, so it is checked — correctly. - The package compiles to CommonJS, where the module-scope `await` used to build the engine pairs is TS1309. Hoisting setup into `beforeAll` fixes the types but breaks the benchmark: vitest's benchmark mode is experimental and does not run the hook, so every engine stayed `undefined`, every iteration threw, and the summary reported `NaNx faster` off zero samples. Uses a memoized lazy init inside the benches instead — construction lands in vitest's warmup, outside the measured samples, and the settled-promise await is paid identically by both arms. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LYnZrTwXbrctB8E8HpJAPT
1 parent 06bf084 commit 3b6b5e7

1 file changed

Lines changed: 33 additions & 10 deletions

File tree

packages/objectql/src/engine-data-events.bench.ts

Lines changed: 33 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,7 @@ async function makeEngine(withRealtime: boolean): Promise<ObjectQL> {
104104
const engine = new ObjectQL();
105105
engine.registerDriver(makeMemoryDriver(), true);
106106
await engine.init();
107-
engine.registry.registerObject(task as any);
107+
engine.registry.registerObject(task as any, 'bench');
108108
if (withRealtime) engine.setRealtimeService(nullRealtime);
109109
// Silence the per-write logger so log formatting is not in the measurement.
110110
const logger = (engine as any).logger;
@@ -136,27 +136,48 @@ async function makePair(): Promise<[ObjectQL, ObjectQL]> {
136136
return pair;
137137
}
138138

139-
const [insertOn, insertOff] = await makePair();
140-
const [updateOn, updateOff] = await makePair();
141-
const [bulkOn, bulkOff] = await makePair();
139+
/**
140+
* Memoized lazy init. Two constraints rule out the obvious alternatives:
141+
* this package compiles to CommonJS, so a top-level `await` is a TS1309 error;
142+
* and vitest's benchmark mode is experimental and does NOT run `beforeAll`, so
143+
* a hook-based setup leaves every engine `undefined`, every iteration throwing,
144+
* and the summary reporting `NaNx faster` off zero samples.
145+
*
146+
* Awaiting an already-settled promise costs one microtask, paid identically by
147+
* both arms, so the delta each case reports is unaffected — and the actual
148+
* construction happens during vitest's warmup iterations, outside the measured
149+
* samples.
150+
*/
151+
function lazyPair(): () => Promise<[ObjectQL, ObjectQL]> {
152+
let pending: Promise<[ObjectQL, ObjectQL]> | undefined;
153+
return () => (pending ??= makePair());
154+
}
155+
156+
const insertPair = lazyPair();
157+
const updatePair = lazyPair();
158+
const bulkPair = lazyPair();
142159

143160
describe('insert — per-record DataEvent (#4626)', () => {
144161
bench('with realtime service', async () => {
145-
await insertOn.insert('task', { title: 'bench', status: 'open' });
162+
const [on] = await insertPair();
163+
await on.insert('task', { title: 'bench', status: 'open' });
146164
});
147165

148166
bench('without realtime service', async () => {
149-
await insertOff.insert('task', { title: 'bench', status: 'open' });
167+
const [, off] = await insertPair();
168+
await off.insert('task', { title: 'bench', status: 'open' });
150169
});
151170
});
152171

153172
describe('single-id update — per-record DataEvent (#4626)', () => {
154173
bench('with realtime service', async () => {
155-
await updateOn.update('task', { id: 'r_1', title: 'bench' });
174+
const [on] = await updatePair();
175+
await on.update('task', { id: 'r_1', title: 'bench' });
156176
});
157177

158178
bench('without realtime service', async () => {
159-
await updateOff.update('task', { id: 'r_1', title: 'bench' });
179+
const [, off] = await updatePair();
180+
await off.update('task', { id: 'r_1', title: 'bench' });
160181
});
161182
});
162183

@@ -170,10 +191,12 @@ describe('predicate update — one aggregate BulkDataEvent (#4639)', () => {
170191
// it selects on would shrink its own match set as the bench ran, making the
171192
// two arms diverge exactly like the shared-engine bug above.
172193
bench('with realtime service', async () => {
173-
await bulkOn.update('task', { title: 'bench' }, { multi: true, where: { status: 'open' } } as any);
194+
const [on] = await bulkPair();
195+
await on.update('task', { title: 'bench' }, { multi: true, where: { status: 'open' } } as any);
174196
});
175197

176198
bench('without realtime service', async () => {
177-
await bulkOff.update('task', { title: 'bench' }, { multi: true, where: { status: 'open' } } as any);
199+
const [, off] = await bulkPair();
200+
await off.update('task', { title: 'bench' }, { multi: true, where: { status: 'open' } } as any);
178201
});
179202
});

0 commit comments

Comments
 (0)