turbine-orm 0.50.0 → 0.51.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 (186) hide show
  1. package/README.md +66 -66
  2. package/dist/adapters/cockroachdb.d.ts +5 -5
  3. package/dist/adapters/cockroachdb.js +10 -10
  4. package/dist/adapters/index.d.ts +5 -5
  5. package/dist/adapters/index.js +7 -7
  6. package/dist/adapters/yugabytedb.d.ts +7 -7
  7. package/dist/adapters/yugabytedb.js +10 -10
  8. package/dist/cjs/adapters/cockroachdb.d.ts +5 -5
  9. package/dist/cjs/adapters/cockroachdb.js +10 -10
  10. package/dist/cjs/adapters/index.d.ts +5 -5
  11. package/dist/cjs/adapters/index.js +7 -7
  12. package/dist/cjs/adapters/yugabytedb.d.ts +7 -7
  13. package/dist/cjs/adapters/yugabytedb.js +10 -10
  14. package/dist/cjs/cli/config.d.ts +13 -2
  15. package/dist/cjs/cli/config.js +3 -2
  16. package/dist/cjs/cli/destructive.d.ts +1 -1
  17. package/dist/cjs/cli/destructive.js +1 -1
  18. package/dist/cjs/cli/index.d.ts +10 -10
  19. package/dist/cjs/cli/index.js +49 -45
  20. package/dist/cjs/cli/loader.d.ts +7 -7
  21. package/dist/cjs/cli/loader.js +9 -9
  22. package/dist/cjs/cli/mcp.js +4 -4
  23. package/dist/cjs/cli/migrate.d.ts +5 -5
  24. package/dist/cjs/cli/migrate.js +11 -11
  25. package/dist/cjs/cli/studio-ui.generated.js +1 -1
  26. package/dist/cjs/cli/ui.d.ts +2 -2
  27. package/dist/cjs/cli/ui.js +2 -2
  28. package/dist/cjs/client.d.ts +49 -38
  29. package/dist/cjs/client.js +57 -56
  30. package/dist/cjs/dialect.d.ts +62 -18
  31. package/dist/cjs/dialect.js +40 -2
  32. package/dist/cjs/errors.d.ts +5 -5
  33. package/dist/cjs/errors.js +11 -11
  34. package/dist/cjs/generate.d.ts +6 -6
  35. package/dist/cjs/generate.js +31 -29
  36. package/dist/cjs/index-advisor.d.ts +5 -5
  37. package/dist/cjs/index-advisor.js +0 -0
  38. package/dist/cjs/index.d.ts +1 -1
  39. package/dist/cjs/index.js +7 -7
  40. package/dist/cjs/introspect.d.ts +35 -9
  41. package/dist/cjs/introspect.js +83 -32
  42. package/dist/cjs/mssql.d.ts +11 -11
  43. package/dist/cjs/mssql.js +64 -29
  44. package/dist/cjs/mysql.d.ts +8 -8
  45. package/dist/cjs/mysql.js +61 -23
  46. package/dist/cjs/nested-write.d.ts +21 -2
  47. package/dist/cjs/nested-write.js +51 -14
  48. package/dist/cjs/optional-peer-import.cjs +7 -7
  49. package/dist/cjs/optional-peer-import.d.cts +7 -7
  50. package/dist/cjs/pipeline-submittable.d.ts +2 -2
  51. package/dist/cjs/pipeline-submittable.js +6 -6
  52. package/dist/cjs/pipeline.d.ts +1 -1
  53. package/dist/cjs/pipeline.js +4 -4
  54. package/dist/cjs/powdb-introspect.d.ts +1 -1
  55. package/dist/cjs/powdb-introspect.js +1 -1
  56. package/dist/cjs/powdb.d.ts +28 -28
  57. package/dist/cjs/powdb.js +66 -66
  58. package/dist/cjs/powql.d.ts +27 -27
  59. package/dist/cjs/powql.js +73 -52
  60. package/dist/cjs/query/aggregates.d.ts +1 -1
  61. package/dist/cjs/query/aggregates.js +5 -5
  62. package/dist/cjs/query/batched-loader.d.ts +11 -11
  63. package/dist/cjs/query/batched-loader.js +24 -24
  64. package/dist/cjs/query/builder.d.ts +39 -21
  65. package/dist/cjs/query/builder.js +99 -57
  66. package/dist/cjs/query/compound-unique.d.ts +1 -1
  67. package/dist/cjs/query/compound-unique.js +0 -0
  68. package/dist/cjs/query/deferred.d.ts +12 -6
  69. package/dist/cjs/query/deferred.js +1 -1
  70. package/dist/cjs/query/filters.d.ts +31 -11
  71. package/dist/cjs/query/filters.js +67 -14
  72. package/dist/cjs/query/index.d.ts +1 -1
  73. package/dist/cjs/query/index.js +1 -1
  74. package/dist/cjs/query/relations.d.ts +9 -9
  75. package/dist/cjs/query/relations.js +164 -57
  76. package/dist/cjs/query/types.d.ts +86 -35
  77. package/dist/cjs/query/types.js +1 -1
  78. package/dist/cjs/query/utils.d.ts +27 -10
  79. package/dist/cjs/query/utils.js +86 -14
  80. package/dist/cjs/query/where.d.ts +47 -28
  81. package/dist/cjs/query/where.js +130 -31
  82. package/dist/cjs/query/writes.d.ts +24 -5
  83. package/dist/cjs/query/writes.js +102 -13
  84. package/dist/cjs/realtime.d.ts +7 -7
  85. package/dist/cjs/realtime.js +9 -9
  86. package/dist/cjs/schema-builder.d.ts +18 -7
  87. package/dist/cjs/schema-builder.js +17 -10
  88. package/dist/cjs/schema-metadata.d.ts +3 -3
  89. package/dist/cjs/schema-metadata.js +9 -9
  90. package/dist/cjs/schema-sql.d.ts +9 -9
  91. package/dist/cjs/schema-sql.js +20 -20
  92. package/dist/cjs/schema.d.ts +19 -9
  93. package/dist/cjs/schema.js +6 -6
  94. package/dist/cjs/serverless.d.ts +15 -15
  95. package/dist/cjs/serverless.js +16 -16
  96. package/dist/cjs/sqlite.d.ts +8 -8
  97. package/dist/cjs/sqlite.js +53 -22
  98. package/dist/cjs/typed-sql.d.ts +4 -4
  99. package/dist/cjs/typed-sql.js +5 -5
  100. package/dist/cli/config.d.ts +13 -2
  101. package/dist/cli/config.js +3 -2
  102. package/dist/cli/destructive.d.ts +1 -1
  103. package/dist/cli/destructive.js +1 -1
  104. package/dist/cli/index.d.ts +10 -10
  105. package/dist/cli/index.js +49 -45
  106. package/dist/cli/loader.d.ts +7 -7
  107. package/dist/cli/loader.js +9 -9
  108. package/dist/cli/mcp.js +4 -4
  109. package/dist/cli/migrate.d.ts +5 -5
  110. package/dist/cli/migrate.js +11 -11
  111. package/dist/cli/studio-ui.generated.js +1 -1
  112. package/dist/cli/ui.d.ts +2 -2
  113. package/dist/cli/ui.js +2 -2
  114. package/dist/client.d.ts +49 -38
  115. package/dist/client.js +57 -56
  116. package/dist/dialect.d.ts +62 -18
  117. package/dist/dialect.js +40 -2
  118. package/dist/errors.d.ts +5 -5
  119. package/dist/errors.js +11 -11
  120. package/dist/generate.d.ts +6 -6
  121. package/dist/generate.js +31 -29
  122. package/dist/index-advisor.d.ts +5 -5
  123. package/dist/index-advisor.js +0 -0
  124. package/dist/index.d.ts +1 -1
  125. package/dist/index.js +7 -7
  126. package/dist/introspect.d.ts +35 -9
  127. package/dist/introspect.js +82 -32
  128. package/dist/mssql.d.ts +11 -11
  129. package/dist/mssql.js +64 -29
  130. package/dist/mysql.d.ts +8 -8
  131. package/dist/mysql.js +61 -23
  132. package/dist/nested-write.d.ts +21 -2
  133. package/dist/nested-write.js +51 -14
  134. package/dist/optional-peer-import.cjs +7 -7
  135. package/dist/optional-peer-import.d.cts +7 -7
  136. package/dist/pipeline-submittable.d.ts +2 -2
  137. package/dist/pipeline-submittable.js +6 -6
  138. package/dist/pipeline.d.ts +1 -1
  139. package/dist/pipeline.js +4 -4
  140. package/dist/powdb-introspect.d.ts +1 -1
  141. package/dist/powdb-introspect.js +1 -1
  142. package/dist/powdb.d.ts +28 -28
  143. package/dist/powdb.js +66 -66
  144. package/dist/powql.d.ts +27 -27
  145. package/dist/powql.js +73 -52
  146. package/dist/query/aggregates.d.ts +1 -1
  147. package/dist/query/aggregates.js +5 -5
  148. package/dist/query/batched-loader.d.ts +11 -11
  149. package/dist/query/batched-loader.js +24 -24
  150. package/dist/query/builder.d.ts +39 -21
  151. package/dist/query/builder.js +100 -58
  152. package/dist/query/compound-unique.d.ts +1 -1
  153. package/dist/query/compound-unique.js +0 -0
  154. package/dist/query/deferred.d.ts +12 -6
  155. package/dist/query/deferred.js +1 -1
  156. package/dist/query/filters.d.ts +31 -11
  157. package/dist/query/filters.js +66 -13
  158. package/dist/query/index.d.ts +1 -1
  159. package/dist/query/index.js +1 -1
  160. package/dist/query/relations.d.ts +9 -9
  161. package/dist/query/relations.js +165 -58
  162. package/dist/query/types.d.ts +86 -35
  163. package/dist/query/types.js +1 -1
  164. package/dist/query/utils.d.ts +27 -10
  165. package/dist/query/utils.js +84 -14
  166. package/dist/query/where.d.ts +47 -28
  167. package/dist/query/where.js +129 -32
  168. package/dist/query/writes.d.ts +24 -5
  169. package/dist/query/writes.js +101 -13
  170. package/dist/realtime.d.ts +7 -7
  171. package/dist/realtime.js +9 -9
  172. package/dist/schema-builder.d.ts +18 -7
  173. package/dist/schema-builder.js +17 -10
  174. package/dist/schema-metadata.d.ts +3 -3
  175. package/dist/schema-metadata.js +9 -9
  176. package/dist/schema-sql.d.ts +9 -9
  177. package/dist/schema-sql.js +20 -20
  178. package/dist/schema.d.ts +19 -9
  179. package/dist/schema.js +6 -6
  180. package/dist/serverless.d.ts +15 -15
  181. package/dist/serverless.js +16 -16
  182. package/dist/sqlite.d.ts +8 -8
  183. package/dist/sqlite.js +53 -22
  184. package/dist/typed-sql.d.ts +4 -4
  185. package/dist/typed-sql.js +5 -5
  186. package/package.json +2 -2
@@ -1,5 +1,5 @@
1
1
  /**
2
- * turbine-orm — Nested write engine
2
+ * turbine-orm, Nested write engine
3
3
  *
4
4
  * Tree-walking create/update that resolves relation fields in `data` into
5
5
  * batched SQL operations within a transaction. Supports create, connect,
@@ -8,7 +8,7 @@
8
8
  *
9
9
  * This module is imported by `query/builder.ts` when the `data` argument
10
10
  * of `create()` or `update()` contains relation fields. It never imports
11
- * `client.ts` directly — the transaction handle is passed in via
11
+ * `client.ts` directly, the transaction handle is passed in via
12
12
  * `NestedWriteContext`.
13
13
  */
14
14
  import { CircularRelationError, describeTargetForMessage, NotFoundError, RelationError, UnsupportedFeatureError, ValidationError, } from './errors.js';
@@ -242,7 +242,7 @@ const M2M_SUPPORTED_OPS = new Set(['connect', 'disconnect', 'set']);
242
242
  * On the core client the auto-created property accessors are CAMELCASED
243
243
  * (`db.userTags` for `user_tags`, see the `Object.defineProperty` loops in
244
244
  * client.ts), so `db["user_tags"]` is `undefined` for every snake_case junction
245
- * — which is every junction `turbine pull` produces over a hand-written join
245
+ * - which is every junction `turbine pull` produces over a hand-written join
246
246
  * table. `db.table("user_tags")` takes the raw table name and exists on both
247
247
  * TurbineClient and the TransactionClient handed to `$transaction`, so that is
248
248
  * the form to recommend.
@@ -469,9 +469,9 @@ const SKIP_DUPLICATES_FEATURE = 'createMany({ skipDuplicates: true })';
469
469
  * `createMany({ skipDuplicates })`, so the engines that refuse it pay for the
470
470
  * refusal once instead of on every connect.
471
471
  *
472
- * The capability is not reachable from here as a flag — the `Dialect` is private
472
+ * The capability is not reachable from here as a flag, the `Dialect` is private
473
473
  * to QueryInterface / TurbineClient and `NestedWriteContext` carries only the
474
- * schema and the transaction — so it is read from the engine's OWN structured
474
+ * schema and the transaction, so it is read from the engine's OWN structured
475
475
  * refusal (`UnsupportedFeatureError.feature`) rather than from a hardcoded
476
476
  * engine list that would drift. Both refusing engines throw while BUILDING the
477
477
  * statement, before anything is written, so the attempt is side-effect-free.
@@ -509,11 +509,11 @@ async function insertJunctionRowsSkippingDuplicates(ctx, plan, values) {
509
509
  *
510
510
  * 1. Junction constrains the pair AND the engine supports `skipDuplicates`
511
511
  * (PostgreSQL, SQLite and MySQL: `ON CONFLICT DO NOTHING` / a no-op
512
- * `ON DUPLICATE KEY UPDATE`) — one INSERT, no read. The engine resolves the
512
+ * `ON DUPLICATE KEY UPDATE`), one INSERT, no read. The engine resolves the
513
513
  * conflict, so two transactions connecting the same pair at the same time
514
514
  * both succeed and one link row exists. This is the introspected path:
515
515
  * every junction introspection can detect declares the pair unique.
516
- * 2. Otherwise — read this parent's existing link rows for exactly these targets
516
+ * 2. Otherwise, read this parent's existing link rows for exactly these targets
517
517
  * and insert only the missing ones. Used when the engine refuses the option
518
518
  * (SQL Server and PowDB have no single-statement skip-duplicates form and
519
519
  * throw E017), and when the junction does NOT constrain the pair, where
@@ -658,7 +658,7 @@ export async function executeNestedCreate(ctx, tableName, data, depth = 0, path
658
658
  validateOps(relName, ops, false);
659
659
  }
660
660
  // belongsTo relations put the foreign key on the PARENT row, so they must be
661
- // resolved BEFORE the parent is inserted — otherwise a NOT NULL FK column
661
+ // resolved BEFORE the parent is inserted, otherwise a NOT NULL FK column
662
662
  // fails on the initial INSERT. We resolve each belongsTo op (create/connect/
663
663
  // connectOrCreate) to its referenced row and fold the FK values into the
664
664
  // parent's own INSERT.
@@ -679,7 +679,7 @@ export async function executeNestedCreate(ctx, tableName, data, depth = 0, path
679
679
  const parentRow = (await ctx.tx.table(tableName).create({
680
680
  data: { ...scalars, ...belongsToFks },
681
681
  }));
682
- // Process hasMany / hasOne relations — their FK lives on the CHILD, so they
682
+ // Process hasMany / hasOne relations, their FK lives on the CHILD, so they
683
683
  // need the parent row to exist first.
684
684
  for (const [relName, ops] of Object.entries(relations)) {
685
685
  const rel = tableMeta.relations[relName];
@@ -746,7 +746,7 @@ export async function executeNestedUpdate(ctx, tableName, where, data, depth = 0
746
746
  for (const [relName, ops] of Object.entries(relations)) {
747
747
  const rel = tableMeta.relations[relName];
748
748
  if (rel.type === 'hasMany' || rel.type === 'hasOne') {
749
- // create, connect, connectOrCreate — same as nested create
749
+ // create, connect, connectOrCreate, same as nested create
750
750
  await processHasManyCreate(ctx, rel, ops, parentRow, depth, path, relName);
751
751
  // disconnect
752
752
  if (ops.disconnect !== undefined) {
@@ -771,7 +771,7 @@ export async function executeNestedUpdate(ctx, tableName, where, data, depth = 0
771
771
  }
772
772
  else if (rel.type === 'belongsTo') {
773
773
  await processBelongsToCreate(ctx, rel, ops, parentRow, tableName, depth, path, relName);
774
- // update (belongsTo — derive where from parent FK)
774
+ // update (belongsTo, derive where from parent FK)
775
775
  if (ops.update !== undefined) {
776
776
  await processBelongsToUpdate(ctx, rel, ops.update, parentRow, tableName);
777
777
  }
@@ -834,7 +834,7 @@ async function processHasManyCreate(ctx, rel, ops, parentRow, depth, path, relNa
834
834
  }
835
835
  }
836
836
  else {
837
- // Batch via createMany (UNNEST) — fast path
837
+ // Batch via createMany (UNNEST), fast path
838
838
  const injected = items.map((item) => injectForeignKey(item, rel, parentRow, ctx.schema));
839
839
  await ctx.tx.table(rel.to).createMany({ data: injected });
840
840
  }
@@ -914,7 +914,7 @@ async function resolveBelongsToForCreate(ctx, rel, ops, parentTable, depth, path
914
914
  async function processBelongsToCreate(ctx, rel, ops, parentRow, parentTable, depth, path, relName) {
915
915
  const fks = normalizeKeyColumns(rel.foreignKey);
916
916
  const refs = normalizeKeyColumns(rel.referenceKey);
917
- // create — insert the related row, then update parent's FK
917
+ // create, insert the related row, then update parent's FK
918
918
  if (ops.create !== undefined) {
919
919
  const items = toArray(ops.create);
920
920
  if (items.length > 0) {
@@ -933,7 +933,7 @@ async function processBelongsToCreate(ctx, rel, ops, parentRow, parentTable, dep
933
933
  });
934
934
  }
935
935
  }
936
- // connect — validate existence, update parent's FK
936
+ // connect, validate existence, update parent's FK
937
937
  if (ops.connect !== undefined) {
938
938
  const items = toArray(ops.connect);
939
939
  if (items.length > 0) {
@@ -960,6 +960,41 @@ async function processBelongsToCreate(ctx, rel, ops, parentRow, parentTable, dep
960
960
  // ---------------------------------------------------------------------------
961
961
  // connect, connectOrCreate, disconnect, set, delete helpers
962
962
  // ---------------------------------------------------------------------------
963
+ /**
964
+ * Refuse a connect that would take a to-many child away from another parent,
965
+ * when {@link NestedWriteContext.scopedConnect} is on. See that field for why.
966
+ *
967
+ * Compares the child's CURRENT foreign key against the parent's reference
968
+ * value. Null (unowned) passes, an exact match passes (idempotent re-connect),
969
+ * anything else is refused. Values are compared after normalizing to a
970
+ * primitive, so a bigint FK read back as a string cannot look like a mismatch
971
+ * against the number the parent write returned.
972
+ */
973
+ function assertConnectInScope(ctx, rel, child, parentRow, target) {
974
+ if (!ctx.scopedConnect)
975
+ return;
976
+ if (rel.type !== 'hasMany' && rel.type !== 'hasOne')
977
+ return;
978
+ const childTable = ctx.schema.tables[rel.to];
979
+ const parentTable = ctx.schema.tables[rel.from];
980
+ if (!childTable)
981
+ return;
982
+ const fks = normalizeKeyColumns(rel.foreignKey);
983
+ const refs = normalizeKeyColumns(rel.referenceKey);
984
+ const key = (v) => (v === null || v === undefined ? null : String(v));
985
+ for (let i = 0; i < fks.length; i++) {
986
+ const fkField = childTable.reverseColumnMap[fks[i]] ?? fks[i];
987
+ const refField = parentTable?.reverseColumnMap[refs[i]] ?? refs[i];
988
+ const current = key(child[fkField]);
989
+ if (current === null)
990
+ continue;
991
+ if (current === key(parentRow[refField]))
992
+ continue;
993
+ throw new ValidationError(`[turbine] connect refused: ${rel.to} row ${describeTargetForMessage(target)} is already owned by ` +
994
+ `another "${rel.from}" (its ${fks[i]} is ${current}). \`scopedConnect\` only allows connecting a row ` +
995
+ `that is unowned or already owned by this parent; re-parenting must be an explicit update.`);
996
+ }
997
+ }
963
998
  async function batchConnect(ctx, rel, items, parentRow) {
964
999
  const fks = normalizeKeyColumns(rel.foreignKey);
965
1000
  const refs = normalizeKeyColumns(rel.referenceKey);
@@ -972,6 +1007,7 @@ async function batchConnect(ctx, rel, items, parentRow) {
972
1007
  if (!existing) {
973
1008
  throw new ValidationError(`[turbine] connect: no ${rel.to} row found matching ${describeTargetForMessage(target)}.`);
974
1009
  }
1010
+ assertConnectInScope(ctx, rel, existing, parentRow, target);
975
1011
  }
976
1012
  // Build FK update data to point children at parent
977
1013
  const updateData = {};
@@ -999,6 +1035,7 @@ async function connectOrCreate(ctx, rel, op, parentRow) {
999
1035
  row = (await ctx.tx.table(rel.to).create({ data: injected }));
1000
1036
  }
1001
1037
  else {
1038
+ assertConnectInScope(ctx, rel, row, parentRow, op.where);
1002
1039
  // Update FK to point to parent
1003
1040
  const updateData = {};
1004
1041
  for (let i = 0; i < fks.length; i++) {
@@ -1,7 +1,7 @@
1
1
  "use strict";
2
2
  /**
3
3
  * True dynamic `import()` for the optional peer dependencies (`mysql2`,
4
- * `mssql`, `@zvndev/powdb-client`, `@zvndev/powdb-embedded`) — safe in BOTH
4
+ * `mssql`, `@zvndev/powdb-client`, `@zvndev/powdb-embedded`), safe in BOTH
5
5
  * build outputs, including for peers that are ESM-only.
6
6
  *
7
7
  * THE PROBLEM THIS FILE SOLVES (the `@zvndev/powdb-client` ≥ 0.9 CJS break):
@@ -9,7 +9,7 @@
9
9
  * peers stay out of the static graph. The ESM build (`tsconfig.json`, module
10
10
  * NodeNext) emits that `import()` verbatim. The CJS build (`tsconfig.cjs.json`,
11
11
  * module CommonJS) however TRANSPILES `import()` into
12
- * `Promise.resolve().then(() => require(...))` — and `require()` of an
12
+ * `Promise.resolve().then(() => require(...))`, and `require()` of an
13
13
  * ESM-only package (no `require` export condition, e.g. powdb-client ≥ 0.9)
14
14
  * throws `ERR_PACKAGE_PATH_NOT_EXPORTED`, breaking every CJS consumer.
15
15
  *
@@ -18,18 +18,18 @@
18
18
  * says `"type": "module"`, so NodeNext would classify every `.ts` source as
19
19
  * ESM and emit ESM into dist/cjs). A `.cts` file is the escape hatch: it is
20
20
  * CommonJS-format by extension regardless of package `type`, so under the ESM
21
- * pass (NodeNext) it compiles to `dist/optional-peer-import.cjs` — a CommonJS
21
+ * pass (NodeNext) it compiles to `dist/optional-peer-import.cjs`, a CommonJS
22
22
  * file whose `import()` SURVIVES transpilation (NodeNext preserves dynamic
23
23
  * import in CJS files precisely because it is the only way CJS can load ESM).
24
24
  *
25
25
  * That gives the published package two copies of this module:
26
- * - `dist/optional-peer-import.cjs` (ESM pass, NodeNext) — real `import()`
27
- * - `dist/cjs/optional-peer-import.cjs` (CJS pass, CommonJS) — lowered to `require()`
26
+ * - `dist/optional-peer-import.cjs` (ESM pass, NodeNext) , real `import()`
27
+ * - `dist/cjs/optional-peer-import.cjs` (CJS pass, CommonJS) , lowered to `require()`
28
28
  *
29
29
  * The lowered copy works fine for CJS-loadable peers (`mysql2`, `mssql`, older
30
30
  * powdb peers). When it hits an ESM-only peer, the `require()` fails with a
31
31
  * recognizable code and this function falls back to delegating the load to the
32
- * sibling NodeNext copy one directory up (`../optional-peer-import.cjs`) —
32
+ * sibling NodeNext copy one directory up (`../optional-peer-import.cjs`) -
33
33
  * which is a plain CommonJS file (loadable by `require()` on every supported
34
34
  * Node) whose real `import()` then loads the ESM peer. The ESM-pass copy has
35
35
  * no such sibling; its lazy `require` throws and the original error surfaces,
@@ -60,7 +60,7 @@ function isEsmOnlyLoadError(err) {
60
60
  * transpilation (see the module doc comment).
61
61
  *
62
62
  * @param specifier bare package specifier (e.g. `'@zvndev/powdb-client'`).
63
- * @param allowEsmFallback internal recursion guard — the delegated call passes
63
+ * @param allowEsmFallback internal recursion guard, the delegated call passes
64
64
  * `false` so a failure in the sibling copy can never bounce back.
65
65
  */
66
66
  async function importOptionalPeer(specifier, allowEsmFallback = true) {
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * True dynamic `import()` for the optional peer dependencies (`mysql2`,
3
- * `mssql`, `@zvndev/powdb-client`, `@zvndev/powdb-embedded`) — safe in BOTH
3
+ * `mssql`, `@zvndev/powdb-client`, `@zvndev/powdb-embedded`), safe in BOTH
4
4
  * build outputs, including for peers that are ESM-only.
5
5
  *
6
6
  * THE PROBLEM THIS FILE SOLVES (the `@zvndev/powdb-client` ≥ 0.9 CJS break):
@@ -8,7 +8,7 @@
8
8
  * peers stay out of the static graph. The ESM build (`tsconfig.json`, module
9
9
  * NodeNext) emits that `import()` verbatim. The CJS build (`tsconfig.cjs.json`,
10
10
  * module CommonJS) however TRANSPILES `import()` into
11
- * `Promise.resolve().then(() => require(...))` — and `require()` of an
11
+ * `Promise.resolve().then(() => require(...))`, and `require()` of an
12
12
  * ESM-only package (no `require` export condition, e.g. powdb-client ≥ 0.9)
13
13
  * throws `ERR_PACKAGE_PATH_NOT_EXPORTED`, breaking every CJS consumer.
14
14
  *
@@ -17,18 +17,18 @@
17
17
  * says `"type": "module"`, so NodeNext would classify every `.ts` source as
18
18
  * ESM and emit ESM into dist/cjs). A `.cts` file is the escape hatch: it is
19
19
  * CommonJS-format by extension regardless of package `type`, so under the ESM
20
- * pass (NodeNext) it compiles to `dist/optional-peer-import.cjs` — a CommonJS
20
+ * pass (NodeNext) it compiles to `dist/optional-peer-import.cjs`, a CommonJS
21
21
  * file whose `import()` SURVIVES transpilation (NodeNext preserves dynamic
22
22
  * import in CJS files precisely because it is the only way CJS can load ESM).
23
23
  *
24
24
  * That gives the published package two copies of this module:
25
- * - `dist/optional-peer-import.cjs` (ESM pass, NodeNext) — real `import()`
26
- * - `dist/cjs/optional-peer-import.cjs` (CJS pass, CommonJS) — lowered to `require()`
25
+ * - `dist/optional-peer-import.cjs` (ESM pass, NodeNext) , real `import()`
26
+ * - `dist/cjs/optional-peer-import.cjs` (CJS pass, CommonJS) , lowered to `require()`
27
27
  *
28
28
  * The lowered copy works fine for CJS-loadable peers (`mysql2`, `mssql`, older
29
29
  * powdb peers). When it hits an ESM-only peer, the `require()` fails with a
30
30
  * recognizable code and this function falls back to delegating the load to the
31
- * sibling NodeNext copy one directory up (`../optional-peer-import.cjs`) —
31
+ * sibling NodeNext copy one directory up (`../optional-peer-import.cjs`) -
32
32
  * which is a plain CommonJS file (loadable by `require()` on every supported
33
33
  * Node) whose real `import()` then loads the ESM peer. The ESM-pass copy has
34
34
  * no such sibling; its lazy `require` throws and the original error surfaces,
@@ -46,7 +46,7 @@
46
46
  * transpilation (see the module doc comment).
47
47
  *
48
48
  * @param specifier bare package specifier (e.g. `'@zvndev/powdb-client'`).
49
- * @param allowEsmFallback internal recursion guard — the delegated call passes
49
+ * @param allowEsmFallback internal recursion guard, the delegated call passes
50
50
  * `false` so a failure in the sibling copy can never bounce back.
51
51
  */
52
52
  declare function importOptionalPeer(specifier: string, allowEsmFallback?: boolean): Promise<unknown>;
@@ -1,5 +1,5 @@
1
1
  /**
2
- * turbine-orm — Real Postgres pipeline protocol implementation
2
+ * turbine-orm, Real Postgres pipeline protocol implementation
3
3
  *
4
4
  * Uses the pg extended-query protocol wire methods (parse/bind/describe/execute/sync)
5
5
  * exposed on pg.Client's Connection object to send multiple queries in a single
@@ -18,7 +18,7 @@
18
18
  */
19
19
  import type { EventEmitter } from 'node:events';
20
20
  import type { DeferredQuery } from './query/index.js';
21
- /** The pg Connection object — an EventEmitter with wire-protocol methods */
21
+ /** The pg Connection object, an EventEmitter with wire-protocol methods */
22
22
  export interface PgConnection extends EventEmitter {
23
23
  stream: {
24
24
  cork?: () => void;
@@ -1,5 +1,5 @@
1
1
  /**
2
- * turbine-orm — Real Postgres pipeline protocol implementation
2
+ * turbine-orm, Real Postgres pipeline protocol implementation
3
3
  *
4
4
  * Uses the pg extended-query protocol wire methods (parse/bind/describe/execute/sync)
5
5
  * exposed on pg.Client's Connection object to send multiple queries in a single
@@ -108,7 +108,7 @@ export async function runPipelined(client, queries, options = {}) {
108
108
  for (let i = 0; i < queries.length; i++) {
109
109
  results.push(new Result(undefined, client._types));
110
110
  }
111
- // commandComplete counter — tracks position across all commands
111
+ // commandComplete counter, tracks position across all commands
112
112
  let commandIndex = 0;
113
113
  // readyForQuery counter
114
114
  let rfqCount = 0;
@@ -186,7 +186,7 @@ export async function runPipelined(client, queries, options = {}) {
186
186
  reject(pipelineError);
187
187
  return;
188
188
  }
189
- // All succeeded — transform results
189
+ // All succeeded, transform results
190
190
  try {
191
191
  const transformed = [];
192
192
  for (let i = 0; i < queries.length; i++) {
@@ -203,13 +203,13 @@ export async function runPipelined(client, queries, options = {}) {
203
203
  // Event handlers
204
204
  // -----------------------------------------------------------------------
205
205
  function onParseComplete() {
206
- // No action needed — anonymous prepared statements
206
+ // No action needed, anonymous prepared statements
207
207
  }
208
208
  function onBindComplete() {
209
209
  // No action needed
210
210
  }
211
211
  function onNoData() {
212
- // DML without RETURNING — no RowDescription follows. Fine.
212
+ // DML without RETURNING, no RowDescription follows. Fine.
213
213
  }
214
214
  function onRowDescription(msg) {
215
215
  const qIdx = currentQueryIndex();
@@ -306,7 +306,7 @@ export async function runPipelined(client, queries, options = {}) {
306
306
  }, timeout);
307
307
  }
308
308
  // -----------------------------------------------------------------------
309
- // Send protocol messages — all in one TCP flush
309
+ // Send protocol messages, all in one TCP flush
310
310
  // -----------------------------------------------------------------------
311
311
  try {
312
312
  if (connection.stream.cork) {
@@ -1,5 +1,5 @@
1
1
  /**
2
- * turbine-orm — Pipeline execution
2
+ * turbine-orm, Pipeline execution
3
3
  *
4
4
  * Pipelines batch multiple independent queries into a single database round-trip.
5
5
  * Instead of N sequential awaits (N round-trips), you get 1 round-trip for all N queries.
package/dist/pipeline.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /**
2
- * turbine-orm — Pipeline execution
2
+ * turbine-orm, Pipeline execution
3
3
  *
4
4
  * Pipelines batch multiple independent queries into a single database round-trip.
5
5
  * Instead of N sequential awaits (N round-trips), you get 1 round-trip for all N queries.
@@ -86,11 +86,11 @@ export async function executePipeline(pool, queries, options) {
86
86
  if (queries.length === 0) {
87
87
  return [];
88
88
  }
89
- // Acquire a single client — reused for both capability check and execution
89
+ // Acquire a single client, reused for both capability check and execution
90
90
  const client = await pool.connect();
91
91
  try {
92
92
  if (supportsExtendedPipeline(client)) {
93
- // Real pipeline path — uses extended-query protocol wire methods
93
+ // Real pipeline path, uses extended-query protocol wire methods
94
94
  const pipelineOptions = {
95
95
  transactional: options?.transactional ?? true,
96
96
  timeout: options?.timeout,
@@ -98,7 +98,7 @@ export async function executePipeline(pool, queries, options) {
98
98
  const results = await runPipelined(client, queries, pipelineOptions);
99
99
  return results;
100
100
  }
101
- // Sequential fallback — reuses the same client
101
+ // Sequential fallback, reuses the same client
102
102
  return await runSequential(client, queries, options);
103
103
  }
104
104
  finally {
@@ -1,5 +1,5 @@
1
1
  /**
2
- * turbine-orm/powdb — `describe`-based introspection.
2
+ * turbine-orm/powdb, `describe`-based introspection.
3
3
  *
4
4
  * PowDB exposes its catalog through two ordinary rows-returning statements
5
5
  * (keywords since engine 0.10):
@@ -1,5 +1,5 @@
1
1
  /**
2
- * turbine-orm/powdb — `describe`-based introspection.
2
+ * turbine-orm/powdb, `describe`-based introspection.
3
3
  *
4
4
  * PowDB exposes its catalog through two ordinary rows-returning statements
5
5
  * (keywords since engine 0.10):
package/dist/powdb.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  /**
2
- * turbine-orm/powdb — Turbine's PowDB / PowQL backend.
2
+ * turbine-orm/powdb, Turbine's PowDB / PowQL backend.
3
3
  *
4
4
  * PowDB is a single-node embedded database with its own query language, **PowQL**
5
5
  * (not SQL), reached over `@zvndev/powdb-client`'s binary TCP protocol. PowDB is a
@@ -10,26 +10,26 @@
10
10
  *
11
11
  * PowDB realities shape the design (all verified firsthand against a live
12
12
  * `powdb-server` / the embedded addon, see `docs/internal/strategy/powdb-parity-matrix.md`):
13
- * - **`RETURNING` (since 0.7.0)** — `create/createMany/update/delete` append the
13
+ * - **`RETURNING` (since 0.7.0)**, `create/createMany/update/delete` append the
14
14
  * trailing `returning` keyword (`RETURNING *`, all columns) and read the
15
15
  * affected rows back in one round-trip. `upsert` is the lone exception (its
16
16
  * statement rejects `returning`) and reselects by primary key.
17
- * - **No generated IDs** — the app must supply every value → Turbine generates a
17
+ * - **No generated IDs**, the app must supply every value → Turbine generates a
18
18
  * client-side UUID for the primary key when it has a default.
19
19
  * - **`uuid`/`datetime`/`bytes` columns can't hold client-supplied values** (no
20
20
  * literal, no working cast on the wire) → Turbine maps everything onto the four
21
21
  * writable types (`str`/`int`/`float`/`bool`); `Date` → `int` epoch micros;
22
22
  * `string` PKs hold UUID strings.
23
- * - **No JSON aggregation / link navigation** — single-query nested `with` is
23
+ * - **No JSON aggregation / link navigation**, single-query nested `with` is
24
24
  * impossible → it degrades to batched N+1 loaders (Phase B).
25
- * - **Single global write lock; no savepoints/isolation** — nested
25
+ * - **Single global write lock; no savepoints/isolation**, nested
26
26
  * transactions / isolation / vector / LISTEN-NOTIFY / RLS throw.
27
27
  * Independent concurrent `db.$transaction` calls do NOT throw: they queue
28
28
  * FIFO on a pool-level gate and run one at a time (see {@link PowdbTxGate}).
29
- * Only a *re-entrant* transaction — a `db.$transaction` opened from inside
29
+ * Only a *re-entrant* transaction, a `db.$transaction` opened from inside
30
30
  * an active transaction callback's async context, which queueing would
31
- * deadlock — fails fast with E017.
32
- * - **The wire protocol pipelines** — `@zvndev/powdb-client` writes each
31
+ * deadlock, fails fast with E017.
32
+ * - **The wire protocol pipelines**, `@zvndev/powdb-client` writes each
33
33
  * request frame immediately and matches replies FIFO, so multiple queries
34
34
  * may be in flight on one connection. {@link PowdbPool}'s checked-out
35
35
  * clients advertise `supportsPipelining`, which lets the batch
@@ -211,7 +211,7 @@ interface PowdbModule {
211
211
  message: string;
212
212
  };
213
213
  }
214
- /** Connection options for {@link turbinePowDB} — host/port, not a connection string. */
214
+ /** Connection options for {@link turbinePowDB}, host/port, not a connection string. */
215
215
  export interface PowdbConnOptions {
216
216
  host: string;
217
217
  port: number;
@@ -258,7 +258,7 @@ export interface PowdbCapabilities {
258
258
  /** ≥ 0.13: server-side joins, hash-accelerated and bounded. */
259
259
  serverJoins: boolean;
260
260
  /**
261
- * ≥ 0.18: nested projections (shaped results) — a projection field may be a
261
+ * ≥ 0.18: nested projections (shaped results), a projection field may be a
262
262
  * whole correlated child query returning a per-parent JSON array. When set,
263
263
  * eligible `with` clauses compile into the parent statement instead of the
264
264
  * batched loaders.
@@ -367,7 +367,7 @@ export declare function powqlColumnType(col: ColumnMetadata): PowqlType;
367
367
  * synthesizing a client-side value for it.
368
368
  */
369
369
  /**
370
- * PowQL reserved words — the v0.10 lexer keyword table from POWQL.md's
370
+ * PowQL reserved words, the v0.10 lexer keyword table from POWQL.md's
371
371
  * "Reserved Words and Quoting" section, including the v0.10 additions
372
372
  * `schema` and `describe`. Keyword matching is case-sensitive in the lexer,
373
373
  * so only the exact lowercase form collides.
@@ -376,7 +376,7 @@ export declare const POWQL_KEYWORDS: ReadonlySet<string>;
376
376
  /**
377
377
  * Backtick-quote an identifier when PowQL would otherwise lex it as a keyword
378
378
  * (or when it contains characters outside the bare-identifier grammar).
379
- * Applied only in bare-identifier positions — DDL type/field names, index DDL,
379
+ * Applied only in bare-identifier positions, DDL type/field names, index DDL,
380
380
  * and `insert`/`update`/`upsert` assignment targets. Dotted references
381
381
  * (`.col` in filters/projections/ordering) bypass keyword lookup on every
382
382
  * engine version and deliberately stay bare for ≤0.9 compatibility. Backticks
@@ -505,7 +505,7 @@ export declare function rowToEntity(raw: Record<string, unknown>, meta: TableMet
505
505
  * So we always run the unique-constraint and message-shape checks first (they
506
506
  * fire for both transports and extract detail like constraint / column names),
507
507
  * then classify by the typed wire error class (`.wireErrorClass`, networked
508
- * server >= 0.17 — accurate even when the server sanitized the message text),
508
+ * server >= 0.17, accurate even when the server sanitized the message text),
509
509
  * then fall through to the networked `.code` switch.
510
510
  */
511
511
  export declare function wrapPowdbError(err: unknown): Error;
@@ -587,7 +587,7 @@ export declare class PowdbPool implements PgCompatPool {
587
587
  * Pool-level single-writer gate. PowDB holds one global write lock, so at
588
588
  * most one transaction may be open across the whole pool. Concurrent
589
589
  * `begin`s queue FIFO on the gate (instead of checking out a second
590
- * connection and blocking on the lock forever — the networked hang);
590
+ * connection and blocking on the lock forever, the networked hang);
591
591
  * re-entrant `begin`s throw E017 (see {@link PowdbTxGate}).
592
592
  */
593
593
  private readonly txGate;
@@ -624,7 +624,7 @@ export declare class PowdbPool implements PgCompatPool {
624
624
  /**
625
625
  * Typed guard mirroring {@link PowdbEmbeddedPool}: after `end()` the driver
626
626
  * pool throws a raw `Error('pool closed')` that {@link wrapPowdbError}
627
- * cannot classify — surface the same ConnectionError on both transports.
627
+ * cannot classify, surface the same ConnectionError on both transports.
628
628
  */
629
629
  private assertOpen;
630
630
  connect(): Promise<PgCompatPoolClient>;
@@ -653,7 +653,7 @@ interface EmbeddedDatabase {
653
653
  querySql(sql: string): EmbeddedQueryResult;
654
654
  queryReadonly(powql: string): EmbeddedQueryResult;
655
655
  isPoisoned(): boolean;
656
- /** WAL durability selector — `@zvndev/powdb-embedded` ≥ 0.7.1. */
656
+ /** WAL durability selector, `@zvndev/powdb-embedded` ≥ 0.7.1. */
657
657
  setSyncMode?(mode: string): void;
658
658
  /**
659
659
  * Lossless typed native wire (`@zvndev/powdb-embedded` ≥ 0.14). All optional
@@ -671,7 +671,7 @@ interface EmbeddedDatabase {
671
671
  interface EmbeddedModule {
672
672
  Database: {
673
673
  open(dir: string): EmbeddedDatabase;
674
- /** Open with a per-query memory budget — `@zvndev/powdb-embedded` ≥ 0.7.1. */
674
+ /** Open with a per-query memory budget, `@zvndev/powdb-embedded` ≥ 0.7.1. */
675
675
  openWithMemoryLimit?(dir: string, limitBytes: number): EmbeddedDatabase;
676
676
  /**
677
677
  * Open a read-only handle for snapshot serving (`@zvndev/powdb-embedded` ≥
@@ -684,14 +684,14 @@ interface EmbeddedModule {
684
684
  }
685
685
  /**
686
686
  * Encode a JS value as a **PowQL literal** for the embedded driver, which takes
687
- * no params array — `$N` placeholders must be materialized into the query text.
687
+ * no params array, `$N` placeholders must be materialized into the query text.
688
688
  *
689
689
  * This is the single place Turbine builds PowQL text from a value, so it is the
690
690
  * security-critical surface. String encoding matches PowDB's lexer
691
691
  * (`crates/query/src/lexer.rs`) exactly: a string literal is `"…"`, and inside
692
692
  * it the lexer recognizes only the escapes `\"`, `\\`, `\n`, `\t` (any other
693
- * `\x` drops the backslash and keeps `x`; every non-`\`/non-`"` char — raw
694
- * newlines, CR, unicode — is taken literally). So we escape `\` → `\\` and
693
+ * `\x` drops the backslash and keeps `x`; every non-`\`/non-`"` char, raw
694
+ * newlines, CR, unicode, is taken literally). So we escape `\` → `\\` and
695
695
  * `"` → `\"` (the only breakout vectors), render `\n`/`\t` as their recognized
696
696
  * escapes, and leave everything else raw. Verified against the real engine:
697
697
  * quotes, backslashes, `$N`, `"); drop … --`, raw CR, and emoji all round-trip
@@ -725,13 +725,13 @@ export declare function encodePowqlLiteral(value: unknown, position?: string): s
725
725
  * `git diff v0.19.0 v0.19.1 -- crates/query/src/lexer.rs` is empty (the bare-dotted-path
726
726
  * hard error is parser-level, not tokenization), so this ceiling stays `'0.19'`. The
727
727
  * guard in {@link PowdbEmbeddedPool.exec} compares major.minor only, so `'0.19'`
728
- * already covers every 0.19.x patch — no bump is needed for 0.19.1.
728
+ * already covers every 0.19.x patch, no bump is needed for 0.19.1.
729
729
  */
730
730
  export declare const POWQL_LEXER_TESTED_CEILING = "0.19";
731
731
  /**
732
732
  * Substitute every `$N` placeholder in a generator-produced PowQL template with
733
733
  * the encoded literal of `params[N-1]`. Safe because the template is produced by
734
- * {@link PowqlInterface} and contains **no** user string literals — the only
734
+ * {@link PowqlInterface} and contains **no** user string literals, the only
735
735
  * `$<digits>` tokens are genuine positional placeholders, so a single scan
736
736
  * cannot accidentally rewrite a `$N` that is itself part of a value (values are
737
737
  * params, never inlined into the template by the generator).
@@ -754,7 +754,7 @@ export declare class PowdbEmbeddedPool implements PgCompatPool {
754
754
  private closed;
755
755
  /**
756
756
  * Single-writer gate. The embedded engine is one handle with one global
757
- * write lock — only one transaction may be open at a time. A re-entrant
757
+ * write lock, only one transaction may be open at a time. A re-entrant
758
758
  * `begin` (a fresh top-level `db.$transaction` opened inside an open one's
759
759
  * callback) would otherwise hit PowDB's raw "already in a transaction"
760
760
  * parse error; the gate surfaces a typed E017 instead, while INDEPENDENT
@@ -820,7 +820,7 @@ export interface TurbinePowdbOptions extends Pick<TurbineConfig, 'logging' | 'de
820
820
  * `0` / `Infinity` = wait without limit). Independent concurrent
821
821
  * transactions queue and run one at a time; only a re-entrant
822
822
  * `db.$transaction` (opened inside an active transaction callback) throws
823
- * E017 — queueing that shape would deadlock.
823
+ * E017, queueing that shape would deadlock.
824
824
  *
825
825
  * Ignored when you inject an already-constructed {@link PowdbPool} (it carries
826
826
  * its own {@link PowdbPoolOptions}); set it on that pool's constructor instead.
@@ -876,7 +876,7 @@ export interface TurbinePowdbOptions extends Pick<TurbineConfig, 'logging' | 'de
876
876
  powdbEmbeddedModule?: EmbeddedModule;
877
877
  }
878
878
  /**
879
- * Selects the **embedded** transport — an in-process `@zvndev/powdb-embedded`
879
+ * Selects the **embedded** transport, an in-process `@zvndev/powdb-embedded`
880
880
  * database at the given data directory (no server, no socket). The value is the
881
881
  * data dir path. Preview: Full-durability checkpoint-bound; built binaries ship
882
882
  * for macOS (arm64/x64) and Unix-glibc only (Intel-mac/musl/Windows fall back to
@@ -885,7 +885,7 @@ export interface TurbinePowdbOptions extends Pick<TurbineConfig, 'logging' | 'de
885
885
  * @example
886
886
  * ```ts
887
887
  * const db = await turbinePowDB({ embedded: '/var/data/app.powdb' }, SCHEMA);
888
- * // Faster writes (fsync off the commit path, bounded-loss) — requires addon >= 0.7.1:
888
+ * // Faster writes (fsync off the commit path, bounded-loss), requires addon >= 0.7.1:
889
889
  * const fast = await turbinePowDB({ embedded: '/var/data/app.powdb', syncMode: 'normal' }, SCHEMA);
890
890
  * ```
891
891
  */
@@ -893,7 +893,7 @@ export interface TurbinePowdbEmbeddedTarget {
893
893
  embedded: string;
894
894
  /**
895
895
  * WAL durability for the embedded engine (requires `@zvndev/powdb-embedded` ≥ 0.7.1):
896
- * `'full'` (default — fsync per commit), `'normal'` (fsync off the commit path,
896
+ * `'full'` (default, fsync per commit), `'normal'` (fsync off the commit path,
897
897
  * ~15–40× faster writes, bounded loss on OS crash/power loss), `'off'` (bench-only).
898
898
  */
899
899
  syncMode?: 'full' | 'normal' | 'off';
@@ -919,7 +919,7 @@ export interface TurbinePowdbEmbeddedTarget {
919
919
  * - an `{ embedded: <data-dir> }` object → an in-process
920
920
  * `@zvndev/powdb-embedded` database (no server);
921
921
  * - an already-constructed `@zvndev/powdb-client` `Pool` or {@link PowdbPool}
922
- * (injection — you own its lifecycle and `disconnect()` is a no-op).
922
+ * (injection, you own its lifecycle and `disconnect()` is a no-op).
923
923
  *
924
924
  * On the networked transport the server version is probed and a clear
925
925
  * {@link ConnectionError} is thrown if it is older than {@link MIN_POWDB_VERSION}