uql-orm 0.33.0 → 0.34.1
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/bunSql/bunSqlQuerierPool.js +2 -1
- package/dist/cockroachdb/crdbQuerierPool.js +2 -1
- package/dist/d1/d1QuerierPool.js +2 -1
- package/dist/dialect/abstractDialect.d.ts +27 -3
- package/dist/dialect/abstractDialect.js +34 -4
- package/dist/dialect/abstractSqlDialect.d.ts +27 -1
- package/dist/dialect/abstractSqlDialect.js +74 -36
- package/dist/dialect/mysqlLikeSqlDialect.js +1 -0
- package/dist/dialect/pgLikeSqlDialect.js +1 -0
- package/dist/entity/metadata/definition.js +9 -0
- package/dist/http/handler.js +16 -1
- package/dist/libsql/libsqlQuerierPool.js +2 -1
- package/dist/maria/mariadbQuerierPool.js +2 -1
- package/dist/migrate/builder/migrationBuilder.js +3 -1
- package/dist/migrate/builder/tableBuilder.js +2 -1
- package/dist/migrate/generator/definitionToNode.js +3 -3
- package/dist/migrate/generator/mongoSchemaGenerator.js +7 -6
- package/dist/migrate/introspection/abstractSqlSchemaIntrospector.d.ts +12 -1
- package/dist/migrate/introspection/abstractSqlSchemaIntrospector.js +16 -2
- package/dist/migrate/introspection/baseSqlIntrospector.d.ts +7 -1
- package/dist/migrate/introspection/baseSqlIntrospector.js +11 -12
- package/dist/migrate/introspection/mongoIntrospector.js +0 -1
- package/dist/migrate/introspection/mysqlIntrospector.d.ts +1 -0
- package/dist/migrate/introspection/mysqlIntrospector.js +8 -6
- package/dist/migrate/introspection/postgresIntrospector.d.ts +1 -0
- package/dist/migrate/introspection/postgresIntrospector.js +6 -5
- package/dist/migrate/migrator.d.ts +10 -1
- package/dist/migrate/migrator.js +30 -8
- package/dist/migrate/schemaGenerator.d.ts +16 -6
- package/dist/migrate/schemaGenerator.js +53 -24
- package/dist/mongo/mongoDialect.js +5 -4
- package/dist/mongo/mongodbQuerierPool.js +2 -1
- package/dist/mysql/mysql2QuerierPool.js +2 -1
- package/dist/neon/neonQuerierPool.js +2 -1
- package/dist/pglite/pgliteQuerierPool.js +2 -1
- package/dist/postgres/pgQuerierPool.js +2 -1
- package/dist/schema/schemaAST.d.ts +8 -1
- package/dist/schema/schemaAST.js +22 -13
- package/dist/schema/schemaASTBuilder.d.ts +5 -3
- package/dist/schema/schemaASTBuilder.js +24 -31
- package/dist/schema/types.d.ts +10 -3
- package/dist/sqlite/localSqliteQuerierPool.js +2 -1
- package/dist/sqlite/sqliteDialect.js +2 -1
- package/dist/turso/tursoLocalQuerierPool.js +2 -1
- package/dist/turso/tursoQuerierPool.js +2 -1
- package/dist/type/dialect.d.ts +6 -0
- package/dist/type/entity.d.ts +7 -0
- package/dist/type/migration.d.ts +16 -2
- package/dist/type/querier.d.ts +5 -0
- package/dist/util/sql.util.d.ts +17 -0
- package/dist/util/sql.util.js +23 -0
- package/package.json +1 -1
|
@@ -2,6 +2,7 @@ import { AbstractDialect } from '../../dialect/abstractDialect.js';
|
|
|
2
2
|
import { getMeta } from '../../entity/index.js';
|
|
3
3
|
import { mongoDialectFeatures } from '../../mongo/mongoDialect.js';
|
|
4
4
|
import { getKeys } from '../../util/index.js';
|
|
5
|
+
import { derivedIndexName } from '../../util/sql.util.js';
|
|
5
6
|
import { indexNodeToSchema } from './indexNodeToSchema.js';
|
|
6
7
|
import { serializeMongoCommand } from './mongoCommand.js';
|
|
7
8
|
export class MongoSchemaGenerator extends AbstractDialect {
|
|
@@ -22,24 +23,24 @@ export class MongoSchemaGenerator extends AbstractDialect {
|
|
|
22
23
|
return this.selected(entities, options?.only).flatMap((entity) => this.generateCreateTable(entity, options));
|
|
23
24
|
}
|
|
24
25
|
generateDropSchema(entities) {
|
|
25
|
-
return this.selected(entities).map((entity) => this.generateDropTable(this.resolveTableName(
|
|
26
|
+
return this.selected(entities).map((entity) => this.generateDropTable(this.resolveTableName(getMeta(entity))));
|
|
26
27
|
}
|
|
27
28
|
selected(entities, only) {
|
|
28
29
|
if (!only) {
|
|
29
30
|
return entities;
|
|
30
31
|
}
|
|
31
32
|
const wanted = new Set(only);
|
|
32
|
-
return entities.filter((entity) => wanted.has(this.resolveTableName(
|
|
33
|
+
return entities.filter((entity) => wanted.has(this.resolveTableName(getMeta(entity))));
|
|
33
34
|
}
|
|
34
35
|
generateCreateTable(entity, _options) {
|
|
35
36
|
const meta = getMeta(entity);
|
|
36
|
-
const collectionName = this.resolveTableName(
|
|
37
|
+
const collectionName = this.resolveTableName(meta);
|
|
37
38
|
const indexes = [];
|
|
38
39
|
for (const key of getKeys(meta.fields)) {
|
|
39
40
|
const field = meta.fields[key];
|
|
40
41
|
if (field?.index) {
|
|
41
42
|
const columnName = this.resolveColumnName(key, field);
|
|
42
|
-
const indexName = typeof field.index === 'string' ? field.index :
|
|
43
|
+
const indexName = typeof field.index === 'string' ? field.index : derivedIndexName(collectionName, [columnName]);
|
|
43
44
|
indexes.push({
|
|
44
45
|
name: indexName,
|
|
45
46
|
entries: [{ column: columnName }],
|
|
@@ -132,7 +133,7 @@ export class MongoSchemaGenerator extends AbstractDialect {
|
|
|
132
133
|
}
|
|
133
134
|
diffSchema(entity, currentTable) {
|
|
134
135
|
const meta = getMeta(entity);
|
|
135
|
-
const collectionName = this.resolveTableName(
|
|
136
|
+
const collectionName = this.resolveTableName(meta);
|
|
136
137
|
if (!currentTable) {
|
|
137
138
|
return { tableName: collectionName, type: 'create' };
|
|
138
139
|
}
|
|
@@ -142,7 +143,7 @@ export class MongoSchemaGenerator extends AbstractDialect {
|
|
|
142
143
|
const field = meta.fields[key];
|
|
143
144
|
if (field?.index) {
|
|
144
145
|
const columnName = this.resolveColumnName(key, field);
|
|
145
|
-
const indexName = typeof field.index === 'string' ? field.index :
|
|
146
|
+
const indexName = typeof field.index === 'string' ? field.index : derivedIndexName(collectionName, [columnName]);
|
|
146
147
|
if (!existingIndexes.has(indexName)) {
|
|
147
148
|
indexesToAdd.push({
|
|
148
149
|
name: indexName,
|
|
@@ -36,7 +36,18 @@ export type TableRowReader = <T extends RawRow>(sql: string, params?: unknown[])
|
|
|
36
36
|
*/
|
|
37
37
|
export declare abstract class AbstractSqlSchemaIntrospector extends BaseSqlIntrospector implements SchemaIntrospector {
|
|
38
38
|
protected readonly pool: QuerierPool;
|
|
39
|
-
constructor(pool: QuerierPool);
|
|
39
|
+
constructor(pool: QuerierPool, schema?: string);
|
|
40
|
+
/**
|
|
41
|
+
* The schema every catalogue query filters on, as SQL: the one that was asked for, or the engine's
|
|
42
|
+
* expression for the connection's default. A literal rather than a bind parameter because these
|
|
43
|
+
* queries are assembled as text and several use it more than once.
|
|
44
|
+
*/
|
|
45
|
+
protected get schemaExpr(): string;
|
|
46
|
+
/**
|
|
47
|
+
* How this engine names the connection's current schema (Postgres) or database (MySQL). Empty on
|
|
48
|
+
* an engine with no schemas, whose catalogue queries never reference one.
|
|
49
|
+
*/
|
|
50
|
+
protected readonly defaultSchemaExpr: string;
|
|
40
51
|
getTableSchema(tableName: string): Promise<TableSchema | undefined>;
|
|
41
52
|
getTableNames(): Promise<string[]>;
|
|
42
53
|
tableExists(tableName: string): Promise<boolean>;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { isSqlQuerier } from '../../type/index.js';
|
|
2
|
+
import { escapeAnsiSqlLiteral } from '../../util/sqlLiteral.js';
|
|
2
3
|
import { BaseSqlIntrospector } from './baseSqlIntrospector.js';
|
|
3
4
|
/**
|
|
4
5
|
* Abstract base class for SQL schema introspectors.
|
|
@@ -21,10 +22,23 @@ import { BaseSqlIntrospector } from './baseSqlIntrospector.js';
|
|
|
21
22
|
*/
|
|
22
23
|
export class AbstractSqlSchemaIntrospector extends BaseSqlIntrospector {
|
|
23
24
|
pool;
|
|
24
|
-
constructor(pool) {
|
|
25
|
-
super(pool.dialect);
|
|
25
|
+
constructor(pool, schema) {
|
|
26
|
+
super(pool.dialect, schema);
|
|
26
27
|
this.pool = pool;
|
|
27
28
|
}
|
|
29
|
+
/**
|
|
30
|
+
* The schema every catalogue query filters on, as SQL: the one that was asked for, or the engine's
|
|
31
|
+
* expression for the connection's default. A literal rather than a bind parameter because these
|
|
32
|
+
* queries are assembled as text and several use it more than once.
|
|
33
|
+
*/
|
|
34
|
+
get schemaExpr() {
|
|
35
|
+
return this.schema === undefined ? this.defaultSchemaExpr : escapeAnsiSqlLiteral(this.schema);
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* How this engine names the connection's current schema (Postgres) or database (MySQL). Empty on
|
|
39
|
+
* an engine with no schemas, whose catalogue queries never reference one.
|
|
40
|
+
*/
|
|
41
|
+
defaultSchemaExpr = '';
|
|
28
42
|
async getTableSchema(tableName) {
|
|
29
43
|
return this.withSqlQuerier(async (querier) => {
|
|
30
44
|
const read = createTableRowReader(querier);
|
|
@@ -7,9 +7,15 @@ import type { TableSchema } from '../../type/migration.js';
|
|
|
7
7
|
*/
|
|
8
8
|
export declare abstract class BaseSqlIntrospector {
|
|
9
9
|
protected readonly dialect: AbstractSqlDialect;
|
|
10
|
+
readonly schema?: string | undefined;
|
|
10
11
|
/** Columns and uniqueness only; each introspector opts in to what its catalogue queries report. */
|
|
11
12
|
readonly indexFacets: ReadonlySet<IndexFacet>;
|
|
12
|
-
|
|
13
|
+
/**
|
|
14
|
+
* The one schema these queries read, `undefined` for the connection's own default. Every table
|
|
15
|
+
* reported is stamped with it, so a diff compares like with like: entity and database both say
|
|
16
|
+
* `undefined` for "wherever the connection points", and name a schema only when one was asked for.
|
|
17
|
+
*/
|
|
18
|
+
constructor(dialect: AbstractSqlDialect, schema?: string | undefined);
|
|
13
19
|
protected escapeId(identifier: string): string;
|
|
14
20
|
/**
|
|
15
21
|
* Introspect entire database schema and return SchemaAST.
|
|
@@ -1,15 +1,22 @@
|
|
|
1
1
|
import { canonicalColumnType } from '../../schema/canonicalType.js';
|
|
2
|
-
import { SchemaAST } from '../../schema/schemaAST.js';
|
|
2
|
+
import { createTableNode, SchemaAST } from '../../schema/schemaAST.js';
|
|
3
3
|
import { escapeSqlId } from '../../util/index.js';
|
|
4
4
|
/**
|
|
5
5
|
* Base class for SQL introspectors with shared AST building logic.
|
|
6
6
|
*/
|
|
7
7
|
export class BaseSqlIntrospector {
|
|
8
8
|
dialect;
|
|
9
|
+
schema;
|
|
9
10
|
/** Columns and uniqueness only; each introspector opts in to what its catalogue queries report. */
|
|
10
11
|
indexFacets = new Set();
|
|
11
|
-
|
|
12
|
+
/**
|
|
13
|
+
* The one schema these queries read, `undefined` for the connection's own default. Every table
|
|
14
|
+
* reported is stamped with it, so a diff compares like with like: entity and database both say
|
|
15
|
+
* `undefined` for "wherever the connection points", and name a schema only when one was asked for.
|
|
16
|
+
*/
|
|
17
|
+
constructor(dialect, schema) {
|
|
12
18
|
this.dialect = dialect;
|
|
19
|
+
this.schema = schema;
|
|
13
20
|
}
|
|
14
21
|
escapeId(identifier) {
|
|
15
22
|
return escapeSqlId(identifier, this.dialect.escapeIdChar);
|
|
@@ -41,16 +48,8 @@ export class BaseSqlIntrospector {
|
|
|
41
48
|
}
|
|
42
49
|
buildTables(ast, tableNodes, tableSchemas) {
|
|
43
50
|
for (const schema of tableSchemas) {
|
|
44
|
-
const
|
|
45
|
-
const
|
|
46
|
-
name: schema.name,
|
|
47
|
-
columns,
|
|
48
|
-
primaryKey: [],
|
|
49
|
-
indexes: [],
|
|
50
|
-
schema: ast,
|
|
51
|
-
incomingRelations: [],
|
|
52
|
-
outgoingRelations: [],
|
|
53
|
-
};
|
|
51
|
+
const table = createTableNode(schema.name, this.schema);
|
|
52
|
+
const { columns } = table;
|
|
54
53
|
for (const col of schema.columns) {
|
|
55
54
|
const column = {
|
|
56
55
|
name: col.name,
|
|
@@ -5,6 +5,7 @@ import { AbstractSqlSchemaIntrospector, type TableRowReader } from './abstractSq
|
|
|
5
5
|
* Works with both MySQL and MariaDB as they share the same information_schema structure.
|
|
6
6
|
*/
|
|
7
7
|
export declare class MysqlSchemaIntrospector extends AbstractSqlSchemaIntrospector {
|
|
8
|
+
protected readonly defaultSchemaExpr = "DATABASE()";
|
|
8
9
|
protected getTableNamesQuery(): string;
|
|
9
10
|
protected tableExistsQuery(): string;
|
|
10
11
|
protected parseTableExistsResult(results: {
|
|
@@ -4,11 +4,13 @@ import { AbstractSqlSchemaIntrospector } from './abstractSqlSchemaIntrospector.j
|
|
|
4
4
|
* Works with both MySQL and MariaDB as they share the same information_schema structure.
|
|
5
5
|
*/
|
|
6
6
|
export class MysqlSchemaIntrospector extends AbstractSqlSchemaIntrospector {
|
|
7
|
+
// A MySQL "schema" is a database, so the connection's own is what `DATABASE()` reports.
|
|
8
|
+
defaultSchemaExpr = 'DATABASE()';
|
|
7
9
|
getTableNamesQuery() {
|
|
8
10
|
return /*sql*/ `
|
|
9
11
|
SELECT TABLE_NAME as table_name
|
|
10
12
|
FROM information_schema.TABLES
|
|
11
|
-
WHERE TABLE_SCHEMA =
|
|
13
|
+
WHERE TABLE_SCHEMA = ${this.schemaExpr}
|
|
12
14
|
AND TABLE_TYPE = 'BASE TABLE'
|
|
13
15
|
ORDER BY TABLE_NAME
|
|
14
16
|
`;
|
|
@@ -17,7 +19,7 @@ export class MysqlSchemaIntrospector extends AbstractSqlSchemaIntrospector {
|
|
|
17
19
|
return /*sql*/ `
|
|
18
20
|
SELECT COUNT(*) as count
|
|
19
21
|
FROM information_schema.TABLES
|
|
20
|
-
WHERE TABLE_SCHEMA =
|
|
22
|
+
WHERE TABLE_SCHEMA = ${this.schemaExpr}
|
|
21
23
|
AND TABLE_NAME = ?
|
|
22
24
|
`;
|
|
23
25
|
}
|
|
@@ -43,7 +45,7 @@ export class MysqlSchemaIntrospector extends AbstractSqlSchemaIntrospector {
|
|
|
43
45
|
EXTRA as extra,
|
|
44
46
|
COLUMN_COMMENT as column_comment
|
|
45
47
|
FROM information_schema.COLUMNS
|
|
46
|
-
WHERE TABLE_SCHEMA =
|
|
48
|
+
WHERE TABLE_SCHEMA = ${this.schemaExpr}
|
|
47
49
|
AND TABLE_NAME = ?
|
|
48
50
|
ORDER BY ORDINAL_POSITION
|
|
49
51
|
`;
|
|
@@ -55,7 +57,7 @@ export class MysqlSchemaIntrospector extends AbstractSqlSchemaIntrospector {
|
|
|
55
57
|
GROUP_CONCAT(COLUMN_NAME ORDER BY SEQ_IN_INDEX) as columns,
|
|
56
58
|
NOT NON_UNIQUE as is_unique
|
|
57
59
|
FROM information_schema.STATISTICS
|
|
58
|
-
WHERE TABLE_SCHEMA =
|
|
60
|
+
WHERE TABLE_SCHEMA = ${this.schemaExpr}
|
|
59
61
|
AND TABLE_NAME = ?
|
|
60
62
|
AND INDEX_NAME != 'PRIMARY'
|
|
61
63
|
GROUP BY INDEX_NAME, NON_UNIQUE
|
|
@@ -75,7 +77,7 @@ export class MysqlSchemaIntrospector extends AbstractSqlSchemaIntrospector {
|
|
|
75
77
|
JOIN information_schema.REFERENTIAL_CONSTRAINTS rc
|
|
76
78
|
ON kcu.CONSTRAINT_NAME = rc.CONSTRAINT_NAME
|
|
77
79
|
AND kcu.TABLE_SCHEMA = rc.CONSTRAINT_SCHEMA
|
|
78
|
-
WHERE kcu.TABLE_SCHEMA =
|
|
80
|
+
WHERE kcu.TABLE_SCHEMA = ${this.schemaExpr}
|
|
79
81
|
AND kcu.TABLE_NAME = ?
|
|
80
82
|
AND kcu.REFERENCED_TABLE_NAME IS NOT NULL
|
|
81
83
|
GROUP BY kcu.CONSTRAINT_NAME, kcu.REFERENCED_TABLE_NAME, rc.DELETE_RULE, rc.UPDATE_RULE
|
|
@@ -86,7 +88,7 @@ export class MysqlSchemaIntrospector extends AbstractSqlSchemaIntrospector {
|
|
|
86
88
|
return /*sql*/ `
|
|
87
89
|
SELECT COLUMN_NAME as column_name
|
|
88
90
|
FROM information_schema.KEY_COLUMN_USAGE
|
|
89
|
-
WHERE TABLE_SCHEMA =
|
|
91
|
+
WHERE TABLE_SCHEMA = ${this.schemaExpr}
|
|
90
92
|
AND TABLE_NAME = ?
|
|
91
93
|
AND CONSTRAINT_NAME = 'PRIMARY'
|
|
92
94
|
ORDER BY ORDINAL_POSITION
|
|
@@ -5,6 +5,7 @@ import { AbstractSqlSchemaIntrospector, type TableRowReader } from './abstractSq
|
|
|
5
5
|
* PostgreSQL schema introspector
|
|
6
6
|
*/
|
|
7
7
|
export declare class PostgresSchemaIntrospector extends AbstractSqlSchemaIntrospector {
|
|
8
|
+
protected readonly defaultSchemaExpr = "current_schema()";
|
|
8
9
|
/**
|
|
9
10
|
* Expressions and predicates are read back too, for `generate:from-db`, but they are text the
|
|
10
11
|
* database reprints in its own words, so they are not comparable and are not claimed here.
|
|
@@ -4,6 +4,7 @@ import { AbstractSqlSchemaIntrospector } from './abstractSqlSchemaIntrospector.j
|
|
|
4
4
|
* PostgreSQL schema introspector
|
|
5
5
|
*/
|
|
6
6
|
export class PostgresSchemaIntrospector extends AbstractSqlSchemaIntrospector {
|
|
7
|
+
defaultSchemaExpr = 'current_schema()';
|
|
7
8
|
/**
|
|
8
9
|
* Expressions and predicates are read back too, for `generate:from-db`, but they are text the
|
|
9
10
|
* database reprints in its own words, so they are not comparable and are not claimed here.
|
|
@@ -19,7 +20,7 @@ export class PostgresSchemaIntrospector extends AbstractSqlSchemaIntrospector {
|
|
|
19
20
|
return /*sql*/ `
|
|
20
21
|
SELECT table_name
|
|
21
22
|
FROM information_schema.tables
|
|
22
|
-
WHERE table_schema =
|
|
23
|
+
WHERE table_schema = ${this.schemaExpr}
|
|
23
24
|
AND table_type = 'BASE TABLE'
|
|
24
25
|
ORDER BY table_name
|
|
25
26
|
`;
|
|
@@ -28,7 +29,7 @@ export class PostgresSchemaIntrospector extends AbstractSqlSchemaIntrospector {
|
|
|
28
29
|
return /*sql*/ `
|
|
29
30
|
SELECT EXISTS (
|
|
30
31
|
SELECT FROM information_schema.tables
|
|
31
|
-
WHERE table_schema =
|
|
32
|
+
WHERE table_schema = ${this.schemaExpr}
|
|
32
33
|
AND table_name = $1
|
|
33
34
|
) AS exists
|
|
34
35
|
`;
|
|
@@ -74,7 +75,7 @@ export class PostgresSchemaIntrospector extends AbstractSqlSchemaIntrospector {
|
|
|
74
75
|
c.ordinal_position
|
|
75
76
|
) AS column_comment
|
|
76
77
|
FROM information_schema.columns c
|
|
77
|
-
WHERE c.table_schema =
|
|
78
|
+
WHERE c.table_schema = ${this.schemaExpr}
|
|
78
79
|
AND c.table_name = $1
|
|
79
80
|
ORDER BY c.ordinal_position
|
|
80
81
|
`;
|
|
@@ -152,7 +153,7 @@ export class PostgresSchemaIntrospector extends AbstractSqlSchemaIntrospector {
|
|
|
152
153
|
AND rc.constraint_schema = tc.table_schema
|
|
153
154
|
WHERE tc.constraint_type = 'FOREIGN KEY'
|
|
154
155
|
AND tc.table_name = $1
|
|
155
|
-
AND tc.table_schema =
|
|
156
|
+
AND tc.table_schema = ${this.schemaExpr}
|
|
156
157
|
GROUP BY tc.constraint_name, ccu.table_name, rc.delete_rule, rc.update_rule
|
|
157
158
|
ORDER BY tc.constraint_name
|
|
158
159
|
`;
|
|
@@ -166,7 +167,7 @@ export class PostgresSchemaIntrospector extends AbstractSqlSchemaIntrospector {
|
|
|
166
167
|
AND tc.table_schema = kcu.table_schema
|
|
167
168
|
WHERE tc.constraint_type = 'PRIMARY KEY'
|
|
168
169
|
AND tc.table_name = $1
|
|
169
|
-
AND tc.table_schema =
|
|
170
|
+
AND tc.table_schema = ${this.schemaExpr}
|
|
170
171
|
ORDER BY kcu.ordinal_position
|
|
171
172
|
`;
|
|
172
173
|
}
|
|
@@ -25,7 +25,8 @@ export declare class Migrator {
|
|
|
25
25
|
* Set the schema generator for DDL operations
|
|
26
26
|
*/
|
|
27
27
|
setSchemaGenerator(generator: SchemaGenerator): void;
|
|
28
|
-
|
|
28
|
+
/** `schema` reads one namespace instead of the connection's own; see {@link BaseSqlIntrospector.schema}. */
|
|
29
|
+
protected createIntrospector(schema?: string): SchemaIntrospector | undefined;
|
|
29
30
|
protected createGenerator(): SchemaGenerator | undefined;
|
|
30
31
|
/**
|
|
31
32
|
* Get all discovered migrations from the migrations directory
|
|
@@ -77,6 +78,14 @@ export declare class Migrator {
|
|
|
77
78
|
* Get all schema differences between entities and database
|
|
78
79
|
*/
|
|
79
80
|
getDiffs(): Promise<SchemaDiff[]>;
|
|
81
|
+
/**
|
|
82
|
+
* One AST spanning every schema the entities claim, each table stamped with the schema it was read
|
|
83
|
+
* from. Read per schema rather than all at once, so a table comes back keyed exactly as the entity
|
|
84
|
+
* that wants it spells the key: `undefined` on both sides for the connection's default, a name on
|
|
85
|
+
* both sides otherwise. Ordinarily that is one schema and one pass, as before, and that pass keeps
|
|
86
|
+
* {@link schemaIntrospector} so a caller that replaced it still wins.
|
|
87
|
+
*/
|
|
88
|
+
private introspectClaimedSchemas;
|
|
80
89
|
findEntityForTable(tableName: string): Promise<Type<unknown> | undefined>;
|
|
81
90
|
/**
|
|
82
91
|
* Sync schema directly (for development only - not for production!)
|
package/dist/migrate/migrator.js
CHANGED
|
@@ -2,7 +2,7 @@ import { mkdir, readdir, writeFile } from 'node:fs/promises';
|
|
|
2
2
|
import { basename, extname, join } from 'node:path';
|
|
3
3
|
import { pathToFileURL } from 'node:url';
|
|
4
4
|
import { getEntities, getMeta } from '../entity/index.js';
|
|
5
|
-
import { introspectSchema } from '../schema/index.js';
|
|
5
|
+
import { introspectSchema, SchemaAST } from '../schema/index.js';
|
|
6
6
|
import { isKnownMigratorDialect, isSqlQuerier } from '../type/index.js';
|
|
7
7
|
import { LoggerWrapper } from '../util/index.js';
|
|
8
8
|
import { withQuerierForMigrations, withSqlQuerierForMigrations } from './acquireQuerierForMigrations.js';
|
|
@@ -71,19 +71,20 @@ export class Migrator {
|
|
|
71
71
|
setSchemaGenerator(generator) {
|
|
72
72
|
this.schemaGenerator = generator;
|
|
73
73
|
}
|
|
74
|
-
|
|
74
|
+
/** `schema` reads one namespace instead of the connection's own; see {@link BaseSqlIntrospector.schema}. */
|
|
75
|
+
createIntrospector(schema) {
|
|
75
76
|
const d = this.dialectName;
|
|
76
77
|
if (!isKnownMigratorDialect(d)) {
|
|
77
78
|
return undefined;
|
|
78
79
|
}
|
|
79
80
|
switch (d) {
|
|
80
81
|
case 'postgres':
|
|
81
|
-
return new PostgresSchemaIntrospector(this.pool);
|
|
82
|
+
return new PostgresSchemaIntrospector(this.pool, schema);
|
|
82
83
|
case 'cockroachdb':
|
|
83
|
-
return new CockroachSchemaIntrospector(this.pool);
|
|
84
|
+
return new CockroachSchemaIntrospector(this.pool, schema);
|
|
84
85
|
case 'mysql':
|
|
85
86
|
case 'mariadb':
|
|
86
|
-
return new MysqlSchemaIntrospector(this.pool);
|
|
87
|
+
return new MysqlSchemaIntrospector(this.pool, schema);
|
|
87
88
|
case 'sqlite':
|
|
88
89
|
return new SqliteSchemaIntrospector(this.pool);
|
|
89
90
|
case 'mongodb':
|
|
@@ -279,11 +280,11 @@ export class Migrator {
|
|
|
279
280
|
if (!this.schemaGenerator || !this.schemaIntrospector) {
|
|
280
281
|
throw new TypeError('Schema generator and introspector must be set');
|
|
281
282
|
}
|
|
282
|
-
const ast = await
|
|
283
|
+
const ast = await this.introspectClaimedSchemas();
|
|
283
284
|
const diffs = [];
|
|
284
285
|
for (const entity of this.entities) {
|
|
285
286
|
const meta = getMeta(entity);
|
|
286
|
-
const tableName = this.schemaGenerator.resolveTableName(
|
|
287
|
+
const tableName = this.schemaGenerator.resolveTableName(meta);
|
|
287
288
|
const currentTable = ast.getTable(tableName);
|
|
288
289
|
const diff = this.schemaGenerator.diffSchema(entity, currentTable);
|
|
289
290
|
if (diff) {
|
|
@@ -292,6 +293,27 @@ export class Migrator {
|
|
|
292
293
|
}
|
|
293
294
|
return diffs;
|
|
294
295
|
}
|
|
296
|
+
/**
|
|
297
|
+
* One AST spanning every schema the entities claim, each table stamped with the schema it was read
|
|
298
|
+
* from. Read per schema rather than all at once, so a table comes back keyed exactly as the entity
|
|
299
|
+
* that wants it spells the key: `undefined` on both sides for the connection's default, a name on
|
|
300
|
+
* both sides otherwise. Ordinarily that is one schema and one pass, as before, and that pass keeps
|
|
301
|
+
* {@link schemaIntrospector} so a caller that replaced it still wins.
|
|
302
|
+
*/
|
|
303
|
+
async introspectClaimedSchemas() {
|
|
304
|
+
const claimed = new Set(this.entities.map((entity) => this.pool.dialect.resolveSchema(getMeta(entity))));
|
|
305
|
+
const merged = new SchemaAST();
|
|
306
|
+
for (const schema of claimed) {
|
|
307
|
+
const introspector = schema === undefined ? this.schemaIntrospector : this.createIntrospector(schema);
|
|
308
|
+
if (!introspector) {
|
|
309
|
+
continue;
|
|
310
|
+
}
|
|
311
|
+
for (const table of (await introspectSchema(introspector)).getTables()) {
|
|
312
|
+
merged.addTable(table);
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
return merged;
|
|
316
|
+
}
|
|
295
317
|
async findEntityForTable(tableName) {
|
|
296
318
|
await this.ensureSchemaGenerator();
|
|
297
319
|
if (!this.schemaGenerator) {
|
|
@@ -299,7 +321,7 @@ export class Migrator {
|
|
|
299
321
|
}
|
|
300
322
|
for (const entity of this.entities) {
|
|
301
323
|
const meta = getMeta(entity);
|
|
302
|
-
const name = this.schemaGenerator.resolveTableName(
|
|
324
|
+
const name = this.schemaGenerator.resolveTableName(meta);
|
|
303
325
|
if (name === tableName) {
|
|
304
326
|
return entity;
|
|
305
327
|
}
|
|
@@ -13,11 +13,11 @@ export declare class SqlSchemaGenerator implements SqlDdlGenerator {
|
|
|
13
13
|
constructor(dialect: AbstractSqlDialect, defaultForeignKeyAction?: ForeignKeyAction);
|
|
14
14
|
get namingStrategy(): NamingStrategy | undefined;
|
|
15
15
|
get features(): DialectFeatures;
|
|
16
|
-
resolveTableName<E>(
|
|
16
|
+
resolveTableName<E>(meta: EntityMeta<E>): string;
|
|
17
|
+
resolveTableAlias<E>(meta: EntityMeta<E>): string;
|
|
18
|
+
resolveSchema<E>(meta: EntityMeta<E>): string | undefined;
|
|
17
19
|
resolveColumnName(key: string, field: FieldOptions): string;
|
|
18
|
-
/**
|
|
19
|
-
* Escape an identifier (table name, column name, etc.)
|
|
20
|
-
*/
|
|
20
|
+
/** Escape an identifier (table name, column name, etc.) */
|
|
21
21
|
protected escapeId(identifier: string): string;
|
|
22
22
|
/**
|
|
23
23
|
* Primary key type for auto-increment integer IDs
|
|
@@ -38,6 +38,12 @@ export declare class SqlSchemaGenerator implements SqlDdlGenerator {
|
|
|
38
38
|
* foreign key in, but it resolves targets lazily, so a forward reference is fine there.
|
|
39
39
|
*/
|
|
40
40
|
generateCreateSchema(entities: readonly Type<unknown>[], options?: CreateSchemaOptions): string[];
|
|
41
|
+
/**
|
|
42
|
+
* One statement per distinct schema the tables being created live in, in first-seen order. Only
|
|
43
|
+
* the tables actually being created, so a narrowed `only` does not declare namespaces it is not
|
|
44
|
+
* about to fill. Empty on an engine without schemas, whose tables are never qualified.
|
|
45
|
+
*/
|
|
46
|
+
private generateCreateSchemas;
|
|
41
47
|
generateDropSchema(entities: readonly Type<unknown>[], options?: DropSchemaOptions): string[];
|
|
42
48
|
/**
|
|
43
49
|
* The tables of `entities` in dependency order, optionally narrowed to `only`. The AST always spans
|
|
@@ -51,7 +57,11 @@ export declare class SqlSchemaGenerator implements SqlDdlGenerator {
|
|
|
51
57
|
generateCreateIndex(tableName: string, index: IndexSchema, options?: {
|
|
52
58
|
ifNotExists?: boolean;
|
|
53
59
|
}): string;
|
|
54
|
-
|
|
60
|
+
/**
|
|
61
|
+
* `schema` is the table's, because that is where its indexes live. MySQL takes it from the table
|
|
62
|
+
* operand instead, which is already qualified.
|
|
63
|
+
*/
|
|
64
|
+
generateDropIndex(tableName: string, indexName: string, schema?: string): string;
|
|
55
65
|
/**
|
|
56
66
|
* Generate a column definition from a {@link ColumnSchema}, whose type is the engine's own spelling
|
|
57
67
|
* and may already carry its precision (or even `PRIMARY KEY`, for a serial).
|
|
@@ -156,7 +166,7 @@ export declare class SqlSchemaGenerator implements SqlDdlGenerator {
|
|
|
156
166
|
* other way and the table is created under one name and compared under another, which reports every
|
|
157
167
|
* table of a project using a naming strategy as both missing and unexpected.
|
|
158
168
|
*/
|
|
159
|
-
export declare function buildEntityAST(generator: Pick<SchemaGenerator, '
|
|
169
|
+
export declare function buildEntityAST(generator: Pick<SchemaGenerator, 'resolveTableAlias' | 'resolveSchema' | 'resolveColumnName'>, entities: readonly Type<unknown>[], defaultForeignKeyAction?: ForeignKeyAction): SchemaAST;
|
|
160
170
|
/**
|
|
161
171
|
* Synchronous factory for SQL schema generators only.
|
|
162
172
|
* For MongoDB, use `createSchemaGeneratorAsync` from `./schemaGeneratorAsync.js` so the optional `mongodb` peer is not loaded at import time.
|