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,25 +1,4 @@
|
|
|
1
|
-
import type
|
|
2
|
-
/**
|
|
3
|
-
* The kind of column a field lands on, which is what decides whether an option means anything on it:
|
|
4
|
-
* `length` is a string's, `precision` a number's, `dimensions` a vector's. Named in the words an
|
|
5
|
-
* error reports it in, so there is no second table of labels to keep in step.
|
|
6
|
-
*/
|
|
7
|
-
export type ColumnFamily = 'string' | 'numeric' | 'boolean' | 'date' | 'json' | 'blob' | 'vector';
|
|
8
|
-
/**
|
|
9
|
-
* The runtime half of the column-type unions in `type/entity.ts`, which TypeScript erases. Each list
|
|
10
|
-
* is checked against its own union, so a type cannot be filed under the wrong family, and
|
|
11
|
-
* {@link UnplacedColumnType} refuses to compile if a new one is filed under none. Nothing here
|
|
12
|
-
* restates the unions: the compile-time side of the same question reads them directly.
|
|
13
|
-
*/
|
|
14
|
-
export declare const COLUMN_TYPES_BY_FAMILY: {
|
|
15
|
-
readonly numeric: readonly ["int", "integer", "tinyint", "smallint", "bigint", "float", "float4", "float8", "double", "double precision", "decimal", "numeric", "real"];
|
|
16
|
-
readonly string: readonly ["char", "varchar", "text", "uuid"];
|
|
17
|
-
readonly date: readonly ["date", "time", "datetime", "timestamp", "timestamptz"];
|
|
18
|
-
readonly json: readonly ["json", "jsonb"];
|
|
19
|
-
readonly blob: readonly ["blob", "bytea"];
|
|
20
|
-
readonly boolean: readonly ["bool", "boolean"];
|
|
21
|
-
readonly vector: readonly ["vector", "halfvec", "sparsevec"];
|
|
22
|
-
};
|
|
1
|
+
import { type ColumnFamily, type EntityMeta, type FieldOptions } from '../type/index.js';
|
|
23
2
|
/** The family of a logical field type, or `undefined` where it names none. */
|
|
24
3
|
export declare function columnFamily(type: unknown): ColumnFamily | undefined;
|
|
25
4
|
/**
|
|
@@ -38,22 +17,11 @@ export declare function isInlinedExpression<F extends FieldOptions>(field: F): f
|
|
|
38
17
|
* computed column *is* a real column, read like one, but writing to it is an error on every engine.
|
|
39
18
|
*/
|
|
40
19
|
export declare function isDatabaseWritten(field: FieldOptions): boolean;
|
|
41
|
-
/**
|
|
42
|
-
* Whether the field is the entity's *whole* primary key - the only kind a serial can stand in for,
|
|
43
|
-
* and the only one that may state `PRIMARY KEY` in its own column definition.
|
|
44
|
-
*
|
|
45
|
-
* One column of a composite is a value the caller supplies, and the table states the key over every
|
|
46
|
-
* column at once. Asked in one place because the two schema paths - the AST that builds a
|
|
47
|
-
* `CREATE TABLE` and the diff that builds an `ALTER` - have to answer it the same way, and each
|
|
48
|
-
* answering for itself is what put a serial `PRIMARY KEY` on both columns of a composite.
|
|
49
|
-
*/
|
|
20
|
+
/** Whether the field is the whole primary key, the only kind a serial stands for and a column may declare. */
|
|
50
21
|
export declare function isSoleIdField<E>(meta: EntityMeta<E>, field: FieldOptions): boolean;
|
|
51
22
|
/**
|
|
52
|
-
* Whether the database generates this column's value.
|
|
53
|
-
*
|
|
54
|
-
* The
|
|
55
|
-
* `onInsert`, so a key the application generates was still emitted `AUTO_INCREMENT`, and it ignored
|
|
56
|
-
* `columnType`, where this one used to let *any* declared width suppress the whole inference. A key
|
|
57
|
-
* that states its width is still a generated key; one that states how it is filled is not.
|
|
23
|
+
* Whether the database generates this column's value: a numeric key nothing else fills. `onInsert` fills
|
|
24
|
+
* it from the application and `references` from the row it shares its key with; a `columnType` only
|
|
25
|
+
* states its width. The one answer the create statement and the diff both read.
|
|
58
26
|
*/
|
|
59
27
|
export declare function isAutoIncrement(field: FieldOptions, isPrimaryKey: boolean): boolean;
|
package/dist/util/field.util.js
CHANGED
|
@@ -1,33 +1,5 @@
|
|
|
1
|
+
import { COLUMN_TYPES, } from '../type/index.js';
|
|
1
2
|
import { getKeys } from './object.util.js';
|
|
2
|
-
/**
|
|
3
|
-
* The runtime half of the column-type unions in `type/entity.ts`, which TypeScript erases. Each list
|
|
4
|
-
* is checked against its own union, so a type cannot be filed under the wrong family, and
|
|
5
|
-
* {@link UnplacedColumnType} refuses to compile if a new one is filed under none. Nothing here
|
|
6
|
-
* restates the unions: the compile-time side of the same question reads them directly.
|
|
7
|
-
*/
|
|
8
|
-
export const COLUMN_TYPES_BY_FAMILY = {
|
|
9
|
-
numeric: [
|
|
10
|
-
'int',
|
|
11
|
-
'integer',
|
|
12
|
-
'tinyint',
|
|
13
|
-
'smallint',
|
|
14
|
-
'bigint',
|
|
15
|
-
'float',
|
|
16
|
-
'float4',
|
|
17
|
-
'float8',
|
|
18
|
-
'double',
|
|
19
|
-
'double precision',
|
|
20
|
-
'decimal',
|
|
21
|
-
'numeric',
|
|
22
|
-
'real',
|
|
23
|
-
],
|
|
24
|
-
string: ['char', 'varchar', 'text', 'uuid'],
|
|
25
|
-
date: ['date', 'time', 'datetime', 'timestamp', 'timestamptz'],
|
|
26
|
-
json: ['json', 'jsonb'],
|
|
27
|
-
blob: ['blob', 'bytea'],
|
|
28
|
-
boolean: ['bool', 'boolean'],
|
|
29
|
-
vector: ['vector', 'halfvec', 'sparsevec'],
|
|
30
|
-
};
|
|
31
3
|
// Constructors and type strings in one map: a logical type is either, and every caller asks the same
|
|
32
4
|
// question of both.
|
|
33
5
|
const FAMILY_OF = new Map([
|
|
@@ -36,12 +8,8 @@ const FAMILY_OF = new Map([
|
|
|
36
8
|
[BigInt, 'numeric'],
|
|
37
9
|
[Boolean, 'boolean'],
|
|
38
10
|
[Date, 'date'],
|
|
11
|
+
...getKeys(COLUMN_TYPES).flatMap((family) => COLUMN_TYPES[family].map((type) => [type, family])),
|
|
39
12
|
]);
|
|
40
|
-
for (const family of getKeys(COLUMN_TYPES_BY_FAMILY)) {
|
|
41
|
-
for (const columnType of COLUMN_TYPES_BY_FAMILY[family]) {
|
|
42
|
-
FAMILY_OF.set(columnType, family);
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
13
|
/** The family of a logical field type, or `undefined` where it names none. */
|
|
46
14
|
export function columnFamily(type) {
|
|
47
15
|
return FAMILY_OF.get(typeof type === 'string' ? type.toLowerCase() : type);
|
|
@@ -80,28 +48,17 @@ export function isInlinedExpression(field) {
|
|
|
80
48
|
export function isDatabaseWritten(field) {
|
|
81
49
|
return field.computed !== undefined;
|
|
82
50
|
}
|
|
83
|
-
/**
|
|
84
|
-
* Whether the field is the entity's *whole* primary key - the only kind a serial can stand in for,
|
|
85
|
-
* and the only one that may state `PRIMARY KEY` in its own column definition.
|
|
86
|
-
*
|
|
87
|
-
* One column of a composite is a value the caller supplies, and the table states the key over every
|
|
88
|
-
* column at once. Asked in one place because the two schema paths - the AST that builds a
|
|
89
|
-
* `CREATE TABLE` and the diff that builds an `ALTER` - have to answer it the same way, and each
|
|
90
|
-
* answering for itself is what put a serial `PRIMARY KEY` on both columns of a composite.
|
|
91
|
-
*/
|
|
51
|
+
/** Whether the field is the whole primary key, the only kind a serial stands for and a column may declare. */
|
|
92
52
|
export function isSoleIdField(meta, field) {
|
|
93
53
|
return field.isId === true && meta.ids.length === 1;
|
|
94
54
|
}
|
|
95
55
|
/**
|
|
96
|
-
* Whether the database generates this column's value.
|
|
97
|
-
*
|
|
98
|
-
* The
|
|
99
|
-
* `onInsert`, so a key the application generates was still emitted `AUTO_INCREMENT`, and it ignored
|
|
100
|
-
* `columnType`, where this one used to let *any* declared width suppress the whole inference. A key
|
|
101
|
-
* that states its width is still a generated key; one that states how it is filled is not.
|
|
56
|
+
* Whether the database generates this column's value: a numeric key nothing else fills. `onInsert` fills
|
|
57
|
+
* it from the application and `references` from the row it shares its key with; a `columnType` only
|
|
58
|
+
* states its width. The one answer the create statement and the diff both read.
|
|
102
59
|
*/
|
|
103
60
|
export function isAutoIncrement(field, isPrimaryKey) {
|
|
104
61
|
if (field.autoIncrement !== undefined)
|
|
105
62
|
return field.autoIncrement;
|
|
106
|
-
return isPrimaryKey && columnFamily(field.type) === 'numeric' && !field.onInsert;
|
|
63
|
+
return isPrimaryKey && columnFamily(field.type) === 'numeric' && !field.onInsert && !field.references;
|
|
107
64
|
}
|
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
import { type ColumnFamily } from './field.util.js';
|
|
1
|
+
import type { ColumnFamily, FamilyOf, FieldOptions, QueryRaw } from '../type/index.js';
|
|
3
2
|
/**
|
|
4
3
|
* The column family each field option means anything on, or `'*'` where it applies to every column.
|
|
5
4
|
* Exhaustive over {@link FieldOptions}, so a new option cannot be added without placing it - the
|
|
@@ -54,13 +53,11 @@ type GeneratedWrite = (typeof GENERATED_WRITES)[number];
|
|
|
54
53
|
*/
|
|
55
54
|
export declare function fieldOptionConflict(opts: FieldOptions): string | undefined;
|
|
56
55
|
/** The family the options put the column in; every family where they name no type to put it in. */
|
|
57
|
-
type
|
|
56
|
+
type OptionsFamily<O> = O extends {
|
|
58
57
|
readonly columnType: infer C;
|
|
59
|
-
} ?
|
|
58
|
+
} ? FamilyOf<C> : O extends {
|
|
60
59
|
readonly type: infer T;
|
|
61
|
-
} ?
|
|
62
|
-
/** Read off the column-type unions themselves, which is what `COLUMN_TYPES_BY_FAMILY` is checked against. */
|
|
63
|
-
type FamilyOfType<T> = T extends NumericColumnType | NumberConstructor | BigIntConstructor ? 'numeric' : T extends StringColumnType | StringConstructor ? 'string' : T extends VectorColumnType ? 'vector' : T extends JsonColumnType ? 'json' : T extends DateColumnType | DateConstructor ? 'date' : T extends BooleanColumnType | BooleanConstructor ? 'boolean' : T extends BlobColumnType ? 'blob' : ColumnFamily;
|
|
60
|
+
} ? FamilyOf<T> : ColumnFamily;
|
|
64
61
|
/** What the field's own values leave unread, matching {@link deadOn} line for line. */
|
|
65
62
|
type DeadOptions<O> = (O extends {
|
|
66
63
|
readonly stored: true;
|
|
@@ -74,16 +71,11 @@ type DeadOptions<O> = (O extends {
|
|
|
74
71
|
} ? 'onUpdate' : never);
|
|
75
72
|
type Given<O> = Extract<keyof O, keyof FieldOptions>;
|
|
76
73
|
type Offending<O> = {
|
|
77
|
-
[K in Given<O>]: (typeof FIELD_OPTION_FAMILY)[K] extends
|
|
74
|
+
[K in Given<O>]: (typeof FIELD_OPTION_FAMILY)[K] extends OptionsFamily<O> | '*' ? K extends DeadOptions<O> ? K : never : K;
|
|
78
75
|
}[Given<O>];
|
|
79
76
|
/**
|
|
80
|
-
*
|
|
81
|
-
*
|
|
82
|
-
* - an inert intersection member - when there are none.
|
|
83
|
-
*
|
|
84
|
-
* `@Id` adds `{ nullable?: false }` of its own rather than passing the `isId` it stamps on, which
|
|
85
|
-
* would have to reach `O` as an intersection - and a non-naked `O` in its own constraint stops it
|
|
86
|
-
* inferring from the options at all.
|
|
77
|
+
* Every option `O` states but cannot use, mapped to `never`, so one that would be ignored does not compile.
|
|
78
|
+
* `@Id` states `{ nullable?: false }` itself, since `O` has to stay naked to be inferred.
|
|
87
79
|
*/
|
|
88
80
|
export type RejectIncompatible<O> = [Offending<O>] extends [never] ? unknown : Record<Offending<O> & string, never>;
|
|
89
81
|
export {};
|
|
@@ -83,7 +83,7 @@ function deadOn(opts, key) {
|
|
|
83
83
|
export function fieldOptionConflict(opts) {
|
|
84
84
|
const family = columnFamily(opts.columnType ?? opts.type);
|
|
85
85
|
// Walked in table order, not in the order the field happened to be written, so a field with two
|
|
86
|
-
// conflicts always reports the same one. An option no rule knows is a typo, which `
|
|
86
|
+
// conflicts always reports the same one. An option no rule knows is a typo, which `@Field`'s own check
|
|
87
87
|
// reports where it can still be spelled right.
|
|
88
88
|
for (const key of getKeys(FIELD_OPTION_FAMILY)) {
|
|
89
89
|
const applies = FIELD_OPTION_FAMILY[key];
|
|
@@ -1,10 +1,7 @@
|
|
|
1
1
|
import type { QueryOptions } from '../type/index.js';
|
|
2
2
|
/**
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
* over the wire. To list *only* trashed rows with a serializable query, constrain the field instead,
|
|
6
|
-
* e.g. `querier.findMany(User, { $where: { deletedAt: { $ne: null } } })` - the filter steps aside
|
|
7
|
-
* for any key you set in `$where`.
|
|
3
|
+
* Options including soft-deleted rows, server-side only. To list only deleted ones over the wire, filter
|
|
4
|
+
* the field: `{ $where: { deletedAt: { $ne: null } } }`.
|
|
8
5
|
* @example `querier.findMany(User, {}, withDeleted())`
|
|
9
6
|
*/
|
|
10
7
|
export declare function withDeleted(): QueryOptions;
|
|
@@ -1,9 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
*
|
|
4
|
-
* over the wire. To list *only* trashed rows with a serializable query, constrain the field instead,
|
|
5
|
-
* e.g. `querier.findMany(User, { $where: { deletedAt: { $ne: null } } })` - the filter steps aside
|
|
6
|
-
* for any key you set in `$where`.
|
|
2
|
+
* Options including soft-deleted rows, server-side only. To list only deleted ones over the wire, filter
|
|
3
|
+
* the field: `{ $where: { deletedAt: { $ne: null } } }`.
|
|
7
4
|
* @example `querier.findMany(User, {}, withDeleted())`
|
|
8
5
|
*/
|
|
9
6
|
export function withDeleted() {
|
package/dist/util/logger.d.ts
CHANGED
|
@@ -63,11 +63,7 @@ export interface ErrorEmittingPool {
|
|
|
63
63
|
on(event: 'error', listener: (err: Error) => void): unknown;
|
|
64
64
|
}
|
|
65
65
|
/**
|
|
66
|
-
*
|
|
67
|
-
*
|
|
68
|
-
* (node-postgres, `mssql`), or is silently swallowed by those that install a no-op of their own
|
|
69
|
-
* (`mariadb`). Reported through the pool's own logger when it has one, and through the default one
|
|
70
|
-
* otherwise: never dropped, whatever levels were configured, since a swallowed pool error is exactly
|
|
71
|
-
* the failure this guards against.
|
|
66
|
+
* Logs a pool's dropped connection, which some drivers would otherwise crash the process on, through
|
|
67
|
+
* the pool's logger or the default one, whatever levels were configured.
|
|
72
68
|
*/
|
|
73
69
|
export declare function attachPoolErrorHandler(pool: ErrorEmittingPool, message: string, logging?: LoggingOptions): void;
|
package/dist/util/logger.js
CHANGED
|
@@ -155,12 +155,8 @@ export function queryLoggerFor(extra) {
|
|
|
155
155
|
return wrapper;
|
|
156
156
|
}
|
|
157
157
|
/**
|
|
158
|
-
*
|
|
159
|
-
*
|
|
160
|
-
* (node-postgres, `mssql`), or is silently swallowed by those that install a no-op of their own
|
|
161
|
-
* (`mariadb`). Reported through the pool's own logger when it has one, and through the default one
|
|
162
|
-
* otherwise: never dropped, whatever levels were configured, since a swallowed pool error is exactly
|
|
163
|
-
* the failure this guards against.
|
|
158
|
+
* Logs a pool's dropped connection, which some drivers would otherwise crash the process on, through
|
|
159
|
+
* the pool's logger or the default one, whatever levels were configured.
|
|
164
160
|
*/
|
|
165
161
|
export function attachPoolErrorHandler(pool, message, logging) {
|
|
166
162
|
const logger = new LoggerWrapper(isOwnLogger(logging) ? logging : true);
|
|
@@ -11,17 +11,13 @@ export declare function hasKeys<T>(obj: T): obj is NonNullable<T>;
|
|
|
11
11
|
export declare function someKey<T extends object>(obj: T, pred: (key: keyof T & string) => boolean): boolean;
|
|
12
12
|
/** Whether any enumerable value of `obj` satisfies `pred`, short-circuiting like {@link someKey}. */
|
|
13
13
|
export declare function someValue(obj: object, pred: (value: unknown) => boolean): boolean;
|
|
14
|
-
/**
|
|
15
|
-
* Whether `value` is a non-empty object whose keys are query/update operators (`$eq`, `$push`, ...).
|
|
16
|
-
* The single source of this test: the SQL dialects, the MongoDB dialect and the `$elemMatch` walker
|
|
17
|
-
* all classify operator objects with it, and they used to disagree about `{}`.
|
|
18
|
-
*/
|
|
14
|
+
/** Whether `value` is a non-empty object with an operator key (`$eq`, `$push`...): the one test every dialect classifies with. */
|
|
19
15
|
export declare function isOperatorObject(value: unknown): value is Record<string, unknown>;
|
|
20
16
|
/** Whether every key of the non-empty object `value` is an operator (no plain field names mixed in). */
|
|
21
17
|
export declare function isOperatorOnlyObject(value: unknown): value is Record<string, unknown>;
|
|
22
18
|
/** Whether `value` is an object that is not an array, whose keys can be read. */
|
|
23
19
|
export declare function isRecord(value: unknown): value is Record<string, unknown>;
|
|
24
|
-
export declare function getKeys<T extends object>(obj: T): (keyof T & string)[];
|
|
20
|
+
export declare function getKeys<T extends object>(obj: T | null | undefined): (keyof T & string)[];
|
|
25
21
|
/** The entries of `record` holding a value: a key declared but left `undefined` is no entry at all. */
|
|
26
22
|
export declare function definedEntries<K extends string, V>(record: Partial<Record<K, V>>): [K, V][];
|
|
27
23
|
/**
|
package/dist/util/object.util.js
CHANGED
|
@@ -37,11 +37,7 @@ export function someValue(obj, pred) {
|
|
|
37
37
|
return someKey(obj, (key) => pred(obj[key]));
|
|
38
38
|
}
|
|
39
39
|
const isOperatorKey = (key) => key.startsWith('$');
|
|
40
|
-
/**
|
|
41
|
-
* Whether `value` is a non-empty object whose keys are query/update operators (`$eq`, `$push`, ...).
|
|
42
|
-
* The single source of this test: the SQL dialects, the MongoDB dialect and the `$elemMatch` walker
|
|
43
|
-
* all classify operator objects with it, and they used to disagree about `{}`.
|
|
44
|
-
*/
|
|
40
|
+
/** Whether `value` is a non-empty object with an operator key (`$eq`, `$push`...): the one test every dialect classifies with. */
|
|
45
41
|
export function isOperatorObject(value) {
|
|
46
42
|
return hasKeys(value) && !Array.isArray(value) && someKey(value, isOperatorKey);
|
|
47
43
|
}
|
package/dist/util/raw.d.ts
CHANGED
|
@@ -1,28 +1,8 @@
|
|
|
1
1
|
import { type EntitySql, type EntityWhere, type EntityWhereMeta, QueryRaw, type QueryRawFn, type RefMap, type Type } from '../type/index.js';
|
|
2
2
|
/**
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
* what it is, so a value cannot become SQL whatever it holds:
|
|
7
|
-
*
|
|
8
|
-
* | Interpolated | Becomes |
|
|
9
|
-
* | :------------------ | :------------------------------------- |
|
|
10
|
-
* | any value | a bound parameter; in DDL, its literal |
|
|
11
|
-
* | a {@link ColumnRef} | its column, escaped and qualified |
|
|
12
|
-
* | a {@link QueryRaw} | that fragment, in place |
|
|
13
|
-
*
|
|
14
|
-
* ```ts
|
|
15
|
-
* const user = refs(User);
|
|
16
|
-
* raw`GREATEST(0, ${user.creditsAllowance} - ${amount})`
|
|
17
|
-
* raw`CONCAT(${user.firstName}, ' ', ${user.lastName})`
|
|
18
|
-
* raw`LOG10(${points})`.as('score')
|
|
19
|
-
* ```
|
|
20
|
-
*
|
|
21
|
-
* The callback form remains for SQL a template cannot express, such as a sub-query generated through
|
|
22
|
-
* `dialect.find(...)`.
|
|
23
|
-
*
|
|
24
|
-
* **⚠️ Security:** the tag is safe because it binds; a callback is not, since it emits whatever it
|
|
25
|
-
* writes, so never build one from user input. Inside a callback, bind with `ctx.addValue()`.
|
|
3
|
+
* Raw SQL, where an interpolated value binds, a `refs` field renders its column, and a `raw` renders
|
|
4
|
+
* in place: `raw`GREATEST(0, ${user.credits} - ${amount})``. A callback writes whatever it writes, so
|
|
5
|
+
* never build one from user input. See the Raw SQL guide.
|
|
26
6
|
*/
|
|
27
7
|
export declare function raw(strings: TemplateStringsArray, ...values: readonly unknown[]): QueryRaw;
|
|
28
8
|
export declare function raw(value: QueryRawFn): QueryRaw;
|
|
@@ -15,22 +15,11 @@ export type ParentJoin = {
|
|
|
15
15
|
readonly joined: string;
|
|
16
16
|
};
|
|
17
17
|
/**
|
|
18
|
-
* How a relation joins
|
|
19
|
-
*
|
|
20
|
-
* goes through one, the child's foreign key otherwise.
|
|
21
|
-
*
|
|
22
|
-
* The two are spelled from opposite ends of `references` (`local` names a column of the table the
|
|
23
|
-
* relation is declared on, `foreign` a column of the other one), and getting that backwards reads a
|
|
24
|
-
* real column of the wrong table, so it is answered once here. One pair per key of the parent.
|
|
18
|
+
* How a relation joins its parent, one pair per key: `parent` a column of the parent's table, `joined` the
|
|
19
|
+
* matching one on the table the relation reads, a junction's or the child's.
|
|
25
20
|
*/
|
|
26
21
|
export declare function parentJoins(relOpts: Pick<RelationMeta, 'references' | 'through'>, parentKeyCount: number): ParentJoin[];
|
|
27
|
-
/**
|
|
28
|
-
* The junction columns holding the target's key, the other half of {@link parentJoins}.
|
|
29
|
-
*
|
|
30
|
-
* `parentKeyCount` is required: the target's columns start after the parent's, so guessing the
|
|
31
|
-
* boundary returned the parent's *second* column as the target's - a real column of the wrong side,
|
|
32
|
-
* which is the mistake this module exists to prevent.
|
|
33
|
-
*/
|
|
22
|
+
/** The junction columns holding the target's key, after the parent's `parentKeyCount` ones. */
|
|
34
23
|
export declare function targetKeyColumns(relOpts: Pick<RelationMeta, 'references'>, parentKeyCount: number): string[];
|
|
35
24
|
/**
|
|
36
25
|
* The `$where` naming exactly the children of the rows `parentIds` identifies: an `IN` over the one
|
|
@@ -14,13 +14,8 @@ export function isToManyRelation(relation) {
|
|
|
14
14
|
return relation.cardinality === '1m' || relation.cardinality === 'mm';
|
|
15
15
|
}
|
|
16
16
|
/**
|
|
17
|
-
* How a relation joins
|
|
18
|
-
*
|
|
19
|
-
* goes through one, the child's foreign key otherwise.
|
|
20
|
-
*
|
|
21
|
-
* The two are spelled from opposite ends of `references` (`local` names a column of the table the
|
|
22
|
-
* relation is declared on, `foreign` a column of the other one), and getting that backwards reads a
|
|
23
|
-
* real column of the wrong table, so it is answered once here. One pair per key of the parent.
|
|
17
|
+
* How a relation joins its parent, one pair per key: `parent` a column of the parent's table, `joined` the
|
|
18
|
+
* matching one on the table the relation reads, a junction's or the child's.
|
|
24
19
|
*/
|
|
25
20
|
export function parentJoins(relOpts, parentKeyCount) {
|
|
26
21
|
if (!relOpts.through) {
|
|
@@ -30,13 +25,7 @@ export function parentJoins(relOpts, parentKeyCount) {
|
|
|
30
25
|
// something its caller already knows - so the boundary is passed rather than stored on a relation.
|
|
31
26
|
return relOpts.references.slice(0, parentKeyCount).map(({ local, foreign }) => ({ parent: foreign, joined: local }));
|
|
32
27
|
}
|
|
33
|
-
/**
|
|
34
|
-
* The junction columns holding the target's key, the other half of {@link parentJoins}.
|
|
35
|
-
*
|
|
36
|
-
* `parentKeyCount` is required: the target's columns start after the parent's, so guessing the
|
|
37
|
-
* boundary returned the parent's *second* column as the target's - a real column of the wrong side,
|
|
38
|
-
* which is the mistake this module exists to prevent.
|
|
39
|
-
*/
|
|
28
|
+
/** The junction columns holding the target's key, after the parent's `parentKeyCount` ones. */
|
|
40
29
|
export function targetKeyColumns(relOpts, parentKeyCount) {
|
|
41
30
|
return relOpts.references.slice(parentKeyCount).map(({ local }) => local);
|
|
42
31
|
}
|
|
@@ -1,13 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* A row's key
|
|
3
|
-
*
|
|
4
|
-
* Reads the columns off the row rather than taking their values, because every caller matches a
|
|
5
|
-
* whole page of rows against one fixed column list: taking an array would make each of them build
|
|
6
|
-
* one per row, which is what a page of 250 rows paid 56 KB for.
|
|
7
|
-
*
|
|
8
|
-
* Values are normalized before joining, not stringified: `String(date)` is locale- and
|
|
9
|
-
* timezone-dependent, so two equal dates could key apart, and a `Uint8Array` stringifies to its
|
|
10
|
-
* bytes with commas. Every column is included, so two rows agreeing on one column of a composite
|
|
11
|
-
* key are not treated as one row.
|
|
2
|
+
* A row's key over `columns`, for matching rows: read off the row, so a page builds no array per row, and
|
|
3
|
+
* normalized rather than stringified, since `String(date)` depends on the locale.
|
|
12
4
|
*/
|
|
13
5
|
export declare function rowKey(row: unknown, columns: readonly string[]): string;
|
package/dist/util/rowKey.util.js
CHANGED
|
@@ -1,16 +1,8 @@
|
|
|
1
1
|
/** Separates the parts of a composite key: a unit separator, which no column value carries. */
|
|
2
2
|
const KEY_SEPARATOR = '\u001f';
|
|
3
3
|
/**
|
|
4
|
-
* A row's key
|
|
5
|
-
*
|
|
6
|
-
* Reads the columns off the row rather than taking their values, because every caller matches a
|
|
7
|
-
* whole page of rows against one fixed column list: taking an array would make each of them build
|
|
8
|
-
* one per row, which is what a page of 250 rows paid 56 KB for.
|
|
9
|
-
*
|
|
10
|
-
* Values are normalized before joining, not stringified: `String(date)` is locale- and
|
|
11
|
-
* timezone-dependent, so two equal dates could key apart, and a `Uint8Array` stringifies to its
|
|
12
|
-
* bytes with commas. Every column is included, so two rows agreeing on one column of a composite
|
|
13
|
-
* key are not treated as one row.
|
|
4
|
+
* A row's key over `columns`, for matching rows: read off the row, so a page builds no array per row, and
|
|
5
|
+
* normalized rather than stringified, since `String(date)` depends on the locale.
|
|
14
6
|
*/
|
|
15
7
|
export function rowKey(row, columns) {
|
|
16
8
|
const values = row;
|
package/dist/util/sql.util.d.ts
CHANGED
|
@@ -17,18 +17,8 @@ export declare function obtainAttrsPaths<T extends object>(row: T): {
|
|
|
17
17
|
*/
|
|
18
18
|
export declare function qualifyName(name: string, schema?: string): string;
|
|
19
19
|
/**
|
|
20
|
-
* The name a derived index or constraint gets
|
|
21
|
-
*
|
|
22
|
-
* One owner for all four kinds, because it is a rule two layers apply and a third has to match: the
|
|
23
|
-
* entity AST derives it, the DDL generator falls back to it, and a `DROP` names what it drops.
|
|
24
|
-
* `table` is the table's own name, never qualified - the result is a single identifier.
|
|
25
|
-
*
|
|
26
|
-
* The kind goes last, as Postgres spells its own (`users_pkey`, `users_email_idx`), so a table's
|
|
27
|
-
* constraints sort together under the table they belong to.
|
|
28
|
-
*
|
|
29
|
-
* Not overridable, deliberately: a `NamingStrategy` hook would have to reach the eight call sites
|
|
30
|
-
* these have, an introspector and two builders among them, to replace a name any declaration can
|
|
31
|
-
* already set outright with `name:`. Worth revisiting only for a case that option cannot express.
|
|
20
|
+
* The name a derived index or constraint gets, `Order__total_idx`, kind last as Postgres names its own.
|
|
21
|
+
* One rule for the AST, the DDL and a `DROP`; not a naming strategy hook, since `name:` already overrides it.
|
|
32
22
|
*/
|
|
33
23
|
export declare function derivedConstraintName(table: string, parts: readonly (string | number)[], kind: ConstraintKind): string;
|
|
34
24
|
/** The kinds of derived name, which is also what `indexNameStem` strips to compare them. */
|
|
@@ -49,13 +39,7 @@ export declare function derivedPrimaryKeyName(table: string, columns: readonly s
|
|
|
49
39
|
export declare function derivedCheckName(table: string, position: number): string;
|
|
50
40
|
/** The constraint name a foreign key gets when nothing named it: `Order__customerId_fk`. */
|
|
51
41
|
export declare function derivedForeignKeyName(table: string, columns: readonly string[]): string;
|
|
52
|
-
/**
|
|
53
|
-
* Escape a SQL identifier (table name, column name, etc.)
|
|
54
|
-
* @param val the identifier to escape
|
|
55
|
-
* @param escapeIdChar the escape character to use (e.g. ` or ")
|
|
56
|
-
* @param forbidQualified whether to forbid qualified identifiers (containing dots)
|
|
57
|
-
* @param addDot whether to add a dot suffix
|
|
58
|
-
*/
|
|
42
|
+
/** Escapes an identifier with `escapeIdChar`, refusing a dotted one where `forbidQualified`, with a trailing dot where `addDot`. */
|
|
59
43
|
export declare function escapeSqlId(val: string | undefined, escapeIdChar?: '`' | '"', forbidQualified?: boolean, addDot?: boolean): string;
|
|
60
44
|
/**
|
|
61
45
|
* Payload for building a QueryUpdateResult.
|
|
@@ -81,24 +65,9 @@ export interface BuildUpdateResultPayload {
|
|
|
81
65
|
upsertStatus?: number;
|
|
82
66
|
}
|
|
83
67
|
/**
|
|
84
|
-
*
|
|
85
|
-
*
|
|
86
|
-
*
|
|
87
|
-
* so the result rows always contain an `id` property regardless of the entity's @Id() key name.
|
|
88
|
-
*
|
|
89
|
-
* The header-derived ID path assumes the database allocated consecutive values for the
|
|
90
|
-
* statement, which holds for a single multi-row `INSERT ... VALUES` on auto-increment keys
|
|
91
|
-
* (with the standard `auto_increment_increment = 1`); the querier only maps these IDs onto
|
|
92
|
-
* payloads when that assumption is safe.
|
|
93
|
-
*
|
|
94
|
-
* Caveat (MySQL/MariaDB-compatible engines with no `RETURNING`, i.e. `insertIdSource: 'firstId'`):
|
|
95
|
-
* contiguous allocation across a statement's rows is only guaranteed under
|
|
96
|
-
* `innodb_autoinc_lock_mode` 0 (`traditional`) or 1 (`consecutive`). Under mode 2 (`interleaved`,
|
|
97
|
-
* MySQL 8.0's default), other connections inserting into the same table concurrently with this
|
|
98
|
-
* statement can interleave with its auto-increment allocation, so the inferred IDs may not be
|
|
99
|
-
* contiguous. There is no code-level fix for this (MySQL has no `RETURNING`); avoid relying on
|
|
100
|
-
* inferred multi-row IDs for a table under heavy concurrent insert load, or set
|
|
101
|
-
* `innodb_autoinc_lock_mode` to 0 or 1.
|
|
68
|
+
* A driver's result as a {@link QueryUpdateResult}: `RETURNING` rows name their id `id`; a MySQL header's
|
|
69
|
+
* first id is extended by the increment, which holds only where auto-increment allocation is contiguous
|
|
70
|
+
* (`innodb_autoinc_lock_mode` 0 or 1).
|
|
102
71
|
*/
|
|
103
72
|
export declare function buildUpdateResult(payload: BuildUpdateResultPayload): QueryUpdateResult;
|
|
104
73
|
/**
|
package/dist/util/sql.util.js
CHANGED
|
@@ -2,7 +2,7 @@ import { hasKeys } from './object.util.js';
|
|
|
2
2
|
/** Pre-computed regex for each SQL identifier escape character to avoid per-call allocation. */
|
|
3
3
|
const escapeIdRegexCache = { '`': /`/g, '"': /"/g };
|
|
4
4
|
export function unflatObjects(objects) {
|
|
5
|
-
if (!
|
|
5
|
+
if (!objects.length) {
|
|
6
6
|
return objects;
|
|
7
7
|
}
|
|
8
8
|
const attrsPaths = obtainAttrsPaths(objects[0]);
|
|
@@ -66,40 +66,16 @@ const MAX_IDENTIFIER_LENGTH = 63;
|
|
|
66
66
|
/** Hex chars of hash kept when a name has to be shortened. 24 bits over one table's constraints. */
|
|
67
67
|
const NAME_HASH_LENGTH = 6;
|
|
68
68
|
/**
|
|
69
|
-
* The name a derived index or constraint gets
|
|
70
|
-
*
|
|
71
|
-
* One owner for all four kinds, because it is a rule two layers apply and a third has to match: the
|
|
72
|
-
* entity AST derives it, the DDL generator falls back to it, and a `DROP` names what it drops.
|
|
73
|
-
* `table` is the table's own name, never qualified - the result is a single identifier.
|
|
74
|
-
*
|
|
75
|
-
* The kind goes last, as Postgres spells its own (`users_pkey`, `users_email_idx`), so a table's
|
|
76
|
-
* constraints sort together under the table they belong to.
|
|
77
|
-
*
|
|
78
|
-
* Not overridable, deliberately: a `NamingStrategy` hook would have to reach the eight call sites
|
|
79
|
-
* these have, an introspector and two builders among them, to replace a name any declaration can
|
|
80
|
-
* already set outright with `name:`. Worth revisiting only for a case that option cannot express.
|
|
69
|
+
* The name a derived index or constraint gets, `Order__total_idx`, kind last as Postgres names its own.
|
|
70
|
+
* One rule for the AST, the DDL and a `DROP`; not a naming strategy hook, since `name:` already overrides it.
|
|
81
71
|
*/
|
|
82
72
|
export function derivedConstraintName(table, parts, kind) {
|
|
83
73
|
const body = parts.length ? `${table}${TABLE_SEPARATOR}${parts.join('_')}` : table;
|
|
84
74
|
return clampIdentifier(`${body}_${kind}`);
|
|
85
75
|
}
|
|
86
|
-
/**
|
|
87
|
-
* What separates the table from the columns, doubled where every other join is single.
|
|
88
|
-
*
|
|
89
|
-
* Postgres and SQLite keep index and constraint names in one flat namespace across the whole
|
|
90
|
-
* database rather than scoping them to a table, so a single underscore lets two tables collide:
|
|
91
|
-
* `user` + `profile_id` and `user_profile` + `id` both reduce to `user_profile_id_idx`. Doubling the
|
|
92
|
-
* one ambiguous boundary settles it, on the same assumption Drupal made for the same engines - that
|
|
93
|
-
* nothing sane carries `__` in a table or column name.
|
|
94
|
-
*/
|
|
76
|
+
/** Between table and columns, doubled: index names share one namespace per database, where `a` + `b_c` and `a_b` + `c` would collide. */
|
|
95
77
|
const TABLE_SEPARATOR = '__';
|
|
96
|
-
/**
|
|
97
|
-
* A name the engine will store whole, shortened around a hash of the full one when it is too long.
|
|
98
|
-
*
|
|
99
|
-
* Truncating alone collides - two long names over the same table differ only in their tail - and a
|
|
100
|
-
* collision means one constraint silently replacing another. The hash is of the *whole* name, so it
|
|
101
|
-
* stays the same on every run, which is what lets a later migration still recognise what it made.
|
|
102
|
-
*/
|
|
78
|
+
/** A name the engine stores whole, shortened around a hash of the full one, which stays stable across runs. */
|
|
103
79
|
function clampIdentifier(name) {
|
|
104
80
|
if (name.length <= MAX_IDENTIFIER_LENGTH) {
|
|
105
81
|
return name;
|
|
@@ -144,13 +120,7 @@ export function derivedCheckName(table, position) {
|
|
|
144
120
|
export function derivedForeignKeyName(table, columns) {
|
|
145
121
|
return derivedConstraintName(table, columns, 'fk');
|
|
146
122
|
}
|
|
147
|
-
/**
|
|
148
|
-
* Escape a SQL identifier (table name, column name, etc.)
|
|
149
|
-
* @param val the identifier to escape
|
|
150
|
-
* @param escapeIdChar the escape character to use (e.g. ` or ")
|
|
151
|
-
* @param forbidQualified whether to forbid qualified identifiers (containing dots)
|
|
152
|
-
* @param addDot whether to add a dot suffix
|
|
153
|
-
*/
|
|
123
|
+
/** Escapes an identifier with `escapeIdChar`, refusing a dotted one where `forbidQualified`, with a trailing dot where `addDot`. */
|
|
154
124
|
export function escapeSqlId(val, escapeIdChar = '`', forbidQualified, addDot) {
|
|
155
125
|
if (!val) {
|
|
156
126
|
return '';
|
|
@@ -167,41 +137,16 @@ export function escapeSqlId(val, escapeIdChar = '`', forbidQualified, addDot) {
|
|
|
167
137
|
return escaped + suffix;
|
|
168
138
|
}
|
|
169
139
|
/**
|
|
170
|
-
*
|
|
171
|
-
*
|
|
172
|
-
*
|
|
173
|
-
* so the result rows always contain an `id` property regardless of the entity's @Id() key name.
|
|
174
|
-
*
|
|
175
|
-
* The header-derived ID path assumes the database allocated consecutive values for the
|
|
176
|
-
* statement, which holds for a single multi-row `INSERT ... VALUES` on auto-increment keys
|
|
177
|
-
* (with the standard `auto_increment_increment = 1`); the querier only maps these IDs onto
|
|
178
|
-
* payloads when that assumption is safe.
|
|
179
|
-
*
|
|
180
|
-
* Caveat (MySQL/MariaDB-compatible engines with no `RETURNING`, i.e. `insertIdSource: 'firstId'`):
|
|
181
|
-
* contiguous allocation across a statement's rows is only guaranteed under
|
|
182
|
-
* `innodb_autoinc_lock_mode` 0 (`traditional`) or 1 (`consecutive`). Under mode 2 (`interleaved`,
|
|
183
|
-
* MySQL 8.0's default), other connections inserting into the same table concurrently with this
|
|
184
|
-
* statement can interleave with its auto-increment allocation, so the inferred IDs may not be
|
|
185
|
-
* contiguous. There is no code-level fix for this (MySQL has no `RETURNING`); avoid relying on
|
|
186
|
-
* inferred multi-row IDs for a table under heavy concurrent insert load, or set
|
|
187
|
-
* `innodb_autoinc_lock_mode` to 0 or 1.
|
|
140
|
+
* A driver's result as a {@link QueryUpdateResult}: `RETURNING` rows name their id `id`; a MySQL header's
|
|
141
|
+
* first id is extended by the increment, which holds only where auto-increment allocation is contiguous
|
|
142
|
+
* (`innodb_autoinc_lock_mode` 0 or 1).
|
|
188
143
|
*/
|
|
189
144
|
export function buildUpdateResult(payload) {
|
|
190
145
|
const { rows, id, insertIdSource, upsertStatus } = payload;
|
|
191
146
|
const changes = payload.changes ?? rows?.length ?? 0;
|
|
192
147
|
const stride = payload.insertIdIncrement && payload.insertIdIncrement > 0 ? payload.insertIdIncrement : 1;
|
|
193
|
-
//
|
|
194
|
-
// the
|
|
195
|
-
// inferred by incrementing it. A header id of `0`/`0n` means no id was generated (e.g. a
|
|
196
|
-
// non-auto-increment key), so we infer none.
|
|
197
|
-
//
|
|
198
|
-
// This arithmetic assumes `changes` equals the batch's row count, which always holds for a plain
|
|
199
|
-
// `insertMany` - but not for `upsertMany` on a `firstId` dialect (MySQL): its `ON DUPLICATE KEY
|
|
200
|
-
// UPDATE` convention makes `changes` a per-row weighted sum (1=insert, 2=update, 0=no-op), so a
|
|
201
|
-
// batch mixing an insert and an update would fabricate ids for rows that were never touched. This
|
|
202
|
-
// function has no way to tell the two call sites apart (`internalRun` reports the same header
|
|
203
|
-
// shape either way), so `AbstractSqlQuerier`'s `runUpsert` discards them for a multi-row `firstId`
|
|
204
|
-
// upsert and reads the ids back by the conflict columns instead.
|
|
148
|
+
// Ids from `RETURNING` are exact; otherwise from the header's first id onward, which assumes `changes`
|
|
149
|
+
// counts the rows (false for a MySQL upsert batch, whose querier reads ids back instead). `0` means none.
|
|
205
150
|
let ids = [];
|
|
206
151
|
if (rows?.length) {
|
|
207
152
|
ids = rows.map((r) => r['id']);
|
|
@@ -215,13 +160,8 @@ export function buildUpdateResult(payload) {
|
|
|
215
160
|
ids = sequentialIds(id, changes, stride);
|
|
216
161
|
}
|
|
217
162
|
}
|
|
218
|
-
// 2
|
|
219
|
-
//
|
|
220
|
-
// MySQL: `affectedRows` convention - 1 = insert, 2 = update, 0 = no-op. Gated on `!== 'returning'`
|
|
221
|
-
// since that convention is unreliable once RETURNING is in play (verified: MariaDB's affectedRows
|
|
222
|
-
// for an `ON DUPLICATE KEY UPDATE ... RETURNING` statement differs by driver and doesn't follow
|
|
223
|
-
// the 1/2/0 convention at all) - `insertIdSource === 'returning'` dialects without a `_created`
|
|
224
|
-
// column (MariaDB, SQLite, CockroachDB) correctly get `undefined` instead of a misleading guess.
|
|
163
|
+
// Whether the row was created: Postgres's `_created` column, or MySQL's 1/2/0 `affectedRows`,
|
|
164
|
+
// which is unreliable under `RETURNING`, so those dialects report nothing.
|
|
225
165
|
const created = (rows?.length === 1 ? rows[0]?.['_created'] : undefined) ??
|
|
226
166
|
(insertIdSource !== 'returning' && typeof upsertStatus === 'number' && upsertStatus >= 0 && upsertStatus <= 2
|
|
227
167
|
? upsertStatus === 1
|