uql-orm 0.79.0 → 0.81.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/uql-browser.min.js.map +2 -2
- package/dist/cockroachdb/cockroachDialect.js +5 -1
- package/dist/dialect/abstractDialect.d.ts +1 -31
- package/dist/dialect/abstractDialect.js +3 -27
- package/dist/dialect/abstractSqlDialect.d.ts +25 -56
- package/dist/dialect/abstractSqlDialect.js +78 -145
- package/dist/dialect/aliases.d.ts +5 -0
- package/dist/dialect/aliases.js +5 -0
- package/dist/dialect/mysqlLikeSqlDialect.d.ts +4 -2
- package/dist/dialect/mysqlLikeSqlDialect.js +14 -1
- package/dist/dialect/operators.d.ts +66 -0
- package/dist/dialect/operators.js +129 -0
- package/dist/dialect/pgLikeSqlDialect.d.ts +4 -1
- package/dist/dialect/pgLikeSqlDialect.js +16 -3
- package/dist/dialect/vectorSqlDialect.d.ts +2 -0
- package/dist/dialect/vectorSqlDialect.js +4 -0
- package/dist/entity/decorator/entity.d.ts +6 -1
- package/dist/entity/decorator/entity.js +12 -1
- package/dist/entity/index.d.ts +1 -1
- package/dist/entity/index.js +1 -1
- package/dist/entity/metadata/definition.d.ts +6 -1
- package/dist/entity/metadata/definition.js +19 -0
- package/dist/migrate/builder/expressions.d.ts +2 -0
- package/dist/migrate/builder/expressions.js +24 -0
- package/dist/migrate/cli.js +1 -1
- package/dist/migrate/codegen/entityCodeGenerator.js +2 -2
- package/dist/migrate/codegen/entityTypes.js +1 -2
- package/dist/migrate/codegen/indexDecoratorSource.d.ts +3 -2
- package/dist/migrate/codegen/indexDecoratorSource.js +5 -23
- package/dist/migrate/ddl/mssqlIndexDdl.d.ts +5 -0
- package/dist/migrate/ddl/mssqlIndexDdl.js +10 -0
- package/dist/migrate/ddl/mssqlTableDdl.d.ts +6 -4
- package/dist/migrate/ddl/mssqlTableDdl.js +25 -14
- package/dist/migrate/ddl/mysqlIndexDdl.d.ts +2 -2
- package/dist/migrate/ddl/mysqlIndexDdl.js +7 -6
- package/dist/migrate/ddl/pgIndexDdl.d.ts +2 -1
- package/dist/migrate/ddl/pgIndexDdl.js +8 -6
- package/dist/migrate/ddl/tableDdl.d.ts +5 -2
- package/dist/migrate/ddl/tableDdl.js +13 -7
- package/dist/migrate/drift/driftDetector.d.ts +4 -5
- package/dist/migrate/drift/driftDetector.js +21 -21
- package/dist/migrate/generator/definitionToNode.d.ts +1 -1
- package/dist/migrate/generator/definitionToNode.js +9 -20
- package/dist/migrate/generator/mongoSchemaGenerator.d.ts +5 -1
- package/dist/migrate/generator/mongoSchemaGenerator.js +20 -18
- package/dist/migrate/index.d.ts +2 -1
- package/dist/migrate/index.js +1 -0
- package/dist/migrate/introspection/abstractSqlSchemaIntrospector.d.ts +16 -6
- package/dist/migrate/introspection/abstractSqlSchemaIntrospector.js +18 -4
- package/dist/migrate/introspection/baseSqlIntrospector.js +7 -18
- package/dist/migrate/introspection/mongoIntrospector.d.ts +3 -1
- package/dist/migrate/introspection/mongoIntrospector.js +7 -3
- package/dist/migrate/introspection/mssqlIntrospector.d.ts +1 -0
- package/dist/migrate/introspection/mssqlIntrospector.js +9 -0
- package/dist/migrate/introspection/mysqlIntrospector.d.ts +16 -5
- package/dist/migrate/introspection/mysqlIntrospector.js +39 -2
- package/dist/migrate/introspection/postgresIntrospector.d.ts +30 -21
- package/dist/migrate/introspection/postgresIntrospector.js +70 -43
- package/dist/migrate/introspection/sqliteIntrospector.d.ts +1 -0
- package/dist/migrate/introspection/sqliteIntrospector.js +13 -8
- package/dist/migrate/migrator.d.ts +33 -1
- package/dist/migrate/migrator.js +111 -43
- package/dist/migrate/schemaChange.d.ts +18 -0
- package/dist/migrate/schemaChange.js +37 -0
- package/dist/migrate/schemaGenerator.d.ts +25 -15
- package/dist/migrate/schemaGenerator.js +130 -182
- package/dist/migrate/storage/databaseStorage.d.ts +4 -0
- package/dist/migrate/storage/databaseStorage.js +14 -8
- package/dist/migrate/triggerSql.d.ts +24 -0
- package/dist/migrate/triggerSql.js +229 -0
- package/dist/mongo/mongoDialect.d.ts +0 -21
- package/dist/mongo/mongoDialect.js +105 -100
- package/dist/mongo/mongodbQuerier.js +17 -1
- package/dist/mssql/mssqlDialect.d.ts +18 -7
- package/dist/mssql/mssqlDialect.js +77 -33
- package/dist/mssql/mssqlQuerier.js +2 -2
- package/dist/schema/canonicalType.d.ts +6 -1
- package/dist/schema/canonicalType.js +14 -0
- package/dist/schema/indexDifferences.d.ts +22 -6
- package/dist/schema/indexDifferences.js +23 -8
- package/dist/schema/matchByKey.d.ts +10 -0
- package/dist/schema/matchByKey.js +18 -0
- package/dist/schema/schemaAST.d.ts +6 -2
- package/dist/schema/schemaAST.js +7 -3
- package/dist/schema/schemaASTBuilder.d.ts +4 -8
- package/dist/schema/schemaASTBuilder.js +20 -29
- package/dist/schema/schemaASTDiffer.d.ts +2 -3
- package/dist/schema/schemaASTDiffer.js +15 -36
- package/dist/schema/types.d.ts +14 -15
- package/dist/sqlite/sqliteDialect.d.ts +1 -1
- package/dist/sqlite/sqliteDialect.js +12 -3
- package/dist/type/dialect.d.ts +69 -9
- package/dist/type/entity.d.ts +96 -3
- package/dist/type/migration.d.ts +43 -44
- package/dist/type/query.d.ts +13 -4
- package/dist/type/queryWhere.d.ts +4 -2
- package/dist/util/ddlExpression.util.d.ts +5 -1
- package/dist/util/ddlExpression.util.js +6 -2
- package/dist/util/field.util.d.ts +9 -1
- package/dist/util/field.util.js +14 -2
- package/dist/util/fieldOption.util.d.ts +2 -2
- package/dist/util/fieldOption.util.js +2 -2
- package/dist/util/raw.d.ts +9 -1
- package/dist/util/raw.js +36 -11
- package/dist/util/sql.util.d.ts +12 -0
- package/dist/util/sql.util.js +24 -3
- package/dist/util/uqlError.d.ts +2 -0
- package/dist/util/uqlError.js +4 -0
- package/package.json +4 -4
- package/skills/uql-orm/SKILL.md +11 -6
|
@@ -10,7 +10,8 @@ export declare class PgIndexDdl extends IndexDdl {
|
|
|
10
10
|
protected indexAccessMethod(index: IndexSchema): string;
|
|
11
11
|
/**
|
|
12
12
|
* A vector index's operator class, `{type}_{metric}_ops` (`halfvec_cosine_ops`), refusing a metric it
|
|
13
|
-
* lacks rather than build with the default; any other entry takes the class it declares.
|
|
13
|
+
* lacks rather than build with the default; any other entry takes the class it declares. Stated even
|
|
14
|
+
* for the default distance: pgvector's own default class is L2, which a cosine search never uses.
|
|
14
15
|
*/
|
|
15
16
|
protected indexColumnOpsClass(entry: IndexColumnSchema, index: IndexSchema): string;
|
|
16
17
|
protected indexInclude(index: IndexSchema): string;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { unsupportedVectorMetric } from '../../type/vector.js';
|
|
1
|
+
import { indexDistance, unsupportedVectorMetric } from '../../type/vector.js';
|
|
2
2
|
import { IndexDdl } from './indexDdl.js';
|
|
3
3
|
/** `CREATE INDEX ... USING hnsw ("embedding" vector_cosine_ops) WITH (m = ...)`, pgvector's form. */
|
|
4
4
|
export class PgIndexDdl extends IndexDdl {
|
|
@@ -33,20 +33,22 @@ export class PgIndexDdl extends IndexDdl {
|
|
|
33
33
|
}
|
|
34
34
|
/**
|
|
35
35
|
* A vector index's operator class, `{type}_{metric}_ops` (`halfvec_cosine_ops`), refusing a metric it
|
|
36
|
-
* lacks rather than build with the default; any other entry takes the class it declares.
|
|
36
|
+
* lacks rather than build with the default; any other entry takes the class it declares. Stated even
|
|
37
|
+
* for the default distance: pgvector's own default class is L2, which a cosine search never uses.
|
|
37
38
|
*/
|
|
38
39
|
indexColumnOpsClass(entry, index) {
|
|
39
|
-
if (!this.isVectorIndex(index)
|
|
40
|
+
if (!this.isVectorIndex(index)) {
|
|
40
41
|
return entry.opsClass ? ` ${entry.opsClass}` : '';
|
|
41
42
|
}
|
|
42
|
-
const
|
|
43
|
+
const distance = indexDistance(index);
|
|
44
|
+
const metric = this.dialect.vectorMetrics.get(distance)?.index;
|
|
43
45
|
if (!metric) {
|
|
44
|
-
throw unsupportedVectorMetric(this.dialect.dialectName,
|
|
46
|
+
throw unsupportedVectorMetric(this.dialect.dialectName, distance, index.name);
|
|
45
47
|
}
|
|
46
48
|
const vectorType = this.dialect.supportedVectorType(index.vectorType ?? 'vector');
|
|
47
49
|
const opsClass = `${vectorType}_${metric}_ops`;
|
|
48
50
|
// IVFFlat has neither a sparsevec nor an L1 operator class; HNSW has all of them (pgvector 0.8.2).
|
|
49
|
-
if (index.type === 'ivfflat' && (vectorType === 'sparsevec' ||
|
|
51
|
+
if (index.type === 'ivfflat' && (vectorType === 'sparsevec' || distance === 'l1')) {
|
|
50
52
|
throw new TypeError(`ivfflat has no ${opsClass} operator class (index "${index.name}"); use hnsw`);
|
|
51
53
|
}
|
|
52
54
|
return ` ${opsClass}`;
|
|
@@ -12,13 +12,16 @@ export declare function sizedType(column: Pick<ColumnSchema, 'type' | 'length' |
|
|
|
12
12
|
export declare class TableDdl {
|
|
13
13
|
protected readonly dialect: AbstractSqlDialect;
|
|
14
14
|
constructor(dialect: AbstractSqlDialect);
|
|
15
|
+
/** A `CREATE TABLE` up to its column list, a no-op where `ifNotExists` and the table is already there. */
|
|
16
|
+
createTable(target: string, ifNotExists: boolean): string;
|
|
15
17
|
addColumn(table: string, definition: string): string;
|
|
16
18
|
dropColumn(table: string, column: string): string[];
|
|
17
19
|
/**
|
|
18
20
|
* What changes `column` to what it now declares. `definition` is the whole column, which MySQL's
|
|
19
|
-
* `MODIFY COLUMN` restates; Postgres takes each change as a clause of its own
|
|
21
|
+
* `MODIFY COLUMN` restates; Postgres takes each change as a clause of its own, so given what the
|
|
22
|
+
* column was (`from`), only the clauses that changed.
|
|
20
23
|
*/
|
|
21
|
-
alterColumn(table: string, column: ColumnSchema, definition: string): string[];
|
|
24
|
+
alterColumn(table: string, column: ColumnSchema, definition: string, from?: ColumnSchema): string[];
|
|
22
25
|
renameColumn(table: string, oldName: string, newName: string): string;
|
|
23
26
|
renameTable(oldName: string, newName: string): string;
|
|
24
27
|
/** A stored generated column's type, with the clause computing it. */
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { formatDefaultValue } from '../builder/expressions.js';
|
|
1
|
+
import { formatDefaultValue, sameDefault } from '../builder/expressions.js';
|
|
2
2
|
/**
|
|
3
3
|
* A column's type with the size it was read back with, unless its spelling already carries one:
|
|
4
4
|
* introspection reports `VARCHAR` and `255` apart, where a type from an entity is already whole.
|
|
@@ -22,6 +22,10 @@ export class TableDdl {
|
|
|
22
22
|
constructor(dialect) {
|
|
23
23
|
this.dialect = dialect;
|
|
24
24
|
}
|
|
25
|
+
/** A `CREATE TABLE` up to its column list, a no-op where `ifNotExists` and the table is already there. */
|
|
26
|
+
createTable(target, ifNotExists) {
|
|
27
|
+
return `CREATE TABLE ${ifNotExists ? 'IF NOT EXISTS ' : ''}${target}`;
|
|
28
|
+
}
|
|
25
29
|
addColumn(table, definition) {
|
|
26
30
|
return `ALTER TABLE ${this.dialect.escapeId(table)} ADD COLUMN ${definition};`;
|
|
27
31
|
}
|
|
@@ -30,9 +34,10 @@ export class TableDdl {
|
|
|
30
34
|
}
|
|
31
35
|
/**
|
|
32
36
|
* What changes `column` to what it now declares. `definition` is the whole column, which MySQL's
|
|
33
|
-
* `MODIFY COLUMN` restates; Postgres takes each change as a clause of its own
|
|
37
|
+
* `MODIFY COLUMN` restates; Postgres takes each change as a clause of its own, so given what the
|
|
38
|
+
* column was (`from`), only the clauses that changed.
|
|
34
39
|
*/
|
|
35
|
-
alterColumn(table, column, definition) {
|
|
40
|
+
alterColumn(table, column, definition, from) {
|
|
36
41
|
if (this.dialect.alterColumnSyntax === 'none') {
|
|
37
42
|
throw new TypeError(`${this.dialect}: Cannot alter column "${column.name}" - you must recreate the table. ` +
|
|
38
43
|
`This database does not support ALTER COLUMN.`);
|
|
@@ -43,10 +48,11 @@ export class TableDdl {
|
|
|
43
48
|
}
|
|
44
49
|
const alter = `ALTER TABLE ${target} ALTER COLUMN ${this.dialect.escapeId(column.name)}`;
|
|
45
50
|
return [
|
|
46
|
-
`${alter} TYPE ${column.type};`,
|
|
47
|
-
`${alter} ${column.nullable ? 'DROP NOT NULL' : 'SET NOT NULL'};`,
|
|
48
|
-
column.defaultValue
|
|
49
|
-
|
|
51
|
+
(!from || from.type !== column.type) && `${alter} TYPE ${column.type};`,
|
|
52
|
+
(!from || from.nullable !== column.nullable) && `${alter} ${column.nullable ? 'DROP NOT NULL' : 'SET NOT NULL'};`,
|
|
53
|
+
(!from || !sameDefault(column.defaultValue, from.defaultValue, this.dialect)) &&
|
|
54
|
+
(column.defaultValue === undefined ? `${alter} DROP DEFAULT;` : `${alter} SET${this.defaultClause(column)};`),
|
|
55
|
+
].filter((statement) => statement !== false);
|
|
50
56
|
}
|
|
51
57
|
renameColumn(table, oldName, newName) {
|
|
52
58
|
const [target, from, to] = [table, oldName, newName].map((name) => this.dialect.escapeId(name));
|
|
@@ -5,7 +5,6 @@
|
|
|
5
5
|
* actual database schema.
|
|
6
6
|
*/
|
|
7
7
|
import type { AbstractDialect } from '../../dialect/abstractDialect.js';
|
|
8
|
-
import type { IndexFacet } from '../../schema/indexDifferences.js';
|
|
9
8
|
import type { SchemaAST } from '../../schema/schemaAST.js';
|
|
10
9
|
import type { DriftReport } from '../../schema/types.js';
|
|
11
10
|
/**
|
|
@@ -18,15 +17,15 @@ export interface DriftDetectorOptions {
|
|
|
18
17
|
checkNullable?: boolean;
|
|
19
18
|
/** Include index differences */
|
|
20
19
|
checkIndexes?: boolean;
|
|
21
|
-
/** `indexFacets` of the introspector that produced the actual schema; anything else goes uncompared. */
|
|
22
|
-
indexFacets?: ReadonlySet<IndexFacet>;
|
|
23
20
|
/** Include foreign key differences */
|
|
24
21
|
checkForeignKeys?: boolean;
|
|
25
22
|
/**
|
|
26
|
-
* Include default value differences. Off
|
|
27
|
-
* (`now()`, `
|
|
23
|
+
* Include default value differences. Off unless {@link defaultsEqual} is given: without it defaults
|
|
24
|
+
* compare as written, and an engine reports one as it stored it (`now()`, `'active'::text`).
|
|
28
25
|
*/
|
|
29
26
|
checkDefaults?: boolean;
|
|
27
|
+
/** How the engine's generator compares a default, so drift reports the ones a migration would change. */
|
|
28
|
+
defaultsEqual?: (expected: unknown, actual: unknown) => boolean;
|
|
30
29
|
/**
|
|
31
30
|
* Tables to leave out of the comparison. The migrations bookkeeping table belongs here - it exists in
|
|
32
31
|
* the database by design and has no entity, so reporting it as unexpected told every project to
|
|
@@ -5,15 +5,15 @@
|
|
|
5
5
|
* actual database schema.
|
|
6
6
|
*/
|
|
7
7
|
import { canonicalToSql, engineType } from '../../schema/canonicalType.js';
|
|
8
|
-
import { diffSchemas, referentialActions } from '../../schema/schemaASTDiffer.js';
|
|
8
|
+
import { defaultsEqualAsWritten, diffSchemas, referentialActions } from '../../schema/schemaASTDiffer.js';
|
|
9
9
|
function resolveOptions(options) {
|
|
10
10
|
return {
|
|
11
11
|
checkTypes: options.checkTypes ?? true,
|
|
12
12
|
checkNullable: options.checkNullable ?? true,
|
|
13
13
|
checkIndexes: options.checkIndexes ?? true,
|
|
14
|
-
indexFacets: options.indexFacets ?? new Set(),
|
|
15
14
|
checkForeignKeys: options.checkForeignKeys ?? true,
|
|
16
|
-
checkDefaults: options.checkDefaults ??
|
|
15
|
+
checkDefaults: options.checkDefaults ?? options.defaultsEqual !== undefined,
|
|
16
|
+
defaultsEqual: options.defaultsEqual ?? defaultsEqualAsWritten,
|
|
17
17
|
excludeTables: options.excludeTables ?? [],
|
|
18
18
|
dialect: options.dialect,
|
|
19
19
|
};
|
|
@@ -27,9 +27,9 @@ export function detectDrift(expectedAST, actualAST, options = {}) {
|
|
|
27
27
|
const { dialect } = opts;
|
|
28
28
|
const diff = diffSchemas(expectedAST, actualAST, {
|
|
29
29
|
compareIndexes: opts.checkIndexes,
|
|
30
|
-
indexFacets: opts.indexFacets,
|
|
31
30
|
compareRelationships: opts.checkForeignKeys,
|
|
32
31
|
excludeTables: opts.excludeTables,
|
|
32
|
+
defaultsEqual: opts.defaultsEqual,
|
|
33
33
|
// Without a dialect there is no engine to compare through, and `formatType` below then reports no
|
|
34
34
|
// type drift at all.
|
|
35
35
|
...(dialect && { normalizeType: engineType(dialect) }),
|
|
@@ -59,10 +59,14 @@ function detectPrimaryKeyDrifts(diff) {
|
|
|
59
59
|
type: 'constraint_mismatch',
|
|
60
60
|
severity: 'critical',
|
|
61
61
|
table: pkDiff.table,
|
|
62
|
-
details: `Primary key of "${pkDiff.table}" is (${pkDiff.actual
|
|
62
|
+
details: `Primary key of "${pkDiff.table}" is (${keyColumns(pkDiff.actual)}) in the database but (${keyColumns(pkDiff.expected)}) in the entity`,
|
|
63
63
|
suggestion: 'Generate a migration to change the primary key',
|
|
64
64
|
}));
|
|
65
65
|
}
|
|
66
|
+
/** A key's columns as a drift names them, `none` where there is no key. */
|
|
67
|
+
function keyColumns(key) {
|
|
68
|
+
return key?.columns.join(', ') || 'none';
|
|
69
|
+
}
|
|
66
70
|
/**
|
|
67
71
|
* Detect table-level drifts (missing/unexpected tables).
|
|
68
72
|
*/
|
|
@@ -121,7 +125,7 @@ function detectColumnDrifts(diff, opts) {
|
|
|
121
125
|
return drifts;
|
|
122
126
|
}
|
|
123
127
|
/**
|
|
124
|
-
* Add drifts for column alterations
|
|
128
|
+
* Add drifts for column alterations: type, nullability and default.
|
|
125
129
|
*/
|
|
126
130
|
function addAlterColumnDrifts(colDiff, drifts, opts) {
|
|
127
131
|
// An auto-increment key is created through the dialect's `serialPrimaryKey`, whose spelling the
|
|
@@ -159,21 +163,17 @@ function addAlterColumnDrifts(colDiff, drifts, opts) {
|
|
|
159
163
|
suggestion: 'Align nullable setting in entity or database',
|
|
160
164
|
});
|
|
161
165
|
}
|
|
162
|
-
if (opts.checkDefaults) {
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
details: `Default mismatch for "${colDiff.column}"`,
|
|
174
|
-
suggestion: 'Align the default in the entity or the database',
|
|
175
|
-
});
|
|
176
|
-
}
|
|
166
|
+
if (opts.checkDefaults && !opts.defaultsEqual(colDiff.expected.defaultValue, colDiff.actual.defaultValue)) {
|
|
167
|
+
drifts.push({
|
|
168
|
+
type: 'constraint_mismatch',
|
|
169
|
+
severity: 'info',
|
|
170
|
+
table: colDiff.table,
|
|
171
|
+
column: colDiff.column,
|
|
172
|
+
expected: String(colDiff.expected.defaultValue ?? 'NULL'),
|
|
173
|
+
actual: String(colDiff.actual.defaultValue ?? 'NULL'),
|
|
174
|
+
details: `Default mismatch for "${colDiff.column}"`,
|
|
175
|
+
suggestion: 'Align the default in the entity or the database',
|
|
176
|
+
});
|
|
177
177
|
}
|
|
178
178
|
}
|
|
179
179
|
/**
|
|
@@ -14,7 +14,7 @@ export declare function tableDefinitionToNode(def: TableDefinition, render: (sql
|
|
|
14
14
|
*/
|
|
15
15
|
export declare function fullColumnDefinitionToNode(col: FullColumnDefinition, tableName: string): ColumnNode;
|
|
16
16
|
/**
|
|
17
|
-
* The index a column-level `index` declares, or nothing.
|
|
17
|
+
* The index a column-level `index` or `unique` declares, or nothing: a unique column is a unique index.
|
|
18
18
|
*
|
|
19
19
|
* Shared with `TableBuilder.build`, which lifts these into the table it is creating: written twice,
|
|
20
20
|
* `addColumn` had no lift at all and silently emitted a column with no index.
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { createTableNode, keyOfColumns } from '../../schema/schemaAST.js';
|
|
1
2
|
import { renderIndexColumn } from '../../util/ddlExpression.util.js';
|
|
2
3
|
import { derivedForeignKeyName, derivedIndexName } from '../../util/sql.util.js';
|
|
3
4
|
/** A table the builder names but has not seen, which the generator reads only the name of. */
|
|
@@ -10,29 +11,17 @@ function unresolvedTable(name) {
|
|
|
10
11
|
* `render`. Free functions and not generator methods: the dialect reaches them only through `render`.
|
|
11
12
|
*/
|
|
12
13
|
export function tableDefinitionToNode(def, render) {
|
|
13
|
-
const
|
|
14
|
-
const
|
|
15
|
-
const table = {
|
|
16
|
-
name: def.name,
|
|
17
|
-
columns,
|
|
18
|
-
primaryKey: [], // placeholder
|
|
19
|
-
indexes: [],
|
|
20
|
-
incomingRelations: [],
|
|
21
|
-
outgoingRelations: [],
|
|
22
|
-
comment: def.comment,
|
|
23
|
-
};
|
|
14
|
+
const table = { ...createTableNode(def.name), comment: def.comment };
|
|
15
|
+
const { columns } = table;
|
|
24
16
|
for (const colDef of def.columns) {
|
|
25
17
|
const node = fullColumnDefinitionToNode(colDef, def.name);
|
|
26
18
|
node.table = table;
|
|
27
19
|
columns.set(node.name, node);
|
|
28
|
-
if (node.isPrimaryKey) {
|
|
29
|
-
pkNodes.push(node);
|
|
30
|
-
}
|
|
31
20
|
}
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
:
|
|
35
|
-
|
|
21
|
+
// A declared key keeps only the columns the table has, in its own order.
|
|
22
|
+
table.primaryKey = def.primaryKey
|
|
23
|
+
? { columns: def.primaryKey.filter((name) => columns.has(name)) }
|
|
24
|
+
: keyOfColumns(columns.values());
|
|
36
25
|
for (const idxDef of def.indexes) {
|
|
37
26
|
table.indexes.push({ ...renderIndexDefinition(idxDef, render), table });
|
|
38
27
|
}
|
|
@@ -64,13 +53,13 @@ export function fullColumnDefinitionToNode(col, tableName) {
|
|
|
64
53
|
return { ...column, table: unresolvedTable(tableName), referencedBy: [] };
|
|
65
54
|
}
|
|
66
55
|
/**
|
|
67
|
-
* The index a column-level `index` declares, or nothing.
|
|
56
|
+
* The index a column-level `index` or `unique` declares, or nothing: a unique column is a unique index.
|
|
68
57
|
*
|
|
69
58
|
* Shared with `TableBuilder.build`, which lifts these into the table it is creating: written twice,
|
|
70
59
|
* `addColumn` had no lift at all and silently emitted a column with no index.
|
|
71
60
|
*/
|
|
72
61
|
export function columnIndex(tableName, col) {
|
|
73
|
-
if (!col.index) {
|
|
62
|
+
if (!col.index && !col.isUnique) {
|
|
74
63
|
return undefined;
|
|
75
64
|
}
|
|
76
65
|
return {
|
|
@@ -31,8 +31,12 @@ export declare class MongoSchemaGenerator extends MongoDialect implements Schema
|
|
|
31
31
|
ifNotExists?: boolean;
|
|
32
32
|
}): string[];
|
|
33
33
|
generateDropTable(tableName: string): string;
|
|
34
|
+
/** A collection's indexes: each dropped, then each created, an alter as both. */
|
|
34
35
|
generateAlterTable(diff: SchemaDiff): string[];
|
|
35
|
-
|
|
36
|
+
/** MongoDB has no triggers, and a write to an entity declaring one is refused, so there is none to reconcile. */
|
|
37
|
+
generateTriggers(): string[];
|
|
38
|
+
generateTriggersDown(): string[];
|
|
39
|
+
generateTriggerDrops(): string[];
|
|
36
40
|
private dropIndexCommand;
|
|
37
41
|
/** An index as MongoDB's key spec (`-1` descending, `'text'` full-text), refusing the SQL-only options. */
|
|
38
42
|
generateCreateIndex(tableName: string, index: IndexSchema): string;
|
|
@@ -8,6 +8,7 @@ import { declaredIndexes, declaredIndexName, renderIndexColumn } from '../../uti
|
|
|
8
8
|
import { fulltextConfig, fulltextWeights } from '../../util/dialect.util.js';
|
|
9
9
|
import { assertIndexFeatures, assertIndexType } from '../ddl/indexDdl.js';
|
|
10
10
|
import { assertIndexPredicate, refusedIndexPredicate } from '../indexPredicate.js';
|
|
11
|
+
import { sides } from '../schemaChange.js';
|
|
11
12
|
import { renderIndexDefinition } from './definitionToNode.js';
|
|
12
13
|
import { indexNodeToSchema } from './indexNodeToSchema.js';
|
|
13
14
|
import { serializeMongoCommand } from './mongoCommand.js';
|
|
@@ -106,17 +107,22 @@ export class MongoSchemaGenerator extends MongoDialect {
|
|
|
106
107
|
generateDropTable(tableName) {
|
|
107
108
|
return serializeMongoCommand({ action: 'dropCollection', name: tableName });
|
|
108
109
|
}
|
|
110
|
+
/** A collection's indexes: each dropped, then each created, an alter as both. */
|
|
109
111
|
generateAlterTable(diff) {
|
|
110
112
|
return [
|
|
111
|
-
...(diff.
|
|
112
|
-
...(diff.
|
|
113
|
+
...sides(diff.indexes, 'from').map((index) => this.dropIndexCommand(diff.tableName, index)),
|
|
114
|
+
...sides(diff.indexes, 'to').map((index) => this.generateCreateIndex(diff.tableName, index)),
|
|
113
115
|
];
|
|
114
116
|
}
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
117
|
+
/** MongoDB has no triggers, and a write to an entity declaring one is refused, so there is none to reconcile. */
|
|
118
|
+
generateTriggers() {
|
|
119
|
+
return [];
|
|
120
|
+
}
|
|
121
|
+
generateTriggersDown() {
|
|
122
|
+
return [];
|
|
123
|
+
}
|
|
124
|
+
generateTriggerDrops() {
|
|
125
|
+
return [];
|
|
120
126
|
}
|
|
121
127
|
dropIndexCommand(tableName, index) {
|
|
122
128
|
return index.type === 'vectorSearch'
|
|
@@ -211,17 +217,13 @@ export class MongoSchemaGenerator extends MongoDialect {
|
|
|
211
217
|
if (!currentTable) {
|
|
212
218
|
return { tableName: collectionName, type: 'create' };
|
|
213
219
|
}
|
|
214
|
-
|
|
215
|
-
const
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
type: 'alter',
|
|
222
|
-
indexesToAdd: toAdd.length ? toAdd : undefined,
|
|
223
|
-
indexesToDrop: toDrop.length ? toDrop.map(indexNodeToSchema) : undefined,
|
|
224
|
-
};
|
|
220
|
+
const { toAdd, toDrop, toAlter } = indexChanges(collectionName, this.indexesOf(meta, collectionName), currentTable.indexes, currentTable.indexFacets);
|
|
221
|
+
const indexes = [
|
|
222
|
+
...toAdd.map((to) => ({ to })),
|
|
223
|
+
...toDrop.map((from) => ({ from: indexNodeToSchema(from) })),
|
|
224
|
+
...toAlter.map(({ from, to }) => ({ from: indexNodeToSchema(from), to })),
|
|
225
|
+
];
|
|
226
|
+
return indexes.length ? { tableName: collectionName, type: 'alter', indexes } : undefined;
|
|
225
227
|
}
|
|
226
228
|
}
|
|
227
229
|
/** The first value `partialFilterExpression` refuses, `null`, or a migration cannot carry as JSON, such as a `Date`. */
|
package/dist/migrate/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export type { ColumnSchema, DialectName, ForeignKeySchema, IndexSchema, Migration, MigrationDefinition, MigrationResult, MigrationStorage, MigratorOptions, MongoQuerier, SchemaDiff, SchemaGenerator, SchemaIntrospector, SqlDialectName, SqlQuerier, SqlQueryDialect, SyncOptions, TableSchema, } from '../type/index.js';
|
|
1
|
+
export type { Change, ColumnSchema, DialectName, ForeignKeySchema, IndexSchema, Migration, MigrationDefinition, MigrationResult, MigrationStorage, MigratorOptions, MongoQuerier, PrimaryKeySchema, SchemaDiff, SchemaGenerator, SchemaIntrospector, SqlDialectName, SqlQuerier, SqlQueryDialect, SyncOptions, TableSchema, } from '../type/index.js';
|
|
2
2
|
export { type Config, isSqlQuerier } from '../type/index.js';
|
|
3
3
|
export { acquireQuerierForMigrations } from './acquireQuerierForMigrations.js';
|
|
4
4
|
export { assertCliConfig } from './assertCliConfig.js';
|
|
@@ -10,6 +10,7 @@ export * from './drift/index.js';
|
|
|
10
10
|
export * from './introspection/index.js';
|
|
11
11
|
export { migrationBuilderFor } from './migrationTarget.js';
|
|
12
12
|
export { type BuilderMigrationDefinition, defineBuilderMigration, defineMigration, Migrator } from './migrator.js';
|
|
13
|
+
export { reverseDiff } from './schemaChange.js';
|
|
13
14
|
export { SqlSchemaGenerator } from './schemaGenerator.js';
|
|
14
15
|
export { DatabaseMigrationStorage } from './storage/databaseStorage.js';
|
|
15
16
|
export { JsonMigrationStorage } from './storage/jsonStorage.js';
|
package/dist/migrate/index.js
CHANGED
|
@@ -16,6 +16,7 @@ export * from './introspection/index.js';
|
|
|
16
16
|
export { migrationBuilderFor } from './migrationTarget.js';
|
|
17
17
|
export { defineBuilderMigration, defineMigration, Migrator } from './migrator.js';
|
|
18
18
|
// Schema generators
|
|
19
|
+
export { reverseDiff } from './schemaChange.js';
|
|
19
20
|
export { SqlSchemaGenerator } from './schemaGenerator.js';
|
|
20
21
|
// Storage implementations
|
|
21
22
|
export { DatabaseMigrationStorage } from './storage/databaseStorage.js';
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { type ForeignKeyAction } from '../../schema/types.js';
|
|
2
|
-
import type { ColumnSchema, ForeignKeySchema, IndexSchema, QuerierPool, RawRow, SchemaIntrospector, SqlQuerier, TableSchema } from '../../type/index.js';
|
|
2
|
+
import type { ColumnSchema, InstalledTriggers, ForeignKeySchema, IndexSchema, PrimaryKeySchema, QuerierPool, RawRow, SchemaIntrospector, SqlQuerier, TableSchema } from '../../type/index.js';
|
|
3
3
|
import { BaseSqlIntrospector } from './baseSqlIntrospector.js';
|
|
4
4
|
/**
|
|
5
5
|
* Reads the rows of one statement while introspecting a table.
|
|
@@ -38,6 +38,12 @@ export declare abstract class AbstractSqlSchemaIntrospector extends BaseSqlIntro
|
|
|
38
38
|
protected readonly defaultSchemaExpr: string;
|
|
39
39
|
getTableSchema(tableName: string): Promise<TableSchema | undefined>;
|
|
40
40
|
getTableNames(): Promise<string[]>;
|
|
41
|
+
/**
|
|
42
|
+
* Every trigger uql installed in this schema, by table and then by name, with the statements recreating
|
|
43
|
+
* it: the whole schema in one read, since a table whose entity stopped declaring one still has one to
|
|
44
|
+
* drop. Ownership is matched here rather than with `LIKE`, whose `_` wildcard would take in a hand-written one.
|
|
45
|
+
*/
|
|
46
|
+
ownedTriggers(table: string): Promise<InstalledTriggers>;
|
|
41
47
|
tableExists(tableName: string): Promise<boolean>;
|
|
42
48
|
/**
|
|
43
49
|
* Introspection reads, so `withQuerier` rather than `transaction`: the pool owns the release either
|
|
@@ -48,10 +54,7 @@ export declare abstract class AbstractSqlSchemaIntrospector extends BaseSqlIntro
|
|
|
48
54
|
protected getColumns(read: TableRowReader, tableName: string): Promise<ColumnSchema[]>;
|
|
49
55
|
protected getIndexes(read: TableRowReader, tableName: string): Promise<IndexSchema[]>;
|
|
50
56
|
protected getForeignKeys(read: TableRowReader, tableName: string): Promise<ForeignKeySchema[]>;
|
|
51
|
-
protected getPrimaryKey(read: TableRowReader, tableName: string): Promise<
|
|
52
|
-
columns?: string[];
|
|
53
|
-
name?: string;
|
|
54
|
-
}>;
|
|
57
|
+
protected getPrimaryKey(read: TableRowReader, tableName: string): Promise<PrimaryKeySchema | undefined>;
|
|
55
58
|
protected tableExistsParams(tableName: string): unknown[];
|
|
56
59
|
protected getColumnsParams(tableName: string): unknown[];
|
|
57
60
|
protected getIndexesParams(tableName: string): unknown[];
|
|
@@ -79,6 +82,13 @@ export declare abstract class AbstractSqlSchemaIntrospector extends BaseSqlIntro
|
|
|
79
82
|
protected abstract getForeignKeysQuery(tableName: string): string;
|
|
80
83
|
/** SQL query to get primary key columns. Parameter: tableName (for PRAGMA-style). */
|
|
81
84
|
protected abstract getPrimaryKeyQuery(tableName: string): string;
|
|
85
|
+
/**
|
|
86
|
+
* SQL listing every trigger in the schema as a `table`, a `name`, the engine's reprint of it as a
|
|
87
|
+
* `definition`, and where the body lives apart, the `requires` recreated first: what is installed, not
|
|
88
|
+
* what uql wrote, which is exactly what a rollback puts back.
|
|
89
|
+
*/
|
|
90
|
+
/** The triggers on the table its one parameter names: each one's `name`, `definition`, and what it `requires`. */
|
|
91
|
+
protected abstract triggersQuery(): string;
|
|
82
92
|
/**
|
|
83
93
|
* Extract table name from a row returned by getTableNamesQuery.
|
|
84
94
|
*
|
|
@@ -101,7 +111,7 @@ export declare abstract class AbstractSqlSchemaIntrospector extends BaseSqlIntro
|
|
|
101
111
|
protected mapPrimaryKeyResult(results: RawRow[]): string[] | undefined;
|
|
102
112
|
/**
|
|
103
113
|
* What the engine calls the key's constraint, where the query reported one. Only a `DROP` needs it,
|
|
104
|
-
* and only the reported name will do - see {@link
|
|
114
|
+
* and only the reported name will do - see {@link PrimaryKeySchema.name}.
|
|
105
115
|
*/
|
|
106
116
|
protected mapPrimaryKeyName(results: RawRow[]): string | undefined;
|
|
107
117
|
/** Parse default value string to appropriate type. */
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { FOREIGN_KEY_ACTIONS } from '../../schema/types.js';
|
|
2
2
|
import { isSqlQuerier } from '../../type/index.js';
|
|
3
|
+
import { isOwnedName } from '../../util/sql.util.js';
|
|
3
4
|
import { BaseSqlIntrospector } from './baseSqlIntrospector.js';
|
|
4
5
|
/** A SQL introspector: an engine states its catalogue queries (`get*Query`) and how their rows map (`map*Result`). */
|
|
5
6
|
export class AbstractSqlSchemaIntrospector extends BaseSqlIntrospector {
|
|
@@ -37,8 +38,7 @@ export class AbstractSqlSchemaIntrospector extends BaseSqlIntrospector {
|
|
|
37
38
|
return {
|
|
38
39
|
name: tableName,
|
|
39
40
|
columns,
|
|
40
|
-
primaryKey
|
|
41
|
-
primaryKeyName: primaryKey.name,
|
|
41
|
+
primaryKey,
|
|
42
42
|
indexes,
|
|
43
43
|
foreignKeys,
|
|
44
44
|
};
|
|
@@ -50,6 +50,19 @@ export class AbstractSqlSchemaIntrospector extends BaseSqlIntrospector {
|
|
|
50
50
|
return results.map((row) => this.mapTableNameRow(row));
|
|
51
51
|
});
|
|
52
52
|
}
|
|
53
|
+
/**
|
|
54
|
+
* Every trigger uql installed in this schema, by table and then by name, with the statements recreating
|
|
55
|
+
* it: the whole schema in one read, since a table whose entity stopped declaring one still has one to
|
|
56
|
+
* drop. Ownership is matched here rather than with `LIKE`, whose `_` wildcard would take in a hand-written one.
|
|
57
|
+
*/
|
|
58
|
+
async ownedTriggers(table) {
|
|
59
|
+
const rows = await this.withSqlQuerier((querier) => querier.all(this.triggersQuery(), [table]));
|
|
60
|
+
return new Map(rows.flatMap((row) => {
|
|
61
|
+
const name = String(row['name']);
|
|
62
|
+
const statements = [row['requires'], row['definition']].filter(Boolean).map((sql) => String(sql));
|
|
63
|
+
return isOwnedName(name) ? [[name, statements]] : [];
|
|
64
|
+
}));
|
|
65
|
+
}
|
|
53
66
|
async tableExists(tableName) {
|
|
54
67
|
return this.withSqlQuerier((querier) => this.tableExistsInternal(createTableRowReader(querier), tableName));
|
|
55
68
|
}
|
|
@@ -83,7 +96,8 @@ export class AbstractSqlSchemaIntrospector extends BaseSqlIntrospector {
|
|
|
83
96
|
}
|
|
84
97
|
async getPrimaryKey(read, tableName) {
|
|
85
98
|
const results = await read(this.getPrimaryKeyQuery(tableName), this.getPrimaryKeyParams(tableName));
|
|
86
|
-
|
|
99
|
+
const columns = this.mapPrimaryKeyResult(results);
|
|
100
|
+
return columns && { columns, name: this.mapPrimaryKeyName(results) };
|
|
87
101
|
}
|
|
88
102
|
tableExistsParams(tableName) {
|
|
89
103
|
return [tableName];
|
|
@@ -145,7 +159,7 @@ export class AbstractSqlSchemaIntrospector extends BaseSqlIntrospector {
|
|
|
145
159
|
}
|
|
146
160
|
/**
|
|
147
161
|
* What the engine calls the key's constraint, where the query reported one. Only a `DROP` needs it,
|
|
148
|
-
* and only the reported name will do - see {@link
|
|
162
|
+
* and only the reported name will do - see {@link PrimaryKeySchema.name}.
|
|
149
163
|
*/
|
|
150
164
|
mapPrimaryKeyName(results) {
|
|
151
165
|
const name = results[0]?.['constraint_name'];
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { canonicalColumnType } from '../../schema/canonicalType.js';
|
|
2
|
-
import { createTableNode, SchemaAST } from '../../schema/schemaAST.js';
|
|
2
|
+
import { createTableNode, keyOfColumns, SchemaAST } from '../../schema/schemaAST.js';
|
|
3
3
|
import { escapeSqlId } from '../../util/index.js';
|
|
4
4
|
import { derivedForeignKeyName } from '../../util/sql.util.js';
|
|
5
5
|
/**
|
|
@@ -56,7 +56,7 @@ export class BaseSqlIntrospector {
|
|
|
56
56
|
return ast;
|
|
57
57
|
}
|
|
58
58
|
buildTable(schema) {
|
|
59
|
-
const table = createTableNode(schema.name, this.schema);
|
|
59
|
+
const table = createTableNode(schema.name, this.schema, this.indexFacets);
|
|
60
60
|
const { columns } = table;
|
|
61
61
|
for (const col of schema.columns) {
|
|
62
62
|
// Spread, not field by field: a `ColumnSchema` is a `ColumnNode` minus the graph links, so
|
|
@@ -71,12 +71,10 @@ export class BaseSqlIntrospector {
|
|
|
71
71
|
};
|
|
72
72
|
columns.set(col.name, column);
|
|
73
73
|
}
|
|
74
|
-
// From the ordered
|
|
75
|
-
//
|
|
76
|
-
//
|
|
77
|
-
|
|
78
|
-
table.primaryKey.push(...keyColumns.flatMap((name) => columns.get(name) ?? []));
|
|
79
|
-
table.primaryKeyName = schema.primaryKeyName;
|
|
74
|
+
// From the ordered key the query returned, not from the per-column flags: `(a, b)` is a different
|
|
75
|
+
// key from `(b, a)`, and a flag says only that a column is *in* the key. Falls back to the flags
|
|
76
|
+
// for an introspector that reports no key of its own.
|
|
77
|
+
table.primaryKey = schema.primaryKey ?? keyOfColumns(schema.columns);
|
|
80
78
|
return table;
|
|
81
79
|
}
|
|
82
80
|
buildRelationships(ast, tableNodes, schema, fromTable) {
|
|
@@ -105,16 +103,7 @@ export class BaseSqlIntrospector {
|
|
|
105
103
|
// does not have, and the index if that leaves none, is what the entity side does too.
|
|
106
104
|
const entries = idx.entries.filter((entry) => entry.expression || table.columns.has(entry.column));
|
|
107
105
|
if (entries.length > 0) {
|
|
108
|
-
|
|
109
|
-
name: idx.name,
|
|
110
|
-
table,
|
|
111
|
-
entries,
|
|
112
|
-
unique: idx.unique,
|
|
113
|
-
type: idx.type,
|
|
114
|
-
where: idx.where,
|
|
115
|
-
include: idx.include,
|
|
116
|
-
};
|
|
117
|
-
ast.addIndex(index);
|
|
106
|
+
ast.addIndex({ ...idx, table, entries });
|
|
118
107
|
}
|
|
119
108
|
}
|
|
120
109
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { IndexFacet } from '../../schema/indexDifferences.js';
|
|
2
2
|
import { SchemaAST } from '../../schema/schemaAST.js';
|
|
3
|
-
import { type QuerierPool, type SchemaIntrospector, type TableSchema } from '../../type/index.js';
|
|
3
|
+
import { type InstalledTriggers, type QuerierPool, type SchemaIntrospector, type TableSchema } from '../../type/index.js';
|
|
4
4
|
/**
|
|
5
5
|
* MongoDB schema introspector.
|
|
6
6
|
* MongoDB doesn't have a fixed schema, so this primarily focuses on collections and indexes.
|
|
@@ -10,6 +10,8 @@ export declare class MongoSchemaIntrospector implements SchemaIntrospector {
|
|
|
10
10
|
/** `listIndexes` reports keys, uniqueness and text weights; a `partialFilterExpression` is no SQL predicate. */
|
|
11
11
|
readonly indexFacets: ReadonlySet<IndexFacet>;
|
|
12
12
|
constructor(pool: QuerierPool);
|
|
13
|
+
/** MongoDB has no triggers, so none is ever installed. */
|
|
14
|
+
ownedTriggers(): Promise<InstalledTriggers>;
|
|
13
15
|
introspect(tables?: readonly string[]): Promise<SchemaAST>;
|
|
14
16
|
getTableSchema(tableName: string): Promise<TableSchema | undefined>;
|
|
15
17
|
/** Collections only, the way a SQL engine lists its base tables: no view, nor the `system.views` behind one. */
|
|
@@ -14,13 +14,17 @@ export class MongoSchemaIntrospector {
|
|
|
14
14
|
constructor(pool) {
|
|
15
15
|
this.pool = pool;
|
|
16
16
|
}
|
|
17
|
+
/** MongoDB has no triggers, so none is ever installed. */
|
|
18
|
+
async ownedTriggers() {
|
|
19
|
+
return new Map();
|
|
20
|
+
}
|
|
17
21
|
async introspect(tables) {
|
|
18
22
|
const tableNames = tables ?? (await this.getTableNames());
|
|
19
23
|
const ast = new SchemaAST();
|
|
20
24
|
for (const name of tableNames) {
|
|
21
25
|
const schema = await this.getTableSchema(name);
|
|
22
26
|
if (schema) {
|
|
23
|
-
ast.addTable(buildTable(schema));
|
|
27
|
+
ast.addTable(buildTable(schema, this.indexFacets));
|
|
24
28
|
}
|
|
25
29
|
}
|
|
26
30
|
return ast;
|
|
@@ -103,8 +107,8 @@ async function hasCollection(db, name) {
|
|
|
103
107
|
return collections.length > 0;
|
|
104
108
|
}
|
|
105
109
|
/** Mongo has no columns to read, so a table's are the fields its indexes name, one node per field. */
|
|
106
|
-
function buildTable({ name, indexes = [] }) {
|
|
107
|
-
const table = createTableNode(name);
|
|
110
|
+
function buildTable({ name, indexes = [] }, indexFacets) {
|
|
111
|
+
const table = createTableNode(name, undefined, indexFacets);
|
|
108
112
|
for (const index of indexes) {
|
|
109
113
|
for (const { column } of index.entries) {
|
|
110
114
|
if (!table.columns.has(column)) {
|
|
@@ -10,6 +10,7 @@ import { AbstractSqlSchemaIntrospector, type JoinedForeignKeyRow, type TableRowR
|
|
|
10
10
|
*/
|
|
11
11
|
export declare class MsSqlSchemaIntrospector extends AbstractSqlSchemaIntrospector {
|
|
12
12
|
protected readonly defaultSchemaExpr = "SCHEMA_NAME()";
|
|
13
|
+
protected triggersQuery(): string;
|
|
13
14
|
protected getTableNamesQuery(): string;
|
|
14
15
|
protected tableExistsQuery(): string;
|
|
15
16
|
protected parseTableExistsResult([row]: {
|
|
@@ -9,6 +9,15 @@ import { AbstractSqlSchemaIntrospector, } from './abstractSqlSchemaIntrospector.
|
|
|
9
9
|
*/
|
|
10
10
|
export class MsSqlSchemaIntrospector extends AbstractSqlSchemaIntrospector {
|
|
11
11
|
defaultSchemaExpr = 'SCHEMA_NAME()';
|
|
12
|
+
triggersQuery() {
|
|
13
|
+
return /*sql*/ `
|
|
14
|
+
SELECT t.name AS name, m.definition AS definition
|
|
15
|
+
FROM sys.triggers t
|
|
16
|
+
JOIN sys.sql_modules m ON m.object_id = t.object_id
|
|
17
|
+
WHERE t.parent_id <> 0 AND OBJECT_SCHEMA_NAME(t.parent_id) = ${this.schemaExpr}
|
|
18
|
+
AND OBJECT_NAME(t.parent_id) = ${this.dialect.placeholder(1)}
|
|
19
|
+
`;
|
|
20
|
+
}
|
|
12
21
|
getTableNamesQuery() {
|
|
13
22
|
return /*sql*/ `
|
|
14
23
|
SELECT TABLE_NAME as table_name
|