turbine-orm 0.76.0 → 0.77.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 (87) hide show
  1. package/dist/cjs/cli/index.js +2 -2
  2. package/dist/cjs/cli/migrate.js +8 -8
  3. package/dist/cjs/cli/studio.js +6 -3
  4. package/dist/cjs/client.js +10 -10
  5. package/dist/cjs/dialect.js +1 -1
  6. package/dist/cjs/errors.d.ts +2 -2
  7. package/dist/cjs/errors.js +21 -25
  8. package/dist/cjs/generate.js +1 -1
  9. package/dist/cjs/introspect.js +5 -5
  10. package/dist/cjs/mssql.js +12 -12
  11. package/dist/cjs/mysql.js +5 -5
  12. package/dist/cjs/nested-write.js +31 -31
  13. package/dist/cjs/observe.js +1 -1
  14. package/dist/cjs/pipeline-submittable.js +5 -1
  15. package/dist/cjs/pipeline.js +8 -0
  16. package/dist/cjs/powdb-introspect.d.ts +1 -1
  17. package/dist/cjs/powdb-introspect.js +4 -4
  18. package/dist/cjs/powdb-shared.d.ts +348 -0
  19. package/dist/cjs/powdb-shared.js +587 -0
  20. package/dist/cjs/powdb.d.ts +12 -299
  21. package/dist/cjs/powdb.js +106 -567
  22. package/dist/cjs/powql.d.ts +1 -1
  23. package/dist/cjs/powql.js +89 -89
  24. package/dist/cjs/prisma-compat.js +16 -16
  25. package/dist/cjs/query/aggregates.js +19 -20
  26. package/dist/cjs/query/batched-loader.js +8 -8
  27. package/dist/cjs/query/builder.js +8 -8
  28. package/dist/cjs/query/compound-unique.js +2 -2
  29. package/dist/cjs/query/filters.js +1 -1
  30. package/dist/cjs/query/relations.js +60 -48
  31. package/dist/cjs/query/types.js +4 -4
  32. package/dist/cjs/query/utils.js +5 -5
  33. package/dist/cjs/query/warn-registry.d.ts +7 -0
  34. package/dist/cjs/query/warn-registry.js +7 -0
  35. package/dist/cjs/query/where-compile.js +1 -1
  36. package/dist/cjs/query/where.js +30 -31
  37. package/dist/cjs/query/writes.js +7 -7
  38. package/dist/cjs/realtime.js +4 -4
  39. package/dist/cjs/schema-metadata.js +1 -1
  40. package/dist/cjs/schema-sql.js +3 -3
  41. package/dist/cjs/seed.js +1 -1
  42. package/dist/cjs/sqlite.js +7 -7
  43. package/dist/cjs/typed-sql.js +1 -1
  44. package/dist/cli/index.js +2 -2
  45. package/dist/cli/migrate.js +8 -8
  46. package/dist/cli/studio.js +6 -3
  47. package/dist/client.js +10 -10
  48. package/dist/dialect.js +1 -1
  49. package/dist/errors.d.ts +2 -2
  50. package/dist/errors.js +21 -25
  51. package/dist/generate.js +1 -1
  52. package/dist/introspect.js +5 -5
  53. package/dist/mssql.js +12 -12
  54. package/dist/mysql.js +5 -5
  55. package/dist/nested-write.js +31 -31
  56. package/dist/observe.js +1 -1
  57. package/dist/pipeline-submittable.js +6 -2
  58. package/dist/pipeline.js +9 -1
  59. package/dist/powdb-introspect.d.ts +1 -1
  60. package/dist/powdb-introspect.js +2 -2
  61. package/dist/powdb-shared.d.ts +348 -0
  62. package/dist/powdb-shared.js +570 -0
  63. package/dist/powdb.d.ts +12 -299
  64. package/dist/powdb.js +71 -534
  65. package/dist/powql.d.ts +1 -1
  66. package/dist/powql.js +43 -43
  67. package/dist/prisma-compat.js +16 -16
  68. package/dist/query/aggregates.js +19 -20
  69. package/dist/query/batched-loader.js +8 -8
  70. package/dist/query/builder.js +8 -8
  71. package/dist/query/compound-unique.js +2 -2
  72. package/dist/query/filters.js +1 -1
  73. package/dist/query/relations.js +60 -48
  74. package/dist/query/types.js +4 -4
  75. package/dist/query/utils.js +5 -5
  76. package/dist/query/warn-registry.d.ts +7 -0
  77. package/dist/query/warn-registry.js +7 -0
  78. package/dist/query/where-compile.js +1 -1
  79. package/dist/query/where.js +30 -31
  80. package/dist/query/writes.js +7 -7
  81. package/dist/realtime.js +4 -4
  82. package/dist/schema-metadata.js +1 -1
  83. package/dist/schema-sql.js +3 -3
  84. package/dist/seed.js +1 -1
  85. package/dist/sqlite.js +7 -7
  86. package/dist/typed-sql.js +1 -1
  87. package/package.json +15 -7
@@ -222,11 +222,11 @@ function keyOf(value) {
222
222
  function validateOps(relationName, ops, isUpdate) {
223
223
  for (const opName of Object.keys(ops)) {
224
224
  if (!CREATE_ONLY_OPS.has(opName) && !UPDATE_ONLY_OPS.has(opName)) {
225
- throw new errors_js_1.ValidationError(`[turbine] Unknown nested write operation "${opName}" on relation "${relationName}". ` +
225
+ throw new errors_js_1.ValidationError(`Unknown nested write operation "${opName}" on relation "${relationName}". ` +
226
226
  `Valid operations: create, connect, connectOrCreate${isUpdate ? ', disconnect, set, delete, update, upsert' : ''}.`);
227
227
  }
228
228
  if (!isUpdate && UPDATE_ONLY_OPS.has(opName)) {
229
- throw new errors_js_1.ValidationError(`[turbine] Operation "${opName}" on relation "${relationName}" is only valid inside update(), not create().`);
229
+ throw new errors_js_1.ValidationError(`Operation "${opName}" on relation "${relationName}" is only valid inside update(), not create().`);
230
230
  }
231
231
  }
232
232
  }
@@ -245,7 +245,7 @@ function pkWhere(tableMeta, row) {
245
245
  // be one this engine just read, so a missing member is an internal fault,
246
246
  // and the only safe response is to refuse rather than to run.
247
247
  if (row[field] === undefined) {
248
- throw new errors_js_1.ValidationError(`[turbine] Cannot address a row of "${tableMeta.name}" by primary key: "${field}" is missing from the ` +
248
+ throw new errors_js_1.ValidationError(`Cannot address a row of "${tableMeta.name}" by primary key: "${field}" is missing from the ` +
249
249
  'row this nested write is operating on, so the generated predicate would match more rows than intended. ' +
250
250
  'This is a bug in turbine, please report it.');
251
251
  }
@@ -347,7 +347,7 @@ function assertTargetSelectsSomething(target, op, relName, rel) {
347
347
  if (target === true) {
348
348
  if (toOne)
349
349
  return;
350
- throw new errors_js_1.ValidationError(`[turbine] Nested ${op} on to-many relation "${relName}" needs a "where" selector: ` +
350
+ throw new errors_js_1.ValidationError(`Nested ${op} on to-many relation "${relName}" needs a "where" selector: ` +
351
351
  `"${op}: true" would ${op} every related "${rel.to}" row.`);
352
352
  }
353
353
  if (target && typeof target === 'object' && !Array.isArray(target)) {
@@ -355,7 +355,7 @@ function assertTargetSelectsSomething(target, op, relName, rel) {
355
355
  if (bound)
356
356
  return;
357
357
  }
358
- throw new errors_js_1.ValidationError(`[turbine] Nested ${op} on relation "${relName}" requires a selector with at least one defined value. ` +
358
+ throw new errors_js_1.ValidationError(`Nested ${op} on relation "${relName}" requires a selector with at least one defined value. ` +
359
359
  `An empty or all-undefined "where" would ${op} every related "${rel.to}" row of this parent.`);
360
360
  }
361
361
  /**
@@ -394,7 +394,7 @@ function junctionAccessorHint(junction) {
394
394
  */
395
395
  function manyToManyOpUnsupported(op, relName, rel) {
396
396
  const junction = rel.through?.table ?? 'junction';
397
- return new errors_js_1.ValidationError(`[turbine] Nested "${op}" is not supported on the many-to-many relation "${relName}" ` +
397
+ return new errors_js_1.ValidationError(`Nested "${op}" is not supported on the many-to-many relation "${relName}" ` +
398
398
  `(via the "${junction}" junction table). The supported many-to-many nested operations are ` +
399
399
  `connect, disconnect and set. To ${op} a "${rel.to}" row itself, write it directly on the ` +
400
400
  `"${rel.to}" table inside the same $transaction and link it with a nested connect; to write ` +
@@ -432,24 +432,24 @@ function junctionPairIsUnique(junctionMeta, sourceCol, targetCol) {
432
432
  function junctionPlan(ctx, rel, relName, parentRow) {
433
433
  const through = rel.through;
434
434
  if (!through) {
435
- throw new errors_js_1.ValidationError(`[turbine] manyToMany relation "${relName}" is missing a \`through\` junction descriptor.`);
435
+ throw new errors_js_1.ValidationError(`manyToMany relation "${relName}" is missing a \`through\` junction descriptor.`);
436
436
  }
437
437
  const junctionMeta = ctx.schema.tables[through.table];
438
438
  if (!junctionMeta) {
439
- throw new errors_js_1.ValidationError(`[turbine] Nested write on the many-to-many relation "${relName}": junction table ` +
439
+ throw new errors_js_1.ValidationError(`Nested write on the many-to-many relation "${relName}": junction table ` +
440
440
  `"${through.table}" is not present in the schema metadata, so its rows cannot be written. ` +
441
441
  `Regenerate the schema (turbine generate) so the junction table is included.`);
442
442
  }
443
443
  const targetMeta = ctx.schema.tables[rel.to];
444
444
  if (!targetMeta) {
445
- throw new errors_js_1.ValidationError(`[turbine] Nested write on the many-to-many relation "${relName}": unknown target table "${rel.to}".`);
445
+ throw new errors_js_1.ValidationError(`Nested write on the many-to-many relation "${relName}": unknown target table "${rel.to}".`);
446
446
  }
447
447
  const sourceKeys = (0, schema_js_1.normalizeKeyColumns)(through.sourceKey);
448
448
  const targetKeys = (0, schema_js_1.normalizeKeyColumns)(through.targetKey);
449
449
  const refKeys = (0, schema_js_1.normalizeKeyColumns)(rel.referenceKey);
450
450
  const targetPk = targetMeta.primaryKey;
451
451
  if (sourceKeys.length !== 1 || targetKeys.length !== 1 || refKeys.length !== 1 || targetPk.length !== 1) {
452
- throw new errors_js_1.ValidationError(`[turbine] Nested writes on the many-to-many relation "${relName}" (via "${through.table}") support ` +
452
+ throw new errors_js_1.ValidationError(`Nested writes on the many-to-many relation "${relName}" (via "${through.table}") support ` +
453
453
  `single-column junction keys only; this relation links on composite keys ` +
454
454
  `(source ${sourceKeys.length}, target ${targetKeys.length}, target primary key ${targetPk.length} column(s)). ` +
455
455
  `Write the junction rows directly inside the same $transaction: ${junctionAccessorHint(through.table)}.`);
@@ -462,7 +462,7 @@ function junctionPlan(ctx, rel, relName, parentRow) {
462
462
  // key at all. Introspection can never produce this (it requires two distinct
463
463
  // FK columns), but a hand-declared `defineSchema` manyToMany can.
464
464
  if (sourceKeys[0] === targetKeys[0]) {
465
- throw new errors_js_1.ValidationError(`[turbine] Nested write on the many-to-many relation "${relName}" cannot run: the junction ` +
465
+ throw new errors_js_1.ValidationError(`Nested write on the many-to-many relation "${relName}" cannot run: the junction ` +
466
466
  `"${through.table}" names the same column "${sourceKeys[0]}" as BOTH its sourceKey and its ` +
467
467
  `targetKey, so a link row cannot hold the parent key and the target key at once. Fix the ` +
468
468
  `relation's \`through\` descriptor to name the two distinct junction columns.`);
@@ -470,7 +470,7 @@ function junctionPlan(ctx, rel, relName, parentRow) {
470
470
  const parentField = ctx.schema.tables[rel.from]?.reverseColumnMap[refKeys[0]] ?? refKeys[0];
471
471
  const parentValue = parentRow[parentField];
472
472
  if (parentValue === null || parentValue === undefined) {
473
- throw new errors_js_1.ValidationError(`[turbine] Nested write on the many-to-many relation "${relName}" cannot run: the parent's reference ` +
473
+ throw new errors_js_1.ValidationError(`Nested write on the many-to-many relation "${relName}" cannot run: the parent's reference ` +
474
474
  `key "${parentField}" is ${parentValue === null ? 'null' : 'missing from the loaded row'}, so no ` +
475
475
  `junction row can be correlated to this parent.`);
476
476
  }
@@ -485,7 +485,7 @@ function junctionPlan(ctx, rel, relName, parentRow) {
485
485
  }
486
486
  /** The E003 for a target selector that matched no row. */
487
487
  function noTargetRow(op, relName, rel, target) {
488
- return new errors_js_1.ValidationError(`[turbine] Nested ${op} on the many-to-many relation "${relName}": no "${rel.to}" row found ` +
488
+ return new errors_js_1.ValidationError(`Nested ${op} on the many-to-many relation "${relName}": no "${rel.to}" row found ` +
489
489
  `matching ${(0, errors_js_1.describeTargetForMessage)(target)}.`);
490
490
  }
491
491
  /**
@@ -544,7 +544,7 @@ async function resolveJunctionTargets(ctx, rel, relName, plan, op, items) {
544
544
  throw noTargetRow(op, relName, rel, target);
545
545
  const value = row[plan.targetKeyField];
546
546
  if (value === null || value === undefined) {
547
- throw new errors_js_1.ValidationError(`[turbine] Nested ${op} on the many-to-many relation "${relName}": the "${rel.to}" row matching ` +
547
+ throw new errors_js_1.ValidationError(`Nested ${op} on the many-to-many relation "${relName}": the "${rel.to}" row matching ` +
548
548
  `${(0, errors_js_1.describeTargetForMessage)(target)} has no "${plan.targetKeyField}" value to link.`);
549
549
  }
550
550
  const key = keyOf(value);
@@ -743,7 +743,7 @@ function notRelatedToParent(op, relName, rel, target) {
743
743
  table: rel.to,
744
744
  where: target,
745
745
  operation: `nested ${op}`,
746
- message: `[turbine] Nested ${op} on relation "${relName}": no "${rel.to}" record matching ` +
746
+ message: `Nested ${op} on relation "${relName}": no "${rel.to}" record matching ` +
747
747
  `${(0, errors_js_1.describeTargetForMessage)(target)} is related to this parent. Either it does not exist, ` +
748
748
  `or it belongs to a different parent (a nested ${op} can only touch this parent's rows).`,
749
749
  });
@@ -777,14 +777,14 @@ async function executeNestedCreate(ctx, tableName, data, depth = 0, path = []) {
777
777
  }
778
778
  const tableMeta = ctx.schema.tables[tableName];
779
779
  if (!tableMeta) {
780
- throw new errors_js_1.ValidationError(`[turbine] Unknown table "${tableName}".`);
780
+ throw new errors_js_1.ValidationError(`Unknown table "${tableName}".`);
781
781
  }
782
782
  const { scalars, relations } = extractRelationFields(data, tableMeta);
783
783
  // Validate all relation operations
784
784
  for (const [relName, ops] of Object.entries(relations)) {
785
785
  const rel = tableMeta.relations[relName];
786
786
  if (!rel) {
787
- throw new errors_js_1.RelationError(`[turbine] Unknown relation "${relName}" on table "${tableName}". ` +
787
+ throw new errors_js_1.RelationError(`Unknown relation "${relName}" on table "${tableName}". ` +
788
788
  `Available relations: ${Object.keys(tableMeta.relations).join(', ') || '(none)'}.`);
789
789
  }
790
790
  validateOps(relName, ops, false);
@@ -856,14 +856,14 @@ async function executeNestedUpdate(ctx, tableName, where, data, depth = 0, path
856
856
  }
857
857
  const tableMeta = ctx.schema.tables[tableName];
858
858
  if (!tableMeta) {
859
- throw new errors_js_1.ValidationError(`[turbine] Unknown table "${tableName}".`);
859
+ throw new errors_js_1.ValidationError(`Unknown table "${tableName}".`);
860
860
  }
861
861
  const { scalars, relations } = extractRelationFields(data, tableMeta);
862
862
  // Validate all relation operations
863
863
  for (const [relName, ops] of Object.entries(relations)) {
864
864
  const rel = tableMeta.relations[relName];
865
865
  if (!rel) {
866
- throw new errors_js_1.RelationError(`[turbine] Unknown relation "${relName}" on table "${tableName}". ` +
866
+ throw new errors_js_1.RelationError(`Unknown relation "${relName}" on table "${tableName}". ` +
867
867
  `Available relations: ${Object.keys(tableMeta.relations).join(', ') || '(none)'}.`);
868
868
  }
869
869
  validateOps(relName, ops, true);
@@ -876,7 +876,7 @@ async function executeNestedUpdate(ctx, tableName, where, data, depth = 0, path
876
876
  else {
877
877
  parentRow = (await ctx.tx.table(tableName).findUnique({ where }));
878
878
  if (!parentRow) {
879
- throw new errors_js_1.ValidationError(`[turbine] update: no ${tableName} row found matching ${(0, errors_js_1.describeTargetForMessage)(where)}.`);
879
+ throw new errors_js_1.ValidationError(`update: no ${tableName} row found matching ${(0, errors_js_1.describeTargetForMessage)(where)}.`);
880
880
  }
881
881
  }
882
882
  // Process each relation
@@ -924,7 +924,7 @@ async function executeNestedUpdate(ctx, tableName, where, data, depth = 0, path
924
924
  return col?.nullable ?? false;
925
925
  });
926
926
  if (!nullable) {
927
- throw new errors_js_1.ValidationError(`[turbine] Cannot disconnect "${relName}": foreign key column(s) ${fks.join(', ')} are NOT NULL. Use delete instead.`);
927
+ throw new errors_js_1.ValidationError(`Cannot disconnect "${relName}": foreign key column(s) ${fks.join(', ')} are NOT NULL. Use delete instead.`);
928
928
  }
929
929
  const updateData = {};
930
930
  for (const fk of fks) {
@@ -1033,7 +1033,7 @@ async function resolveBelongsToForCreate(ctx, rel, ops, parentTable, depth, path
1033
1033
  const target = items[0];
1034
1034
  relatedRow = (await ctx.tx.table(rel.to).findUnique({ where: target }));
1035
1035
  if (!relatedRow) {
1036
- throw new errors_js_1.ValidationError(`[turbine] connect on "${relName}": no ${rel.to} row found matching ${(0, errors_js_1.describeTargetForMessage)(target)}.`);
1036
+ throw new errors_js_1.ValidationError(`connect on "${relName}": no ${rel.to} row found matching ${(0, errors_js_1.describeTargetForMessage)(target)}.`);
1037
1037
  }
1038
1038
  }
1039
1039
  }
@@ -1088,7 +1088,7 @@ async function processBelongsToCreate(ctx, rel, ops, parentRow, parentTable, dep
1088
1088
  const target = items[0];
1089
1089
  const existing = await ctx.tx.table(rel.to).findUnique({ where: target });
1090
1090
  if (!existing) {
1091
- throw new errors_js_1.ValidationError(`[turbine] connect on "${relName}": no ${rel.to} row found matching ${(0, errors_js_1.describeTargetForMessage)(target)}.`);
1091
+ throw new errors_js_1.ValidationError(`connect on "${relName}": no ${rel.to} row found matching ${(0, errors_js_1.describeTargetForMessage)(target)}.`);
1092
1092
  }
1093
1093
  const updateData = {};
1094
1094
  const relatedTable = ctx.schema.tables[rel.to];
@@ -1138,7 +1138,7 @@ function assertConnectInScope(ctx, rel, child, parentRow, target) {
1138
1138
  continue;
1139
1139
  if (current === key(parentRow[refField]))
1140
1140
  continue;
1141
- throw new errors_js_1.ValidationError(`[turbine] connect refused: ${rel.to} row ${(0, errors_js_1.describeTargetForMessage)(target)} is already owned by ` +
1141
+ throw new errors_js_1.ValidationError(`connect refused: ${rel.to} row ${(0, errors_js_1.describeTargetForMessage)(target)} is already owned by ` +
1142
1142
  `another "${rel.from}" (its ${fks[i]} is ${current}). \`scopedConnect\` only allows connecting a row ` +
1143
1143
  `that is unowned or already owned by this parent; re-parenting must be an explicit update.`);
1144
1144
  }
@@ -1153,7 +1153,7 @@ async function batchConnect(ctx, rel, items, parentRow) {
1153
1153
  for (const target of items) {
1154
1154
  const existing = await ctx.tx.table(rel.to).findUnique({ where: target });
1155
1155
  if (!existing) {
1156
- throw new errors_js_1.ValidationError(`[turbine] connect: no ${rel.to} row found matching ${(0, errors_js_1.describeTargetForMessage)(target)}.`);
1156
+ throw new errors_js_1.ValidationError(`connect: no ${rel.to} row found matching ${(0, errors_js_1.describeTargetForMessage)(target)}.`);
1157
1157
  }
1158
1158
  assertConnectInScope(ctx, rel, existing, parentRow, target);
1159
1159
  }
@@ -1205,7 +1205,7 @@ async function processDisconnect(ctx, rel, disconnectArg, relName, parentRow) {
1205
1205
  return col?.nullable ?? false;
1206
1206
  });
1207
1207
  if (!nullable) {
1208
- throw new errors_js_1.ValidationError(`[turbine] Cannot disconnect "${relName}": foreign key column(s) ${fks.join(', ')} on "${rel.to}" are NOT NULL. Use delete instead.`);
1208
+ throw new errors_js_1.ValidationError(`Cannot disconnect "${relName}": foreign key column(s) ${fks.join(', ')} on "${rel.to}" are NOT NULL. Use delete instead.`);
1209
1209
  }
1210
1210
  const items = toArray(disconnectArg);
1211
1211
  if (items.length === 0)
@@ -1248,7 +1248,7 @@ async function processSet(ctx, rel, setItems, parentRow) {
1248
1248
  const refField = ctx.schema.tables[rel.from]?.reverseColumnMap[refs[i]] ?? refs[i];
1249
1249
  const value = parentRow[refField];
1250
1250
  if (value === null || value === undefined) {
1251
- throw new errors_js_1.ValidationError(`[turbine] Nested set on relation "${rel.name}" cannot run: the parent's reference key ` +
1251
+ throw new errors_js_1.ValidationError(`Nested set on relation "${rel.name}" cannot run: the parent's reference key ` +
1252
1252
  `"${refField}" is ${value === null ? 'null' : 'missing from the loaded row'}, so no child rows ` +
1253
1253
  `can be correlated to this parent.`);
1254
1254
  }
@@ -1286,7 +1286,7 @@ async function processNestedUpdate(ctx, rel, updateArg, relName, parentRow) {
1286
1286
  const correlation = parentCorrelationWhere(ctx, rel, parentRow);
1287
1287
  for (const item of items) {
1288
1288
  if (!item.where || !item.data) {
1289
- throw new errors_js_1.ValidationError(`[turbine] Nested update on "${rel.name}" requires both "where" and "data" fields.`);
1289
+ throw new errors_js_1.ValidationError(`Nested update on "${rel.name}" requires both "where" and "data" fields.`);
1290
1290
  }
1291
1291
  assertTargetSelectsSomething(item.where, 'update', relName, rel);
1292
1292
  if (!correlation)
@@ -1310,7 +1310,7 @@ async function processNestedUpsert(ctx, rel, upsertArg, parentRow, relName) {
1310
1310
  const correlation = parentCorrelationWhere(ctx, rel, parentRow);
1311
1311
  for (const item of items) {
1312
1312
  if (!item.where || !item.create || !item.update) {
1313
- throw new errors_js_1.ValidationError(`[turbine] Nested upsert on "${rel.name}" requires "where", "create", and "update" fields.`);
1313
+ throw new errors_js_1.ValidationError(`Nested upsert on "${rel.name}" requires "where", "create", and "update" fields.`);
1314
1314
  }
1315
1315
  assertTargetSelectsSomething(item.where, 'upsert', relName, rel);
1316
1316
  const scoped = correlation ? scopeWhereToParent(item.where, correlation) : null;
@@ -1332,7 +1332,7 @@ async function processNestedUpsert(ctx, rel, upsertArg, parentRow, relName) {
1332
1332
  async function processBelongsToUpdate(ctx, rel, updateArg, parentRow, parentTable) {
1333
1333
  const item = updateArg;
1334
1334
  if (!item.data) {
1335
- throw new errors_js_1.ValidationError(`[turbine] Nested update on belongsTo "${rel.name}" requires a "data" field.`);
1335
+ throw new errors_js_1.ValidationError(`Nested update on belongsTo "${rel.name}" requires a "data" field.`);
1336
1336
  }
1337
1337
  // The related row is the one this parent's FK points at. Route through the
1338
1338
  // shared correlation helper (like every sibling operation) so a NULL parent
@@ -1354,7 +1354,7 @@ async function processBelongsToUpdate(ctx, rel, updateArg, parentRow, parentTabl
1354
1354
  async function processBelongsToUpsert(ctx, rel, upsertArg, parentRow, parentTable) {
1355
1355
  const item = upsertArg;
1356
1356
  if (!item.where || !item.create || !item.update) {
1357
- throw new errors_js_1.ValidationError(`[turbine] Nested upsert on belongsTo "${rel.name}" requires "where", "create", and "update" fields.`);
1357
+ throw new errors_js_1.ValidationError(`Nested upsert on belongsTo "${rel.name}" requires "where", "create", and "update" fields.`);
1358
1358
  }
1359
1359
  // Scope the lookup to the row this parent actually points at. Without the
1360
1360
  // correlation, a `where` naming any other row would update a record with no
@@ -164,7 +164,7 @@ class ObserveEngine {
164
164
  stopped = false;
165
165
  constructor(config) {
166
166
  if (!config.sink && !config.connectionString) {
167
- throw new errors_js_1.ValidationError('[turbine] ObserveEngine: neither `connectionString` nor `sink` was provided, so there is nowhere to ' +
167
+ throw new errors_js_1.ValidationError('ObserveEngine: neither `connectionString` nor `sink` was provided, so there is nowhere to ' +
168
168
  'flush metrics. Pass `connectionString` (a separate metrics database URL, often TURBINE_OBSERVE_URL) ' +
169
169
  'or a custom `sink` implementing ObserveSink.');
170
170
  }
@@ -318,7 +318,11 @@ async function runPipelined(client, queries, options = {}) {
318
318
  // -----------------------------------------------------------------------
319
319
  if (timeout && timeout > 0) {
320
320
  timeoutHandle = setTimeout(() => {
321
- pipelineError = new Error(`[turbine] Pipeline timed out after ${timeout}ms`);
321
+ // TimeoutError (E002), matching $transaction({ timeout }). A bare Error
322
+ // here meant `pipeline({ timeout })` rejected with no .code, no
323
+ // .docsUrl, and failing `instanceof TurbineError`, so the two timeout
324
+ // paths in the same client disagreed about their own contract.
325
+ pipelineError = new errors_js_1.TimeoutError(timeout, 'Pipeline');
322
326
  if (connection.stream.destroy) {
323
327
  connection.stream.destroy(pipelineError);
324
328
  }
@@ -222,6 +222,14 @@ async function executePipeline(pool, queries, options) {
222
222
  // keywords rather than Postgres's.
223
223
  return await runSequential(client, queries, poolDialect(pool), options);
224
224
  }
225
+ catch (err) {
226
+ // Already-typed Turbine errors pass through untouched; anything else is a
227
+ // driver error that must not escape with a SQLSTATE sitting in the same
228
+ // `.code` slot Turbine puts TURBINE_E0NN in.
229
+ if (err instanceof errors_js_1.TurbineError)
230
+ throw err;
231
+ throw (0, errors_js_1.wrapPgError)(err);
232
+ }
225
233
  finally {
226
234
  client.release();
227
235
  }
@@ -62,7 +62,7 @@
62
62
  * wired to a networked `exec`, and `cli/config.ts` teaching the generate
63
63
  * funnel to construct a PowDB client instead of a `pg` client for `powdb://`.
64
64
  */
65
- import { type PowdbCapabilities } from './powdb.js';
65
+ import { type PowdbCapabilities } from './powdb-shared.js';
66
66
  import type { SchemaMetadata } from './schema.js';
67
67
  /** A minimal rows-returning executor over a PowDB connection (embedded or networked). */
68
68
  export type PowdbExec = (powql: string) => Promise<{
@@ -67,7 +67,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
67
67
  exports.introspectPowdbDatabase = introspectPowdbDatabase;
68
68
  const errors_js_1 = require("./errors.js");
69
69
  const introspect_js_1 = require("./introspect.js");
70
- const powdb_js_1 = require("./powdb.js");
70
+ const powdb_shared_js_1 = require("./powdb-shared.js");
71
71
  const schema_js_1 = require("./schema.js");
72
72
  /** Coerce a wire cell to string (legacy wire cells are strings; native cells may be typed). */
73
73
  function asString(v) {
@@ -116,7 +116,7 @@ async function introspectPowdbDatabase(exec, options = {}) {
116
116
  // knows the version, so a pre-0.10 engine gets a typed E017 hint instead of
117
117
  // an opaque `unexpected token schema` parse error.
118
118
  if (options.capabilities) {
119
- (0, powdb_js_1.requireCapability)(options.capabilities, 'introspection', 'PowDB `describe` introspection');
119
+ (0, powdb_shared_js_1.requireCapability)(options.capabilities, 'introspection', 'PowDB `describe` introspection');
120
120
  }
121
121
  // ----- Types (one row per table, columns `name`, `columns`) -----
122
122
  const schemaRows = (await exec('schema')).rows;
@@ -126,7 +126,7 @@ async function introspectPowdbDatabase(exec, options = {}) {
126
126
  // every table filters out and the schema comes back silently empty. Refuse
127
127
  // that instead of losing data: real rows must carry a `name`.
128
128
  if (schemaRows.length > 0 && candidateTables.length === 0) {
129
- throw new errors_js_1.ValidationError(`[turbine] PowDB introspection: the \`schema\` statement returned ${schemaRows.length} row(s) but none carried a ` +
129
+ throw new errors_js_1.ValidationError(`PowDB introspection: the \`schema\` statement returned ${schemaRows.length} row(s) but none carried a ` +
130
130
  '`name` cell. The `exec` you supplied likely returns POSITIONAL rows (string[][]) rather than records keyed by ' +
131
131
  'column name; zip `columns` with each row (see introspectPowdbDatabase docs).');
132
132
  }
@@ -137,7 +137,7 @@ async function introspectPowdbDatabase(exec, options = {}) {
137
137
  // `describe` needs the table name in bare-identifier position → quote it so
138
138
  // a reserved-word / non-bare table name (`order`) does not become a parse
139
139
  // error.
140
- const describeRows = (await exec(`describe ${(0, powdb_js_1.quotePowqlIdent)(tableName)}`)).rows
140
+ const describeRows = (await exec(`describe ${(0, powdb_shared_js_1.quotePowqlIdent)(tableName)}`)).rows
141
141
  // PowDB >= 0.19.1 appends entity-LINK rows after the 4 column rows in
142
142
  // `describe <T>` (a `type` cell of literally `"link"`, an Empty nullable
143
143
  // slot, and an arrow description in the index slot). They are NOT columns,