ReviewOS

stacks/bun-query-builder

upsert/insertOrIgnore/insertGetId/updateOrInsert can't execute (Bun ${sql(table)} ${sql(values)} interaction + sqlite values-helper gap)

#1052
Closed glennmichael123 opened this 22 days ago · 0 comments
22 days ago

Summary

Discovered while fixing #1035: the db.upsert() / db.insertOrIgnore() / db.insertGetId() / db.updateOrInsert() methods (which build SQL via bunSql\INSERT INTO ${bunSql(table)} ${bunSql(values)} ...``) cannot execute. Three layered problems:

  1. Lazy bunSql proxy was not callable — FIXED as part of #1035 (the proxy wrapped a {} target, so bunSql\...`` threw "not a function"; target is now a function).
  2. Bun ${sql(table)} ${sql(values)} interaction (remaining): even with a working proxy, sql\INSERT INTO ${sql(table)} ${sql(values)} ON CONFLICT ...`throwsSyntaxError: Cannot INSERT with no columns on Postgres. Verified: the same statement with a *literal* table (INSERT INTO mytable ${sql(values)} ...) works, so passing the table via sql(table)adjacent to thesql(values)` helper confuses Bun's parser.
  3. SQLite sql(values) helper gap (remaining): createSQLiteSQL (the bun:sqlite wrapper in db.ts) does not implement Bun's sql(object) insert-helper form, so bunSql(values) returns an empty query on sqlite.

Impact

These helper methods are effectively broken at runtime on all dialects (each blocked by a different layer). No existing test exercises them (see #1038), which is why this went unnoticed.

Suggested fix

Rewrite the affected methods to build the INSERT explicitly (columns + dialect-aware placeholders via .unsafe), instead of relying on Bun's ${sql(table)} ${sql(values)} helper composition — which sidesteps both #2 and #3 and works uniformly across sqlite/mysql/postgres.

Found while fixing #1035 (the empty-SET SQL-generation bug, which is fixed separately).

Sign in to comment on this issue.