uql-orm 0.65.1 → 0.67.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/dist/browser/querier/httpQuerier.js +1 -8
- package/dist/browser/uql-browser.min.js.map +5 -5
- package/dist/bunSql/bunSql.util.d.ts +2 -6
- package/dist/bunSql/bunSql.util.js +2 -6
- package/dist/bunSql/bunSqlQuerier.d.ts +2 -5
- package/dist/bunSql/bunSqlQuerier.js +2 -5
- package/dist/cockroachdb/cockroachDialect.d.ts +4 -13
- package/dist/cockroachdb/cockroachDialect.js +4 -13
- package/dist/context/context.browser.js +2 -10
- package/dist/context/context.d.ts +4 -17
- package/dist/context/context.js +4 -17
- package/dist/dialect/abstractDialect.d.ts +4 -19
- package/dist/dialect/abstractDialect.js +2 -20
- package/dist/dialect/abstractSqlDialect.d.ts +47 -212
- package/dist/dialect/abstractSqlDialect.js +68 -222
- package/dist/dialect/aliases.d.ts +2 -12
- package/dist/dialect/aliases.js +4 -12
- package/dist/dialect/hydrateColumn.d.ts +2 -6
- package/dist/dialect/hydrateColumn.js +3 -13
- package/dist/dialect/jsonArrayElemMatchUtils.d.ts +1 -7
- package/dist/dialect/jsonArrayElemMatchUtils.js +1 -7
- package/dist/dialect/jsonSql.d.ts +6 -27
- package/dist/dialect/jsonSql.js +6 -27
- package/dist/dialect/mergeSqlDialect.d.ts +4 -22
- package/dist/dialect/mergeSqlDialect.js +4 -22
- package/dist/dialect/mysqlLikeSqlDialect.d.ts +11 -37
- package/dist/dialect/mysqlLikeSqlDialect.js +35 -51
- package/dist/dialect/pgLikeSqlDialect.d.ts +8 -22
- package/dist/dialect/pgLikeSqlDialect.js +36 -39
- package/dist/dialect/queryContext.d.ts +4 -22
- package/dist/dialect/queryContext.js +4 -22
- package/dist/dialect/queryJoins.d.ts +3 -12
- package/dist/dialect/queryJoins.js +3 -12
- package/dist/dialect/vectorCast.d.ts +2 -12
- package/dist/dialect/vectorCast.js +3 -19
- package/dist/dialect/vectorSqlDialect.d.ts +8 -38
- package/dist/dialect/vectorSqlDialect.js +7 -38
- package/dist/entity/decorator/bag.d.ts +6 -19
- package/dist/entity/decorator/bag.js +6 -22
- package/dist/entity/decorator/entity.d.ts +5 -10
- package/dist/entity/decorator/entity.js +2 -7
- package/dist/entity/decorator/members.d.ts +10 -31
- package/dist/entity/decorator/members.js +3 -12
- package/dist/entity/metadata/definition.d.ts +5 -21
- package/dist/entity/metadata/definition.js +69 -91
- package/dist/http/handler.d.ts +2 -14
- package/dist/index.d.ts +3 -1
- package/dist/index.js +3 -1
- package/dist/libsql/libsqlDialect.d.ts +1 -8
- package/dist/libsql/libsqlDialect.js +1 -8
- package/dist/maria/mariaDialect.d.ts +3 -5
- package/dist/maria/mariaDialect.js +5 -5
- package/dist/maria/mariadbQuerier.js +2 -2
- package/dist/maria/mariadbQuerierPool.js +1 -6
- package/dist/migrate/builder/migrationBuilder.js +3 -19
- package/dist/migrate/builder/splitSqlStatements.d.ts +1 -14
- package/dist/migrate/builder/splitSqlStatements.js +2 -22
- package/dist/migrate/builder/types.d.ts +2 -15
- package/dist/migrate/cli-config.js +2 -11
- package/dist/migrate/cli.js +2 -7
- package/dist/migrate/codegen/entityCodeGenerator.d.ts +0 -15
- package/dist/migrate/codegen/entityCodeGenerator.js +15 -44
- package/dist/migrate/codegen/fieldOptionsSource.d.ts +1 -8
- package/dist/migrate/codegen/fieldOptionsSource.js +3 -22
- package/dist/migrate/ddl/indexDdl.d.ts +2 -5
- package/dist/migrate/ddl/indexDdl.js +2 -5
- package/dist/migrate/ddl/pgIndexDdl.d.ts +3 -13
- package/dist/migrate/ddl/pgIndexDdl.js +3 -13
- package/dist/migrate/generator/definitionToNode.d.ts +2 -9
- package/dist/migrate/generator/definitionToNode.js +3 -17
- package/dist/migrate/generator/indexNodeToSchema.d.ts +2 -3
- package/dist/migrate/generator/indexNodeToSchema.js +2 -3
- package/dist/migrate/generator/mongoCommand.d.ts +1 -8
- package/dist/migrate/generator/mongoSchemaGenerator.d.ts +1 -8
- package/dist/migrate/generator/mongoSchemaGenerator.js +1 -8
- package/dist/migrate/introspection/abstractSqlSchemaIntrospector.d.ts +6 -26
- package/dist/migrate/introspection/abstractSqlSchemaIntrospector.js +9 -41
- package/dist/migrate/introspection/baseSqlIntrospector.js +0 -1
- package/dist/migrate/introspection/mongoIntrospector.d.ts +3 -1
- package/dist/migrate/introspection/mongoIntrospector.js +48 -46
- package/dist/migrate/introspection/mssqlIntrospector.d.ts +4 -4
- package/dist/migrate/introspection/mssqlIntrospector.js +18 -27
- package/dist/migrate/introspection/mysqlIntrospector.d.ts +7 -2
- package/dist/migrate/introspection/mysqlIntrospector.js +16 -14
- package/dist/migrate/introspection/postgresIntrospector.d.ts +24 -9
- package/dist/migrate/introspection/postgresIntrospector.js +68 -59
- package/dist/migrate/introspection/sqliteIntrospector.d.ts +1 -1
- package/dist/migrate/introspection/sqliteIntrospector.js +8 -10
- package/dist/migrate/migrator.d.ts +9 -53
- package/dist/migrate/migrator.js +32 -65
- package/dist/migrate/schemaGenerator.d.ts +20 -66
- package/dist/migrate/schemaGenerator.js +32 -93
- package/dist/mongo/mongoDialect.d.ts +21 -53
- package/dist/mongo/mongoDialect.js +25 -70
- package/dist/mongo/mongodbQuerier.d.ts +5 -8
- package/dist/mongo/mongodbQuerier.js +31 -65
- package/dist/mssql/mssqlDialect.d.ts +8 -34
- package/dist/mssql/mssqlDialect.js +37 -51
- package/dist/mssql/mssqlQuerier.d.ts +37 -4
- package/dist/mssql/mssqlQuerier.js +2 -2
- package/dist/mssql/mssqlWireTypes.d.ts +2 -14
- package/dist/mssql/mssqlWireTypes.js +2 -14
- package/dist/nestjs/uqlModule.js +2 -7
- package/dist/pglite/pgliteQuerier.d.ts +1 -9
- package/dist/pglite/pgliteQuerierPool.d.ts +4 -26
- package/dist/pglite/pgliteQuerierPool.js +3 -18
- package/dist/postgres/abstractPgQuerierPool.d.ts +1 -8
- package/dist/postgres/abstractPgQuerierPool.js +1 -8
- package/dist/postgres/pgNumericTypes.d.ts +3 -26
- package/dist/postgres/pgNumericTypes.js +3 -26
- package/dist/postgres/postgresDialect.d.ts +4 -10
- package/dist/postgres/postgresDialect.js +4 -10
- package/dist/querier/abstractQuerier.d.ts +35 -103
- package/dist/querier/abstractQuerier.js +105 -201
- package/dist/querier/abstractSharedHandleQuerierPool.d.ts +3 -17
- package/dist/querier/abstractSharedHandleQuerierPool.js +3 -17
- package/dist/querier/abstractSqlQuerier.d.ts +15 -36
- package/dist/querier/abstractSqlQuerier.js +49 -131
- package/dist/schema/canonicalType.d.ts +3 -21
- package/dist/schema/canonicalType.js +22 -67
- package/dist/schema/dependencyGraph.d.ts +2 -8
- package/dist/schema/dependencyGraph.js +2 -32
- package/dist/schema/index.d.ts +1 -25
- package/dist/schema/index.js +0 -26
- package/dist/schema/indexColumns.d.ts +1 -8
- package/dist/schema/indexColumns.js +1 -8
- package/dist/schema/indexDifferences.d.ts +7 -40
- package/dist/schema/indexDifferences.js +6 -31
- package/dist/schema/schemaAST.d.ts +8 -175
- package/dist/schema/schemaAST.js +13 -365
- package/dist/schema/schemaASTBuilder.d.ts +2 -24
- package/dist/schema/schemaASTBuilder.js +6 -41
- package/dist/schema/schemaASTDiffer.d.ts +6 -46
- package/dist/schema/schemaASTDiffer.js +8 -56
- package/dist/schema/types.d.ts +5 -61
- package/dist/schema/types.js +3 -6
- package/dist/sqlite/abstractSqliteQuerier.d.ts +1 -8
- package/dist/sqlite/localSqliteQuerierPool.d.ts +1 -7
- package/dist/sqlite/localSqliteQuerierPool.js +1 -7
- package/dist/sqlite/nodeSqliteQuerierPool.d.ts +2 -7
- package/dist/sqlite/nodeSqliteQuerierPool.js +2 -7
- package/dist/sqlite/sqliteDialect.d.ts +5 -20
- package/dist/sqlite/sqliteDialect.js +29 -35
- package/dist/turso/tursoDialect.d.ts +4 -6
- package/dist/turso/tursoDialect.js +4 -6
- package/dist/turso/tursoLocalQuerierPool.d.ts +1 -7
- package/dist/turso/tursoLocalQuerierPool.js +1 -7
- package/dist/turso/tursoQuerierPool.d.ts +2 -6
- package/dist/turso/tursoQuerierPool.js +2 -6
- package/dist/turso/tursoSessionQuerier.d.ts +1 -7
- package/dist/turso/tursoSessionQuerier.js +1 -7
- package/dist/type/dialect.d.ts +42 -94
- package/dist/type/dialect.js +3 -13
- package/dist/type/entity.d.ts +189 -551
- package/dist/type/entity.js +26 -9
- package/dist/type/logger.d.ts +2 -14
- package/dist/type/migration.d.ts +9 -38
- package/dist/type/querier.d.ts +9 -28
- package/dist/type/querierPool.d.ts +4 -26
- package/dist/type/query.d.ts +28 -78
- package/dist/type/query.js +2 -7
- package/dist/type/queryAggregate.d.ts +18 -98
- package/dist/type/queryRaw.d.ts +1 -8
- package/dist/type/queryRaw.js +1 -8
- package/dist/type/queryWhere.d.ts +13 -61
- package/dist/type/universalQuerier.d.ts +18 -105
- package/dist/type/utility.d.ts +12 -24
- package/dist/type/vector.d.ts +8 -38
- package/dist/type/vector.js +1 -1
- package/dist/type/wire.d.ts +2 -5
- package/dist/util/dialect.util.d.ts +9 -27
- package/dist/util/dialect.util.js +10 -27
- package/dist/util/field.util.d.ts +5 -37
- package/dist/util/field.util.js +7 -50
- package/dist/util/fieldOption.util.d.ts +7 -15
- package/dist/util/fieldOption.util.js +1 -1
- package/dist/util/filters.util.d.ts +2 -5
- package/dist/util/filters.util.js +2 -5
- package/dist/util/logger.d.ts +2 -6
- package/dist/util/logger.js +2 -6
- package/dist/util/object.util.d.ts +2 -6
- package/dist/util/object.util.js +1 -5
- package/dist/util/raw.d.ts +3 -23
- package/dist/util/relationQuery.util.d.ts +3 -14
- package/dist/util/relationQuery.util.js +3 -14
- package/dist/util/rowKey.util.d.ts +2 -10
- package/dist/util/rowKey.util.js +2 -10
- package/dist/util/sql.util.d.ts +6 -37
- package/dist/util/sql.util.js +13 -73
- package/dist/util/sqlLiteral.d.ts +2 -13
- package/dist/util/sqlLiteral.js +8 -13
- package/dist/util/string.util.js +0 -2
- package/package.json +4 -4
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { SOFT_DELETE_FILTER } from '../../type/index.js';
|
|
2
2
|
import { isInlinedExpression } from '../../util/field.util.js';
|
|
3
|
-
import { entitySql, entityWhere, fieldOptionConflict, getKeys, hasKeys, isToManyRelation,
|
|
3
|
+
import { entitySql, entityWhere, fieldOptionConflict, getKeys, hasKeys, isToManyRelation, memberRefs, normalizeIndexColumn, definedEntries, } from '../../util/index.js';
|
|
4
4
|
import { ownRegistrations } from '../decorator/bag.js';
|
|
5
5
|
/**
|
|
6
6
|
* A map held on `globalThis` through the global symbol registry, so a single one survives multiple
|
|
@@ -108,7 +108,9 @@ export function defineFilter(entity, name, opts) {
|
|
|
108
108
|
if (name === SOFT_DELETE_FILTER) {
|
|
109
109
|
throw TypeError(`'${entity.name}' filter name '${SOFT_DELETE_FILTER}' is reserved; it is auto-registered from @Field({ softDelete })`);
|
|
110
110
|
}
|
|
111
|
-
|
|
111
|
+
// Widened for a caller the types did not reach, which is the only one this can refuse.
|
|
112
|
+
const { security, onMissing } = opts;
|
|
113
|
+
if (security && onMissing === 'skip') {
|
|
112
114
|
throw TypeError(`'${entity.name}' security filter '${name}' cannot use onMissing: 'skip' (it must fail closed)`);
|
|
113
115
|
}
|
|
114
116
|
(meta.filters ??= {})[name] = opts;
|
|
@@ -173,11 +175,8 @@ export function defineEntity(entity, opts = {}) {
|
|
|
173
175
|
if (!hasKeys(meta.fields)) {
|
|
174
176
|
throw TypeError(`'${entity.name}' must have fields`);
|
|
175
177
|
}
|
|
176
|
-
// A later call composes onto the entity, so
|
|
177
|
-
//
|
|
178
|
-
// It records that the class name stood in, telling a naming strategy there is something to derive;
|
|
179
|
-
// comparing the two cannot, since an entity may name its table exactly what its class is called and
|
|
180
|
-
// a spec's minted class is named after its table.
|
|
178
|
+
// A later call composes onto the entity, so a name is only ever set, and `derivedName` records that
|
|
179
|
+
// the class name stood in, which is what a naming strategy derives from.
|
|
181
180
|
if (opts.name !== undefined) {
|
|
182
181
|
meta.name = opts.name;
|
|
183
182
|
meta.derivedName = false;
|
|
@@ -249,27 +248,11 @@ export function relationOf(meta, key) {
|
|
|
249
248
|
}
|
|
250
249
|
return relation;
|
|
251
250
|
}
|
|
252
|
-
/**
|
|
253
|
-
* Whether the caller named every column of the row's primary key, so {@link idOf} can name the row.
|
|
254
|
-
*
|
|
255
|
-
* `!= null` rather than falsiness: `0` and an empty string are ids a row can legitimately carry, and
|
|
256
|
-
* reading them as "no id" is how a write of that row turned into a second insert. Distinct from
|
|
257
|
-
* "does the row carry this column", which an insert asks of `undefined` alone because that is what
|
|
258
|
-
* decides whether the column appears in its `VALUES` list at all.
|
|
259
|
-
*/
|
|
251
|
+
/** Whether the row names every column of its primary key, `0` and `''` included. */
|
|
260
252
|
export function namesKey(meta, row) {
|
|
261
253
|
return meta.ids.every((key) => row[key] != null);
|
|
262
254
|
}
|
|
263
|
-
/**
|
|
264
|
-
* A row's primary key: the value itself for a single key, an object carrying every key for a
|
|
265
|
-
* composite - which is {@link WrittenId}, and reads as the {@link EntityId} a `$where` takes.
|
|
266
|
-
*
|
|
267
|
-
* What a settled write names its rows by, and what a write hands back. Naming a composite row by one
|
|
268
|
-
* of its columns would address every row agreeing on that one.
|
|
269
|
-
*
|
|
270
|
-
* `WrittenId` does not reduce for an unresolved `E`, so which branch this entity is in cannot be
|
|
271
|
-
* proven here, only checked - which is what `ids.length` does.
|
|
272
|
-
*/
|
|
255
|
+
/** A row's primary key: its value, or a map of every column on a composite, checked at run time. */
|
|
273
256
|
export function idOf(meta, row) {
|
|
274
257
|
const { ids } = meta;
|
|
275
258
|
const id = ids.length === 1 ? row[ids[0]] : Object.fromEntries(ids.map((key) => [key, row[key]]));
|
|
@@ -326,9 +309,13 @@ function registeredMeta(entity) {
|
|
|
326
309
|
function fillRelations(meta) {
|
|
327
310
|
for (const [relKey, relation] of definedEntries(meta.relations)) {
|
|
328
311
|
const at = `'${meta.entity.name}.${relKey}'`;
|
|
329
|
-
|
|
312
|
+
const references = settledReferences(at, meta, relKey, relation);
|
|
313
|
+
if (!references.length) {
|
|
330
314
|
throw new TypeError(`${at} has no columns to join on.`);
|
|
331
315
|
}
|
|
316
|
+
if (!relation.through) {
|
|
317
|
+
assertJoins(at, meta, relation, references);
|
|
318
|
+
}
|
|
332
319
|
}
|
|
333
320
|
// A column `references` names is a foreign key with or without a relation over it, and one cannot point
|
|
334
321
|
// at a composite key: refused on first read, as a relation that cannot join is, not at the schema build.
|
|
@@ -356,18 +343,11 @@ function settledReferences(at, meta, relKey, relOpts) {
|
|
|
356
343
|
return fillInverseSide(at, meta, relOpts, mappedBy);
|
|
357
344
|
if (through)
|
|
358
345
|
return fillThrough(at, meta, relOpts, through);
|
|
359
|
-
|
|
360
|
-
}
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
*/
|
|
365
|
-
function settleOwnColumns(meta) {
|
|
366
|
-
for (const [relKey, relation] of definedEntries(meta.relations)) {
|
|
367
|
-
if (!relation.mappedBy && !relation.through) {
|
|
368
|
-
settledReferences(`'${meta.entity.name}.${relKey}'`, meta, relKey, relation);
|
|
369
|
-
}
|
|
370
|
-
}
|
|
346
|
+
throw new TypeError(isToManyRelation(relOpts)
|
|
347
|
+
? `${at} is a to-many relation with no way to join: it needs 'mappedBy' (the member on the other side), ` +
|
|
348
|
+
"'through' (a junction entity), or 'references' (the columns)."
|
|
349
|
+
: `${at} needs 'references', the foreign key column it joins by, or 'mappedBy', the member on the other ` +
|
|
350
|
+
'side holding it.');
|
|
371
351
|
}
|
|
372
352
|
/**
|
|
373
353
|
* Each key of this entity, then each of the target, paired with the junction's one column referencing it.
|
|
@@ -382,48 +362,9 @@ function fillThrough(at, meta, relOpts, through) {
|
|
|
382
362
|
];
|
|
383
363
|
return relOpts.references;
|
|
384
364
|
}
|
|
385
|
-
function fillOwningSide(at, meta, relKey, relOpts) {
|
|
386
|
-
if (isToManyRelation(relOpts)) {
|
|
387
|
-
throw new TypeError(`${at} is a to-many relation with no way to join: it needs 'mappedBy' (the field on the other side), ` +
|
|
388
|
-
"'through' (a junction entity), or 'references' (the columns).");
|
|
389
|
-
}
|
|
390
|
-
const relMeta = ensureMeta(relOpts.entity());
|
|
391
|
-
// `<rel>Id` for the one-key case it has always been; `<rel><Key>` per column otherwise. Both name a
|
|
392
|
-
// property, so both are spelled from the referenced *property* - a column name is what the naming
|
|
393
|
-
// strategy makes of this afterwards.
|
|
394
|
-
const sole = relMeta.ids.length === 1;
|
|
395
|
-
const references = relMeta.ids.map((key) => ({
|
|
396
|
-
local: sole ? `${relKey}Id` : `${relKey}${upperFirst(key)}`,
|
|
397
|
-
foreign: key,
|
|
398
|
-
}));
|
|
399
|
-
// A column the entity declares would be joined by its name alone, so renaming either one would leave
|
|
400
|
-
// the other behind, still compiling.
|
|
401
|
-
const fields = meta.fields;
|
|
402
|
-
if (references.some(({ local }) => fields[local])) {
|
|
403
|
-
const own = lowerFirst(meta.entity.name);
|
|
404
|
-
throw new TypeError(`${at} joins ${references.map(({ local }) => `'${local}'`).join(', ')} by name, which a rename does not ` +
|
|
405
|
-
`follow: link them with ${sole ? `'references: (${own}) => ${own}.${references[0].local}'` : "'references' pairs"}.`);
|
|
406
|
-
}
|
|
407
|
-
// `typeFromReference` so schema generation resolves the referenced primary key's exact type
|
|
408
|
-
// (columnType, length, chained keys) rather than trusting the fallback, as it does for an
|
|
409
|
-
// explicit `@Field({ references })`.
|
|
410
|
-
for (const { local, foreign } of references) {
|
|
411
|
-
fields[local] = {
|
|
412
|
-
name: local,
|
|
413
|
-
type: fieldOf(relMeta, foreign).type ?? Number,
|
|
414
|
-
references: relOpts.entity,
|
|
415
|
-
referencedKey: foreign,
|
|
416
|
-
typeFromReference: true,
|
|
417
|
-
};
|
|
418
|
-
}
|
|
419
|
-
relOpts.references = references;
|
|
420
|
-
return references;
|
|
421
|
-
}
|
|
422
365
|
function fillInverseSide(at, meta, relOpts, mappedBy) {
|
|
423
366
|
const relMeta = registeredMeta(relOpts.entity());
|
|
424
367
|
const other = `'${relMeta.entity.name}.${mappedBy}'`;
|
|
425
|
-
// The other side's own columns first: they declare, or create, what this side is mapped by.
|
|
426
|
-
settleOwnColumns(relMeta);
|
|
427
368
|
if (relMeta.fields[mappedBy]) {
|
|
428
369
|
if (meta.ids.length > 1) {
|
|
429
370
|
throw new TypeError(`${at} is mapped by ${other}, one column, but the primary key of ` +
|
|
@@ -441,6 +382,10 @@ function fillInverseSide(at, meta, relOpts, mappedBy) {
|
|
|
441
382
|
if (owner.mappedBy) {
|
|
442
383
|
throw new TypeError(`${at} is mapped by ${other}, an inverse side too, so neither owns the foreign key.`);
|
|
443
384
|
}
|
|
385
|
+
const ownerTarget = owner.entity();
|
|
386
|
+
if (!isA(meta.entity, ownerTarget)) {
|
|
387
|
+
throw new TypeError(`${at} is mapped by ${other}, a relation to '${ownerTarget.name}', not to '${meta.entity.name}'.`);
|
|
388
|
+
}
|
|
444
389
|
const ownerReferences = settledReferences(other, relMeta, mappedBy, owner);
|
|
445
390
|
// Two different flips: a junction's pairs are the owner's group followed by ours, so the two groups
|
|
446
391
|
// swap - `toReversed` would also reverse each group, pairing a composite's columns crosswise. A
|
|
@@ -452,16 +397,52 @@ function fillInverseSide(at, meta, relOpts, mappedBy) {
|
|
|
452
397
|
relOpts.through = owner.through;
|
|
453
398
|
return relOpts.references;
|
|
454
399
|
}
|
|
400
|
+
/**
|
|
401
|
+
* Refuses a join on a column either entity does not store, and a one-column join whose foreign key, on
|
|
402
|
+
* whichever side holds it, points at another entity: it would match unrelated rows by their keys.
|
|
403
|
+
*/
|
|
404
|
+
function assertJoins(at, meta, relOpts, pairs) {
|
|
405
|
+
const target = registeredMeta(relOpts.entity());
|
|
406
|
+
// Only the owning side of a to-one holds its foreign key; an inverse side and a to-many join on the target's.
|
|
407
|
+
const holdsLocally = !relOpts.mappedBy && !isToManyRelation(relOpts);
|
|
408
|
+
const sides = [
|
|
409
|
+
{ meta: columnsOf(meta), keys: pairs.map(({ local }) => local), joins: target.entity, holds: holdsLocally },
|
|
410
|
+
{ meta: columnsOf(target), keys: pairs.map(({ foreign }) => foreign), joins: meta.entity, holds: !holdsLocally },
|
|
411
|
+
];
|
|
412
|
+
for (const side of sides) {
|
|
413
|
+
for (const key of side.keys) {
|
|
414
|
+
const column = `'${side.meta.entity.name}.${key}'`;
|
|
415
|
+
const field = side.meta.fields[key];
|
|
416
|
+
if (!field || isInlinedExpression(field)) {
|
|
417
|
+
throw new TypeError(`${at} joins ${column}, which is not a column: declare it with '@Field'.`);
|
|
418
|
+
}
|
|
419
|
+
const referenced = side.holds && pairs.length === 1 ? field.references?.() : undefined;
|
|
420
|
+
if (referenced && !isA(side.joins, referenced)) {
|
|
421
|
+
throw new TypeError(`${at} joins ${column}, a foreign key to '${referenced.name}', not to '${side.joins.name}'.`);
|
|
422
|
+
}
|
|
423
|
+
}
|
|
424
|
+
}
|
|
425
|
+
}
|
|
426
|
+
/** `meta` with its fields read by any name, as a join's columns come. */
|
|
427
|
+
function columnsOf(meta) {
|
|
428
|
+
return meta;
|
|
429
|
+
}
|
|
430
|
+
/** Whether `entity` is `base` or extends it, as an entity inheriting a relation does. */
|
|
431
|
+
function isA(entity, base) {
|
|
432
|
+
return entity === base || entity.prototype instanceof base;
|
|
433
|
+
}
|
|
455
434
|
/**
|
|
456
435
|
* The foreign keys an entity holds: each owning to-one's columns, and each `@Field({ references })` no
|
|
457
436
|
* relation joins on, as the many-to-one it describes, once its target has registered a key. What the
|
|
458
|
-
* schema build constrains and a junction joins by,
|
|
437
|
+
* schema build constrains and a junction joins by, settling the relations holding them first.
|
|
459
438
|
*/
|
|
460
439
|
export function foreignKeysOf(meta) {
|
|
461
|
-
settleOwnColumns(meta);
|
|
462
440
|
const owning = definedEntries(meta.relations)
|
|
463
|
-
.
|
|
464
|
-
.
|
|
441
|
+
.filter(([, relation]) => !relation.mappedBy && !relation.through && !isToManyRelation(relation))
|
|
442
|
+
.map(([relKey, relation]) => {
|
|
443
|
+
settledReferences(`'${meta.entity.name}.${relKey}'`, meta, relKey, relation);
|
|
444
|
+
return relation;
|
|
445
|
+
});
|
|
465
446
|
const joined = new Set(owning.flatMap(({ references }) => references.map(({ local }) => local)));
|
|
466
447
|
const columns = definedEntries(meta.fields).flatMap(([key, field]) => {
|
|
467
448
|
if (!field.references || joined.has(key))
|
|
@@ -471,8 +452,8 @@ export function foreignKeysOf(meta) {
|
|
|
471
452
|
return [];
|
|
472
453
|
if (target.ids.length > 1) {
|
|
473
454
|
throw new TypeError(`'${meta.entity.name}.${key}' cannot reference '${target.entity.name}', whose primary key is composite ` +
|
|
474
|
-
`(${target.ids.join(', ')}): a column points at one.
|
|
475
|
-
`'@ManyToOne
|
|
455
|
+
`(${target.ids.join(', ')}): a column points at one. Declare a column per key and pair each with it ` +
|
|
456
|
+
`in a '@ManyToOne' to '${target.entity.name}'.`);
|
|
476
457
|
}
|
|
477
458
|
return [{ entity: field.references, cardinality: 'm1', references: [{ local: key, foreign: target.ids[0] }] }];
|
|
478
459
|
});
|
|
@@ -486,9 +467,9 @@ function junctionReferences(at, junction, side) {
|
|
|
486
467
|
const referenced = `'${side.entity.name}.${key}'`;
|
|
487
468
|
if (!pair) {
|
|
488
469
|
const declare = side.ids.length > 1
|
|
489
|
-
?
|
|
490
|
-
:
|
|
491
|
-
throw new TypeError(`${at} joins through '${junction.entity.name}', which has no column referencing ${referenced}: declare
|
|
470
|
+
? `a column per key, paired in a '@ManyToOne' to '${side.entity.name}'`
|
|
471
|
+
: `'@Field({ references: () => ${side.entity.name} })'`;
|
|
472
|
+
throw new TypeError(`${at} joins through '${junction.entity.name}', which has no column referencing ${referenced}: declare ${declare}.`);
|
|
492
473
|
}
|
|
493
474
|
if (others.length) {
|
|
494
475
|
const columns = [pair, ...others].map(({ local }) => `'${local}'`).join(' and ');
|
|
@@ -503,11 +484,8 @@ function getIdKeys(meta) {
|
|
|
503
484
|
return getKeys(meta.fields).filter((key) => meta.fields[key]?.isId);
|
|
504
485
|
}
|
|
505
486
|
/**
|
|
506
|
-
* Merges `ancestor` and its
|
|
507
|
-
*
|
|
508
|
-
* its registrations, so do it here. Walking the *class* prototype chain rather than the metadata
|
|
509
|
-
* object's is what makes this work on every transformer: tsc and esbuild chain metadata across
|
|
510
|
-
* `extends`, SWC does not.
|
|
487
|
+
* Merges `ancestor` and its ancestors into `meta`, nearest first, draining an undecorated base's
|
|
488
|
+
* registrations. Walks the class chain, since not every compiler chains decorator metadata.
|
|
511
489
|
*/
|
|
512
490
|
function inheritFrom(meta, ancestor) {
|
|
513
491
|
for (let parent = ancestor; parent && parent !== Object; parent = parentOf(parent)) {
|
package/dist/http/handler.d.ts
CHANGED
|
@@ -29,13 +29,7 @@ export type HookContext<E extends object, Ctx = unknown> = {
|
|
|
29
29
|
readonly meta: EntityMeta<E>;
|
|
30
30
|
readonly op: CrudOperation;
|
|
31
31
|
readonly method: HttpMethod;
|
|
32
|
-
/**
|
|
33
|
-
* parsed query - mutate in place or reassign to shape it (e.g. force a `$select`, inject a
|
|
34
|
-
* `$sort`). For actual tenant/row-level scoping, prefer `@Filter(..., { security: true })` on
|
|
35
|
-
* the entity instead: unlike a hook mutation, it is AND-merged (a client `$where` on the same
|
|
36
|
-
* key cannot silently win), fails closed when its context is missing, and applies uniformly
|
|
37
|
-
* across every query path including joined relations.
|
|
38
|
-
*/
|
|
32
|
+
/** The parsed query, to reshape in place. Scope rows with a `security` filter instead, which a client cannot override. */
|
|
39
33
|
query: Query<E>;
|
|
40
34
|
/**
|
|
41
35
|
* request payload - reassignable for sanitization or field injection.
|
|
@@ -51,13 +45,7 @@ export type ResponseHook<Ctx = unknown> = <E extends object>(ctx: HookContext<E,
|
|
|
51
45
|
export type RequestHandlerOptions<Ctx = unknown> = {
|
|
52
46
|
include?: Type<object>[];
|
|
53
47
|
exclude?: Type<object>[];
|
|
54
|
-
/**
|
|
55
|
-
* The URL segment an entity is addressed by, defaulting to its kebab-cased class name.
|
|
56
|
-
*
|
|
57
|
-
* State it where the default cannot serve: a build that minifies class names renames every route,
|
|
58
|
-
* and two entities mapping one table in different schemas collide on one. The browser client takes
|
|
59
|
-
* the same option, so both ends can read one map.
|
|
60
|
-
*/
|
|
48
|
+
/** The URL segment an entity is addressed by, its kebab-cased class name by default; the browser client takes the same option. */
|
|
61
49
|
entityPath?: (entity: Type<unknown>) => string;
|
|
62
50
|
/**
|
|
63
51
|
* Allow augment any kind of request before it runs. Hooks may be async
|
package/dist/index.d.ts
CHANGED
|
@@ -4,4 +4,6 @@ export * from './entity/index.js';
|
|
|
4
4
|
export * from './namingStrategy/index.js';
|
|
5
5
|
export * from './querier/index.js';
|
|
6
6
|
export * from './type/index.js';
|
|
7
|
-
export
|
|
7
|
+
export { withDeleted } from './util/filters.util.js';
|
|
8
|
+
export { DefaultLogger } from './util/logger.js';
|
|
9
|
+
export { raw, refs } from './util/raw.js';
|
package/dist/index.js
CHANGED
|
@@ -4,4 +4,6 @@ export * from './entity/index.js';
|
|
|
4
4
|
export * from './namingStrategy/index.js';
|
|
5
5
|
export * from './querier/index.js';
|
|
6
6
|
export * from './type/index.js';
|
|
7
|
-
export
|
|
7
|
+
export { withDeleted } from './util/filters.util.js';
|
|
8
|
+
export { DefaultLogger } from './util/logger.js';
|
|
9
|
+
export { raw, refs } from './util/raw.js';
|
|
@@ -7,13 +7,6 @@ import type { VectorDistance, VectorMetric } from '../type/index.js';
|
|
|
7
7
|
* functions, which `TursoDialect` inherits.
|
|
8
8
|
*/
|
|
9
9
|
export declare class LibsqlDialect extends SqliteDialect {
|
|
10
|
-
/**
|
|
11
|
-
* libSQL has vector search built in, under its own names, so the sqlite-vec `vec_distance_*`
|
|
12
|
-
* functions this dialect would otherwise inherit are never present.
|
|
13
|
-
*
|
|
14
|
-
* @remarks `inner` and `l1` are left out: `vector_distance_dot` only exists in the newer Rust
|
|
15
|
-
* engine (see `TursoLocalDialect`) and no libSQL build has an L1 metric. Both raise the same
|
|
16
|
-
* "does not support vector distance metric" error as any other unsupported metric.
|
|
17
|
-
*/
|
|
10
|
+
/** libSQL's built-in vector functions; no `inner` (only the Rust engine has it) and no `l1`. */
|
|
18
11
|
readonly vectorMetrics: ReadonlyMap<VectorDistance, VectorMetric>;
|
|
19
12
|
}
|
|
@@ -6,14 +6,7 @@ import { SqliteDialect } from '../sqlite/sqliteDialect.js';
|
|
|
6
6
|
* functions, which `TursoDialect` inherits.
|
|
7
7
|
*/
|
|
8
8
|
export class LibsqlDialect extends SqliteDialect {
|
|
9
|
-
/**
|
|
10
|
-
* libSQL has vector search built in, under its own names, so the sqlite-vec `vec_distance_*`
|
|
11
|
-
* functions this dialect would otherwise inherit are never present.
|
|
12
|
-
*
|
|
13
|
-
* @remarks `inner` and `l1` are left out: `vector_distance_dot` only exists in the newer Rust
|
|
14
|
-
* engine (see `TursoLocalDialect`) and no libSQL build has an L1 metric. Both raise the same
|
|
15
|
-
* "does not support vector distance metric" error as any other unsupported metric.
|
|
16
|
-
*/
|
|
9
|
+
/** libSQL's built-in vector functions; no `inner` (only the Rust engine has it) and no `l1`. */
|
|
17
10
|
vectorMetrics = new Map([
|
|
18
11
|
['cosine', { fn: 'vector_distance_cos' }],
|
|
19
12
|
['l2', { fn: 'vector_distance_l2' }],
|
|
@@ -1,16 +1,14 @@
|
|
|
1
1
|
import { type RelationRows } from '../dialect/abstractSqlDialect.js';
|
|
2
2
|
import { MysqlLikeSqlDialect } from '../dialect/mysqlLikeSqlDialect.js';
|
|
3
|
-
import type {
|
|
3
|
+
import type { EntityMeta, FieldOptions, Query, QueryContext, SqlDialectFeatures, Type, VectorDistance, VectorMetric } from '../type/index.js';
|
|
4
4
|
export declare class MariaDialect extends MysqlLikeSqlDialect {
|
|
5
5
|
readonly dialectName = "mariadb";
|
|
6
6
|
readonly insertIdSource = "returning";
|
|
7
|
-
/** MariaDB has no `FOR ... OF`, so a lock cannot be narrowed to one table of a join. */
|
|
8
|
-
readonly supportsLockOf = false;
|
|
9
7
|
/**
|
|
10
8
|
* Unlike MySQL: `VECTOR(n)` takes its dimension, every column of a vector index has to be NOT NULL,
|
|
11
|
-
*
|
|
9
|
+
* `CREATE INDEX` takes `IF NOT EXISTS`, and a lock cannot be narrowed to one table of a join.
|
|
12
10
|
*/
|
|
13
|
-
|
|
11
|
+
readonly features: SqlDialectFeatures;
|
|
14
12
|
/**
|
|
15
13
|
* A derived table here reads no column of the statement around it, so the aggregate reads the
|
|
16
14
|
* related table itself, and orders and pages inside `JSON_ARRAYAGG`, which takes both.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { relationTermKey } from '../dialect/abstractSqlDialect.js';
|
|
2
2
|
import { jsonPath } from '../dialect/jsonSql.js';
|
|
3
|
-
import { MysqlLikeSqlDialect } from '../dialect/mysqlLikeSqlDialect.js';
|
|
3
|
+
import { MYSQL_FEATURES, MysqlLikeSqlDialect } from '../dialect/mysqlLikeSqlDialect.js';
|
|
4
4
|
import { getMeta } from '../entity/index.js';
|
|
5
5
|
import { columnFamily } from '../util/field.util.js';
|
|
6
6
|
import { MARIA_VECTOR_METRICS } from './mariaVectorMetrics.js';
|
|
@@ -8,16 +8,16 @@ export class MariaDialect extends MysqlLikeSqlDialect {
|
|
|
8
8
|
dialectName = 'mariadb';
|
|
9
9
|
// MariaDB 10.5+ has `INSERT ... RETURNING`, so ids come back exact per row - the upsert's too.
|
|
10
10
|
insertIdSource = 'returning';
|
|
11
|
-
/** MariaDB has no `FOR ... OF`, so a lock cannot be narrowed to one table of a join. */
|
|
12
|
-
supportsLockOf = false;
|
|
13
11
|
/**
|
|
14
12
|
* Unlike MySQL: `VECTOR(n)` takes its dimension, every column of a vector index has to be NOT NULL,
|
|
15
|
-
*
|
|
13
|
+
* `CREATE INDEX` takes `IF NOT EXISTS`, and a lock cannot be narrowed to one table of a join.
|
|
16
14
|
*/
|
|
17
|
-
|
|
15
|
+
features = {
|
|
16
|
+
...MYSQL_FEATURES,
|
|
18
17
|
vectorSupportsLength: true,
|
|
19
18
|
vectorIndexRequiresNotNull: true,
|
|
20
19
|
indexIfNotExists: true,
|
|
20
|
+
rowLockOf: false,
|
|
21
21
|
};
|
|
22
22
|
/**
|
|
23
23
|
* A derived table here reads no column of the statement around it, so the aggregate reads the
|
|
@@ -7,8 +7,8 @@ export class MariadbQuerier extends AbstractPoolQuerier {
|
|
|
7
7
|
}
|
|
8
8
|
async internalRun(query, values) {
|
|
9
9
|
const res = await this.getConn().query(query, values);
|
|
10
|
-
//
|
|
11
|
-
const changes = res.affectedRows ?? res.length
|
|
10
|
+
// An OK packet reports `affectedRows`; a `RETURNING` statement answers rows instead, and counts by them.
|
|
11
|
+
const changes = res.affectedRows ?? res.length;
|
|
12
12
|
const rows = res.length ? Array.from(res, decodeBigInts) : [];
|
|
13
13
|
return this.buildUpdateResult({ rows, changes, upsertStatus: res.affectedRows });
|
|
14
14
|
}
|
|
@@ -11,12 +11,7 @@ export class MariadbQuerierPool extends AbstractSqlQuerierPool {
|
|
|
11
11
|
// BIGINT stays the driver's `bigint`, which `MariadbQuerier` decodes by the rule every driver here
|
|
12
12
|
// shares (`decodeWideNumber`) - not `bigIntAsNumber`, which rounds past 2^53 without a word.
|
|
13
13
|
this.pool = createPool(opts);
|
|
14
|
-
// `mariadb`'
|
|
15
|
-
// listener (so a dropped connection can't crash the process), but its
|
|
16
|
-
// `Pool` type only declares `on` for 'acquire' | 'connection' | 'enqueue'
|
|
17
|
-
// | 'release' - 'error' genuinely fires at runtime (see `lib/pool.js`)
|
|
18
|
-
// but isn't in the declaration, hence the cast. Re-attaching our own
|
|
19
|
-
// listener here just makes the error visible instead of a silent no-op.
|
|
14
|
+
// `mariadb` fires 'error' at runtime without declaring it, hence the cast; this makes it visible.
|
|
20
15
|
attachPoolErrorHandler(this.pool, 'Idle MariaDB pool connection encountered an error', extra?.logger);
|
|
21
16
|
}
|
|
22
17
|
async getQuerier() {
|
|
@@ -20,13 +20,7 @@ function createIndexOperation(tableName, columns, options = {}) {
|
|
|
20
20
|
},
|
|
21
21
|
};
|
|
22
22
|
}
|
|
23
|
-
/**
|
|
24
|
-
* The one shape of an `addForeignKey` operation, `NO ACTION` defaults included.
|
|
25
|
-
*
|
|
26
|
-
* Three callers build it and differ only in what they do with the result: the table builder records
|
|
27
|
-
* it through its parent, the recorder records it directly, and the executing builder also runs it.
|
|
28
|
-
* Spelled out three times, a changed default would have had to be found in all three.
|
|
29
|
-
*/
|
|
23
|
+
/** An `addForeignKey` operation, `NO ACTION` defaults included, for the three builders that record one. */
|
|
30
24
|
function addForeignKeyOperation(tableName, columns, target, options = {}) {
|
|
31
25
|
return {
|
|
32
26
|
type: 'addForeignKey',
|
|
@@ -40,21 +34,11 @@ function addForeignKeyOperation(tableName, columns, target, options = {}) {
|
|
|
40
34
|
},
|
|
41
35
|
};
|
|
42
36
|
}
|
|
43
|
-
/**
|
|
44
|
-
* Declare one column through the same vocabulary `createTable` uses. A throwaway {@link TableBuilder}
|
|
45
|
-
* is that vocabulary: `addColumn`/`alterColumn` used to take a bare {@link IColumnBuilder}, which
|
|
46
|
-
* cannot express a type, so every column they recorded was hard-coded `VARCHAR`.
|
|
47
|
-
*/
|
|
37
|
+
/** One column declared through `createTable`'s vocabulary, a throwaway {@link TableBuilder}, so its type is stated. */
|
|
48
38
|
function buildOneColumn(callback) {
|
|
49
39
|
return callback(new TableBuilder('')).build();
|
|
50
40
|
}
|
|
51
|
-
/**
|
|
52
|
-
* Collects the operations one `alterTable` callback declares, in the order it declared them.
|
|
53
|
-
*
|
|
54
|
-
* Collected rather than dispatched to the parent as they are made: the chaining methods are
|
|
55
|
-
* synchronous by contract, so a builder that executes could only fire and forget, which returned from
|
|
56
|
-
* `alterTable` with the statements still in flight and turned a failure into an unhandled rejection.
|
|
57
|
-
*/
|
|
41
|
+
/** The operations one `alterTable` callback declares, collected in order, since its methods are synchronous. */
|
|
58
42
|
class AlterTableBuilder {
|
|
59
43
|
tableName;
|
|
60
44
|
operations = [];
|
|
@@ -1,15 +1,2 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Splits a SQL blob on semicolons into separate statements.
|
|
3
|
-
*
|
|
4
|
-
* Uses a declarative Master-Regex scanner to rapidly
|
|
5
|
-
* identify and skip "non-splittable" blocks (strings, comments, dollar-quotes) in a single pass.
|
|
6
|
-
* This approach is $O(n)$, leverages native regex speed, and is trivially easy to audit.
|
|
7
|
-
*
|
|
8
|
-
* Handles:
|
|
9
|
-
* - Single quotes: '...' (standard SQL, respects '' and \')
|
|
10
|
-
* - Double quotes: "..." (identifiers or MySQL strings)
|
|
11
|
-
* - Backticks: `...` (MySQL identifiers)
|
|
12
|
-
* - Postgres Dollar quotes: $tag$...$tag$ or $$...$$
|
|
13
|
-
* - Comments: -- and /* ... *\/
|
|
14
|
-
*/
|
|
1
|
+
/** Splits SQL on semicolons, skipping strings, quoted identifiers, dollar-quoted blocks and comments in one regex pass. */
|
|
15
2
|
export declare function splitSqlStatements(sql: string): string[];
|
|
@@ -1,28 +1,8 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Splits a SQL blob on semicolons into separate statements.
|
|
3
|
-
*
|
|
4
|
-
* Uses a declarative Master-Regex scanner to rapidly
|
|
5
|
-
* identify and skip "non-splittable" blocks (strings, comments, dollar-quotes) in a single pass.
|
|
6
|
-
* This approach is $O(n)$, leverages native regex speed, and is trivially easy to audit.
|
|
7
|
-
*
|
|
8
|
-
* Handles:
|
|
9
|
-
* - Single quotes: '...' (standard SQL, respects '' and \')
|
|
10
|
-
* - Double quotes: "..." (identifiers or MySQL strings)
|
|
11
|
-
* - Backticks: `...` (MySQL identifiers)
|
|
12
|
-
* - Postgres Dollar quotes: $tag$...$tag$ or $$...$$
|
|
13
|
-
* - Comments: -- and /* ... *\/
|
|
14
|
-
*/
|
|
1
|
+
/** Splits SQL on semicolons, skipping strings, quoted identifiers, dollar-quoted blocks and comments in one regex pass. */
|
|
15
2
|
export function splitSqlStatements(sql) {
|
|
16
3
|
const statements = [];
|
|
17
4
|
let lastIndex = 0;
|
|
18
|
-
//
|
|
19
|
-
// 1. Single quoted strings: '(?:''|\\['\\]|[^'])*(?:'|(?=$))
|
|
20
|
-
// 2. Double quoted identifiers: "(?:""|\\["\\]|[^"])*(?:"|(?=$))
|
|
21
|
-
// 3. Backticked identifiers: `(?:``|\\[`\\]|[^`])*(?:`|(?=$))
|
|
22
|
-
// 4. Postgres Dollar quoted blocks: \$(?<tag>[a-zA-Z0-9_]*)\$[\s\S]*?(?:\$\k<tag>|(?=$))
|
|
23
|
-
// 5. Single-line comments: --.*
|
|
24
|
-
// 6. Multi-line comments: \/\*[\s\S]*?(?:\*\/|(?=$))
|
|
25
|
-
// 7. Statement terminator: ;
|
|
5
|
+
// Quoted strings and identifiers, dollar quotes, comments, or a `;`: the one regex scanning them all.
|
|
26
6
|
const masterRegex = /'(?:''|\\['\\]|[^'])*(?:'|(?=$))|"(?:""|\\["\\]|[^"])*(?:"|(?=$))|`(?:``|\\[`\\]|[^`])*(?:`|(?=$))|\$(?<tag>[a-zA-Z0-9_]*)\$[\s\S]*?(?:\$\k<tag>|(?=$))|--.*|\/\*[\s\S]*?(?:\*\/|(?=$))|;/g;
|
|
27
7
|
for (const match of sql.matchAll(masterRegex)) {
|
|
28
8
|
if (match[0] === ';') {
|
|
@@ -67,14 +67,7 @@ export interface VectorColumnOptions extends BaseColumnOptions {
|
|
|
67
67
|
/** Number of dimensions */
|
|
68
68
|
dimensions?: number;
|
|
69
69
|
}
|
|
70
|
-
/**
|
|
71
|
-
* A column as the builder describes one: {@link ColumnNode} without the graph links a DTO cannot carry.
|
|
72
|
-
*
|
|
73
|
-
* Derived rather than restated, so the two cannot drift. A column gained `enum` and this shape was
|
|
74
|
-
* simply missing it, which is why a hand-written `createTable` could never constrain one. A field
|
|
75
|
-
* added to the node now reaches here, and failing to render it is a compile error rather than a
|
|
76
|
-
* column that quietly loses half its declaration.
|
|
77
|
-
*/
|
|
70
|
+
/** A column as the builder describes one: a {@link ColumnNode} without its graph links. */
|
|
78
71
|
export type ColumnDefinition = Omit<ColumnNode, 'table' | 'referencedBy' | 'references'>;
|
|
79
72
|
/**
|
|
80
73
|
* The foreign key a single column declares: {@link ForeignKeySchema} without the local columns, which
|
|
@@ -260,13 +253,7 @@ export interface IForeignKeyBuilder extends IColumnBuilder {
|
|
|
260
253
|
/** Set ON UPDATE action */
|
|
261
254
|
onUpdate(action: ForeignKeyAction): this;
|
|
262
255
|
}
|
|
263
|
-
/**
|
|
264
|
-
* The column vocabulary: every column type the builder can declare, name first.
|
|
265
|
-
*
|
|
266
|
-
* Split out of {@link ITableBuilder} so `addColumn`/`alterColumn` can hand it to their callback. They
|
|
267
|
-
* used to take an {@link IColumnBuilder}, which has no way to say what type a column is - so the
|
|
268
|
-
* builder hard-coded `VARCHAR`, and every column a generated migration added or altered was a string.
|
|
269
|
-
*/
|
|
256
|
+
/** Every column type the builder can declare, name first, handed to `addColumn`/`alterColumn` callbacks too. */
|
|
270
257
|
export interface IColumnFactory {
|
|
271
258
|
/** Add an auto-incrementing primary key */
|
|
272
259
|
id(name?: string, options?: BaseColumnOptions): IColumnBuilder;
|
|
@@ -2,17 +2,8 @@ import { stat } from 'node:fs/promises';
|
|
|
2
2
|
import { resolve } from 'node:path';
|
|
3
3
|
import { pathToFileURL } from 'node:url';
|
|
4
4
|
/**
|
|
5
|
-
* Loads the config with a plain `import()`, leaving TypeScript to
|
|
6
|
-
*
|
|
7
|
-
* @remarks uql deliberately bundles no transpiler. The config imports the entity classes, so whoever
|
|
8
|
-
* loads it decides which decorator spec their decorators are invoked with, and only the runtime knows
|
|
9
|
-
* the project's `tsconfig.json`. Bun and `node --import tsx` both get it right; a bundled loader would
|
|
10
|
-
* be guessing, and `jiti` guessed wrong (it hardcodes the legacy transform, so standard decorators were
|
|
11
|
-
* called as `(prototype, key)` and every field was silently dropped).
|
|
12
|
-
*
|
|
13
|
-
* Node's own type stripping covers a config that is only types plus a plain object, which is why the
|
|
14
|
-
* error below distinguishes the two cases: decorators are not erasable syntax, so a config that reaches
|
|
15
|
-
* decorated entity classes needs a runtime that actually transforms them.
|
|
5
|
+
* Loads the config with a plain `import()`, leaving TypeScript to the runtime: uql bundles no transpiler,
|
|
6
|
+
* since only the project knows its decorator spec. Node's type stripping handles no decorators.
|
|
16
7
|
*/
|
|
17
8
|
async function importConfig(path) {
|
|
18
9
|
const mod = (await import(pathToFileURL(path).href).catch((cause) => {
|
package/dist/migrate/cli.js
CHANGED
|
@@ -76,11 +76,7 @@ export async function main(args = process.argv.slice(2)) {
|
|
|
76
76
|
printHelp();
|
|
77
77
|
process.exit(1);
|
|
78
78
|
}
|
|
79
|
-
|
|
80
|
-
const pool = config.pool;
|
|
81
|
-
if (pool.end) {
|
|
82
|
-
await pool.end();
|
|
83
|
-
}
|
|
79
|
+
await config.pool.end();
|
|
84
80
|
}
|
|
85
81
|
catch (error) {
|
|
86
82
|
console.error('Error:', error.message);
|
|
@@ -202,8 +198,7 @@ export async function runSync(migrator, args, config) {
|
|
|
202
198
|
const force = args.includes('--force');
|
|
203
199
|
const safe = !args.includes('--unsafe');
|
|
204
200
|
const options = { force, safe, drop: !safe };
|
|
205
|
-
// Ahead of the warning
|
|
206
|
-
// asked for, and it used to be ignored beside `--force`.
|
|
201
|
+
// Ahead of the warning and the run: `--dry-run` means the same whatever else was asked for, `--force` included.
|
|
207
202
|
if (args.includes('--dry-run')) {
|
|
208
203
|
const statements = await migrator.planSync(options);
|
|
209
204
|
console.log(statements.length ? `\n${statements.join('\n')}` : '\nSchema is already in sync.');
|
|
@@ -1,14 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Entity Code Generator
|
|
3
|
-
*
|
|
4
|
-
* Generates TypeScript entity files from SchemaAST.
|
|
5
|
-
* Supports:
|
|
6
|
-
* - ES Module syntax
|
|
7
|
-
* - TypeScript types
|
|
8
|
-
* - Relations with proper decorators
|
|
9
|
-
* - Indexes
|
|
10
|
-
* - JSDoc comments for sync-added fields
|
|
11
|
-
*/
|
|
12
1
|
import type { SchemaAST } from '../../schema/schemaAST.js';
|
|
13
2
|
/**
|
|
14
3
|
* Options for entity code generation.
|
|
@@ -107,10 +96,6 @@ export declare class EntityCodeGenerator {
|
|
|
107
96
|
* Build incoming relation (OneToMany where other tables have FK to this).
|
|
108
97
|
*/
|
|
109
98
|
private buildIncomingRelation;
|
|
110
|
-
/**
|
|
111
|
-
* Get decorator name for relation type.
|
|
112
|
-
*/
|
|
113
|
-
private getRelationDecoratorName;
|
|
114
99
|
/**
|
|
115
100
|
* Format type for description.
|
|
116
101
|
*/
|