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/cjs/errors.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.ReadOnlyError = exports.UnsupportedFeatureError = exports.OptimisticLockError = exports.PipelineError = exports.ExclusionConstraintError = exports.CheckConstraintError = exports.SerializationFailureError = exports.DeadlockError = exports.NotNullViolationError = exports.ForeignKeyError = exports.UniqueConstraintError = exports.CircularRelationError = exports.MigrationError = exports.RelationError = exports.ConnectionError = exports.ValidationError = exports.TimeoutError = exports.NotFoundError = exports.REDACTED_DETAIL = exports.TurbineError = exports.TurbineErrorCode = void 0;
|
|
3
|
+
exports.InvariantError = exports.INVARIANT_REPORT_HINT = exports.TransactionRolledBackError = exports.ReadOnlyError = exports.UnsupportedFeatureError = exports.OptimisticLockError = exports.PipelineError = exports.ExclusionConstraintError = exports.CheckConstraintError = exports.LockNotAvailableError = exports.SerializationFailureError = exports.DeadlockError = exports.NotNullViolationError = exports.ForeignKeyError = exports.UniqueConstraintError = exports.CircularRelationError = exports.MigrationError = exports.RelationError = exports.ConnectionError = exports.ValidationError = exports.TimeoutError = exports.NotFoundError = exports.REDACTED_DETAIL = exports.TurbineError = exports.TurbineErrorCode = void 0;
|
|
4
4
|
exports.registerClientErrorMessageMode = registerClientErrorMessageMode;
|
|
5
5
|
exports.errorMessageModesDiverged = errorMessageModesDiverged;
|
|
6
6
|
exports.runWithErrorMessageMode = runWithErrorMessageMode;
|
|
@@ -39,6 +39,8 @@ exports.TurbineErrorCode = {
|
|
|
39
39
|
EXCLUSION_VIOLATION: 'TURBINE_E016',
|
|
40
40
|
UNSUPPORTED_FEATURE: 'TURBINE_E017',
|
|
41
41
|
READ_ONLY: 'TURBINE_E018',
|
|
42
|
+
TRANSACTION_ROLLED_BACK: 'TURBINE_E019',
|
|
43
|
+
INVARIANT_VIOLATION: 'TURBINE_E020',
|
|
42
44
|
};
|
|
43
45
|
/**
|
|
44
46
|
* The docs page anchor for a code: `TURBINE_E003` -> `.../errors#e003`.
|
|
@@ -622,12 +624,14 @@ function renderWhereForMessage(where, mode) {
|
|
|
622
624
|
* `[TURBINE_E001] findUniqueOrThrow on "users" found no record matching where: {"id":1}`
|
|
623
625
|
*
|
|
624
626
|
* The full `where` object, `table`, and `operation` are always available as
|
|
625
|
-
* structured properties on the error instance regardless of mode.
|
|
627
|
+
* structured properties on the error instance regardless of mode. `where`
|
|
628
|
+
* carries the caller's raw values, so under 'safe' it is NON-ENUMERABLE:
|
|
629
|
+
* `err.where` reads it, while `JSON.stringify`, `util.inspect` and error
|
|
630
|
+
* serializers that copy own enumerable fields leave it out.
|
|
626
631
|
*/
|
|
627
632
|
class NotFoundError extends TurbineError {
|
|
628
633
|
static CODE = exports.TurbineErrorCode.NOT_FOUND;
|
|
629
634
|
table;
|
|
630
|
-
where;
|
|
631
635
|
operation;
|
|
632
636
|
constructor(input) {
|
|
633
637
|
// Back-compat: string argument (or undefined), replicate legacy behavior.
|
|
@@ -654,7 +658,12 @@ class NotFoundError extends TurbineError {
|
|
|
654
658
|
super(exports.TurbineErrorCode.NOT_FOUND, message, { cause });
|
|
655
659
|
this.name = 'NotFoundError';
|
|
656
660
|
this.table = table;
|
|
657
|
-
this
|
|
661
|
+
Object.defineProperty(this, 'where', {
|
|
662
|
+
value: where,
|
|
663
|
+
enumerable: currentErrorMessageMode() === 'verbose',
|
|
664
|
+
writable: false,
|
|
665
|
+
configurable: true,
|
|
666
|
+
});
|
|
658
667
|
this.operation = operation;
|
|
659
668
|
}
|
|
660
669
|
}
|
|
@@ -663,18 +672,22 @@ exports.NotFoundError = NotFoundError;
|
|
|
663
672
|
class TimeoutError extends TurbineError {
|
|
664
673
|
static CODE = exports.TurbineErrorCode.TIMEOUT;
|
|
665
674
|
timeoutMs;
|
|
675
|
+
/** Whether the interrupted statement can have taken effect. See {@link TimeoutOutcome}. */
|
|
676
|
+
outcome;
|
|
666
677
|
/**
|
|
667
678
|
* @param timeoutMs the client-side timeout budget in ms. Pass `0` when the
|
|
668
679
|
* duration is unknown (e.g. a server-side `statement_timeout` cancellation
|
|
669
680
|
* surfaced via `wrapPgError`, where Turbine did not set the deadline).
|
|
670
681
|
* @param context human label for the operation ("Query", "Transaction").
|
|
671
682
|
* @param options optional `message` override and pg `cause` to preserve, used
|
|
672
|
-
* when wrapping a driver error rather than a client-side timer expiry
|
|
683
|
+
* when wrapping a driver error rather than a client-side timer expiry, and
|
|
684
|
+
* the `outcome` (default `'unknown'`, the only answer that is never wrong).
|
|
673
685
|
*/
|
|
674
686
|
constructor(timeoutMs, context = 'Query', options) {
|
|
675
687
|
super(exports.TurbineErrorCode.TIMEOUT, options?.message ?? `${context} timed out after ${timeoutMs}ms`, options);
|
|
676
688
|
this.name = 'TimeoutError';
|
|
677
689
|
this.timeoutMs = timeoutMs;
|
|
690
|
+
this.outcome = options?.outcome ?? 'unknown';
|
|
678
691
|
}
|
|
679
692
|
}
|
|
680
693
|
exports.TimeoutError = TimeoutError;
|
|
@@ -975,6 +988,75 @@ class SerializationFailureError extends TurbineError {
|
|
|
975
988
|
}
|
|
976
989
|
}
|
|
977
990
|
exports.SerializationFailureError = SerializationFailureError;
|
|
991
|
+
/** Marks a {@link LockNotAvailableError} across copies of this module (it shares E013 with its parent). */
|
|
992
|
+
const LOCK_NOT_AVAILABLE_BRAND = Symbol.for('turbine-orm.lockNotAvailable');
|
|
993
|
+
/**
|
|
994
|
+
* A row lock could not be taken. A locking read with `noWait` found a row
|
|
995
|
+
* locked by another transaction (PostgreSQL 55P03, MySQL 3572), or a lock wait
|
|
996
|
+
* outlasted the server's lock timeout (PostgreSQL 55P03 under `lock_timeout`,
|
|
997
|
+
* MySQL 1205, SQL Server 1222).
|
|
998
|
+
*
|
|
999
|
+
* A {@link SerializationFailureError}: same code (E013) and `isRetryable`, so
|
|
1000
|
+
* code that already retries E013 retries this too. Retry after a backoff, or
|
|
1001
|
+
* read with `skipLocked` to move on to the rows that are free.
|
|
1002
|
+
*
|
|
1003
|
+
* On PostgreSQL the failed statement aborts the transaction it ran in. To keep
|
|
1004
|
+
* the outer transaction alive, take the lock in a nested `tx.$transaction(...)`
|
|
1005
|
+
* (a savepoint) and catch the error outside it.
|
|
1006
|
+
*/
|
|
1007
|
+
class LockNotAvailableError extends SerializationFailureError {
|
|
1008
|
+
constructor(opts = {}) {
|
|
1009
|
+
const { cause } = opts;
|
|
1010
|
+
let message = opts.message;
|
|
1011
|
+
if (!message) {
|
|
1012
|
+
const driverMessage = cause?.message;
|
|
1013
|
+
message =
|
|
1014
|
+
`Row lock not available${driverMessage ? `: ${driverMessage}` : ''}. Another transaction holds the lock. ` +
|
|
1015
|
+
'Retry after a backoff, or read with skipLocked to take only the rows that are free.';
|
|
1016
|
+
}
|
|
1017
|
+
super({ message, cause });
|
|
1018
|
+
this.name = 'LockNotAvailableError';
|
|
1019
|
+
Object.defineProperty(this, LOCK_NOT_AVAILABLE_BRAND, {
|
|
1020
|
+
value: true,
|
|
1021
|
+
enumerable: false,
|
|
1022
|
+
writable: false,
|
|
1023
|
+
configurable: false,
|
|
1024
|
+
});
|
|
1025
|
+
}
|
|
1026
|
+
/**
|
|
1027
|
+
* `instanceof` across two copies of this module. The code alone cannot tell
|
|
1028
|
+
* this class from its parent (both E013), so another copy's instance must
|
|
1029
|
+
* also carry this class's own brand. A caller's subclass answers only for
|
|
1030
|
+
* its own instances, as {@link TurbineError[Symbol.hasInstance]} does.
|
|
1031
|
+
*/
|
|
1032
|
+
static [Symbol.hasInstance](value) {
|
|
1033
|
+
// biome-ignore lint/complexity/noThisInStatic: the receiver may be a caller's subclass, see TurbineError
|
|
1034
|
+
// biome-ignore lint/complexity/noUselessThisAlias: one alias carries one suppression
|
|
1035
|
+
const cls = this;
|
|
1036
|
+
if (Function.prototype[Symbol.hasInstance].call(cls, value))
|
|
1037
|
+
return true;
|
|
1038
|
+
if (cls !== LockNotAvailableError)
|
|
1039
|
+
return false;
|
|
1040
|
+
return (SerializationFailureError[Symbol.hasInstance](value) &&
|
|
1041
|
+
value[LOCK_NOT_AVAILABLE_BRAND] === true);
|
|
1042
|
+
}
|
|
1043
|
+
}
|
|
1044
|
+
exports.LockNotAvailableError = LockNotAvailableError;
|
|
1045
|
+
/**
|
|
1046
|
+
* A lock that could not be taken: PostgreSQL 55P03 (`NOWAIT`, or
|
|
1047
|
+
* `lock_timeout`), MySQL 3572 (`NOWAIT`) and 1205 (lock wait timeout), SQL
|
|
1048
|
+
* Server 1222 (lock request timeout). The MySQL and SQL Server shapes arrive
|
|
1049
|
+
* with `.code` already set to 40001 by their engine modules, so the driver's
|
|
1050
|
+
* own number decides.
|
|
1051
|
+
*/
|
|
1052
|
+
function isLockNotAvailableError(err, code) {
|
|
1053
|
+
if (code === '55P03' || code === 'ER_LOCK_NOWAIT')
|
|
1054
|
+
return true;
|
|
1055
|
+
const e = err;
|
|
1056
|
+
if (e.errno === 3572)
|
|
1057
|
+
return true;
|
|
1058
|
+
return code === '40001' && (e.errno === 1205 || e.number === 1222);
|
|
1059
|
+
}
|
|
978
1060
|
/** Thrown when a CHECK constraint is violated (pg code 23514) */
|
|
979
1061
|
class CheckConstraintError extends TurbineError {
|
|
980
1062
|
static CODE = exports.TurbineErrorCode.CHECK_VIOLATION;
|
|
@@ -1146,24 +1228,114 @@ class ReadOnlyError extends TurbineError {
|
|
|
1146
1228
|
* fail-fast flag), so NOTHING can write here and writes must route to the
|
|
1147
1229
|
* primary. `'rbac'`: the database is writable but THIS connection's role may
|
|
1148
1230
|
* not write (per-connection permission), so re-authenticating may suffice.
|
|
1231
|
+
* `'transaction'`: the transaction is read-only (`$transaction({ readOnly:
|
|
1232
|
+
* true })`, `BEGIN READ ONLY`, or a read replica, where every transaction
|
|
1233
|
+
* is), so the write belongs in a read-write transaction on the primary.
|
|
1149
1234
|
*/
|
|
1150
1235
|
reason;
|
|
1151
1236
|
/**
|
|
1152
1237
|
* @param detail human-readable description of the refused write (the engine
|
|
1153
|
-
* message, or a local fail-fast description). A
|
|
1154
|
-
*
|
|
1238
|
+
* message, or a local fail-fast description). A hint naming where the
|
|
1239
|
+
* write belongs is always appended.
|
|
1155
1240
|
* @param options optional driver `cause` to preserve when wrapping a refusal,
|
|
1156
1241
|
* and the refusal `reason` (default `'snapshot'`).
|
|
1157
1242
|
*/
|
|
1158
1243
|
constructor(detail, options) {
|
|
1159
|
-
|
|
1244
|
+
const reason = options?.reason ?? 'snapshot';
|
|
1245
|
+
super(exports.TurbineErrorCode.READ_ONLY, `${detail} ${READ_ONLY_HINTS[reason]}`, {
|
|
1160
1246
|
cause: options?.cause,
|
|
1161
1247
|
});
|
|
1162
1248
|
this.name = 'ReadOnlyError';
|
|
1163
|
-
this.reason =
|
|
1249
|
+
this.reason = reason;
|
|
1164
1250
|
}
|
|
1165
1251
|
}
|
|
1166
1252
|
exports.ReadOnlyError = ReadOnlyError;
|
|
1253
|
+
const READ_ONLY_HINTS = {
|
|
1254
|
+
snapshot: 'Route writes to a writable primary.',
|
|
1255
|
+
rbac: 'Route writes to a writable primary.',
|
|
1256
|
+
transaction: 'Run the write in a read-write transaction (not `readOnly: true` or BEGIN READ ONLY) on the primary, ' +
|
|
1257
|
+
'not a read replica.',
|
|
1258
|
+
};
|
|
1259
|
+
/**
|
|
1260
|
+
* Thrown when work the caller expected to be saved was rolled back instead:
|
|
1261
|
+
* a `$transaction` or `transaction()` whose COMMIT the server answered with
|
|
1262
|
+
* ROLLBACK, a transaction that cannot commit because a statement inside it was
|
|
1263
|
+
* cut short by its `timeout`, or a nested `tx.$transaction(...)` block that
|
|
1264
|
+
* could not be kept for the same reasons.
|
|
1265
|
+
*
|
|
1266
|
+
* PostgreSQL aborts a transaction at its first error. Catching that error
|
|
1267
|
+
* inside the callback does not undo the abort, so the callback returns, the
|
|
1268
|
+
* COMMIT ends as a ROLLBACK, and none of the transaction's writes are saved.
|
|
1269
|
+
* The first failure is attached as `cause`. Nothing was committed, so the
|
|
1270
|
+
* whole transaction can be run again once the cause is dealt with; to keep the
|
|
1271
|
+
* rest of the work after an expected failure, run the statement that can fail
|
|
1272
|
+
* in its own nested `tx.$transaction(...)`.
|
|
1273
|
+
*
|
|
1274
|
+
* NOT retryable on its own: the failure that caused it is not known to be
|
|
1275
|
+
* transient. When that first failure WAS a deadlock or a serialization
|
|
1276
|
+
* conflict, the retryable class (`DeadlockError`, `SerializationFailureError`)
|
|
1277
|
+
* is thrown instead, so `$retry` re-runs the transaction.
|
|
1278
|
+
*/
|
|
1279
|
+
class TransactionRolledBackError extends TurbineError {
|
|
1280
|
+
static CODE = exports.TurbineErrorCode.TRANSACTION_ROLLED_BACK;
|
|
1281
|
+
/**
|
|
1282
|
+
* @param message what was rolled back and how to keep the work next time.
|
|
1283
|
+
* @param options the first failure inside the transaction, as `cause`.
|
|
1284
|
+
*/
|
|
1285
|
+
constructor(message, options) {
|
|
1286
|
+
super(exports.TurbineErrorCode.TRANSACTION_ROLLED_BACK, message, options);
|
|
1287
|
+
this.name = 'TransactionRolledBackError';
|
|
1288
|
+
}
|
|
1289
|
+
}
|
|
1290
|
+
exports.TransactionRolledBackError = TransactionRolledBackError;
|
|
1291
|
+
/**
|
|
1292
|
+
* The sentence every {@link InvariantError} message ends with, before the docs
|
|
1293
|
+
* link. Exported so a test can assert it without restating it.
|
|
1294
|
+
*/
|
|
1295
|
+
exports.INVARIANT_REPORT_HINT = 'This is a bug in turbine-orm, not in your code. Please report it at ' +
|
|
1296
|
+
'https://github.com/zvndev/turbine-orm/issues with this message.';
|
|
1297
|
+
/**
|
|
1298
|
+
* Turbine detected a bug in itself: a branch that no argument can reach was
|
|
1299
|
+
* reached, or two internal paths that must agree did not (the SQL-template
|
|
1300
|
+
* cache's build and param-collect paths, for example).
|
|
1301
|
+
*
|
|
1302
|
+
* Not caused by the arguments, so rewriting the call is not the fix, and not
|
|
1303
|
+
* retryable: the same call fails the same way. `invariant` is a stable id for
|
|
1304
|
+
* the broken rule (`'sql-cache-lockstep'`, `'sql-cache-param-count'`, ...), so
|
|
1305
|
+
* a report or an alert can group on it. The message names no row or parameter
|
|
1306
|
+
* value.
|
|
1307
|
+
*
|
|
1308
|
+
* Thrown in place of executing a statement Turbine knows is wrong, which is
|
|
1309
|
+
* what makes the checks behind it safe to run in production.
|
|
1310
|
+
*/
|
|
1311
|
+
class InvariantError extends TurbineError {
|
|
1312
|
+
static CODE = exports.TurbineErrorCode.INVARIANT_VIOLATION;
|
|
1313
|
+
/** Stable id of the broken invariant, e.g. `'sql-cache-lockstep'`. */
|
|
1314
|
+
invariant;
|
|
1315
|
+
/**
|
|
1316
|
+
* @param invariant stable id of the broken rule.
|
|
1317
|
+
* @param message what disagreed, with no row or parameter value in it. The
|
|
1318
|
+
* report hint is appended once.
|
|
1319
|
+
* @param options the error that exposed the broken rule, as `cause`.
|
|
1320
|
+
*/
|
|
1321
|
+
constructor(invariant, message, options) {
|
|
1322
|
+
const body = message.includes(exports.INVARIANT_REPORT_HINT) ? message : `${message} ${exports.INVARIANT_REPORT_HINT}`;
|
|
1323
|
+
super(exports.TurbineErrorCode.INVARIANT_VIOLATION, body, options);
|
|
1324
|
+
this.name = 'InvariantError';
|
|
1325
|
+
this.invariant = invariant;
|
|
1326
|
+
}
|
|
1327
|
+
}
|
|
1328
|
+
exports.InvariantError = InvariantError;
|
|
1329
|
+
/**
|
|
1330
|
+
* A write refused because its transaction is read-only: PostgreSQL SQLSTATE
|
|
1331
|
+
* 25006, or MySQL's error 1792 (which carries the same SQLSTATE).
|
|
1332
|
+
*/
|
|
1333
|
+
function isReadOnlyTransactionError(err, code) {
|
|
1334
|
+
if (code === '25006' || code === 'ER_CANT_EXECUTE_IN_READ_ONLY_TRANSACTION')
|
|
1335
|
+
return true;
|
|
1336
|
+
const e = err;
|
|
1337
|
+
return e.errno === 1792 && e.sqlState === '25006';
|
|
1338
|
+
}
|
|
1167
1339
|
/**
|
|
1168
1340
|
* Parse column names out of a pg `detail` string like:
|
|
1169
1341
|
* "Key (email)=(foo@bar) already exists."
|
|
@@ -1195,6 +1367,11 @@ const CONNECTION_ERROR_CODES = new Set([
|
|
|
1195
1367
|
'08006', // connection_failure
|
|
1196
1368
|
'08007', // transaction_resolution_unknown
|
|
1197
1369
|
'08P01', // protocol_violation
|
|
1370
|
+
// A named prepared statement met a server connection that did not prepare it
|
|
1371
|
+
// (26000) or already holds it (42P05). Turbine names its own statements, so
|
|
1372
|
+
// the usual cause is a transaction-pooling endpoint switching backends.
|
|
1373
|
+
'42P05', // duplicate_prepared_statement
|
|
1374
|
+
'26000', // invalid_sql_statement_name
|
|
1198
1375
|
// pg SQLSTATE class 28: the server answered and REFUSED us. These are the
|
|
1199
1376
|
// most common first-run failures there are (wrong password, a pg_hba rule
|
|
1200
1377
|
// that does not cover this user/host), and they used to fall through
|
|
@@ -1214,6 +1391,11 @@ const CONNECTION_ERROR_CODES = new Set([
|
|
|
1214
1391
|
'57P01', // admin_shutdown
|
|
1215
1392
|
'57P02', // crash_shutdown
|
|
1216
1393
|
'57P03', // cannot_connect_now
|
|
1394
|
+
// The server ended a session that sat idle inside an open transaction past
|
|
1395
|
+
// idle_in_transaction_session_timeout (a FATAL: the connection is gone).
|
|
1396
|
+
// A cursor stream sets that limit on its own transaction, see
|
|
1397
|
+
// query/stream-idle.ts, so this is how a frozen process's stream ends.
|
|
1398
|
+
'25P03', // idle_in_transaction_session_timeout
|
|
1217
1399
|
// Node driver-level socket errors (surface on err.code too)
|
|
1218
1400
|
'ECONNREFUSED',
|
|
1219
1401
|
'ECONNRESET',
|
|
@@ -1253,6 +1435,11 @@ const PG_CONNECTION_LOSS_MESSAGES = new Set([
|
|
|
1253
1435
|
'Connection terminated',
|
|
1254
1436
|
'Connection terminated due to connection timeout',
|
|
1255
1437
|
]);
|
|
1438
|
+
/** pg-pool's own words for a checkout that waited longer than `connectionTimeoutMillis`. */
|
|
1439
|
+
const PG_POOL_CHECKOUT_TIMEOUT_MESSAGE = 'timeout exceeded when trying to connect';
|
|
1440
|
+
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 " +
|
|
1441
|
+
'connection timeout: long transactions or streams, or a query on the outer client inside a `$transaction` ' +
|
|
1442
|
+
'callback, which needs a second connection (use `tx` there). Raise the pool size if the load is genuine.';
|
|
1256
1443
|
/** The follow-on errors pg raises for a query sent to a client already known to be dead. */
|
|
1257
1444
|
const PG_NOT_QUERYABLE_MESSAGES = new Set([
|
|
1258
1445
|
'Client has encountered a connection error and is not queryable',
|
|
@@ -1311,6 +1498,11 @@ function isStaleConnectionError(err) {
|
|
|
1311
1498
|
}
|
|
1312
1499
|
const CONNECTION_LOSS_HINT = 'The server or the network closed it (a restart, failover, idle timeout, compute suspend, or ' +
|
|
1313
1500
|
'pg_terminate_backend). The pool discards the connection, so retrying the operation opens a fresh one.';
|
|
1501
|
+
const PREPARED_STATEMENT_POOLER_HINT = 'A named prepared statement met a server connection that did not prepare it, or that already holds it. A ' +
|
|
1502
|
+
'transaction-pooling endpoint (PgBouncer in transaction mode, a managed "-pooler" host, port 6432 or 6543) ' +
|
|
1503
|
+
'gives each transaction to a different server connection, which is the usual cause. Connect to the direct ' +
|
|
1504
|
+
'endpoint, set `preparedStatements: false`, or turn on prepared-statement support in the pooler (PgBouncer ' +
|
|
1505
|
+
'1.21 or later, `max_prepared_statements` above 0).';
|
|
1314
1506
|
/**
|
|
1315
1507
|
* Actionable next step per connection-class code, appended to the driver's own
|
|
1316
1508
|
* message. The driver message states WHAT happened ("password authentication
|
|
@@ -1320,11 +1512,18 @@ const CONNECTION_LOSS_HINT = 'The server or the network closed it (a restart, fa
|
|
|
1320
1512
|
* A code with no entry here simply gets no hint appended.
|
|
1321
1513
|
*/
|
|
1322
1514
|
const CONNECTION_ERROR_HINTS = {
|
|
1515
|
+
'42P05': PREPARED_STATEMENT_POOLER_HINT,
|
|
1516
|
+
'26000': PREPARED_STATEMENT_POOLER_HINT,
|
|
1323
1517
|
'28P01': 'The server rejected the credentials. Check the password in your connection string (or DATABASE_URL), including any URL-encoding of special characters.',
|
|
1324
1518
|
'28000': "The server refused this user/host combination. Check the user name and the server's pg_hba.conf rules for the client address.",
|
|
1325
1519
|
'3D000': 'The database named in the connection string does not exist. Check the path segment after the host, and create the database if needed.',
|
|
1326
1520
|
'53300': "The server has no free connection slots. Lower `poolSize` or raise the server's max_connections.",
|
|
1327
1521
|
'57P03': 'The server is still starting up (or shutting down) and is not accepting connections yet.',
|
|
1522
|
+
'25P03': 'The server ended the session because it sat idle inside an open transaction for longer than ' +
|
|
1523
|
+
'`idle_in_transaction_session_timeout`. A cursor stream sets that limit to its idle timeout plus 10 s, so for ' +
|
|
1524
|
+
'a stream this means the process ran nothing for that long (a frozen serverless instance, a blocked event ' +
|
|
1525
|
+
'loop); for a transaction, that the callback awaited something else for longer than the server allows. The ' +
|
|
1526
|
+
'connection is discarded and the pool opens a fresh one.',
|
|
1328
1527
|
ECONNREFUSED: 'Nothing is listening on that host and port. Check the server is running and the port is right.',
|
|
1329
1528
|
ENOTFOUND: 'The host in the connection string could not be resolved. Check the host name, and that the connection string itself is well formed.',
|
|
1330
1529
|
EAI_AGAIN: 'DNS lookup for the host failed temporarily. Check network/DNS availability, then retry.',
|
|
@@ -1556,9 +1755,13 @@ function scrubUnclassifiedServerError(err, code) {
|
|
|
1556
1755
|
* 23P01 (exclusion_violation) -> ExclusionConstraintError
|
|
1557
1756
|
* 40P01 (deadlock_detected) -> DeadlockError (retryable)
|
|
1558
1757
|
* 40001 (serialization_failure) -> SerializationFailureError (retryable)
|
|
1758
|
+
* 55P03 (lock_not_available) -> LockNotAvailableError (retryable, E013); also
|
|
1759
|
+
* MySQL 3572 / 1205 and SQL Server 1222
|
|
1559
1760
|
* 57014 (query_canceled) -> TimeoutError (server-side statement_timeout)
|
|
1560
1761
|
* 28P01 / 28000 (auth refused) -> ConnectionError, with a remediation hint
|
|
1561
1762
|
* 3D000 (no such database) -> ConnectionError, with a remediation hint
|
|
1763
|
+
* 42P05 / 26000 (prepared statement name clash or miss, a transaction-mode
|
|
1764
|
+
* pooler) -> ConnectionError, with a remediation hint
|
|
1562
1765
|
* connection-class codes -> ConnectionError (see CONNECTION_ERROR_CODES)
|
|
1563
1766
|
* 22xxx (data exception) -> ValidationError naming the column (when the
|
|
1564
1767
|
* server did) and the SQLSTATE; driver text
|
|
@@ -1587,8 +1790,26 @@ function wrapPgError(err) {
|
|
|
1587
1790
|
if (err instanceof Error && PG_CONNECTION_LOSS_MESSAGES.has(err.message)) {
|
|
1588
1791
|
return new ConnectionError(`Database connection lost: ${err.message}. ${CONNECTION_LOSS_HINT}`, { cause: err });
|
|
1589
1792
|
}
|
|
1793
|
+
// pg-pool's checkout timeout carries no code either. A pool Turbine owns
|
|
1794
|
+
// types it at checkout (checkout.ts); this covers a caller's own pg.Pool.
|
|
1795
|
+
if (err instanceof Error && err.message === PG_POOL_CHECKOUT_TIMEOUT_MESSAGE) {
|
|
1796
|
+
return new ConnectionError(POOL_CHECKOUT_TIMEOUT_HINT, { cause: err });
|
|
1797
|
+
}
|
|
1590
1798
|
return err;
|
|
1591
1799
|
}
|
|
1800
|
+
if (isReadOnlyTransactionError(err, e.code)) {
|
|
1801
|
+
const pgMessage = typeof e.message === 'string' && e.message.length > 0 ? e.message : 'write refused';
|
|
1802
|
+
return new ReadOnlyError(`${pgMessage} (SQLSTATE 25006).`, { cause: err, reason: 'transaction' });
|
|
1803
|
+
}
|
|
1804
|
+
if (isLockNotAvailableError(err, e.code))
|
|
1805
|
+
return new LockNotAvailableError({ cause: err });
|
|
1806
|
+
// A protocol violation answered with ERROR rather than FATAL concerns one
|
|
1807
|
+
// message, and the connection stays usable. The common cause is a Buffer
|
|
1808
|
+
// bound to a column that is not bytea: node-postgres sends a Buffer as
|
|
1809
|
+
// binary data, which the server cannot read as an integer or a date.
|
|
1810
|
+
if (e.code === '08P01' && e.severity === 'ERROR') {
|
|
1811
|
+
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.');
|
|
1812
|
+
}
|
|
1592
1813
|
switch (e.code) {
|
|
1593
1814
|
case '23505': {
|
|
1594
1815
|
const cols = e.detail ? parseColumnsFromDetail(e.detail) : undefined;
|
|
@@ -1633,13 +1854,27 @@ function wrapPgError(err) {
|
|
|
1633
1854
|
cause: err,
|
|
1634
1855
|
});
|
|
1635
1856
|
case '57014':
|
|
1636
|
-
// query_canceled:
|
|
1637
|
-
//
|
|
1638
|
-
//
|
|
1857
|
+
// query_canceled: the statement was stopped, so it made no change. A
|
|
1858
|
+
// cancel request (what Turbine sends when a query or transaction
|
|
1859
|
+
// `timeout` expires) reads "due to user request"; anything else is the
|
|
1860
|
+
// server's own statement_timeout.
|
|
1639
1861
|
return new TimeoutError(0, 'Query', {
|
|
1640
|
-
message: '
|
|
1862
|
+
message: typeof e.message === 'string' && /user request/i.test(e.message)
|
|
1863
|
+
? 'Query cancelled on the server by a cancel request, which Turbine sends when a query or ' +
|
|
1864
|
+
'transaction `timeout` expires. It made no change.'
|
|
1865
|
+
: 'Query canceled by server-side statement_timeout',
|
|
1641
1866
|
cause: err,
|
|
1867
|
+
outcome: 'not-executed',
|
|
1642
1868
|
});
|
|
1869
|
+
case '25P02':
|
|
1870
|
+
// in_failed_sql_transaction: a statement sent after an earlier one failed. Turbine's own
|
|
1871
|
+
// transactions refuse it first, with the failure attached (transaction-state.ts); this is
|
|
1872
|
+
// the driver's answer on a path that sent it anyway (a connection used outside Turbine).
|
|
1873
|
+
return new TransactionRolledBackError('A statement was sent after an earlier statement in the same transaction failed. PostgreSQL ignores ' +
|
|
1874
|
+
'every statement after a failure until the transaction, or the savepoint it ran in, is rolled back, ' +
|
|
1875
|
+
'so nothing more can be saved in it. Catching the error does not undo the abort: let it leave the ' +
|
|
1876
|
+
'transaction, or run the statement that can fail in its own nested `tx.$transaction(...)`, which ' +
|
|
1877
|
+
'rolls back only that savepoint. The earlier failure is the error that statement threw.', { cause: err });
|
|
1643
1878
|
default:
|
|
1644
1879
|
if (CONNECTION_ERROR_CODES.has(e.code)) {
|
|
1645
1880
|
const pgMessage = typeof e.message === 'string' && e.message.length > 0 ? e.message : undefined;
|
|
@@ -1662,6 +1897,14 @@ function wrapPgError(err) {
|
|
|
1662
1897
|
: DATA_EXCEPTION_FALLBACK;
|
|
1663
1898
|
return wrapValueBearingPgError(err, e, subject, phrase);
|
|
1664
1899
|
}
|
|
1900
|
+
// 42883: no operator or function for these argument types, e.g. a bigint
|
|
1901
|
+
// column compared with text. PostgreSQL's message names types, never
|
|
1902
|
+
// values, so it is kept in both modes.
|
|
1903
|
+
if (e.code === '42883') {
|
|
1904
|
+
const pgMessage = typeof e.message === 'string' && e.message.length > 0 ? `${e.message} ` : '';
|
|
1905
|
+
return new ValidationError(`${pgMessage}(SQLSTATE 42883). A value of one type was compared with or passed to something that takes ` +
|
|
1906
|
+
"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 });
|
|
1907
|
+
}
|
|
1665
1908
|
// 42601 is any syntax error. Only the to_tsquery parse failure is a
|
|
1666
1909
|
// caller-input problem Turbine can name (the `search` operator), so the
|
|
1667
1910
|
// message text is the discriminator; every other 42601 takes the generic
|
package/dist/cjs/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 {};
|