turbine-orm 0.81.0 → 0.90.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +26 -25
- package/dist/checkout.d.ts +27 -2
- package/dist/checkout.js +75 -4
- package/dist/cjs/checkout.d.ts +27 -2
- package/dist/cjs/checkout.js +76 -3
- package/dist/cjs/cli/code-first-tags.d.ts +62 -0
- package/dist/cjs/cli/code-first-tags.js +124 -0
- package/dist/cjs/cli/compile-query.js +9 -0
- package/dist/cjs/cli/config.d.ts +35 -6
- package/dist/cjs/cli/config.js +17 -1
- package/dist/cjs/cli/destructive.d.ts +7 -4
- package/dist/cjs/cli/destructive.js +224 -20
- package/dist/cjs/cli/error-catalog.js +36 -0
- package/dist/cjs/cli/error-text.d.ts +15 -0
- package/dist/cjs/cli/error-text.js +40 -0
- package/dist/cjs/cli/index.d.ts +62 -4
- package/dist/cjs/cli/index.js +568 -108
- package/dist/cjs/cli/local-server-guard.d.ts +53 -0
- package/dist/cjs/cli/local-server-guard.js +119 -0
- package/dist/cjs/cli/local-server-output.d.ts +41 -0
- package/dist/cjs/cli/local-server-output.js +103 -0
- package/dist/cjs/cli/mcp.d.ts +8 -0
- package/dist/cjs/cli/mcp.js +121 -32
- package/dist/cjs/cli/migrate.d.ts +113 -5
- package/dist/cjs/cli/migrate.js +270 -21
- package/dist/cjs/cli/observe.d.ts +6 -1
- package/dist/cjs/cli/observe.js +85 -55
- package/dist/cjs/cli/pii-predicate-guard.d.ts +43 -23
- package/dist/cjs/cli/pii-predicate-guard.js +98 -37
- package/dist/cjs/cli/prisma-resolve.js +17 -13
- package/dist/cjs/cli/prisma-schema.js +12 -4
- package/dist/cjs/cli/studio-ui.generated.js +1 -1
- package/dist/cjs/cli/studio.d.ts +14 -2
- package/dist/cjs/cli/studio.js +244 -69
- package/dist/cjs/cli/ui.d.ts +1 -1
- package/dist/cjs/client.d.ts +558 -85
- package/dist/cjs/client.js +1270 -395
- package/dist/cjs/connection-guard.d.ts +13 -0
- package/dist/cjs/connection-guard.js +28 -0
- package/dist/cjs/connection-url.d.ts +51 -16
- package/dist/cjs/connection-url.js +67 -34
- package/dist/cjs/diagnostics.d.ts +81 -0
- package/dist/cjs/diagnostics.js +147 -0
- package/dist/cjs/dialect.d.ts +449 -20
- package/dist/cjs/dialect.js +117 -76
- package/dist/cjs/engine-config.d.ts +7 -6
- package/dist/cjs/errors.d.ts +126 -6
- package/dist/cjs/errors.js +256 -13
- package/dist/cjs/generate.d.ts +57 -7
- package/dist/cjs/generate.js +635 -279
- package/dist/cjs/global-filters-config.d.ts +59 -0
- package/dist/cjs/global-filters-config.js +367 -0
- package/dist/cjs/index.d.ts +9 -4
- package/dist/cjs/index.js +10 -2
- package/dist/cjs/introspect.d.ts +31 -6
- package/dist/cjs/introspect.js +108 -50
- package/dist/cjs/log-codes.d.ts +12 -0
- package/dist/cjs/log-codes.js +77 -0
- package/dist/cjs/logger.d.ts +87 -0
- package/dist/cjs/logger.js +98 -0
- package/dist/cjs/mssql.d.ts +8 -5
- package/dist/cjs/mssql.js +352 -65
- package/dist/cjs/mysql.d.ts +3 -5
- package/dist/cjs/mysql.js +420 -70
- package/dist/cjs/nested-write.d.ts +3 -0
- package/dist/cjs/nested-write.js +179 -114
- package/dist/cjs/pipeline-submittable.d.ts +12 -0
- package/dist/cjs/pipeline-submittable.js +118 -44
- package/dist/cjs/pipeline.js +21 -26
- package/dist/cjs/powdb-introspect.d.ts +5 -2
- package/dist/cjs/powdb-introspect.js +20 -15
- package/dist/cjs/powdb-shared.d.ts +36 -5
- package/dist/cjs/powdb-shared.js +67 -8
- package/dist/cjs/powdb.d.ts +4 -0
- package/dist/cjs/powdb.js +183 -51
- package/dist/cjs/powql.d.ts +394 -51
- package/dist/cjs/powql.js +1829 -284
- package/dist/cjs/prisma-compat.d.ts +23 -15
- package/dist/cjs/prisma-compat.js +507 -372
- package/dist/cjs/query/aggregates.d.ts +17 -1
- package/dist/cjs/query/aggregates.js +261 -29
- package/dist/cjs/query/batched-loader.d.ts +25 -6
- package/dist/cjs/query/batched-loader.js +103 -20
- package/dist/cjs/query/builder.d.ts +325 -184
- package/dist/cjs/query/builder.js +1452 -490
- package/dist/cjs/query/column-ref.d.ts +61 -0
- package/dist/cjs/query/column-ref.js +73 -0
- package/dist/cjs/query/compound-unique.d.ts +21 -0
- package/dist/cjs/query/compound-unique.js +98 -18
- package/dist/cjs/query/deferred.d.ts +53 -16
- package/dist/cjs/query/expr.d.ts +217 -0
- package/dist/cjs/query/expr.js +859 -0
- package/dist/cjs/query/filters.d.ts +155 -53
- package/dist/cjs/query/filters.js +613 -76
- package/dist/cjs/query/index.d.ts +2 -0
- package/dist/cjs/query/index.js +7 -1
- package/dist/cjs/query/json-value.d.ts +43 -0
- package/dist/cjs/query/json-value.js +59 -0
- package/dist/cjs/query/normalize-args.d.ts +87 -0
- package/dist/cjs/query/normalize-args.js +527 -0
- package/dist/cjs/query/option-surface.d.ts +16 -4
- package/dist/cjs/query/option-surface.js +57 -14
- package/dist/cjs/query/relation-names.d.ts +14 -0
- package/dist/cjs/query/relation-names.js +77 -18
- package/dist/cjs/query/relations.d.ts +30 -3
- package/dist/cjs/query/relations.js +219 -63
- package/dist/cjs/query/row-lock.d.ts +49 -0
- package/dist/cjs/query/row-lock.js +138 -0
- package/dist/cjs/query/sql-comment.d.ts +161 -0
- package/dist/cjs/query/sql-comment.js +381 -0
- package/dist/cjs/query/stream-idle.d.ts +132 -0
- package/dist/cjs/query/stream-idle.js +212 -0
- package/dist/cjs/query/table-client.d.ts +101 -0
- package/dist/cjs/query/table-client.js +74 -0
- package/dist/cjs/query/types.d.ts +677 -298
- package/dist/cjs/query/utils.d.ts +105 -6
- package/dist/cjs/query/utils.js +426 -19
- package/dist/cjs/query/warn-registry.d.ts +18 -0
- package/dist/cjs/query/warn-registry.js +18 -0
- package/dist/cjs/query/where-compile.d.ts +138 -14
- package/dist/cjs/query/where-compile.js +513 -29
- package/dist/cjs/query/where.d.ts +159 -59
- package/dist/cjs/query/where.js +716 -246
- package/dist/cjs/query/writes.d.ts +112 -50
- package/dist/cjs/query/writes.js +1498 -200
- package/dist/cjs/query-events.d.ts +4 -2
- package/dist/cjs/query-events.js +3 -1
- package/dist/cjs/realtime.d.ts +7 -3
- package/dist/cjs/realtime.js +13 -2
- package/dist/cjs/schema-builder.d.ts +55 -4
- package/dist/cjs/schema-builder.js +382 -18
- package/dist/cjs/schema-metadata.d.ts +21 -1
- package/dist/cjs/schema-metadata.js +29 -7
- package/dist/cjs/schema-sql.d.ts +75 -5
- package/dist/cjs/schema-sql.js +497 -45
- package/dist/cjs/schema.d.ts +26 -5
- package/dist/cjs/schema.js +110 -13
- package/dist/cjs/sql-placeholders.d.ts +56 -0
- package/dist/cjs/sql-placeholders.js +204 -0
- package/dist/cjs/sqlite.d.ts +75 -20
- package/dist/cjs/sqlite.js +593 -95
- package/dist/cjs/supplied-pool-types.d.ts +48 -0
- package/dist/cjs/supplied-pool-types.js +256 -0
- package/dist/cjs/transaction-control.d.ts +51 -0
- package/dist/cjs/transaction-control.js +316 -0
- package/dist/cjs/transaction-state.d.ts +342 -0
- package/dist/cjs/transaction-state.js +707 -0
- package/dist/cjs/typed-sql.d.ts +37 -3
- package/dist/cjs/typed-sql.js +102 -8
- package/dist/cli/code-first-tags.d.ts +62 -0
- package/dist/cli/code-first-tags.js +120 -0
- package/dist/cli/compile-query.js +9 -0
- package/dist/cli/config.d.ts +35 -6
- package/dist/cli/config.js +16 -1
- package/dist/cli/destructive.d.ts +7 -4
- package/dist/cli/destructive.js +224 -20
- package/dist/cli/error-catalog.js +36 -0
- package/dist/cli/error-text.d.ts +15 -0
- package/dist/cli/error-text.js +37 -0
- package/dist/cli/index.d.ts +62 -4
- package/dist/cli/index.js +569 -112
- package/dist/cli/local-server-guard.d.ts +53 -0
- package/dist/cli/local-server-guard.js +113 -0
- package/dist/cli/local-server-output.d.ts +41 -0
- package/dist/cli/local-server-output.js +98 -0
- package/dist/cli/mcp.d.ts +8 -0
- package/dist/cli/mcp.js +121 -34
- package/dist/cli/migrate.d.ts +113 -5
- package/dist/cli/migrate.js +261 -21
- package/dist/cli/observe.d.ts +6 -1
- package/dist/cli/observe.js +84 -54
- package/dist/cli/pii-predicate-guard.d.ts +43 -23
- package/dist/cli/pii-predicate-guard.js +100 -35
- package/dist/cli/prisma-resolve.js +15 -11
- package/dist/cli/prisma-schema.js +12 -4
- package/dist/cli/studio-ui.generated.js +1 -1
- package/dist/cli/studio.d.ts +14 -2
- package/dist/cli/studio.js +246 -71
- package/dist/cli/ui.d.ts +1 -1
- package/dist/client.d.ts +558 -85
- package/dist/client.js +1275 -400
- package/dist/connection-guard.d.ts +13 -0
- package/dist/connection-guard.js +27 -0
- package/dist/connection-url.d.ts +51 -16
- package/dist/connection-url.js +63 -34
- package/dist/diagnostics.d.ts +81 -0
- package/dist/diagnostics.js +144 -0
- package/dist/dialect.d.ts +449 -20
- package/dist/dialect.js +115 -43
- package/dist/engine-config.d.ts +7 -6
- package/dist/errors.d.ts +126 -6
- package/dist/errors.js +252 -12
- package/dist/generate.d.ts +57 -7
- package/dist/generate.js +635 -281
- package/dist/global-filters-config.d.ts +59 -0
- package/dist/global-filters-config.js +361 -0
- package/dist/index.d.ts +9 -4
- package/dist/index.js +4 -2
- package/dist/introspect.d.ts +31 -6
- package/dist/introspect.js +106 -50
- package/dist/log-codes.d.ts +12 -0
- package/dist/log-codes.js +74 -0
- package/dist/logger.d.ts +87 -0
- package/dist/logger.js +93 -0
- package/dist/mssql.d.ts +8 -5
- package/dist/mssql.js +354 -67
- package/dist/mysql.d.ts +3 -5
- package/dist/mysql.js +423 -73
- package/dist/nested-write.d.ts +3 -0
- package/dist/nested-write.js +177 -112
- package/dist/pipeline-submittable.d.ts +12 -0
- package/dist/pipeline-submittable.js +117 -44
- package/dist/pipeline.js +21 -26
- package/dist/powdb-introspect.d.ts +5 -2
- package/dist/powdb-introspect.js +21 -16
- package/dist/powdb-shared.d.ts +36 -5
- package/dist/powdb-shared.js +65 -8
- package/dist/powdb.d.ts +4 -0
- package/dist/powdb.js +183 -51
- package/dist/powql.d.ts +394 -51
- package/dist/powql.js +1836 -291
- package/dist/prisma-compat.d.ts +23 -15
- package/dist/prisma-compat.js +508 -373
- package/dist/query/aggregates.d.ts +17 -1
- package/dist/query/aggregates.js +263 -32
- package/dist/query/batched-loader.d.ts +25 -6
- package/dist/query/batched-loader.js +101 -21
- package/dist/query/builder.d.ts +325 -184
- package/dist/query/builder.js +1458 -495
- package/dist/query/column-ref.d.ts +61 -0
- package/dist/query/column-ref.js +66 -0
- package/dist/query/compound-unique.d.ts +21 -0
- package/dist/query/compound-unique.js +97 -19
- package/dist/query/deferred.d.ts +53 -16
- package/dist/query/expr.d.ts +217 -0
- package/dist/query/expr.js +848 -0
- package/dist/query/filters.d.ts +155 -53
- package/dist/query/filters.js +597 -72
- package/dist/query/index.d.ts +2 -0
- package/dist/query/index.js +4 -0
- package/dist/query/json-value.d.ts +43 -0
- package/dist/query/json-value.js +54 -0
- package/dist/query/normalize-args.d.ts +87 -0
- package/dist/query/normalize-args.js +517 -0
- package/dist/query/option-surface.d.ts +16 -4
- package/dist/query/option-surface.js +56 -13
- package/dist/query/relation-names.d.ts +14 -0
- package/dist/query/relation-names.js +77 -19
- package/dist/query/relations.d.ts +30 -3
- package/dist/query/relations.js +220 -67
- package/dist/query/row-lock.d.ts +49 -0
- package/dist/query/row-lock.js +131 -0
- package/dist/query/sql-comment.d.ts +161 -0
- package/dist/query/sql-comment.js +374 -0
- package/dist/query/stream-idle.d.ts +132 -0
- package/dist/query/stream-idle.js +203 -0
- package/dist/query/table-client.d.ts +101 -0
- package/dist/query/table-client.js +70 -0
- package/dist/query/types.d.ts +677 -298
- package/dist/query/utils.d.ts +105 -6
- package/dist/query/utils.js +414 -18
- package/dist/query/warn-registry.d.ts +18 -0
- package/dist/query/warn-registry.js +18 -0
- package/dist/query/where-compile.d.ts +138 -14
- package/dist/query/where-compile.js +508 -31
- package/dist/query/where.d.ts +159 -59
- package/dist/query/where.js +711 -248
- package/dist/query/writes.d.ts +112 -50
- package/dist/query/writes.js +1496 -202
- package/dist/query-events.d.ts +4 -2
- package/dist/query-events.js +3 -1
- package/dist/realtime.d.ts +7 -3
- package/dist/realtime.js +13 -2
- package/dist/schema-builder.d.ts +55 -4
- package/dist/schema-builder.js +381 -18
- package/dist/schema-metadata.d.ts +21 -1
- package/dist/schema-metadata.js +28 -7
- package/dist/schema-sql.d.ts +75 -5
- package/dist/schema-sql.js +494 -44
- package/dist/schema.d.ts +26 -5
- package/dist/schema.js +109 -13
- package/dist/sql-placeholders.d.ts +56 -0
- package/dist/sql-placeholders.js +200 -0
- package/dist/sqlite.d.ts +75 -20
- package/dist/sqlite.js +597 -99
- package/dist/supplied-pool-types.d.ts +48 -0
- package/dist/supplied-pool-types.js +247 -0
- package/dist/transaction-control.d.ts +51 -0
- package/dist/transaction-control.js +311 -0
- package/dist/transaction-state.d.ts +342 -0
- package/dist/transaction-state.js +696 -0
- package/dist/typed-sql.d.ts +37 -3
- package/dist/typed-sql.js +100 -8
- package/package.json +7 -4
- package/skills/turbine-orm/SKILL.md +56 -6
package/dist/errors.js
CHANGED
|
@@ -25,6 +25,8 @@ export const TurbineErrorCode = {
|
|
|
25
25
|
EXCLUSION_VIOLATION: 'TURBINE_E016',
|
|
26
26
|
UNSUPPORTED_FEATURE: 'TURBINE_E017',
|
|
27
27
|
READ_ONLY: 'TURBINE_E018',
|
|
28
|
+
TRANSACTION_ROLLED_BACK: 'TURBINE_E019',
|
|
29
|
+
INVARIANT_VIOLATION: 'TURBINE_E020',
|
|
28
30
|
};
|
|
29
31
|
/**
|
|
30
32
|
* The docs page anchor for a code: `TURBINE_E003` -> `.../errors#e003`.
|
|
@@ -607,12 +609,14 @@ function renderWhereForMessage(where, mode) {
|
|
|
607
609
|
* `[TURBINE_E001] findUniqueOrThrow on "users" found no record matching where: {"id":1}`
|
|
608
610
|
*
|
|
609
611
|
* The full `where` object, `table`, and `operation` are always available as
|
|
610
|
-
* structured properties on the error instance regardless of mode.
|
|
612
|
+
* structured properties on the error instance regardless of mode. `where`
|
|
613
|
+
* carries the caller's raw values, so under 'safe' it is NON-ENUMERABLE:
|
|
614
|
+
* `err.where` reads it, while `JSON.stringify`, `util.inspect` and error
|
|
615
|
+
* serializers that copy own enumerable fields leave it out.
|
|
611
616
|
*/
|
|
612
617
|
export class NotFoundError extends TurbineError {
|
|
613
618
|
static CODE = TurbineErrorCode.NOT_FOUND;
|
|
614
619
|
table;
|
|
615
|
-
where;
|
|
616
620
|
operation;
|
|
617
621
|
constructor(input) {
|
|
618
622
|
// Back-compat: string argument (or undefined), replicate legacy behavior.
|
|
@@ -639,7 +643,12 @@ export class NotFoundError extends TurbineError {
|
|
|
639
643
|
super(TurbineErrorCode.NOT_FOUND, message, { cause });
|
|
640
644
|
this.name = 'NotFoundError';
|
|
641
645
|
this.table = table;
|
|
642
|
-
this
|
|
646
|
+
Object.defineProperty(this, 'where', {
|
|
647
|
+
value: where,
|
|
648
|
+
enumerable: currentErrorMessageMode() === 'verbose',
|
|
649
|
+
writable: false,
|
|
650
|
+
configurable: true,
|
|
651
|
+
});
|
|
643
652
|
this.operation = operation;
|
|
644
653
|
}
|
|
645
654
|
}
|
|
@@ -647,18 +656,22 @@ export class NotFoundError extends TurbineError {
|
|
|
647
656
|
export class TimeoutError extends TurbineError {
|
|
648
657
|
static CODE = TurbineErrorCode.TIMEOUT;
|
|
649
658
|
timeoutMs;
|
|
659
|
+
/** Whether the interrupted statement can have taken effect. See {@link TimeoutOutcome}. */
|
|
660
|
+
outcome;
|
|
650
661
|
/**
|
|
651
662
|
* @param timeoutMs the client-side timeout budget in ms. Pass `0` when the
|
|
652
663
|
* duration is unknown (e.g. a server-side `statement_timeout` cancellation
|
|
653
664
|
* surfaced via `wrapPgError`, where Turbine did not set the deadline).
|
|
654
665
|
* @param context human label for the operation ("Query", "Transaction").
|
|
655
666
|
* @param options optional `message` override and pg `cause` to preserve, used
|
|
656
|
-
* when wrapping a driver error rather than a client-side timer expiry
|
|
667
|
+
* when wrapping a driver error rather than a client-side timer expiry, and
|
|
668
|
+
* the `outcome` (default `'unknown'`, the only answer that is never wrong).
|
|
657
669
|
*/
|
|
658
670
|
constructor(timeoutMs, context = 'Query', options) {
|
|
659
671
|
super(TurbineErrorCode.TIMEOUT, options?.message ?? `${context} timed out after ${timeoutMs}ms`, options);
|
|
660
672
|
this.name = 'TimeoutError';
|
|
661
673
|
this.timeoutMs = timeoutMs;
|
|
674
|
+
this.outcome = options?.outcome ?? 'unknown';
|
|
662
675
|
}
|
|
663
676
|
}
|
|
664
677
|
/** Thrown when query arguments fail validation (unknown column, invalid operator, etc.) */
|
|
@@ -948,6 +961,74 @@ export class SerializationFailureError extends TurbineError {
|
|
|
948
961
|
this.name = 'SerializationFailureError';
|
|
949
962
|
}
|
|
950
963
|
}
|
|
964
|
+
/** Marks a {@link LockNotAvailableError} across copies of this module (it shares E013 with its parent). */
|
|
965
|
+
const LOCK_NOT_AVAILABLE_BRAND = Symbol.for('turbine-orm.lockNotAvailable');
|
|
966
|
+
/**
|
|
967
|
+
* A row lock could not be taken. A locking read with `noWait` found a row
|
|
968
|
+
* locked by another transaction (PostgreSQL 55P03, MySQL 3572), or a lock wait
|
|
969
|
+
* outlasted the server's lock timeout (PostgreSQL 55P03 under `lock_timeout`,
|
|
970
|
+
* MySQL 1205, SQL Server 1222).
|
|
971
|
+
*
|
|
972
|
+
* A {@link SerializationFailureError}: same code (E013) and `isRetryable`, so
|
|
973
|
+
* code that already retries E013 retries this too. Retry after a backoff, or
|
|
974
|
+
* read with `skipLocked` to move on to the rows that are free.
|
|
975
|
+
*
|
|
976
|
+
* On PostgreSQL the failed statement aborts the transaction it ran in. To keep
|
|
977
|
+
* the outer transaction alive, take the lock in a nested `tx.$transaction(...)`
|
|
978
|
+
* (a savepoint) and catch the error outside it.
|
|
979
|
+
*/
|
|
980
|
+
export class LockNotAvailableError extends SerializationFailureError {
|
|
981
|
+
constructor(opts = {}) {
|
|
982
|
+
const { cause } = opts;
|
|
983
|
+
let message = opts.message;
|
|
984
|
+
if (!message) {
|
|
985
|
+
const driverMessage = cause?.message;
|
|
986
|
+
message =
|
|
987
|
+
`Row lock not available${driverMessage ? `: ${driverMessage}` : ''}. Another transaction holds the lock. ` +
|
|
988
|
+
'Retry after a backoff, or read with skipLocked to take only the rows that are free.';
|
|
989
|
+
}
|
|
990
|
+
super({ message, cause });
|
|
991
|
+
this.name = 'LockNotAvailableError';
|
|
992
|
+
Object.defineProperty(this, LOCK_NOT_AVAILABLE_BRAND, {
|
|
993
|
+
value: true,
|
|
994
|
+
enumerable: false,
|
|
995
|
+
writable: false,
|
|
996
|
+
configurable: false,
|
|
997
|
+
});
|
|
998
|
+
}
|
|
999
|
+
/**
|
|
1000
|
+
* `instanceof` across two copies of this module. The code alone cannot tell
|
|
1001
|
+
* this class from its parent (both E013), so another copy's instance must
|
|
1002
|
+
* also carry this class's own brand. A caller's subclass answers only for
|
|
1003
|
+
* its own instances, as {@link TurbineError[Symbol.hasInstance]} does.
|
|
1004
|
+
*/
|
|
1005
|
+
static [Symbol.hasInstance](value) {
|
|
1006
|
+
// biome-ignore lint/complexity/noThisInStatic: the receiver may be a caller's subclass, see TurbineError
|
|
1007
|
+
// biome-ignore lint/complexity/noUselessThisAlias: one alias carries one suppression
|
|
1008
|
+
const cls = this;
|
|
1009
|
+
if (Function.prototype[Symbol.hasInstance].call(cls, value))
|
|
1010
|
+
return true;
|
|
1011
|
+
if (cls !== LockNotAvailableError)
|
|
1012
|
+
return false;
|
|
1013
|
+
return (SerializationFailureError[Symbol.hasInstance](value) &&
|
|
1014
|
+
value[LOCK_NOT_AVAILABLE_BRAND] === true);
|
|
1015
|
+
}
|
|
1016
|
+
}
|
|
1017
|
+
/**
|
|
1018
|
+
* A lock that could not be taken: PostgreSQL 55P03 (`NOWAIT`, or
|
|
1019
|
+
* `lock_timeout`), MySQL 3572 (`NOWAIT`) and 1205 (lock wait timeout), SQL
|
|
1020
|
+
* Server 1222 (lock request timeout). The MySQL and SQL Server shapes arrive
|
|
1021
|
+
* with `.code` already set to 40001 by their engine modules, so the driver's
|
|
1022
|
+
* own number decides.
|
|
1023
|
+
*/
|
|
1024
|
+
function isLockNotAvailableError(err, code) {
|
|
1025
|
+
if (code === '55P03' || code === 'ER_LOCK_NOWAIT')
|
|
1026
|
+
return true;
|
|
1027
|
+
const e = err;
|
|
1028
|
+
if (e.errno === 3572)
|
|
1029
|
+
return true;
|
|
1030
|
+
return code === '40001' && (e.errno === 1205 || e.number === 1222);
|
|
1031
|
+
}
|
|
951
1032
|
/** Thrown when a CHECK constraint is violated (pg code 23514) */
|
|
952
1033
|
export class CheckConstraintError extends TurbineError {
|
|
953
1034
|
static CODE = TurbineErrorCode.CHECK_VIOLATION;
|
|
@@ -1114,23 +1195,111 @@ export class ReadOnlyError extends TurbineError {
|
|
|
1114
1195
|
* fail-fast flag), so NOTHING can write here and writes must route to the
|
|
1115
1196
|
* primary. `'rbac'`: the database is writable but THIS connection's role may
|
|
1116
1197
|
* not write (per-connection permission), so re-authenticating may suffice.
|
|
1198
|
+
* `'transaction'`: the transaction is read-only (`$transaction({ readOnly:
|
|
1199
|
+
* true })`, `BEGIN READ ONLY`, or a read replica, where every transaction
|
|
1200
|
+
* is), so the write belongs in a read-write transaction on the primary.
|
|
1117
1201
|
*/
|
|
1118
1202
|
reason;
|
|
1119
1203
|
/**
|
|
1120
1204
|
* @param detail human-readable description of the refused write (the engine
|
|
1121
|
-
* message, or a local fail-fast description). A
|
|
1122
|
-
*
|
|
1205
|
+
* message, or a local fail-fast description). A hint naming where the
|
|
1206
|
+
* write belongs is always appended.
|
|
1123
1207
|
* @param options optional driver `cause` to preserve when wrapping a refusal,
|
|
1124
1208
|
* and the refusal `reason` (default `'snapshot'`).
|
|
1125
1209
|
*/
|
|
1126
1210
|
constructor(detail, options) {
|
|
1127
|
-
|
|
1211
|
+
const reason = options?.reason ?? 'snapshot';
|
|
1212
|
+
super(TurbineErrorCode.READ_ONLY, `${detail} ${READ_ONLY_HINTS[reason]}`, {
|
|
1128
1213
|
cause: options?.cause,
|
|
1129
1214
|
});
|
|
1130
1215
|
this.name = 'ReadOnlyError';
|
|
1131
|
-
this.reason =
|
|
1216
|
+
this.reason = reason;
|
|
1132
1217
|
}
|
|
1133
1218
|
}
|
|
1219
|
+
const READ_ONLY_HINTS = {
|
|
1220
|
+
snapshot: 'Route writes to a writable primary.',
|
|
1221
|
+
rbac: 'Route writes to a writable primary.',
|
|
1222
|
+
transaction: 'Run the write in a read-write transaction (not `readOnly: true` or BEGIN READ ONLY) on the primary, ' +
|
|
1223
|
+
'not a read replica.',
|
|
1224
|
+
};
|
|
1225
|
+
/**
|
|
1226
|
+
* Thrown when work the caller expected to be saved was rolled back instead:
|
|
1227
|
+
* a `$transaction` or `transaction()` whose COMMIT the server answered with
|
|
1228
|
+
* ROLLBACK, a transaction that cannot commit because a statement inside it was
|
|
1229
|
+
* cut short by its `timeout`, or a nested `tx.$transaction(...)` block that
|
|
1230
|
+
* could not be kept for the same reasons.
|
|
1231
|
+
*
|
|
1232
|
+
* PostgreSQL aborts a transaction at its first error. Catching that error
|
|
1233
|
+
* inside the callback does not undo the abort, so the callback returns, the
|
|
1234
|
+
* COMMIT ends as a ROLLBACK, and none of the transaction's writes are saved.
|
|
1235
|
+
* The first failure is attached as `cause`. Nothing was committed, so the
|
|
1236
|
+
* whole transaction can be run again once the cause is dealt with; to keep the
|
|
1237
|
+
* rest of the work after an expected failure, run the statement that can fail
|
|
1238
|
+
* in its own nested `tx.$transaction(...)`.
|
|
1239
|
+
*
|
|
1240
|
+
* NOT retryable on its own: the failure that caused it is not known to be
|
|
1241
|
+
* transient. When that first failure WAS a deadlock or a serialization
|
|
1242
|
+
* conflict, the retryable class (`DeadlockError`, `SerializationFailureError`)
|
|
1243
|
+
* is thrown instead, so `$retry` re-runs the transaction.
|
|
1244
|
+
*/
|
|
1245
|
+
export class TransactionRolledBackError extends TurbineError {
|
|
1246
|
+
static CODE = TurbineErrorCode.TRANSACTION_ROLLED_BACK;
|
|
1247
|
+
/**
|
|
1248
|
+
* @param message what was rolled back and how to keep the work next time.
|
|
1249
|
+
* @param options the first failure inside the transaction, as `cause`.
|
|
1250
|
+
*/
|
|
1251
|
+
constructor(message, options) {
|
|
1252
|
+
super(TurbineErrorCode.TRANSACTION_ROLLED_BACK, message, options);
|
|
1253
|
+
this.name = 'TransactionRolledBackError';
|
|
1254
|
+
}
|
|
1255
|
+
}
|
|
1256
|
+
/**
|
|
1257
|
+
* The sentence every {@link InvariantError} message ends with, before the docs
|
|
1258
|
+
* link. Exported so a test can assert it without restating it.
|
|
1259
|
+
*/
|
|
1260
|
+
export const INVARIANT_REPORT_HINT = 'This is a bug in turbine-orm, not in your code. Please report it at ' +
|
|
1261
|
+
'https://github.com/zvndev/turbine-orm/issues with this message.';
|
|
1262
|
+
/**
|
|
1263
|
+
* Turbine detected a bug in itself: a branch that no argument can reach was
|
|
1264
|
+
* reached, or two internal paths that must agree did not (the SQL-template
|
|
1265
|
+
* cache's build and param-collect paths, for example).
|
|
1266
|
+
*
|
|
1267
|
+
* Not caused by the arguments, so rewriting the call is not the fix, and not
|
|
1268
|
+
* retryable: the same call fails the same way. `invariant` is a stable id for
|
|
1269
|
+
* the broken rule (`'sql-cache-lockstep'`, `'sql-cache-param-count'`, ...), so
|
|
1270
|
+
* a report or an alert can group on it. The message names no row or parameter
|
|
1271
|
+
* value.
|
|
1272
|
+
*
|
|
1273
|
+
* Thrown in place of executing a statement Turbine knows is wrong, which is
|
|
1274
|
+
* what makes the checks behind it safe to run in production.
|
|
1275
|
+
*/
|
|
1276
|
+
export class InvariantError extends TurbineError {
|
|
1277
|
+
static CODE = TurbineErrorCode.INVARIANT_VIOLATION;
|
|
1278
|
+
/** Stable id of the broken invariant, e.g. `'sql-cache-lockstep'`. */
|
|
1279
|
+
invariant;
|
|
1280
|
+
/**
|
|
1281
|
+
* @param invariant stable id of the broken rule.
|
|
1282
|
+
* @param message what disagreed, with no row or parameter value in it. The
|
|
1283
|
+
* report hint is appended once.
|
|
1284
|
+
* @param options the error that exposed the broken rule, as `cause`.
|
|
1285
|
+
*/
|
|
1286
|
+
constructor(invariant, message, options) {
|
|
1287
|
+
const body = message.includes(INVARIANT_REPORT_HINT) ? message : `${message} ${INVARIANT_REPORT_HINT}`;
|
|
1288
|
+
super(TurbineErrorCode.INVARIANT_VIOLATION, body, options);
|
|
1289
|
+
this.name = 'InvariantError';
|
|
1290
|
+
this.invariant = invariant;
|
|
1291
|
+
}
|
|
1292
|
+
}
|
|
1293
|
+
/**
|
|
1294
|
+
* A write refused because its transaction is read-only: PostgreSQL SQLSTATE
|
|
1295
|
+
* 25006, or MySQL's error 1792 (which carries the same SQLSTATE).
|
|
1296
|
+
*/
|
|
1297
|
+
function isReadOnlyTransactionError(err, code) {
|
|
1298
|
+
if (code === '25006' || code === 'ER_CANT_EXECUTE_IN_READ_ONLY_TRANSACTION')
|
|
1299
|
+
return true;
|
|
1300
|
+
const e = err;
|
|
1301
|
+
return e.errno === 1792 && e.sqlState === '25006';
|
|
1302
|
+
}
|
|
1134
1303
|
/**
|
|
1135
1304
|
* Parse column names out of a pg `detail` string like:
|
|
1136
1305
|
* "Key (email)=(foo@bar) already exists."
|
|
@@ -1162,6 +1331,11 @@ const CONNECTION_ERROR_CODES = new Set([
|
|
|
1162
1331
|
'08006', // connection_failure
|
|
1163
1332
|
'08007', // transaction_resolution_unknown
|
|
1164
1333
|
'08P01', // protocol_violation
|
|
1334
|
+
// A named prepared statement met a server connection that did not prepare it
|
|
1335
|
+
// (26000) or already holds it (42P05). Turbine names its own statements, so
|
|
1336
|
+
// the usual cause is a transaction-pooling endpoint switching backends.
|
|
1337
|
+
'42P05', // duplicate_prepared_statement
|
|
1338
|
+
'26000', // invalid_sql_statement_name
|
|
1165
1339
|
// pg SQLSTATE class 28: the server answered and REFUSED us. These are the
|
|
1166
1340
|
// most common first-run failures there are (wrong password, a pg_hba rule
|
|
1167
1341
|
// that does not cover this user/host), and they used to fall through
|
|
@@ -1181,6 +1355,11 @@ const CONNECTION_ERROR_CODES = new Set([
|
|
|
1181
1355
|
'57P01', // admin_shutdown
|
|
1182
1356
|
'57P02', // crash_shutdown
|
|
1183
1357
|
'57P03', // cannot_connect_now
|
|
1358
|
+
// The server ended a session that sat idle inside an open transaction past
|
|
1359
|
+
// idle_in_transaction_session_timeout (a FATAL: the connection is gone).
|
|
1360
|
+
// A cursor stream sets that limit on its own transaction, see
|
|
1361
|
+
// query/stream-idle.ts, so this is how a frozen process's stream ends.
|
|
1362
|
+
'25P03', // idle_in_transaction_session_timeout
|
|
1184
1363
|
// Node driver-level socket errors (surface on err.code too)
|
|
1185
1364
|
'ECONNREFUSED',
|
|
1186
1365
|
'ECONNRESET',
|
|
@@ -1220,6 +1399,11 @@ const PG_CONNECTION_LOSS_MESSAGES = new Set([
|
|
|
1220
1399
|
'Connection terminated',
|
|
1221
1400
|
'Connection terminated due to connection timeout',
|
|
1222
1401
|
]);
|
|
1402
|
+
/** pg-pool's own words for a checkout that waited longer than `connectionTimeoutMillis`. */
|
|
1403
|
+
const PG_POOL_CHECKOUT_TIMEOUT_MESSAGE = 'timeout exceeded when trying to connect';
|
|
1404
|
+
const POOL_CHECKOUT_TIMEOUT_HINT = "Timed out waiting for a free connection from the pool. Something is holding connections for longer than the pool's " +
|
|
1405
|
+
'connection timeout: long transactions or streams, or a query on the outer client inside a `$transaction` ' +
|
|
1406
|
+
'callback, which needs a second connection (use `tx` there). Raise the pool size if the load is genuine.';
|
|
1223
1407
|
/** The follow-on errors pg raises for a query sent to a client already known to be dead. */
|
|
1224
1408
|
const PG_NOT_QUERYABLE_MESSAGES = new Set([
|
|
1225
1409
|
'Client has encountered a connection error and is not queryable',
|
|
@@ -1278,6 +1462,11 @@ export function isStaleConnectionError(err) {
|
|
|
1278
1462
|
}
|
|
1279
1463
|
const CONNECTION_LOSS_HINT = 'The server or the network closed it (a restart, failover, idle timeout, compute suspend, or ' +
|
|
1280
1464
|
'pg_terminate_backend). The pool discards the connection, so retrying the operation opens a fresh one.';
|
|
1465
|
+
const PREPARED_STATEMENT_POOLER_HINT = 'A named prepared statement met a server connection that did not prepare it, or that already holds it. A ' +
|
|
1466
|
+
'transaction-pooling endpoint (PgBouncer in transaction mode, a managed "-pooler" host, port 6432 or 6543) ' +
|
|
1467
|
+
'gives each transaction to a different server connection, which is the usual cause. Connect to the direct ' +
|
|
1468
|
+
'endpoint, set `preparedStatements: false`, or turn on prepared-statement support in the pooler (PgBouncer ' +
|
|
1469
|
+
'1.21 or later, `max_prepared_statements` above 0).';
|
|
1281
1470
|
/**
|
|
1282
1471
|
* Actionable next step per connection-class code, appended to the driver's own
|
|
1283
1472
|
* message. The driver message states WHAT happened ("password authentication
|
|
@@ -1287,11 +1476,18 @@ const CONNECTION_LOSS_HINT = 'The server or the network closed it (a restart, fa
|
|
|
1287
1476
|
* A code with no entry here simply gets no hint appended.
|
|
1288
1477
|
*/
|
|
1289
1478
|
const CONNECTION_ERROR_HINTS = {
|
|
1479
|
+
'42P05': PREPARED_STATEMENT_POOLER_HINT,
|
|
1480
|
+
'26000': PREPARED_STATEMENT_POOLER_HINT,
|
|
1290
1481
|
'28P01': 'The server rejected the credentials. Check the password in your connection string (or DATABASE_URL), including any URL-encoding of special characters.',
|
|
1291
1482
|
'28000': "The server refused this user/host combination. Check the user name and the server's pg_hba.conf rules for the client address.",
|
|
1292
1483
|
'3D000': 'The database named in the connection string does not exist. Check the path segment after the host, and create the database if needed.',
|
|
1293
1484
|
'53300': "The server has no free connection slots. Lower `poolSize` or raise the server's max_connections.",
|
|
1294
1485
|
'57P03': 'The server is still starting up (or shutting down) and is not accepting connections yet.',
|
|
1486
|
+
'25P03': 'The server ended the session because it sat idle inside an open transaction for longer than ' +
|
|
1487
|
+
'`idle_in_transaction_session_timeout`. A cursor stream sets that limit to its idle timeout plus 10 s, so for ' +
|
|
1488
|
+
'a stream this means the process ran nothing for that long (a frozen serverless instance, a blocked event ' +
|
|
1489
|
+
'loop); for a transaction, that the callback awaited something else for longer than the server allows. The ' +
|
|
1490
|
+
'connection is discarded and the pool opens a fresh one.',
|
|
1295
1491
|
ECONNREFUSED: 'Nothing is listening on that host and port. Check the server is running and the port is right.',
|
|
1296
1492
|
ENOTFOUND: 'The host in the connection string could not be resolved. Check the host name, and that the connection string itself is well formed.',
|
|
1297
1493
|
EAI_AGAIN: 'DNS lookup for the host failed temporarily. Check network/DNS availability, then retry.',
|
|
@@ -1523,9 +1719,13 @@ function scrubUnclassifiedServerError(err, code) {
|
|
|
1523
1719
|
* 23P01 (exclusion_violation) -> ExclusionConstraintError
|
|
1524
1720
|
* 40P01 (deadlock_detected) -> DeadlockError (retryable)
|
|
1525
1721
|
* 40001 (serialization_failure) -> SerializationFailureError (retryable)
|
|
1722
|
+
* 55P03 (lock_not_available) -> LockNotAvailableError (retryable, E013); also
|
|
1723
|
+
* MySQL 3572 / 1205 and SQL Server 1222
|
|
1526
1724
|
* 57014 (query_canceled) -> TimeoutError (server-side statement_timeout)
|
|
1527
1725
|
* 28P01 / 28000 (auth refused) -> ConnectionError, with a remediation hint
|
|
1528
1726
|
* 3D000 (no such database) -> ConnectionError, with a remediation hint
|
|
1727
|
+
* 42P05 / 26000 (prepared statement name clash or miss, a transaction-mode
|
|
1728
|
+
* pooler) -> ConnectionError, with a remediation hint
|
|
1529
1729
|
* connection-class codes -> ConnectionError (see CONNECTION_ERROR_CODES)
|
|
1530
1730
|
* 22xxx (data exception) -> ValidationError naming the column (when the
|
|
1531
1731
|
* server did) and the SQLSTATE; driver text
|
|
@@ -1554,8 +1754,26 @@ export function wrapPgError(err) {
|
|
|
1554
1754
|
if (err instanceof Error && PG_CONNECTION_LOSS_MESSAGES.has(err.message)) {
|
|
1555
1755
|
return new ConnectionError(`Database connection lost: ${err.message}. ${CONNECTION_LOSS_HINT}`, { cause: err });
|
|
1556
1756
|
}
|
|
1757
|
+
// pg-pool's checkout timeout carries no code either. A pool Turbine owns
|
|
1758
|
+
// types it at checkout (checkout.ts); this covers a caller's own pg.Pool.
|
|
1759
|
+
if (err instanceof Error && err.message === PG_POOL_CHECKOUT_TIMEOUT_MESSAGE) {
|
|
1760
|
+
return new ConnectionError(POOL_CHECKOUT_TIMEOUT_HINT, { cause: err });
|
|
1761
|
+
}
|
|
1557
1762
|
return err;
|
|
1558
1763
|
}
|
|
1764
|
+
if (isReadOnlyTransactionError(err, e.code)) {
|
|
1765
|
+
const pgMessage = typeof e.message === 'string' && e.message.length > 0 ? e.message : 'write refused';
|
|
1766
|
+
return new ReadOnlyError(`${pgMessage} (SQLSTATE 25006).`, { cause: err, reason: 'transaction' });
|
|
1767
|
+
}
|
|
1768
|
+
if (isLockNotAvailableError(err, e.code))
|
|
1769
|
+
return new LockNotAvailableError({ cause: err });
|
|
1770
|
+
// A protocol violation answered with ERROR rather than FATAL concerns one
|
|
1771
|
+
// message, and the connection stays usable. The common cause is a Buffer
|
|
1772
|
+
// bound to a column that is not bytea: node-postgres sends a Buffer as
|
|
1773
|
+
// binary data, which the server cannot read as an integer or a date.
|
|
1774
|
+
if (e.code === '08P01' && e.severity === 'ERROR') {
|
|
1775
|
+
return wrapValueBearingPgError(err, e, 'Invalid input', 'a bound value could not be read as the type the statement expects', ' A Buffer is sent as binary data and fits only a bytea column; pass a number, string or Date for any other type.');
|
|
1776
|
+
}
|
|
1559
1777
|
switch (e.code) {
|
|
1560
1778
|
case '23505': {
|
|
1561
1779
|
const cols = e.detail ? parseColumnsFromDetail(e.detail) : undefined;
|
|
@@ -1600,13 +1818,27 @@ export function wrapPgError(err) {
|
|
|
1600
1818
|
cause: err,
|
|
1601
1819
|
});
|
|
1602
1820
|
case '57014':
|
|
1603
|
-
// query_canceled:
|
|
1604
|
-
//
|
|
1605
|
-
//
|
|
1821
|
+
// query_canceled: the statement was stopped, so it made no change. A
|
|
1822
|
+
// cancel request (what Turbine sends when a query or transaction
|
|
1823
|
+
// `timeout` expires) reads "due to user request"; anything else is the
|
|
1824
|
+
// server's own statement_timeout.
|
|
1606
1825
|
return new TimeoutError(0, 'Query', {
|
|
1607
|
-
message: '
|
|
1826
|
+
message: typeof e.message === 'string' && /user request/i.test(e.message)
|
|
1827
|
+
? 'Query cancelled on the server by a cancel request, which Turbine sends when a query or ' +
|
|
1828
|
+
'transaction `timeout` expires. It made no change.'
|
|
1829
|
+
: 'Query canceled by server-side statement_timeout',
|
|
1608
1830
|
cause: err,
|
|
1831
|
+
outcome: 'not-executed',
|
|
1609
1832
|
});
|
|
1833
|
+
case '25P02':
|
|
1834
|
+
// in_failed_sql_transaction: a statement sent after an earlier one failed. Turbine's own
|
|
1835
|
+
// transactions refuse it first, with the failure attached (transaction-state.ts); this is
|
|
1836
|
+
// the driver's answer on a path that sent it anyway (a connection used outside Turbine).
|
|
1837
|
+
return new TransactionRolledBackError('A statement was sent after an earlier statement in the same transaction failed. PostgreSQL ignores ' +
|
|
1838
|
+
'every statement after a failure until the transaction, or the savepoint it ran in, is rolled back, ' +
|
|
1839
|
+
'so nothing more can be saved in it. Catching the error does not undo the abort: let it leave the ' +
|
|
1840
|
+
'transaction, or run the statement that can fail in its own nested `tx.$transaction(...)`, which ' +
|
|
1841
|
+
'rolls back only that savepoint. The earlier failure is the error that statement threw.', { cause: err });
|
|
1610
1842
|
default:
|
|
1611
1843
|
if (CONNECTION_ERROR_CODES.has(e.code)) {
|
|
1612
1844
|
const pgMessage = typeof e.message === 'string' && e.message.length > 0 ? e.message : undefined;
|
|
@@ -1629,6 +1861,14 @@ export function wrapPgError(err) {
|
|
|
1629
1861
|
: DATA_EXCEPTION_FALLBACK;
|
|
1630
1862
|
return wrapValueBearingPgError(err, e, subject, phrase);
|
|
1631
1863
|
}
|
|
1864
|
+
// 42883: no operator or function for these argument types, e.g. a bigint
|
|
1865
|
+
// column compared with text. PostgreSQL's message names types, never
|
|
1866
|
+
// values, so it is kept in both modes.
|
|
1867
|
+
if (e.code === '42883') {
|
|
1868
|
+
const pgMessage = typeof e.message === 'string' && e.message.length > 0 ? `${e.message} ` : '';
|
|
1869
|
+
return new ValidationError(`${pgMessage}(SQLSTATE 42883). A value of one type was compared with or passed to something that takes ` +
|
|
1870
|
+
"another, usually a value bound to a column of a different type. Pass a value of the column's type.", { cause: err, sqlstate: e.code });
|
|
1871
|
+
}
|
|
1632
1872
|
// 42601 is any syntax error. Only the to_tsquery parse failure is a
|
|
1633
1873
|
// caller-input problem Turbine can name (the `search` operator), so the
|
|
1634
1874
|
// message text is the discriminator; every other 42601 takes the generic
|
package/dist/generate.d.ts
CHANGED
|
@@ -8,10 +8,36 @@
|
|
|
8
8
|
*
|
|
9
9
|
* Output goes to the specified directory (default: ./generated/turbine/).
|
|
10
10
|
*/
|
|
11
|
-
import { type
|
|
11
|
+
import { type TurbineLogger } from './logger.js';
|
|
12
|
+
import { type ColumnMetadata, type PrismaCompatMap, type SchemaMetadata } from './schema.js';
|
|
13
|
+
/**
|
|
14
|
+
* Per-column TypeScript overrides from {@link GenerateOptions.columnTypes},
|
|
15
|
+
* keyed by database table name, then database column name.
|
|
16
|
+
*/
|
|
17
|
+
type ColumnTypeOverrides = ReadonlyMap<string, ReadonlyMap<string, string>>;
|
|
18
|
+
/**
|
|
19
|
+
* Resolve the TypeScript type for a column, mapping enum-typed columns to their
|
|
20
|
+
* generated string-literal union (PascalCase enum name) instead of the
|
|
21
|
+
* `unknown` that {@link pgTypeToTs} yields for user-defined types. A
|
|
22
|
+
* `columnTypes` override replaces the type outright (nullability is still
|
|
23
|
+
* added). Falls back to the introspected `col.tsType` for everything else.
|
|
24
|
+
*/
|
|
25
|
+
export declare function columnTsType(col: ColumnMetadata, enums: Record<string, string[]>, override?: string): string;
|
|
26
|
+
/**
|
|
27
|
+
* Validate {@link GenerateOptions.columnTypes} against the schema and index it.
|
|
28
|
+
* A key naming no table or column is a `ValidationError`, not a silent no-op,
|
|
29
|
+
* since an override that applies to nothing leaves the column typed `unknown`.
|
|
30
|
+
*/
|
|
31
|
+
export declare function resolveColumnTypeOverrides(schema: SchemaMetadata, columnTypes: Readonly<Record<string, string>> | undefined): ColumnTypeOverrides | undefined;
|
|
12
32
|
export interface GenerateOptions {
|
|
13
33
|
/** The introspected schema to generate from */
|
|
14
34
|
schema: SchemaMetadata;
|
|
35
|
+
/**
|
|
36
|
+
* Where generation notes go (a relation omitted from the generated types
|
|
37
|
+
* because it shadows a column). Defaults to the console logger. Never
|
|
38
|
+
* affects the generated files.
|
|
39
|
+
*/
|
|
40
|
+
logger?: TurbineLogger;
|
|
15
41
|
/** Output directory (default: './generated/turbine') */
|
|
16
42
|
outDir?: string;
|
|
17
43
|
/** Redact connection string from generated comments */
|
|
@@ -36,6 +62,10 @@ export interface GenerateOptions {
|
|
|
36
62
|
*
|
|
37
63
|
* - `'js'`: always `./types.js` (required by NodeNext `tsc` and by
|
|
38
64
|
* tsc-compiled ESM run on Node; the pre-0.41 behavior).
|
|
65
|
+
* - `'ts'`: always `./types.ts`, so Node's native type stripping can run the
|
|
66
|
+
* generated files directly (`node app.ts`). A type checker needs
|
|
67
|
+
* `allowImportingTsExtensions` or `rewriteRelativeImportExtensions` to
|
|
68
|
+
* accept it. `'auto'` never picks this.
|
|
39
69
|
* - `'none'`: always `./types` (correct for bundlers / `moduleResolution
|
|
40
70
|
* bundler | node10`: webpack, Next.js/SWC, Vite/esbuild).
|
|
41
71
|
* - `'auto'` (default): walk up from `outDir` to the nearest `tsconfig.json`
|
|
@@ -44,7 +74,7 @@ export interface GenerateOptions {
|
|
|
44
74
|
* neither is, and fall back to `'.js'` when the tsconfig is missing,
|
|
45
75
|
* unparseable, or ambiguous (so NodeNext consumers can never regress).
|
|
46
76
|
*/
|
|
47
|
-
importExtension?: 'js' | 'none' | 'auto';
|
|
77
|
+
importExtension?: 'js' | 'ts' | 'none' | 'auto';
|
|
48
78
|
/**
|
|
49
79
|
* Rewrite generated column FIELD names to the raw database column names
|
|
50
80
|
* (snake_case) instead of camelCase (F4). Opt-in; when unset the output is
|
|
@@ -54,18 +84,36 @@ export interface GenerateOptions {
|
|
|
54
84
|
* names are unaffected.
|
|
55
85
|
*/
|
|
56
86
|
keepColumnNames?: boolean;
|
|
87
|
+
/**
|
|
88
|
+
* TypeScript types for specific columns, keyed `"<table>.<column>"` with
|
|
89
|
+
* database names. The value is emitted as written into the row type and the
|
|
90
|
+
* `*Create` / `*Update` input types (`| null` is added for a nullable
|
|
91
|
+
* column), so a json/jsonb column can carry its real shape instead of
|
|
92
|
+
* `unknown`:
|
|
93
|
+
*
|
|
94
|
+
* columnTypes: { 'users.settings': "import('../src/settings.js').Settings" }
|
|
95
|
+
*
|
|
96
|
+
* A relative `import()` resolves from the output directory. The type is a
|
|
97
|
+
* compile-time claim: nothing checks stored values against it. A key naming
|
|
98
|
+
* no table or column is an error.
|
|
99
|
+
*/
|
|
100
|
+
columnTypes?: Readonly<Record<string, string>>;
|
|
57
101
|
}
|
|
58
102
|
/** Per-file generator options (subset of {@link GenerateOptions} the emitters need). */
|
|
59
103
|
export interface GenerateFileOptions {
|
|
60
104
|
/** Omit the `Generated at:` header line for reproducible output. */
|
|
61
105
|
noTimestamp?: boolean;
|
|
62
106
|
/**
|
|
63
|
-
* Resolved sibling-import extension for `generateIndex` (`'.js'` or `''`).
|
|
107
|
+
* Resolved sibling-import extension for `generateIndex` (`'.js'`, `'.ts'` or `''`).
|
|
64
108
|
* Defaults to `'.js'` when unset so direct callers stay byte-stable.
|
|
65
109
|
*/
|
|
66
110
|
importExt?: string;
|
|
67
111
|
/** Human-readable resolved import mode, recorded as a comment in `index.ts`. */
|
|
68
112
|
importMode?: string;
|
|
113
|
+
/** {@link GenerateOptions.columnTypes}; validated against the schema by the emitter. */
|
|
114
|
+
columnTypes?: Readonly<Record<string, string>>;
|
|
115
|
+
/** {@link GenerateOptions.logger}. */
|
|
116
|
+
logger?: TurbineLogger;
|
|
69
117
|
}
|
|
70
118
|
export declare function generate(options: GenerateOptions): {
|
|
71
119
|
outDir: string;
|
|
@@ -77,12 +125,13 @@ export declare function generate(options: GenerateOptions): {
|
|
|
77
125
|
* mode label for the generated comment.
|
|
78
126
|
*
|
|
79
127
|
* - `'js'` → `.js`
|
|
128
|
+
* - `'ts'` → `.ts`
|
|
80
129
|
* - `'none'` → `''`
|
|
81
130
|
* - `'auto'` → tsconfig-driven ({@link detectTsconfigExtension}); falls back
|
|
82
131
|
* to `.js` (the pre-0.41 default) when detection is uncertain, so NodeNext
|
|
83
132
|
* consumers can never regress.
|
|
84
133
|
*/
|
|
85
|
-
export declare function resolveImportExtension(outDir: string, requested: 'js' | 'none' | 'auto'): {
|
|
134
|
+
export declare function resolveImportExtension(outDir: string, requested: 'js' | 'ts' | 'none' | 'auto'): {
|
|
86
135
|
ext: string;
|
|
87
136
|
mode: string;
|
|
88
137
|
};
|
|
@@ -137,10 +186,10 @@ export declare function isEmittableIdentifier(name: string): boolean;
|
|
|
137
186
|
export declare function assertEmittableSchema(schema: SchemaMetadata): void;
|
|
138
187
|
/**
|
|
139
188
|
* Generate the contents of `types.ts` (entity interfaces, *Create / *Update,
|
|
140
|
-
*
|
|
141
|
-
* generator output without writing files to disk.
|
|
189
|
+
* *Relations brand-field interfaces, and the write input types). Exported so
|
|
190
|
+
* tests can pin the generator output without writing files to disk.
|
|
142
191
|
*/
|
|
143
|
-
export declare function generateTypes(
|
|
192
|
+
export declare function generateTypes(input: SchemaMetadata, options?: GenerateFileOptions): string;
|
|
144
193
|
/**
|
|
145
194
|
* Generate the contents of `zod.ts`. Emits, per table, `XSchema` (the full
|
|
146
195
|
* row), `XCreateSchema` (PK/defaulted/nullable columns optional, STORED
|
|
@@ -161,3 +210,4 @@ export declare function generateIndex(schema: SchemaMetadata, options?: Generate
|
|
|
161
210
|
* stable input regenerates byte-identical output under `noTimestamp`.
|
|
162
211
|
*/
|
|
163
212
|
export declare function generatePrismaMap(map: PrismaCompatMap, options?: GenerateFileOptions): string;
|
|
213
|
+
export {};
|