Skip to content

Add null and range predicates, variadic and/or, DISTINCT and row locks - #16

Merged
Makisuo merged 2 commits into
mainfrom
feat/predicates-distinct-locking
Oct 4, 2026
Merged

Makisuo merged 2 commits into
mainfrom
feat/predicates-distinct-locking

Conversation

@Makisuo

@Makisuo Makisuo commented Oct 4, 2026 •

Copy link
Copy Markdown
Contributor

Next items from design/gap-review.md: DISTINCT (~10 Maple sites), row locks (7), and the null and range predicates every query builder has.

.where(($) => [$.done_at.isNull(), $.id.between(lo, hi), CH.or(CH.when(name, (n) => $.name.eq(n)), undefined)])
.distinctOn("org").orderBy(["org", "asc"], ["id", "desc"])
.limit(1).forUpdate({ skipLocked: true })

What changes

  • Predicates. isNull(), isNotNull(), between() and notBetween() on every Expr. The ends of a range are encoded through the column's codec.
  • CH.and(...) / CH.or(...) take any number of conditions, skip undefined ones, write one flat group, and return undefined when none are left (which where then skips). and keeps tenant evidence; or drops it.
  • distinct() / distinctOn(...aliases) work on both dialects; ClickHouse 26.2 and 26.8 accept DISTINCT ON.
  • Row locks. forUpdate / forNoKeyUpdate / forShare / forKeyShare take { skipLocked, noWait, of } and are written after LIMIT. New optional DialectClauses.locking; ClickHouse refuses with a defect.
  • compile(query) no longer needs a params argument for a query with no params. Before this, such a call fell through to the write overload with a confusing type error.
  • Docs. The isNull docs example now uses the built-in instead of a hand-declared defineCondFn.

Testing

  • bun run typecheck and bun run test: 550 unit tests and the doc checks pass.
  • New shared core cases run on Postgres and on both ClickHouse matrix servers. The locking case must be refused on ClickHouse.
  • PGlite job-queue claim with FOR UPDATE SKIP LOCKED inside Database.transaction, plus DISTINCT ON, BETWEEN and IS NULL.
  • Live ClickHouse suite (281 tests) on 26.2.19.43 and 26.8.2.7.

🤖 Generated with Claude Code


View with [code]smith Autofix with [code]smith
Need help on this PR? Tag @codesmith-bot with what you need. Autofix is disabled.

- isNull, isNotNull, between and notBetween on every expression; the
  ends of a range are encoded through the column, like a comparison.
- CH.and / CH.or take any number of conditions, skip undefined ones,
  write one flat group, and return undefined when none are left. and
  keeps tenant evidence; or drops it, as .and / .or do.
- distinct() and distinctOn(...aliases) on queries, both dialects.
- forUpdate / forNoKeyUpdate / forShare / forKeyShare with skipLocked,
  noWait and of, written after LIMIT. DialectClauses.locking gates them;
  ClickHouse refuses at compile.
- compile(query) takes params as optional, so a query without params no
  longer falls through to the write overload with a confusing error.

Each feature runs in the shared core suite on Postgres and on both
ClickHouse matrix servers.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Oct 4, 2026 •

Copy link
Copy Markdown

Warning

Review limit reached

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

Next included review available in 22 minutes.

Check out review usage here.

View limit details

Limit details: You’ve used the included review currently available.

Learn how review limits work.

Review configuration:

⚙️ Run configuration
  • Configuration used: defaults
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: caefa5d7-2688-4d19-a55a-17d9cc63bb58
📥 Commits

Reviewing files that changed from the base of the PR and between 7e43f59 and 63b3bc7.

⛔ Files ignored due to path filters (1)
  • tests/__snapshots__/core-sql.test.ts.snap is excluded by !**/*.snap
📒 Files selected for processing (22)
  • CHANGELOG.md
  • design/gap-review.md
  • docs/expressions.md
  • docs/queries.md
  • docs/reference.md
  • scripts/check-doc-examples.mjs
  • src/ch/compile.ts
  • src/ch/dialect.ts
  • src/ch/expr.ts
  • src/ch/index.ts
  • src/ch/param.ts
  • src/ch/predicates.test.ts
  • src/ch/query.test-d.ts
  • src/ch/query.ts
  • src/database/database.test.ts
  • src/expr.ts
  • src/pg/dialect.ts
  • src/sql/sql-query.ts
  • tests/core-cases.ts
  • tests/database.clickhouse.test.ts
  • tests/dialect-cases.ts
  • tests/dialect-coverage.test.ts
  • Autopilot · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

From review: a qualified name in a lock's OF (Postgres takes only
unqualified names), a lock on a query with DISTINCT, GROUP BY or HAVING,
and a lock on a unionAll branch were all compiled and then refused by
the server; they are now QueryBuilderDefects. distinctOn() with no keys
silently became a whole-row DISTINCT; it is now a defect too.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@Makisuo
Makisuo merged commit 13eea13 into main Oct 4, 2026
4 checks passed
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.

1 participant