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/introspect.js
CHANGED
|
@@ -16,6 +16,8 @@ exports.DEFAULT_EXCLUDED_TABLES = void 0;
|
|
|
16
16
|
exports.pgConfActionToReferential = pgConfActionToReferential;
|
|
17
17
|
exports.applyTableFilters = applyTableFilters;
|
|
18
18
|
exports.defaultExcludedTablesPresent = defaultExcludedTablesPresent;
|
|
19
|
+
exports.printableCatalogName = printableCatalogName;
|
|
20
|
+
exports.nullRecord = nullRecord;
|
|
19
21
|
exports.assertSafeCatalogIdentifier = assertSafeCatalogIdentifier;
|
|
20
22
|
exports.assertSafeCatalogSchema = assertSafeCatalogSchema;
|
|
21
23
|
exports.introspect = introspect;
|
|
@@ -38,6 +40,7 @@ exports.deriveEngineRelations = deriveEngineRelations;
|
|
|
38
40
|
const _pg_1 = __importDefault(require("pg"));
|
|
39
41
|
const dialect_js_1 = require("./dialect.js");
|
|
40
42
|
const errors_js_1 = require("./errors.js");
|
|
43
|
+
const logger_js_1 = require("./logger.js");
|
|
41
44
|
const schema_js_1 = require("./schema.js");
|
|
42
45
|
/**
|
|
43
46
|
* Map a `pg_constraint.confdeltype` / `confupdtype` character to a
|
|
@@ -356,6 +359,58 @@ function defaultExcludedTablesPresent(names, options = {}) {
|
|
|
356
359
|
*/
|
|
357
360
|
// biome-ignore lint/suspicious/noControlCharactersInRegex: detecting control characters is this pattern's purpose
|
|
358
361
|
const UNSAFE_CATALOG_CHARS = /[\u0000-\u001f\u007f-\u009f\u2028\u2029]/;
|
|
362
|
+
/**
|
|
363
|
+
* Characters that must not reach a terminal or a log verbatim: everything in
|
|
364
|
+
* {@link UNSAFE_CATALOG_CHARS} (an ESC starts an ANSI sequence, a carriage
|
|
365
|
+
* return overwrites the line), plus the bidirectional controls that reorder how
|
|
366
|
+
* a name is displayed without changing what it is.
|
|
367
|
+
*/
|
|
368
|
+
// biome-ignore lint/suspicious/noControlCharactersInRegex: neutralizing control characters is this pattern's purpose
|
|
369
|
+
const TERMINAL_UNSAFE_CHARS = /[\u0000-\u001f\u007f-\u009f\u2028\u2029\u200e\u200f\u202a-\u202e\u2066-\u2069]/g;
|
|
370
|
+
/**
|
|
371
|
+
* A catalog name made safe to PRINT. Every diagnostic that quotes a table,
|
|
372
|
+
* column, enum, relation or constraint name goes through this, because Postgres
|
|
373
|
+
* lets anyone with CREATE privilege pick any characters for those, and an
|
|
374
|
+
* unescaped name in an error message is a way to write escape sequences to the
|
|
375
|
+
* developer's terminal. Control and bidi characters become visible escapes
|
|
376
|
+
* (`\n`, `\u001b`); everything else, including non-ASCII letters, is untouched.
|
|
377
|
+
*/
|
|
378
|
+
function printableCatalogName(name) {
|
|
379
|
+
return name.replace(TERMINAL_UNSAFE_CHARS, (ch) => {
|
|
380
|
+
if (ch === '\n')
|
|
381
|
+
return '\\n';
|
|
382
|
+
if (ch === '\r')
|
|
383
|
+
return '\\r';
|
|
384
|
+
if (ch === '\t')
|
|
385
|
+
return '\\t';
|
|
386
|
+
return `\\u${ch.charCodeAt(0).toString(16).padStart(4, '0')}`;
|
|
387
|
+
});
|
|
388
|
+
}
|
|
389
|
+
/**
|
|
390
|
+
* An empty record for something keyed by catalog names. Prototype-less on
|
|
391
|
+
* purpose: a plain `{}` turns a table named `__proto__` into a prototype
|
|
392
|
+
* assignment (the table silently disappears), and makes `enums['constructor']`
|
|
393
|
+
* truthy before any enum was ever added.
|
|
394
|
+
*/
|
|
395
|
+
function nullRecord() {
|
|
396
|
+
return Object.create(null);
|
|
397
|
+
}
|
|
398
|
+
/**
|
|
399
|
+
* The TypeScript type for a catalog type name. A user-defined type can be named
|
|
400
|
+
* after an `Object.prototype` member (`toString`, `constructor`, `valueOf`),
|
|
401
|
+
* which a plain-object type table answers with a function instead of nothing, so
|
|
402
|
+
* that case is pinned to `unknown` here, before any type table is consulted,
|
|
403
|
+
* rather than emitted as function source. `lookup` is the dialect's own mapping
|
|
404
|
+
* for every other name.
|
|
405
|
+
*/
|
|
406
|
+
function tsTypeForCatalogType(typeName, nullable, lookup = schema_js_1.pgTypeToTs) {
|
|
407
|
+
const isArray = typeName.startsWith('_');
|
|
408
|
+
if ((isArray ? typeName.slice(1) : typeName) in Object.prototype) {
|
|
409
|
+
const unknownType = isArray ? 'unknown[]' : 'unknown';
|
|
410
|
+
return nullable ? `${unknownType} | null` : unknownType;
|
|
411
|
+
}
|
|
412
|
+
return lookup(typeName, nullable);
|
|
413
|
+
}
|
|
359
414
|
/**
|
|
360
415
|
* Refuse one catalog identifier carrying a character from
|
|
361
416
|
* {@link UNSAFE_CATALOG_CHARS}. `subject` names the object in the error.
|
|
@@ -365,7 +420,7 @@ function assertSafeCatalogIdentifier(name, subject) {
|
|
|
365
420
|
if (match === null)
|
|
366
421
|
return;
|
|
367
422
|
const code = match[0].charCodeAt(0).toString(16).padStart(4, '0');
|
|
368
|
-
throw new errors_js_1.ValidationError(`Refusing to introspect ${subject}: its name contains the control character U+${code.toUpperCase()} ` +
|
|
423
|
+
throw new errors_js_1.ValidationError(`Refusing to introspect ${printableCatalogName(subject)}: its name contains the control character U+${code.toUpperCase()} ` +
|
|
369
424
|
`at position ${match.index}. Such a name cannot be safely emitted into generated code, SQL comments, or ` +
|
|
370
425
|
`tooling output. Rename the database object, or exclude it from introspection.`);
|
|
371
426
|
}
|
|
@@ -425,14 +480,15 @@ function assertSafeCatalogSchema(schema) {
|
|
|
425
480
|
/**
|
|
426
481
|
* Introspect a database into {@link SchemaMetadata}, routing through the active
|
|
427
482
|
* dialect's {@link Dialect.introspector} so each engine can override the catalog
|
|
428
|
-
* SQL. PostgreSQL is
|
|
483
|
+
* SQL. A dialect with none, PostgreSQL included, is read by
|
|
484
|
+
* {@link introspectPostgresCatalog}.
|
|
429
485
|
*/
|
|
430
486
|
async function introspect(options) {
|
|
431
487
|
const dialect = options.dialect ?? dialect_js_1.postgresDialect;
|
|
432
488
|
const introspector = dialect.introspector;
|
|
433
489
|
const schema = introspector
|
|
434
490
|
? await introspector.introspect(options)
|
|
435
|
-
: //
|
|
491
|
+
: // PostgreSQL, and any dialect without an introspector, reads the Postgres catalog.
|
|
436
492
|
await introspectPostgresCatalog(options);
|
|
437
493
|
// Applied here rather than inside each introspector so every engine gets it.
|
|
438
494
|
const renamed = options.relationNames ? applyRelationRenames(schema, options.relationNames) : schema;
|
|
@@ -458,18 +514,18 @@ async function introspect(options) {
|
|
|
458
514
|
* means the call sites it was supposed to fix break at runtime instead.
|
|
459
515
|
*/
|
|
460
516
|
function applyRelationRenames(schema, renames) {
|
|
461
|
-
const tables =
|
|
517
|
+
const tables = Object.assign(nullRecord(), schema.tables);
|
|
462
518
|
for (const [table, mapping] of Object.entries(renames)) {
|
|
463
|
-
const meta = tables[table];
|
|
519
|
+
const meta = Object.hasOwn(tables, table) ? tables[table] : undefined;
|
|
464
520
|
if (!meta) {
|
|
465
|
-
throw new errors_js_1.ValidationError(`relationNames: unknown table "${table}". Known tables: ${Object.keys(tables).join(', ')}.`);
|
|
521
|
+
throw new errors_js_1.ValidationError(`relationNames: unknown table "${printableCatalogName(table)}". Known tables: ${Object.keys(tables).map(printableCatalogName).join(', ')}.`);
|
|
466
522
|
}
|
|
467
|
-
const relations =
|
|
523
|
+
const relations = Object.assign(nullRecord(), meta.relations);
|
|
468
524
|
const columnFields = new Set(Object.values(meta.columnMap));
|
|
469
525
|
for (const [from, to] of Object.entries(mapping)) {
|
|
470
526
|
if (!Object.hasOwn(relations, from)) {
|
|
471
|
-
throw new errors_js_1.ValidationError(`relationNames: table "${table}" has no relation "${from}". ` +
|
|
472
|
-
`Derived relations: ${Object.keys(relations).join(', ') || '(none)'}.`);
|
|
527
|
+
throw new errors_js_1.ValidationError(`relationNames: table "${printableCatalogName(table)}" has no relation "${printableCatalogName(from)}". ` +
|
|
528
|
+
`Derived relations: ${Object.keys(relations).map(printableCatalogName).join(', ') || '(none)'}.`);
|
|
473
529
|
}
|
|
474
530
|
if (from === to)
|
|
475
531
|
continue;
|
|
@@ -522,21 +578,21 @@ function assertDistinctColumnFields(tableName, columns) {
|
|
|
522
578
|
for (const [field, names] of columnsByField) {
|
|
523
579
|
if (names.length < 2)
|
|
524
580
|
continue;
|
|
525
|
-
const quoted = names.map((n) => `"${n}"`);
|
|
581
|
+
const quoted = names.map((n) => `"${printableCatalogName(n)}"`);
|
|
526
582
|
const list = `${quoted.slice(0, -1).join(', ')} and ${quoted[quoted.length - 1]}`;
|
|
527
|
-
collisions.push(`columns ${list} ${names.length === 2 ? 'both' : 'all'} resolve to the field "${field}"`);
|
|
583
|
+
collisions.push(`columns ${list} ${names.length === 2 ? 'both' : 'all'} resolve to the field "${printableCatalogName(field)}"`);
|
|
528
584
|
}
|
|
529
585
|
if (collisions.length === 0)
|
|
530
586
|
return;
|
|
531
|
-
throw new errors_js_1.ValidationError(`Field collision on table "${tableName}": ${collisions.join('; ')}. A client addresses one column per field, ` +
|
|
587
|
+
throw new errors_js_1.ValidationError(`Field collision on table "${printableCatalogName(tableName)}": ${collisions.join('; ')}. A client addresses one column per field, ` +
|
|
532
588
|
'so reads would fold the colliding columns into one property and a write to that field would reach only ' +
|
|
533
589
|
'one of them. Rename one of the columns, or set `keepColumnNames: true` in turbine.config.ts ' +
|
|
534
590
|
'(`turbine generate --keep-column-names`) so every field is its raw column name.');
|
|
535
591
|
}
|
|
536
592
|
/**
|
|
537
593
|
* PostgreSQL catalog introspector: reads information_schema + pg_catalog and
|
|
538
|
-
* produces {@link SchemaMetadata}.
|
|
539
|
-
*
|
|
594
|
+
* produces {@link SchemaMetadata}. {@link introspect} calls it for PostgreSQL;
|
|
595
|
+
* call {@link introspect} for dialect routing.
|
|
540
596
|
*/
|
|
541
597
|
async function introspectPostgresCatalog(options) {
|
|
542
598
|
const schema = options.schema ?? 'public';
|
|
@@ -609,8 +665,7 @@ async function introspectPostgresCatalog(options) {
|
|
|
609
665
|
field: options.keepColumnNames ? row.column_name : (0, schema_js_1.snakeToCamel)(row.column_name),
|
|
610
666
|
dialectType,
|
|
611
667
|
pgType: dialectType,
|
|
612
|
-
tsType:
|
|
613
|
-
(0, schema_js_1.pgTypeToTs)(isArray ? dialectType : baseType, isNullable),
|
|
668
|
+
tsType: tsTypeForCatalogType(isArray ? dialectType : baseType, isNullable, dialect.typeToTypeScript?.bind(dialect) ?? schema_js_1.pgTypeToTs),
|
|
614
669
|
nullable: isNullable,
|
|
615
670
|
hasDefault: row.column_default !== null,
|
|
616
671
|
// Server-generated = a sequence default (serial/BIGSERIAL → nextval(…))
|
|
@@ -706,9 +761,9 @@ async function introspectPostgresCatalog(options) {
|
|
|
706
761
|
});
|
|
707
762
|
}
|
|
708
763
|
// ----- Collect enums -----
|
|
709
|
-
const enums =
|
|
764
|
+
const enums = nullRecord();
|
|
710
765
|
for (const row of enumResult.rows) {
|
|
711
|
-
if (!enums
|
|
766
|
+
if (!Object.hasOwn(enums, row.typname))
|
|
712
767
|
enums[row.typname] = [];
|
|
713
768
|
enums[row.typname].push(row.enumlabel);
|
|
714
769
|
}
|
|
@@ -754,9 +809,9 @@ async function introspectPostgresCatalog(options) {
|
|
|
754
809
|
}
|
|
755
810
|
const foreignKeys = Array.from(fkGroups.values());
|
|
756
811
|
if (crossSchemaRefs.length > 0) {
|
|
757
|
-
|
|
758
|
-
`${crossSchemaRefs.join(', ')}. Generated clients address tables by bare name within one schema, so no ` +
|
|
759
|
-
`relation is emitted for these. Introspect the other schema separately, or add the target table to this one
|
|
812
|
+
(0, logger_js_1.logTo)(options.logger ?? logger_js_1.consoleLogger, 'warn', `Skipped ${crossSchemaRefs.length} foreign key(s) referencing a table outside schema "${printableCatalogName(schema)}": ` +
|
|
813
|
+
`${crossSchemaRefs.map(printableCatalogName).join(', ')}. Generated clients address tables by bare name within one schema, so no ` +
|
|
814
|
+
`relation is emitted for these. Introspect the other schema separately, or add the target table to this one.`, { code: 'introspect-cross-schema-fk', schema, references: crossSchemaRefs.length });
|
|
760
815
|
}
|
|
761
816
|
// Referential actions (ON DELETE / ON UPDATE) per constraint. Keyed
|
|
762
817
|
// "<table>::<constraint>" because the NAME alone is not unique (the same
|
|
@@ -789,16 +844,17 @@ async function introspectPostgresCatalog(options) {
|
|
|
789
844
|
enums,
|
|
790
845
|
fkActions,
|
|
791
846
|
legacyToManyUniques: options.legacyToManyUniques,
|
|
847
|
+
...(options.logger !== undefined ? { logger: options.logger } : {}),
|
|
792
848
|
});
|
|
793
849
|
// ----- Assemble TableMetadata for each table -----
|
|
794
|
-
const tables =
|
|
850
|
+
const tables = nullRecord();
|
|
795
851
|
for (const tableName of tableNames) {
|
|
796
852
|
const columns = columnsByTable.get(tableName) ?? [];
|
|
797
|
-
const columnMap =
|
|
798
|
-
const reverseColumnMap =
|
|
853
|
+
const columnMap = nullRecord();
|
|
854
|
+
const reverseColumnMap = nullRecord();
|
|
799
855
|
const dateColumns = new Set();
|
|
800
|
-
const dialectTypes =
|
|
801
|
-
const pgTypes =
|
|
856
|
+
const dialectTypes = nullRecord();
|
|
857
|
+
const pgTypes = nullRecord();
|
|
802
858
|
const allColumns = [];
|
|
803
859
|
for (const col of columns) {
|
|
804
860
|
columnMap[col.field] = col.name;
|
|
@@ -822,7 +878,7 @@ async function introspectPostgresCatalog(options) {
|
|
|
822
878
|
allColumns,
|
|
823
879
|
primaryKey: pkByTable.get(tableName) ?? [],
|
|
824
880
|
uniqueColumns: uniqueByTable.get(tableName) ?? [],
|
|
825
|
-
relations: relationsByTable.get(tableName) ??
|
|
881
|
+
relations: relationsByTable.get(tableName) ?? nullRecord(),
|
|
826
882
|
indexes: indexesByTable.get(tableName) ?? [],
|
|
827
883
|
checks: checksByTable.get(tableName) ?? [],
|
|
828
884
|
...(viewNameSet.has(tableName) ? { isView: true } : {}),
|
|
@@ -1209,13 +1265,13 @@ function detectUniqueForeignKeySets(pkByTable, uniqueByTable, indexesByTable) {
|
|
|
1209
1265
|
* colliding name would otherwise shadow a column field and generate types
|
|
1210
1266
|
* that fail `tsc --strict` (TS2430/TS2322).
|
|
1211
1267
|
*/
|
|
1212
|
-
function resolveRelationNameCollision(candidate, taken, table, source) {
|
|
1268
|
+
function resolveRelationNameCollision(candidate, taken, table, source, logger) {
|
|
1213
1269
|
if (!taken.has(candidate))
|
|
1214
1270
|
return candidate;
|
|
1215
1271
|
let name = `${candidate}Rel`;
|
|
1216
1272
|
for (let i = 2; taken.has(name); i++)
|
|
1217
1273
|
name = `${candidate}Rel${i}`;
|
|
1218
|
-
|
|
1274
|
+
(0, logger_js_1.logTo)(logger, 'warn', printableCatalogName(`Relation name "${candidate}" on table "${table}" (from ${source}) collides with an existing column or relation, using "${name}" instead.`), { code: 'introspect-relation-renamed', table, relation: name, wanted: candidate });
|
|
1219
1275
|
return name;
|
|
1220
1276
|
}
|
|
1221
1277
|
/**
|
|
@@ -1257,7 +1313,7 @@ function resolveRelationNameCollision(candidate, taken, table, source) {
|
|
|
1257
1313
|
* engine introspectors and `defineSchema` path do) to keep every reverse
|
|
1258
1314
|
* relation `hasMany`.
|
|
1259
1315
|
*/
|
|
1260
|
-
function buildRelationsFromForeignKeys(foreignKeys, columnFieldsByTable, fkActions, unknownTypedFieldsByTable, uniqueSetsByTable) {
|
|
1316
|
+
function buildRelationsFromForeignKeys(foreignKeys, columnFieldsByTable, fkActions, unknownTypedFieldsByTable, uniqueSetsByTable, logger = logger_js_1.consoleLogger) {
|
|
1261
1317
|
// Count FKs per (source, target) pair for disambiguation.
|
|
1262
1318
|
const fkCounts = new Map();
|
|
1263
1319
|
for (const fk of foreignKeys) {
|
|
@@ -1293,18 +1349,19 @@ function buildRelationsFromForeignKeys(foreignKeys, columnFieldsByTable, fkActio
|
|
|
1293
1349
|
const taken = takenFor(table);
|
|
1294
1350
|
if (!taken.has(legacy))
|
|
1295
1351
|
return legacy;
|
|
1296
|
-
//
|
|
1297
|
-
// (
|
|
1298
|
-
// typeSafeRelations() keeps the generated
|
|
1352
|
+
// A relation named like a json/jsonb column keeps that name: it works at
|
|
1353
|
+
// runtime and compiles (the column's `unknown` type absorbs the relation
|
|
1354
|
+
// payload). Keep it and warn; typeSafeRelations() keeps the generated types
|
|
1355
|
+
// sound.
|
|
1299
1356
|
if (!assignedFor(table).has(legacy) && unknownTypedFieldsByTable?.get(table)?.has(legacy)) {
|
|
1300
|
-
|
|
1357
|
+
(0, logger_js_1.logTo)(logger, 'warn', printableCatalogName(`Relation "${legacy}" on table "${table}" (from ${source}) shadows the json/jsonb column ` +
|
|
1301
1358
|
`"${legacy}", keeping the historical name for runtime compatibility; the relation is omitted from ` +
|
|
1302
|
-
`the generated types. Rename the column to expose it.`);
|
|
1359
|
+
`the generated types. Rename the column to expose it.`), { code: 'introspect-relation-shadows-json', table, relation: legacy });
|
|
1303
1360
|
return legacy;
|
|
1304
1361
|
}
|
|
1305
1362
|
if (modern !== null && modern !== legacy && !taken.has(modern))
|
|
1306
1363
|
return modern;
|
|
1307
|
-
return resolveRelationNameCollision(modern ?? legacy, taken, table, source);
|
|
1364
|
+
return resolveRelationNameCollision(modern ?? legacy, taken, table, source, logger);
|
|
1308
1365
|
};
|
|
1309
1366
|
for (const fk of foreignKeys) {
|
|
1310
1367
|
const pairKey = `${fk.sourceTable}→${fk.targetTable}`;
|
|
@@ -1353,7 +1410,7 @@ function buildRelationsFromForeignKeys(foreignKeys, columnFieldsByTable, fkActio
|
|
|
1353
1410
|
if (actions?.onUpdate && actions.onUpdate !== 'no action')
|
|
1354
1411
|
actionFields.onUpdate = actions.onUpdate;
|
|
1355
1412
|
if (!relationsByTable.has(fk.sourceTable))
|
|
1356
|
-
relationsByTable.set(fk.sourceTable,
|
|
1413
|
+
relationsByTable.set(fk.sourceTable, nullRecord());
|
|
1357
1414
|
relationsByTable.get(fk.sourceTable)[belongsToName] = {
|
|
1358
1415
|
type: 'belongsTo',
|
|
1359
1416
|
name: belongsToName,
|
|
@@ -1394,7 +1451,7 @@ function buildRelationsFromForeignKeys(foreignKeys, columnFieldsByTable, fkActio
|
|
|
1394
1451
|
takenFor(fk.targetTable).add(reverseName);
|
|
1395
1452
|
assignedFor(fk.targetTable).add(reverseName);
|
|
1396
1453
|
if (!relationsByTable.has(fk.targetTable))
|
|
1397
|
-
relationsByTable.set(fk.targetTable,
|
|
1454
|
+
relationsByTable.set(fk.targetTable, nullRecord());
|
|
1398
1455
|
relationsByTable.get(fk.targetTable)[reverseName] = {
|
|
1399
1456
|
type: reverseType,
|
|
1400
1457
|
name: reverseName,
|
|
@@ -1433,7 +1490,7 @@ function buildRelationsFromForeignKeys(foreignKeys, columnFieldsByTable, fkActio
|
|
|
1433
1490
|
* - a shadowed concrete-typed column → deterministic `Rel` suffix + warn
|
|
1434
1491
|
* instead of silently dropping the relation.
|
|
1435
1492
|
*/
|
|
1436
|
-
function addAutoManyToManyRelations(tableNames, foreignKeys, pkByTable, columnNamesByTable, relationsByTable, columnFieldsByTable, unknownTypedFieldsByTable, uniqueIndexColsByTable) {
|
|
1493
|
+
function addAutoManyToManyRelations(tableNames, foreignKeys, pkByTable, columnNamesByTable, relationsByTable, columnFieldsByTable, unknownTypedFieldsByTable, uniqueIndexColsByTable, logger = logger_js_1.consoleLogger) {
|
|
1437
1494
|
for (const tableName of tableNames) {
|
|
1438
1495
|
// FKs whose source is this table, both must be single-column.
|
|
1439
1496
|
const tableFks = foreignKeys.filter((fk) => fk.sourceTable === tableName);
|
|
@@ -1479,22 +1536,22 @@ function addAutoManyToManyRelations(tableNames, foreignKeys, pkByTable, columnNa
|
|
|
1479
1536
|
const targetTbl = other.targetTable; // B
|
|
1480
1537
|
let relName = (0, schema_js_1.snakeToCamel)(targetTbl); // plural table name → e.g. "tags"
|
|
1481
1538
|
if (!relationsByTable.has(sourceTbl))
|
|
1482
|
-
relationsByTable.set(sourceTbl,
|
|
1539
|
+
relationsByTable.set(sourceTbl, nullRecord());
|
|
1483
1540
|
const existing = relationsByTable.get(sourceTbl);
|
|
1484
1541
|
// Additive-only: never clobber an existing relation name.
|
|
1485
|
-
if (existing
|
|
1542
|
+
if (Object.hasOwn(existing, relName))
|
|
1486
1543
|
return;
|
|
1487
1544
|
const columnFields = columnFieldsByTable?.get(sourceTbl);
|
|
1488
1545
|
if (columnFields?.has(relName)) {
|
|
1489
1546
|
if (unknownTypedFieldsByTable?.get(sourceTbl)?.has(relName)) {
|
|
1490
|
-
//
|
|
1491
|
-
|
|
1547
|
+
// Same json/jsonb shadow as above: keep the name and warn.
|
|
1548
|
+
(0, logger_js_1.logTo)(logger, 'warn', printableCatalogName(`Relation "${relName}" on table "${sourceTbl}" (junction ${tableName}) shadows the ` +
|
|
1492
1549
|
`json/jsonb column "${relName}", keeping the historical name for runtime compatibility; ` +
|
|
1493
|
-
`the relation is omitted from the generated types.`);
|
|
1550
|
+
`the relation is omitted from the generated types.`), { code: 'introspect-relation-shadows-json', table: sourceTbl, relation: relName });
|
|
1494
1551
|
}
|
|
1495
1552
|
else {
|
|
1496
1553
|
const taken = new Set([...columnFields, ...Object.keys(existing)]);
|
|
1497
|
-
relName = resolveRelationNameCollision(relName, taken, sourceTbl, `junction ${tableName}
|
|
1554
|
+
relName = resolveRelationNameCollision(relName, taken, sourceTbl, `junction ${tableName}`, logger);
|
|
1498
1555
|
}
|
|
1499
1556
|
}
|
|
1500
1557
|
existing[relName] = {
|
|
@@ -1558,7 +1615,8 @@ function deriveCatalogRelations(inputs) {
|
|
|
1558
1615
|
const uniqueSetsByTable = inputs.legacyToManyUniques
|
|
1559
1616
|
? undefined
|
|
1560
1617
|
: detectUniqueForeignKeySets(pkByTable, uniqueByTable, indexesByTable);
|
|
1561
|
-
const
|
|
1618
|
+
const logger = inputs.logger ?? logger_js_1.consoleLogger;
|
|
1619
|
+
const relationsByTable = buildRelationsFromForeignKeys(foreignKeys, columnFieldsByTable, inputs.fkActions, unknownTypedFieldsByTable, uniqueSetsByTable, logger);
|
|
1562
1620
|
// Prisma's implicit m2m junctions have no primary key (just a two-column
|
|
1563
1621
|
// UNIQUE index over the FK columns), so pass the introspected two-column
|
|
1564
1622
|
// unique indexes as the fallback junction-key source.
|
|
@@ -1587,7 +1645,7 @@ function deriveCatalogRelations(inputs) {
|
|
|
1587
1645
|
if (twoColUniques.length > 0)
|
|
1588
1646
|
uniqueIndexColsByTable.set(tbl, twoColUniques);
|
|
1589
1647
|
}
|
|
1590
|
-
addAutoManyToManyRelations(tableNames, foreignKeys, pkByTable, new Map(Array.from(columnsByTable, ([tbl, cols]) => [tbl, cols.map((c) => c.name)])), relationsByTable, columnFieldsByTable, unknownTypedFieldsByTable, uniqueIndexColsByTable);
|
|
1648
|
+
addAutoManyToManyRelations(tableNames, foreignKeys, pkByTable, new Map(Array.from(columnsByTable, ([tbl, cols]) => [tbl, cols.map((c) => c.name)])), relationsByTable, columnFieldsByTable, unknownTypedFieldsByTable, uniqueIndexColsByTable, logger);
|
|
1591
1649
|
return relationsByTable;
|
|
1592
1650
|
}
|
|
1593
1651
|
/**
|
|
@@ -1599,7 +1657,7 @@ function deriveCatalogRelations(inputs) {
|
|
|
1599
1657
|
* relation names for the same logical schema (the engines previously carried
|
|
1600
1658
|
* stale copies of a retired naming scheme).
|
|
1601
1659
|
*/
|
|
1602
|
-
function deriveEngineRelations(tableNames, foreignKeys, pkByTable, columnsByTable) {
|
|
1660
|
+
function deriveEngineRelations(tableNames, foreignKeys, pkByTable, columnsByTable, logger = logger_js_1.consoleLogger) {
|
|
1603
1661
|
const tableSet = new Set(tableNames);
|
|
1604
1662
|
const fks = foreignKeys.filter((fk) => tableSet.has(fk.sourceTable) && tableSet.has(fk.targetTable));
|
|
1605
1663
|
const columnFieldsByTable = new Map();
|
|
@@ -1608,7 +1666,7 @@ function deriveEngineRelations(tableNames, foreignKeys, pkByTable, columnsByTabl
|
|
|
1608
1666
|
columnFieldsByTable.set(tbl, new Set(cols.map((c) => c.field)));
|
|
1609
1667
|
unknownTypedFieldsByTable.set(tbl, new Set(cols.filter((c) => isUnknownTsType(c.tsType)).map((c) => c.field)));
|
|
1610
1668
|
}
|
|
1611
|
-
const relationsByTable = buildRelationsFromForeignKeys(fks, columnFieldsByTable, undefined, unknownTypedFieldsByTable);
|
|
1612
|
-
addAutoManyToManyRelations(tableNames, fks, pkByTable, new Map(Array.from(columnsByTable, ([tbl, cols]) => [tbl, cols.map((c) => c.name)])), relationsByTable, columnFieldsByTable, unknownTypedFieldsByTable);
|
|
1669
|
+
const relationsByTable = buildRelationsFromForeignKeys(fks, columnFieldsByTable, undefined, unknownTypedFieldsByTable, undefined, logger);
|
|
1670
|
+
addAutoManyToManyRelations(tableNames, fks, pkByTable, new Map(Array.from(columnsByTable, ([tbl, cols]) => [tbl, cols.map((c) => c.name)])), relationsByTable, columnFieldsByTable, unknownTypedFieldsByTable, undefined, logger);
|
|
1613
1671
|
return relationsByTable;
|
|
1614
1672
|
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* turbine-orm, every `code` a Turbine log line can carry.
|
|
3
|
+
*
|
|
4
|
+
* A log line's TEXT is not a stable contract; its `code` is. This list is the
|
|
5
|
+
* whole set. Library code imports it as a TYPE only (see `TurbineLogCode` in
|
|
6
|
+
* logger.ts), so an emitter cannot use a code that is not here and the list
|
|
7
|
+
* itself never reaches a bundle. The tests import the runtime array: one test
|
|
8
|
+
* per code, and a source scan that fails on a code nothing emits.
|
|
9
|
+
*/
|
|
10
|
+
export declare const LOG_CODES: readonly ["unknown-config-key", "plan-cache-mode-ignored", "prepared-statements-on-pooler", "connection-option-ignored", "pool-error", "query-listener-error", "pool-listener-error", "replica-close-error", "external-pool", "pool-created", "replicas-configured", "pipeline", "raw-sql", "transaction-committed", "transaction-rolled-back", "listen", "notify", "connection-verified", "disconnect-skipped", "pool-disconnected", "typed-sql", "listen-reconnecting", "listen-lost", "parser-overwrite", "untyped-columns", "unordered-page", "auto-strategy", "deep-with", "flatten-blocked", "redundant-sort-term", "unknown-query-option", "unlimited-find-many", "temporal-infinity", "cache-mismatch", "stream-idle-timeout", "sql-comment-dropped", "relation-payload-json", "flatten-fallback", "unindexed-relation", "prisma-compat-unknown-option", "prisma-compat-native-spelling", "prisma-map-stale", "prisma-compat-junction-collision", "powdb-link-collision", "powdb-link-drift", "powdb-introspect-no-primary-key", "introspect-cross-schema-fk", "introspect-relation-renamed", "introspect-relation-shadows-json", "generate-relation-shadows-column"];
|
|
11
|
+
/** A stable, machine-readable log line id. */
|
|
12
|
+
export type TurbineLogCode = (typeof LOG_CODES)[number];
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.LOG_CODES = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* turbine-orm, every `code` a Turbine log line can carry.
|
|
6
|
+
*
|
|
7
|
+
* A log line's TEXT is not a stable contract; its `code` is. This list is the
|
|
8
|
+
* whole set. Library code imports it as a TYPE only (see `TurbineLogCode` in
|
|
9
|
+
* logger.ts), so an emitter cannot use a code that is not here and the list
|
|
10
|
+
* itself never reaches a bundle. The tests import the runtime array: one test
|
|
11
|
+
* per code, and a source scan that fails on a code nothing emits.
|
|
12
|
+
*/
|
|
13
|
+
exports.LOG_CODES = [
|
|
14
|
+
// client.ts, construction (always on)
|
|
15
|
+
'unknown-config-key',
|
|
16
|
+
'plan-cache-mode-ignored',
|
|
17
|
+
'prepared-statements-on-pooler',
|
|
18
|
+
'connection-option-ignored',
|
|
19
|
+
// client.ts, runtime errors
|
|
20
|
+
'pool-error',
|
|
21
|
+
'query-listener-error',
|
|
22
|
+
'pool-listener-error',
|
|
23
|
+
'replica-close-error',
|
|
24
|
+
// client.ts, `logging: true` lifecycle lines
|
|
25
|
+
'external-pool',
|
|
26
|
+
'pool-created',
|
|
27
|
+
'replicas-configured',
|
|
28
|
+
'pipeline',
|
|
29
|
+
'raw-sql',
|
|
30
|
+
'transaction-committed',
|
|
31
|
+
'transaction-rolled-back',
|
|
32
|
+
'listen',
|
|
33
|
+
'notify',
|
|
34
|
+
'connection-verified',
|
|
35
|
+
'disconnect-skipped',
|
|
36
|
+
'pool-disconnected',
|
|
37
|
+
// typed-sql.ts
|
|
38
|
+
'typed-sql',
|
|
39
|
+
// realtime.ts
|
|
40
|
+
'listen-reconnecting',
|
|
41
|
+
'listen-lost',
|
|
42
|
+
// query/utils.ts, a pg type parser replaced (client construction, always on)
|
|
43
|
+
'parser-overwrite',
|
|
44
|
+
// query/builder.ts, query/utils.ts, query/option-surface.ts: per-query advice
|
|
45
|
+
'untyped-columns',
|
|
46
|
+
'unordered-page',
|
|
47
|
+
'auto-strategy',
|
|
48
|
+
'deep-with',
|
|
49
|
+
'flatten-blocked',
|
|
50
|
+
'redundant-sort-term',
|
|
51
|
+
'unknown-query-option',
|
|
52
|
+
// query/builder.ts, always on
|
|
53
|
+
'unlimited-find-many',
|
|
54
|
+
'temporal-infinity',
|
|
55
|
+
'cache-mismatch',
|
|
56
|
+
'stream-idle-timeout',
|
|
57
|
+
// query/sql-comment.ts, always on (a sqlComment.dynamic value left out)
|
|
58
|
+
'sql-comment-dropped',
|
|
59
|
+
// query/relations.ts, per-query advice
|
|
60
|
+
'relation-payload-json',
|
|
61
|
+
'flatten-fallback',
|
|
62
|
+
'unindexed-relation',
|
|
63
|
+
// prisma-compat.ts
|
|
64
|
+
'prisma-compat-unknown-option',
|
|
65
|
+
'prisma-compat-native-spelling',
|
|
66
|
+
'prisma-map-stale',
|
|
67
|
+
'prisma-compat-junction-collision',
|
|
68
|
+
// powdb.ts, powdb-introspect.ts
|
|
69
|
+
'powdb-link-collision',
|
|
70
|
+
'powdb-link-drift',
|
|
71
|
+
'powdb-introspect-no-primary-key',
|
|
72
|
+
// introspect.ts, generate.ts
|
|
73
|
+
'introspect-cross-schema-fk',
|
|
74
|
+
'introspect-relation-renamed',
|
|
75
|
+
'introspect-relation-shadows-json',
|
|
76
|
+
'generate-relation-shadows-column',
|
|
77
|
+
];
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* turbine-orm, the pluggable logger.
|
|
3
|
+
*
|
|
4
|
+
* Every line Turbine writes goes through a {@link TurbineLogger}: the client's
|
|
5
|
+
* `logger` option, or {@link consoleLogger} when none is set. Each line is a
|
|
6
|
+
* human message plus a {@link TurbineLogEntry} whose `code` is stable and
|
|
7
|
+
* machine-readable; the message text is not a stable contract.
|
|
8
|
+
*
|
|
9
|
+
* No log line carries a bound parameter value or a row value, whatever
|
|
10
|
+
* `logQueryParams` says: that option governs `$on('query')` events only. An
|
|
11
|
+
* entry about a where clause names its keys, never its values.
|
|
12
|
+
*
|
|
13
|
+
* This module and `seed.ts` (a CLI-driven runner) are the only library modules
|
|
14
|
+
* that call `console` directly; a source scan fails the build on another.
|
|
15
|
+
*/
|
|
16
|
+
import type { ResolvedDiagnostics } from './diagnostics.js';
|
|
17
|
+
import type { TurbineLogCode } from './log-codes.js';
|
|
18
|
+
export type { TurbineLogCode } from './log-codes.js';
|
|
19
|
+
/** The structured half of a log line. */
|
|
20
|
+
export interface TurbineLogEntry {
|
|
21
|
+
/** Stable, machine-readable id of the line, e.g. `'pool-error'`, `'unknown-config-key'`. */
|
|
22
|
+
code: string;
|
|
23
|
+
/** The table the line is about, when there is one. */
|
|
24
|
+
table?: string;
|
|
25
|
+
/** The operation the line is about (`'findMany'`, `'$transaction'`), when there is one. */
|
|
26
|
+
operation?: string;
|
|
27
|
+
/** The error the line reports, when it reports one. */
|
|
28
|
+
error?: unknown;
|
|
29
|
+
[field: string]: unknown;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Where Turbine's log lines go. Every method is optional, and a missing method
|
|
33
|
+
* drops that level, so `{}` silences Turbine entirely. The argument order,
|
|
34
|
+
* `(message, entry)`, matches `console` and winston; pino and bunyan take
|
|
35
|
+
* `(object, message)` and need a two-line adapter.
|
|
36
|
+
*
|
|
37
|
+
* A method that throws is ignored: logging never fails the operation that
|
|
38
|
+
* logged.
|
|
39
|
+
*/
|
|
40
|
+
export interface TurbineLogger {
|
|
41
|
+
debug?(message: string, entry: TurbineLogEntry): void;
|
|
42
|
+
info?(message: string, entry: TurbineLogEntry): void;
|
|
43
|
+
warn?(message: string, entry: TurbineLogEntry): void;
|
|
44
|
+
error?(message: string, entry: TurbineLogEntry): void;
|
|
45
|
+
}
|
|
46
|
+
/** One of the four {@link TurbineLogger} levels. */
|
|
47
|
+
export type TurbineLogLevel = 'debug' | 'info' | 'warn' | 'error';
|
|
48
|
+
/**
|
|
49
|
+
* The logger a client uses when `logger` is not set. `console` is looked up
|
|
50
|
+
* on every call, not captured, so anything that replaces `console.warn` (a
|
|
51
|
+
* test, an APM agent) sees Turbine's lines.
|
|
52
|
+
*/
|
|
53
|
+
export declare const consoleLogger: TurbineLogger;
|
|
54
|
+
/**
|
|
55
|
+
* Validate the `logger` option: unset means {@link consoleLogger}; otherwise an
|
|
56
|
+
* object whose `debug` / `info` / `warn` / `error` members, where present, are
|
|
57
|
+
* functions. Other members are ignored, so a pino, winston or console object is
|
|
58
|
+
* accepted as it is. Throws `ValidationError` (E003) otherwise.
|
|
59
|
+
*/
|
|
60
|
+
export declare function resolveLogger(logger: unknown): TurbineLogger;
|
|
61
|
+
/** An entry as Turbine's own emitters build it: the code is one of {@link TurbineLogCode}. */
|
|
62
|
+
export interface InternalLogEntry extends TurbineLogEntry {
|
|
63
|
+
code: TurbineLogCode;
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Send one line to `logger` at `level`. A logger without that level drops it;
|
|
67
|
+
* a logger that throws is ignored. Called as a method, so a class-based
|
|
68
|
+
* logger keeps its `this`.
|
|
69
|
+
*
|
|
70
|
+
* Callers build `message` only once they know the line is wanted (behind the
|
|
71
|
+
* `logging` flag, the advice gate, or the warn-once registry), so a silenced
|
|
72
|
+
* line costs nothing.
|
|
73
|
+
*/
|
|
74
|
+
export declare function logTo(logger: TurbineLogger, level: TurbineLogLevel, message: string, entry: InternalLogEntry): void;
|
|
75
|
+
/**
|
|
76
|
+
* What a client hands to code that wraps it (prisma-compat) or runs on its
|
|
77
|
+
* behalf: its logger and its resolved diagnostics.
|
|
78
|
+
*/
|
|
79
|
+
export interface ClientLogContext {
|
|
80
|
+
readonly logger: TurbineLogger;
|
|
81
|
+
readonly diagnostics: ResolvedDiagnostics;
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* The key a `TurbineClient` exposes its {@link ClientLogContext} under.
|
|
85
|
+
* `Symbol.for`, so an ESM and a CJS copy of the package agree on it.
|
|
86
|
+
*/
|
|
87
|
+
export declare const CLIENT_LOG_CONTEXT: unique symbol;
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* turbine-orm, the pluggable logger.
|
|
4
|
+
*
|
|
5
|
+
* Every line Turbine writes goes through a {@link TurbineLogger}: the client's
|
|
6
|
+
* `logger` option, or {@link consoleLogger} when none is set. Each line is a
|
|
7
|
+
* human message plus a {@link TurbineLogEntry} whose `code` is stable and
|
|
8
|
+
* machine-readable; the message text is not a stable contract.
|
|
9
|
+
*
|
|
10
|
+
* No log line carries a bound parameter value or a row value, whatever
|
|
11
|
+
* `logQueryParams` says: that option governs `$on('query')` events only. An
|
|
12
|
+
* entry about a where clause names its keys, never its values.
|
|
13
|
+
*
|
|
14
|
+
* This module and `seed.ts` (a CLI-driven runner) are the only library modules
|
|
15
|
+
* that call `console` directly; a source scan fails the build on another.
|
|
16
|
+
*/
|
|
17
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
18
|
+
exports.CLIENT_LOG_CONTEXT = exports.consoleLogger = void 0;
|
|
19
|
+
exports.resolveLogger = resolveLogger;
|
|
20
|
+
exports.logTo = logTo;
|
|
21
|
+
const errors_js_1 = require("./errors.js");
|
|
22
|
+
const LEVELS = ['debug', 'info', 'warn', 'error'];
|
|
23
|
+
/**
|
|
24
|
+
* What the default logger prints for one line: `[turbine] <message>`, plus the
|
|
25
|
+
* entry's error as a second argument when the message ends with a colon. Such
|
|
26
|
+
* a message names a failure and the error completes it (`Query listener error:`
|
|
27
|
+
* followed by the error and its stack); every other message is complete on its
|
|
28
|
+
* own and already carries what it needs from the error.
|
|
29
|
+
*/
|
|
30
|
+
function consoleArgs(message, entry) {
|
|
31
|
+
// turbine-prefix-ok: this line only ever reaches the console.* calls in consoleLogger, never an Error.
|
|
32
|
+
const line = `[turbine] ${message}`;
|
|
33
|
+
return entry.error !== undefined && message.endsWith(':') ? [line, entry.error] : [line];
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* The logger a client uses when `logger` is not set. `console` is looked up
|
|
37
|
+
* on every call, not captured, so anything that replaces `console.warn` (a
|
|
38
|
+
* test, an APM agent) sees Turbine's lines.
|
|
39
|
+
*/
|
|
40
|
+
exports.consoleLogger = Object.freeze({
|
|
41
|
+
debug(message, entry) {
|
|
42
|
+
console.log(...consoleArgs(message, entry));
|
|
43
|
+
},
|
|
44
|
+
info(message, entry) {
|
|
45
|
+
console.info(...consoleArgs(message, entry));
|
|
46
|
+
},
|
|
47
|
+
warn(message, entry) {
|
|
48
|
+
console.warn(...consoleArgs(message, entry));
|
|
49
|
+
},
|
|
50
|
+
error(message, entry) {
|
|
51
|
+
console.error(...consoleArgs(message, entry));
|
|
52
|
+
},
|
|
53
|
+
});
|
|
54
|
+
/**
|
|
55
|
+
* Validate the `logger` option: unset means {@link consoleLogger}; otherwise an
|
|
56
|
+
* object whose `debug` / `info` / `warn` / `error` members, where present, are
|
|
57
|
+
* functions. Other members are ignored, so a pino, winston or console object is
|
|
58
|
+
* accepted as it is. Throws `ValidationError` (E003) otherwise.
|
|
59
|
+
*/
|
|
60
|
+
function resolveLogger(logger) {
|
|
61
|
+
if (logger === undefined)
|
|
62
|
+
return exports.consoleLogger;
|
|
63
|
+
if ((typeof logger !== 'object' && typeof logger !== 'function') || logger === null || Array.isArray(logger)) {
|
|
64
|
+
throw new errors_js_1.ValidationError(`Invalid logger option: expected an object with optional debug, info, warn and error methods, got ${logger === null ? 'null' : Array.isArray(logger) ? 'an array' : typeof logger}. Pass {} to silence Turbine, or leave the option unset for console.`);
|
|
65
|
+
}
|
|
66
|
+
for (const level of LEVELS) {
|
|
67
|
+
const member = logger[level];
|
|
68
|
+
if (member !== undefined && typeof member !== 'function') {
|
|
69
|
+
throw new errors_js_1.ValidationError(`Invalid logger option: logger.${level} must be a function (message, entry) or absent, got ${typeof member}.`);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
return logger;
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Send one line to `logger` at `level`. A logger without that level drops it;
|
|
76
|
+
* a logger that throws is ignored. Called as a method, so a class-based
|
|
77
|
+
* logger keeps its `this`.
|
|
78
|
+
*
|
|
79
|
+
* Callers build `message` only once they know the line is wanted (behind the
|
|
80
|
+
* `logging` flag, the advice gate, or the warn-once registry), so a silenced
|
|
81
|
+
* line costs nothing.
|
|
82
|
+
*/
|
|
83
|
+
function logTo(logger, level, message, entry) {
|
|
84
|
+
const method = logger[level];
|
|
85
|
+
if (typeof method !== 'function')
|
|
86
|
+
return;
|
|
87
|
+
try {
|
|
88
|
+
method.call(logger, message, entry);
|
|
89
|
+
}
|
|
90
|
+
catch {
|
|
91
|
+
// A logging failure must never become the caller's failure.
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* The key a `TurbineClient` exposes its {@link ClientLogContext} under.
|
|
96
|
+
* `Symbol.for`, so an ESM and a CJS copy of the package agree on it.
|
|
97
|
+
*/
|
|
98
|
+
exports.CLIENT_LOG_CONTEXT = Symbol.for('turbine-orm.clientLogContext');
|