Skip to content

Conversation

@arv
Copy link
Contributor

@arv arv commented Dec 16, 2025

This pull request adds comprehensive tests for custom queries—defined using defineQueries and defineQuery—within both client and server transactions. It ensures that custom queries work correctly with and without validators, including support for transforming and failing validators, and verifies nested query structures. Additionally, it introduces a deterministic mockRandom utility for predictable randomness in tests.

Custom queries in transactions:

  • Added extensive tests to custom.test.ts and adapters.pg.test.ts verifying that tx.run() supports custom queries defined via defineQueries and defineQuery in both client and server transaction contexts. These tests cover cases with and without validators, including transforming and failing validators, and nested query objects. [1] [2]
  • Ensured that custom queries work seamlessly across all supported adapters (node-pg, postgresjs, and drizzle) by adding integration tests.

Test utility improvements:

  • Introduced a new mockRandom utility in mock-random.ts that uses a seeded linear congruential generator to mock Math.random() for deterministic results in tests. This integrates with Vitest's mocking system and supports automatic cleanup with the using keyword.
  • Added thorough tests for mockRandom, verifying deterministic output, integration with functions relying on randomness (including nanoid), and proper restoration of Math.random().

Type and import improvements:

  • Updated type assertions in server adapter tests to use toExtend instead of toMatchTypeOf for improved type checking. [1] [2]
  • Added missing type imports for StandardSchemaV1 in both client and server test files to support custom validator definitions. [1] [2]
  • Added necessary imports for query registry helpers in test files to enable custom query definitions. [1] [2]

@arv arv requested a review from 0xcadams December 16, 2025 14:43
@vercel
Copy link

vercel bot commented Dec 16, 2025

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Review Updated (UTC)
replicache-docs Ready Ready Preview, Comment Dec 17, 2025 9:20am
zbugs Ready Ready Preview, Comment Dec 17, 2025 9:20am

@arv
Copy link
Contributor Author

arv commented Dec 16, 2025

@0xcadams @aboodman This makes it clear to me that we need to embed the context in the Transaction so that we can pass a QueryRequest to tx.run instead of having to use addContextToQuery.

@github-actions
Copy link

github-actions bot commented Dec 16, 2025

🐰 Bencher Report

Brancharv/queries-in-transactions
TestbedLinux
Click to view all benchmark results
BenchmarkFile SizeBenchmark Result
kilobytes (KB)
(Result Δ%)
Upper Boundary
kilobytes (KB)
(Limit %)
zero-package.tgz📈 view plot
🚷 view threshold
1,773.01 KB
(0.00%)Baseline: 1,773.01 KB
1,808.47 KB
(98.04%)
zero.js📈 view plot
🚷 view threshold
240.21 KB
(0.00%)Baseline: 240.21 KB
245.01 KB
(98.04%)
zero.js.br📈 view plot
🚷 view threshold
65.96 KB
(0.00%)Baseline: 65.96 KB
67.28 KB
(98.04%)
🐰 View full continuous benchmarking report in Bencher

@github-actions
Copy link

github-actions bot commented Dec 16, 2025

🐰 Bencher Report

Brancharv/queries-in-transactions
Testbedself-hosted
Click to view all benchmark results
BenchmarkThroughputBenchmark Result
operations / second (ops/s)
(Result Δ%)
Lower Boundary
operations / second (ops/s)
(Limit %)
src/client/custom.bench.ts > big schema📈 view plot
🚷 view threshold
145,812.84 ops/s
(-77.01%)Baseline: 634,370.29 ops/s
-177,318.55 ops/s
(-121.61%)
src/client/zero.bench.ts > basics > All 1000 rows x 10 columns (numbers)📈 view plot
🚷 view threshold
2,633.47 ops/s
(+2.83%)Baseline: 2,560.93 ops/s
2,278.41 ops/s
(86.52%)
src/client/zero.bench.ts > pk compare > pk = N📈 view plot
🚷 view threshold
70,457.91 ops/s
(+8.89%)Baseline: 64,708.32 ops/s
56,750.25 ops/s
(80.54%)
src/client/zero.bench.ts > with filter > Lower rows 500 x 10 columns (numbers)📈 view plot
🚷 view threshold
4,097.18 ops/s
(+4.74%)Baseline: 3,911.62 ops/s
3,589.52 ops/s
(87.61%)
🐰 View full continuous benchmarking report in Bencher

@github-actions
Copy link

github-actions bot commented Dec 16, 2025

🐰 Bencher Report

Brancharv/queries-in-transactions
Testbedself-hosted
Click to view all benchmark results
BenchmarkThroughputBenchmark Result
operations / second (ops/s)
(Result Δ%)
Lower Boundary
operations / second (ops/s)
(Limit %)
1 exists: track.exists(album)📈 view plot
🚷 view threshold
15,010.11 ops/s
(+1.42%)Baseline: 14,800.34 ops/s
13,698.73 ops/s
(91.26%)
10 exists (AND)📈 view plot
🚷 view threshold
217,555.74 ops/s
(-0.37%)Baseline: 218,368.96 ops/s
211,917.18 ops/s
(97.41%)
10 exists (OR)📈 view plot
🚷 view threshold
4,355.61 ops/s
(+2.85%)Baseline: 4,235.09 ops/s
3,938.79 ops/s
(90.43%)
12 exists (AND)📈 view plot
🚷 view threshold
192,446.13 ops/s
(-0.15%)Baseline: 192,729.32 ops/s
184,344.19 ops/s
(95.79%)
12 exists (OR)📈 view plot
🚷 view threshold
3,681.75 ops/s
(+2.25%)Baseline: 3,600.62 ops/s
3,366.49 ops/s
(91.44%)
12 level nesting📈 view plot
🚷 view threshold
3,180.22 ops/s
(+1.39%)Baseline: 3,136.64 ops/s
2,928.93 ops/s
(92.10%)
2 exists (AND): track.exists(album).exists(genre)📈 view plot
🚷 view threshold
5,568.79 ops/s
(-0.59%)Baseline: 5,602.04 ops/s
5,213.03 ops/s
(93.61%)
3 exists (AND)📈 view plot
🚷 view threshold
2,228.93 ops/s
(+3.36%)Baseline: 2,156.39 ops/s
1,990.72 ops/s
(89.31%)
3 exists (OR)📈 view plot
🚷 view threshold
1,102.81 ops/s
(+1.59%)Baseline: 1,085.56 ops/s
1,001.31 ops/s
(90.80%)
5 exists (AND)📈 view plot
🚷 view threshold
343.60 ops/s
(+0.84%)Baseline: 340.75 ops/s
318.33 ops/s
(92.65%)
5 exists (OR)📈 view plot
🚷 view threshold
180.89 ops/s
(+0.49%)Baseline: 180.00 ops/s
167.40 ops/s
(92.54%)
Nested 2 levels: track > album > artist📈 view plot
🚷 view threshold
5,003.27 ops/s
(+3.43%)Baseline: 4,837.38 ops/s
4,508.47 ops/s
(90.11%)
Nested 4 levels: playlist > tracks > album > artist📈 view plot
🚷 view threshold
814.96 ops/s
(+2.59%)Baseline: 794.37 ops/s
741.06 ops/s
(90.93%)
Nested with filters: track > album > artist (filtered)📈 view plot
🚷 view threshold
3,981.64 ops/s
(-1.06%)Baseline: 4,024.27 ops/s
3,718.32 ops/s
(93.39%)
planned: playlist.exists(tracks)📈 view plot
🚷 view threshold
672.50 ops/s
(+2.92%)Baseline: 653.44 ops/s
623.39 ops/s
(92.70%)
planned: track.exists(album) OR exists(genre)📈 view plot
🚷 view threshold
166.73 ops/s
(-3.12%)Baseline: 172.10 ops/s
161.76 ops/s
(97.02%)
planned: track.exists(album) where title="Big Ones"📈 view plot
🚷 view threshold
7,793.14 ops/s
(-2.04%)Baseline: 7,955.83 ops/s
7,567.99 ops/s
(97.11%)
planned: track.exists(album).exists(genre)📈 view plot
🚷 view threshold
41.15 ops/s
(-1.17%)Baseline: 41.64 ops/s
40.03 ops/s
(97.28%)
planned: track.exists(album).exists(genre) with filters📈 view plot
🚷 view threshold
5,685.74 ops/s
(+0.93%)Baseline: 5,633.49 ops/s
5,340.24 ops/s
(93.92%)
planned: track.exists(playlists)📈 view plot
🚷 view threshold
4.31 ops/s
(+1.99%)Baseline: 4.23 ops/s
4.06 ops/s
(94.04%)
unplanned: playlist.exists(tracks)📈 view plot
🚷 view threshold
652.16 ops/s
(+2.81%)Baseline: 634.32 ops/s
606.27 ops/s
(92.96%)
unplanned: track.exists(album) OR exists(genre)📈 view plot
🚷 view threshold
48.66 ops/s
(+2.17%)Baseline: 47.62 ops/s
45.20 ops/s
(92.89%)
unplanned: track.exists(album) where title="Big Ones"📈 view plot
🚷 view threshold
60.20 ops/s
(+1.14%)Baseline: 59.52 ops/s
56.89 ops/s
(94.51%)
unplanned: track.exists(album).exists(genre)📈 view plot
🚷 view threshold
40.90 ops/s
(-1.30%)Baseline: 41.44 ops/s
39.79 ops/s
(97.27%)
unplanned: track.exists(album).exists(genre) with filters📈 view plot
🚷 view threshold
58.74 ops/s
(+1.42%)Baseline: 57.92 ops/s
55.65 ops/s
(94.74%)
unplanned: track.exists(playlists)📈 view plot
🚷 view threshold
4.23 ops/s
(+0.08%)Baseline: 4.23 ops/s
4.07 ops/s
(96.24%)
zpg: all playlists📈 view plot
🚷 view threshold
5.76 ops/s
(-1.08%)Baseline: 5.82 ops/s
5.69 ops/s
(98.87%)
zql: all playlists📈 view plot
🚷 view threshold
8.52 ops/s
(+6.68%)Baseline: 7.98 ops/s
6.99 ops/s
(82.09%)
zql: edit for limited query, inside the bound📈 view plot
🚷 view threshold
219,641.26 ops/s
(+0.17%)Baseline: 219,273.30 ops/s
201,717.39 ops/s
(91.84%)
zql: edit for limited query, outside the bound📈 view plot
🚷 view threshold
209,770.97 ops/s
(-8.14%)Baseline: 228,357.89 ops/s
197,825.50 ops/s
(94.31%)
zql: push into limited query, inside the bound📈 view plot
🚷 view threshold
117,136.43 ops/s
(+3.49%)Baseline: 113,189.91 ops/s
107,301.38 ops/s
(91.60%)
zql: push into limited query, outside the bound📈 view plot
🚷 view threshold
452,871.20 ops/s
(+9.11%)Baseline: 415,060.75 ops/s
360,232.26 ops/s
(79.54%)
zql: push into unlimited query📈 view plot
🚷 view threshold
361,003.09 ops/s
(+5.06%)Baseline: 343,600.08 ops/s
312,660.39 ops/s
(86.61%)
zqlite: all playlists📈 view plot
🚷 view threshold
1.92 ops/s
(+2.00%)Baseline: 1.88 ops/s
1.79 ops/s
(93.17%)
zqlite: edit for limited query, inside the bound📈 view plot
🚷 view threshold
80,538.88 ops/s
(+1.12%)Baseline: 79,650.73 ops/s
72,006.56 ops/s
(89.41%)
zqlite: edit for limited query, outside the bound📈 view plot
🚷 view threshold
82,360.82 ops/s
(+2.47%)Baseline: 80,372.74 ops/s
69,296.79 ops/s
(84.14%)
zqlite: push into limited query, inside the bound📈 view plot
🚷 view threshold
4,217.10 ops/s
(+1.95%)Baseline: 4,136.44 ops/s
3,989.83 ops/s
(94.61%)
zqlite: push into limited query, outside the bound📈 view plot
🚷 view threshold
93,880.51 ops/s
(+3.21%)Baseline: 90,956.40 ops/s
83,398.53 ops/s
(88.83%)
zqlite: push into unlimited query📈 view plot
🚷 view threshold
137,276.41 ops/s
(+5.86%)Baseline: 129,682.56 ops/s
119,433.09 ops/s
(87.00%)
🐰 View full continuous benchmarking report in Bencher


// Query all users using custom query
const allUsers = await tx.run(
addContextToQuery(customQueries.allUsers(), {}),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can't this just be customQueries.allUsers.fn({ args: {}, ctx: {} })?

@0xcadams
Copy link
Member

@0xcadams @aboodman This makes it clear to me that we need to embed the context in the Transaction so that we can pass a QueryRequest to tx.run instead of having to use addContextToQuery.

I agree it would be cleaner to add context to transactions. But the workaround of .fn({}) is a bit easier to use than the current tests.

},
]);

expect(queriedIssue).toEqual({
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: .toEqual(queriedIssues[0])

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants