gemi 0.54.2 → 0.54.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (166) hide show
  1. package/dist/app/index.js +2 -2
  2. package/dist/app/index.js.map +1 -1
  3. package/dist/bun/plugin.js +2 -2
  4. package/dist/bun/plugin.js.map +1 -1
  5. package/dist/bun/preload.js +2 -2
  6. package/dist/bun/preload.js.map +2 -2
  7. package/dist/chunk-1312a1t4.js +4 -0
  8. package/dist/{chunk-r9z5rrk0.js.map → chunk-1312a1t4.js.map} +2 -2
  9. package/dist/{chunk-9taz1h3t.js → chunk-1psx59jt.js} +2 -2
  10. package/dist/{chunk-9taz1h3t.js.map → chunk-1psx59jt.js.map} +1 -1
  11. package/dist/chunk-2s75crt8.js +4 -0
  12. package/dist/{chunk-07t0dmdg.js.map → chunk-2s75crt8.js.map} +2 -2
  13. package/dist/chunk-2zyharpa.js +4 -0
  14. package/dist/{chunk-hk067634.js.map → chunk-2zyharpa.js.map} +2 -2
  15. package/dist/chunk-35j03vge.js +4 -0
  16. package/dist/{chunk-br8ten26.js.map → chunk-35j03vge.js.map} +2 -2
  17. package/dist/chunk-3njyfdj5.js +19 -0
  18. package/dist/chunk-3njyfdj5.js.map +60 -0
  19. package/dist/chunk-4n0xx0y6.js +66 -0
  20. package/dist/{chunk-n382ygnp.js.map → chunk-4n0xx0y6.js.map} +4 -53
  21. package/dist/{chunk-gn9zjgep.js → chunk-5ad8era8.js} +2 -2
  22. package/dist/{chunk-gn9zjgep.js.map → chunk-5ad8era8.js.map} +1 -1
  23. package/dist/{chunk-50vm7x98.js → chunk-6c5xkj0z.js} +2 -2
  24. package/dist/{chunk-50vm7x98.js.map → chunk-6c5xkj0z.js.map} +1 -1
  25. package/dist/chunk-6yy92txx.js +9 -0
  26. package/dist/{chunk-k8endm5j.js.map → chunk-6yy92txx.js.map} +6 -6
  27. package/dist/chunk-796pyrm9.js +4 -0
  28. package/dist/{chunk-1snh7yc4.js.map → chunk-796pyrm9.js.map} +2 -2
  29. package/dist/chunk-876p591d.js +5 -0
  30. package/dist/chunk-876p591d.js.map +13 -0
  31. package/dist/chunk-95t14jaw.js +13 -0
  32. package/dist/chunk-95t14jaw.js.map +222 -0
  33. package/dist/{chunk-kz39hphm.js → chunk-97rcmaps.js} +3 -3
  34. package/dist/{chunk-kz39hphm.js.map → chunk-97rcmaps.js.map} +1 -1
  35. package/dist/{chunk-c22vcxty.js → chunk-9agd5hjw.js} +2 -2
  36. package/dist/{chunk-c22vcxty.js.map → chunk-9agd5hjw.js.map} +2 -2
  37. package/dist/chunk-9wrbnr38.js +4 -0
  38. package/dist/{chunk-c0wcsmpj.js.map → chunk-9wrbnr38.js.map} +2 -2
  39. package/dist/{chunk-sqp7kn7h.js → chunk-a1h4paj1.js} +3 -3
  40. package/dist/{chunk-sqp7kn7h.js.map → chunk-a1h4paj1.js.map} +1 -1
  41. package/dist/{chunk-r06rxn19.js → chunk-b5mc1st9.js} +2 -2
  42. package/dist/{chunk-r06rxn19.js.map → chunk-b5mc1st9.js.map} +1 -1
  43. package/dist/chunk-c6qxw3v9.js +5 -0
  44. package/dist/{chunk-f13f68c0.js.map → chunk-c6qxw3v9.js.map} +2 -2
  45. package/dist/{chunk-113khwbw.js → chunk-cbqrkfjm.js} +2 -2
  46. package/dist/{chunk-113khwbw.js.map → chunk-cbqrkfjm.js.map} +1 -1
  47. package/dist/{chunk-jp4pf3yt.js → chunk-dngwctnt.js} +4 -4
  48. package/dist/{chunk-jp4pf3yt.js.map → chunk-dngwctnt.js.map} +2 -2
  49. package/dist/{chunk-f418jh9k.js → chunk-ejrcyzx8.js} +2 -2
  50. package/dist/{chunk-f418jh9k.js.map → chunk-ejrcyzx8.js.map} +1 -1
  51. package/dist/chunk-h3b0v3bz.js +4 -0
  52. package/dist/{chunk-4qkzdyj7.js.map → chunk-h3b0v3bz.js.map} +1 -1
  53. package/dist/{chunk-jb022m7n.js → chunk-hg9y6ctt.js} +2 -2
  54. package/dist/{chunk-jb022m7n.js.map → chunk-hg9y6ctt.js.map} +1 -1
  55. package/dist/chunk-j15ewww3.js +5 -0
  56. package/dist/{chunk-2pt6kyn9.js.map → chunk-j15ewww3.js.map} +2 -2
  57. package/dist/{chunk-zckj6bs6.js → chunk-j3tzdcz7.js} +3 -3
  58. package/dist/{chunk-zckj6bs6.js.map → chunk-j3tzdcz7.js.map} +1 -1
  59. package/dist/chunk-jq46m17j.js +5 -0
  60. package/dist/{chunk-efsk1wy0.js.map → chunk-jq46m17j.js.map} +2 -2
  61. package/dist/{chunk-pgjk5ft3.js → chunk-k5jvafmh.js} +1 -1
  62. package/dist/chunk-kckva77b.js +5 -0
  63. package/dist/{chunk-dxw8k6f1.js.map → chunk-kckva77b.js.map} +2 -2
  64. package/dist/{chunk-cz3szqhq.js → chunk-ke6tsnx1.js} +2 -2
  65. package/dist/{chunk-cz3szqhq.js.map → chunk-ke6tsnx1.js.map} +1 -1
  66. package/dist/{chunk-qq2yhtpp.js → chunk-kz5zcw6s.js} +2 -2
  67. package/dist/{chunk-qq2yhtpp.js.map → chunk-kz5zcw6s.js.map} +2 -2
  68. package/dist/{chunk-h7mcwfg5.js → chunk-nakfv7pa.js} +4 -4
  69. package/dist/{chunk-h7mcwfg5.js.map → chunk-nakfv7pa.js.map} +2 -2
  70. package/dist/chunk-nph4mm6k.js +4 -0
  71. package/dist/{chunk-jb2nst6v.js.map → chunk-nph4mm6k.js.map} +2 -2
  72. package/dist/{chunk-dwx2y7br.js → chunk-r07s2p1z.js} +4 -4
  73. package/dist/{chunk-dwx2y7br.js.map → chunk-r07s2p1z.js.map} +2 -2
  74. package/dist/chunk-teyphwr0.js +5 -0
  75. package/dist/{chunk-6rhebm18.js.map → chunk-teyphwr0.js.map} +2 -2
  76. package/dist/{chunk-agabw2w1.js → chunk-tkdxv6cq.js} +2 -2
  77. package/dist/{chunk-agabw2w1.js.map → chunk-tkdxv6cq.js.map} +1 -1
  78. package/dist/chunk-v094r7tz.js +6 -0
  79. package/dist/{chunk-05edp1zf.js.map → chunk-v094r7tz.js.map} +2 -2
  80. package/dist/{chunk-3xa807p3.js → chunk-v0t5dejz.js} +2 -2
  81. package/dist/{chunk-3xa807p3.js.map → chunk-v0t5dejz.js.map} +1 -1
  82. package/dist/{chunk-f4e7fh95.js → chunk-v7y8zm61.js} +3 -3
  83. package/dist/{chunk-f4e7fh95.js.map → chunk-v7y8zm61.js.map} +2 -2
  84. package/dist/{chunk-kv2ep453.js → chunk-vj1vt6qs.js} +18 -19
  85. package/dist/{chunk-kv2ep453.js.map → chunk-vj1vt6qs.js.map} +4 -8
  86. package/dist/{chunk-71m47kad.js → chunk-wxepr09t.js} +2 -2
  87. package/dist/{chunk-71m47kad.js.map → chunk-wxepr09t.js.map} +2 -2
  88. package/dist/{chunk-efp54183.js → chunk-x1g40y59.js} +1 -1
  89. package/dist/chunk-x5w7es67.js +4 -0
  90. package/dist/{chunk-s6e7cvek.js.map → chunk-x5w7es67.js.map} +2 -2
  91. package/dist/chunk-x67dm5ef.js +5 -0
  92. package/dist/{chunk-jdgvdddd.js.map → chunk-x67dm5ef.js.map} +2 -2
  93. package/dist/{chunk-fcqc3e3r.js → chunk-xnytbrda.js} +2 -2
  94. package/dist/{chunk-fcqc3e3r.js.map → chunk-xnytbrda.js.map} +1 -1
  95. package/dist/chunk-xska2hx3.js +4 -0
  96. package/dist/{chunk-hrrmxreg.js.map → chunk-xska2hx3.js.map} +2 -2
  97. package/dist/{chunk-ms8qd7da.js → chunk-yd6aqeyc.js} +2 -2
  98. package/dist/{chunk-ms8qd7da.js.map → chunk-yd6aqeyc.js.map} +1 -1
  99. package/dist/{chunk-bb3zvxsf.js → chunk-zacf5ph0.js} +2 -2
  100. package/dist/{chunk-bb3zvxsf.js.map → chunk-zacf5ph0.js.map} +1 -1
  101. package/dist/console/run.js +2 -2
  102. package/dist/console/run.js.map +1 -1
  103. package/dist/database/DatabaseManager.d.ts.map +1 -1
  104. package/dist/database/index.js +2 -2
  105. package/dist/database/index.js.map +1 -1
  106. package/dist/email/index.js +1 -1
  107. package/dist/facades/Storage.d.ts +1 -1
  108. package/dist/facades/Storage.d.ts.map +1 -1
  109. package/dist/facades/index.js +1 -1
  110. package/dist/i18n/dictionaryRuntime.js +2 -2
  111. package/dist/i18n/dictionaryRuntime.js.map +1 -1
  112. package/dist/i18n/index.js +2 -2
  113. package/dist/i18n/index.js.map +2 -2
  114. package/dist/kernel/index.js +2 -2
  115. package/dist/kernel/index.js.map +2 -2
  116. package/dist/orm/corpus.d.ts.map +1 -1
  117. package/dist/orm/dialect/index.d.ts +32 -1
  118. package/dist/orm/dialect/index.d.ts.map +1 -1
  119. package/dist/orm/dialect/postgres.d.ts +14 -0
  120. package/dist/orm/dialect/postgres.d.ts.map +1 -1
  121. package/dist/orm/dialect/sqlite.d.ts +31 -0
  122. package/dist/orm/dialect/sqlite.d.ts.map +1 -1
  123. package/dist/orm/index.js +3 -3
  124. package/dist/orm/index.js.map +3 -3
  125. package/dist/orm/types.d.ts +82 -38
  126. package/dist/orm/types.d.ts.map +1 -1
  127. package/dist/server/index.js +2 -2
  128. package/dist/server/index.js.map +2 -2
  129. package/dist/services/email/drivers/ResendDriver.d.ts.map +1 -1
  130. package/dist/services/file-storage/drivers/S3Driver.d.ts +24 -1
  131. package/dist/services/file-storage/drivers/S3Driver.d.ts.map +1 -1
  132. package/dist/services/image-optimization/drivers/SharpDriver.d.ts.map +1 -1
  133. package/dist/services/index.js +9 -18
  134. package/dist/services/index.js.map +5 -99
  135. package/dist/services/rate-limiter/drivers/RedisRateLimiterDriver.d.ts.map +1 -1
  136. package/dist/services/redis/RedisManager.d.ts +19 -2
  137. package/dist/services/redis/RedisManager.d.ts.map +1 -1
  138. package/dist/services/router/ViewRouteDispatcher.d.ts.map +1 -1
  139. package/dist/services/router/htmlInsertionPoint.d.ts +64 -0
  140. package/dist/services/router/htmlInsertionPoint.d.ts.map +1 -0
  141. package/dist/services/router/streamQueryInjection.d.ts +10 -0
  142. package/dist/services/router/streamQueryInjection.d.ts.map +1 -1
  143. package/dist/support/sharp.d.ts +21 -0
  144. package/dist/support/sharp.d.ts.map +1 -0
  145. package/package.json +1 -1
  146. package/dist/chunk-05edp1zf.js +0 -6
  147. package/dist/chunk-07t0dmdg.js +0 -4
  148. package/dist/chunk-1snh7yc4.js +0 -4
  149. package/dist/chunk-2pt6kyn9.js +0 -5
  150. package/dist/chunk-4qkzdyj7.js +0 -4
  151. package/dist/chunk-6rhebm18.js +0 -5
  152. package/dist/chunk-br8ten26.js +0 -4
  153. package/dist/chunk-c0wcsmpj.js +0 -4
  154. package/dist/chunk-dxw8k6f1.js +0 -5
  155. package/dist/chunk-efsk1wy0.js +0 -5
  156. package/dist/chunk-f13f68c0.js +0 -5
  157. package/dist/chunk-hk067634.js +0 -4
  158. package/dist/chunk-hrrmxreg.js +0 -4
  159. package/dist/chunk-jb2nst6v.js +0 -4
  160. package/dist/chunk-jdgvdddd.js +0 -5
  161. package/dist/chunk-k8endm5j.js +0 -9
  162. package/dist/chunk-n382ygnp.js +0 -81
  163. package/dist/chunk-r9z5rrk0.js +0 -4
  164. package/dist/chunk-s6e7cvek.js +0 -4
  165. /package/dist/{chunk-pgjk5ft3.js.map → chunk-k5jvafmh.js.map} +0 -0
  166. /package/dist/{chunk-efp54183.js.map → chunk-x1g40y59.js.map} +0 -0
@@ -4,15 +4,15 @@
4
4
  "sourcesContent": [
5
5
  "// The SQL dialects Bun's `SQL` client can talk to. Bun infers the *connection*\n// from the URL protocol on its own, but it does not tell us which dialect it\n// picked — and gemi needs to know, because the SQL it generates differs per\n// dialect (`RETURNING` support, upsert syntax, autoincrement, boolean and\n// timestamp types). So we infer it a second time, here, for query generation.\nexport type Dialect = \"sqlite\" | \"postgres\" | \"mysql\" | \"mariadb\";\n\nexport class UnknownDatabaseUrlError extends Error {\n constructor(url: string) {\n super(\n `Could not infer a database dialect from \"${url}\". Expected a URL ` +\n `starting with postgres://, postgresql://, mysql://, mariadb://, ` +\n `sqlite://, or file: — or a SQLite path such as ./dev.db or :memory:.`,\n );\n this.name = \"UnknownDatabaseUrlError\";\n }\n}\n\nexport class MissingDatabaseUrlError extends Error {\n // The connection's name, when it is not the default one. A named connection\n // has no environment variable behind it and no top-level `url` to fall back\n // on, so the generic message would send whoever reads it to check\n // `DATABASE_URL`, which is set and is not what is missing.\n constructor(connection?: string) {\n super(\n connection === undefined || connection === \"default\"\n ? \"No database URL configured. Set the DATABASE_URL environment \" +\n \"variable, or set `url` in app/config/database.ts.\"\n : `The \"${connection}\" database connection has no \\`url\\`. Set one ` +\n `under \\`connections.${connection}\\` in app/config/database.ts.`,\n );\n this.name = \"MissingDatabaseUrlError\";\n }\n}\n\nconst PROTOCOLS: Record<string, Dialect> = {\n \"postgres:\": \"postgres\",\n \"postgresql:\": \"postgres\",\n \"mysql:\": \"mysql\",\n \"mariadb:\": \"mariadb\",\n \"sqlite:\": \"sqlite\",\n \"file:\": \"sqlite\",\n};\n\nconst SQLITE_FILE_EXTENSIONS = [\".db\", \".sqlite\", \".sqlite3\"];\n\n// Infer the dialect from a connection string. Accepts every form Bun's `SQL`\n// accepts, including the bare SQLite paths (`./dev.db`, `:memory:`) that have no\n// protocol at all.\n//\n// Note this deliberately does NOT default to postgres the way `new SQL(...)`\n// does. Guessing the dialect wrong means generating SQL that fails at runtime\n// against a database that connected fine, which is a far more confusing failure\n// than refusing to guess.\nexport function inferDialect(url: string): Dialect {\n const trimmed = url.trim();\n\n if (trimmed === \"\") {\n throw new UnknownDatabaseUrlError(url);\n }\n\n // `:memory:` is SQLite's in-memory database. It looks like a protocol to\n // `new URL()` but isn't one, so it has to be checked before parsing.\n if (trimmed === \":memory:\") {\n return \"sqlite\";\n }\n\n const separator = trimmed.indexOf(\":\");\n if (separator !== -1) {\n const protocol = trimmed.slice(0, separator + 1).toLowerCase();\n const dialect = PROTOCOLS[protocol];\n if (dialect) {\n return dialect;\n }\n }\n\n // No recognised protocol. Bun treats a bare path as a SQLite file, so we do\n // too — but only when it actually looks like one, rather than treating every\n // unrecognised string as SQLite.\n if (looksLikeSqlitePath(trimmed)) {\n return \"sqlite\";\n }\n\n throw new UnknownDatabaseUrlError(url);\n}\n\nfunction looksLikeSqlitePath(value: string): boolean {\n if (value.startsWith(\"./\") || value.startsWith(\"../\") || value.startsWith(\"/\")) {\n return true;\n }\n const lower = value.toLowerCase();\n return SQLITE_FILE_EXTENSIONS.some((extension) => lower.endsWith(extension));\n}\n\n// True when the dialect stores a SQLite database, i.e. a local file rather than\n// a networked server. Callers use this to decide whether `db:setup` should\n// create a file, and which DDL flavour to emit.\nexport function isSqlite(dialect: Dialect): boolean {\n return dialect === \"sqlite\";\n}\n\n// MariaDB is wire-compatible with MySQL and takes the same SQL in everything\n// gemi generates, so query builders collapse the two.\nexport function isMysqlFamily(dialect: Dialect): boolean {\n return dialect === \"mysql\" || dialect === \"mariadb\";\n}\n",
6
6
  "import { SQL } from \"bun\";\nimport type { ConnectionConfig } from \"./config\";\nimport { MissingDatabaseUrlError, inferDialect, type Dialect } from \"./dialect\";\n\n/**\n * The name of the connection an application gets without asking for one: the\n * `url` / `options` pair at the top level of `app/config/database.ts`.\n *\n * A constant rather than the string spelled at each site, because it is\n * compared in five places across three layers — the manager resolving a name,\n * the ORM deciding whether a query names a different pool than the open\n * transaction, and the facade — and a typo in any one of them reads as \"that\n * connection is not configured\" rather than as a typo.\n */\nexport const DEFAULT_CONNECTION = \"default\";\n\n/**\n * What every layer above `database/` is allowed to know about a connection.\n *\n * `DatabaseManager` implements this itself and *is* the default connection —\n * see the note on `DatabaseManager.connection`. So this interface is the one\n * shape the ORM and the `DB` facade read, whether they are looking at the\n * default pool or at a named one, and neither has to branch on which it got.\n */\nexport interface DatabaseConnection {\n /** `\"default\"`, or the key this connection was declared under. */\n readonly name: string;\n readonly url: string;\n readonly dialect: Dialect;\n readonly sql: SQL;\n readonly ready: Promise<void>;\n readonly config: ConnectionConfig;\n}\n\n/** A connection named in the config that the manager has no pool for. */\nexport class UnknownConnectionError extends Error {\n constructor(name: string, known: readonly string[]) {\n super(\n `No database connection named \"${name}\". Configured: ` +\n `${known.map((one) => `\"${one}\"`).join(\", \")}. Declare it under ` +\n `\\`connections\\` in app/config/database.ts.`,\n );\n this.name = \"UnknownConnectionError\";\n }\n}\n\n/**\n * A `connections` entry that would shadow the top-level `url`.\n *\n * Refused rather than merged, because the two spellings would be a silent\n * either/or: whichever the manager happened to build last would win, and the\n * losing half of the config would go on describing a pool nothing uses.\n */\nexport class ReservedConnectionNameError extends Error {\n constructor(name: string) {\n super(\n `\"${name}\" is the name of the connection declared by the top-level ` +\n `\\`url\\` and \\`options\\`, so it cannot also appear under ` +\n `\\`connections\\`. Rename it, or move its settings up to the top level.`,\n );\n this.name = \"ReservedConnectionNameError\";\n }\n}\n\n/**\n * A statement that named one connection while a transaction was open on\n * another.\n *\n * **The whole reason named connections refuse rather than route.** A\n * transaction lives on one reserved connection of one pool; there is no\n * mechanism by which a second pool's statement could join it, and no rollback\n * that could take it back. So the alternatives to this error are both worse\n * than an error:\n *\n * - Run it on the other pool anyway, *outside* the transaction. The caller\n * wrote `Model.transaction`, the block rolls back, and that one statement\n * stays committed. Half the work landed and nothing said so.\n * - Run it on the open handle, ignoring the name. Then the statement went to\n * the wrong database, which the ORM cannot even detect afterwards — the\n * tables are usually the same shape.\n *\n * There is no third answer at this layer; two-phase commit is not what a second\n * pool for analytics is asking for. So the failure is made loud and early, at\n * the call that would have straddled the two, and the fix is always the same\n * shape: move that query outside the transaction, or do the whole unit on one\n * connection.\n */\nexport class CrossConnectionTransactionError extends Error {\n constructor(\n /** The connection the open transaction belongs to. */\n public readonly open: string,\n /** The connection the refused statement named. */\n public readonly requested: string,\n ) {\n super(\n `A transaction is open on the \"${open}\" connection, and this statement ` +\n `names \"${requested}\". A transaction cannot span two connections: ` +\n `the statement would run outside it and stay committed when the ` +\n `transaction rolls back. Move this query outside the transaction, or ` +\n `run the whole unit on one connection.`,\n );\n this.name = \"CrossConnectionTransactionError\";\n }\n}\n\n/**\n * One pool: a URL, its dialect, and Bun's client for it.\n *\n * Extracted from `DatabaseManager` when a second connection became\n * configurable (#327). The manager kept the lifecycle — which names exist, how\n * they are resolved, closing them all — and this kept everything that is true\n * of a connection *one at a time*, so the two do not have to be written twice.\n *\n * Safe to build eagerly, like the manager it came from: Bun's client connects\n * on the first query, not at construction. A named connection an application\n * declares and never queries therefore costs an object.\n */\nexport class Connection implements DatabaseConnection {\n public readonly sql: SQL;\n public readonly dialect: Dialect;\n public readonly url: string;\n\n /**\n * Resolves once the connection has been configured, or rejects if it could\n * not be. Only SQLite has anything to do; elsewhere it is already resolved.\n *\n * Exposed so a caller that needs the guarantee can wait for it. Nothing has\n * to: SQLite queues statements on one connection in the order they were\n * issued, so the pragma below is ahead of anything a caller sends after the\n * constructor returns. That ordering is asserted in `DatabaseManager.test.ts`\n * rather than assumed, because it is the load-bearing half.\n */\n public readonly ready: Promise<void>;\n\n constructor(\n public readonly name: string,\n public readonly config: ConnectionConfig = {},\n ) {\n const url = config.url;\n if (!url) {\n throw new MissingDatabaseUrlError(name);\n }\n\n this.url = url;\n // An explicit `dialect` wins, for URLs whose protocol we can't read (a\n // pooler on a custom scheme). Otherwise infer, which throws rather than\n // guessing — see the note in dialect.ts.\n this.dialect = config.dialect ?? inferDialect(url);\n this.sql = config.options\n ? new SQL(url, config.options as any)\n : new SQL(url);\n this.ready = this.configure();\n }\n\n /**\n * `pragma foreign_keys = ON`, which SQLite leaves **off** by default — and so\n * does Bun's driver, which reports `0` on a fresh connection.\n *\n * Without it SQLite enforces nothing at all. Not \"cascades do not fire\":\n * nothing. An insert naming a parent that does not exist is accepted, a\n * dangling reference survives the parent's deletion, and `ON DELETE RESTRICT`\n * does not restrict — while the migrations declare all three. Postgres\n * enforces them always, and Prisma turns the pragma on for every SQLite\n * connection it opens, so leaving it off meant development and production\n * disagreed about whether the schema's constraints were real.\n *\n * It is also why this is more than a dialect gap. The differential harness\n * compares gemi against Prisma on one database per dialect; with the pragma\n * off on one side, the two were being asked to agree while running under\n * different integrity rules, so an entire class of divergence was invisible\n * to the instrument rather than merely untested.\n *\n * **Per connection, not per database**, which is what makes this a live\n * assumption rather than a one-line fix: Bun serves SQLite from a single\n * connection today, so setting it once holds for every later statement. If\n * that ever becomes a pool, one statement's worth of enforcement would move\n * to whichever connection happened to serve it. `DatabaseManager.test.ts`\n * pins both halves — the value, and that it is the same across concurrent\n * queries — so the day it changes is a failing test rather than a silent\n * regression.\n *\n * That per-connection wording is now literal in a second sense: a named\n * SQLite connection is a *different* Bun client, so it needs the pragma of\n * its own. Running it from this constructor is what makes that automatic —\n * the alternative, doing it once for the default connection, was correct\n * exactly while there was only one.\n *\n * Issued outside any transaction. SQLite documents the pragma as a no-op\n * inside one, so a lazy \"set it on first use\" would be correct exactly until\n * the first use happened to be a transaction.\n */\n private async configure(): Promise<void> {\n if (this.dialect !== \"sqlite\") return;\n await this.sql.unsafe(\"pragma foreign_keys = ON\");\n }\n\n // Escape hatch matching Bun's own API, so `connection.query` reads like `sql`\n // does in Bun's docs: connection.query`select * from users where id = ${id}`\n get query(): SQL {\n return this.sql;\n }\n\n async close(): Promise<void> {\n // A close that races the constructor's `pragma` leaves that statement to\n // settle against a client that is going away, and it settles as a rejection\n // — `ERR_SQLITE_CONNECTION_CLOSED`, from a promise nobody is holding, which\n // arrives as an unhandled rejection naming neither the close nor the\n // pragma. The caller asked for this connection to go away, so that\n // rejection is expected rather than something to surface. Marked handled\n // here rather than suppressed globally, and only on the way out.\n this.ready.catch(() => {});\n await this.sql.close();\n }\n}\n",
7
- "import type { SQL } from \"bun\";\nimport type { ConnectionConfig, DatabaseConfig } from \"./config\";\nimport {\n Connection,\n DEFAULT_CONNECTION,\n ReservedConnectionNameError,\n UnknownConnectionError,\n type DatabaseConnection,\n} from \"./Connection\";\nimport type { Dialect } from \"./dialect\";\n\n// Wraps Bun's `SQL` client. Bun ships one client that speaks SQLite, Postgres,\n// MySQL and MariaDB, so gemi does not need a driver per database — it needs to\n// know *which* one is in use, which is what `dialect` carries.\n//\n// Like `RedisManager`, this is safe to build eagerly: Bun's client connects on\n// the first query, not at construction. It is still bound as a lazy singleton,\n// so an app that never touches the database never resolves it and never has to\n// have DATABASE_URL set.\n//\n// Since #327 it holds *connections*, plural: the top-level `url` and `options`\n// build the one called `\"default\"`, and each key under `connections` builds\n// another. What it does not do is decide which one a query uses — that is the\n// ORM's ambient scope and the `DB` facade, because the choice is per query\n// rather than per application. See `connection` below.\nexport class DatabaseManager implements DatabaseConnection {\n static token = \"database\";\n\n /**\n * This object *is* the default connection, so it answers to the name.\n *\n * Not a formality: `connection(\"default\")` returns `this` rather than the\n * `Connection` in the map, which is what keeps every existing reader —\n * `DB.sql`, `db.dialect`, and the test harnesses that wrap the manager in a\n * Proxy to count statements — looking at the same object the ORM executes\n * through. A second object for the default pool would have quietly bypassed\n * all of them while every test still passed.\n */\n public readonly name = DEFAULT_CONNECTION;\n\n /**\n * Every pool this manager owns, keyed by name and including the default one.\n *\n * Private because the map is the manager's bookkeeping — `connection()` is\n * the way in, and it is the only path that knows the default is `this`.\n */\n private readonly pools = new Map<string, Connection>();\n\n /**\n * Resolves once **every** connection has been configured, or rejects if one\n * could not be. Only SQLite has anything to do; elsewhere it is already\n * resolved.\n *\n * All of them rather than the default alone, because the thing a caller waits\n * on this for — SQLite's `pragma foreign_keys` — is per client, so a second\n * SQLite connection has its own and a caller awaiting one manager-level\n * promise means all of them.\n */\n public readonly ready: Promise<void>;\n\n constructor(public config: DatabaseConfig = {}) {\n const { connections = {}, ...primary } = config;\n\n // The default first, so a `MissingDatabaseUrlError` from a missing\n // `DATABASE_URL` still comes out of construction the way it always has,\n // rather than after a named connection has already opened a client.\n this.pools.set(\n DEFAULT_CONNECTION,\n new Connection(DEFAULT_CONNECTION, primary),\n );\n\n // A connection that is built before the one whose config is wrong is still\n // a live client with an open handle, and on the throwing path nothing else\n // will ever hold it: the manager never becomes a value, so nobody can call\n // `close`. Left alone, the pragma this constructor issues for a SQLite\n // connection settles against a client being torn down and surfaces as an\n // unhandled rejection with no configuration error anywhere near it.\n try {\n this.build(connections, primary.slowTransactionThreshold);\n } catch (error) {\n for (const pool of this.pools.values()) {\n // The in-flight configuration first: it is what rejects when the client\n // under it goes away, and this is the only place that can say the\n // rejection was expected.\n pool.ready.catch(() => {});\n pool.close().catch(() => {});\n }\n throw error;\n }\n\n // Built once here rather than derived per read, so that a connection whose\n // configuration rejects produces one unhandled rejection at most instead of\n // a fresh one per access.\n this.ready = Promise.all(\n [...this.pools.values()].map((pool) => pool.ready),\n ).then(() => undefined);\n }\n\n private build(\n connections: Record<string, ConnectionConfig>,\n slowTransactionThreshold: number | false | undefined,\n ): void {\n for (const [name, connection] of Object.entries(connections)) {\n if (name === DEFAULT_CONNECTION)\n throw new ReservedConnectionNameError(name);\n\n this.pools.set(\n name,\n new Connection(name, {\n // The threshold is the one setting a named connection is likely to\n // want *unchanged*: it is a development diagnostic about holding a\n // pooled connection, and that concern does not stop applying because\n // the pool has a name. `url`, `options` and `dialect` are deliberately\n // not inherited — a connection that borrowed the default's URL by\n // omission would be a second pool onto the same database created by a\n // typo in a key.\n slowTransactionThreshold,\n ...connection,\n }),\n );\n }\n }\n\n /**\n * The connection called `name`, or the default one when called with nothing.\n *\n * Throws rather than falling back to the default for an unknown name, and\n * that is the important half. A fallback would make `Model.on(\"analitycs\")`\n * run on the hot path — the exact pool the caller was trying to stay off —\n * and the only symptom would be the incident it was meant to prevent,\n * arriving weeks later with nothing pointing back at the typo.\n */\n connection(name: string = DEFAULT_CONNECTION): DatabaseConnection {\n // `this`, not `pools.get(DEFAULT_CONNECTION)` — see `name` above.\n if (name === DEFAULT_CONNECTION) return this;\n\n const found = this.pools.get(name);\n if (!found) throw new UnknownConnectionError(name, this.connectionNames);\n return found;\n }\n\n /** Every configured name, default first. For error messages and diagnostics. */\n get connectionNames(): string[] {\n return [...this.pools.keys()];\n }\n\n /**\n * The default connection's client. Unchanged in meaning: an application that\n * never names a connection sees exactly what it saw before #327.\n */\n get sql(): SQL {\n return this.default.sql;\n }\n\n get dialect(): Dialect {\n return this.default.dialect;\n }\n\n get url(): string {\n return this.default.url;\n }\n\n // Escape hatch matching Bun's own API, so `db.query` reads like `sql` does in\n // Bun's docs: db.query`select * from users where id = ${id}`\n get query(): SQL {\n return this.sql;\n }\n\n /** Closes every connection, not only the default one. */\n async close(): Promise<void> {\n // The aggregate promise needs the same treatment each connection's own\n // `ready` gets in `Connection.close` — it is derived from them, so a\n // rejection there arrives here as a second, separately unhandled one.\n this.ready.catch(() => {});\n await Promise.all([...this.pools.values()].map((pool) => pool.close()));\n }\n\n private get default(): Connection {\n return this.pools.get(DEFAULT_CONNECTION)!;\n }\n}\n",
7
+ "import type { SQL } from \"bun\";\nimport type { ConnectionConfig, DatabaseConfig } from \"./config\";\nimport {\n Connection,\n DEFAULT_CONNECTION,\n ReservedConnectionNameError,\n UnknownConnectionError,\n type DatabaseConnection,\n} from \"./Connection\";\nimport type { Dialect } from \"./dialect\";\n\n// Wraps Bun's `SQL` client. Bun ships one client that speaks SQLite, Postgres,\n// MySQL and MariaDB, so gemi does not need a driver per database — it needs to\n// know *which* one is in use, which is what `dialect` carries.\n//\n// Safe to build eagerly: Bun's client connects on the first query, not at\n// construction. (`RedisManager` used to be cited here as the parallel case. As\n// of #403 it builds its client in a memoizing getter instead — not because\n// eager construction was unsafe, but because naming Bun's `RedisClient` at\n// module scope is what made `gemi/services` unloadable off Bun. `Connection`\n// still imports `SQL` as a value for the same reason, which is the remaining\n// half of #396.) It is still bound as a lazy singleton,\n// so an app that never touches the database never resolves it and never has to\n// have DATABASE_URL set.\n//\n// Since #327 it holds *connections*, plural: the top-level `url` and `options`\n// build the one called `\"default\"`, and each key under `connections` builds\n// another. What it does not do is decide which one a query uses — that is the\n// ORM's ambient scope and the `DB` facade, because the choice is per query\n// rather than per application. See `connection` below.\nexport class DatabaseManager implements DatabaseConnection {\n static token = \"database\";\n\n /**\n * This object *is* the default connection, so it answers to the name.\n *\n * Not a formality: `connection(\"default\")` returns `this` rather than the\n * `Connection` in the map, which is what keeps every existing reader —\n * `DB.sql`, `db.dialect`, and the test harnesses that wrap the manager in a\n * Proxy to count statements — looking at the same object the ORM executes\n * through. A second object for the default pool would have quietly bypassed\n * all of them while every test still passed.\n */\n public readonly name = DEFAULT_CONNECTION;\n\n /**\n * Every pool this manager owns, keyed by name and including the default one.\n *\n * Private because the map is the manager's bookkeeping — `connection()` is\n * the way in, and it is the only path that knows the default is `this`.\n */\n private readonly pools = new Map<string, Connection>();\n\n /**\n * Resolves once **every** connection has been configured, or rejects if one\n * could not be. Only SQLite has anything to do; elsewhere it is already\n * resolved.\n *\n * All of them rather than the default alone, because the thing a caller waits\n * on this for — SQLite's `pragma foreign_keys` — is per client, so a second\n * SQLite connection has its own and a caller awaiting one manager-level\n * promise means all of them.\n */\n public readonly ready: Promise<void>;\n\n constructor(public config: DatabaseConfig = {}) {\n const { connections = {}, ...primary } = config;\n\n // The default first, so a `MissingDatabaseUrlError` from a missing\n // `DATABASE_URL` still comes out of construction the way it always has,\n // rather than after a named connection has already opened a client.\n this.pools.set(\n DEFAULT_CONNECTION,\n new Connection(DEFAULT_CONNECTION, primary),\n );\n\n // A connection that is built before the one whose config is wrong is still\n // a live client with an open handle, and on the throwing path nothing else\n // will ever hold it: the manager never becomes a value, so nobody can call\n // `close`. Left alone, the pragma this constructor issues for a SQLite\n // connection settles against a client being torn down and surfaces as an\n // unhandled rejection with no configuration error anywhere near it.\n try {\n this.build(connections, primary.slowTransactionThreshold);\n } catch (error) {\n for (const pool of this.pools.values()) {\n // The in-flight configuration first: it is what rejects when the client\n // under it goes away, and this is the only place that can say the\n // rejection was expected.\n pool.ready.catch(() => {});\n pool.close().catch(() => {});\n }\n throw error;\n }\n\n // Built once here rather than derived per read, so that a connection whose\n // configuration rejects produces one unhandled rejection at most instead of\n // a fresh one per access.\n this.ready = Promise.all(\n [...this.pools.values()].map((pool) => pool.ready),\n ).then(() => undefined);\n }\n\n private build(\n connections: Record<string, ConnectionConfig>,\n slowTransactionThreshold: number | false | undefined,\n ): void {\n for (const [name, connection] of Object.entries(connections)) {\n if (name === DEFAULT_CONNECTION)\n throw new ReservedConnectionNameError(name);\n\n this.pools.set(\n name,\n new Connection(name, {\n // The threshold is the one setting a named connection is likely to\n // want *unchanged*: it is a development diagnostic about holding a\n // pooled connection, and that concern does not stop applying because\n // the pool has a name. `url`, `options` and `dialect` are deliberately\n // not inherited — a connection that borrowed the default's URL by\n // omission would be a second pool onto the same database created by a\n // typo in a key.\n slowTransactionThreshold,\n ...connection,\n }),\n );\n }\n }\n\n /**\n * The connection called `name`, or the default one when called with nothing.\n *\n * Throws rather than falling back to the default for an unknown name, and\n * that is the important half. A fallback would make `Model.on(\"analitycs\")`\n * run on the hot path — the exact pool the caller was trying to stay off —\n * and the only symptom would be the incident it was meant to prevent,\n * arriving weeks later with nothing pointing back at the typo.\n */\n connection(name: string = DEFAULT_CONNECTION): DatabaseConnection {\n // `this`, not `pools.get(DEFAULT_CONNECTION)` — see `name` above.\n if (name === DEFAULT_CONNECTION) return this;\n\n const found = this.pools.get(name);\n if (!found) throw new UnknownConnectionError(name, this.connectionNames);\n return found;\n }\n\n /** Every configured name, default first. For error messages and diagnostics. */\n get connectionNames(): string[] {\n return [...this.pools.keys()];\n }\n\n /**\n * The default connection's client. Unchanged in meaning: an application that\n * never names a connection sees exactly what it saw before #327.\n */\n get sql(): SQL {\n return this.default.sql;\n }\n\n get dialect(): Dialect {\n return this.default.dialect;\n }\n\n get url(): string {\n return this.default.url;\n }\n\n // Escape hatch matching Bun's own API, so `db.query` reads like `sql` does in\n // Bun's docs: db.query`select * from users where id = ${id}`\n get query(): SQL {\n return this.sql;\n }\n\n /** Closes every connection, not only the default one. */\n async close(): Promise<void> {\n // The aggregate promise needs the same treatment each connection's own\n // `ready` gets in `Connection.close` — it is derived from them, so a\n // rejection there arrives here as a second, separately unhandled one.\n this.ready.catch(() => {});\n await Promise.all([...this.pools.values()].map((pool) => pool.close()));\n }\n\n private get default(): Connection {\n return this.pools.get(DEFAULT_CONNECTION)!;\n }\n}\n",
8
8
  "import type { SQL } from \"bun\";\nimport type { Dialect } from \"./dialect\";\n\n// One connection: a URL, the dialect to compile for, and the pool behind it.\n//\n// Split out of `DatabaseConfig` when a second connection became configurable\n// (#327), so that a named connection is described by exactly the same fields\n// the default one is — rather than by a smaller, second-class shape that would\n// need widening the first time somebody's analytics pool needed a `dialect`\n// override or a threshold of its own.\nexport interface ConnectionConfig {\n // Connection string. Defaults to the `DATABASE_URL` environment variable.\n // The dialect is inferred from it — `postgres://`, `mysql://`, `mariadb://`,\n // `sqlite://`, `file:`, or a SQLite path like `./dev.db` or `:memory:`.\n url?: string;\n\n // Override the inferred dialect. Only needed when the URL doesn't carry a\n // recognisable protocol — a proxy or connection pooler fronting Postgres on a\n // custom scheme, say. Wrong values here produce SQL that fails at runtime\n // against a database that connected fine, so leave it unset unless inference\n // actually gets it wrong.\n dialect?: Dialect;\n\n // Options passed straight through to Bun's `SQL` client (pool size, timeouts,\n // TLS, ...). See https://bun.sh/docs/api/sql.\n options?: Record<string, unknown>;\n\n // How long a transaction may run, in milliseconds, before development warns\n // that it is still holding a pooled connection. `false` turns the warning off.\n //\n // A diagnostic, not a limit: nothing here cancels or shortens a transaction.\n // It only fires in development — the cost of a long transaction is paid by\n // unrelated queries blocking on connection acquisition, and that is a problem\n // worth catching while the callback is still in front of you.\n //\n // Raise it for a seed script or a data migration whose transactions are\n // legitimately long; `false` if the noise is not worth it at all. A value\n // that is not a positive finite number falls back to the 2s default rather\n // than disabling, so the warning cannot be lost to a typo — say `false` when\n // you mean off.\n //\n // Per connection, and this is the field most likely to differ between two of\n // them: a connection that exists *because* its queries are slow will warn on\n // every transaction it opens if it inherits the hot path's threshold, and a\n // warning that always fires is one nobody reads. A named connection that\n // does not set it inherits the top-level value.\n slowTransactionThreshold?: number | false;\n}\n\n// Config key: `database`.\n//\n// The top-level `url` / `options` / `dialect` describe the connection called\n// `\"default\"` — the one every query uses unless it says otherwise. `connections`\n// declares the others.\nexport interface DatabaseConfig extends ConnectionConfig {\n // Additional connections, keyed by the name `DB.connection(name)` and\n // `Model.on(name)` take.\n //\n // The case this exists for is two pools against **one** database with\n // opposite workloads — a hot path that must never block, and an analytics\n // path whose queries legitimately run for seconds:\n //\n // export default defineDatabaseConfig({\n // url: process.env.DATABASE_URL,\n // options: { max: 12 },\n //\n // connections: {\n // analytics: {\n // url: process.env.DATABASE_URL,\n // options: { max: 3, idleTimeout: 60, connectionTimeout: 45 },\n // slowTransactionThreshold: 60_000,\n // },\n // },\n // })\n //\n // A value that protects one of those is the wrong value for the other, which\n // is the entire reason they cannot be one pool with one setting. The same URL\n // twice is normal here and is not a mistake: what differs is the pool, not\n // the database.\n //\n // Two consequences worth knowing before declaring one, both of them\n // structural rather than incidental:\n //\n // - **A transaction cannot span two connections.** A statement that names one\n // while a transaction is open on another raises\n // `CrossConnectionTransactionError` rather than quietly running outside the\n // transaction.\n // - **Every connection is a real pool**, counted separately against whatever\n // connection cap the server or the pooler enforces. Two pools of 12 is 24\n // connections, not 12.\n connections?: Record<string, ConnectionConfig>;\n}\n\nexport function defineDatabaseConfig(config: DatabaseConfig): DatabaseConfig {\n return config;\n}\n\nexport function databaseConfigDefaults(): DatabaseConfig {\n return {\n url: process.env.DATABASE_URL,\n dialect: undefined,\n options: undefined,\n slowTransactionThreshold: SLOW_TRANSACTION_THRESHOLD,\n connections: undefined,\n };\n}\n\n// The default warning threshold, in milliseconds. Exported so the ORM can fall\n// back to the same number when a `DatabaseManager` was built without going\n// through `withDefaults` — a test constructing one directly, say — rather than\n// keeping a second copy of it that can drift.\nexport const SLOW_TRANSACTION_THRESHOLD = 2_000;\n\nexport type { SQL };\n",
9
9
  "import type { SqlDialect } from \"../dialect\";\nimport { ParameterLimitError } from \"../errors\";\n\n/**\n * Pulls one value out of the argument tree at bind time. Compilation closes\n * over the *path* to a value, never the value itself — that is what makes two\n * calls with the same argument shape and different values produce byte\n * identical SQL, and it is what the plan cache depends on.\n *\n * Writes add a second source: values that do not exist in the argument tree at\n * all. A `@default(cuid())` is minted per call, `@default(now())` has to be the\n * *same* instant across every field and row of one logical operation, and a\n * nested `create` produces a foreign key only once its own insert has run. All\n * three arrive through the context rather than through `args`, so the binder\n * stays a pure function of (arguments, call) and compilation stays pure.\n */\nexport type Binder = (args: any, context: BindContext) => unknown;\n\n/**\n * Per-call state a binder may read. Created once per `$exec`, never cached with\n * the plan — a plan outlives the call, and `now` must not.\n */\nexport interface BindContext {\n /**\n * One instant for the whole operation. Prisma returns `createdAt` and\n * `updatedAt` from a single `create` as the same instant (verified against\n * 6.19.2), which reading the clock per field would not reproduce.\n */\n now: Date;\n /**\n * Values produced before the main statement runs, keyed by field name. Today\n * that is exactly the foreign keys a nested `connect` or `create` resolved.\n */\n resolved: Record<string, unknown>;\n}\n\nexport function createBindContext(): BindContext {\n return { now: new Date(), resolved: {} };\n}\n\n/**\n * The default context for a read. Reads never consult it, but `bind` takes one\n * argument on every path so the choke point does not have to branch.\n */\nconst READ_CONTEXT: BindContext = { now: new Date(0), resolved: {} };\n\n/** Turns a compiled binder list into a plan's `bind`. */\nexport function bindValues(\n binders: Binder[],\n): (args: any, context?: BindContext) => unknown[] {\n return (args: any, context: BindContext = READ_CONTEXT) => {\n const values: unknown[] = [];\n for (let i = 0; i < binders.length; i++) {\n values.push(binders[i](args, context));\n }\n return values;\n };\n}\n\n/**\n * Marks a parameter position inside a fragment's text. Placeholders are only\n * rendered once the whole statement is assembled, because Postgres numbers them\n * (`$1`, `$2`) and the number is not knowable until a fragment's position in\n * the final statement is fixed. A sentinel rather than a shared mutable counter\n * is what lets fragments compose in any order without corrupting parameter\n * ordering.\n *\n * NUL cannot appear in an identifier from the schema and never appears in the\n * keywords the compiler emits, so it cannot collide with real text.\n */\nconst PARAM_MARKER = \"\\u0000\";\n\nexport interface Fragment {\n text: string;\n binders: Binder[];\n}\n\n/** A fragment with no parameters: keywords, quoted identifiers, punctuation. */\nexport function sql(text: string): Fragment {\n return { text, binders: [] };\n}\n\n/**\n * A single parameter position, bound from the argument tree at call time.\n *\n * `cast` is SQL appended immediately after the placeholder — `$1::text::jsonb`.\n * It rides as ordinary text rather than as a parallel array because the marker\n * is replaced in place at render, so text following it needs no bookkeeping and\n * cannot fall out of step with the binders.\n *\n * Only a dialect may supply one, and only from a constant: it is the one string\n * here that reaches the statement without being a parameter. See\n * `castParameter`.\n */\nexport function param(binder: Binder, cast = \"\"): Fragment {\n return { text: PARAM_MARKER + cast, binders: [binder] };\n}\n\n/**\n * A fragment's text cut at every parameter: `segments[i]` is the text that\n * precedes parameter `i`, and `segments[i + 1]` the text that follows it. The\n * inverse is `fromParamSegments`.\n *\n * It exists so that one caller — `renderFragment` — can read *what the author\n * wrote next to a parameter* before placeholders are assigned. A `::jsonb` a\n * caller wrote onto their own placeholder is the only thing that says a raw\n * parameter is JSON, and it is only readable here, in the marker's own\n * coordinates; after `render` the text holds `$1` and the segment boundaries\n * are gone.\n *\n * Nothing in the compiler uses this. A plan's casts come from the dialect and\n * are already correct, and re-deriving them from text would be a second,\n * weaker source for something the schema already answers.\n */\nexport function paramSegments(fragment: Fragment): string[] {\n return fragment.text.split(PARAM_MARKER);\n}\n\n/** `paramSegments` reversed: the segments woven back around the markers. */\nexport function fromParamSegments(\n segments: readonly string[],\n binders: Binder[],\n): Fragment {\n return { text: segments.join(PARAM_MARKER), binders };\n}\n\nexport function concat(...parts: Fragment[]): Fragment {\n return joinFragments(parts, \"\");\n}\n\nexport function joinFragments(parts: Fragment[], separator: string): Fragment {\n let text = \"\";\n const binders: Binder[] = [];\n for (let i = 0; i < parts.length; i++) {\n if (i > 0) text += separator;\n text += parts[i].text;\n for (const binder of parts[i].binders) binders.push(binder);\n }\n return { text, binders };\n}\n\n/**\n * Replace every parameter marker with the dialect's placeholder for its\n * position. Runs once per compiled plan, never per call.\n */\nexport function render(\n fragment: Fragment,\n dialect: SqlDialect,\n /**\n * Where the statement came from, for the parameter-ceiling error.\n *\n * Required, and deliberately so. Optional would reintroduce in miniature the\n * hole this check exists to close — a new call site that omits it skips the\n * ceiling silently, which is the same failure as a per-compiler guard, one\n * level down. Making it required is the difference between a convention and\n * something `tsc` enforces. A test that wants to render bare can pass\n * `{ model: \"test\", operation: \"test\" }`.\n */\n origin: { model: string; operation: string },\n): { text: string; binders: Binder[] } {\n const segments = fragment.text.split(PARAM_MARKER);\n const count = segments.length - 1;\n\n if (count !== fragment.binders.length) {\n // Unreachable unless a fragment was built by hand with a mismatched count.\n // Worth an assertion rather than a subtly misaligned parameter array.\n throw new Error(\n `Compiled ${count} parameter placeholders but collected ` +\n `${fragment.binders.length} binders.`,\n );\n }\n\n // The parameter ceiling, checked here because this is the one place that\n // knows a *statement's* final count — and because a guard at any single\n // compiler is a guard the next compiler forgets.\n //\n // It started life inside `compileCreateMany`, on the reasoning that\n // `rows × columns` was the only count that scaled with the caller's data.\n // That was wrong: on SQLite an `in` list binds one placeholder per element,\n // so `findMany({ where: { id: { in: <40 000 ids> } } })` walks into the same\n // driver error, and such a list is routinely request-derived. The relation\n // loader has the same shape, batching an `in` over the parent keys — so a\n // large `findMany` with an `include` reaches it without anyone writing a big\n // list by hand. Postgres is unaffected either way: `= any($1)` is one\n // parameter however long the array.\n //\n // Compile-time is exact rather than approximate, on both dialects: where the\n // length changes the placeholder count it also changes the SQL text, so it is\n // already part of the plan's identity.\n if (count > dialect.maxBoundParameters) {\n throw new ParameterLimitError(\n origin.model,\n origin.operation,\n count,\n dialect.maxBoundParameters,\n dialect.name,\n dialect.bindsListAsOneParameter\n ? `That is one parameter per value in the statement.`\n : `That is one parameter per value, and on ${dialect.name} each ` +\n `element of an 'in' list counts separately.`,\n );\n }\n\n let text = segments[0];\n for (let i = 0; i < count; i++) {\n text += dialect.placeholder(i) + segments[i + 1];\n }\n\n return { text, binders: fragment.binders };\n}\n",
10
- "import type { Dialect } from \"../../database/dialect\";\nimport {\n type Binder,\n type Fragment,\n concat,\n param,\n sql,\n} from \"../compile/fragment\";\nimport { DecodeError } from \"../errors\";\nimport type { FieldSchema, ScalarType } from \"../schema\";\nimport type { ConstraintViolation, SqlDialect } from \"./index\";\n\n// Postgres has real `timestamptz`, `boolean`, `numeric` and `jsonb` types, so\n// its driver already returns what Prisma returns and `decode` is almost\n// entirely a pass-through. That asymmetry with SQLite is the point: the same\n// query returns the same JavaScript values on both dialects, which is exactly\n// what the differential harness checks.\nexport class PostgresDialect implements SqlDialect {\n readonly name: Dialect = \"postgres\";\n\n // `ilike`. Note this makes the *default* `contains` case-*sensitive* here and\n // case-insensitive on SQLite, because SQLite's `like` is ASCII-insensitive\n // and has no way to opt out. Prisma has the same split; gemi matches Prisma\n // per dialect rather than inventing a uniformity Prisma does not have.\n readonly supportsInsensitiveMode = true;\n\n // `= any($1)`: one parameter, one SQL text, one plan for every list length.\n readonly bindsListAsOneParameter = true;\n\n readonly supportsReturning = true;\n\n // The wire protocol's Bind message carries the parameter count as an int16,\n // so 65535 is the ceiling for any client, not a Bun or a server setting. Past\n // it the driver's error names neither the model nor the cause.\n readonly maxBoundParameters = 65535;\n\n // The server describes the statement and Bun encodes to the type it is told,\n // which is why a `::jsonb` on the placeholder changes what a JS string means.\n // See `json-param.ts`.\n readonly typesParametersFromStatement = true;\n\n quoteIdent(name: string): string {\n // See the SQLite implementation: NUL is the parameter sentinel in\n // compile/fragment.ts, so it is the one character that could shift a\n // placeholder's position rather than merely produce broken SQL.\n if (name.includes(\"\\u0000\")) {\n throw new Error(\n `Refusing to quote the identifier ${JSON.stringify(name)}: it contains ` +\n `a NUL byte, which is reserved as the parameter marker.`,\n );\n }\n return `\"${name.replace(/\"/g, '\"\"')}\"`;\n }\n\n placeholder(index: number): string {\n return `$${index + 1}`;\n }\n\n // The whole array binds to a single parameter, so every list length shares one\n // SQL text — one plan cache entry and one prepared statement, instead of one\n // per distinct length the way SQLite needs. That matters more from iteration 3\n // on, where every batched relation query is an `in` over the parent keys and\n // the list length is the *number of parent rows*.\n //\n // The array is serialized to a Postgres array literal rather than handed over\n // as a JS array: Bun's driver rejects an array bound to a `= any($1)`\n // parameter outright — `insufficient data left in message` for numbers,\n // `malformed array literal` for strings. It is still one bound parameter and\n // still never touches the SQL text, so nothing about the injection story or\n // the plan cache changes.\n inList(\n lhs: string,\n negated: boolean,\n _length: number,\n values: Binder,\n ): Fragment {\n const operator = negated ? \"<> all\" : \"= any\";\n return concat(\n sql(`${lhs} ${operator} (`),\n param((args, context) => arrayLiteral(values(args, context) as unknown[])),\n sql(\")\"),\n );\n }\n\n /**\n * The SQL type each Prisma scalar takes inside an `unnest` cast.\n *\n * **Deliberately not the whole table.** Only the types a composite join key\n * realistically uses are here, and anything else falls back to the portable\n * `OR` rather than being guessed at — the cast has to round-trip the value\n * exactly, and a wrong one is silently wrong rows rather than an error.\n *\n * `DateTime` is the instructive absence: Prisma maps it to `timestamp(3)`,\n * and this driver's own note records that a zoneless timestamp decodes\n * differently depending on which protocol the statement used. Putting that\n * through a text array literal adds a second representation question to one\n * that is already open, for a key type nobody joins on.\n */\n private static readonly COMPOSITE_IN_TYPES: Partial<\n Record<ScalarType, string>\n > = {\n Int: \"int\",\n BigInt: \"bigint\",\n String: \"text\",\n Boolean: \"boolean\",\n };\n\n canBindCompositeIn(types: readonly ScalarType[]): boolean {\n return (\n types.length > 0 &&\n types.every((type) => PostgresDialect.COMPOSITE_IN_TYPES[type])\n );\n }\n\n /**\n * `(a, b) in (select * from unnest($1::int[], $2::text[]))`.\n *\n * **One parameter per column, not per parent**, which is the whole point:\n * the text is fixed however many tuples arrive, so a batched composite\n * `include` is one plan entry rather than one per parent count (#97). The\n * `OR` it replaces costs a placeholder per field *per parent* and a plan key\n * per length.\n *\n * The tuples arrive row-wise — one array per parent — and are transposed\n * here, because that is the shape the loader has and the shape `unnest`\n * needs. Serialized as Postgres array literals for the reason `inList`\n * already documents: this driver rejects a JS array bound against an array\n * parameter, and the literal is still one bound value that never touches the\n * SQL text.\n */\n compositeIn(\n columns: readonly string[],\n types: readonly ScalarType[],\n values: Binder,\n ): Fragment {\n const arrays = columns.map((_column, index) =>\n concat(\n param((args, context) =>\n arrayLiteral(\n (values(args, context) as unknown[][]).map((tuple) => tuple[index]),\n ),\n ),\n sql(`::${PostgresDialect.COMPOSITE_IN_TYPES[types[index]]}[]`),\n ),\n );\n\n return concat(\n sql(`(${columns.join(\", \")}) in (select * from unnest(`),\n ...arrays.flatMap((array, index) =>\n index === 0 ? [array] : [sql(\", \"), array],\n ),\n sql(\"))\"),\n );\n }\n\n /**\n * Everything Prisma exposes on a scalar list, because `text[]` can express\n * all of it (#300).\n *\n * `equals` is in the set even though it is compiled by the generic `equals`\n * path rather than by a method here: the set is what the compiler consults to\n * decide whether a list filter is *available at all*, and leaving it out\n * would make `{ tags: [\"a\"] }` — the bare-array shorthand — refuse itself on\n * the one dialect that can serve it.\n */\n readonly listFilters: ReadonlySet<string> = new Set([\n \"equals\",\n \"has\",\n \"hasEvery\",\n \"hasSome\",\n \"isEmpty\",\n ]);\n\n /**\n * `$1 = any(\"tags\")` — the element on the left, which is the mirror of\n * {@link inList} and worth not confusing with it. There, one column is\n * matched against a caller's list; here, one caller value is matched against\n * a column that *is* a list.\n *\n * No cast is added *here*, in this method or the three below. An untyped\n * array literal resolves against the column's own element type in every one\n * of these positions — measured through Bun 1.3.14 against Postgres 16 on\n * `text[]`, `jsonb[]`, `bytea[]`, `timestamp(3)[]` and an `enum[]`. That is\n * not merely convenient: an explicit cast would have to *name* the element\n * type, and for an enum that name is the database's own enum type, which the\n * generated artifact does not carry. Leaning on inference is what lets enum\n * lists work without widening the artifact.\n *\n * **The operand is a `Fragment`, not a `Binder`**, and `Json` is why. A\n * single element of a `Json[]` still needs #209's `::text::jsonb`, and it\n * needs the serialisation that travels with it — so the parameter is built by\n * `fieldParam` before it gets here, and this method only picks the operator.\n * Measured, because every wrong form fails *silently*:\n *\n * $1 = any(docs) {\"a\":1} -> false\n * $1::jsonb = any(docs) {\"a\":1} -> false\n * $1::text::jsonb = any(docs) {\"a\":1} -> true\n *\n * No error on either of the first two. A dialect that built its own parameter\n * here would have to restate `fieldParam`'s rule, and the version that\n * restated it slightly wrong would return \"no rows\" rather than raising.\n */\n listHas(column: string, value: Fragment): Fragment {\n return concat(value, sql(` = any(${column})`));\n }\n\n /** `\"tags\" @> $1` — containment: every element of the operand is present. */\n listHasEvery(column: string, values: Fragment): Fragment {\n return concat(sql(`${column} @> `), values);\n }\n\n /** `\"tags\" && $1` — overlap: at least one element is shared. */\n listHasSome(column: string, values: Fragment): Fragment {\n return concat(sql(`${column} && `), values);\n }\n\n /**\n * `\"tags\" = $1` against the empty array, rather than `cardinality(…) = 0`.\n *\n * The two are equivalent on a non-null column — and a scalar list cannot be\n * null, since Prisma refuses `String[]?` — including on the NULL case, where\n * both yield NULL and so exclude the row.\n *\n * The comparison is the one that keeps the invariant `FALSE` is spelled\n * `false` for: **no digit reaches the SQL text outside an identifier**. A\n * literal `0` would be the first, for a constant the compiler already knows —\n * which is exactly the exception `jsonNullComparison` declines to make.\n */\n listIsEmpty(column: string, empty: boolean): Fragment {\n return concat(\n sql(`${column} ${empty ? \"=\" : \"<>\"} `),\n param(() => arrayLiteral([])),\n );\n }\n\n /**\n * `array_cat(\"tags\", $1)` — the right-hand side of a `push`.\n *\n * **`array_cat` rather than `||`**, and the difference is not stylistic.\n * `||` is overloaded `anyarray || anyarray` *and* `anyarray || anyelement`,\n * so an untyped parameter beside it is genuinely ambiguous — and Prisma's\n * `push` accepts both a single element and a list, which is precisely the\n * pair that would resolve differently. `array_cat` has one signature, so the\n * compiler can normalise `push` to an array once and the operator cannot be\n * read the other way.\n */\n listPush(column: string, values: Fragment): Fragment {\n return concat(sql(`array_cat(${column}, `), values, sql(\")\"));\n }\n\n /** `path: [\"a\", \"b\"]`, where SQLite takes `\"$.a.b\"`. Prisma's own split. */\n readonly jsonPathSyntax = \"array\" as const;\n\n /** Everything, which is what `jsonb` can express and Prisma exposes here. */\n readonly jsonFilters: ReadonlySet<string> = new Set([\n \"equals\",\n \"not\",\n \"string_contains\",\n \"string_starts_with\",\n \"string_ends_with\",\n \"array_contains\",\n \"lt\",\n \"lte\",\n \"gt\",\n \"gte\",\n ]);\n\n /** `#>>` yields `text`, so a comparison binds the value's text form. */\n readonly jsonComparesAsText = true;\n\n /**\n * `\"col\" #> $1` for the JSON value, `#>>` for its text.\n *\n * Both take the path as a **`text[]` parameter**, which is the whole reason\n * this is expressible without bending invariant 2 — the one place a caller's\n * value decides part of an expression's meaning, and it still never reaches\n * the SQL text. The array is serialized the same way `inList` serializes\n * one, for the same driver reason.\n */\n jsonExtract(column: string, path: Binder, asText: boolean): Fragment {\n return concat(\n sql(`${column} ${asText ? \"#>>\" : \"#>\"} `),\n param((args, context) => arrayLiteral(path(args, context) as unknown[])),\n );\n }\n\n /**\n * `(\"col\" #> $1) @> $2` — containment, which is what Prisma's\n * `array_contains` compiles to and why it accepts both a scalar and a list:\n * `@>` asks whether the left document contains the right one, and a bare\n * value is a one-element containment test.\n */\n jsonArrayContains(column: string, path: Binder, value: Binder): Fragment {\n return concat(\n sql(\"(\"),\n this.jsonExtract(column, path, false),\n sql(\") @> \"),\n // **Raw, not `JSON.stringify`d**, and the cast is what makes that safe.\n // Bun already encodes a parameter bound against `jsonb` as JSON, so\n // stringifying first sends the *string* `\"[\\\"a\\\"]\"` rather than the\n // array — containment then asks whether a JSON array contains a JSON\n // string spelling of itself, which is `false`. No error, no rows.\n // Measured through the driver:\n //\n // raw scalar \"a\" -> true\n // raw array [\"a\"] -> true\n // JSON.stringify([\"a\"]) -> false <- what this used to send\n // raw number 3 -> cannot cast type integer to jsonb\n //\n // The last line is why the cast is explicit and the value is normalised:\n // a number has to become JSON text for the driver to type it as `jsonb`\n // at all.\n param((args, context) => {\n const raw = value(args, context);\n if (raw === null || raw === undefined) return null;\n return typeof raw === \"string\" || typeof raw === \"object\"\n ? raw\n : JSON.stringify(raw);\n }),\n sql(\"::jsonb\"),\n );\n }\n\n like(lhs: string, insensitive: boolean, pattern: Binder): Fragment {\n return concat(\n sql(`${lhs} ${insensitive ? \"ilike\" : \"like\"} `),\n param(pattern),\n );\n }\n\n // `on conflict do nothing` with no target: it covers every unique constraint\n // and the primary key at once, which is what `skipDuplicates` means — Prisma\n // names no conflict target either. A targeted `on conflict (col)` would skip\n // rows that collide on that column and still fail on any other constraint,\n // which is the plausible wrong version.\n //\n // Rows it skips are absent from `RETURNING`, so the `{ count }` the compiler\n // builds from the returned rows is the number *inserted* rather than the\n // number supplied — which is the part the issue flags as most likely to be\n // got wrong, and it falls out rather than needing a second count.\n ignoreConflicts(): Fragment {\n return sql(\" on conflict do nothing\");\n }\n\n // Unlike SQLite, Postgres accepts `offset` on its own, so neither clause has\n // to be invented to satisfy the other.\n paginate(take: Binder | null, skip: Binder | null): Fragment {\n const parts: Fragment[] = [];\n if (take) parts.push(concat(sql(\" limit \"), param(take)));\n if (skip) parts.push(concat(sql(\" offset \"), param(skip)));\n return concat(...parts);\n }\n\n // Postgres reports a duplicate key as SQLSTATE 23505, and unlike SQLite it\n // carries structured fields alongside the message. Read off a live server\n // through Bun rather than from the Postgres manual, because the placement is\n // the surprise:\n //\n // name: 'PostgresError'\n // code: 'ERR_POSTGRES_SERVER_ERROR' <- Bun's own code, not the SQLSTATE\n // errno: '23505' <- the SQLSTATE lives here\n // constraint: 'User_email_key'\n // detail: 'Key (email)=(a@x) already exists.'\n // table: 'User'\n //\n // Checking `code` alone — the obvious reading, and the one this started with\n // — matches nothing at all, so every unique violation escaped as a raw driver\n // error. Both are consulted now: `errno` is where Bun puts it today, and\n // `code` is where a driver following the `pg` convention would.\n //\n // The class code `23` covers integrity violations generally — 23502 not-null,\n // 23503 foreign key, 23514 check — so matching the *full* five characters is\n // what keeps those from being reported as duplicate keys.\n //\n // Only the constraint name is taken as authoritative. `detail` is parsed\n // best-effort for the column list because Postgres localises it: on a server\n // with `lc_messages` set to anything but English the prefix is not `Key`, and\n // the regex simply does not match. That degrades to a violation with no\n // columns — still typed, still catchable, still naming the constraint — rather\n // than to a wrong column list.\n constraintViolation(error: unknown): ConstraintViolation | null {\n const source = error as Record<string, unknown> | null;\n if (!source) return null;\n\n const sqlstate = String(source.errno ?? source.code ?? \"\");\n if (sqlstate !== \"23505\") return null;\n\n const constraint =\n typeof source.constraint === \"string\" && source.constraint !== \"\"\n ? source.constraint\n : undefined;\n\n const detail = typeof source.detail === \"string\" ? source.detail : \"\";\n const listed = /\\((.+?)\\)=/.exec(detail);\n const columns = listed\n ? listed[1]\n .split(\",\")\n .map((entry) => entry.trim())\n .filter((entry) => entry !== \"\")\n : [];\n\n return { kind: \"unique\", columns, constraint };\n }\n\n // `$1::text::jsonb` for a `Json` column, nothing for a scalar list, and\n // nothing for anything else. A scalar `Date`, `boolean` or `bigint` binds\n // natively and needs neither a cast nor an encoder — which is why `encode`\n // below reads `field` for exactly two questions and passes everything else\n // through.\n //\n // The value is serialised by `fieldParam`, not by `encode` below, so a\n // binding site that does not ask for the cast still binds raw and keeps the\n // loud failure rather than acquiring a silent mis-store. The comment on\n // `encode` has the measurements.\n castParameter(field: FieldSchema): string {\n // A list is bound as an array literal and needs no cast in any position it\n // can occupy — see `listHas` for the measurements. Checked *before* the\n // `Json` branch rather than after, because a `Json[]` would otherwise take\n // it and bind `$1::text::jsonb` against a `jsonb[]` column, which is a type\n // error rather than a wrong answer. The order is the whole check.\n if (field.isList) return \"\";\n return field.type === \"Json\" ? \"::text::jsonb\" : \"\";\n }\n\n encode(value: unknown, field: FieldSchema): unknown {\n if (value === null || value === undefined) return null;\n\n // A scalar list crosses as one Postgres array literal, which is the same\n // trick `inList` and `compositeIn` already use for a bound array: still one\n // parameter, still nothing in the SQL text.\n //\n // `Json` is the element type that needs work here rather than in\n // `fieldParam`, and it is not the exception it looks like. `fieldParam`'s\n // rule is that the cast and the serialisation travel together; a list emits\n // *no* cast, because the array literal already carries the element's text\n // form and Postgres casts each element to the column's element type. So\n // serialising a `Json` element here is what makes the literal well-formed,\n // not a second place doing `fieldParam`'s job.\n if (field.isList) {\n // Not an `InvalidArgumentError`: the compiler validates every list\n // operand where the model and operation are in scope to name them, so a\n // non-array arriving here reports an ORM bug rather than a caller's —\n // the same call `fieldParam` makes about a stray `AnyNull`.\n if (!Array.isArray(value)) {\n throw new Error(\n `gemi ORM bug: a non-array reached the parameter binder for the ` +\n `scalar list '${field.column}' (received ${typeof value}). Every ` +\n `path that binds a list is supposed to have checked its operand.`,\n );\n }\n return arrayLiteral(\n field.type === \"Json\"\n ? value.map((element) =>\n element === null || element === undefined\n ? null\n : JSON.stringify(element),\n )\n : value,\n );\n }\n // **`Json` is handed over raw**, because Bun serializes it for a `jsonb`\n // parameter and doing it here first is the mirror of the decode bug beside\n // it: `JSON.stringify({a:1})` produces the *string* `{\"a\":1}`, and Bun then\n // stores that as the JSON string `\"{\\\"a\\\":1}\"` rather than as an object.\n //\n // The two used to cancel: encode over-serialized, decode re-parsed, and the\n // round trip looked right as long as nothing else read the column. What it\n // could not survive was a value that is legitimately a JSON *string* —\n // `\"42\"` went in as the number 42 — and nothing noticed, because the\n // template's schema had no `Json` column for the differential harness to\n // compare.\n //\n // Measured through Bun 1.3.14 against Postgres 16: an object, an array, a\n // string and null all round-trip identically when bound raw.\n //\n // A bare number or boolean is the one shape Bun binds as its own type, so\n // it now raises — `column is of type jsonb but expression is of type\n // boolean`. That reads like a regression and is not one: under the old\n // encoder `42` was stored as the jsonb **string** `\"42\"` (checked with\n // `jsonb_typeof`, which answered `string` for a number, a boolean and an\n // object alike). It only looked correct because the old decoder re-parsed\n // it on the way out — so the value was wrong in the database the whole\n // time, and anything reading that column *other than this ORM* saw a\n // string. A loud failure replaces a silent mis-store.\n //\n // **Fixed, in the compiler rather than here** — see `compile/cast.ts`. The\n // placeholder carries `::text::jsonb` and `fieldParam` serialises the value\n // to match, which is the only one of the four forms measured that carries\n // all six shapes:\n //\n // values ($1) 42 integer vs jsonb\n // values ($1::jsonb) \"42\" jsonb_typeof -> string\n // values (to_jsonb($1)) {a:1} could not determine polymorphic type\n // values ($1::text::jsonb) \"42\" jsonb_typeof -> number\n //\n // The serialisation deliberately does **not** live here. `encode` runs at\n // every binding site, and a site that serialises without also emitting the\n // cast is the second row above — the silent mis-store this whole comment is\n // about. Keeping the two together in `fieldParam` means a site nobody\n // converted still binds raw and still fails loudly.\n //\n // **The second row is also what a raw statement hits**, and there the cast\n // is the caller's rather than the dialect's: `payload || $1::jsonb` is a\n // Prisma port's spelling, and under Bun it appends the serialised text to an\n // array instead of merging. `json-param.ts` retypes it, on the same\n // reasoning and with the cast and the serialisation kept together for the\n // same reason.\n //\n return value;\n }\n\n // Nothing to do without a field: the only conversion `encode` makes here is\n // the JSON one, and that is precisely the one that needs the column's\n // declared type to be legitimate. `Date`, `boolean`, `bigint` and arrays all\n // bind natively, which is why a raw fragment is portable across the two\n // dialects even though only SQLite has to normalise anything.\n //\n // A parameter the caller cast to `json`/`jsonb` never arrives here: it has a\n // declared type after all, and `renderFragment` binds it as JSON text.\n encodeUntyped(value: unknown): unknown {\n return value;\n }\n\n // Postgres returns real `timestamptz`, `boolean` and `double precision`, so\n // most columns need nothing. Two do, and neither is reachable from the\n // template's schema — which is why they went unnoticed until a fixture with\n // every scalar type existed. Read off a live server through Bun:\n //\n // integer -> number ✓\n // double precision -> number ✓\n // boolean -> boolean ✓\n // text -> string ✓\n // timestamp(3) -> Date ✓ (but see the protocol note below)\n // bytea -> Buffer ✗ where Prisma gives a plain Uint8Array\n // bigint -> \"123\" ✗ string, where Prisma gives 123n\n // jsonb / json -> '{\"a\":1}' ✗ unparsed text, where Prisma gives an object\n //\n // The `bytea` line carried a ✓ and the parenthetical \"a Uint8Array, which is\n // what Prisma gives\". Both halves are true and the conclusion was still wrong:\n // a `Buffer` *is* a `Uint8Array`, so the type checks out, but it is not the\n // one Prisma returns and it does not behave the same. Checked against a\n // generated Prisma 6 client on both dialects rather than reasoned about —\n // Prisma returns a plain `Uint8Array` for `Bytes` everywhere.\n //\n // `numeric` also arrives as a string, which is the correct thing for it to\n // do — but `Decimal` is refused at *generation* time (iteration 1), so no\n // such field can reach this.\n needsDecode(field: FieldSchema): boolean {\n // `Json` is deliberately absent: Bun hands back a parsed JSON value, so\n // `decode` returns it unchanged, and this predicate documents itself as\n // \"false when the driver already returns exactly what Prisma would\" — which\n // is now exactly true. Leaving it in cost a function call per Json value on\n // every read for nothing.\n //\n // **Every list is decoded**, including a `String[]` whose elements the\n // driver already hands back correctly. Three separate reasons, and the\n // first alone settles it: the *container* is wrong for two element types\n // regardless of the elements — `int[]` arrives as an `Int32Array`, and an\n // `enum[]` arrives as an unparsed `{…}` literal — so a predicate that\n // answered per element type would have to encode which container Bun picks\n // for which Postgres type, which is a table nothing keeps in step. Second,\n // `int[]`'s container differs *by protocol*: `Int32Array` when the\n // statement binds a parameter, a plain `Array` when it does not. Third, the\n // cost is one call per list value, not per element.\n return field.isList === true || field.type === \"BigInt\" || field.type === \"Bytes\";\n }\n\n decode(value: unknown, field: FieldSchema): unknown {\n if (value === null || value === undefined) return null;\n if (field.isList) return this.decodeList(value, field);\n return this.decodeScalar(value, field);\n }\n\n /**\n * One array column, element by element.\n *\n * **Three container shapes arrive here**, all measured through Bun 1.3.14\n * against Postgres 16 rather than read off a driver's documentation:\n *\n * text[] float8[] bool[] timestamp[] bytea[] jsonb[] bigint[] -> Array\n * int[] -> Int32Array\n * enum[] domain[] -> \"{a,b}\"\n *\n * The third is the surprise and the reason this is not four lines: Bun has no\n * decoder for an array whose element type it does not recognise, so it hands\n * the **Postgres array output literal back as a string** — and every enum\n * list is in that case. `real[]` is the same story as `int[]` with a\n * `Float32Array`, which is why the typed-array branch is written against\n * `ArrayBuffer.isView` rather than against `Int32Array` by name.\n *\n * `int[]`'s container also depends on the *protocol*: a statement that binds\n * at least one parameter goes over the extended protocol and yields an\n * `Int32Array`, one that binds none yields a plain `Array`. Same column, same\n * row, two shapes — so this cannot be decided once and cached.\n *\n * Elements then go through {@link decodeScalar}, which is the same function\n * the scalar path uses. That is what makes `BigInt[]` exact and `Bytes[]` a\n * `Uint8Array[]` rather than a `Buffer[]` without restating either rule.\n */\n private decodeList(value: unknown, field: FieldSchema): unknown {\n const elements = Array.isArray(value)\n ? value\n : typeof value === \"string\"\n ? parseArrayLiteral(value, field)\n : ArrayBuffer.isView(value)\n ? Array.from(value as unknown as ArrayLike<unknown>)\n : null;\n\n if (elements === null) throw new DecodeError(field, value);\n\n return elements.map((element) =>\n element === null || element === undefined\n ? null\n : this.decodeScalar(element, field),\n );\n }\n\n private decodeScalar(value: unknown, field: FieldSchema): unknown {\n switch (field.type) {\n case \"BigInt\":\n if (typeof value === \"bigint\") return value;\n try {\n return BigInt(value as string);\n } catch {\n throw new DecodeError(field, value);\n }\n case \"Json\":\n // **Bun parses `json` and `jsonb` for us**, so there is nothing to do.\n // Measured against Postgres 16 through Bun 1.3.14, one row per shape:\n //\n // '{\"a\":1}' -> object '[]' -> object (array)\n // '\"42\"' -> string '42' -> number\n // '\"text\"' -> string 'null' -> null\n //\n // This used to read `typeof value === \"string\" ? JSON.parse(value) :\n // value`, on the reasoning that jsonb \"arrives as text\" and that the\n // `typeof` check would cope either way. It does not cope, and cannot:\n // **a JS string is ambiguous** between \"raw JSON text the driver did\n // not parse\" and \"a JSON string value the driver did parse\", and the\n // two are indistinguishable by inspection. So the guard silently\n // re-parsed legitimate string values — a column holding the JSON string\n // `\"42\"` came back as the *number* 42, `\"true\"` as a boolean, and\n // `\"{\\\"a\\\":1}\"` as an object. `\"text\"` survived only because\n // `JSON.parse` threw and the catch handed the value back.\n //\n // Found by adding a `Json` column to the template schema: the\n // differential harness had never seen one, and every unit test that\n // \"covered\" this was written against the same assumption as the code.\n return value;\n case \"Bytes\":\n // The driver hands back a `Buffer`; Prisma 6 returns a `Uint8Array`,\n // on **every** dialect, and so does this ORM on SQLite where the\n // driver's own value already is one. Returning the `Buffer` verbatim\n // therefore diverged from Prisma and from our own SQLite path at the\n // same time — and `Buffer` being a `Uint8Array` subclass is exactly\n // what made it invisible: it satisfies the generated type, survives\n // `ArrayBuffer.isView`, and compares equal element by element.\n //\n // What it does not survive is `toString`. `Buffer.prototype.toString`\n // takes an encoding; `Uint8Array.prototype.toString` ignores its\n // argument and joins with commas. So `row.digest.toString(\"hex\")` read\n // `\"0102ff\"` in production on Postgres and `\"1,2,255\"` in development\n // on SQLite, with no error on either.\n //\n // A view, not a copy: same bytes, same lifetime, no allocation.\n return Buffer.isBuffer(value)\n ? new Uint8Array(value.buffer, value.byteOffset, value.byteLength)\n : value;\n default:\n return value;\n }\n }\n\n // KNOWN DIVERGENCE, and not one this can fix: Prisma maps `DateTime` to\n // `timestamp(3)` — no time zone — and stores UTC in it, but Bun's driver\n // decodes that column differently depending on the *protocol* the statement\n // used. A query that binds no parameters goes over the simple query protocol\n // and comes back as zoneless text, which is then parsed as local time; a\n // query that binds even one parameter goes over the extended protocol, comes\n // back in binary, and is correct. Same row, same column, two instants, on any\n // machine whose clock is not already UTC.\n //\n // select \"createdAt\" from \"User\" limit 1 -> 10:26:40Z\n // select \"createdAt\" from \"User\" where \"id\" = $1 -> 12:26:40Z\n // select \"createdAt\"::text from \"User\" limit 1 -> 12:26:40\n //\n // A `decode` cannot correct it, because the value alone does not say which\n // protocol produced it; nothing below the plan does. Until it is fixed\n // upstream, run the process with TZ=UTC, where both paths agree.\n //\n // Note this is why `DateTime` stays out of `needsDecode` above: there is no\n // correction to apply, only a caveat to record.\n}\n\n/**\n * `[1, 2]` -> `{\"1\",\"2\"}`: Postgres' text form for an array value.\n *\n * Every element is quoted, including numbers and booleans — Postgres casts a\n * quoted element to the array's element type, so one rule covers every column\n * type instead of a per-type branch that has to stay in step with `encode`.\n * `NULL` is the one thing that cannot be quoted, since `\"NULL\"` is the string.\n *\n * Verified against a real database for `int`, `text` (with quotes, commas,\n * braces, backslashes and newlines in the value), `timestamp`, `boolean`,\n * `bigint` past 2^53, `bytea` and `double precision`.\n */\nfunction arrayLiteral(values: unknown[]): string {\n let out = \"{\";\n for (let i = 0; i < values.length; i++) {\n if (i > 0) out += \",\";\n out += arrayElement(values[i]);\n }\n return out + \"}\";\n}\n\nfunction arrayElement(value: unknown): string {\n if (value === null || value === undefined) return \"NULL\";\n\n // ISO 8601 keeps the value's own UTC wall clock, which is what Prisma stores\n // in a `timestamp(3)`; the zone designator is ignored on the way in.\n if (value instanceof Date) return `\"${value.toISOString()}\"`;\n\n if (ArrayBuffer.isView(value)) {\n let hex = \"\";\n for (const byte of new Uint8Array(\n value.buffer,\n value.byteOffset,\n value.byteLength,\n )) {\n hex += byte.toString(16).padStart(2, \"0\");\n }\n // `\\x…` is Postgres' hex bytea form, and the backslash is doubled because\n // the array literal parser reads one level of escapes first.\n return `\"\\\\\\\\x${hex}\"`;\n }\n\n const text = typeof value === \"string\" ? value : String(value);\n return `\"${text.replace(/\\\\/g, \"\\\\\\\\\").replace(/\"/g, '\\\\\"')}\"`;\n}\n\n/**\n * `{a,\"b,c\",NULL}` -> `[\"a\", \"b,c\", null]`: the same form, read back.\n *\n * **Only reached for an array type Bun has no decoder for**, which today means\n * an `enum[]` or a `domain[]` — everything else arrives as a JS array and never\n * comes near this. That is why it exists at all: an enum list is the one scalar\n * list a Prisma schema is *likely* to declare, and it is precisely the one the\n * driver hands back as text.\n *\n * Splitting on commas is wrong and looks right, which is the whole reason this\n * is a state machine. Postgres quotes an element only when it has to, and then\n * escapes `\"` and `\\` inside the quotes — so a label containing a comma, a\n * brace, a quote or a backslash all survive the output format and none of them\n * survive a `split(\",\")`. Verified against a live server with an enum declaring\n * exactly those labels, plus one spelled `NULL`: unquoted `NULL` is the null\n * element, and quoted `\"NULL\"` is the four-character string.\n *\n * A nested `{` is a multi-dimensional array, which Prisma's scalar lists cannot\n * be. It is refused rather than flattened — flattening would return a row shape\n * that disagrees with the type Prisma handed the caller, which is the failure\n * this whole feature was refused for eight iterations to avoid.\n */\nfunction parseArrayLiteral(text: string, field: FieldSchema): unknown[] {\n if (!text.startsWith(\"{\") || !text.endsWith(\"}\")) {\n throw new DecodeError(field, text);\n }\n if (text === \"{}\") return [];\n\n const out: unknown[] = [];\n let index = 1;\n const end = text.length - 1;\n\n while (index <= end) {\n let raw = \"\";\n let quoted = false;\n\n if (text[index] === '\"') {\n quoted = true;\n index++;\n while (index < end && text[index] !== '\"') {\n // One level of backslash escaping, which is what the writer above emits\n // and what `bytea`'s own `\\x` prefix is doubled to survive.\n raw += text[index] === \"\\\\\" ? text[++index] : text[index];\n index++;\n }\n // The closing quote.\n index++;\n } else {\n while (index < end && text[index] !== \",\") {\n if (text[index] === \"{\") throw new DecodeError(field, text);\n raw += text[index];\n index++;\n }\n }\n\n // Unquoted `NULL` is the null element; quoted, it is the string.\n out.push(!quoted && raw.toUpperCase() === \"NULL\" ? null : raw);\n\n // Either a separator or the closing brace, and nothing else is well-formed.\n if (index < end && text[index] !== \",\") throw new DecodeError(field, text);\n index++;\n }\n\n if (field.type !== \"Json\") return out;\n\n // **The one place a JS string is not ambiguous**, which is worth saying next\n // to `decodeScalar`'s `Json` case insisting that it usually is. There, a\n // string could be raw JSON text the driver skipped *or* a JSON string value\n // it parsed, and nothing distinguishes them. Here the element was read out of\n // Postgres' own array output a moment ago, so it is raw text by construction\n // and there is no second reading to guess between.\n return out.map((element) => {\n if (element === null) return null;\n try {\n return JSON.parse(element as string);\n } catch {\n throw new DecodeError(field, element);\n }\n });\n}\n",
10
+ "import type { Dialect } from \"../../database/dialect\";\nimport {\n type Binder,\n type Fragment,\n concat,\n param,\n sql,\n} from \"../compile/fragment\";\nimport { DecodeError } from \"../errors\";\nimport type { FieldSchema, ScalarType } from \"../schema\";\nimport type { ConstraintViolation, SqlDialect } from \"./index\";\n\n// Postgres has real `timestamptz`, `boolean`, `numeric` and `jsonb` types, so\n// its driver already returns what Prisma returns and `decode` is almost\n// entirely a pass-through. That asymmetry with SQLite is the point: the same\n// query returns the same JavaScript values on both dialects, which is exactly\n// what the differential harness checks.\nexport class PostgresDialect implements SqlDialect {\n readonly name: Dialect = \"postgres\";\n\n // `ilike`. Note this makes the *default* `contains` case-*sensitive* here and\n // case-insensitive on SQLite, because SQLite's `like` is ASCII-insensitive\n // and has no way to opt out. Prisma has the same split; gemi matches Prisma\n // per dialect rather than inventing a uniformity Prisma does not have.\n readonly supportsInsensitiveMode = true;\n\n // `= any($1)`: one parameter, one SQL text, one plan for every list length.\n readonly bindsListAsOneParameter = true;\n\n readonly supportsReturning = true;\n\n // The wire protocol's Bind message carries the parameter count as an int16,\n // so 65535 is the ceiling for any client, not a Bun or a server setting. Past\n // it the driver's error names neither the model nor the cause.\n readonly maxBoundParameters = 65535;\n\n // The server describes the statement and Bun encodes to the type it is told,\n // which is why a `::jsonb` on the placeholder changes what a JS string means.\n // See `json-param.ts`.\n readonly typesParametersFromStatement = true;\n\n quoteIdent(name: string): string {\n // See the SQLite implementation: NUL is the parameter sentinel in\n // compile/fragment.ts, so it is the one character that could shift a\n // placeholder's position rather than merely produce broken SQL.\n if (name.includes(\"\\u0000\")) {\n throw new Error(\n `Refusing to quote the identifier ${JSON.stringify(name)}: it contains ` +\n `a NUL byte, which is reserved as the parameter marker.`,\n );\n }\n return `\"${name.replace(/\"/g, '\"\"')}\"`;\n }\n\n placeholder(index: number): string {\n return `$${index + 1}`;\n }\n\n // The whole array binds to a single parameter, so every list length shares one\n // SQL text — one plan cache entry and one prepared statement, instead of one\n // per distinct length the way SQLite needs. That matters more from iteration 3\n // on, where every batched relation query is an `in` over the parent keys and\n // the list length is the *number of parent rows*.\n //\n // The array is serialized to a Postgres array literal rather than handed over\n // as a JS array: Bun's driver rejects an array bound to a `= any($1)`\n // parameter outright — `insufficient data left in message` for numbers,\n // `malformed array literal` for strings. It is still one bound parameter and\n // still never touches the SQL text, so nothing about the injection story or\n // the plan cache changes.\n inList(\n lhs: string,\n negated: boolean,\n _length: number,\n values: Binder,\n ): Fragment {\n const operator = negated ? \"<> all\" : \"= any\";\n return concat(\n sql(`${lhs} ${operator} (`),\n param((args, context) => arrayLiteral(values(args, context) as unknown[])),\n sql(\")\"),\n );\n }\n\n /**\n * The SQL type each Prisma scalar takes inside an `unnest` cast.\n *\n * **Deliberately not the whole table.** Only the types a composite join key\n * realistically uses are here, and anything else falls back to the portable\n * `OR` rather than being guessed at — the cast has to round-trip the value\n * exactly, and a wrong one is silently wrong rows rather than an error.\n *\n * `DateTime` is the instructive absence: Prisma maps it to `timestamp(3)`,\n * and this driver's own note records that a zoneless timestamp decodes\n * differently depending on which protocol the statement used. Putting that\n * through a text array literal adds a second representation question to one\n * that is already open, for a key type nobody joins on.\n */\n private static readonly COMPOSITE_IN_TYPES: Partial<\n Record<ScalarType, string>\n > = {\n Int: \"int\",\n BigInt: \"bigint\",\n String: \"text\",\n Boolean: \"boolean\",\n };\n\n canBindCompositeIn(types: readonly ScalarType[]): boolean {\n return (\n types.length > 0 &&\n types.every((type) => PostgresDialect.COMPOSITE_IN_TYPES[type])\n );\n }\n\n /**\n * `(a, b) in (select * from unnest($1::int[], $2::text[]))`.\n *\n * **One parameter per column, not per parent**, which is the whole point:\n * the text is fixed however many tuples arrive, so a batched composite\n * `include` is one plan entry rather than one per parent count (#97). The\n * `OR` it replaces costs a placeholder per field *per parent* and a plan key\n * per length.\n *\n * The tuples arrive row-wise — one array per parent — and are transposed\n * here, because that is the shape the loader has and the shape `unnest`\n * needs. Serialized as Postgres array literals for the reason `inList`\n * already documents: this driver rejects a JS array bound against an array\n * parameter, and the literal is still one bound value that never touches the\n * SQL text.\n */\n compositeIn(\n columns: readonly string[],\n types: readonly ScalarType[],\n values: Binder,\n ): Fragment {\n const arrays = columns.map((_column, index) =>\n concat(\n param((args, context) =>\n arrayLiteral(\n (values(args, context) as unknown[][]).map((tuple) => tuple[index]),\n ),\n ),\n sql(`::${PostgresDialect.COMPOSITE_IN_TYPES[types[index]]}[]`),\n ),\n );\n\n return concat(\n sql(`(${columns.join(\", \")}) in (select * from unnest(`),\n ...arrays.flatMap((array, index) =>\n index === 0 ? [array] : [sql(\", \"), array],\n ),\n sql(\"))\"),\n );\n }\n\n /**\n * Everything Prisma exposes on a scalar list, because `text[]` can express\n * all of it (#300).\n *\n * `equals` is in the set even though it is compiled by the generic `equals`\n * path rather than by a method here: the set is what the compiler consults to\n * decide whether a list filter is *available at all*, and leaving it out\n * would make `{ tags: [\"a\"] }` — the bare-array shorthand — refuse itself on\n * the one dialect that can serve it.\n */\n readonly listFilters: ReadonlySet<string> = new Set([\n \"equals\",\n \"has\",\n \"hasEvery\",\n \"hasSome\",\n \"isEmpty\",\n ]);\n\n /**\n * `$1 = any(\"tags\")` — the element on the left, which is the mirror of\n * {@link inList} and worth not confusing with it. There, one column is\n * matched against a caller's list; here, one caller value is matched against\n * a column that *is* a list.\n *\n * No cast is added *here*, in this method or the three below. An untyped\n * array literal resolves against the column's own element type in every one\n * of these positions — measured through Bun 1.3.14 against Postgres 16 on\n * `text[]`, `jsonb[]`, `bytea[]`, `timestamp(3)[]` and an `enum[]`. That is\n * not merely convenient: an explicit cast would have to *name* the element\n * type, and for an enum that name is the database's own enum type, which the\n * generated artifact does not carry. Leaning on inference is what lets enum\n * lists work without widening the artifact.\n *\n * **The operand is a `Fragment`, not a `Binder`**, and `Json` is why. A\n * single element of a `Json[]` still needs #209's `::text::jsonb`, and it\n * needs the serialisation that travels with it — so the parameter is built by\n * `fieldParam` before it gets here, and this method only picks the operator.\n * Measured, because every wrong form fails *silently*:\n *\n * $1 = any(docs) {\"a\":1} -> false\n * $1::jsonb = any(docs) {\"a\":1} -> false\n * $1::text::jsonb = any(docs) {\"a\":1} -> true\n *\n * No error on either of the first two. A dialect that built its own parameter\n * here would have to restate `fieldParam`'s rule, and the version that\n * restated it slightly wrong would return \"no rows\" rather than raising.\n */\n listHas(column: string, value: Fragment): Fragment {\n return concat(value, sql(` = any(${column})`));\n }\n\n /** `\"tags\" @> $1` — containment: every element of the operand is present. */\n listHasEvery(column: string, values: Fragment): Fragment {\n return concat(sql(`${column} @> `), values);\n }\n\n /** `\"tags\" && $1` — overlap: at least one element is shared. */\n listHasSome(column: string, values: Fragment): Fragment {\n return concat(sql(`${column} && `), values);\n }\n\n /**\n * `\"tags\" = $1` against the empty array, rather than `cardinality(…) = 0`.\n *\n * The two are equivalent on a non-null column — and a scalar list cannot be\n * null, since Prisma refuses `String[]?` — including on the NULL case, where\n * both yield NULL and so exclude the row.\n *\n * The comparison is the one that keeps the invariant `FALSE` is spelled\n * `false` for: **no digit reaches the SQL text outside an identifier**. A\n * literal `0` would be the first, for a constant the compiler already knows —\n * which is exactly the exception `jsonNullComparison` declines to make.\n */\n listIsEmpty(column: string, empty: boolean): Fragment {\n return concat(\n sql(`${column} ${empty ? \"=\" : \"<>\"} `),\n param(() => arrayLiteral([])),\n );\n }\n\n /**\n * `array_cat(\"tags\", $1)` — the right-hand side of a `push`.\n *\n * **`array_cat` rather than `||`**, and the difference is not stylistic.\n * `||` is overloaded `anyarray || anyarray` *and* `anyarray || anyelement`,\n * so an untyped parameter beside it is genuinely ambiguous — and Prisma's\n * `push` accepts both a single element and a list, which is precisely the\n * pair that would resolve differently. `array_cat` has one signature, so the\n * compiler can normalise `push` to an array once and the operator cannot be\n * read the other way.\n */\n listPush(column: string, values: Fragment): Fragment {\n return concat(sql(`array_cat(${column}, `), values, sql(\")\"));\n }\n\n /** `path: [\"a\", \"b\"]`, where SQLite takes `\"$.a.b\"`. Prisma's own split. */\n readonly jsonPathSyntax = \"array\" as const;\n\n /** Everything, which is what `jsonb` can express and Prisma exposes here. */\n readonly jsonFilters: ReadonlySet<string> = new Set([\n \"equals\",\n \"not\",\n \"string_contains\",\n \"string_starts_with\",\n \"string_ends_with\",\n \"array_contains\",\n \"lt\",\n \"lte\",\n \"gt\",\n \"gte\",\n ]);\n\n /** `#>>` yields `text`, so a comparison binds the value's text form. */\n readonly jsonComparesAsText = true;\n\n /**\n * `\"col\" #> $1` for the JSON value, `#>>` for its text.\n *\n * Both take the path as a **`text[]` parameter**, which is the whole reason\n * this is expressible without bending invariant 2 — the one place a caller's\n * value decides part of an expression's meaning, and it still never reaches\n * the SQL text. The array is serialized the same way `inList` serializes\n * one, for the same driver reason.\n */\n jsonExtract(column: string, path: Binder, asText: boolean): Fragment {\n return concat(\n sql(`${column} ${asText ? \"#>>\" : \"#>\"} `),\n param((args, context) => arrayLiteral(path(args, context) as unknown[])),\n );\n }\n\n /**\n * `(\"col\" #> $1)::jsonb` — the JSON value at the path, comparable.\n *\n * The cast is load-bearing on a `@db.Json` column and a no-op on the `jsonb`\n * one Prisma maps `Json` to by default. Measured against Postgres 16, on a\n * `json` column:\n *\n * (payload #> '{operation}') = 'null'::jsonb operator does not exist: json = jsonb\n * ((payload #> '{operation}')::jsonb) = 'null'::jsonb the row whose key holds a JSON null\n *\n * Prisma emits the same cast — `(\"Doc\".\"payload\"#>ARRAY[$1]::text[])::jsonb`\n * — which is where this one comes from rather than from the manual.\n */\n jsonValueAt(column: string, path: Binder): Fragment {\n return concat(\n sql(\"(\"),\n this.jsonExtract(column, path, false),\n sql(\")::jsonb\"),\n );\n }\n\n /**\n * `(\"col\" #> $1) @> $2` — containment, which is what Prisma's\n * `array_contains` compiles to and why it accepts both a scalar and a list:\n * `@>` asks whether the left document contains the right one, and a bare\n * value is a one-element containment test.\n */\n jsonArrayContains(column: string, path: Binder, value: Binder): Fragment {\n return concat(\n sql(\"(\"),\n this.jsonExtract(column, path, false),\n sql(\") @> \"),\n // **Raw, not `JSON.stringify`d**, and the cast is what makes that safe.\n // Bun already encodes a parameter bound against `jsonb` as JSON, so\n // stringifying first sends the *string* `\"[\\\"a\\\"]\"` rather than the\n // array — containment then asks whether a JSON array contains a JSON\n // string spelling of itself, which is `false`. No error, no rows.\n // Measured through the driver:\n //\n // raw scalar \"a\" -> true\n // raw array [\"a\"] -> true\n // JSON.stringify([\"a\"]) -> false <- what this used to send\n // raw number 3 -> cannot cast type integer to jsonb\n //\n // The last line is why the cast is explicit and the value is normalised:\n // a number has to become JSON text for the driver to type it as `jsonb`\n // at all.\n param((args, context) => {\n const raw = value(args, context);\n if (raw === null || raw === undefined) return null;\n return typeof raw === \"string\" || typeof raw === \"object\"\n ? raw\n : JSON.stringify(raw);\n }),\n sql(\"::jsonb\"),\n );\n }\n\n like(lhs: string, insensitive: boolean, pattern: Binder): Fragment {\n return concat(\n sql(`${lhs} ${insensitive ? \"ilike\" : \"like\"} `),\n param(pattern),\n );\n }\n\n // `on conflict do nothing` with no target: it covers every unique constraint\n // and the primary key at once, which is what `skipDuplicates` means — Prisma\n // names no conflict target either. A targeted `on conflict (col)` would skip\n // rows that collide on that column and still fail on any other constraint,\n // which is the plausible wrong version.\n //\n // Rows it skips are absent from `RETURNING`, so the `{ count }` the compiler\n // builds from the returned rows is the number *inserted* rather than the\n // number supplied — which is the part the issue flags as most likely to be\n // got wrong, and it falls out rather than needing a second count.\n ignoreConflicts(): Fragment {\n return sql(\" on conflict do nothing\");\n }\n\n // Unlike SQLite, Postgres accepts `offset` on its own, so neither clause has\n // to be invented to satisfy the other.\n paginate(take: Binder | null, skip: Binder | null): Fragment {\n const parts: Fragment[] = [];\n if (take) parts.push(concat(sql(\" limit \"), param(take)));\n if (skip) parts.push(concat(sql(\" offset \"), param(skip)));\n return concat(...parts);\n }\n\n // Postgres reports a duplicate key as SQLSTATE 23505, and unlike SQLite it\n // carries structured fields alongside the message. Read off a live server\n // through Bun rather than from the Postgres manual, because the placement is\n // the surprise:\n //\n // name: 'PostgresError'\n // code: 'ERR_POSTGRES_SERVER_ERROR' <- Bun's own code, not the SQLSTATE\n // errno: '23505' <- the SQLSTATE lives here\n // constraint: 'User_email_key'\n // detail: 'Key (email)=(a@x) already exists.'\n // table: 'User'\n //\n // Checking `code` alone — the obvious reading, and the one this started with\n // — matches nothing at all, so every unique violation escaped as a raw driver\n // error. Both are consulted now: `errno` is where Bun puts it today, and\n // `code` is where a driver following the `pg` convention would.\n //\n // The class code `23` covers integrity violations generally — 23502 not-null,\n // 23503 foreign key, 23514 check — so matching the *full* five characters is\n // what keeps those from being reported as duplicate keys.\n //\n // Only the constraint name is taken as authoritative. `detail` is parsed\n // best-effort for the column list because Postgres localises it: on a server\n // with `lc_messages` set to anything but English the prefix is not `Key`, and\n // the regex simply does not match. That degrades to a violation with no\n // columns — still typed, still catchable, still naming the constraint — rather\n // than to a wrong column list.\n constraintViolation(error: unknown): ConstraintViolation | null {\n const source = error as Record<string, unknown> | null;\n if (!source) return null;\n\n const sqlstate = String(source.errno ?? source.code ?? \"\");\n if (sqlstate !== \"23505\") return null;\n\n const constraint =\n typeof source.constraint === \"string\" && source.constraint !== \"\"\n ? source.constraint\n : undefined;\n\n const detail = typeof source.detail === \"string\" ? source.detail : \"\";\n const listed = /\\((.+?)\\)=/.exec(detail);\n const columns = listed\n ? listed[1]\n .split(\",\")\n .map((entry) => entry.trim())\n .filter((entry) => entry !== \"\")\n : [];\n\n return { kind: \"unique\", columns, constraint };\n }\n\n // `$1::text::jsonb` for a `Json` column, nothing for a scalar list, and\n // nothing for anything else. A scalar `Date`, `boolean` or `bigint` binds\n // natively and needs neither a cast nor an encoder — which is why `encode`\n // below reads `field` for exactly two questions and passes everything else\n // through.\n //\n // The value is serialised by `fieldParam`, not by `encode` below, so a\n // binding site that does not ask for the cast still binds raw and keeps the\n // loud failure rather than acquiring a silent mis-store. The comment on\n // `encode` has the measurements.\n castParameter(field: FieldSchema): string {\n // A list is bound as an array literal and needs no cast in any position it\n // can occupy — see `listHas` for the measurements. Checked *before* the\n // `Json` branch rather than after, because a `Json[]` would otherwise take\n // it and bind `$1::text::jsonb` against a `jsonb[]` column, which is a type\n // error rather than a wrong answer. The order is the whole check.\n if (field.isList) return \"\";\n return field.type === \"Json\" ? \"::text::jsonb\" : \"\";\n }\n\n encode(value: unknown, field: FieldSchema): unknown {\n if (value === null || value === undefined) return null;\n\n // A scalar list crosses as one Postgres array literal, which is the same\n // trick `inList` and `compositeIn` already use for a bound array: still one\n // parameter, still nothing in the SQL text.\n //\n // `Json` is the element type that needs work here rather than in\n // `fieldParam`, and it is not the exception it looks like. `fieldParam`'s\n // rule is that the cast and the serialisation travel together; a list emits\n // *no* cast, because the array literal already carries the element's text\n // form and Postgres casts each element to the column's element type. So\n // serialising a `Json` element here is what makes the literal well-formed,\n // not a second place doing `fieldParam`'s job.\n if (field.isList) {\n // Not an `InvalidArgumentError`: the compiler validates every list\n // operand where the model and operation are in scope to name them, so a\n // non-array arriving here reports an ORM bug rather than a caller's —\n // the same call `fieldParam` makes about a stray `AnyNull`.\n if (!Array.isArray(value)) {\n throw new Error(\n `gemi ORM bug: a non-array reached the parameter binder for the ` +\n `scalar list '${field.column}' (received ${typeof value}). Every ` +\n `path that binds a list is supposed to have checked its operand.`,\n );\n }\n return arrayLiteral(\n field.type === \"Json\"\n ? value.map((element) =>\n element === null || element === undefined\n ? null\n : JSON.stringify(element),\n )\n : value,\n );\n }\n // **`Json` is handed over raw**, because Bun serializes it for a `jsonb`\n // parameter and doing it here first is the mirror of the decode bug beside\n // it: `JSON.stringify({a:1})` produces the *string* `{\"a\":1}`, and Bun then\n // stores that as the JSON string `\"{\\\"a\\\":1}\"` rather than as an object.\n //\n // The two used to cancel: encode over-serialized, decode re-parsed, and the\n // round trip looked right as long as nothing else read the column. What it\n // could not survive was a value that is legitimately a JSON *string* —\n // `\"42\"` went in as the number 42 — and nothing noticed, because the\n // template's schema had no `Json` column for the differential harness to\n // compare.\n //\n // Measured through Bun 1.3.14 against Postgres 16: an object, an array, a\n // string and null all round-trip identically when bound raw.\n //\n // A bare number or boolean is the one shape Bun binds as its own type, so\n // it now raises — `column is of type jsonb but expression is of type\n // boolean`. That reads like a regression and is not one: under the old\n // encoder `42` was stored as the jsonb **string** `\"42\"` (checked with\n // `jsonb_typeof`, which answered `string` for a number, a boolean and an\n // object alike). It only looked correct because the old decoder re-parsed\n // it on the way out — so the value was wrong in the database the whole\n // time, and anything reading that column *other than this ORM* saw a\n // string. A loud failure replaces a silent mis-store.\n //\n // **Fixed, in the compiler rather than here** — see `compile/cast.ts`. The\n // placeholder carries `::text::jsonb` and `fieldParam` serialises the value\n // to match, which is the only one of the four forms measured that carries\n // all six shapes:\n //\n // values ($1) 42 integer vs jsonb\n // values ($1::jsonb) \"42\" jsonb_typeof -> string\n // values (to_jsonb($1)) {a:1} could not determine polymorphic type\n // values ($1::text::jsonb) \"42\" jsonb_typeof -> number\n //\n // The serialisation deliberately does **not** live here. `encode` runs at\n // every binding site, and a site that serialises without also emitting the\n // cast is the second row above — the silent mis-store this whole comment is\n // about. Keeping the two together in `fieldParam` means a site nobody\n // converted still binds raw and still fails loudly.\n //\n // **The second row is also what a raw statement hits**, and there the cast\n // is the caller's rather than the dialect's: `payload || $1::jsonb` is a\n // Prisma port's spelling, and under Bun it appends the serialised text to an\n // array instead of merging. `json-param.ts` retypes it, on the same\n // reasoning and with the cast and the serialisation kept together for the\n // same reason.\n //\n return value;\n }\n\n // Nothing to do without a field: the only conversion `encode` makes here is\n // the JSON one, and that is precisely the one that needs the column's\n // declared type to be legitimate. `Date`, `boolean`, `bigint` and arrays all\n // bind natively, which is why a raw fragment is portable across the two\n // dialects even though only SQLite has to normalise anything.\n //\n // A parameter the caller cast to `json`/`jsonb` never arrives here: it has a\n // declared type after all, and `renderFragment` binds it as JSON text.\n encodeUntyped(value: unknown): unknown {\n return value;\n }\n\n // Postgres returns real `timestamptz`, `boolean` and `double precision`, so\n // most columns need nothing. Two do, and neither is reachable from the\n // template's schema — which is why they went unnoticed until a fixture with\n // every scalar type existed. Read off a live server through Bun:\n //\n // integer -> number ✓\n // double precision -> number ✓\n // boolean -> boolean ✓\n // text -> string ✓\n // timestamp(3) -> Date ✓ (but see the protocol note below)\n // bytea -> Buffer ✗ where Prisma gives a plain Uint8Array\n // bigint -> \"123\" ✗ string, where Prisma gives 123n\n // jsonb / json -> '{\"a\":1}' ✗ unparsed text, where Prisma gives an object\n //\n // The `bytea` line carried a ✓ and the parenthetical \"a Uint8Array, which is\n // what Prisma gives\". Both halves are true and the conclusion was still wrong:\n // a `Buffer` *is* a `Uint8Array`, so the type checks out, but it is not the\n // one Prisma returns and it does not behave the same. Checked against a\n // generated Prisma 6 client on both dialects rather than reasoned about —\n // Prisma returns a plain `Uint8Array` for `Bytes` everywhere.\n //\n // `numeric` also arrives as a string, which is the correct thing for it to\n // do — but `Decimal` is refused at *generation* time (iteration 1), so no\n // such field can reach this.\n needsDecode(field: FieldSchema): boolean {\n // `Json` is deliberately absent: Bun hands back a parsed JSON value, so\n // `decode` returns it unchanged, and this predicate documents itself as\n // \"false when the driver already returns exactly what Prisma would\" — which\n // is now exactly true. Leaving it in cost a function call per Json value on\n // every read for nothing.\n //\n // **Every list is decoded**, including a `String[]` whose elements the\n // driver already hands back correctly. Three separate reasons, and the\n // first alone settles it: the *container* is wrong for two element types\n // regardless of the elements — `int[]` arrives as an `Int32Array`, and an\n // `enum[]` arrives as an unparsed `{…}` literal — so a predicate that\n // answered per element type would have to encode which container Bun picks\n // for which Postgres type, which is a table nothing keeps in step. Second,\n // `int[]`'s container differs *by protocol*: `Int32Array` when the\n // statement binds a parameter, a plain `Array` when it does not. Third, the\n // cost is one call per list value, not per element.\n return field.isList === true || field.type === \"BigInt\" || field.type === \"Bytes\";\n }\n\n decode(value: unknown, field: FieldSchema): unknown {\n if (value === null || value === undefined) return null;\n if (field.isList) return this.decodeList(value, field);\n return this.decodeScalar(value, field);\n }\n\n /**\n * One array column, element by element.\n *\n * **Three container shapes arrive here**, all measured through Bun 1.3.14\n * against Postgres 16 rather than read off a driver's documentation:\n *\n * text[] float8[] bool[] timestamp[] bytea[] jsonb[] bigint[] -> Array\n * int[] -> Int32Array\n * enum[] domain[] -> \"{a,b}\"\n *\n * The third is the surprise and the reason this is not four lines: Bun has no\n * decoder for an array whose element type it does not recognise, so it hands\n * the **Postgres array output literal back as a string** — and every enum\n * list is in that case. `real[]` is the same story as `int[]` with a\n * `Float32Array`, which is why the typed-array branch is written against\n * `ArrayBuffer.isView` rather than against `Int32Array` by name.\n *\n * `int[]`'s container also depends on the *protocol*: a statement that binds\n * at least one parameter goes over the extended protocol and yields an\n * `Int32Array`, one that binds none yields a plain `Array`. Same column, same\n * row, two shapes — so this cannot be decided once and cached.\n *\n * Elements then go through {@link decodeScalar}, which is the same function\n * the scalar path uses. That is what makes `BigInt[]` exact and `Bytes[]` a\n * `Uint8Array[]` rather than a `Buffer[]` without restating either rule.\n */\n private decodeList(value: unknown, field: FieldSchema): unknown {\n const elements = Array.isArray(value)\n ? value\n : typeof value === \"string\"\n ? parseArrayLiteral(value, field)\n : ArrayBuffer.isView(value)\n ? Array.from(value as unknown as ArrayLike<unknown>)\n : null;\n\n if (elements === null) throw new DecodeError(field, value);\n\n return elements.map((element) =>\n element === null || element === undefined\n ? null\n : this.decodeScalar(element, field),\n );\n }\n\n private decodeScalar(value: unknown, field: FieldSchema): unknown {\n switch (field.type) {\n case \"BigInt\":\n if (typeof value === \"bigint\") return value;\n try {\n return BigInt(value as string);\n } catch {\n throw new DecodeError(field, value);\n }\n case \"Json\":\n // **Bun parses `json` and `jsonb` for us**, so there is nothing to do.\n // Measured against Postgres 16 through Bun 1.3.14, one row per shape:\n //\n // '{\"a\":1}' -> object '[]' -> object (array)\n // '\"42\"' -> string '42' -> number\n // '\"text\"' -> string 'null' -> null\n //\n // This used to read `typeof value === \"string\" ? JSON.parse(value) :\n // value`, on the reasoning that jsonb \"arrives as text\" and that the\n // `typeof` check would cope either way. It does not cope, and cannot:\n // **a JS string is ambiguous** between \"raw JSON text the driver did\n // not parse\" and \"a JSON string value the driver did parse\", and the\n // two are indistinguishable by inspection. So the guard silently\n // re-parsed legitimate string values — a column holding the JSON string\n // `\"42\"` came back as the *number* 42, `\"true\"` as a boolean, and\n // `\"{\\\"a\\\":1}\"` as an object. `\"text\"` survived only because\n // `JSON.parse` threw and the catch handed the value back.\n //\n // Found by adding a `Json` column to the template schema: the\n // differential harness had never seen one, and every unit test that\n // \"covered\" this was written against the same assumption as the code.\n return value;\n case \"Bytes\":\n // The driver hands back a `Buffer`; Prisma 6 returns a `Uint8Array`,\n // on **every** dialect, and so does this ORM on SQLite where the\n // driver's own value already is one. Returning the `Buffer` verbatim\n // therefore diverged from Prisma and from our own SQLite path at the\n // same time — and `Buffer` being a `Uint8Array` subclass is exactly\n // what made it invisible: it satisfies the generated type, survives\n // `ArrayBuffer.isView`, and compares equal element by element.\n //\n // What it does not survive is `toString`. `Buffer.prototype.toString`\n // takes an encoding; `Uint8Array.prototype.toString` ignores its\n // argument and joins with commas. So `row.digest.toString(\"hex\")` read\n // `\"0102ff\"` in production on Postgres and `\"1,2,255\"` in development\n // on SQLite, with no error on either.\n //\n // A view, not a copy: same bytes, same lifetime, no allocation.\n return Buffer.isBuffer(value)\n ? new Uint8Array(value.buffer, value.byteOffset, value.byteLength)\n : value;\n default:\n return value;\n }\n }\n\n // KNOWN DIVERGENCE, and not one this can fix: Prisma maps `DateTime` to\n // `timestamp(3)` — no time zone — and stores UTC in it, but Bun's driver\n // decodes that column differently depending on the *protocol* the statement\n // used. A query that binds no parameters goes over the simple query protocol\n // and comes back as zoneless text, which is then parsed as local time; a\n // query that binds even one parameter goes over the extended protocol, comes\n // back in binary, and is correct. Same row, same column, two instants, on any\n // machine whose clock is not already UTC.\n //\n // select \"createdAt\" from \"User\" limit 1 -> 10:26:40Z\n // select \"createdAt\" from \"User\" where \"id\" = $1 -> 12:26:40Z\n // select \"createdAt\"::text from \"User\" limit 1 -> 12:26:40\n //\n // A `decode` cannot correct it, because the value alone does not say which\n // protocol produced it; nothing below the plan does. Until it is fixed\n // upstream, run the process with TZ=UTC, where both paths agree.\n //\n // Note this is why `DateTime` stays out of `needsDecode` above: there is no\n // correction to apply, only a caveat to record.\n}\n\n/**\n * `[1, 2]` -> `{\"1\",\"2\"}`: Postgres' text form for an array value.\n *\n * Every element is quoted, including numbers and booleans — Postgres casts a\n * quoted element to the array's element type, so one rule covers every column\n * type instead of a per-type branch that has to stay in step with `encode`.\n * `NULL` is the one thing that cannot be quoted, since `\"NULL\"` is the string.\n *\n * Verified against a real database for `int`, `text` (with quotes, commas,\n * braces, backslashes and newlines in the value), `timestamp`, `boolean`,\n * `bigint` past 2^53, `bytea` and `double precision`.\n */\nfunction arrayLiteral(values: unknown[]): string {\n let out = \"{\";\n for (let i = 0; i < values.length; i++) {\n if (i > 0) out += \",\";\n out += arrayElement(values[i]);\n }\n return out + \"}\";\n}\n\nfunction arrayElement(value: unknown): string {\n if (value === null || value === undefined) return \"NULL\";\n\n // ISO 8601 keeps the value's own UTC wall clock, which is what Prisma stores\n // in a `timestamp(3)`; the zone designator is ignored on the way in.\n if (value instanceof Date) return `\"${value.toISOString()}\"`;\n\n if (ArrayBuffer.isView(value)) {\n let hex = \"\";\n for (const byte of new Uint8Array(\n value.buffer,\n value.byteOffset,\n value.byteLength,\n )) {\n hex += byte.toString(16).padStart(2, \"0\");\n }\n // `\\x…` is Postgres' hex bytea form, and the backslash is doubled because\n // the array literal parser reads one level of escapes first.\n return `\"\\\\\\\\x${hex}\"`;\n }\n\n const text = typeof value === \"string\" ? value : String(value);\n return `\"${text.replace(/\\\\/g, \"\\\\\\\\\").replace(/\"/g, '\\\\\"')}\"`;\n}\n\n/**\n * `{a,\"b,c\",NULL}` -> `[\"a\", \"b,c\", null]`: the same form, read back.\n *\n * **Only reached for an array type Bun has no decoder for**, which today means\n * an `enum[]` or a `domain[]` — everything else arrives as a JS array and never\n * comes near this. That is why it exists at all: an enum list is the one scalar\n * list a Prisma schema is *likely* to declare, and it is precisely the one the\n * driver hands back as text.\n *\n * Splitting on commas is wrong and looks right, which is the whole reason this\n * is a state machine. Postgres quotes an element only when it has to, and then\n * escapes `\"` and `\\` inside the quotes — so a label containing a comma, a\n * brace, a quote or a backslash all survive the output format and none of them\n * survive a `split(\",\")`. Verified against a live server with an enum declaring\n * exactly those labels, plus one spelled `NULL`: unquoted `NULL` is the null\n * element, and quoted `\"NULL\"` is the four-character string.\n *\n * A nested `{` is a multi-dimensional array, which Prisma's scalar lists cannot\n * be. It is refused rather than flattened — flattening would return a row shape\n * that disagrees with the type Prisma handed the caller, which is the failure\n * this whole feature was refused for eight iterations to avoid.\n */\nfunction parseArrayLiteral(text: string, field: FieldSchema): unknown[] {\n if (!text.startsWith(\"{\") || !text.endsWith(\"}\")) {\n throw new DecodeError(field, text);\n }\n if (text === \"{}\") return [];\n\n const out: unknown[] = [];\n let index = 1;\n const end = text.length - 1;\n\n while (index <= end) {\n let raw = \"\";\n let quoted = false;\n\n if (text[index] === '\"') {\n quoted = true;\n index++;\n while (index < end && text[index] !== '\"') {\n // One level of backslash escaping, which is what the writer above emits\n // and what `bytea`'s own `\\x` prefix is doubled to survive.\n raw += text[index] === \"\\\\\" ? text[++index] : text[index];\n index++;\n }\n // The closing quote.\n index++;\n } else {\n while (index < end && text[index] !== \",\") {\n if (text[index] === \"{\") throw new DecodeError(field, text);\n raw += text[index];\n index++;\n }\n }\n\n // Unquoted `NULL` is the null element; quoted, it is the string.\n out.push(!quoted && raw.toUpperCase() === \"NULL\" ? null : raw);\n\n // Either a separator or the closing brace, and nothing else is well-formed.\n if (index < end && text[index] !== \",\") throw new DecodeError(field, text);\n index++;\n }\n\n if (field.type !== \"Json\") return out;\n\n // **The one place a JS string is not ambiguous**, which is worth saying next\n // to `decodeScalar`'s `Json` case insisting that it usually is. There, a\n // string could be raw JSON text the driver skipped *or* a JSON string value\n // it parsed, and nothing distinguishes them. Here the element was read out of\n // Postgres' own array output a moment ago, so it is raw text by construction\n // and there is no second reading to guess between.\n return out.map((element) => {\n if (element === null) return null;\n try {\n return JSON.parse(element as string);\n } catch {\n throw new DecodeError(field, element);\n }\n });\n}\n",
11
11
  "/**\n * Prisma's two null sentinels for a `Json` column, recognised without importing\n * Prisma.\n *\n * A nullable `Json` column has *two* legal empty values and Prisma makes the\n * caller choose between them, because they are different rows:\n *\n * Prisma.DbNull the column is SQL NULL\n * Prisma.JsonNull the column holds the JSON value `null`\n *\n * A bare `null` is a type error on both libraries — gemi takes Prisma's\n * argument types verbatim, so the sentinels are what type-checks here too, and\n * `differential.test.ts` already notes that \"a decoder that conflates them\n * returns the wrong one of two legal answers\".\n *\n * Nothing translated them. Both are ordinary objects with no enumerable\n * properties, so every path that serialises a Json value turned them into the\n * jsonb object `{}` — a plausible-looking value, silently wrong, on both\n * dialects and with nothing raised. That is the same silent mis-store the\n * bare-scalar refusal existed to prevent.\n *\n * **Recognised by `toString`, not by `instanceof` or the constructor's name.**\n * The ORM runtime may not import the Prisma client package at all —\n * `runtime-isolation.test.ts` greps for the name, comments included — so\n * `instanceof` is unavailable. Prisma implements\n * `toString` on these deliberately, returning `Prisma.DbNull` and\n * `Prisma.JsonNull`; a constructor name would be the other candidate and is the\n * one a minifier is free to rewrite.\n */\nexport type JsonNullKind = \"db\" | \"json\" | \"any\";\n\nconst SENTINELS: Record<string, JsonNullKind> = {\n \"Prisma.DbNull\": \"db\",\n \"Prisma.JsonNull\": \"json\",\n \"Prisma.AnyNull\": \"any\",\n};\n\n/**\n * Which sentinel this is, or `null` for any ordinary value.\n *\n * **`\"any\"` is not a storable value, and the two others are.** `DbNull` and\n * `JsonNull` each name one of the column's two legal empty states, so an\n * encoder can turn either into something to write. `AnyNull` names *both at\n * once* — it is a question, only ever meaningful in a filter, and Prisma raises\n * if it reaches a write. Callers that encode must therefore handle it\n * separately rather than treating the three alike; `cast.ts` and the SQLite\n * encoder refuse it outright, since by the time a value reaches them the filter\n * and write paths have each had their say.\n *\n * It was previously absent from this table, and **absent is not the same as\n * refused** — it fell through to the data path, where a write stored it as the\n * jsonb object `{}` and a filter compiled to `= '{}'`, returning the complement\n * of the rows it asks for. That was #259.\n */\n/**\n * A sentinel, built the way the recogniser below demands.\n *\n * **A class, so the prototype's `toString` is non-enumerable.** A method in an\n * object literal is enumerable, `for…in` walks it, and the shape check below\n * would reject it — which is how the first version of the test helper in\n * `json-null.test.ts` failed while Prisma's real sentinels passed. Prisma builds\n * them as classes; this matches, and `json-null.test.ts` pins that they are\n * recognised so the two cannot drift apart.\n *\n * **The tag still reads `Prisma.…`, and that is deliberate.** It is what makes\n * gemi's sentinel and Prisma's the *same value* as far as every reader is\n * concerned: an app migrating off `@prisma/client` can swap the import without\n * touching a call site, and one that still passes Prisma's keeps working. The\n * tag is a wire format shared with another library, not a name gemi is free to\n * choose.\n */\nfunction sentinel(tag: string): object {\n return new (class {\n toString() {\n return tag;\n }\n })();\n}\n\n/**\n * Nominal types for the three sentinels.\n *\n * Branded rather than typed as `object`, so a `Json` column's input type can\n * name exactly these and nothing else. The brand is a type-level fiction — the\n * runtime values carry no such property, and must not: `jsonNullKind` rejects\n * any object with own properties, which is what stops an ordinary value from\n * being mistaken for a sentinel.\n */\ndeclare const sentinelBrand: unique symbol;\n\nexport interface DbNullValue {\n readonly [sentinelBrand]: \"db\";\n}\nexport interface JsonNullValue {\n readonly [sentinelBrand]: \"json\";\n}\nexport interface AnyNullValue {\n readonly [sentinelBrand]: \"any\";\n}\n\n/**\n * The two empty states of a nullable `Json` column, and the filter that means\n * both.\n *\n * `docs/orm.md` used to spell these `Prisma.DbNull` and `Prisma.JsonNull`,\n * which made a *runtime* value import of `@prisma/client` the one piece of\n * ordinary application code that could not be written without the package. The\n * recogniser never needed it — it has always matched structurally, precisely so\n * that the ORM runtime could stay free of Prisma — so exporting gemi's own\n * costs nothing and removes the last such import.\n *\n * `AnyNull` is a question, not a value: it is only meaningful in a filter, and\n * both `cast.ts` and the SQLite encoder refuse it in a write.\n */\nexport const DbNull = sentinel(\"Prisma.DbNull\") as DbNullValue;\nexport const JsonNull = sentinel(\"Prisma.JsonNull\") as JsonNullValue;\nexport const AnyNull = sentinel(\"Prisma.AnyNull\") as AnyNullValue;\n\n/**\n * The ORM's own spelling of `JsonNull`, for a comparison the *compiler* authors\n * rather than the caller.\n *\n * `AnyNull` compiles to `is null or = <JSON null>`, and the right-hand side has\n * no argument to read it out of — the caller wrote `AnyNull`, not `JsonNull`.\n * Rather than teach the encoders a second way to say the same thing, or splice\n * a literal into the SQL text, the compiler binds this and every existing path\n * treats it exactly as it treats the real sentinel.\n *\n * The same object as the exported `JsonNull` rather than a second one: two\n * values with one tag would be two things to keep recognisable, and the\n * compiler's need and the caller's are the same need.\n */\nexport const JSON_NULL: object = JsonNull as unknown as object;\n\nexport function jsonNullKind(value: unknown): JsonNullKind | null {\n if (typeof value !== \"object\" || value === null) return null;\n\n // **A sentinel carries no data**, and checking that before anything else is\n // what makes this safe rather than merely usually-right.\n //\n // Recognising by `toString` alone is forgeable: an object whose `toString`\n // happens to return `Prisma.DbNull` was read as the sentinel and written as\n // SQL NULL, losing the object. It also made the bind *throw* for a value\n // whose `toString` throws — something Prisma stores without ever calling it,\n // since `JSON.stringify` does not consult `toString`.\n //\n // Both reach `String` only for an object with nothing in it, which no\n // application stores on purpose. The enumerable check runs first because it\n // allocates nothing and exits on the first key, which is the common case; the\n // own-property scan is for the handful of values that get past it, and is\n // what keeps `[]` and `{}` out — an empty array is a legitimate Json value.\n for (const _key in value) return null;\n if (Object.getOwnPropertyNames(value).length > 0) return null;\n\n // A null-prototype object has no `toString` at all and `String` throws on it.\n // It is a legitimate Json value, so this answers \"not a sentinel\" rather than\n // failing the write.\n let tag: string;\n try {\n tag = String(value);\n } catch {\n return null;\n }\n\n return SENTINELS[tag] ?? null;\n}\n",
12
- "import type { Dialect } from \"../../database/dialect\";\nimport {\n type Binder,\n type Fragment,\n concat,\n joinFragments,\n param,\n sql,\n} from \"../compile/fragment\";\nimport { DecodeError } from \"../errors\";\nimport { jsonNullKind } from \"../json-null\";\nimport type { FieldSchema } from \"../schema\";\nimport type { ConstraintViolation, SqlDialect } from \"./index\";\n\n// SQLite has five storage classes and neither `DateTime` nor `Boolean` is among\n// them. Prisma stores a `DateTime` as integer milliseconds since the epoch and a\n// `Boolean` as `0` / `1`, so handing the driver's values straight back would\n// already diverge from Prisma's result shape on the template's `createdAt`.\n//\n// `CURRENT_TIMESTAMP` column defaults are the one exception: a row inserted by\n// raw SQL or by a migration rather than by Prisma holds the text form\n// `YYYY-MM-DD HH:MM:SS`, which SQLite defines as UTC. Both forms are decoded.\nconst SQLITE_TEXT_TIMESTAMP =\n /^\\d{4}-\\d{2}-\\d{2}[ T]\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?$/;\n\nfunction toDate(value: unknown, field: FieldSchema): Date {\n if (value instanceof Date) return value;\n\n let date: Date;\n if (typeof value === \"number\") {\n date = new Date(value);\n } else if (typeof value === \"bigint\") {\n date = new Date(Number(value));\n } else if (typeof value === \"string\") {\n // Naked SQLite timestamps carry no zone but are documented as UTC; `Date`\n // would otherwise read them as local time and shift them.\n date = new Date(\n SQLITE_TEXT_TIMESTAMP.test(value) ? `${value.replace(\" \", \"T\")}Z` : value,\n );\n } else {\n throw new DecodeError(field, value);\n }\n\n // `new Date(\"nonsense\")` is an `Invalid Date`, not a throw — every field on it\n // reads `NaN`. Returning one would be a wrong answer rather than an error,\n // which is the failure mode this whole file exists to avoid.\n if (Number.isNaN(date.getTime())) throw new DecodeError(field, value);\n return date;\n}\n\nexport class SqliteDialect implements SqlDialect {\n readonly name: Dialect = \"sqlite\";\n\n // Prisma rejects `mode: \"insensitive\"` on SQLite rather than emulating it, so\n // gemi does too — the contract is with Prisma's behaviour, not with\n // cross-dialect uniformity. Note SQLite's `like` is *already* case-insensitive\n // for ASCII, which is the opposite of Postgres and is why the two dialects\n // legitimately return different rows for the same `contains`.\n readonly supportsInsensitiveMode = false;\n\n // `in (?, ?, ?)`: the length is part of the text, so it is part of the plan.\n readonly bindsListAsOneParameter = false;\n\n // SQLite has had RETURNING since 3.35; Bun 1.3.14 bundles 3.51.0, confirmed by\n // querying `select sqlite_version()` through the driver rather than by reading\n // a changelog. Multi-row `insert ... returning` was verified there too, since\n // `createMany` depends on it for its row count.\n readonly supportsReturning = true;\n\n // `SQLITE_MAX_VARIABLE_NUMBER`, which has defaulted to 32766 since SQLite\n // 3.32 (it was 999 before). A build can lower it and `sqlite3_limit` can\n // lower it further at runtime, so this is the documented default rather than\n // a reading off the connection — which makes it an upper bound on what is\n // safe, which is the direction that matters for a guard.\n readonly maxBoundParameters = 32766;\n\n // A parameter's type is the bound value's, and `cast(x as json)` is NUMERIC\n // affinity rather than a JSON cast — `cast('{\"a\":1}' as json)` is `0`. So\n // there is no #376 mis-store to correct here, and correcting one anyway would\n // emit `cast(? as text)::json`, which SQLite refuses to parse. Measured with\n // `bun:sqlite`; the table is on `SqlDialect.typesParametersFromStatement`.\n readonly typesParametersFromStatement = false;\n\n quoteIdent(name: string): string {\n // NUL is the parameter sentinel in compile/fragment.ts, so it is the one\n // character that could shift a placeholder's position rather than merely\n // produce broken SQL. An identifier from the generated schema cannot\n // contain one — but asserting it makes the invariant unconditional instead\n // of argued, which is the standard the rest of this file holds.\n if (name.includes(\"\\u0000\")) {\n throw new Error(\n `Refusing to quote the identifier ${JSON.stringify(name)}: it contains ` +\n `a NUL byte, which is reserved as the parameter marker.`,\n );\n }\n // An embedded quote is not an attack vector for the same reason, but\n // escaping it costs nothing.\n return `\"${name.replace(/\"/g, '\"\"')}\"`;\n }\n\n placeholder(_index: number): string {\n return \"?\";\n }\n\n // One placeholder per element, so the array's length is part of the SQL text\n // and therefore part of the plan key. `in: [1,2]` and `in: [1,2,3]` are two\n // plans here; on Postgres they are one. See the note on `SqlDialect`.\n inList(\n lhs: string,\n negated: boolean,\n length: number,\n values: Binder,\n ): Fragment {\n const operator = negated ? \"not in\" : \"in\";\n const elements: Fragment[] = [];\n for (let i = 0; i < length; i++) {\n elements.push(\n param((args, context) => (values(args, context) as unknown[])[i]),\n );\n }\n return concat(\n sql(`${lhs} ${operator} (`),\n joinFragments(elements, \", \"),\n sql(\")\"),\n );\n }\n\n /**\n * Never. SQLite has no `unnest`, and its row-value `in` still needs one\n * `(?, ?)` group per tuple — so the text grows with the list either way and\n * there is nothing to gain over the `OR` the loader already builds.\n *\n * That is consistent with the single-column case: `plan.ts` records that \"a\n * coarser key cannot fix the SQLite side\", because every distinct length is\n * genuinely a different statement here.\n */\n canBindCompositeIn(): boolean {\n return false;\n }\n\n compositeIn(): Fragment {\n // Unreachable: the caller asks `canBindCompositeIn` first and keeps the\n // portable `OR` when it says no. Throwing rather than emitting something\n // plausible keeps the two from disagreeing silently.\n throw new Error(\n \"SQLite cannot bind a composite `in`; `canBindCompositeIn` is the guard.\",\n );\n }\n\n /**\n * **None**, because SQLite has no array type — and this is Prisma's answer\n * before it is gemi's. The generated client never sees such a column here:\n * `prisma generate` refuses the *schema* with *\"Field `tags` in model `User`\n * can't be a list. The current connector does not support lists of primitive\n * types.\"*\n *\n * So the only way to reach a scalar list on this dialect is an artifact\n * generated against a Postgres schema and a `DATABASE_URL` pointed at SQLite\n * — a real configuration, since the artifact is deliberately dialect-agnostic\n * (#300), and one where the underlying table has no such column either. An\n * empty set is what turns that into a refusal naming the dialect, in place of\n * `no such column: tags` from the driver.\n */\n readonly listFilters: ReadonlySet<string> = new Set();\n\n // All five are unreachable: `listFilters` is empty, so `where.ts` and\n // `write.ts` refuse first with a message naming the dialect. Throwing rather\n // than emitting something plausible keeps the two from disagreeing silently —\n // the same call `compositeIn` and `jsonArrayContains` above already make.\n listHas(): Fragment {\n throw new Error(unsupportedList(\"has\"));\n }\n\n listHasEvery(): Fragment {\n throw new Error(unsupportedList(\"hasEvery\"));\n }\n\n listHasSome(): Fragment {\n throw new Error(unsupportedList(\"hasSome\"));\n }\n\n listIsEmpty(): Fragment {\n throw new Error(unsupportedList(\"isEmpty\"));\n }\n\n listPush(): Fragment {\n throw new Error(unsupportedList(\"push\"));\n }\n\n /**\n * `path: \"$.a.b\"` — a JSONPath *string*, where Postgres takes an array.\n *\n * Prisma's own split, measured on both: the generated client refuses\n * `[\"a\",\"b\"]` here with *\"Expected String, provided (String)\"* and refuses\n * `\"$.a.b\"` on Postgres with *\"Expected String[], provided String\"*. So the\n * argument a caller writes is dialect-specific before it reaches this ORM,\n * and reproducing that is what compatibility means.\n */\n readonly jsonPathSyntax = \"jsonpath\" as const;\n\n /**\n * What Prisma will apply to an extracted value here — and the absences are\n * the point. `array_contains` and the numeric comparisons are refused by the\n * generated client on SQLite with *\"Unknown argument\"*, so accepting them\n * would put gemi ahead of Prisma on a dialect where a differential test has\n * no oracle to check it against.\n */\n readonly jsonFilters: ReadonlySet<string> = new Set([\n \"equals\",\n \"not\",\n \"string_contains\",\n \"string_starts_with\",\n \"string_ends_with\",\n ]);\n\n /**\n * `json_extract` returns a *native* value — an INTEGER for a JSON number —\n * so `equals: 3` binds `3`. Binding `\"3\"` compares INTEGER to TEXT, which\n * SQLite answers `false` rather than refusing: no rows, no error, and the\n * differential harness catching it against Prisma is the only reason it did\n * not ship that way.\n */\n readonly jsonComparesAsText = false;\n\n /**\n * `json_extract(\"col\", ?)`, with the path bound.\n *\n * SQLite has no separate text-returning extraction: `json_extract` already\n * yields a SQL value rather than a JSON document for a scalar at the path, so\n * `asText` changes nothing. That is why the string filters can compare\n * against it directly.\n */\n jsonExtract(column: string, path: Binder, _asText: boolean): Fragment {\n return concat(sql(`json_extract(${column}, `), param(path), sql(\")\"));\n }\n\n jsonArrayContains(): Fragment {\n // Unreachable: `jsonFilters` does not list it, so `where.ts` refuses first\n // with a message naming the dialect. Throwing here rather than returning\n // something plausible keeps the two from disagreeing silently.\n throw new Error(\n \"SQLite cannot express array_contains; `jsonFilters` is the guard.\",\n );\n }\n\n like(lhs: string, _insensitive: boolean, pattern: Binder): Fragment {\n // `_insensitive` is unreachable — the compiler checks\n // `supportsInsensitiveMode` and raises a contextful error first.\n return concat(sql(`${lhs} like `), param(pattern));\n }\n\n // Not offered, and deliberately: see `SqlDialect.ignoreConflicts`. SQLite can\n // express it — `on conflict do nothing` works here — but Prisma rejects the\n // argument on this dialect, so implementing it would put gemi ahead of Prisma\n // on the one dialect where the differential harness could no longer check it.\n ignoreConflicts(): Fragment | null {\n return null;\n }\n\n // SQLite cannot parse `offset` without a preceding `limit`, so a bare `skip`\n // needs a limit anyway. `-1` is SQLite's \"no limit\", and it goes through a\n // parameter rather than into the text like everything else.\n paginate(take: Binder | null, skip: Binder | null): Fragment {\n if (!take && !skip) return sql(\"\");\n if (!skip) return concat(sql(\" limit \"), param(take!));\n return concat(\n sql(\" limit \"),\n param(take ?? (() => -1)),\n sql(\" offset \"),\n param(skip),\n );\n }\n\n // SQLite reports every constraint failure as a `SQLiteError`, distinguished\n // only by `code`. Read off the driver rather than guessed:\n //\n // UNIQUE constraint failed: T.email SQLITE_CONSTRAINT_UNIQUE\n // UNIQUE constraint failed: C.a, C.b SQLITE_CONSTRAINT_UNIQUE (composite)\n // NOT NULL constraint failed: N.v SQLITE_CONSTRAINT_NOTNULL\n // FOREIGN KEY constraint failed SQLITE_CONSTRAINT_FOREIGNKEY\n //\n // Matching on the code and not on the message is what keeps the last two from\n // being reported as duplicate keys. There is no constraint *name* in any of\n // them — SQLite does not carry one — so only the columns come back.\n constraintViolation(error: unknown): ConstraintViolation | null {\n const code = (error as { code?: unknown } | null)?.code;\n if (code !== \"SQLITE_CONSTRAINT_UNIQUE\" && code !== \"SQLITE_CONSTRAINT_PRIMARYKEY\") {\n return null;\n }\n\n const message = String((error as { message?: unknown }).message ?? \"\");\n const listed = /constraint failed:\\s*(.+)$/.exec(message);\n if (!listed) return { kind: \"unique\", columns: [] };\n\n const columns = listed[1]\n .split(\",\")\n .map((entry) => entry.trim())\n // Each entry is `Table.column`; the table is the one being written, so\n // only the column carries information. A column name may itself contain a\n // dot, so the split is on the *first* one.\n .map((entry) => {\n const dot = entry.indexOf(\".\");\n return dot === -1 ? entry : entry.slice(dot + 1);\n })\n .filter((entry) => entry !== \"\");\n\n return { kind: \"unique\", columns };\n }\n\n // Nothing to cast. SQLite stores JSON as text and has no typed jsonb column\n // to disagree with the parameter, which is why the boundary #209 describes is\n // a Postgres one.\n castParameter(_field: FieldSchema): string {\n return \"\";\n }\n\n encode(value: unknown, field: FieldSchema): unknown {\n if (value === null || value === undefined) return null;\n\n switch (field.type) {\n case \"DateTime\":\n // The one that bites: Bun's SQLite driver binds a `Date` object to\n // NULL, so `where: { createdAt: date }` would quietly match nothing.\n // Prisma stores DateTime as integer milliseconds, so that is what the\n // parameter has to be.\n return value instanceof Date ? value.getTime() : value;\n case \"Boolean\":\n // Bun already maps true/false to 1/0, but doing it here keeps the\n // stored representation the dialect's decision rather than the driver's.\n return typeof value === \"boolean\" ? (value ? 1 : 0) : value;\n case \"Json\":\n // **Always serialized, never passed through.** SQLite stores JSON as\n // text, so the column holds whatever string this returns — and the\n // `typeof value === \"string\" ? value : …` guard it used to carry could\n // not tell \"already JSON text\" from \"a JSON string value\". A field set\n // to the string `\"42\"` was stored as the text `42` and decoded back as\n // the *number* 42.\n //\n // `JSON.stringify` on every value is unambiguous: a string becomes\n // `\"42\"` with its quotes, which is what `JSON.parse` needs to hand back\n // a string. The mirror of `decode`, which parses unconditionally.\n //\n // Except Prisma's two null sentinels, which have no enumerable\n // properties and would serialise to `{}` — see `json-null.ts`.\n // `DbNull` is the column being NULL; `JsonNull` is the JSON value.\n {\n const kind = jsonNullKind(value);\n if (kind === \"db\") return null;\n if (kind === \"json\") return \"null\";\n // `AnyNull` is not one of the two storable nulls — it asks for both.\n // The same backstop as `compile/cast.ts`, and for the same reason:\n // silently serialising it here is #259's `{}` by another route.\n if (kind === \"any\") {\n throw new Error(\n \"gemi ORM bug: Prisma.AnyNull reached the SQLite encoder. It is \" +\n \"a filter operand only, and both the filter and write paths \" +\n \"are supposed to have handled it before this point.\",\n );\n }\n }\n return JSON.stringify(value);\n default:\n // BigInt passes through. Bun's driver truncates integers above 2^53 on\n // the way in, which affects a raw `db.sql` query identically — it is\n // not something the compiler can correct at the parameter level.\n return value;\n }\n }\n\n // The two conversions above that do not need a field to decide: a `Date` is\n // milliseconds and a boolean is 0/1, which is what the ORM writes and\n // therefore what a raw statement has to compare against.\n //\n // Everything else is handed to the driver as it arrived, **including a plain\n // object**, and that is a decision rather than an omission. Measured, since\n // the obvious guesses are both wrong: Bun binds a plain object without\n // complaint on *both* dialects, and on Postgres it lands correctly in a\n // `jsonb` column — an object bound into one comes back as the object. So\n // refusing them here would break the legitimate case to catch the mistaken\n // one. On SQLite the same value binds to something no row matches, silently;\n // stringify it yourself if the column is JSON.\n //\n // Guessing from the value is the other tempting fix and is worse: the\n // compiler only JSON-encodes because a field says `Json`, and encoding on\n // sight would turn a mistyped parameter into a successfully-written string.\n // (An *array* is the one Bun does reject on SQLite, with\n // `SQLite query expected 1 values, received 2` — a confusing message for a\n // real mistake, but a loud one.)\n encodeUntyped(value: unknown): unknown {\n if (value instanceof Date) return value.getTime();\n if (typeof value === \"boolean\") return value ? 1 : 0;\n return value;\n }\n\n needsDecode(field: FieldSchema): boolean {\n switch (field.type) {\n case \"DateTime\":\n case \"Boolean\":\n case \"BigInt\":\n case \"Json\":\n return true;\n default:\n return false;\n }\n }\n\n decode(value: unknown, field: FieldSchema): unknown {\n // The driver reports a missing value as `null`; Prisma does too, so there\n // is nothing to convert. `undefined` can only appear if a column was not\n // selected, which the explicit column list makes impossible.\n if (value === null || value === undefined) return null;\n\n switch (field.type) {\n case \"DateTime\":\n return toDate(value, field);\n case \"Boolean\":\n if (typeof value === \"boolean\") return value;\n // `Number(...)` rather than `value !== 0`: a bigint zero is `0n`, and\n // `0n !== 0` is true, so a strict comparison would decode it as `true`.\n return Number(value) !== 0;\n case \"BigInt\":\n if (typeof value === \"bigint\") return value;\n try {\n return BigInt(value as string);\n } catch {\n // `BigInt(3.5)` throws a RangeError naming neither the column nor the\n // field, which is not enough to act on.\n throw new DecodeError(field, value);\n }\n case \"Json\":\n try {\n return typeof value === \"string\" ? JSON.parse(value) : value;\n } catch {\n throw new DecodeError(field, value);\n }\n default:\n return value;\n }\n }\n}\n\nfunction unsupportedList(operator: string): string {\n return (\n `SQLite has no array type, so it cannot express '${operator}' on a scalar ` +\n `list; \\`listFilters\\` is the guard.`\n );\n}\n",
13
- "import type { Dialect } from \"../../database/dialect\";\nimport type { Binder, Fragment } from \"../compile/fragment\";\nimport type { FieldSchema, ScalarType } from \"../schema\";\nimport { PostgresDialect } from \"./postgres\";\nimport { SqliteDialect } from \"./sqlite\";\n\n/**\n * The per-database strategy.\n *\n * The rule this interface exists to enforce: no `if (dialect === \"postgres\")`\n * ever appears inside the compiler. When something genuinely cannot be\n * expressed through the interface, the interface widens — which is why\n * `inList`, `like` and `paginate` return `Fragment`s rather than strings. Each\n * of the three is a place where SQLite and Postgres disagree about *structure*,\n * not just spelling:\n *\n * - `inList` — SQLite expands one placeholder per element, so `in: [1,2]` and\n * `in: [1,2,3]` are different SQL and different plans. Postgres binds the\n * whole array to one parameter with `= any($1)`, so every length shares a\n * single plan and a single prepared statement.\n * - `like` — Postgres has `ilike` for `mode: \"insensitive\"`; SQLite has no\n * equivalent, and Prisma rejects the argument there outright.\n * - `paginate` — SQLite cannot parse `offset` without a preceding `limit`.\n */\nexport interface SqlDialect {\n readonly name: Dialect;\n\n /**\n * Whether `mode: \"insensitive\"` can be expressed at all. False on SQLite,\n * where Prisma rejects the argument rather than emulating it.\n */\n readonly supportsInsensitiveMode: boolean;\n\n /**\n * Whether an `in` list binds as a single parameter however long it is.\n *\n * True on Postgres (`= any($1)`), false on SQLite (`in (?, ?, ?)`). It is the\n * plan *cache* that needs to know: where the length does not change the SQL\n * text, it must not change the cache key either, or every distinct list\n * length mints another entry holding SQL identical to its neighbours'. That\n * matters most for relations, where the list length is the parent row count\n * and so varies with the data rather than with the code.\n */\n readonly bindsListAsOneParameter: boolean;\n\n /**\n * Whether `insert`/`update`/`delete` can return the rows they touched.\n *\n * True on both implemented dialects — Postgres has had `RETURNING` forever,\n * and SQLite since 3.35 (Bun 1.3.14 bundles 3.51.0, verified by querying\n * `sqlite_version()` rather than by reading a changelog).\n *\n * It is a capability rather than an assumption because MySQL and MariaDB have\n * no `RETURNING` at all. Their fallback — `lastInsertRowid` plus a re-select,\n * and no way to identify the rows an `updateMany` touched — is a different\n * statement shape, not a different spelling. Iteration 4 does not build it,\n * but it must stay expressible, so the write compiler asks rather than\n * assumes and raises a clear error when the answer is no.\n */\n readonly supportsReturning: boolean;\n\n /**\n * How many parameters one statement may bind.\n *\n * A hard protocol/driver limit, not a tuning knob: Postgres sends the\n * parameter count as an int16 in the Bind message, and SQLite compiles\n * `SQLITE_MAX_VARIABLE_NUMBER` in.\n *\n * Three shapes can approach it, all of them scaling with the caller's *data*\n * rather than with the query's shape:\n *\n * - `createMany`, at `rows × columns`.\n * - An `in` list on SQLite, which binds one placeholder per element — and\n * such a list is routinely request-derived (`?ids=…`).\n * - A to-many `include` on SQLite, which batches an `in` over the parent\n * keys, so a large enough `findMany` reaches it with no big list in sight.\n *\n * Postgres escapes the last two: `= any($1)` is one parameter however long\n * the array. The check itself lives in `compile/fragment.ts`'s `render`,\n * because that is the one place that sees a statement's final count.\n *\n * It lives *here* rather than as a constant in the compiler for the usual\n * reason: the number differs per dialect, and the compiler is not allowed to\n * know which dialect it is compiling for.\n */\n readonly maxBoundParameters: number;\n\n /**\n * Whether the **statement** decides a parameter's type, so a cast the caller\n * wrote onto their own placeholder changes how the driver encodes the value.\n *\n * True on Postgres: the server describes the statement, the client is told\n * the parameter is `jsonb`, and Bun then JSON-*encodes* whatever JS value it\n * was handed. That is the whole of #376 — the reason `json-param.ts` retypes\n * such a parameter through `text` and serialises it to match.\n *\n * False on SQLite, and not merely because the correction is unnecessary\n * there: it would be **wrong**, and it would not parse. A parameter's type is\n * the bound value's, and `cast(x as json)` is not a JSON cast at all — SQLite\n * takes any type name and applies affinity rules, and a name containing none\n * of INT/CHAR/CLOB/TEXT/BLOB/REAL/FLOA/DOUB gets NUMERIC affinity, so\n * `cast('{\"a\":1}' as json)` is `0`. Measured through `bun:sqlite` (Bun\n * 1.3.14):\n *\n * select cast(? as jsonb) -> 0 (runs)\n * select json_set('{\"a\":1}','$.b', cast(? as json)) -> {\"a\":1,\"b\":2}\n * select cast(? as text)::json -> ERROR unrecognized token: \":\"\n *\n * So the retyping's rewrite — `cast(? as text)::json` — turns a statement\n * that runs on SQLite today into a syntax error. `::` genuinely cannot fire\n * there (it does not parse), but `cast(… as …)` is not Postgres-only syntax,\n * and \"SQLite has no jsonb type\" is a claim about semantics rather than about\n * what the parser accepts. Asking here rather than matching on `name` is what\n * makes that a fact `tsc` and a test can hold.\n */\n readonly typesParametersFromStatement: boolean;\n\n /** Quote a table or column name. Only ever called with names from the schema. */\n quoteIdent(name: string): string;\n\n /**\n * The parameter marker for the `index`-th (0-based) parameter in a statement.\n * SQLite ignores the index and returns `?`; Postgres returns `$1`, `$2`, ...\n */\n placeholder(index: number): string;\n\n /**\n * Prisma-shaped value -> the value the driver must be handed for this field.\n * The mirror of `decode`, and just as load-bearing: Bun's SQLite driver binds\n * a `Date` to `NULL`, so an unencoded `where: { createdAt: date }` would\n * return no rows rather than failing.\n *\n * Applied at bind time, not compile time — it is a function of the value.\n * Which encoder runs is still decided from the schema, so compile stays pure.\n */\n encode(value: unknown, field: FieldSchema): unknown;\n\n /**\n * SQL appended to this field's placeholder, or `\"\"` for none.\n *\n * The one string a dialect contributes to the statement that is not a\n * parameter, so it must be a constant — never derived from a value, and never\n * from anything an application supplies. `fieldParam` is the only caller, and\n * a non-empty cast also means it serialises the value; the two travel\n * together and neither is correct alone (#209).\n */\n castParameter(field: FieldSchema): string;\n\n /**\n * The same, for a value with **no declared column type** — a parameter\n * interpolated into a composed raw fragment, where there is no schema to ask.\n *\n * It exists because \"raw\" cannot mean \"unportable\". Bun's SQLite driver\n * rejects a `Date` outright (`Binding expected string, TypedArray, boolean,\n * number, bigint or null`) while Postgres takes one, so\n * ``sql`where \"createdAt\" > ${date}` `` would work on one dialect and throw on\n * the other — and the caller has no dialect-independent value to reach for\n * instead, because milliseconds are only correct if that is what the ORM\n * stored. Which it is: this converts to exactly what `encode` writes for a\n * `DateTime`, so a raw statement compares against ORM-written rows correctly.\n *\n * Deliberately narrow. It normalises the JavaScript types whose SQL form the\n * ORM has already decided — a `Date`, a boolean — and touches nothing else. A\n * plain object is *not* JSON-encoded here: the compiler only knows to do that\n * because a field says `Json`, and guessing from the value would turn a\n * mistyped parameter into a successfully-written string.\n *\n * The exception is a parameter the *caller* cast to `json`/`jsonb`, which is\n * a declared type by another route and does not reach this at all — see\n * `json-param.ts`. It is still not a guess from the value: the statement says\n * so.\n */\n encodeUntyped(value: unknown): unknown;\n\n /** Driver value -> the value Prisma would have returned for this field. */\n decode(value: unknown, field: FieldSchema): unknown;\n\n /**\n * False when the driver already returns exactly what Prisma would for this\n * field, letting the shaper skip the call entirely on the hot path.\n */\n needsDecode(field: FieldSchema): boolean;\n\n /**\n * `<lhs> in (...)` / `<lhs> not in (...)`.\n *\n * `length` is the element count, which is shape information and is already\n * part of the plan key. `values` returns the whole array at bind time; how it\n * is spread across parameters is the dialect's business.\n */\n inList(\n lhs: string,\n negated: boolean,\n length: number,\n values: Binder,\n ): Fragment;\n\n /** `<lhs> like <pattern>`, case-insensitively when the dialect can. */\n like(lhs: string, insensitive: boolean, pattern: Binder): Fragment;\n\n /**\n * Whether this dialect can match a **tuple** of columns against a list of\n * tuples in a statement whose text does not grow with the list.\n *\n * The single-column case is `inList`, and on Postgres `= any($1)` already\n * gives one SQL text for every length — which is what lets `collapsedList`\n * keep a batched relation query to one plan entry however many parents it\n * has. A relation joining on *more than one* field cannot use it, so the\n * loader falls back to an `OR` of `AND`s whose text does grow, and the plan\n * cache churns with the parent count (#97).\n *\n * `unnest` closes that on Postgres — one array parameter per *column*, so the\n * text is fixed — but it needs each column's SQL type for the cast, and the\n * types are asked about here rather than assumed: a dialect that cannot spell\n * one of them says so and the caller keeps the portable `OR`.\n */\n canBindCompositeIn(types: readonly ScalarType[]): boolean;\n\n /**\n * `(a, b) in (select * from unnest($1::t[], $2::u[]))`.\n *\n * `values` yields one tuple per parent at bind time; the dialect decides how\n * they are transposed into per-column arrays. Only called when\n * {@link canBindCompositeIn} returned true for these types.\n */\n compositeIn(\n columns: readonly string[],\n types: readonly ScalarType[],\n values: Binder,\n ): Fragment;\n\n /**\n * The filters this dialect can apply to a **scalar list** — `tags String[]`.\n *\n * **Empty is the whole of SQLite's answer**, and it is a capability rather\n * than a gap in this ORM: SQLite has no array type, and Prisma refuses the\n * declaration there at validation time — *\"Field `tags` in model `User` can't\n * be a list. The current connector does not support lists of primitive\n * types.\"* So a SQLite database cannot hold such a column to begin with.\n *\n * The refusal lives here rather than in the generator, which is where it used\n * to live (#300). The generated artifact is dialect-agnostic on purpose —\n * `DATABASE_URL` can name a different database than `prisma generate` saw —\n * so a generator that refused a scalar list refused it for Postgres too, and\n * one `String[]` anywhere meant no artifact for *any* model. Asking the\n * dialect at compile time refuses exactly the combination that cannot work,\n * and names it, which is the shape {@link UnsupportedDialectError} already\n * has for the dialects with no compiler at all.\n */\n readonly listFilters: ReadonlySet<string>;\n\n /**\n * `<value> = any(<column>)` — is this element in the list?\n *\n * The mirror of {@link inList} rather than a variant of it, and the two are\n * easy to confuse: there, one column is matched against a caller's list;\n * here, one caller value is matched against a column that *is* a list.\n *\n * **These four take a `Fragment` where every other member here takes a\n * `Binder`**, which is a deliberate exception. A list operand may need a cast\n * on its placeholder — a single element of a `Json[]` needs #209's\n * `::text::jsonb`, and the serialisation that must travel with it — so the\n * parameter is built by `fieldParam` before it arrives and the dialect\n * chooses only the operator. Handing over a `Binder` instead would oblige\n * each dialect to restate `fieldParam`'s rule, and restating it slightly\n * wrong is silent: `$1::jsonb = any(col)` answers *false* where\n * `$1::text::jsonb = any(col)` answers true, with no error on either.\n */\n listHas(column: string, value: Fragment): Fragment;\n\n /** `hasEvery` — every element of the operand is present in the column. */\n listHasEvery(column: string, values: Fragment): Fragment;\n\n /** `hasSome` — the column and the operand share at least one element. */\n listHasSome(column: string, values: Fragment): Fragment;\n\n /**\n * `isEmpty: true`, or its negation when `empty` is false.\n *\n * The odd one out with no operand at all: the value being compared against is\n * the empty list, which is the compiler's own constant rather than the\n * caller's. It stays a bound parameter regardless — see `jsonNullComparison`,\n * which declines the same exception for the same reason.\n */\n listIsEmpty(column: string, empty: boolean): Fragment;\n\n /**\n * The right-hand side of a `push`: the column's current value with the\n * operand appended. An expression rather than a statement, because it is\n * assigned by the write compiler like any other `set` value.\n */\n listPush(column: string, values: Fragment): Fragment;\n\n /**\n * How this dialect spells a JSON path, and which filters it can apply to one.\n *\n * The **path grammar itself differs**, which is unusual enough to be worth\n * stating rather than hiding: Prisma takes `path: [\"a\", \"b\"]` on Postgres and\n * `path: \"$.a.b\"` on SQLite, and refuses the other form on each. That is not\n * a gemi choice — it is the shape the generated client accepts, measured on\n * both — so reproducing it is what \"Prisma-compatible\" means here.\n *\n * `jsonFilters` is the set of scalar filters the dialect can apply to an\n * extracted value. Prisma refuses `array_contains` and the numeric\n * comparisons on SQLite with *\"Unknown argument\"*, so refusing them here is\n * matching it rather than falling short of it.\n */\n readonly jsonPathSyntax: \"array\" | \"jsonpath\";\n readonly jsonFilters: ReadonlySet<string>;\n\n /**\n * Whether an extracted value compares as **text**.\n *\n * Postgres's `#>>` yields `text`, so `equals: 3` has to bind `\"3\"` — comparing\n * text to an integer parameter is a type error there. SQLite's `json_extract`\n * yields a native value, so the same filter has to bind `3`: bind `\"3\"` and\n * SQLite compares an INTEGER to a TEXT, which is silently *false* rather than\n * an error. One filter, two encodings, and the wrong one is a returned-no-rows\n * bug on one dialect and a raised error on the other.\n */\n readonly jsonComparesAsText: boolean;\n\n /**\n * The extracted value, as a fragment whose path is **bound**.\n *\n * A JSON path is the one place a caller's *value* decides part of an\n * expression's meaning, which makes it the obvious place to interpolate by\n * accident and break invariant 2. Both dialects can take it as a parameter —\n * Postgres's `#>` accepts a `text[]`, SQLite's `json_extract` a string — so\n * nothing has to be bent to keep it out of the SQL text.\n *\n * `asText` picks the extraction that yields SQL text rather than JSON. Every\n * comparison in `jsonComparison` passes `true` — the string filters compare\n * against text, and `equals` / `not` / the numeric operators compare an\n * extracted *scalar*, which is what the text form gives them. The JSON form\n * has exactly one caller, `jsonArrayContains`, because containment is the one\n * operator whose right-hand side is a document.\n *\n * SQLite ignores the flag: `json_extract` already yields a SQL value rather\n * than a JSON document for a scalar at the path.\n */\n jsonExtract(column: string, path: Binder, asText: boolean): Fragment;\n\n /** `<extracted> @> <value>` — Postgres only; see `jsonFilters`. */\n jsonArrayContains(column: string, path: Binder, value: Binder): Fragment;\n\n /**\n * `limit`/`offset`. Both are values and therefore parameters — this is the\n * single most tempting place in the compiler to inline a number.\n */\n paginate(take: Binder | null, skip: Binder | null): Fragment;\n\n /**\n * The clause that makes an insert skip rows violating a unique constraint —\n * `createMany({ skipDuplicates: true })` — or `null` where it is not offered.\n *\n * **`null` is a parity decision, not a missing feature**, and that is worth\n * knowing before someone \"fixes\" SQLite by returning `insert or ignore`.\n * SQLite has `on conflict do nothing` and has since 3.24; Prisma nonetheless\n * rejects the *argument* on SQLite — `Unknown argument 'skipDuplicates'`,\n * whatever its value, verified against a generated 6.19 client. Offering it\n * here would make gemi a silent superset of Prisma on the one dialect the\n * differential harness could then no longer compare, which is the trade this\n * project has declined every other time it came up.\n *\n * A method rather than a boolean because the SQL differs where it exists, and\n * a `Fragment` because everything the compiler emits is one.\n */\n ignoreConflicts(): Fragment | null;\n\n /**\n * Recognise a driver error as a constraint violation, and say which columns\n * it names.\n *\n * Returns `null` for anything else, including the *other* constraint kinds:\n * SQLite reports NOT NULL and FOREIGN KEY failures through the same exception\n * type, and reporting one of those as a duplicate-key error would send a\n * caller looking for a row that does not exist.\n *\n * Columns, not fields — the driver only knows the database's names. The\n * caller maps them back through the schema, where `@map` is in scope.\n */\n constraintViolation(error: unknown): ConstraintViolation | null;\n}\n\n/** A driver error identified as a constraint failure, in dialect-neutral terms. */\nexport interface ConstraintViolation {\n /** Only `unique` is translated today; the rest surface as the raw error. */\n kind: \"unique\";\n /** Database column names, in the order the driver reported them. */\n columns: string[];\n /** The constraint's own name, when the driver gives one. Postgres does. */\n constraint?: string;\n}\n\n/**\n * The ORM was asked to compile against a dialect it does not implement.\n *\n * **The split this message has to convey**, because it is the surprising part:\n * `DatabaseManager` connects to MySQL and MariaDB perfectly well — Bun's client\n * speaks all four — so raw SQL through `DB.query` / `DB.sql` works, and\n * transactions work. What does not exist is a `SqlDialect` for them, so\n * everything that *compiles* a statement stops here.\n *\n * A caller who reads only \"not supported\" reasonably concludes the connection\n * is unusable, which is wrong and is the more expensive misreading: it is the\n * ORM that is unavailable, not the database.\n */\nexport class UnsupportedDialectError extends Error {\n constructor(dialect: Dialect) {\n super(\n `The gemi ORM does not support the '${dialect}' dialect. Only sqlite ` +\n `and postgres are implemented — see the supported matrix in ` +\n `docs/orm.md.\\n\\n` +\n `The *connection* is fine: Bun's client speaks ${dialect}, so raw SQL ` +\n `through DB.query / DB.sql and transactions all work. It is the query ` +\n `compiler that has no ${dialect} dialect, so every model operation ` +\n `raises this.\\n\\n` +\n `Point DATABASE_URL at Postgres or SQLite to use the ORM, or keep ` +\n `using Prisma's own client for this database.`,\n );\n this.name = \"UnsupportedDialectError\";\n }\n}\n\n/**\n * Whether the ORM can compile for this dialect at all.\n *\n * Exported so an application can find out at **boot** rather than on its first\n * query. That is the whole gap this closes: `DatabaseManager` constructs\n * happily against MySQL, so a deploy pointed at one starts, passes a health\n * check, serves traffic, and fails on the first model read — which is the\n * latest and most expensive moment to learn it.\n */\nexport function ormSupports(dialect: Dialect): boolean {\n return COMPILERS[dialect] !== null;\n}\n\n/** Every dialect `Dialect` names, for anything that has to walk them all. */\nexport function everyDialect(): Dialect[] {\n return Object.keys(COMPILERS) as Dialect[];\n}\n\n/**\n * The compiler for each dialect, or `null` where the ORM has none.\n *\n * **One map rather than two lists, and `satisfies` rather than a lookup.** The\n * supported set used to be written three times — `ormSupports`' `||` chain,\n * `dialectFor`'s `if` chain, and a test enumerating a hand-written copy of the\n * `Dialect` union — so adding a fifth member to that union changed nothing\n * anywhere: `tsc` clean, tests green, the new dialect silently reported as\n * unsupported by one function and unknown to the other.\n *\n * That moment is exactly what the guard exists for. Adding a dialect to the\n * union is the *first step of implementing one*, and it is the step where a\n * half-added dialect would disagree with itself.\n *\n * `satisfies Record<Dialect, …>` makes it a compile error in a file the build\n * actually checks. It has to live here rather than in a test: `tsconfig.json`\n * excludes test files and vitest transpiles without type-checking, so an\n * exhaustiveness check written there is a type error nothing ever evaluates.\n *\n * The sixth thing in this codebase made `tsc`'s job rather than a convention's\n * — see the note on `resolveLink`'s `operation`.\n */\nconst COMPILERS = {\n sqlite: new SqliteDialect(),\n postgres: new PostgresDialect(),\n // Bun's client speaks both; the ORM has no compiler for either. See\n // `UnsupportedDialectError`, which is careful to say that the *connection*\n // still works.\n mysql: null,\n mariadb: null,\n} satisfies Record<Dialect, SqlDialect | null>;\n\n/**\n * Resolved per call from `DatabaseManager.dialect`, never baked into a\n * generated artifact — `DATABASE_URL` can point at a different database than\n * the one `prisma generate` saw.\n */\nexport function dialectFor(dialect: Dialect): SqlDialect {\n const compiler = COMPILERS[dialect];\n if (compiler === null) throw new UnsupportedDialectError(dialect);\n return compiler;\n}\n\nexport { PostgresDialect, SqliteDialect };\n"
12
+ "import type { Dialect } from \"../../database/dialect\";\nimport {\n type Binder,\n type Fragment,\n concat,\n joinFragments,\n param,\n sql,\n} from \"../compile/fragment\";\nimport { DecodeError } from \"../errors\";\nimport { jsonNullKind } from \"../json-null\";\nimport type { FieldSchema } from \"../schema\";\nimport type { ConstraintViolation, SqlDialect } from \"./index\";\n\n// SQLite has five storage classes and neither `DateTime` nor `Boolean` is among\n// them. Prisma stores a `DateTime` as integer milliseconds since the epoch and a\n// `Boolean` as `0` / `1`, so handing the driver's values straight back would\n// already diverge from Prisma's result shape on the template's `createdAt`.\n//\n// `CURRENT_TIMESTAMP` column defaults are the one exception: a row inserted by\n// raw SQL or by a migration rather than by Prisma holds the text form\n// `YYYY-MM-DD HH:MM:SS`, which SQLite defines as UTC. Both forms are decoded.\nconst SQLITE_TEXT_TIMESTAMP =\n /^\\d{4}-\\d{2}-\\d{2}[ T]\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?$/;\n\nfunction toDate(value: unknown, field: FieldSchema): Date {\n if (value instanceof Date) return value;\n\n let date: Date;\n if (typeof value === \"number\") {\n date = new Date(value);\n } else if (typeof value === \"bigint\") {\n date = new Date(Number(value));\n } else if (typeof value === \"string\") {\n // Naked SQLite timestamps carry no zone but are documented as UTC; `Date`\n // would otherwise read them as local time and shift them.\n date = new Date(\n SQLITE_TEXT_TIMESTAMP.test(value) ? `${value.replace(\" \", \"T\")}Z` : value,\n );\n } else {\n throw new DecodeError(field, value);\n }\n\n // `new Date(\"nonsense\")` is an `Invalid Date`, not a throw — every field on it\n // reads `NaN`. Returning one would be a wrong answer rather than an error,\n // which is the failure mode this whole file exists to avoid.\n if (Number.isNaN(date.getTime())) throw new DecodeError(field, value);\n return date;\n}\n\nexport class SqliteDialect implements SqlDialect {\n readonly name: Dialect = \"sqlite\";\n\n // Prisma rejects `mode: \"insensitive\"` on SQLite rather than emulating it, so\n // gemi does too — the contract is with Prisma's behaviour, not with\n // cross-dialect uniformity. Note SQLite's `like` is *already* case-insensitive\n // for ASCII, which is the opposite of Postgres and is why the two dialects\n // legitimately return different rows for the same `contains`.\n readonly supportsInsensitiveMode = false;\n\n // `in (?, ?, ?)`: the length is part of the text, so it is part of the plan.\n readonly bindsListAsOneParameter = false;\n\n // SQLite has had RETURNING since 3.35; Bun 1.3.14 bundles 3.51.0, confirmed by\n // querying `select sqlite_version()` through the driver rather than by reading\n // a changelog. Multi-row `insert ... returning` was verified there too, since\n // `createMany` depends on it for its row count.\n readonly supportsReturning = true;\n\n // `SQLITE_MAX_VARIABLE_NUMBER`, which has defaulted to 32766 since SQLite\n // 3.32 (it was 999 before). A build can lower it and `sqlite3_limit` can\n // lower it further at runtime, so this is the documented default rather than\n // a reading off the connection — which makes it an upper bound on what is\n // safe, which is the direction that matters for a guard.\n readonly maxBoundParameters = 32766;\n\n // A parameter's type is the bound value's, and `cast(x as json)` is NUMERIC\n // affinity rather than a JSON cast — `cast('{\"a\":1}' as json)` is `0`. So\n // there is no #376 mis-store to correct here, and correcting one anyway would\n // emit `cast(? as text)::json`, which SQLite refuses to parse. Measured with\n // `bun:sqlite`; the table is on `SqlDialect.typesParametersFromStatement`.\n readonly typesParametersFromStatement = false;\n\n quoteIdent(name: string): string {\n // NUL is the parameter sentinel in compile/fragment.ts, so it is the one\n // character that could shift a placeholder's position rather than merely\n // produce broken SQL. An identifier from the generated schema cannot\n // contain one — but asserting it makes the invariant unconditional instead\n // of argued, which is the standard the rest of this file holds.\n if (name.includes(\"\\u0000\")) {\n throw new Error(\n `Refusing to quote the identifier ${JSON.stringify(name)}: it contains ` +\n `a NUL byte, which is reserved as the parameter marker.`,\n );\n }\n // An embedded quote is not an attack vector for the same reason, but\n // escaping it costs nothing.\n return `\"${name.replace(/\"/g, '\"\"')}\"`;\n }\n\n placeholder(_index: number): string {\n return \"?\";\n }\n\n // One placeholder per element, so the array's length is part of the SQL text\n // and therefore part of the plan key. `in: [1,2]` and `in: [1,2,3]` are two\n // plans here; on Postgres they are one. See the note on `SqlDialect`.\n inList(\n lhs: string,\n negated: boolean,\n length: number,\n values: Binder,\n ): Fragment {\n const operator = negated ? \"not in\" : \"in\";\n const elements: Fragment[] = [];\n for (let i = 0; i < length; i++) {\n elements.push(\n param((args, context) => (values(args, context) as unknown[])[i]),\n );\n }\n return concat(\n sql(`${lhs} ${operator} (`),\n joinFragments(elements, \", \"),\n sql(\")\"),\n );\n }\n\n /**\n * Never. SQLite has no `unnest`, and its row-value `in` still needs one\n * `(?, ?)` group per tuple — so the text grows with the list either way and\n * there is nothing to gain over the `OR` the loader already builds.\n *\n * That is consistent with the single-column case: `plan.ts` records that \"a\n * coarser key cannot fix the SQLite side\", because every distinct length is\n * genuinely a different statement here.\n */\n canBindCompositeIn(): boolean {\n return false;\n }\n\n compositeIn(): Fragment {\n // Unreachable: the caller asks `canBindCompositeIn` first and keeps the\n // portable `OR` when it says no. Throwing rather than emitting something\n // plausible keeps the two from disagreeing silently.\n throw new Error(\n \"SQLite cannot bind a composite `in`; `canBindCompositeIn` is the guard.\",\n );\n }\n\n /**\n * **None**, because SQLite has no array type — and this is Prisma's answer\n * before it is gemi's. The generated client never sees such a column here:\n * `prisma generate` refuses the *schema* with *\"Field `tags` in model `User`\n * can't be a list. The current connector does not support lists of primitive\n * types.\"*\n *\n * So the only way to reach a scalar list on this dialect is an artifact\n * generated against a Postgres schema and a `DATABASE_URL` pointed at SQLite\n * — a real configuration, since the artifact is deliberately dialect-agnostic\n * (#300), and one where the underlying table has no such column either. An\n * empty set is what turns that into a refusal naming the dialect, in place of\n * `no such column: tags` from the driver.\n */\n readonly listFilters: ReadonlySet<string> = new Set();\n\n // All five are unreachable: `listFilters` is empty, so `where.ts` and\n // `write.ts` refuse first with a message naming the dialect. Throwing rather\n // than emitting something plausible keeps the two from disagreeing silently —\n // the same call `compositeIn` and `jsonArrayContains` above already make.\n listHas(): Fragment {\n throw new Error(unsupportedList(\"has\"));\n }\n\n listHasEvery(): Fragment {\n throw new Error(unsupportedList(\"hasEvery\"));\n }\n\n listHasSome(): Fragment {\n throw new Error(unsupportedList(\"hasSome\"));\n }\n\n listIsEmpty(): Fragment {\n throw new Error(unsupportedList(\"isEmpty\"));\n }\n\n listPush(): Fragment {\n throw new Error(unsupportedList(\"push\"));\n }\n\n /**\n * `path: \"$.a.b\"` — a JSONPath *string*, where Postgres takes an array.\n *\n * Prisma's own split, measured on both: the generated client refuses\n * `[\"a\",\"b\"]` here with *\"Expected String, provided (String)\"* and refuses\n * `\"$.a.b\"` on Postgres with *\"Expected String[], provided String\"*. So the\n * argument a caller writes is dialect-specific before it reaches this ORM,\n * and reproducing that is what compatibility means.\n */\n readonly jsonPathSyntax = \"jsonpath\" as const;\n\n /**\n * What Prisma will apply to an extracted value here — and the absences are\n * the point. `array_contains` and the numeric comparisons are refused by the\n * generated client on SQLite with *\"Unknown argument\"*, so accepting them\n * would put gemi ahead of Prisma on a dialect where a differential test has\n * no oracle to check it against.\n */\n readonly jsonFilters: ReadonlySet<string> = new Set([\n \"equals\",\n \"not\",\n \"string_contains\",\n \"string_starts_with\",\n \"string_ends_with\",\n ]);\n\n /**\n * `json_extract` returns a *native* value — an INTEGER for a JSON number —\n * so `equals: 3` binds `3`. Binding `\"3\"` compares INTEGER to TEXT, which\n * SQLite answers `false` rather than refusing: no rows, no error, and the\n * differential harness catching it against Prisma is the only reason it did\n * not ship that way.\n */\n readonly jsonComparesAsText = false;\n\n /**\n * `json_extract(\"col\", ?)`, with the path bound.\n *\n * SQLite has no separate text-returning extraction: `json_extract` already\n * yields a SQL value rather than a JSON document for a scalar at the path, so\n * `asText` changes nothing. That is why the string filters can compare\n * against it directly.\n */\n jsonExtract(column: string, path: Binder, _asText: boolean): Fragment {\n return concat(sql(`json_extract(${column}, `), param(path), sql(\")\"));\n }\n\n /**\n * `(\"col\" -> ?)` — the JSON value at the path, as JSON text.\n *\n * **`->` rather than `json_extract`, and the difference is the whole point.**\n * `json_extract` returns a *native* SQL value, so a JSON `null` comes back as\n * SQL NULL and is then indistinguishable from an absent key — the collapse\n * that had the sentinels refused here. `->` returns the JSON *text* of the\n * subcomponent, which keeps them apart. Measured on SQLite 3.51 against\n * `'$.operation'`:\n *\n * {\"operation\":null} ->: 'null' json_extract: NULL\n * {\"other\":1} ->: NULL json_extract: NULL\n * {\"operation\":\"sync\"} ->: '\"sync\"' json_extract: 'sync'\n * {\"operation\":\"null\"} ->: '\"null\"' json_extract: 'null'\n *\n * The last row is why this is a real distinction rather than a spelling one:\n * a JSON string `\"null\"` and a JSON null differ under `->` (the quotes are\n * part of the text) and are the same under `json_extract`. So\n * `equals: JsonNull` does not accidentally match a document holding the\n * string.\n *\n * `json_type` would answer the same question and is the form #407 proposed;\n * `->` is what Prisma emits here — `` `Doc`.`payload`->? IS NULL `` — and\n * matching the oracle's operator costs nothing over inventing a second one.\n * It needs SQLite 3.38 (2022); Bun ships 3.51.\n *\n * No cast, unlike Postgres: `->` already yields the text form both sides of\n * the comparison are in, and `encode` spells a JSON null `'null'` for the\n * bound side.\n */\n jsonValueAt(column: string, path: Binder): Fragment {\n return concat(sql(`(${column} -> `), param(path), sql(\")\"));\n }\n\n jsonArrayContains(): Fragment {\n // Unreachable: `jsonFilters` does not list it, so `where.ts` refuses first\n // with a message naming the dialect. Throwing here rather than returning\n // something plausible keeps the two from disagreeing silently.\n throw new Error(\n \"SQLite cannot express array_contains; `jsonFilters` is the guard.\",\n );\n }\n\n like(lhs: string, _insensitive: boolean, pattern: Binder): Fragment {\n // `_insensitive` is unreachable — the compiler checks\n // `supportsInsensitiveMode` and raises a contextful error first.\n return concat(sql(`${lhs} like `), param(pattern));\n }\n\n // Not offered, and deliberately: see `SqlDialect.ignoreConflicts`. SQLite can\n // express it — `on conflict do nothing` works here — but Prisma rejects the\n // argument on this dialect, so implementing it would put gemi ahead of Prisma\n // on the one dialect where the differential harness could no longer check it.\n ignoreConflicts(): Fragment | null {\n return null;\n }\n\n // SQLite cannot parse `offset` without a preceding `limit`, so a bare `skip`\n // needs a limit anyway. `-1` is SQLite's \"no limit\", and it goes through a\n // parameter rather than into the text like everything else.\n paginate(take: Binder | null, skip: Binder | null): Fragment {\n if (!take && !skip) return sql(\"\");\n if (!skip) return concat(sql(\" limit \"), param(take!));\n return concat(\n sql(\" limit \"),\n param(take ?? (() => -1)),\n sql(\" offset \"),\n param(skip),\n );\n }\n\n // SQLite reports every constraint failure as a `SQLiteError`, distinguished\n // only by `code`. Read off the driver rather than guessed:\n //\n // UNIQUE constraint failed: T.email SQLITE_CONSTRAINT_UNIQUE\n // UNIQUE constraint failed: C.a, C.b SQLITE_CONSTRAINT_UNIQUE (composite)\n // NOT NULL constraint failed: N.v SQLITE_CONSTRAINT_NOTNULL\n // FOREIGN KEY constraint failed SQLITE_CONSTRAINT_FOREIGNKEY\n //\n // Matching on the code and not on the message is what keeps the last two from\n // being reported as duplicate keys. There is no constraint *name* in any of\n // them — SQLite does not carry one — so only the columns come back.\n constraintViolation(error: unknown): ConstraintViolation | null {\n const code = (error as { code?: unknown } | null)?.code;\n if (code !== \"SQLITE_CONSTRAINT_UNIQUE\" && code !== \"SQLITE_CONSTRAINT_PRIMARYKEY\") {\n return null;\n }\n\n const message = String((error as { message?: unknown }).message ?? \"\");\n const listed = /constraint failed:\\s*(.+)$/.exec(message);\n if (!listed) return { kind: \"unique\", columns: [] };\n\n const columns = listed[1]\n .split(\",\")\n .map((entry) => entry.trim())\n // Each entry is `Table.column`; the table is the one being written, so\n // only the column carries information. A column name may itself contain a\n // dot, so the split is on the *first* one.\n .map((entry) => {\n const dot = entry.indexOf(\".\");\n return dot === -1 ? entry : entry.slice(dot + 1);\n })\n .filter((entry) => entry !== \"\");\n\n return { kind: \"unique\", columns };\n }\n\n // Nothing to cast. SQLite stores JSON as text and has no typed jsonb column\n // to disagree with the parameter, which is why the boundary #209 describes is\n // a Postgres one.\n castParameter(_field: FieldSchema): string {\n return \"\";\n }\n\n encode(value: unknown, field: FieldSchema): unknown {\n if (value === null || value === undefined) return null;\n\n switch (field.type) {\n case \"DateTime\":\n // The one that bites: Bun's SQLite driver binds a `Date` object to\n // NULL, so `where: { createdAt: date }` would quietly match nothing.\n // Prisma stores DateTime as integer milliseconds, so that is what the\n // parameter has to be.\n return value instanceof Date ? value.getTime() : value;\n case \"Boolean\":\n // Bun already maps true/false to 1/0, but doing it here keeps the\n // stored representation the dialect's decision rather than the driver's.\n return typeof value === \"boolean\" ? (value ? 1 : 0) : value;\n case \"Json\":\n // **Always serialized, never passed through.** SQLite stores JSON as\n // text, so the column holds whatever string this returns — and the\n // `typeof value === \"string\" ? value : …` guard it used to carry could\n // not tell \"already JSON text\" from \"a JSON string value\". A field set\n // to the string `\"42\"` was stored as the text `42` and decoded back as\n // the *number* 42.\n //\n // `JSON.stringify` on every value is unambiguous: a string becomes\n // `\"42\"` with its quotes, which is what `JSON.parse` needs to hand back\n // a string. The mirror of `decode`, which parses unconditionally.\n //\n // Except Prisma's two null sentinels, which have no enumerable\n // properties and would serialise to `{}` — see `json-null.ts`.\n // `DbNull` is the column being NULL; `JsonNull` is the JSON value.\n {\n const kind = jsonNullKind(value);\n if (kind === \"db\") return null;\n if (kind === \"json\") return \"null\";\n // `AnyNull` is not one of the two storable nulls — it asks for both.\n // The same backstop as `compile/cast.ts`, and for the same reason:\n // silently serialising it here is #259's `{}` by another route.\n if (kind === \"any\") {\n throw new Error(\n \"gemi ORM bug: Prisma.AnyNull reached the SQLite encoder. It is \" +\n \"a filter operand only, and both the filter and write paths \" +\n \"are supposed to have handled it before this point.\",\n );\n }\n }\n return JSON.stringify(value);\n default:\n // BigInt passes through. Bun's driver truncates integers above 2^53 on\n // the way in, which affects a raw `db.sql` query identically — it is\n // not something the compiler can correct at the parameter level.\n return value;\n }\n }\n\n // The two conversions above that do not need a field to decide: a `Date` is\n // milliseconds and a boolean is 0/1, which is what the ORM writes and\n // therefore what a raw statement has to compare against.\n //\n // Everything else is handed to the driver as it arrived, **including a plain\n // object**, and that is a decision rather than an omission. Measured, since\n // the obvious guesses are both wrong: Bun binds a plain object without\n // complaint on *both* dialects, and on Postgres it lands correctly in a\n // `jsonb` column — an object bound into one comes back as the object. So\n // refusing them here would break the legitimate case to catch the mistaken\n // one. On SQLite the same value binds to something no row matches, silently;\n // stringify it yourself if the column is JSON.\n //\n // Guessing from the value is the other tempting fix and is worse: the\n // compiler only JSON-encodes because a field says `Json`, and encoding on\n // sight would turn a mistyped parameter into a successfully-written string.\n // (An *array* is the one Bun does reject on SQLite, with\n // `SQLite query expected 1 values, received 2` — a confusing message for a\n // real mistake, but a loud one.)\n encodeUntyped(value: unknown): unknown {\n if (value instanceof Date) return value.getTime();\n if (typeof value === \"boolean\") return value ? 1 : 0;\n return value;\n }\n\n needsDecode(field: FieldSchema): boolean {\n switch (field.type) {\n case \"DateTime\":\n case \"Boolean\":\n case \"BigInt\":\n case \"Json\":\n return true;\n default:\n return false;\n }\n }\n\n decode(value: unknown, field: FieldSchema): unknown {\n // The driver reports a missing value as `null`; Prisma does too, so there\n // is nothing to convert. `undefined` can only appear if a column was not\n // selected, which the explicit column list makes impossible.\n if (value === null || value === undefined) return null;\n\n switch (field.type) {\n case \"DateTime\":\n return toDate(value, field);\n case \"Boolean\":\n if (typeof value === \"boolean\") return value;\n // `Number(...)` rather than `value !== 0`: a bigint zero is `0n`, and\n // `0n !== 0` is true, so a strict comparison would decode it as `true`.\n return Number(value) !== 0;\n case \"BigInt\":\n if (typeof value === \"bigint\") return value;\n try {\n return BigInt(value as string);\n } catch {\n // `BigInt(3.5)` throws a RangeError naming neither the column nor the\n // field, which is not enough to act on.\n throw new DecodeError(field, value);\n }\n case \"Json\":\n try {\n return typeof value === \"string\" ? JSON.parse(value) : value;\n } catch {\n throw new DecodeError(field, value);\n }\n default:\n return value;\n }\n }\n}\n\nfunction unsupportedList(operator: string): string {\n return (\n `SQLite has no array type, so it cannot express '${operator}' on a scalar ` +\n `list; \\`listFilters\\` is the guard.`\n );\n}\n",
13
+ "import type { Dialect } from \"../../database/dialect\";\nimport type { Binder, Fragment } from \"../compile/fragment\";\nimport type { FieldSchema, ScalarType } from \"../schema\";\nimport { PostgresDialect } from \"./postgres\";\nimport { SqliteDialect } from \"./sqlite\";\n\n/**\n * The per-database strategy.\n *\n * The rule this interface exists to enforce: no `if (dialect === \"postgres\")`\n * ever appears inside the compiler. When something genuinely cannot be\n * expressed through the interface, the interface widens — which is why\n * `inList`, `like` and `paginate` return `Fragment`s rather than strings. Each\n * of the three is a place where SQLite and Postgres disagree about *structure*,\n * not just spelling:\n *\n * - `inList` — SQLite expands one placeholder per element, so `in: [1,2]` and\n * `in: [1,2,3]` are different SQL and different plans. Postgres binds the\n * whole array to one parameter with `= any($1)`, so every length shares a\n * single plan and a single prepared statement.\n * - `like` — Postgres has `ilike` for `mode: \"insensitive\"`; SQLite has no\n * equivalent, and Prisma rejects the argument there outright.\n * - `paginate` — SQLite cannot parse `offset` without a preceding `limit`.\n */\nexport interface SqlDialect {\n readonly name: Dialect;\n\n /**\n * Whether `mode: \"insensitive\"` can be expressed at all. False on SQLite,\n * where Prisma rejects the argument rather than emulating it.\n */\n readonly supportsInsensitiveMode: boolean;\n\n /**\n * Whether an `in` list binds as a single parameter however long it is.\n *\n * True on Postgres (`= any($1)`), false on SQLite (`in (?, ?, ?)`). It is the\n * plan *cache* that needs to know: where the length does not change the SQL\n * text, it must not change the cache key either, or every distinct list\n * length mints another entry holding SQL identical to its neighbours'. That\n * matters most for relations, where the list length is the parent row count\n * and so varies with the data rather than with the code.\n */\n readonly bindsListAsOneParameter: boolean;\n\n /**\n * Whether `insert`/`update`/`delete` can return the rows they touched.\n *\n * True on both implemented dialects — Postgres has had `RETURNING` forever,\n * and SQLite since 3.35 (Bun 1.3.14 bundles 3.51.0, verified by querying\n * `sqlite_version()` rather than by reading a changelog).\n *\n * It is a capability rather than an assumption because MySQL and MariaDB have\n * no `RETURNING` at all. Their fallback — `lastInsertRowid` plus a re-select,\n * and no way to identify the rows an `updateMany` touched — is a different\n * statement shape, not a different spelling. Iteration 4 does not build it,\n * but it must stay expressible, so the write compiler asks rather than\n * assumes and raises a clear error when the answer is no.\n */\n readonly supportsReturning: boolean;\n\n /**\n * How many parameters one statement may bind.\n *\n * A hard protocol/driver limit, not a tuning knob: Postgres sends the\n * parameter count as an int16 in the Bind message, and SQLite compiles\n * `SQLITE_MAX_VARIABLE_NUMBER` in.\n *\n * Three shapes can approach it, all of them scaling with the caller's *data*\n * rather than with the query's shape:\n *\n * - `createMany`, at `rows × columns`.\n * - An `in` list on SQLite, which binds one placeholder per element — and\n * such a list is routinely request-derived (`?ids=…`).\n * - A to-many `include` on SQLite, which batches an `in` over the parent\n * keys, so a large enough `findMany` reaches it with no big list in sight.\n *\n * Postgres escapes the last two: `= any($1)` is one parameter however long\n * the array. The check itself lives in `compile/fragment.ts`'s `render`,\n * because that is the one place that sees a statement's final count.\n *\n * It lives *here* rather than as a constant in the compiler for the usual\n * reason: the number differs per dialect, and the compiler is not allowed to\n * know which dialect it is compiling for.\n */\n readonly maxBoundParameters: number;\n\n /**\n * Whether the **statement** decides a parameter's type, so a cast the caller\n * wrote onto their own placeholder changes how the driver encodes the value.\n *\n * True on Postgres: the server describes the statement, the client is told\n * the parameter is `jsonb`, and Bun then JSON-*encodes* whatever JS value it\n * was handed. That is the whole of #376 — the reason `json-param.ts` retypes\n * such a parameter through `text` and serialises it to match.\n *\n * False on SQLite, and not merely because the correction is unnecessary\n * there: it would be **wrong**, and it would not parse. A parameter's type is\n * the bound value's, and `cast(x as json)` is not a JSON cast at all — SQLite\n * takes any type name and applies affinity rules, and a name containing none\n * of INT/CHAR/CLOB/TEXT/BLOB/REAL/FLOA/DOUB gets NUMERIC affinity, so\n * `cast('{\"a\":1}' as json)` is `0`. Measured through `bun:sqlite` (Bun\n * 1.3.14):\n *\n * select cast(? as jsonb) -> 0 (runs)\n * select json_set('{\"a\":1}','$.b', cast(? as json)) -> {\"a\":1,\"b\":2}\n * select cast(? as text)::json -> ERROR unrecognized token: \":\"\n *\n * So the retyping's rewrite — `cast(? as text)::json` — turns a statement\n * that runs on SQLite today into a syntax error. `::` genuinely cannot fire\n * there (it does not parse), but `cast(… as …)` is not Postgres-only syntax,\n * and \"SQLite has no jsonb type\" is a claim about semantics rather than about\n * what the parser accepts. Asking here rather than matching on `name` is what\n * makes that a fact `tsc` and a test can hold.\n */\n readonly typesParametersFromStatement: boolean;\n\n /** Quote a table or column name. Only ever called with names from the schema. */\n quoteIdent(name: string): string;\n\n /**\n * The parameter marker for the `index`-th (0-based) parameter in a statement.\n * SQLite ignores the index and returns `?`; Postgres returns `$1`, `$2`, ...\n */\n placeholder(index: number): string;\n\n /**\n * Prisma-shaped value -> the value the driver must be handed for this field.\n * The mirror of `decode`, and just as load-bearing: Bun's SQLite driver binds\n * a `Date` to `NULL`, so an unencoded `where: { createdAt: date }` would\n * return no rows rather than failing.\n *\n * Applied at bind time, not compile time — it is a function of the value.\n * Which encoder runs is still decided from the schema, so compile stays pure.\n */\n encode(value: unknown, field: FieldSchema): unknown;\n\n /**\n * SQL appended to this field's placeholder, or `\"\"` for none.\n *\n * The one string a dialect contributes to the statement that is not a\n * parameter, so it must be a constant — never derived from a value, and never\n * from anything an application supplies. `fieldParam` is the only caller, and\n * a non-empty cast also means it serialises the value; the two travel\n * together and neither is correct alone (#209).\n */\n castParameter(field: FieldSchema): string;\n\n /**\n * The same, for a value with **no declared column type** — a parameter\n * interpolated into a composed raw fragment, where there is no schema to ask.\n *\n * It exists because \"raw\" cannot mean \"unportable\". Bun's SQLite driver\n * rejects a `Date` outright (`Binding expected string, TypedArray, boolean,\n * number, bigint or null`) while Postgres takes one, so\n * ``sql`where \"createdAt\" > ${date}` `` would work on one dialect and throw on\n * the other — and the caller has no dialect-independent value to reach for\n * instead, because milliseconds are only correct if that is what the ORM\n * stored. Which it is: this converts to exactly what `encode` writes for a\n * `DateTime`, so a raw statement compares against ORM-written rows correctly.\n *\n * Deliberately narrow. It normalises the JavaScript types whose SQL form the\n * ORM has already decided — a `Date`, a boolean — and touches nothing else. A\n * plain object is *not* JSON-encoded here: the compiler only knows to do that\n * because a field says `Json`, and guessing from the value would turn a\n * mistyped parameter into a successfully-written string.\n *\n * The exception is a parameter the *caller* cast to `json`/`jsonb`, which is\n * a declared type by another route and does not reach this at all — see\n * `json-param.ts`. It is still not a guess from the value: the statement says\n * so.\n */\n encodeUntyped(value: unknown): unknown;\n\n /** Driver value -> the value Prisma would have returned for this field. */\n decode(value: unknown, field: FieldSchema): unknown;\n\n /**\n * False when the driver already returns exactly what Prisma would for this\n * field, letting the shaper skip the call entirely on the hot path.\n */\n needsDecode(field: FieldSchema): boolean;\n\n /**\n * `<lhs> in (...)` / `<lhs> not in (...)`.\n *\n * `length` is the element count, which is shape information and is already\n * part of the plan key. `values` returns the whole array at bind time; how it\n * is spread across parameters is the dialect's business.\n */\n inList(\n lhs: string,\n negated: boolean,\n length: number,\n values: Binder,\n ): Fragment;\n\n /** `<lhs> like <pattern>`, case-insensitively when the dialect can. */\n like(lhs: string, insensitive: boolean, pattern: Binder): Fragment;\n\n /**\n * Whether this dialect can match a **tuple** of columns against a list of\n * tuples in a statement whose text does not grow with the list.\n *\n * The single-column case is `inList`, and on Postgres `= any($1)` already\n * gives one SQL text for every length — which is what lets `collapsedList`\n * keep a batched relation query to one plan entry however many parents it\n * has. A relation joining on *more than one* field cannot use it, so the\n * loader falls back to an `OR` of `AND`s whose text does grow, and the plan\n * cache churns with the parent count (#97).\n *\n * `unnest` closes that on Postgres — one array parameter per *column*, so the\n * text is fixed — but it needs each column's SQL type for the cast, and the\n * types are asked about here rather than assumed: a dialect that cannot spell\n * one of them says so and the caller keeps the portable `OR`.\n */\n canBindCompositeIn(types: readonly ScalarType[]): boolean;\n\n /**\n * `(a, b) in (select * from unnest($1::t[], $2::u[]))`.\n *\n * `values` yields one tuple per parent at bind time; the dialect decides how\n * they are transposed into per-column arrays. Only called when\n * {@link canBindCompositeIn} returned true for these types.\n */\n compositeIn(\n columns: readonly string[],\n types: readonly ScalarType[],\n values: Binder,\n ): Fragment;\n\n /**\n * The filters this dialect can apply to a **scalar list** — `tags String[]`.\n *\n * **Empty is the whole of SQLite's answer**, and it is a capability rather\n * than a gap in this ORM: SQLite has no array type, and Prisma refuses the\n * declaration there at validation time — *\"Field `tags` in model `User` can't\n * be a list. The current connector does not support lists of primitive\n * types.\"* So a SQLite database cannot hold such a column to begin with.\n *\n * The refusal lives here rather than in the generator, which is where it used\n * to live (#300). The generated artifact is dialect-agnostic on purpose —\n * `DATABASE_URL` can name a different database than `prisma generate` saw —\n * so a generator that refused a scalar list refused it for Postgres too, and\n * one `String[]` anywhere meant no artifact for *any* model. Asking the\n * dialect at compile time refuses exactly the combination that cannot work,\n * and names it, which is the shape {@link UnsupportedDialectError} already\n * has for the dialects with no compiler at all.\n */\n readonly listFilters: ReadonlySet<string>;\n\n /**\n * `<value> = any(<column>)` — is this element in the list?\n *\n * The mirror of {@link inList} rather than a variant of it, and the two are\n * easy to confuse: there, one column is matched against a caller's list;\n * here, one caller value is matched against a column that *is* a list.\n *\n * **These four take a `Fragment` where every other member here takes a\n * `Binder`**, which is a deliberate exception. A list operand may need a cast\n * on its placeholder — a single element of a `Json[]` needs #209's\n * `::text::jsonb`, and the serialisation that must travel with it — so the\n * parameter is built by `fieldParam` before it arrives and the dialect\n * chooses only the operator. Handing over a `Binder` instead would oblige\n * each dialect to restate `fieldParam`'s rule, and restating it slightly\n * wrong is silent: `$1::jsonb = any(col)` answers *false* where\n * `$1::text::jsonb = any(col)` answers true, with no error on either.\n */\n listHas(column: string, value: Fragment): Fragment;\n\n /** `hasEvery` — every element of the operand is present in the column. */\n listHasEvery(column: string, values: Fragment): Fragment;\n\n /** `hasSome` — the column and the operand share at least one element. */\n listHasSome(column: string, values: Fragment): Fragment;\n\n /**\n * `isEmpty: true`, or its negation when `empty` is false.\n *\n * The odd one out with no operand at all: the value being compared against is\n * the empty list, which is the compiler's own constant rather than the\n * caller's. It stays a bound parameter regardless — see `jsonNullComparison`,\n * which declines the same exception for the same reason.\n */\n listIsEmpty(column: string, empty: boolean): Fragment;\n\n /**\n * The right-hand side of a `push`: the column's current value with the\n * operand appended. An expression rather than a statement, because it is\n * assigned by the write compiler like any other `set` value.\n */\n listPush(column: string, values: Fragment): Fragment;\n\n /**\n * How this dialect spells a JSON path, and which filters it can apply to one.\n *\n * The **path grammar itself differs**, which is unusual enough to be worth\n * stating rather than hiding: Prisma takes `path: [\"a\", \"b\"]` on Postgres and\n * `path: \"$.a.b\"` on SQLite, and refuses the other form on each. That is not\n * a gemi choice — it is the shape the generated client accepts, measured on\n * both — so reproducing it is what \"Prisma-compatible\" means here.\n *\n * `jsonFilters` is the set of scalar filters the dialect can apply to an\n * extracted value. Prisma refuses `array_contains` and the numeric\n * comparisons on SQLite with *\"Unknown argument\"*, so refusing them here is\n * matching it rather than falling short of it.\n */\n readonly jsonPathSyntax: \"array\" | \"jsonpath\";\n readonly jsonFilters: ReadonlySet<string>;\n\n /**\n * Whether an extracted value compares as **text**.\n *\n * Postgres's `#>>` yields `text`, so `equals: 3` has to bind `\"3\"` — comparing\n * text to an integer parameter is a type error there. SQLite's `json_extract`\n * yields a native value, so the same filter has to bind `3`: bind `\"3\"` and\n * SQLite compares an INTEGER to a TEXT, which is silently *false* rather than\n * an error. One filter, two encodings, and the wrong one is a returned-no-rows\n * bug on one dialect and a raised error on the other.\n */\n readonly jsonComparesAsText: boolean;\n\n /**\n * The extracted value, as a fragment whose path is **bound**.\n *\n * A JSON path is the one place a caller's *value* decides part of an\n * expression's meaning, which makes it the obvious place to interpolate by\n * accident and break invariant 2. Both dialects can take it as a parameter —\n * Postgres's `#>` accepts a `text[]`, SQLite's `json_extract` a string — so\n * nothing has to be bent to keep it out of the SQL text.\n *\n * `asText` picks the extraction that yields SQL text rather than JSON. Every\n * comparison in `jsonComparison` passes `true` — the string filters compare\n * against text, and `equals` / `not` / the numeric operators compare an\n * extracted *scalar*, which is what the text form gives them. The JSON form\n * has exactly one caller, `jsonArrayContains`, because containment is the one\n * operator whose right-hand side is a document.\n *\n * SQLite ignores the flag: `json_extract` already yields a SQL value rather\n * than a JSON document for a scalar at the path. That is why the null\n * sentinels need {@link jsonValueAt} instead of this — see there.\n */\n jsonExtract(column: string, path: Binder, asText: boolean): Fragment;\n\n /** `<extracted> @> <value>` — Postgres only; see `jsonFilters`. */\n jsonArrayContains(column: string, path: Binder, value: Binder): Fragment;\n\n /**\n * The value at `path` **as JSON**, in the form two JSON values compare in.\n *\n * The difference from {@link jsonExtract} is the whole of #407, and it is the\n * distinction the null sentinels are made of. Both dialects have an\n * extraction that collapses \"the key is absent\" into \"the key holds the JSON\n * value `null`\", and both have one that does not:\n *\n * | | collapses | keeps the distinction |\n * | --- | --- | --- |\n * | postgres | `#>>` (text) | `#>` (jsonb) |\n * | sqlite | `json_extract` | `->` (JSON text) |\n *\n * `jsonExtract` is the left column at `asText: true`, which is what every\n * scalar comparison wants — a value to compare, not a document. This is the\n * right column, and it is what lets `equals: DbNull` compile to\n * `<value at path> is null` while `equals: JsonNull` compiles to\n * `<value at path> = <the JSON null>`. Refusing them because `#>>` cannot\n * tell the two apart was true of `#>>` and not of the dialect.\n *\n * **Postgres casts and SQLite does not**, and the cast is not decoration:\n * `#>` on a `json` column (a `@db.Json` field) yields `json`, which has no\n * equality operator at all — *\"operator does not exist: json = jsonb\"*, a\n * raised error rather than a wrong answer, but still one Prisma does not\n * raise. Prisma emits `(…#>…)::jsonb` for exactly this reason and so does\n * this. SQLite's `->` already yields the JSON text form.\n *\n * Bound, never interpolated, for the same reason `jsonExtract` is.\n */\n jsonValueAt(column: string, path: Binder): Fragment;\n\n /**\n * `limit`/`offset`. Both are values and therefore parameters — this is the\n * single most tempting place in the compiler to inline a number.\n */\n paginate(take: Binder | null, skip: Binder | null): Fragment;\n\n /**\n * The clause that makes an insert skip rows violating a unique constraint —\n * `createMany({ skipDuplicates: true })` — or `null` where it is not offered.\n *\n * **`null` is a parity decision, not a missing feature**, and that is worth\n * knowing before someone \"fixes\" SQLite by returning `insert or ignore`.\n * SQLite has `on conflict do nothing` and has since 3.24; Prisma nonetheless\n * rejects the *argument* on SQLite — `Unknown argument 'skipDuplicates'`,\n * whatever its value, verified against a generated 6.19 client. Offering it\n * here would make gemi a silent superset of Prisma on the one dialect the\n * differential harness could then no longer compare, which is the trade this\n * project has declined every other time it came up.\n *\n * A method rather than a boolean because the SQL differs where it exists, and\n * a `Fragment` because everything the compiler emits is one.\n */\n ignoreConflicts(): Fragment | null;\n\n /**\n * Recognise a driver error as a constraint violation, and say which columns\n * it names.\n *\n * Returns `null` for anything else, including the *other* constraint kinds:\n * SQLite reports NOT NULL and FOREIGN KEY failures through the same exception\n * type, and reporting one of those as a duplicate-key error would send a\n * caller looking for a row that does not exist.\n *\n * Columns, not fields — the driver only knows the database's names. The\n * caller maps them back through the schema, where `@map` is in scope.\n */\n constraintViolation(error: unknown): ConstraintViolation | null;\n}\n\n/** A driver error identified as a constraint failure, in dialect-neutral terms. */\nexport interface ConstraintViolation {\n /** Only `unique` is translated today; the rest surface as the raw error. */\n kind: \"unique\";\n /** Database column names, in the order the driver reported them. */\n columns: string[];\n /** The constraint's own name, when the driver gives one. Postgres does. */\n constraint?: string;\n}\n\n/**\n * The ORM was asked to compile against a dialect it does not implement.\n *\n * **The split this message has to convey**, because it is the surprising part:\n * `DatabaseManager` connects to MySQL and MariaDB perfectly well — Bun's client\n * speaks all four — so raw SQL through `DB.query` / `DB.sql` works, and\n * transactions work. What does not exist is a `SqlDialect` for them, so\n * everything that *compiles* a statement stops here.\n *\n * A caller who reads only \"not supported\" reasonably concludes the connection\n * is unusable, which is wrong and is the more expensive misreading: it is the\n * ORM that is unavailable, not the database.\n */\nexport class UnsupportedDialectError extends Error {\n constructor(dialect: Dialect) {\n super(\n `The gemi ORM does not support the '${dialect}' dialect. Only sqlite ` +\n `and postgres are implemented — see the supported matrix in ` +\n `docs/orm.md.\\n\\n` +\n `The *connection* is fine: Bun's client speaks ${dialect}, so raw SQL ` +\n `through DB.query / DB.sql and transactions all work. It is the query ` +\n `compiler that has no ${dialect} dialect, so every model operation ` +\n `raises this.\\n\\n` +\n `Point DATABASE_URL at Postgres or SQLite to use the ORM, or keep ` +\n `using Prisma's own client for this database.`,\n );\n this.name = \"UnsupportedDialectError\";\n }\n}\n\n/**\n * Whether the ORM can compile for this dialect at all.\n *\n * Exported so an application can find out at **boot** rather than on its first\n * query. That is the whole gap this closes: `DatabaseManager` constructs\n * happily against MySQL, so a deploy pointed at one starts, passes a health\n * check, serves traffic, and fails on the first model read — which is the\n * latest and most expensive moment to learn it.\n */\nexport function ormSupports(dialect: Dialect): boolean {\n return COMPILERS[dialect] !== null;\n}\n\n/** Every dialect `Dialect` names, for anything that has to walk them all. */\nexport function everyDialect(): Dialect[] {\n return Object.keys(COMPILERS) as Dialect[];\n}\n\n/**\n * The compiler for each dialect, or `null` where the ORM has none.\n *\n * **One map rather than two lists, and `satisfies` rather than a lookup.** The\n * supported set used to be written three times — `ormSupports`' `||` chain,\n * `dialectFor`'s `if` chain, and a test enumerating a hand-written copy of the\n * `Dialect` union — so adding a fifth member to that union changed nothing\n * anywhere: `tsc` clean, tests green, the new dialect silently reported as\n * unsupported by one function and unknown to the other.\n *\n * That moment is exactly what the guard exists for. Adding a dialect to the\n * union is the *first step of implementing one*, and it is the step where a\n * half-added dialect would disagree with itself.\n *\n * `satisfies Record<Dialect, …>` makes it a compile error in a file the build\n * actually checks. It has to live here rather than in a test: `tsconfig.json`\n * excludes test files and vitest transpiles without type-checking, so an\n * exhaustiveness check written there is a type error nothing ever evaluates.\n *\n * The sixth thing in this codebase made `tsc`'s job rather than a convention's\n * — see the note on `resolveLink`'s `operation`.\n */\nconst COMPILERS = {\n sqlite: new SqliteDialect(),\n postgres: new PostgresDialect(),\n // Bun's client speaks both; the ORM has no compiler for either. See\n // `UnsupportedDialectError`, which is careful to say that the *connection*\n // still works.\n mysql: null,\n mariadb: null,\n} satisfies Record<Dialect, SqlDialect | null>;\n\n/**\n * Resolved per call from `DatabaseManager.dialect`, never baked into a\n * generated artifact — `DATABASE_URL` can point at a different database than\n * the one `prisma generate` saw.\n */\nexport function dialectFor(dialect: Dialect): SqlDialect {\n const compiler = COMPILERS[dialect];\n if (compiler === null) throw new UnsupportedDialectError(dialect);\n return compiler;\n}\n\nexport { PostgresDialect, SqliteDialect };\n"
14
14
  ],
15
- "mappings": "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",
16
- "debugId": "7CBA34C990D1070664756E2164756E21",
15
+ "mappings": "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",
16
+ "debugId": "AFBAD7EA85FC45F664756E2164756E21",
17
17
  "names": []
18
18
  }