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
@@ -192,8 +192,7 @@ function resolveProjection(qi, table, meta, select, omit, includePii) {
192
192
  // numeric indices and throw a cryptic `Unknown field "0"`, catch it early
193
193
  // with an actionable message.
194
194
  if (Array.isArray(select)) {
195
- throw new errors_js_1.ValidationError(`[turbine] "select" must be an object mapping field names to true ` +
196
- `(e.g. { id: true, name: true }), not an array.`);
195
+ throw new errors_js_1.ValidationError(`"select" must be an object mapping field names to true ` + `(e.g. { id: true, name: true }), not an array.`);
197
196
  }
198
197
  // Only include columns where value is true. An explicit `select` naming a
199
198
  // PII column IS the opt-in: it comes back regardless of `includePii`.
@@ -235,7 +234,7 @@ function resolveProjection(qi, table, meta, select, omit, includePii) {
235
234
  const hasPii = piiCols !== undefined && piiCols.size > 0;
236
235
  if (omit) {
237
236
  if (Array.isArray(omit)) {
238
- throw new errors_js_1.ValidationError(`[turbine] "omit" must be an object mapping field names to true ` + `(e.g. { createdAt: true }), not an array.`);
237
+ throw new errors_js_1.ValidationError(`"omit" must be an object mapping field names to true ` + `(e.g. { createdAt: true }), not an array.`);
239
238
  }
240
239
  // Include all columns except those where value is true (and PII columns).
241
240
  const omitCols = new Set(Object.entries(omit)
@@ -586,7 +585,7 @@ function buildOrderBy(qi, orderBy, params, lateralSink) {
586
585
  if (meta)
587
586
  resolveOrderByColumn(qi, qi.table, meta, key);
588
587
  if (!params) {
589
- throw new errors_js_1.ValidationError(`[turbine] Vector distance ordering on "${key}" is only supported in a top-level findMany orderBy.`);
588
+ throw new errors_js_1.ValidationError(`Vector distance ordering on "${key}" is only supported in a top-level findMany orderBy.`);
590
589
  }
591
590
  const rawColumn = qi.toColumn(key);
592
591
  const operator = whereMod.vectorOperator(qi, key, rawColumn, value.distance.metric);
@@ -666,7 +665,7 @@ function nullsSuffix(qi, nulls) {
666
665
  function resolveOrderByColumn(_qi, table, meta, key) {
667
666
  const col = (0, utils_js_1.resolveColumnName)(meta, key);
668
667
  if (col === undefined) {
669
- throw new errors_js_1.ValidationError(`[turbine] Unknown field "${key}" in orderBy on table "${table}". ` +
668
+ throw new errors_js_1.ValidationError(`Unknown field "${key}" in orderBy on table "${table}". ` +
670
669
  `Known fields: ${Object.keys(meta.columnMap).join(', ') || '(none)'}.`);
671
670
  }
672
671
  return col;
@@ -682,12 +681,12 @@ function validateJsonPathOrderBy(qi, table, meta, field, spec) {
682
681
  const col = resolveOrderByColumn(qi, table, meta, field);
683
682
  if (spec.path.length === 0 ||
684
683
  spec.path.some((el) => typeof el !== 'string' && !(typeof el === 'number' && Number.isFinite(el)))) {
685
- throw new errors_js_1.ValidationError(`[turbine] JSON-path orderBy on "${field}" (table "${table}") requires a non-empty \`path\` array ` +
684
+ throw new errors_js_1.ValidationError(`JSON-path orderBy on "${field}" (table "${table}") requires a non-empty \`path\` array ` +
686
685
  `of keys/indexes (e.g. { path: ['weight'], direction: 'asc' }).`);
687
686
  }
688
687
  const colType = whereMod.pgTypeForColumn(qi, meta, col);
689
688
  if (!whereMod.isJsonColumnType(qi, colType)) {
690
- throw new errors_js_1.ValidationError(`[turbine] JSON-path orderBy on "${field}": column "${col}" on table "${table}" is not a JSON column ` +
689
+ throw new errors_js_1.ValidationError(`JSON-path orderBy on "${field}": column "${col}" on table "${table}" is not a JSON column ` +
691
690
  `(actual type: ${colType}).`);
692
691
  }
693
692
  return col;
@@ -704,7 +703,7 @@ function validateJsonPathOrderBy(qi, table, meta, field, spec) {
704
703
  function buildJsonPathOrderEntry(qi, table, meta, field, spec, prefix, params) {
705
704
  const col = validateJsonPathOrderBy(qi, table, meta, field, spec);
706
705
  if (!params) {
707
- throw new errors_js_1.ValidationError(`[turbine] JSON-path ordering on "${field}" is not supported in this orderBy context.`);
706
+ throw new errors_js_1.ValidationError(`JSON-path ordering on "${field}" is not supported in this orderBy context.`);
708
707
  }
709
708
  params.push(whereMod.jsonPathParam(qi, spec.path));
710
709
  const extract = qi.dialect.buildJsonPathExtract(`${prefix}${qi.q(col)}`, qi.p(params.length));
@@ -756,14 +755,14 @@ function buildChainedToOneOrderBy(qi, head, nextRelName, nextValue, params) {
756
755
  // relation object. Bounded by the same depth cap as nested `with`.
757
756
  for (;;) {
758
757
  if (!currentMeta)
759
- throw new errors_js_1.RelationError(`[turbine] Unknown relation target in orderBy chain "${path.join('.')}"`);
758
+ throw new errors_js_1.RelationError(`Unknown relation target in orderBy chain "${path.join('.')}"`);
760
759
  const relDef = (0, utils_js_1.ownLookup)(currentMeta.relations, relName);
761
760
  if (!relDef) {
762
- throw new errors_js_1.ValidationError(`[turbine] Unknown relation "${relName}" in orderBy on relation "${path.join('.')}" ` +
761
+ throw new errors_js_1.ValidationError(`Unknown relation "${relName}" in orderBy on relation "${path.join('.')}" ` +
763
762
  `(table "${currentMeta.name}"). Available: ${Object.keys(currentMeta.relations).join(', ') || '(none)'}.`);
764
763
  }
765
764
  if (relDef.type !== 'belongsTo' && relDef.type !== 'hasOne') {
766
- throw new errors_js_1.ValidationError(`[turbine] orderBy cannot traverse the to-many relation "${relName}" on "${currentMeta.name}" ` +
765
+ throw new errors_js_1.ValidationError(`orderBy cannot traverse the to-many relation "${relName}" on "${currentMeta.name}" ` +
767
766
  `(path "${path.concat(relName).join('.')}"): a to-many relation has no single value to order by. ` +
768
767
  `Use a pick-row ordering ({ pick, by }) at the top level, or order by "_count".`);
769
768
  }
@@ -772,7 +771,7 @@ function buildChainedToOneOrderBy(qi, head, nextRelName, nextValue, params) {
772
771
  }
773
772
  const nextMeta = qi.schema.tables[relDef.to];
774
773
  if (!nextMeta)
775
- throw new errors_js_1.RelationError(`[turbine] Unknown relation target "${relDef.to}" in orderBy`);
774
+ throw new errors_js_1.RelationError(`Unknown relation target "${relDef.to}" in orderBy`);
776
775
  const nextAlias = `${head.alias}c${hop}`;
777
776
  const on = relDef.type === 'belongsTo'
778
777
  ? qi.dialect.buildCorrelation(nextAlias, relDef.referenceKey, currentAlias, relDef.foreignKey)
@@ -790,7 +789,7 @@ function buildChainedToOneOrderBy(qi, head, nextRelName, nextValue, params) {
790
789
  // Exactly one key per level, as with the single-hop form.
791
790
  const entries = Object.entries(value);
792
791
  if (entries.length !== 1) {
793
- throw new errors_js_1.ValidationError(`[turbine] orderBy on relation "${path.join('.')}" needs exactly one key per level ` +
792
+ throw new errors_js_1.ValidationError(`orderBy on relation "${path.join('.')}" needs exactly one key per level ` +
794
793
  `(got: ${entries.map(([k]) => k).join(', ') || '(empty)'}).`);
795
794
  }
796
795
  const [key, entryValue] = entries[0];
@@ -806,7 +805,7 @@ function buildChainedToOneOrderBy(qi, head, nextRelName, nextValue, params) {
806
805
  // Terminal: a column on the last table in the chain.
807
806
  const snakeCol = (0, utils_js_1.resolveColumnName)(currentMeta, key);
808
807
  if (snakeCol === undefined) {
809
- throw new errors_js_1.ValidationError(`[turbine] Unknown column "${key}" in orderBy on relation "${path.join('.')}" (table "${currentMeta.name}").`);
808
+ throw new errors_js_1.ValidationError(`Unknown column "${key}" in orderBy on relation "${path.join('.')}" (table "${currentMeta.name}").`);
810
809
  }
811
810
  (0, types_js_1.assertOrderDirection)(entryValue, `orderBy on relation path "${path.join('.')}"`);
812
811
  const { dir, nulls } = (0, filters_js_1.normalizeOrderBy)(entryValue);
@@ -854,9 +853,9 @@ function buildRelationOrderBy(qi, relName, value, alias, params, ctx, lateralSin
854
853
  // missing relation.
855
854
  const isColumn = (0, utils_js_1.resolveColumnName)(ownerMeta, relName) !== undefined;
856
855
  throw new errors_js_1.RelationError(isColumn
857
- ? `[turbine] orderBy on "${ownerTable}.${relName}" got a relation-shaped value, but "${relName}" is a ` +
856
+ ? `orderBy on "${ownerTable}.${relName}" got a relation-shaped value, but "${relName}" is a ` +
858
857
  `column. Order a column with 'asc' / 'desc' (or { sort, nulls }); the object form is for relations.`
859
- : `[turbine] Unknown relation "${relName}" in orderBy on table "${ownerTable}". ` +
858
+ : `Unknown relation "${relName}" in orderBy on table "${ownerTable}". ` +
860
859
  (0, utils_js_1.availableClause)(Object.keys(ownerMeta.relations), `"${ownerTable}" has no relations.`));
861
860
  }
862
861
  // Pick-row ordering (`{ pick, by }`): order by a value from ONE related
@@ -872,7 +871,7 @@ function buildRelationOrderBy(qi, relName, value, alias, params, ctx, lateralSin
872
871
  if (relDef.type === 'hasMany' || relDef.type === 'manyToMany') {
873
872
  const keys = Object.keys(value);
874
873
  if (keys.length !== 1 || keys[0] !== '_count') {
875
- throw new errors_js_1.ValidationError(`[turbine] orderBy on to-many relation "${relName}" only supports "_count" ` +
874
+ throw new errors_js_1.ValidationError(`orderBy on to-many relation "${relName}" only supports "_count" ` +
876
875
  `or a pick-row ordering ({ pick, by }) (got: ${keys.join(', ') || '(empty)'}).`);
877
876
  }
878
877
  (0, types_js_1.assertOrderDirection)(value._count, `orderBy { ${relName}: { _count } }`);
@@ -882,7 +881,7 @@ function buildRelationOrderBy(qi, relName, value, alias, params, ctx, lateralSin
882
881
  // To-one: each entry orders by a correlated scalar subquery on a target column.
883
882
  const targetMeta = qi.schema.tables[relDef.to];
884
883
  if (!targetMeta)
885
- throw new errors_js_1.RelationError(`[turbine] Unknown relation target "${relDef.to}"`);
884
+ throw new errors_js_1.RelationError(`Unknown relation target "${relDef.to}"`);
886
885
  const qTarget = qi.q(relDef.to);
887
886
  const qParent = qi.q(parentRef);
888
887
  // belongsTo: alias.referenceKey = parent.foreignKey; hasOne: reversed.
@@ -891,7 +890,7 @@ function buildRelationOrderBy(qi, relName, value, alias, params, ctx, lateralSin
891
890
  : qi.dialect.buildCorrelation(alias, relDef.foreignKey, qParent, relDef.referenceKey);
892
891
  const entries = Object.entries(value);
893
892
  if (entries.length === 0) {
894
- throw new errors_js_1.ValidationError(`[turbine] orderBy on to-one relation "${relName}" needs at least one target column.`);
893
+ throw new errors_js_1.ValidationError(`orderBy on to-one relation "${relName}" needs at least one target column.`);
895
894
  }
896
895
  return entries
897
896
  .map(([col, dirValue]) => {
@@ -911,7 +910,7 @@ function buildRelationOrderBy(qi, relName, value, alias, params, ctx, lateralSin
911
910
  ? ` "${col}" is a relation on "${relDef.to}": order by one of ITS columns, e.g. ` +
912
911
  `{ ${relName}: { ${col}: { <column>: 'asc' } } }.`
913
912
  : '';
914
- throw new errors_js_1.ValidationError(`[turbine] Unknown column "${col}" in orderBy on relation "${relName}" (table "${relDef.to}").${relationHint}`);
913
+ throw new errors_js_1.ValidationError(`Unknown column "${col}" in orderBy on relation "${relName}" (table "${relDef.to}").${relationHint}`);
915
914
  }
916
915
  (0, types_js_1.assertOrderDirection)(dirValue, `orderBy "${col}" on relation "${relName}"`);
917
916
  const { dir, nulls } = (0, filters_js_1.normalizeOrderBy)(dirValue);
@@ -942,7 +941,7 @@ function buildRelationOrderBy(qi, relName, value, alias, params, ctx, lateralSin
942
941
  * - `by` must be a target column name or a `{ field, path }` JSON-path spec.
943
942
  */
944
943
  function pickOrderNestedError(_qi, relName) {
945
- return new errors_js_1.ValidationError(`[turbine] Pick-row ordering on relation "${relName}" is only supported in a top-level ` +
944
+ return new errors_js_1.ValidationError(`Pick-row ordering on relation "${relName}" is only supported in a top-level ` +
946
945
  'findMany orderBy: nested `with` orderBy does not support it.');
947
946
  }
948
947
  function validatePickOrderBy(qi, relName, relDef, spec, nested) {
@@ -950,10 +949,10 @@ function validatePickOrderBy(qi, relName, relDef, spec, nested) {
950
949
  throw pickOrderNestedError(qi, relName);
951
950
  }
952
951
  if (relDef.type === 'manyToMany') {
953
- throw new errors_js_1.ValidationError(`[turbine] Pick-row ordering is not supported on manyToMany relation "${relName}": hasMany relations only.`);
952
+ throw new errors_js_1.ValidationError(`Pick-row ordering is not supported on manyToMany relation "${relName}": hasMany relations only.`);
954
953
  }
955
954
  if (relDef.type !== 'hasMany') {
956
- throw new errors_js_1.ValidationError(`[turbine] Pick-row ordering is only for to-many (hasMany) relations; "${relName}" is ${relDef.type}. ` +
955
+ throw new errors_js_1.ValidationError(`Pick-row ordering is only for to-many (hasMany) relations; "${relName}" is ${relDef.type}. ` +
957
956
  `Order by the target column directly instead ({ ${relName}: { <column>: 'asc' } }).`);
958
957
  }
959
958
  const pickOrder = spec.pick?.orderBy;
@@ -962,20 +961,20 @@ function validatePickOrderBy(qi, relName, relDef, spec, nested) {
962
961
  typeof pickOrder !== 'object' ||
963
962
  pickOrder === null ||
964
963
  Object.keys(pickOrder).length === 0) {
965
- throw new errors_js_1.ValidationError(`[turbine] Pick-row ordering on relation "${relName}" requires \`pick.orderBy\` to choose ONE ` +
964
+ throw new errors_js_1.ValidationError(`Pick-row ordering on relation "${relName}" requires \`pick.orderBy\` to choose ONE ` +
966
965
  "related row deterministically (e.g. pick: { orderBy: { createdAt: 'desc' } }).");
967
966
  }
968
967
  const by = spec.by;
969
968
  const validJsonBy = typeof by === 'object' && by !== null && typeof by.field === 'string' && Array.isArray(by.path);
970
969
  if (typeof by !== 'string' && !validJsonBy) {
971
- throw new errors_js_1.ValidationError(`[turbine] Pick-row ordering on relation "${relName}" requires \`by\`: a target column name ` +
970
+ throw new errors_js_1.ValidationError(`Pick-row ordering on relation "${relName}" requires \`by\`: a target column name ` +
972
971
  "or a JSON-path spec ({ field: 'data', path: ['title'] }).");
973
972
  }
974
973
  // Physical plan gate. A typo like `plan: 'latreal'` must never silently run
975
974
  // the subquery plan (a silent plan change wearing a validation gap). Shared
976
975
  // by build and cache-hit collect so a warmed cache throws identically.
977
976
  if (spec.plan !== undefined && spec.plan !== 'subquery' && spec.plan !== 'lateral') {
978
- throw new errors_js_1.ValidationError(`[turbine] Pick-row ordering on relation "${relName}" has an invalid \`plan\`: ` +
977
+ throw new errors_js_1.ValidationError(`Pick-row ordering on relation "${relName}" has an invalid \`plan\`: ` +
979
978
  `${JSON.stringify(spec.plan)}. Use 'subquery' (default) or 'lateral'.`);
980
979
  }
981
980
  if (spec.plan === 'lateral') {
@@ -986,7 +985,7 @@ function validatePickOrderBy(qi, relName, relDef, spec, nested) {
986
985
  // parent column with that exact name would make the unqualified WHERE
987
986
  // reference ambiguous once the join is in scope; refuse it explicitly.
988
987
  if (qi.tableMeta.allColumns.includes('__turbine_pick')) {
989
- throw new errors_js_1.ValidationError(`[turbine] Pick-row ordering with plan: 'lateral' cannot be used: table "${qi.tableMeta.name}" ` +
988
+ throw new errors_js_1.ValidationError(`Pick-row ordering with plan: 'lateral' cannot be used: table "${qi.tableMeta.name}" ` +
990
989
  'has a column named "__turbine_pick", which the lateral join output reserves.');
991
990
  }
992
991
  }
@@ -1010,11 +1009,11 @@ function validatePickOrderBy(qi, relName, relDef, spec, nested) {
1010
1009
  */
1011
1010
  function buildRelationPickOrderBy(qi, relName, relDef, spec, alias, parentRef, params, lateralSink) {
1012
1011
  if (!params) {
1013
- throw new errors_js_1.ValidationError(`[turbine] Pick-row ordering on relation "${relName}" is only supported in a top-level findMany orderBy.`);
1012
+ throw new errors_js_1.ValidationError(`Pick-row ordering on relation "${relName}" is only supported in a top-level findMany orderBy.`);
1014
1013
  }
1015
1014
  const targetMeta = qi.schema.tables[relDef.to];
1016
1015
  if (!targetMeta)
1017
- throw new errors_js_1.RelationError(`[turbine] Unknown relation target "${relDef.to}"`);
1016
+ throw new errors_js_1.RelationError(`Unknown relation target "${relDef.to}"`);
1018
1017
  (0, types_js_1.assertDirectionToken)(spec.direction, `pick-row orderBy on relation "${relName}"`);
1019
1018
  const dir = spec.direction?.toLowerCase() === 'desc' ? 'DESC' : 'ASC';
1020
1019
  const limitOne = qi.buildPagination('1', undefined, true);
@@ -1039,7 +1038,7 @@ function buildRelationPickOrderBy(qi, relName, relDef, spec, alias, parentRef, p
1039
1038
  // context and hard-fails rather than silently emitting a subquery.
1040
1039
  if (spec.plan === 'lateral') {
1041
1040
  if (!lateralSink) {
1042
- throw new errors_js_1.ValidationError(`[turbine] Pick-row ordering with plan: 'lateral' on relation "${relName}" is only supported ` +
1041
+ throw new errors_js_1.ValidationError(`Pick-row ordering with plan: 'lateral' on relation "${relName}" is only supported ` +
1043
1042
  'in a top-level findMany orderBy.');
1044
1043
  }
1045
1044
  const childAlias = `${alias}i`;
@@ -1106,7 +1105,7 @@ function collectRelationPickOrderParams(qi, relName, relDef, spec, params) {
1106
1105
  validatePickOrderBy(qi, relName, relDef, spec, false);
1107
1106
  const targetMeta = qi.schema.tables[relDef.to];
1108
1107
  if (!targetMeta)
1109
- throw new errors_js_1.RelationError(`[turbine] Unknown relation target "${relDef.to}"`);
1108
+ throw new errors_js_1.RelationError(`Unknown relation target "${relDef.to}"`);
1110
1109
  if (typeof spec.by === 'string') {
1111
1110
  resolveOrderByColumn(qi, relDef.to, targetMeta, spec.by);
1112
1111
  }
@@ -1151,7 +1150,7 @@ function buildRelationOrderClause(qi, targetTable, targetMeta, alias, orderEntri
1151
1150
  const orders = orderEntries
1152
1151
  .map(([key, dirValue]) => {
1153
1152
  if ((0, filters_js_1.isVectorOrderBy)(dirValue)) {
1154
- throw new errors_js_1.ValidationError(`[turbine] Vector distance ordering on "${key}" is only supported in a top-level findMany orderBy.`);
1153
+ throw new errors_js_1.ValidationError(`Vector distance ordering on "${key}" is only supported in a top-level findMany orderBy.`);
1155
1154
  }
1156
1155
  if ((0, filters_js_1.isJsonPathOrderBy)(dirValue)) {
1157
1156
  return buildJsonPathOrderEntry(qi, targetTable, targetMeta, key, dirValue, `${alias}.`, params);
@@ -1177,7 +1176,7 @@ function buildRelationOrderClause(qi, targetTable, targetMeta, alias, orderEntri
1177
1176
  function collectRelationOrderParams(qi, targetTable, targetMeta, orderEntries, params) {
1178
1177
  for (const [key, dirValue] of orderEntries) {
1179
1178
  if ((0, filters_js_1.isVectorOrderBy)(dirValue)) {
1180
- throw new errors_js_1.ValidationError(`[turbine] Vector distance ordering on "${key}" is only supported in a top-level findMany orderBy.`);
1179
+ throw new errors_js_1.ValidationError(`Vector distance ordering on "${key}" is only supported in a top-level findMany orderBy.`);
1181
1180
  }
1182
1181
  if ((0, filters_js_1.isJsonPathOrderBy)(dirValue)) {
1183
1182
  validateJsonPathOrderBy(qi, targetTable, targetMeta, key, dirValue);
@@ -1221,7 +1220,7 @@ function buildRelationCountExpr(qi, relDef, parentRef, alias, params) {
1221
1220
  const count = qi.castAgg('COUNT(*)', 'int');
1222
1221
  if (relDef.type === 'manyToMany') {
1223
1222
  if (!relDef.through) {
1224
- throw new errors_js_1.ValidationError(`[turbine] manyToMany relation "${relDef.name}" is missing its \`through\` junction.`);
1223
+ throw new errors_js_1.ValidationError(`manyToMany relation "${relDef.name}" is missing its \`through\` junction.`);
1225
1224
  }
1226
1225
  const qJ = qi.q(relDef.through.table);
1227
1226
  const jalias = `${alias}j`;
@@ -1405,9 +1404,22 @@ function parseNestedRow(qi, row, table, fromJson = false) {
1405
1404
  parsed[relName] = jsonVal;
1406
1405
  }
1407
1406
  }
1408
- catch {
1409
- console.warn(`[turbine] Warning: Failed to parse JSON for relation "${relName}" on table "${qi.table}". Using raw value.`);
1410
- parsed[relName] = rawValue;
1407
+ catch (err) {
1408
+ // A relation column that does not parse is a bug in the emitted SQL or
1409
+ // a driver-level corruption, not a recoverable condition. Handing back
1410
+ // the raw string satisfied the assignment and violated the generated
1411
+ // type: callers got a `string` where `Post[]` was promised, and found
1412
+ // out at the first `.map`. Throw instead, with the context needed to
1413
+ // find it.
1414
+ //
1415
+ // The warn is gated and deduped because this sits in parseNestedRow's
1416
+ // per-relation loop: one 10,000-row page was 10,000 console.warn calls.
1417
+ if (process.env.NODE_ENV !== 'production' &&
1418
+ (0, warn_registry_js_1.shouldWarnOnce)(warn_registry_js_1.WARN_NS.relationParseFailure, `${qi.table}.${relName}`)) {
1419
+ console.warn(`[turbine] Relation "${relName}" on "${qi.table}" returned a payload that is not valid JSON. ` +
1420
+ `This is a bug; please report it with the emitted SQL.`);
1421
+ }
1422
+ throw new errors_js_1.ValidationError(`Relation "${relName}" on table "${qi.table}" returned a payload that could not be parsed as JSON.`, { cause: err });
1411
1423
  }
1412
1424
  }
1413
1425
  else if (Array.isArray(rawValue)) {
@@ -2238,7 +2250,7 @@ function makeFlattenParser(qi, plan) {
2238
2250
  function buildSelectWithRelations(qi, table, withClause, params, columnsList, depth, path, includePii, flatten) {
2239
2251
  const meta = qi.schema.tables[table];
2240
2252
  if (!meta)
2241
- throw new errors_js_1.ValidationError(`[turbine] Unknown table "${table}"`);
2253
+ throw new errors_js_1.ValidationError(`Unknown table "${table}"`);
2242
2254
  // Positional JSON encoding is Postgres-only in v1. Gate here, the single
2243
2255
  // entry point for every `with` clause, so no engine ever emits the
2244
2256
  // json_build_array shape its dialect can't produce (and mssql's FOR JSON
@@ -2257,7 +2269,7 @@ function buildSelectWithRelations(qi, table, withClause, params, columnsList, de
2257
2269
  continue;
2258
2270
  const relDef = (0, utils_js_1.ownLookup)(meta.relations, relName);
2259
2271
  if (!relDef) {
2260
- throw new errors_js_1.RelationError(`[turbine] Unknown relation "${relName}" on table "${table}". ` +
2272
+ throw new errors_js_1.RelationError(`Unknown relation "${relName}" on table "${table}". ` +
2261
2273
  (0, utils_js_1.availableClause)(Object.keys(meta.relations), `"${table}" has no relations.`));
2262
2274
  }
2263
2275
  // `relationLoadStrategy: 'flatten'`: an eligible to-one relation becomes a
@@ -2391,7 +2403,7 @@ function buildRelationSubquery(qi, relDef, spec, params, parentRef, aliasCounter
2391
2403
  }
2392
2404
  const targetMeta = qi.schema.tables[targetTable];
2393
2405
  if (!targetMeta)
2394
- throw new errors_js_1.RelationError(`[turbine] Unknown relation target "${targetTable}"`);
2406
+ throw new errors_js_1.RelationError(`Unknown relation target "${targetTable}"`);
2395
2407
  // `true` IS `{}`; below this line there is no `true` case, which is what
2396
2408
  // keeps this walk and collectRelationSubqueryParams reading one shape.
2397
2409
  // The raw `spec` is still what crosses the dialect seam below, since
@@ -2496,7 +2508,7 @@ function buildRelationSubquery(qi, relDef, spec, params, parentRef, aliasCounter
2496
2508
  for (const [nestedRelName, nestedSpec] of (0, filters_js_1.sortedEntries)(opts.with)) {
2497
2509
  const nestedRelDef = (0, utils_js_1.ownLookup)(targetMeta.relations, nestedRelName);
2498
2510
  if (!nestedRelDef) {
2499
- throw new errors_js_1.RelationError(`[turbine] Unknown relation "${nestedRelName}" on table "${targetTable}". ` +
2511
+ throw new errors_js_1.RelationError(`Unknown relation "${nestedRelName}" on table "${targetTable}". ` +
2500
2512
  (0, utils_js_1.availableClause)(Object.keys(targetMeta.relations), `"${relDef.to}" has no relations.`));
2501
2513
  }
2502
2514
  // Recursively build nested subquery, passing THIS alias as the parent reference
@@ -2570,7 +2582,7 @@ function buildRelationSubquery(qi, relDef, spec, params, parentRef, aliasCounter
2570
2582
  for (const [nestedRelName, nestedSpec] of (0, filters_js_1.sortedEntries)(opts.with)) {
2571
2583
  const nestedRelDef = (0, utils_js_1.ownLookup)(targetMeta.relations, nestedRelName);
2572
2584
  if (!nestedRelDef) {
2573
- throw new errors_js_1.RelationError(`[turbine] Unknown relation "${nestedRelName}" on table "${targetTable}". ` +
2585
+ throw new errors_js_1.RelationError(`Unknown relation "${nestedRelName}" on table "${targetTable}". ` +
2574
2586
  (0, utils_js_1.availableClause)(Object.keys(targetMeta.relations), `"${relDef.to}" has no relations.`));
2575
2587
  }
2576
2588
  const nestedSub = buildRelationSubquery(qi, nestedRelDef, nestedSpec, params, innerAlias, aliasCounter, currentDepth + 1, [...currentPath, relDef.name], includePii);
@@ -2614,7 +2626,7 @@ function buildRelationSubquery(qi, relDef, spec, params, parentRef, aliasCounter
2614
2626
  */
2615
2627
  function buildManyToManySubquery(qi, relDef, spec, params, parentRef, aliasCounter, currentDepth, currentPath, talias, targetMeta, targetColumns, includePii) {
2616
2628
  if (!relDef.through) {
2617
- throw new errors_js_1.ValidationError(`[turbine] manyToMany relation "${relDef.name}" is missing a \`through\` junction descriptor.`);
2629
+ throw new errors_js_1.ValidationError(`manyToMany relation "${relDef.name}" is missing a \`through\` junction descriptor.`);
2618
2630
  }
2619
2631
  // `true` IS `{}`; see {@link relationOptions}. Same reading as
2620
2632
  // buildRelationSubquery and collectRelationSubqueryParams' m2m branch.
@@ -2630,12 +2642,12 @@ function buildManyToManySubquery(qi, relDef, spec, params, parentRef, aliasCount
2630
2642
  // introspected PK means we cannot know what to JOIN on, fail loudly rather than
2631
2643
  // silently guessing `id` and generating a wrong JOIN.
2632
2644
  if (targetMeta.primaryKey.length === 0) {
2633
- throw new errors_js_1.ValidationError(`[turbine] manyToMany relation "${relDef.name}" targets table "${targetTable}" which has no primary key; ` +
2645
+ throw new errors_js_1.ValidationError(`manyToMany relation "${relDef.name}" targets table "${targetTable}" which has no primary key; ` +
2634
2646
  `cannot determine the join column. Define a primary key or use an explicit through descriptor.`);
2635
2647
  }
2636
2648
  const targetPk = targetMeta.primaryKey;
2637
2649
  if (targetKeys.length !== targetPk.length) {
2638
- throw new errors_js_1.ValidationError(`[turbine] manyToMany relation "${relDef.name}": through.targetKey has ${targetKeys.length} column(s) ` +
2650
+ throw new errors_js_1.ValidationError(`manyToMany relation "${relDef.name}": through.targetKey has ${targetKeys.length} column(s) ` +
2639
2651
  `but target "${targetTable}" primary key has ${targetPk.length}. Composite keys must pair positionally.`);
2640
2652
  }
2641
2653
  const joinOn = targetKeys.map((jcol, i) => `${jalias}.${qi.q(jcol)} = ${talias}.${qi.q(targetPk[i])}`).join(' AND ');
@@ -2643,7 +2655,7 @@ function buildManyToManySubquery(qi, relDef, spec, params, parentRef, aliasCount
2643
2655
  const sourceKeys = (0, schema_js_1.normalizeKeyColumns)(relDef.through.sourceKey);
2644
2656
  const refKeys = (0, schema_js_1.normalizeKeyColumns)(relDef.referenceKey);
2645
2657
  if (sourceKeys.length !== refKeys.length) {
2646
- throw new errors_js_1.ValidationError(`[turbine] manyToMany relation "${relDef.name}": through.sourceKey has ${sourceKeys.length} column(s) ` +
2658
+ throw new errors_js_1.ValidationError(`manyToMany relation "${relDef.name}": through.sourceKey has ${sourceKeys.length} column(s) ` +
2647
2659
  `but referenceKey has ${refKeys.length}. Composite keys must pair positionally.`);
2648
2660
  }
2649
2661
  let whereClause = sourceKeys
@@ -2689,7 +2701,7 @@ function buildManyToManySubquery(qi, relDef, spec, params, parentRef, aliasCount
2689
2701
  for (const [nestedRelName, nestedSpec] of (0, filters_js_1.sortedEntries)(opts.with)) {
2690
2702
  const nestedRelDef = (0, utils_js_1.ownLookup)(targetMeta.relations, nestedRelName);
2691
2703
  if (!nestedRelDef) {
2692
- throw new errors_js_1.RelationError(`[turbine] Unknown relation "${nestedRelName}" on table "${targetTable}". ` +
2704
+ throw new errors_js_1.RelationError(`Unknown relation "${nestedRelName}" on table "${targetTable}". ` +
2693
2705
  (0, utils_js_1.availableClause)(Object.keys(targetMeta.relations), `"${relDef.to}" has no relations.`));
2694
2706
  }
2695
2707
  const nestedSub = buildRelationSubquery(qi, nestedRelDef, nestedSpec, params, innerAlias, aliasCounter, currentDepth + 1, [...currentPath, relDef.name], includePii);
@@ -2709,7 +2721,7 @@ function buildManyToManySubquery(qi, relDef, spec, params, parentRef, aliasCount
2709
2721
  for (const [nestedRelName, nestedSpec] of (0, filters_js_1.sortedEntries)(opts.with)) {
2710
2722
  const nestedRelDef = (0, utils_js_1.ownLookup)(targetMeta.relations, nestedRelName);
2711
2723
  if (!nestedRelDef) {
2712
- throw new errors_js_1.RelationError(`[turbine] Unknown relation "${nestedRelName}" on table "${targetTable}". ` +
2724
+ throw new errors_js_1.RelationError(`Unknown relation "${nestedRelName}" on table "${targetTable}". ` +
2713
2725
  (0, utils_js_1.availableClause)(Object.keys(targetMeta.relations), `"${relDef.to}" has no relations.`));
2714
2726
  }
2715
2727
  const nestedSub = buildRelationSubquery(qi, nestedRelDef, nestedSpec, params, talias, aliasCounter, currentDepth + 1, [...currentPath, relDef.name], includePii);
@@ -73,7 +73,7 @@ const errors_js_1 = require("../errors.js");
73
73
  exports.UNSAFE = Symbol.for('turbine-orm.UNSAFE');
74
74
  /** The one message shape every privilege refusal uses. */
75
75
  function privilegeRefusal(option, received, extra = '') {
76
- return new errors_js_1.ValidationError(`[turbine] \`${option}\` must be the \`UNSAFE\` symbol, received ${describeValue(received)}. ` +
76
+ return new errors_js_1.ValidationError(`\`${option}\` must be the \`UNSAFE\` symbol, received ${describeValue(received)}. ` +
77
77
  `${option} is a privilege option: it removes a safety boundary (a tenant filter, the PII ` +
78
78
  'projection, or the empty-`where` guard), so it cannot be enabled by a plain value that ' +
79
79
  'JSON.parse can produce. Import the sentinel and pass it explicitly: ' +
@@ -145,12 +145,12 @@ function resolveSkipGlobalFilters(value) {
145
145
  // `[UNSAFE, ...tables]` ESCALATE to a global skip whenever `tables` happens
146
146
  // to come back empty, which is the same accident with a much worse outcome.
147
147
  if (tables.length === 0) {
148
- throw new errors_js_1.ValidationError('[turbine] `skipGlobalFilters: [UNSAFE]` names no table, so it would skip nothing. ' +
148
+ throw new errors_js_1.ValidationError('`skipGlobalFilters: [UNSAFE]` names no table, so it would skip nothing. ' +
149
149
  'Pass the tables to skip (`[UNSAFE, "posts"]`), or the bare sentinel (`UNSAFE`) to skip every table.');
150
150
  }
151
151
  for (const t of tables) {
152
152
  if (typeof t !== 'string') {
153
- throw new errors_js_1.ValidationError('[turbine] `skipGlobalFilters: [UNSAFE, ...]` takes table accessor NAMES after the sentinel, ' +
153
+ throw new errors_js_1.ValidationError('`skipGlobalFilters: [UNSAFE, ...]` takes table accessor NAMES after the sentinel, ' +
154
154
  `received ${describeValue(t)}.`);
155
155
  }
156
156
  }
@@ -212,7 +212,7 @@ function assertDirectionToken(value, context) {
212
212
  if (lowered === 'asc' || lowered === 'desc')
213
213
  return;
214
214
  }
215
- throw new errors_js_1.ValidationError(`[turbine] Invalid orderBy direction ${describeValue(value)} for ${context}. ` +
215
+ throw new errors_js_1.ValidationError(`Invalid orderBy direction ${describeValue(value)} for ${context}. ` +
216
216
  "Use 'asc' or 'desc'. An unrecognized direction used to sort ASCENDING silently, " +
217
217
  'which returns a correct-looking page in the wrong order.');
218
218
  }
@@ -1464,7 +1464,7 @@ function unknownFieldMessage(table, field, meta) {
1464
1464
  const didYouMean = suggestion
1465
1465
  ? ` Did you mean "${suggestion}"${relations.includes(suggestion) ? ' (a relation)' : ''}?`
1466
1466
  : '';
1467
- return (`[turbine] Unknown field "${field}" on table "${table}".${didYouMean}` +
1467
+ return (`Unknown field "${field}" on table "${table}".${didYouMean}` +
1468
1468
  ` Known columns: ${columns.join(', ') || '(none)'}.` +
1469
1469
  (relations.length ? ` Known relations (valid in \`where\` and \`with\`): ${relations.join(', ')}.` : ''));
1470
1470
  }
@@ -1499,7 +1499,7 @@ function availableClause(names, emptySentence) {
1499
1499
  * it. Naming the fix costs one sentence and saves a search.
1500
1500
  */
1501
1501
  function relationInProjectionMessage(table, field, clause) {
1502
- const head = `[turbine] "${field}" is a relation on table "${table}", not a column, so it cannot be named in \`${clause}\`.`;
1502
+ const head = `"${field}" is a relation on table "${table}", not a column, so it cannot be named in \`${clause}\`.`;
1503
1503
  return clause === 'select'
1504
1504
  ? `${head} Load it with \`with: { ${field}: true }\`, which is a sibling of \`select\`, not a member of it.` +
1505
1505
  " To narrow the relation's own columns, put a `select` inside that relation's options:" +
@@ -1550,11 +1550,11 @@ function warnRedundantSortTerm(table, clause, dropped) {
1550
1550
  * which is exactly the class 0.64/0.65 exist to kill.
1551
1551
  */
1552
1552
  function selectNamesNothingMessage(table) {
1553
- return (`[turbine] "select" names no fields (on table "${table}"): every value is false or it is empty. ` +
1553
+ return (`"select" names no fields (on table "${table}"): every value is false or it is empty. ` +
1554
1554
  `Pass at least one field as true, or drop "select" to get the default projection.`);
1555
1555
  }
1556
1556
  function selectOmitExclusiveMessage(table) {
1557
- return (`[turbine] "select" and "omit" are mutually exclusive (on table "${table}"). ` +
1557
+ return (`"select" and "omit" are mutually exclusive (on table "${table}"). ` +
1558
1558
  `A select already lists exactly the fields you want.`);
1559
1559
  }
1560
1560
  /**
@@ -1608,7 +1608,7 @@ function normalizePagination(args) {
1608
1608
  function assertAliasAgrees(alias, aliasValue, native, nativeValue) {
1609
1609
  if (nativeValue === undefined || nativeValue === aliasValue)
1610
1610
  return;
1611
- throw new errors_js_1.ValidationError(`[turbine] "${alias}" and "${native}" are the same option and were given different values ` +
1611
+ throw new errors_js_1.ValidationError(`"${alias}" and "${native}" are the same option and were given different values ` +
1612
1612
  `(${alias}: ${String(aliasValue)}, ${native}: ${String(nativeValue)}). ` +
1613
1613
  `"${alias}" is Prisma's spelling of "${native}"; pass one of them.`);
1614
1614
  }
@@ -127,4 +127,11 @@ export declare const WARN_NS: {
127
127
  * Keyed on the requested mode.
128
128
  */
129
129
  readonly planCacheModeIgnored: "planCacheModeIgnored";
130
+ /**
131
+ * A relation's JSON payload could not be parsed in `parseNestedRow`
132
+ * (relations.ts). Keyed on `table.relation`, so a page of 10,000 rows whose
133
+ * relation column is malformed says it once rather than once per row: the
134
+ * warn sits in the per-relation loop, which runs once per row per relation.
135
+ */
136
+ readonly relationParseFailure: "relationParseFailure";
130
137
  };
@@ -168,4 +168,11 @@ exports.WARN_NS = {
168
168
  * Keyed on the requested mode.
169
169
  */
170
170
  planCacheModeIgnored: 'planCacheModeIgnored',
171
+ /**
172
+ * A relation's JSON payload could not be parsed in `parseNestedRow`
173
+ * (relations.ts). Keyed on `table.relation`, so a page of 10,000 rows whose
174
+ * relation column is malformed says it once rather than once per row: the
175
+ * warn sits in the per-relation loop, which runs once per row per relation.
176
+ */
177
+ relationParseFailure: 'relationParseFailure',
171
178
  };
@@ -75,7 +75,7 @@ exports.MAX_WHERE_DEPTH = 32;
75
75
  function assertWhereDepth(depth, clause = 'where') {
76
76
  if (depth <= exports.MAX_WHERE_DEPTH)
77
77
  return;
78
- throw new errors_js_1.ValidationError(`[turbine] \`${clause}\` clause nests more than ${exports.MAX_WHERE_DEPTH} levels of AND / OR / NOT ` +
78
+ throw new errors_js_1.ValidationError(`\`${clause}\` clause nests more than ${exports.MAX_WHERE_DEPTH} levels of AND / OR / NOT ` +
79
79
  `(or relation filters) deep. That is far past anything a real predicate needs, and an unbounded ` +
80
80
  `walk over caller-supplied nesting is a stack-overflow surface, so it is refused. If this is a ` +
81
81
  `generated predicate, flatten it: a single \`AND\` / \`OR\` array of N conditions is one level, ` +