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
package/dist/dialect.js CHANGED
@@ -1,11 +1,12 @@
1
1
  /**
2
- * turbine-orm — SQL dialect contract
2
+ * turbine-orm, SQL dialect contract
3
3
  *
4
4
  * Phase-1 seam for future database packages. The current package remains
5
5
  * PostgreSQL-native by default, but query generation now depends on this
6
6
  * contract for the SQL primitives that vary across MySQL and SQLite.
7
7
  */
8
8
  import { ValidationError } from './errors.js';
9
+ import { coerceJsonWireValue, jsonWireCoercionOid } from './query/utils.js';
9
10
  import { pgArrayType, pgTypeToTs } from './schema.js';
10
11
  /** PostgreSQL implementation of the dialect contract. */
11
12
  export const postgresDialect = {
@@ -80,6 +81,28 @@ export const postgresDialect = {
80
81
  if (!input.columnArrayTypes || input.columnArrayTypes.length !== input.columns.length) {
81
82
  throw new ValidationError('PostgreSQL bulk insert requires one array type per column');
82
83
  }
84
+ // Row-major form: required when a target column is itself array-typed,
85
+ // because the UNNEST transpose below flattens nested arrays (see
86
+ // `requireRowValues`). One placeholder per cell instead of per column.
87
+ if (input.requireRowValues) {
88
+ const params = [];
89
+ const tuples = input.rowValues.map((row) => {
90
+ const cells = input.columns.map((_, i) => {
91
+ params.push(row[i]);
92
+ // No cast: PostgreSQL infers each parameter's type from the INSERT
93
+ // target column, which is what single-row `create` already relies on
94
+ // and is what makes arrays and enums both work here. The casts in
95
+ // `columnArrayTypes` are ARRAY-OF-column-type, correct for the
96
+ // UNNEST transpose below but wrong for an individual cell.
97
+ return this.paramPlaceholder(params.length);
98
+ });
99
+ return `(${cells.join(', ')})`;
100
+ });
101
+ let rowSql = `INSERT INTO ${input.table} (${input.columns.join(', ')}) VALUES ${tuples.join(', ')}`;
102
+ if (input.skipDuplicates)
103
+ rowSql += ' ON CONFLICT DO NOTHING';
104
+ return { sql: `${rowSql}${this.buildReturningClause(input.returning)}`, params };
105
+ }
83
106
  const columnArrays = input.columns.map((_, columnIndex) => input.rowValues.map((row) => row[columnIndex]));
84
107
  const unnestArgs = input.columns.map((_, i) => `${this.paramPlaceholder(i + 1)}::${input.columnArrayTypes[i]}`);
85
108
  let sql = `INSERT INTO ${input.table} (${input.columns.join(', ')}) SELECT * FROM UNNEST(${unnestArgs.join(', ')})`;
@@ -124,6 +147,21 @@ export const postgresDialect = {
124
147
  arrayType(baseType) {
125
148
  return pgArrayType(baseType);
126
149
  },
150
+ jsonWireRule(columnType) {
151
+ // `json_build_object` renders these as a JSON number / bare token that does
152
+ // not match what the driver returns for the same column (numeric past
153
+ // double precision and int8 past 2^53 lose digits outright). Carry the
154
+ // driver's own wire TEXT instead and hand it back to the driver's parser
155
+ // for that OID, so the join strategy returns exactly what a top-level read
156
+ // returns.
157
+ const oid = jsonWireCoercionOid(columnType);
158
+ if (oid === undefined)
159
+ return undefined;
160
+ return {
161
+ sql: (ref) => `${ref}::text`,
162
+ decode: (value) => coerceJsonWireValue(oid, value),
163
+ };
164
+ },
127
165
  buildColumnType(input) {
128
166
  if (input.type === 'VARCHAR' && input.maxLength != null) {
129
167
  return `VARCHAR(${input.maxLength})`;
@@ -195,7 +233,7 @@ export const postgresDialect = {
195
233
  return `ROLLBACK TO SAVEPOINT ${name}`;
196
234
  },
197
235
  buildSetSessionConfig(name, value) {
198
- // set_config(name, value, is_local=true) — the parameterizable,
236
+ // set_config(name, value, is_local=true), the parameterizable,
199
237
  // transaction-local equivalent of `SET LOCAL` (which rejects bind params).
200
238
  return {
201
239
  sql: `SELECT set_config(${this.paramPlaceholder(1)}, ${this.paramPlaceholder(2)}, true)`,
package/dist/errors.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  /**
2
- * turbine-orm — Error types
2
+ * turbine-orm, Error types
3
3
  *
4
4
  * Typed errors with error codes for programmatic handling.
5
5
  * All Turbine errors extend TurbineError which includes a `code` property.
@@ -39,7 +39,7 @@ export declare class TurbineError extends Error {
39
39
  *
40
40
  * Defaults to `'safe'` to avoid leaking PII into error logs (Sentry, Datadog,
41
41
  * etc.). The full `where` object is always available as `err.where` for
42
- * programmatic access — only the human-readable message is redacted.
42
+ * programmatic access, only the human-readable message is redacted.
43
43
  *
44
44
  * Set via `setErrorMessageMode('verbose')` or by constructing TurbineClient
45
45
  * with `{ errorMessages: 'verbose' }`.
@@ -182,7 +182,7 @@ export declare class NotNullViolationError extends TurbineError {
182
182
  /**
183
183
  * Thrown when Postgres detects a deadlock (pg code 40P01).
184
184
  *
185
- * This error is **retryable** — when caught, callers can safely retry the
185
+ * This error is **retryable**, when caught, callers can safely retry the
186
186
  * transaction (typically with backoff). Catch it explicitly:
187
187
  *
188
188
  * ```ts
@@ -207,9 +207,9 @@ export declare class DeadlockError extends TurbineError {
207
207
  }
208
208
  /**
209
209
  * Thrown when a Serializable transaction fails due to a serialization
210
- * conflict (pg code 40001 — `could not serialize access due to ...`).
210
+ * conflict (pg code 40001, `could not serialize access due to ...`).
211
211
  *
212
- * This error is **retryable** — by Postgres documentation, the recommended
212
+ * This error is **retryable**, by Postgres documentation, the recommended
213
213
  * response is to re-run the entire transaction. Catch it explicitly:
214
214
  *
215
215
  * ```ts
package/dist/errors.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /**
2
- * turbine-orm — Error types
2
+ * turbine-orm, Error types
3
3
  *
4
4
  * Typed errors with error codes for programmatic handling.
5
5
  * All Turbine errors extend TurbineError which includes a `code` property.
@@ -140,7 +140,7 @@ export class NotFoundError extends TurbineError {
140
140
  where;
141
141
  operation;
142
142
  constructor(input) {
143
- // Back-compat: string argument (or undefined) — replicate legacy behavior.
143
+ // Back-compat: string argument (or undefined), replicate legacy behavior.
144
144
  if (typeof input === 'string' || input === undefined) {
145
145
  super(TurbineErrorCode.NOT_FOUND, input ?? 'Record not found');
146
146
  this.name = 'NotFoundError';
@@ -255,7 +255,7 @@ export class UniqueConstraintError extends TurbineError {
255
255
  // PII-safe by default: the raw pg `detail` string contains the
256
256
  // conflicting row VALUES (e.g. `Key (email)=(alice@x.com) already
257
257
  // exists.`). Only append it in 'verbose' mode. In 'safe' mode the
258
- // message carries keys/constraint/column names only — the structured
258
+ // message carries keys/constraint/column names only, the structured
259
259
  // `.columns`/`.constraint`/`.column` fields and `.cause` still expose
260
260
  // the full detail for programmatic use.
261
261
  const detail = errorMessageMode === 'verbose' ? detailFromCause(cause) : undefined;
@@ -282,7 +282,7 @@ export class ForeignKeyError extends TurbineError {
282
282
  // PII-safe by default: the raw pg `detail` string contains the
283
283
  // conflicting row VALUES (e.g. `Key (email)=(alice@x.com) already
284
284
  // exists.`). Only append it in 'verbose' mode. In 'safe' mode the
285
- // message carries keys/constraint/column names only — the structured
285
+ // message carries keys/constraint/column names only, the structured
286
286
  // `.columns`/`.constraint`/`.column` fields and `.cause` still expose
287
287
  // the full detail for programmatic use.
288
288
  const detail = errorMessageMode === 'verbose' ? detailFromCause(cause) : undefined;
@@ -308,7 +308,7 @@ export class NotNullViolationError extends TurbineError {
308
308
  // PII-safe by default: the raw pg `detail` string contains the
309
309
  // conflicting row VALUES (e.g. `Key (email)=(alice@x.com) already
310
310
  // exists.`). Only append it in 'verbose' mode. In 'safe' mode the
311
- // message carries keys/constraint/column names only — the structured
311
+ // message carries keys/constraint/column names only, the structured
312
312
  // `.columns`/`.constraint`/`.column` fields and `.cause` still expose
313
313
  // the full detail for programmatic use.
314
314
  const detail = errorMessageMode === 'verbose' ? detailFromCause(cause) : undefined;
@@ -324,7 +324,7 @@ export class NotNullViolationError extends TurbineError {
324
324
  /**
325
325
  * Thrown when Postgres detects a deadlock (pg code 40P01).
326
326
  *
327
- * This error is **retryable** — when caught, callers can safely retry the
327
+ * This error is **retryable**, when caught, callers can safely retry the
328
328
  * transaction (typically with backoff). Catch it explicitly:
329
329
  *
330
330
  * ```ts
@@ -355,9 +355,9 @@ export class DeadlockError extends TurbineError {
355
355
  }
356
356
  /**
357
357
  * Thrown when a Serializable transaction fails due to a serialization
358
- * conflict (pg code 40001 — `could not serialize access due to ...`).
358
+ * conflict (pg code 40001, `could not serialize access due to ...`).
359
359
  *
360
- * This error is **retryable** — by Postgres documentation, the recommended
360
+ * This error is **retryable**, by Postgres documentation, the recommended
361
361
  * response is to re-run the entire transaction. Catch it explicitly:
362
362
  *
363
363
  * ```ts
@@ -399,7 +399,7 @@ export class CheckConstraintError extends TurbineError {
399
399
  // PII-safe by default: the raw pg `detail` string contains the
400
400
  // conflicting row VALUES (e.g. `Key (email)=(alice@x.com) already
401
401
  // exists.`). Only append it in 'verbose' mode. In 'safe' mode the
402
- // message carries keys/constraint/column names only — the structured
402
+ // message carries keys/constraint/column names only, the structured
403
403
  // `.columns`/`.constraint`/`.column` fields and `.cause` still expose
404
404
  // the full detail for programmatic use.
405
405
  const detail = errorMessageMode === 'verbose' ? detailFromCause(cause) : undefined;
@@ -424,7 +424,7 @@ export class ExclusionConstraintError extends TurbineError {
424
424
  // PII-safe by default: the raw pg `detail` string contains the
425
425
  // conflicting row VALUES (e.g. `Key (email)=(alice@x.com) already
426
426
  // exists.`). Only append it in 'verbose' mode. In 'safe' mode the
427
- // message carries keys/constraint/column names only — the structured
427
+ // message carries keys/constraint/column names only, the structured
428
428
  // `.columns`/`.constraint`/`.column` fields and `.cause` still expose
429
429
  // the full detail for programmatic use.
430
430
  const detail = errorMessageMode === 'verbose' ? detailFromCause(cause) : undefined;
@@ -482,7 +482,7 @@ export class OptimisticLockError extends TurbineError {
482
482
  versionField;
483
483
  expectedVersion;
484
484
  constructor(opts) {
485
- super(TurbineErrorCode.OPTIMISTIC_LOCK, `[turbine] Optimistic lock failed on "${opts.table}" — ` +
485
+ super(TurbineErrorCode.OPTIMISTIC_LOCK, `[turbine] Optimistic lock failed on "${opts.table}", ` +
486
486
  `expected ${opts.versionField} = ${opts.expectedVersion} but row was modified by another transaction`);
487
487
  this.name = 'OptimisticLockError';
488
488
  this.table = opts.table;
@@ -1,10 +1,10 @@
1
1
  /**
2
- * turbine-orm — Code generator
2
+ * turbine-orm, Code generator
3
3
  *
4
4
  * Takes an IntrospectedSchema and emits TypeScript files:
5
- * - types.ts — Entity interfaces, Create/Update input types
6
- * - metadata.ts — Runtime schema metadata (column maps, relations, etc.)
7
- * - index.ts — Configured TurbineClient with typed table accessors
5
+ * - types.ts , Entity interfaces, Create/Update input types
6
+ * - metadata.ts , Runtime schema metadata (column maps, relations, etc.)
7
+ * - index.ts , Configured TurbineClient with typed table accessors
8
8
  *
9
9
  * Output goes to the specified directory (default: ./generated/turbine/).
10
10
  */
@@ -19,13 +19,13 @@ export interface GenerateOptions {
19
19
  /**
20
20
  * Also emit `zod.ts` with per-table `XSchema` / `XCreateSchema` /
21
21
  * `XUpdateSchema` Zod validators (H1). The file imports the user-side `zod`
22
- * package — it is never imported by Turbine's runtime, so Zod stays out of the
22
+ * package, it is never imported by Turbine's runtime, so Zod stays out of the
23
23
  * library's dependency graph. Default: `false`.
24
24
  */
25
25
  zod?: boolean;
26
26
  /**
27
27
  * Omit the `Generated at: <ISO timestamp>` line from every generated file
28
- * header (T-8b — reproducible codegen). With this set, byte-identical
28
+ * header (T-8b, reproducible codegen). With this set, byte-identical
29
29
  * schemas regenerate to byte-identical output, so regens produce empty
30
30
  * diffs. Default: `false` (timestamp included, unchanged behavior).
31
31
  */
package/dist/generate.js CHANGED
@@ -1,10 +1,10 @@
1
1
  /**
2
- * turbine-orm — Code generator
2
+ * turbine-orm, Code generator
3
3
  *
4
4
  * Takes an IntrospectedSchema and emits TypeScript files:
5
- * - types.ts — Entity interfaces, Create/Update input types
6
- * - metadata.ts — Runtime schema metadata (column maps, relations, etc.)
7
- * - index.ts — Configured TurbineClient with typed table accessors
5
+ * - types.ts , Entity interfaces, Create/Update input types
6
+ * - metadata.ts , Runtime schema metadata (column maps, relations, etc.)
7
+ * - index.ts , Configured TurbineClient with typed table accessors
8
8
  *
9
9
  * Output goes to the specified directory (default: ./generated/turbine/).
10
10
  */
@@ -66,7 +66,7 @@ function escSQ(value) {
66
66
  // ---------------------------------------------------------------------------
67
67
  export function generate(options) {
68
68
  const outDir = options.outDir ?? './generated/turbine';
69
- // Path traversal protection — ensure output stays within project root
69
+ // Path traversal protection, ensure output stays within project root
70
70
  const resolved = resolve(outDir);
71
71
  const rel = relative(process.cwd(), resolved);
72
72
  if (rel.startsWith('..') || resolve(rel) !== resolved) {
@@ -92,7 +92,7 @@ export function generate(options) {
92
92
  const indexContent = generateIndex(schema, fileOptions);
93
93
  writeFileSync(join(outDir, 'index.ts'), indexContent, 'utf-8');
94
94
  files.push('index.ts');
95
- // Generate zod.ts (optional — --zod flag)
95
+ // Generate zod.ts (optional, --zod flag)
96
96
  if (options.zod) {
97
97
  const zodContent = generateZod(schema, fileOptions);
98
98
  writeFileSync(join(outDir, 'zod.ts'), zodContent, 'utf-8');
@@ -251,7 +251,7 @@ function generatedFileHeader(options) {
251
251
  // unchanged schema produces byte-identical files.
252
252
  return [
253
253
  '/**',
254
- ' * Auto-generated by turbine-orm — DO NOT EDIT',
254
+ ' * Auto-generated by turbine-orm, DO NOT EDIT',
255
255
  ' *',
256
256
  ...(options?.noTimestamp ? [] : [` * Generated at: ${new Date().toISOString()}`]),
257
257
  ' * @see https://turbineorm.dev',
@@ -265,7 +265,7 @@ function generatedFileHeader(options) {
265
265
  * column: `interface XWithY extends X` becomes TS2430, the `XCreate & { y?: … }`
266
266
  * intersection collapses (TS2322), and neither the column nor the relation is
267
267
  * targetable. Introspection no longer produces such names (they are
268
- * disambiguated at the source), but hand-written or legacy metadata may —
268
+ * disambiguated at the source), but hand-written or legacy metadata may -
269
269
  * skip those relations here with a warning instead of emitting broken types.
270
270
  * The runtime metadata (metadata.ts) still carries every relation.
271
271
  */
@@ -275,7 +275,7 @@ function typeSafeRelations(table, warn = true) {
275
275
  for (const [relName, rel] of Object.entries(table.relations)) {
276
276
  if (columnFields.has(relName)) {
277
277
  if (warn) {
278
- console.warn(`[turbine] Relation "${relName}" on table "${table.name}" shadows a column field of the same name — ` +
278
+ console.warn(`[turbine] Relation "${relName}" on table "${table.name}" shadows a column field of the same name, ` +
279
279
  `omitting it from the generated types. Rename the relation (or the column) to expose it.`);
280
280
  }
281
281
  continue;
@@ -349,7 +349,7 @@ export function generateTypes(schema, options) {
349
349
  lines.push(`/** Input type for creating a row in \`${table.name}\` */`);
350
350
  lines.push(`export type ${typeName}Create = {`);
351
351
  for (const col of table.columns) {
352
- // STORED generated columns are computed by the database — never writable.
352
+ // STORED generated columns are computed by the database, never writable.
353
353
  if (col.isGeneratedStored)
354
354
  continue;
355
355
  const isPk = table.primaryKey.includes(col.name);
@@ -381,7 +381,7 @@ export function generateTypes(schema, options) {
381
381
  // Each relation is emitted as a `RelationDescriptor<Target, Cardinality,
382
382
  // TargetRelations>` brand-field interface. This is what enables the
383
383
  // recursive `WithResult` type to walk through nested `with` clauses at
384
- // any depth — `RelationRelations<R[K]>` reads the third type parameter
384
+ // any depth, `RelationRelations<R[K]>` reads the third type parameter
385
385
  // and threads it into the next recursion step. If the target table has
386
386
  // no relations of its own, the descriptor uses `{}` (the default).
387
387
  const safeRelations = safeRelationsByTable.get(table.name) ?? [];
@@ -425,7 +425,7 @@ export function generateTypes(schema, options) {
425
425
  const typeName = entityName(table.name);
426
426
  const safeRelations = safeRelationsByTable.get(table.name) ?? [];
427
427
  const hasRels = safeRelations.length > 0;
428
- // WhereUnique — union of unique constraint shapes, deduplicating PK
428
+ // WhereUnique, union of unique constraint shapes, deduplicating PK
429
429
  const seen = new Set();
430
430
  const uniqueSets = [];
431
431
  // Always include the primary key first
@@ -502,7 +502,7 @@ export function generateTypes(schema, options) {
502
502
  lines.push(`export type ${typeName}WhereUnique = ${branches.join(' | ')};`);
503
503
  lines.push('');
504
504
  }
505
- // CreateInput / UpdateInput — extends base type with optional relation fields
505
+ // CreateInput / UpdateInput, extends base type with optional relation fields
506
506
  if (hasRels) {
507
507
  lines.push(`export type ${typeName}CreateInput = ${typeName}Create & {`);
508
508
  for (const [relName, rel] of safeRelations) {
@@ -556,11 +556,11 @@ export function generateTypes(schema, options) {
556
556
  return lines.join('\n');
557
557
  }
558
558
  // ---------------------------------------------------------------------------
559
- // zod.ts generator (H1 — `turbine generate --zod`)
559
+ // zod.ts generator (H1, `turbine generate --zod`)
560
560
  // ---------------------------------------------------------------------------
561
561
  /**
562
562
  * Map a TypeScript primitive (as produced by {@link pgTypeToTs}) to its Zod
563
- * expression. `Date` uses `z.coerce.date()` — the generated schemas double as
563
+ * expression. `Date` uses `z.coerce.date()`, the generated schemas double as
564
564
  * request-body validators where dates arrive as ISO strings, and coercion keeps
565
565
  * both a `Date` and a valid date-string acceptable (documented decision).
566
566
  */
@@ -579,7 +579,7 @@ function zodScalar(ts) {
579
579
  case 'Buffer':
580
580
  return 'z.instanceof(Uint8Array)';
581
581
  case 'number[]':
582
- // pgvector — `pgTypeToTs('vector')` yields `number[]`.
582
+ // pgvector, `pgTypeToTs('vector')` yields `number[]`.
583
583
  return 'z.array(z.number())';
584
584
  default:
585
585
  // json/jsonb and any unmapped user-defined type.
@@ -589,7 +589,7 @@ function zodScalar(ts) {
589
589
  /**
590
590
  * Base Zod expression for a column, resolving enums → `z.enum([...])`, arrays →
591
591
  * `.array()`, and vectors → `z.array(z.number())`. Does NOT append
592
- * `.nullable()` / `.optional()` — callers layer those on per-schema.
592
+ * `.nullable()` / `.optional()`, callers layer those on per-schema.
593
593
  *
594
594
  * `forWrite` mirrors {@link writeColumnTsType}: the Create/Update schemas
595
595
  * validate WRITE input, where a `time` / `timetz` column also accepts a JS
@@ -624,7 +624,7 @@ function zodBaseType(col, enums, forWrite = false) {
624
624
  */
625
625
  export function generateZod(schema, options) {
626
626
  const lines = [...generatedFileHeader(options)];
627
- // `zod` is a USER dependency — this generated file imports it, but the Turbine
627
+ // `zod` is a USER dependency, this generated file imports it, but the Turbine
628
628
  // library runtime never does, so Zod stays out of the package's dep graph.
629
629
  lines.push("import { z } from 'zod';");
630
630
  lines.push('');
@@ -641,7 +641,7 @@ export function generateZod(schema, options) {
641
641
  }
642
642
  lines.push('});');
643
643
  lines.push('');
644
- // Create schema — STORED generated columns can never be written; PK,
644
+ // Create schema, STORED generated columns can never be written; PK,
645
645
  // defaulted, and nullable columns are optional.
646
646
  lines.push(`/** Zod schema for creating a \`${table.name}\` row */`);
647
647
  lines.push(`export const ${typeName}CreateSchema = z.object({`);
@@ -658,7 +658,7 @@ export function generateZod(schema, options) {
658
658
  }
659
659
  lines.push('});');
660
660
  lines.push('');
661
- // Update schema — PK and STORED generated columns omitted; all else optional.
661
+ // Update schema, PK and STORED generated columns omitted; all else optional.
662
662
  lines.push(`/** Zod schema for updating a \`${table.name}\` row */`);
663
663
  lines.push(`export const ${typeName}UpdateSchema = z.object({`);
664
664
  for (const col of table.columns) {
@@ -740,7 +740,7 @@ export function generateMetadata(schema, options) {
740
740
  const refLiteral = Array.isArray(rel.referenceKey)
741
741
  ? `[${rel.referenceKey.map((c) => `'${escSQ(c)}'`).join(', ')}]`
742
742
  : `'${escSQ(rel.referenceKey)}'`;
743
- // manyToMany relations carry a `through` junction descriptor — emit it so
743
+ // manyToMany relations carry a `through` junction descriptor, emit it so
744
744
  // the runtime query builder can JOIN through the junction table.
745
745
  let throughLiteral = '';
746
746
  if (rel.through) {
@@ -774,7 +774,7 @@ export function generateMetadata(schema, options) {
774
774
  }
775
775
  lines.push(' ],');
776
776
  }
777
- // isView — read-only marker; the runtime write guard reads it.
777
+ // isView, read-only marker; the runtime write guard reads it.
778
778
  if (table.isView)
779
779
  lines.push(' isView: true,');
780
780
  lines.push(' },');
@@ -827,7 +827,7 @@ export function generateIndex(schema, options) {
827
827
  lines.push(`import type { ${typeImports.join(', ')} } from './types${ext}';`);
828
828
  lines.push('');
829
829
  // -------------------------------------------------------------------------
830
- // TypedTransactionClient — same typed table accessors as TurbineClient,
830
+ // TypedTransactionClient, same typed table accessors as TurbineClient,
831
831
  // but scoped to a single transaction connection. The runtime instance is
832
832
  // an ordinary `TransactionClient` from turbine-orm; this declaration just
833
833
  // teaches TypeScript about the auto-attached accessors so users get
@@ -835,7 +835,7 @@ export function generateIndex(schema, options) {
835
835
  // -------------------------------------------------------------------------
836
836
  lines.push('/**');
837
837
  lines.push(' * Transaction-scoped client with the same typed table accessors as TurbineClient.');
838
- lines.push(' * Created automatically by `db.$transaction(async (tx) => ...)` — never instantiate');
838
+ lines.push(' * Created automatically by `db.$transaction(async (tx) => ...)`, never instantiate');
839
839
  lines.push(' * directly. All queries run on a dedicated connection within a BEGIN/COMMIT block.');
840
840
  lines.push(' */');
841
841
  lines.push('export class TypedTransactionClient extends BaseTransactionClient {');
@@ -900,7 +900,7 @@ export function generateIndex(schema, options) {
900
900
  // so users get autocomplete on `tx.users`, `tx.posts`, etc.
901
901
  //
902
902
  // IMPORTANT: the merged member must be compatible with the base class's
903
- // $transaction ON ITS OWN (TS2415) — since v0.26 the base method also has a
903
+ // $transaction ON ITS OWN (TS2415), since v0.26 the base method also has a
904
904
  // batch-array overload (`$transaction([...queries])`), so the merged
905
905
  // interface must redeclare BOTH signatures. Emitting only the callback form
906
906
  // makes every generated client fail `tsc` with "incorrectly extends".
@@ -1030,7 +1030,7 @@ function serializeColumn(col) {
1030
1030
  `arrayType: '${escSQ(col.arrayType ?? col.pgArrayType)}'`,
1031
1031
  `pgArrayType: '${escSQ(col.pgArrayType)}'`,
1032
1032
  ];
1033
- // Cross-schema type marker — introspection records it only for types living
1033
+ // Cross-schema type marker, introspection records it only for types living
1034
1034
  // outside the introspected schema; it must survive codegen or the runtime
1035
1035
  // enum-cast guard in query/builder.ts loses the signal (N-5).
1036
1036
  if (col.pgTypeSchema !== undefined)
@@ -1039,7 +1039,7 @@ function serializeColumn(col) {
1039
1039
  // output stays byte-identical for the common client-default columns.
1040
1040
  if (col.isGenerated)
1041
1041
  parts.push(`isGenerated: true`);
1042
- // STORED generated columns — the runtime write guard reads isGeneratedStored.
1042
+ // STORED generated columns, the runtime write guard reads isGeneratedStored.
1043
1043
  if (col.isGeneratedStored)
1044
1044
  parts.push(`isGeneratedStored: true`);
1045
1045
  if (col.generationExpression !== undefined) {
@@ -1050,6 +1050,8 @@ function serializeColumn(col) {
1050
1050
  // object built from `defineSchema` (pii: true) carries it through codegen.
1051
1051
  if (col.pii)
1052
1052
  parts.push(`pii: true`);
1053
+ if (col.updatedAt)
1054
+ parts.push(`updatedAt: true`);
1053
1055
  if (col.maxLength !== undefined)
1054
1056
  parts.push(`maxLength: ${col.maxLength}`);
1055
1057
  return `{ ${parts.join(', ')} }`;
@@ -1065,7 +1067,7 @@ function snakeToCamelStr(s) {
1065
1067
  * `T | UpdateOperatorInput<number> | null?` so users can write atomic
1066
1068
  * operators (`{ increment: 1 }`, `{ multiply: 2 }`, etc.) without casts.
1067
1069
  *
1068
- * The check is purely structural — if the column's TS type contains
1070
+ * The check is purely structural, if the column's TS type contains
1069
1071
  * `'number'` (e.g. `number`, `number | null`), it's eligible. Other
1070
1072
  * scalar types (`string`, `boolean`, `Date`, `unknown`, `Buffer`,
1071
1073
  * `Date | null`, etc.) pass through unchanged.
@@ -1079,7 +1081,7 @@ function updateFieldType(tsType) {
1079
1081
  }
1080
1082
  /**
1081
1083
  * Detect whether a TypeScript type expression contains the `number` primitive
1082
- * as a top-level union member. Conservative on purpose — only matches
1084
+ * as a top-level union member. Conservative on purpose, only matches
1083
1085
  * `number`, `number | null`, `null | number`, etc., not `number[]` or
1084
1086
  * `Record<string, number>`.
1085
1087
  */
@@ -1,11 +1,11 @@
1
1
  /**
2
- * Index advisor — finds relation probes that lack index support.
2
+ * Index advisor, finds relation probes that lack index support.
3
3
  *
4
4
  * Turbine loads `with` relations as correlated subqueries: for every parent row,
5
5
  * the child table is probed by its FK column(s) (`child.fk = parent.pk`). Relation
6
6
  * filters (`some`/`none`/`every`, `is`/`isNot`) probe the same columns. This
7
7
  * strategy outperforms batched loading (`WHERE fk IN (ids)`) when the probed
8
- * column is indexed — but with NO index, each probe is a full table scan and the
8
+ * column is indexed, but with NO index, each probe is a full table scan and the
9
9
  * cost multiplies by the parent rowcount, while batched loading would pay the
10
10
  * scan only once. A missing FK index that is invisible under a batched-loader
11
11
  * ORM becomes pathological under a correlated one.
@@ -27,7 +27,7 @@ export interface RelationProbe {
27
27
  export interface MissingRelationIndex {
28
28
  /** Table that gets probed per parent row */
29
29
  table: string;
30
- /** Probed column(s) — equality lookups, so a covering index must LEAD with one of them */
30
+ /** Probed column(s), equality lookups, so a covering index must LEAD with one of them */
31
31
  columns: string[];
32
32
  /** Every relation that generates this probe */
33
33
  probes: RelationProbe[];
@@ -46,7 +46,7 @@ export interface CreateIndexSqlOptions {
46
46
  * it must also carry the `-- turbine:no-transaction` directive.
47
47
  */
48
48
  concurrently?: boolean;
49
- /** Emit `IF NOT EXISTS` (default true — required for idempotent no-transaction migrations). */
49
+ /** Emit `IF NOT EXISTS` (default true, required for idempotent no-transaction migrations). */
50
50
  ifNotExists?: boolean;
51
51
  /**
52
52
  * Emit a partial index `... WHERE <col> IS NOT NULL`. Only applied for a
@@ -134,7 +134,7 @@ export declare function schemaHasIndexInfo(schema: SchemaMetadata): boolean;
134
134
  * Single-relation check for the dev-mode runtime warning: the (table, columns)
135
135
  * this relation probes and whether that probe is unindexed. Returns null when
136
136
  * indexed, unknown, or when the schema carries no index info at all (metadata
137
- * built without introspection — warning would be a blanket false positive).
137
+ * built without introspection, warning would be a blanket false positive).
138
138
  */
139
139
  export declare function missingIndexForRelation(schema: SchemaMetadata, relDef: {
140
140
  name: string;
Binary file
package/dist/index.d.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * turbine-orm
3
3
  *
4
- * Turbine TypeScript SDK — type-safe Postgres queries with nested relations
4
+ * Turbine TypeScript SDK, type-safe Postgres queries with nested relations
5
5
  * and pipeline batching. Feels like Prisma, runs at raw-SQL speed.
6
6
  *
7
7
  * @example
package/dist/index.js CHANGED
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * turbine-orm
3
3
  *
4
- * Turbine TypeScript SDK — type-safe Postgres queries with nested relations
4
+ * Turbine TypeScript SDK, type-safe Postgres queries with nested relations
5
5
  * and pipeline batching. Feels like Prisma, runs at raw-SQL speed.
6
6
  *
7
7
  * @example
@@ -50,21 +50,21 @@ export { HttpJsonSink, PgMetricsSink, } from './observe.js';
50
50
  export { executePipeline, pipelineSupported } from './pipeline.js';
51
51
  // Query builder
52
52
  export { AUTO_ASSUMED_ROUND_TRIP_MS, AUTO_JOIN_PENALTY_MS_PER_ROW, AUTO_TO_ONE_JOIN_MAX_ROWS, AUTO_TO_ONE_JOIN_ROWS_MAX, AUTO_TO_ONE_JOIN_ROWS_MIN, QueryInterface, } from './query/index.js';
53
- // Realtime — LISTEN/NOTIFY pub/sub
53
+ // Realtime, LISTEN/NOTIFY pub/sub
54
54
  export { validateChannel } from './realtime.js';
55
55
  // Schema utilities
56
56
  export { camelToSnake, isDateType, normalizeKeyColumns, pgArrayType, pgTypeToTs, singularize, snakeToCamel, snakeToPascal, withDbFieldNames, } from './schema.js';
57
- // Schema builder — define schemas in TypeScript
57
+ // Schema builder, define schemas in TypeScript
58
58
  export { applyManyToManyRelations, ColumnBuilder, column, defineSchema, isDocFieldIndexDef,
59
- // Legacy compat (deprecated — use object format with defineSchema)
59
+ // Legacy compat (deprecated, use object format with defineSchema)
60
60
  table, } from './schema-builder.js';
61
- // Schema metadata bridge — defineSchema() → SchemaMetadata without a live DB
61
+ // Schema metadata bridge, defineSchema() → SchemaMetadata without a live DB
62
62
  export { schemaDefToMetadata } from './schema-metadata.js';
63
- // Schema SQL — generate DDL, diff, and push
63
+ // Schema SQL, generate DDL, diff, and push
64
64
  export { DestructivePushRefusal, schemaDiff, schemaPush, schemaToSQL, schemaToSQLString, } from './schema-sql.js';
65
65
  // Seed helper
66
66
  export { defineSeed } from './seed.js';
67
67
  // Serverless / edge factory
68
68
  export { turbineHttp } from './serverless.js';
69
- // Typed raw SQL — Turbine's TypedSQL escape hatch
69
+ // Typed raw SQL, Turbine's TypedSQL escape hatch
70
70
  export { buildTypedSql, TypedSqlQuery } from './typed-sql.js';