turbine-orm 0.81.0 → 0.90.0

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 (295) hide show
  1. package/README.md +26 -25
  2. package/dist/checkout.d.ts +27 -2
  3. package/dist/checkout.js +75 -4
  4. package/dist/cjs/checkout.d.ts +27 -2
  5. package/dist/cjs/checkout.js +76 -3
  6. package/dist/cjs/cli/code-first-tags.d.ts +62 -0
  7. package/dist/cjs/cli/code-first-tags.js +124 -0
  8. package/dist/cjs/cli/compile-query.js +9 -0
  9. package/dist/cjs/cli/config.d.ts +35 -6
  10. package/dist/cjs/cli/config.js +17 -1
  11. package/dist/cjs/cli/destructive.d.ts +7 -4
  12. package/dist/cjs/cli/destructive.js +224 -20
  13. package/dist/cjs/cli/error-catalog.js +36 -0
  14. package/dist/cjs/cli/error-text.d.ts +15 -0
  15. package/dist/cjs/cli/error-text.js +40 -0
  16. package/dist/cjs/cli/index.d.ts +62 -4
  17. package/dist/cjs/cli/index.js +568 -108
  18. package/dist/cjs/cli/local-server-guard.d.ts +53 -0
  19. package/dist/cjs/cli/local-server-guard.js +119 -0
  20. package/dist/cjs/cli/local-server-output.d.ts +41 -0
  21. package/dist/cjs/cli/local-server-output.js +103 -0
  22. package/dist/cjs/cli/mcp.d.ts +8 -0
  23. package/dist/cjs/cli/mcp.js +121 -32
  24. package/dist/cjs/cli/migrate.d.ts +113 -5
  25. package/dist/cjs/cli/migrate.js +270 -21
  26. package/dist/cjs/cli/observe.d.ts +6 -1
  27. package/dist/cjs/cli/observe.js +85 -55
  28. package/dist/cjs/cli/pii-predicate-guard.d.ts +43 -23
  29. package/dist/cjs/cli/pii-predicate-guard.js +98 -37
  30. package/dist/cjs/cli/prisma-resolve.js +17 -13
  31. package/dist/cjs/cli/prisma-schema.js +12 -4
  32. package/dist/cjs/cli/studio-ui.generated.js +1 -1
  33. package/dist/cjs/cli/studio.d.ts +14 -2
  34. package/dist/cjs/cli/studio.js +244 -69
  35. package/dist/cjs/cli/ui.d.ts +1 -1
  36. package/dist/cjs/client.d.ts +558 -85
  37. package/dist/cjs/client.js +1270 -395
  38. package/dist/cjs/connection-guard.d.ts +13 -0
  39. package/dist/cjs/connection-guard.js +28 -0
  40. package/dist/cjs/connection-url.d.ts +51 -16
  41. package/dist/cjs/connection-url.js +67 -34
  42. package/dist/cjs/diagnostics.d.ts +81 -0
  43. package/dist/cjs/diagnostics.js +147 -0
  44. package/dist/cjs/dialect.d.ts +449 -20
  45. package/dist/cjs/dialect.js +117 -76
  46. package/dist/cjs/engine-config.d.ts +7 -6
  47. package/dist/cjs/errors.d.ts +126 -6
  48. package/dist/cjs/errors.js +256 -13
  49. package/dist/cjs/generate.d.ts +57 -7
  50. package/dist/cjs/generate.js +635 -279
  51. package/dist/cjs/global-filters-config.d.ts +59 -0
  52. package/dist/cjs/global-filters-config.js +367 -0
  53. package/dist/cjs/index.d.ts +9 -4
  54. package/dist/cjs/index.js +10 -2
  55. package/dist/cjs/introspect.d.ts +31 -6
  56. package/dist/cjs/introspect.js +108 -50
  57. package/dist/cjs/log-codes.d.ts +12 -0
  58. package/dist/cjs/log-codes.js +77 -0
  59. package/dist/cjs/logger.d.ts +87 -0
  60. package/dist/cjs/logger.js +98 -0
  61. package/dist/cjs/mssql.d.ts +8 -5
  62. package/dist/cjs/mssql.js +352 -65
  63. package/dist/cjs/mysql.d.ts +3 -5
  64. package/dist/cjs/mysql.js +420 -70
  65. package/dist/cjs/nested-write.d.ts +3 -0
  66. package/dist/cjs/nested-write.js +179 -114
  67. package/dist/cjs/pipeline-submittable.d.ts +12 -0
  68. package/dist/cjs/pipeline-submittable.js +118 -44
  69. package/dist/cjs/pipeline.js +21 -26
  70. package/dist/cjs/powdb-introspect.d.ts +5 -2
  71. package/dist/cjs/powdb-introspect.js +20 -15
  72. package/dist/cjs/powdb-shared.d.ts +36 -5
  73. package/dist/cjs/powdb-shared.js +67 -8
  74. package/dist/cjs/powdb.d.ts +4 -0
  75. package/dist/cjs/powdb.js +183 -51
  76. package/dist/cjs/powql.d.ts +394 -51
  77. package/dist/cjs/powql.js +1829 -284
  78. package/dist/cjs/prisma-compat.d.ts +23 -15
  79. package/dist/cjs/prisma-compat.js +507 -372
  80. package/dist/cjs/query/aggregates.d.ts +17 -1
  81. package/dist/cjs/query/aggregates.js +261 -29
  82. package/dist/cjs/query/batched-loader.d.ts +25 -6
  83. package/dist/cjs/query/batched-loader.js +103 -20
  84. package/dist/cjs/query/builder.d.ts +325 -184
  85. package/dist/cjs/query/builder.js +1452 -490
  86. package/dist/cjs/query/column-ref.d.ts +61 -0
  87. package/dist/cjs/query/column-ref.js +73 -0
  88. package/dist/cjs/query/compound-unique.d.ts +21 -0
  89. package/dist/cjs/query/compound-unique.js +98 -18
  90. package/dist/cjs/query/deferred.d.ts +53 -16
  91. package/dist/cjs/query/expr.d.ts +217 -0
  92. package/dist/cjs/query/expr.js +859 -0
  93. package/dist/cjs/query/filters.d.ts +155 -53
  94. package/dist/cjs/query/filters.js +613 -76
  95. package/dist/cjs/query/index.d.ts +2 -0
  96. package/dist/cjs/query/index.js +7 -1
  97. package/dist/cjs/query/json-value.d.ts +43 -0
  98. package/dist/cjs/query/json-value.js +59 -0
  99. package/dist/cjs/query/normalize-args.d.ts +87 -0
  100. package/dist/cjs/query/normalize-args.js +527 -0
  101. package/dist/cjs/query/option-surface.d.ts +16 -4
  102. package/dist/cjs/query/option-surface.js +57 -14
  103. package/dist/cjs/query/relation-names.d.ts +14 -0
  104. package/dist/cjs/query/relation-names.js +77 -18
  105. package/dist/cjs/query/relations.d.ts +30 -3
  106. package/dist/cjs/query/relations.js +219 -63
  107. package/dist/cjs/query/row-lock.d.ts +49 -0
  108. package/dist/cjs/query/row-lock.js +138 -0
  109. package/dist/cjs/query/sql-comment.d.ts +161 -0
  110. package/dist/cjs/query/sql-comment.js +381 -0
  111. package/dist/cjs/query/stream-idle.d.ts +132 -0
  112. package/dist/cjs/query/stream-idle.js +212 -0
  113. package/dist/cjs/query/table-client.d.ts +101 -0
  114. package/dist/cjs/query/table-client.js +74 -0
  115. package/dist/cjs/query/types.d.ts +677 -298
  116. package/dist/cjs/query/utils.d.ts +105 -6
  117. package/dist/cjs/query/utils.js +426 -19
  118. package/dist/cjs/query/warn-registry.d.ts +18 -0
  119. package/dist/cjs/query/warn-registry.js +18 -0
  120. package/dist/cjs/query/where-compile.d.ts +138 -14
  121. package/dist/cjs/query/where-compile.js +513 -29
  122. package/dist/cjs/query/where.d.ts +159 -59
  123. package/dist/cjs/query/where.js +716 -246
  124. package/dist/cjs/query/writes.d.ts +112 -50
  125. package/dist/cjs/query/writes.js +1498 -200
  126. package/dist/cjs/query-events.d.ts +4 -2
  127. package/dist/cjs/query-events.js +3 -1
  128. package/dist/cjs/realtime.d.ts +7 -3
  129. package/dist/cjs/realtime.js +13 -2
  130. package/dist/cjs/schema-builder.d.ts +55 -4
  131. package/dist/cjs/schema-builder.js +382 -18
  132. package/dist/cjs/schema-metadata.d.ts +21 -1
  133. package/dist/cjs/schema-metadata.js +29 -7
  134. package/dist/cjs/schema-sql.d.ts +75 -5
  135. package/dist/cjs/schema-sql.js +497 -45
  136. package/dist/cjs/schema.d.ts +26 -5
  137. package/dist/cjs/schema.js +110 -13
  138. package/dist/cjs/sql-placeholders.d.ts +56 -0
  139. package/dist/cjs/sql-placeholders.js +204 -0
  140. package/dist/cjs/sqlite.d.ts +75 -20
  141. package/dist/cjs/sqlite.js +593 -95
  142. package/dist/cjs/supplied-pool-types.d.ts +48 -0
  143. package/dist/cjs/supplied-pool-types.js +256 -0
  144. package/dist/cjs/transaction-control.d.ts +51 -0
  145. package/dist/cjs/transaction-control.js +316 -0
  146. package/dist/cjs/transaction-state.d.ts +342 -0
  147. package/dist/cjs/transaction-state.js +707 -0
  148. package/dist/cjs/typed-sql.d.ts +37 -3
  149. package/dist/cjs/typed-sql.js +102 -8
  150. package/dist/cli/code-first-tags.d.ts +62 -0
  151. package/dist/cli/code-first-tags.js +120 -0
  152. package/dist/cli/compile-query.js +9 -0
  153. package/dist/cli/config.d.ts +35 -6
  154. package/dist/cli/config.js +16 -1
  155. package/dist/cli/destructive.d.ts +7 -4
  156. package/dist/cli/destructive.js +224 -20
  157. package/dist/cli/error-catalog.js +36 -0
  158. package/dist/cli/error-text.d.ts +15 -0
  159. package/dist/cli/error-text.js +37 -0
  160. package/dist/cli/index.d.ts +62 -4
  161. package/dist/cli/index.js +569 -112
  162. package/dist/cli/local-server-guard.d.ts +53 -0
  163. package/dist/cli/local-server-guard.js +113 -0
  164. package/dist/cli/local-server-output.d.ts +41 -0
  165. package/dist/cli/local-server-output.js +98 -0
  166. package/dist/cli/mcp.d.ts +8 -0
  167. package/dist/cli/mcp.js +121 -34
  168. package/dist/cli/migrate.d.ts +113 -5
  169. package/dist/cli/migrate.js +261 -21
  170. package/dist/cli/observe.d.ts +6 -1
  171. package/dist/cli/observe.js +84 -54
  172. package/dist/cli/pii-predicate-guard.d.ts +43 -23
  173. package/dist/cli/pii-predicate-guard.js +100 -35
  174. package/dist/cli/prisma-resolve.js +15 -11
  175. package/dist/cli/prisma-schema.js +12 -4
  176. package/dist/cli/studio-ui.generated.js +1 -1
  177. package/dist/cli/studio.d.ts +14 -2
  178. package/dist/cli/studio.js +246 -71
  179. package/dist/cli/ui.d.ts +1 -1
  180. package/dist/client.d.ts +558 -85
  181. package/dist/client.js +1275 -400
  182. package/dist/connection-guard.d.ts +13 -0
  183. package/dist/connection-guard.js +27 -0
  184. package/dist/connection-url.d.ts +51 -16
  185. package/dist/connection-url.js +63 -34
  186. package/dist/diagnostics.d.ts +81 -0
  187. package/dist/diagnostics.js +144 -0
  188. package/dist/dialect.d.ts +449 -20
  189. package/dist/dialect.js +115 -43
  190. package/dist/engine-config.d.ts +7 -6
  191. package/dist/errors.d.ts +126 -6
  192. package/dist/errors.js +252 -12
  193. package/dist/generate.d.ts +57 -7
  194. package/dist/generate.js +635 -281
  195. package/dist/global-filters-config.d.ts +59 -0
  196. package/dist/global-filters-config.js +361 -0
  197. package/dist/index.d.ts +9 -4
  198. package/dist/index.js +4 -2
  199. package/dist/introspect.d.ts +31 -6
  200. package/dist/introspect.js +106 -50
  201. package/dist/log-codes.d.ts +12 -0
  202. package/dist/log-codes.js +74 -0
  203. package/dist/logger.d.ts +87 -0
  204. package/dist/logger.js +93 -0
  205. package/dist/mssql.d.ts +8 -5
  206. package/dist/mssql.js +354 -67
  207. package/dist/mysql.d.ts +3 -5
  208. package/dist/mysql.js +423 -73
  209. package/dist/nested-write.d.ts +3 -0
  210. package/dist/nested-write.js +177 -112
  211. package/dist/pipeline-submittable.d.ts +12 -0
  212. package/dist/pipeline-submittable.js +117 -44
  213. package/dist/pipeline.js +21 -26
  214. package/dist/powdb-introspect.d.ts +5 -2
  215. package/dist/powdb-introspect.js +21 -16
  216. package/dist/powdb-shared.d.ts +36 -5
  217. package/dist/powdb-shared.js +65 -8
  218. package/dist/powdb.d.ts +4 -0
  219. package/dist/powdb.js +183 -51
  220. package/dist/powql.d.ts +394 -51
  221. package/dist/powql.js +1836 -291
  222. package/dist/prisma-compat.d.ts +23 -15
  223. package/dist/prisma-compat.js +508 -373
  224. package/dist/query/aggregates.d.ts +17 -1
  225. package/dist/query/aggregates.js +263 -32
  226. package/dist/query/batched-loader.d.ts +25 -6
  227. package/dist/query/batched-loader.js +101 -21
  228. package/dist/query/builder.d.ts +325 -184
  229. package/dist/query/builder.js +1458 -495
  230. package/dist/query/column-ref.d.ts +61 -0
  231. package/dist/query/column-ref.js +66 -0
  232. package/dist/query/compound-unique.d.ts +21 -0
  233. package/dist/query/compound-unique.js +97 -19
  234. package/dist/query/deferred.d.ts +53 -16
  235. package/dist/query/expr.d.ts +217 -0
  236. package/dist/query/expr.js +848 -0
  237. package/dist/query/filters.d.ts +155 -53
  238. package/dist/query/filters.js +597 -72
  239. package/dist/query/index.d.ts +2 -0
  240. package/dist/query/index.js +4 -0
  241. package/dist/query/json-value.d.ts +43 -0
  242. package/dist/query/json-value.js +54 -0
  243. package/dist/query/normalize-args.d.ts +87 -0
  244. package/dist/query/normalize-args.js +517 -0
  245. package/dist/query/option-surface.d.ts +16 -4
  246. package/dist/query/option-surface.js +56 -13
  247. package/dist/query/relation-names.d.ts +14 -0
  248. package/dist/query/relation-names.js +77 -19
  249. package/dist/query/relations.d.ts +30 -3
  250. package/dist/query/relations.js +220 -67
  251. package/dist/query/row-lock.d.ts +49 -0
  252. package/dist/query/row-lock.js +131 -0
  253. package/dist/query/sql-comment.d.ts +161 -0
  254. package/dist/query/sql-comment.js +374 -0
  255. package/dist/query/stream-idle.d.ts +132 -0
  256. package/dist/query/stream-idle.js +203 -0
  257. package/dist/query/table-client.d.ts +101 -0
  258. package/dist/query/table-client.js +70 -0
  259. package/dist/query/types.d.ts +677 -298
  260. package/dist/query/utils.d.ts +105 -6
  261. package/dist/query/utils.js +414 -18
  262. package/dist/query/warn-registry.d.ts +18 -0
  263. package/dist/query/warn-registry.js +18 -0
  264. package/dist/query/where-compile.d.ts +138 -14
  265. package/dist/query/where-compile.js +508 -31
  266. package/dist/query/where.d.ts +159 -59
  267. package/dist/query/where.js +711 -248
  268. package/dist/query/writes.d.ts +112 -50
  269. package/dist/query/writes.js +1496 -202
  270. package/dist/query-events.d.ts +4 -2
  271. package/dist/query-events.js +3 -1
  272. package/dist/realtime.d.ts +7 -3
  273. package/dist/realtime.js +13 -2
  274. package/dist/schema-builder.d.ts +55 -4
  275. package/dist/schema-builder.js +381 -18
  276. package/dist/schema-metadata.d.ts +21 -1
  277. package/dist/schema-metadata.js +28 -7
  278. package/dist/schema-sql.d.ts +75 -5
  279. package/dist/schema-sql.js +494 -44
  280. package/dist/schema.d.ts +26 -5
  281. package/dist/schema.js +109 -13
  282. package/dist/sql-placeholders.d.ts +56 -0
  283. package/dist/sql-placeholders.js +200 -0
  284. package/dist/sqlite.d.ts +75 -20
  285. package/dist/sqlite.js +597 -99
  286. package/dist/supplied-pool-types.d.ts +48 -0
  287. package/dist/supplied-pool-types.js +247 -0
  288. package/dist/transaction-control.d.ts +51 -0
  289. package/dist/transaction-control.js +311 -0
  290. package/dist/transaction-state.d.ts +342 -0
  291. package/dist/transaction-state.js +696 -0
  292. package/dist/typed-sql.d.ts +37 -3
  293. package/dist/typed-sql.js +100 -8
  294. package/package.json +7 -4
  295. package/skills/turbine-orm/SKILL.md +56 -6
@@ -32,8 +32,10 @@ exports.parsePowdbSemver = parsePowdbSemver;
32
32
  exports.atLeastVersion = atLeastVersion;
33
33
  exports.requireCapability = requireCapability;
34
34
  exports.baseTsType = baseTsType;
35
+ exports.powdbEnumLabels = powdbEnumLabels;
35
36
  exports.isJsonColumn = isJsonColumn;
36
37
  exports.powqlColumnType = powqlColumnType;
38
+ exports.isPowdbDecimalTextColumn = isPowdbDecimalTextColumn;
37
39
  exports.isDateColumn = isDateColumn;
38
40
  exports.isPowdbDatetimeColumn = isPowdbDatetimeColumn;
39
41
  exports.quotePowqlIdent = quotePowqlIdent;
@@ -239,16 +241,42 @@ function isTsSpace(code) {
239
241
  code === 0xfeff);
240
242
  }
241
243
  /**
242
- * Does this column map to PowDB's native `json` document type? A Postgres
244
+ * The labels of the enum type this column is declared as, or `undefined` when
245
+ * it is not an enum column of `enums`.
246
+ *
247
+ * An enum column carries its TYPE NAME as `dialectType` / `pgType` and a
248
+ * `tsType` that says nothing useful (`unknown` from `defineSchema`, a union of
249
+ * the labels from introspection), so the column's own metadata cannot answer
250
+ * the question: the schema's `enums` map is the only authority. PowDB has no
251
+ * enum type, so such a column is a `str` holding the label text, which is what
252
+ * PostgreSQL stores and returns. Without this the tsType heuristic in
253
+ * {@link isJsonColumn} declared a `defineSchema` enum column as `json`, and
254
+ * writing a label failed as invalid JSON.
255
+ */
256
+ function powdbEnumLabels(col, enums) {
257
+ if (!enums || col.isArray)
258
+ return undefined;
259
+ const type = col.dialectType ?? col.pgType;
260
+ return type !== undefined && Object.hasOwn(enums, type) ? enums[type] : undefined;
261
+ }
262
+ /**
263
+ * Does this column map to PowDB's native `json` document type? An enum column
264
+ * of `enums` never does (see {@link powdbEnumLabels}). A Postgres
243
265
  * `json`/`jsonb` type (via `dialectType`/`pgType`) is authoritative; otherwise
244
266
  * the tsType heuristic (`Record<…>`, `object`, `unknown`, an object/array
245
267
  * literal) that the four scalar branches do not claim. Array columns never map
246
268
  * to json, a PowDB array only exists INSIDE a json document, so a Postgres
247
269
  * array column has no PowDB shape and still throws in {@link powqlColumnType}.
270
+ *
271
+ * `enums` is optional for callers outside Turbine; every call inside the
272
+ * engine passes the schema's map (a source scan in fx-powdb-r2.test.ts
273
+ * checks it).
248
274
  */
249
- function isJsonColumn(col) {
275
+ function isJsonColumn(col, enums) {
250
276
  if (col.isArray)
251
277
  return false;
278
+ if (powdbEnumLabels(col, enums))
279
+ return false;
252
280
  const dbType = (col.dialectType ?? col.pgType ?? '').toLowerCase();
253
281
  if (dbType === 'json' || dbType === 'jsonb')
254
282
  return true;
@@ -266,14 +294,17 @@ function isJsonColumn(col) {
266
294
  * - `Date` → `int` (epoch micros) - `boolean` → `bool`
267
295
  * - integral `number`/`bigint` → `int` - fractional `number` → `float`
268
296
  * - JSON / object columns → `json` (native PowDB document type, ≥ 0.12)
297
+ * - an enum column of `enums` → `str` (the label text)
269
298
  * - everything else (incl. UUID/PK strings) → `str`
270
299
  * Array (non-json) and bytes columns throw, they have no PowDB equivalent.
271
300
  */
272
- function powqlColumnType(col) {
301
+ function powqlColumnType(col, enums) {
273
302
  if (col.isArray) {
274
303
  throw new errors_js_1.ValidationError(`Column "${col.name}" is an array, PowDB has no array type. Arrays are unsupported on the PowDB backend.`);
275
304
  }
276
- if (isJsonColumn(col))
305
+ if (powdbEnumLabels(col, enums))
306
+ return 'str';
307
+ if (isJsonColumn(col, enums))
277
308
  return 'json';
278
309
  const ts = baseTsType(col.tsType);
279
310
  if (ts === 'Date')
@@ -291,6 +322,23 @@ function powqlColumnType(col) {
291
322
  }
292
323
  return 'str';
293
324
  }
325
+ /**
326
+ * Is this a `numeric` / `decimal` / `money` column that PowDB stores as `str`?
327
+ *
328
+ * A Postgres-sourced decimal surfaces as a JS string (so its digits survive),
329
+ * and PowDB has no decimal type, so the column is DDL'd as PowQL `str`. Every
330
+ * comparison, ordering and aggregate the engine runs on it is then a TEXT
331
+ * operation, which is why the query generator refuses those on such a column.
332
+ */
333
+ function isPowdbDecimalTextColumn(col, enums) {
334
+ // An enum type's NAME is free text (`money_kind`), so an enum column is
335
+ // answered before the type-name match below can mistake it for a decimal.
336
+ if (powdbEnumLabels(col, enums))
337
+ return false;
338
+ if (col.isArray || isJsonColumn(col, enums) || baseTsType(col.tsType) !== 'string')
339
+ return false;
340
+ return /numeric|decimal|money/.test((col.dialectType ?? col.pgType ?? '').toLowerCase());
341
+ }
294
342
  /** Heuristic: does this numeric column hold fractional values (→ PowQL `float`)? */
295
343
  function isFloatColumn(col) {
296
344
  const t = (col.dialectType ?? col.pgType ?? '').toLowerCase();
@@ -486,9 +534,12 @@ function quotePowqlDotted(name) {
486
534
  * Every PowDB value arrives as a string; NULL arrives as the bareword `"null"`.
487
535
  * Metadata resolves the `"null"` ambiguity for nullable non-string columns.
488
536
  */
489
- function coerceValue(raw, col) {
537
+ function coerceValue(raw, col, enums) {
538
+ // An enum column holds its label as text, read as a string column is.
539
+ if (powdbEnumLabels(col, enums))
540
+ return raw === 'null' && col.nullable ? null : raw;
490
541
  const ts = baseTsType(col.tsType);
491
- const json = isJsonColumn(col);
542
+ const json = isJsonColumn(col, enums);
492
543
  // NULL bareword: unambiguous for non-string columns; for `str` we cannot tell a
493
544
  // literal "null" from SQL NULL, so a nullable str of value "null" reads as null.
494
545
  // For a `json` column the bareword `null` (a legacy-wire rendering shared by an
@@ -571,7 +622,7 @@ function coerceNativeValue(value, col) {
571
622
  * cells arrive pre-typed and go through {@link coerceNativeValue} (see F3).
572
623
  * Callers on the native transport pass `this.pool.capabilities.nativeRaw`.
573
624
  */
574
- function rowToEntity(raw, meta, native = false) {
625
+ function rowToEntity(raw, meta, native = false, enums) {
575
626
  const byName = new Map(meta.columns.map((c) => [c.name, c]));
576
627
  const out = {};
577
628
  for (const snake of Object.keys(raw)) {
@@ -584,8 +635,16 @@ function rowToEntity(raw, meta, native = false) {
584
635
  else if (native) {
585
636
  out[field] = coerceNativeValue(value, col);
586
637
  }
638
+ else if (typeof value === 'string') {
639
+ out[field] = coerceValue(value, col, enums);
640
+ }
641
+ else if ((typeof value === 'number' || typeof value === 'bigint') && isDateColumn(col)) {
642
+ // A Date column's micros as a number cell: the Date it stores, as on the
643
+ // other wires, never the raw count (which a filter would then refuse).
644
+ out[field] = new Date(Number(value) / 1000);
645
+ }
587
646
  else {
588
- out[field] = typeof value === 'string' ? coerceValue(value, col) : value;
647
+ out[field] = value;
589
648
  }
590
649
  }
591
650
  return out;
@@ -55,6 +55,7 @@
55
55
  import { type PgCompatPool, type PgCompatPoolClient, TurbineClient, type TurbineConfig } from './client.js';
56
56
  import { type Dialect } from './dialect.js';
57
57
  import type { EngineClientConfig } from './engine-config.js';
58
+ import { type TurbineLogger } from './logger.js';
58
59
  import type { PowdbExec } from './powdb-introspect.js';
59
60
  import { type PowdbCapabilities } from './powdb-shared.js';
60
61
  import { type SchemaMetadata } from './schema.js';
@@ -261,6 +262,8 @@ export declare function capabilitiesFromVersion(version: string | undefined | nu
261
262
  */
262
263
  export interface PowqlSchemaDDLOptions {
263
264
  capabilities?: PowdbCapabilities;
265
+ /** Where a skipped-link warning goes. Defaults to the console logger. */
266
+ logger?: TurbineLogger;
264
267
  /**
265
268
  * Emit `link Owner.name -> Target on local = target` declarations (PowDB entity
266
269
  * links, >= 0.19) for every single-column hasMany / hasOne / belongsTo relation
@@ -340,6 +343,7 @@ export declare function powqlSchemaDDL(schema: SchemaMetadata, opts?: PowqlSchem
340
343
  */
341
344
  export declare function applyPowdbLinks(exec: PowdbExec, schema: SchemaMetadata, options?: {
342
345
  capabilities?: PowdbCapabilities;
346
+ logger?: TurbineLogger;
343
347
  }): Promise<string[]>;
344
348
  /**
345
349
  * Translate a PowDB error into a typed Turbine error. Handles BOTH transports,
package/dist/cjs/powdb.js CHANGED
@@ -106,6 +106,7 @@ const node_async_hooks_1 = require("node:async_hooks");
106
106
  const client_js_1 = require("./client.js");
107
107
  const dialect_js_1 = require("./dialect.js");
108
108
  const errors_js_1 = require("./errors.js");
109
+ const logger_js_1 = require("./logger.js");
109
110
  const optional_peer_import_cjs_1 = __importDefault(require("./optional-peer-import.cjs"));
110
111
  const powdb_shared_js_1 = require("./powdb-shared.js");
111
112
  const warn_registry_js_1 = require("./query/warn-registry.js");
@@ -155,6 +156,48 @@ Object.defineProperty(exports, "rowToEntity", { enumerable: true, get: function
155
156
  exports.powdbDialect = {
156
157
  ...dialect_js_1.postgresDialect,
157
158
  name: 'powdb',
159
+ // PowqlInterface compiles PowQL itself and refuses what PowDB lacks; these
160
+ // answer for the client paths a PowDB client shares (transactions, raw
161
+ // queries, `tx.$connection()`) and keep every SQL-only feature off.
162
+ capabilities: Object.freeze({
163
+ distinctOn: false,
164
+ positionalJson: false,
165
+ nullsOrderingClause: false,
166
+ nullsSortHigh: false,
167
+ insensitiveInList: false,
168
+ jsonDocumentEquality: 'text',
169
+ jsonExtractTyped: false,
170
+ jsonExactNumericCast: false,
171
+ numericTextComparison: false,
172
+ // PowDB has no foreign keys: declared relations are not enforced, and its
173
+ // own mass-mutation guard already folds with foreignKeys: false.
174
+ enforcesForeignKeys: false,
175
+ partitionLimitPushdown: false,
176
+ utcTimestampRewrite: false,
177
+ paramTypeCasts: false,
178
+ namedEnumTypes: false,
179
+ structuredValueColumns: 'scalars',
180
+ maxBindParameters: Number.POSITIVE_INFINITY,
181
+ maxInsertRows: Number.POSITIVE_INFINITY,
182
+ upsertConflictTarget: 'explicit',
183
+ setClauseOrder: 'snapshot',
184
+ reselectLocksRows: false,
185
+ integerDivision: '/',
186
+ updateExpressions: false,
187
+ bulkUpsertAppliesRepeatedKeys: false,
188
+ readOnlyTransactions: false,
189
+ connectionParameters: false,
190
+ backendCancel: false,
191
+ idleTransactionTimeout: false,
192
+ abortsTransactionOnError: false,
193
+ connectionDriver: 'none',
194
+ preparesEveryStatement: false,
195
+ statementSyntax: null,
196
+ // No foreign keys to declare, inline or otherwise; PowQL DDL comes from
197
+ // powqlSchemaDDL, which never reads this.
198
+ inlineForeignKeys: false,
199
+ unboundedTextKeys: true,
200
+ }),
158
201
  // `resultStrategy` is decorative for PowDB, PowqlInterface owns its own write
159
202
  // path and never reads it. Set to 'returning' for honesty: writes use PowDB
160
203
  // 0.7.0's trailing `returning` keyword (upsert excepted, see PowqlInterface).
@@ -172,6 +215,11 @@ exports.powdbDialect = {
172
215
  // earlier, this override keeps the flag truthful if a future path consults it.
173
216
  supportsLateralJoin: false,
174
217
  supportsPlanCacheMode: false,
218
+ // PowqlInterface reads none of these (it refuses each feature itself); they
219
+ // are set so the flags stay truthful if a shared path consults them.
220
+ rowLockModes: [],
221
+ supportsPercentileAggregates: false,
222
+ supportsBulkUpsert: false,
175
223
  beginStatement: () => 'begin',
176
224
  commitStatement: () => 'commit',
177
225
  rollbackStatement: () => 'rollback',
@@ -388,7 +436,7 @@ function powqlSchemaDDL(schema, opts = {}) {
388
436
  new Set(idx.columns).size === pkSet.size &&
389
437
  idx.columns.every((c) => pkSet.has(c));
390
438
  const fields = meta.columns.map((col) => {
391
- const powqlType = (0, powdb_shared_js_1.powqlColumnType)(col);
439
+ const powqlType = (0, powdb_shared_js_1.powqlColumnType)(col, schema.enums);
392
440
  // Gate `json` columns behind the engine's jsonDocs capability when a
393
441
  // caller supplied one, an old engine has no `json` type and would reject
394
442
  // the DDL. Pure-function callers (no opts) emit unconditionally.
@@ -473,8 +521,8 @@ function powqlSchemaDDL(schema, opts = {}) {
473
521
  (0, powdb_shared_js_1.requireCapability)(caps, 'entityLinks', 'entity link DDL (`emitLinks`)');
474
522
  const links = deriveDesiredLinks(schema, (owner, name) => {
475
523
  if ((0, warn_registry_js_1.shouldWarnOnce)(warn_registry_js_1.WARN_NS.powdbLinks, `collide:${owner}.${name}`)) {
476
- console.warn(`[turbine] powqlSchemaDDL(emitLinks): relation "${name}" on "${owner}" collides with a column of the ` +
477
- 'same name; skipping its link declaration (PowDB hard-errors on a link that shadows a column).');
524
+ (0, logger_js_1.logTo)(opts.logger ?? logger_js_1.consoleLogger, 'warn', `powqlSchemaDDL(emitLinks): relation "${name}" on "${owner}" collides with a column of the ` +
525
+ 'same name; skipping its link declaration (PowDB hard-errors on a link that shadows a column).', { code: 'powdb-link-collision', table: owner, relation: name, operation: 'powqlSchemaDDL' });
478
526
  }
479
527
  });
480
528
  for (const link of links)
@@ -502,6 +550,7 @@ function powqlSchemaDDL(schema, opts = {}) {
502
550
  */
503
551
  async function applyPowdbLinks(exec, schema, options = {}) {
504
552
  const caps = options.capabilities;
553
+ const logger = options.logger ?? logger_js_1.consoleLogger;
505
554
  if (caps) {
506
555
  (0, powdb_shared_js_1.requireCapability)(caps, 'entityLinks', 'entity link DDL (`applyPowdbLinks`)');
507
556
  (0, powdb_shared_js_1.requireCapability)(caps, 'linkIntrospection', 'PowDB `schema links` introspection');
@@ -510,8 +559,8 @@ async function applyPowdbLinks(exec, schema, options = {}) {
510
559
  const byOwnerName = new Map(existing.map((l) => [`${l.owner}\u0000${l.name}`, l]));
511
560
  const desired = deriveDesiredLinks(schema, (owner, name) => {
512
561
  if ((0, warn_registry_js_1.shouldWarnOnce)(warn_registry_js_1.WARN_NS.powdbLinks, `collide:${owner}.${name}`)) {
513
- console.warn(`[turbine] applyPowdbLinks: relation "${name}" on "${owner}" collides with a column of the same name; ` +
514
- 'skipping its link (PowDB hard-errors on a link that shadows a column).');
562
+ (0, logger_js_1.logTo)(logger, 'warn', `applyPowdbLinks: relation "${name}" on "${owner}" collides with a column of the same name; ` +
563
+ 'skipping its link (PowDB hard-errors on a link that shadows a column).', { code: 'powdb-link-collision', table: owner, relation: name, operation: 'applyPowdbLinks' });
515
564
  }
516
565
  });
517
566
  const executed = [];
@@ -520,9 +569,9 @@ async function applyPowdbLinks(exec, schema, options = {}) {
520
569
  if (found) {
521
570
  const same = found.target === link.target && found.localKey === link.localKey && found.targetKey === link.targetKey;
522
571
  if (!same && (0, warn_registry_js_1.shouldWarnOnce)(warn_registry_js_1.WARN_NS.powdbLinks, `drift:${link.owner}.${link.name}`)) {
523
- console.warn(`[turbine] applyPowdbLinks: link "${link.name}" on "${link.owner}" is already declared with different ` +
572
+ (0, logger_js_1.logTo)(logger, 'warn', `applyPowdbLinks: link "${link.name}" on "${link.owner}" is already declared with different ` +
524
573
  `endpoints (have ${found.target} on ${found.localKey} = ${found.targetKey}, want ${link.target} on ` +
525
- `${link.localKey} = ${link.targetKey}); leaving it untouched (PowDB has no drop-link DDL).`);
574
+ `${link.localKey} = ${link.targetKey}); leaving it untouched (PowDB has no drop-link DDL).`, { code: 'powdb-link-drift', table: link.owner, relation: link.name, operation: 'applyPowdbLinks' });
526
575
  }
527
576
  continue; // identical → idempotent skip; drift → warned skip
528
577
  }
@@ -768,7 +817,9 @@ function wrapPowdbError(err) {
768
817
  // evaluate true for every row. Runs before the generic `type mismatch` regex
769
818
  // below so the column name and the fix survive into the message.
770
819
  {
771
- const m = /type mismatch for column '([^']+)': expected ([^,]+), got (\w+)/i.exec(msg);
820
+ // Every group is bounded: `[^,]+` retried from each "expected " in a long
821
+ // message made this quadratic in the message length.
822
+ const m = /type mismatch for column '([^']{1,256})': expected ([^,]{1,64}), got (\w{1,32})/i.exec(msg);
772
823
  if (m) {
773
824
  return new errors_js_1.ValidationError(`PowDB rejected a comparison on column "${m[1]}": the column is ${m[2]} but the bound value is ` +
774
825
  `${m[3]}. PowQL never coerces across types in a comparison (before engine 0.20 this silently matched ` +
@@ -905,6 +956,19 @@ function reentrantTransactionError() {
905
956
  'on the write lock the open transaction holds. Use the `tx` client the callback receives, or start the ' +
906
957
  'second transaction after the first completes. (Independent concurrent transactions queue automatically.)');
907
958
  }
959
+ /**
960
+ * The error for a plain statement issued through the CLIENT (not the `tx`
961
+ * client) from inside that client's own open transaction callback, on the
962
+ * embedded engine. Its one handle carries one transaction, so the statement
963
+ * could only run inside the transaction (and be rolled back with it) or wait
964
+ * for the transaction to finish, which is itself waiting on this statement.
965
+ */
966
+ function statementInsideTransactionError() {
967
+ return new errors_js_1.UnsupportedFeatureError('A statement on the client while its own transaction is open', 'powdb', 'This call was made through the client, not the `tx` client, from inside an open $transaction callback. The ' +
968
+ 'embedded engine has one handle and one transaction, so the call would either join that transaction (and be ' +
969
+ 'rolled back with it) or wait for it forever. Use the `tx` client the callback receives, or make the call ' +
970
+ 'after the transaction completes.');
971
+ }
908
972
  // ---------------------------------------------------------------------------
909
973
  // Single-writer transaction gate, FIFO queueing + re-entrancy detection
910
974
  // ---------------------------------------------------------------------------
@@ -975,9 +1039,15 @@ class PowdbTxGate {
975
1039
  queueTimeoutMs;
976
1040
  /** Tail of the FIFO queue, resolves once every earlier transaction has finished. */
977
1041
  tail = Promise.resolve();
1042
+ /** Holds taken and not yet finished, queued ones included. */
1043
+ outstanding = 0;
978
1044
  constructor(queueTimeoutMs) {
979
1045
  this.queueTimeoutMs = queueTimeoutMs;
980
1046
  }
1047
+ /** True while any transaction holds the gate or waits for it. */
1048
+ get busy() {
1049
+ return this.outstanding > 0;
1050
+ }
981
1051
  /**
982
1052
  * Take a place in the transaction queue. The prologue walks the caller's
983
1053
  * marker chain (planted around transaction callbacks by the pool's
@@ -986,7 +1056,7 @@ class PowdbTxGate {
986
1056
  * the returned hold carries the fresh marker (`hold.ctx`) for
987
1057
  * `wrapTransactionCallback` to scope around the user callback.
988
1058
  */
989
- async acquire() {
1059
+ async acquire(reentrantError = reentrantTransactionError) {
990
1060
  // Walk the WHOLE marker chain, not just the innermost marker: with two
991
1061
  // pools, dbA-tx → dbB-tx → dbA-begin leaves dbB's marker innermost, but
992
1062
  // the dbA ancestor is still open, queueing the inner dbA begin behind it
@@ -999,7 +1069,7 @@ class PowdbTxGate {
999
1069
  parent = parent.parent;
1000
1070
  for (let c = parent; c !== undefined; c = c.parent) {
1001
1071
  if (c.gate === this && !c.done) {
1002
- throw reentrantTransactionError();
1072
+ throw reentrantError();
1003
1073
  }
1004
1074
  }
1005
1075
  const ctx = { gate: this, done: false, parent };
@@ -1009,12 +1079,14 @@ class PowdbTxGate {
1009
1079
  });
1010
1080
  const ahead = this.tail;
1011
1081
  this.tail = ahead.then(() => finished);
1082
+ this.outstanding++;
1012
1083
  const hold = {
1013
1084
  ctx,
1014
1085
  finish: () => {
1015
1086
  if (ctx.done)
1016
1087
  return;
1017
1088
  ctx.done = true;
1089
+ this.outstanding--;
1018
1090
  handOff();
1019
1091
  },
1020
1092
  };
@@ -1673,6 +1745,30 @@ class PowdbEmbeddedPool {
1673
1745
  throw new errors_js_1.ConnectionError('The PowDB embedded pool is closed: disconnect() was already called on this client.');
1674
1746
  }
1675
1747
  }
1748
+ if (ctl === null && holdRef.hold === null && this.txGate.busy) {
1749
+ // A statement from OUTSIDE the open transaction. The engine is one
1750
+ // handle, so running it now would put it inside that transaction: it
1751
+ // would read uncommitted rows, and a write would be rolled back with the
1752
+ // transaction after being reported as done. It takes its FIFO turn on the
1753
+ // gate instead, as a one-statement transaction of its own would. From
1754
+ // inside the transaction's own callback that wait could never end, so the
1755
+ // gate refuses it there.
1756
+ const hold = await this.txGate.acquire(statementInsideTransactionError);
1757
+ try {
1758
+ if (this.closed) {
1759
+ throw new errors_js_1.ConnectionError('The PowDB embedded pool is closed: disconnect() was already called on this client.');
1760
+ }
1761
+ try {
1762
+ return this.exec(powql, params);
1763
+ }
1764
+ catch (err) {
1765
+ throw wrapPowdbError(err);
1766
+ }
1767
+ }
1768
+ finally {
1769
+ hold.finish();
1770
+ }
1771
+ }
1676
1772
  if ((ctl === 'commit' || ctl === 'rollback') && holdRef.hold === null) {
1677
1773
  // This context never acquired the gate, its `begin` never ran (the
1678
1774
  // gate timed out / threw re-entrant E017, or no begin was issued at
@@ -1867,25 +1963,52 @@ async function openEmbeddedPool(target, poolOptions = {}, assumeEngineVersion, i
1867
1963
  throw err;
1868
1964
  throw new errors_js_1.ConnectionError(`PowDB embedded could not open data dir "${dir}": ${err.message}`);
1869
1965
  }
1870
- if (syncMode !== undefined) {
1871
- if (typeof db.setSyncMode !== 'function') {
1872
- throw new errors_js_1.ConnectionError('embedded `syncMode` requires @zvndev/powdb-embedded ≥ 0.7.1 (the installed addon has no setSyncMode).');
1966
+ try {
1967
+ if (syncMode !== undefined) {
1968
+ if (typeof db.setSyncMode !== 'function') {
1969
+ throw new errors_js_1.ConnectionError('embedded `syncMode` requires @zvndev/powdb-embedded ≥ 0.7.1 (the installed addon has no setSyncMode).');
1970
+ }
1971
+ db.setSyncMode(syncMode);
1972
+ }
1973
+ // Native typed wire is feature-detected on the OPENED handle: an addon ≥ 0.14
1974
+ // exposes `queryWithParams`, so nativeRaw turns on (server-gate ≥ 0.13 still
1975
+ // applies via the version); an older addon has no such method → false.
1976
+ const capabilities = capabilitiesFromVersion(assumeEngineVersion ?? resolveEmbeddedVersion(), {
1977
+ hasNativeRaw: typeof db.queryWithParams === 'function',
1978
+ });
1979
+ // A read-only target forces the pool's readonly flag; otherwise honor whatever
1980
+ // `poolOptions` (threaded from `options.readonly`) carried.
1981
+ return new PowdbEmbeddedPool(db, {
1982
+ ...poolOptions,
1983
+ capabilities,
1984
+ readonly: Boolean(readonly) || Boolean(poolOptions.readonly),
1985
+ });
1986
+ }
1987
+ catch (err) {
1988
+ // The caller never receives this handle, so nothing else can close it.
1989
+ try {
1990
+ db.close?.();
1991
+ }
1992
+ catch {
1993
+ // The failure being reported is the useful one.
1873
1994
  }
1874
- db.setSyncMode(syncMode);
1995
+ throw err;
1996
+ }
1997
+ }
1998
+ /**
1999
+ * Probe a networked pool Turbine just built and wrap it. The pool is closed
2000
+ * when the probe or the wrapper refuses, because the caller never sees it
2001
+ * and its idle sockets would otherwise keep the process alive.
2002
+ */
2003
+ async function wrapOwnedClientPool(clientPool, poolOptions, assumeEngineVersion) {
2004
+ try {
2005
+ const capabilities = await assertNetworkedVersion(clientPool, assumeEngineVersion);
2006
+ return new PowdbPool(clientPool, undefined, { ...poolOptions, capabilities });
2007
+ }
2008
+ catch (err) {
2009
+ await clientPool.close().catch(() => { });
2010
+ throw err;
1875
2011
  }
1876
- // Native typed wire is feature-detected on the OPENED handle: an addon ≥ 0.14
1877
- // exposes `queryWithParams`, so nativeRaw turns on (server-gate ≥ 0.13 still
1878
- // applies via the version); an older addon has no such method → false.
1879
- const capabilities = capabilitiesFromVersion(assumeEngineVersion ?? resolveEmbeddedVersion(), {
1880
- hasNativeRaw: typeof db.queryWithParams === 'function',
1881
- });
1882
- // A read-only target forces the pool's readonly flag; otherwise honor whatever
1883
- // `poolOptions` (threaded from `options.readonly`) carried.
1884
- return new PowdbEmbeddedPool(db, {
1885
- ...poolOptions,
1886
- capabilities,
1887
- readonly: Boolean(readonly) || Boolean(poolOptions.readonly),
1888
- });
1889
2012
  }
1890
2013
  /**
1891
2014
  * Bind Turbine to PowDB. `target` is one of:
@@ -1916,9 +2039,7 @@ async function turbinePowDB(target, schema, options = {}) {
1916
2039
  const max = options.connectionLimit ?? 10;
1917
2040
  if (typeof target === 'string') {
1918
2041
  const mod = options.powdbClientModule ?? (await loadPowdb());
1919
- const clientPool = new mod.Pool({ ...parsePowdbUrl(target), max });
1920
- const capabilities = await assertNetworkedVersion(clientPool, options.assumeEngineVersion);
1921
- pool = new PowdbPool(clientPool, undefined, { ...poolOptions, capabilities });
2042
+ pool = await wrapOwnedClientPool(new mod.Pool({ ...parsePowdbUrl(target), max }), poolOptions, options.assumeEngineVersion);
1922
2043
  owns = true;
1923
2044
  }
1924
2045
  else if (target instanceof PowdbPool) {
@@ -1938,26 +2059,36 @@ async function turbinePowDB(target, schema, options = {}) {
1938
2059
  }
1939
2060
  else {
1940
2061
  const mod = options.powdbClientModule ?? (await loadPowdb());
1941
- const clientPool = new mod.Pool({ ...target, max });
1942
- const capabilities = await assertNetworkedVersion(clientPool, options.assumeEngineVersion);
1943
- pool = new PowdbPool(clientPool, undefined, { ...poolOptions, capabilities });
2062
+ pool = await wrapOwnedClientPool(new mod.Pool({ ...target, max }), poolOptions, options.assumeEngineVersion);
1944
2063
  owns = true;
1945
2064
  }
1946
- // The PowQL generator is loaded here to keep client.ts free of any PowDB import.
1947
- const { PowqlInterface } = await Promise.resolve().then(() => __importStar(require('./powql.js')));
1948
- const queryInterfaceFactory = (p, table, sch, middlewares, opts) => new PowqlInterface(p, table, sch, middlewares, opts);
1949
- // Forward every client-level option EXCEPT the ones this factory owns (they
1950
- // configure the pool / transport above, and TurbineClient warns on a config
1951
- // key it does not recognize). Destructured rather than hand-listed on the way
1952
- // IN: an allowlist is how `globalFilters` came to be accepted and ignored.
1953
- const { connectionLimit: _connectionLimit, transactionQueueTimeoutMs: _transactionQueueTimeoutMs, retryStaleReads: _retryStaleReads, assumeEngineVersion: _assumeEngineVersion, readonly: _readonly, powdbClientModule: _powdbClientModule, powdbEmbeddedModule: _powdbEmbeddedModule, ...clientConfig } = options;
1954
- const client = new client_js_1.TurbineClient({
1955
- ...clientConfig,
1956
- pool,
1957
- preparedStatements: false,
1958
- dialect: exports.powdbDialect,
1959
- queryInterfaceFactory,
1960
- }, schema);
2065
+ let client;
2066
+ try {
2067
+ // The PowQL generator is loaded here to keep client.ts free of any PowDB import.
2068
+ const { PowqlInterface } = await Promise.resolve().then(() => __importStar(require('./powql.js')));
2069
+ const queryInterfaceFactory = (p, table, sch, middlewares, opts) => new PowqlInterface(p, table, sch, middlewares, opts);
2070
+ // Forward every client-level option EXCEPT the ones this factory owns (they
2071
+ // configure the pool / transport above, and TurbineClient warns on a config
2072
+ // key it does not recognize). Destructured rather than hand-listed on the way
2073
+ // IN: an allowlist is how `globalFilters` came to be accepted and ignored.
2074
+ const { connectionLimit: _connectionLimit, transactionQueueTimeoutMs: _transactionQueueTimeoutMs, retryStaleReads: _retryStaleReads, assumeEngineVersion: _assumeEngineVersion, readonly: _readonly, powdbClientModule: _powdbClientModule, powdbEmbeddedModule: _powdbEmbeddedModule, ...clientConfig } = options;
2075
+ client = new client_js_1.TurbineClient({
2076
+ ...clientConfig,
2077
+ pool,
2078
+ preparedStatements: false,
2079
+ dialect: exports.powdbDialect,
2080
+ queryInterfaceFactory,
2081
+ }, schema);
2082
+ }
2083
+ catch (err) {
2084
+ // A failed factory hands the caller nothing to close, so a pool or embedded
2085
+ // handle it BUILT is closed here (the client constructor refuses a bad
2086
+ // config, a static global filter naming no table for one). A pool the
2087
+ // caller supplied is the caller's and stays open.
2088
+ if (owns)
2089
+ await pool.end().catch(() => { });
2090
+ throw err;
2091
+ }
1961
2092
  if (owns) {
1962
2093
  // Turbine built this pool / embedded handle, so disconnect()/end() must
1963
2094
  // close it. client.ts sees TurbineConfig.pool as EXTERNAL (ownsPool =
@@ -1966,9 +2097,10 @@ async function turbinePowDB(target, schema, options = {}) {
1966
2097
  // open until powdb-server's idle timeout (~300s) closed them. Consistent
1967
2098
  // with turbineMssql's owned-pool patch.
1968
2099
  const baseDisconnect = client.disconnect.bind(client);
1969
- const close = async () => {
1970
- await baseDisconnect();
2100
+ const close = async (options) => {
2101
+ const result = options === undefined ? await baseDisconnect() : await baseDisconnect(options);
1971
2102
  await pool.end();
2103
+ return result ?? undefined;
1972
2104
  };
1973
2105
  const patch = client;
1974
2106
  patch.disconnect = close;
@@ -1976,7 +2108,7 @@ async function turbinePowDB(target, schema, options = {}) {
1976
2108
  }
1977
2109
  else {
1978
2110
  // Injected pool, the caller owns its lifecycle.
1979
- client.disconnect = async () => { };
2111
+ client.disconnect = async (options) => (options === undefined ? undefined : { timedOut: false, forcedConnections: 0 });
1980
2112
  }
1981
2113
  return client;
1982
2114
  }