Skip to content

Require db.pg statically so tree shaking can proceed - #11

Merged
yogthos merged 1 commit into
mainfrom
static-pg-require
Aug 11, 2026
Merged

Require db.pg statically so tree shaking can proceed#11
yogthos merged 1 commit into
mainfrom
static-pg-require

Conversation

@yogthos

@yogthos yogthos commented Aug 11, 2026

Copy link
Copy Markdown
Contributor

Adopts #10 by @sundbp, extended to the java.sql shim and resolved against main, which had moved underneath it.

The problem, as #10 diagnosed it

jdbc.core reached the postgres driver through (resolve (symbol "db.pg" n)) behind a runtime require. A reachable call to resolve stops jolt from building a sound whole-program call graph, so jolt build --tree-shake skipped shaking entirely for any program that loaded jdbc.core, sqlite-only ones included. A runtime require is also the wrong dependency edge for an AOT binary, which has no source roots to load db.pg from later.

The reason the indirection existed is in the comment it replaces: a compile-time db.pg/foo reference used to be read as a host class. That is no longer the case, and the namespace alias works.

What changed relative to #10

The PR conflicted because main moved: pg-placeholders now lives in db.pg and is applied inside db.pg/run, so pg-eval no longer rewrites, and execute! returns affected rows on postgres.

More importantly, db.jdbc-shim had since grown its own copy of the same pgfn trick. That one matters more than the jdbc.core one: jdbc.core is on its way out when the clojure.jdbc switchover lands, while the shim is what stays. Adopting the PR as written would have fixed the file that is being deleted and left the defect in the file that survives. Both are now static.

Verification

I checked the claim rather than the diff, since the whole point is a build-time property no unit test covers.

Before, on main:

jolt build: tree-shake skipped (reachable code resolves vars at runtime):

After:

jolt build: tree-shake kept 336 of 764 defs (core 237/659)
jolt build: dropping compiler image (no runtime eval)

and the resulting binary runs and returns rows.

The load-bearing claim is that a sqlite-only app still does not need libpq, which is easy to assert and easy to get wrong, so I tested it directly: a project whose deps.edn points :jolt/native at a libpq that does not exist builds, runs and returns {:name "ada"}. Loading db.pg only declares the bindings; ffi/defcfn resolves a symbol on first call, not on load. The stale docstrings in db.pg that promised lazy loading now say that instead.

Suite is unchanged at 91 checks, sqlite-only and against postgres 16.

Adopted from #10 by sundbp, extended to the java.sql shim and resolved against
main, which had moved underneath it.

jdbc.core reached the postgres driver through (resolve (symbol "db.pg" n)) behind
a runtime require. A reachable call to resolve stops jolt from building a sound
whole-program call graph, so jolt build --tree-shake skipped shaking entirely for
any program that loaded jdbc.core, sqlite-only ones included. A runtime require is
also the wrong edge for an AOT binary, which has no source roots to load db.pg
from later.

The reason that indirection existed was that a compile-time db.pg/foo reference
used to be read as a host class. That is no longer so, and the namespace alias
works, so both callers now require db.pg statically and call pg/connect, pg/close,
pg/exec, pg/all and pg/all-raw directly.

db.jdbc-shim had grown its own copy of the same pgfn trick, which matters more
than the jdbc.core one: jdbc.core is on its way out when the switchover lands,
while the shim is what stays. Fixing only the file in the PR would have carried
the defect into the new architecture.

A sqlite-only app still does not need libpq. Loading db.pg only declares the
bindings; ffi/defcfn resolves a symbol on first call. Checked against a project
whose deps.edn points :jolt/native at a libpq that does not exist: it builds, runs
and returns rows.

Verified the actual claim rather than the diff. Against main, jolt build
--tree-shake reports "tree-shake skipped (reachable code resolves vars at
runtime)". With this, it reports "tree-shake kept 336 of 764 defs (core 237/659)"
and the resulting binary runs.

Co-authored-by: sundbp <sundbp@users.noreply.github.com>
@yogthos
yogthos merged commit 9955782 into main Aug 11, 2026
2 of 3 checks passed
@yogthos
yogthos deleted the static-pg-require branch August 11, 2026 22:16
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