uql-orm 0.43.0 → 0.45.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -2
- package/dist/browser/querier/httpQuerier.d.ts +6 -0
- package/dist/browser/querier/httpQuerier.js +1 -1
- package/dist/browser/uql-browser.min.js +2 -2
- package/dist/browser/uql-browser.min.js.map +4 -4
- package/dist/dialect/abstractDialect.js +5 -6
- package/dist/dialect/abstractSqlDialect.d.ts +2 -2
- package/dist/dialect/abstractSqlDialect.js +1 -1
- package/dist/dialect/mysqlLikeSqlDialect.d.ts +8 -1
- package/dist/dialect/mysqlLikeSqlDialect.js +8 -1
- package/dist/dialect/pgLikeSqlDialect.d.ts +1 -1
- package/dist/dialect/pgLikeSqlDialect.js +1 -1
- package/dist/entity/decorator/bag.d.ts +3 -0
- package/dist/entity/index.d.ts +1 -1
- package/dist/entity/index.js +1 -1
- package/dist/entity/metadata/definition.d.ts +15 -13
- package/dist/entity/metadata/definition.js +47 -16
- package/dist/http/handler.d.ts +8 -0
- package/dist/http/handler.js +5 -5
- package/dist/migrate/builder/migrationBuilder.js +1 -2
- package/dist/migrate/builder/tableBuilder.d.ts +1 -0
- package/dist/migrate/builder/tableBuilder.js +9 -10
- package/dist/migrate/builder/types.d.ts +3 -19
- package/dist/migrate/cli.d.ts +5 -0
- package/dist/migrate/cli.js +33 -16
- package/dist/migrate/codegen/entityTypes.d.ts +7 -0
- package/dist/migrate/codegen/entityTypes.js +69 -0
- package/dist/migrate/codegen/index.d.ts +1 -0
- package/dist/migrate/codegen/index.js +1 -0
- package/dist/migrate/generator/definitionToNode.js +2 -2
- package/dist/migrate/index.d.ts +1 -1
- package/dist/migrate/introspection/abstractSqlSchemaIntrospector.d.ts +2 -5
- package/dist/migrate/introspection/abstractSqlSchemaIntrospector.js +2 -0
- package/dist/migrate/introspection/baseSqlIntrospector.js +4 -3
- package/dist/migrate/introspection/mysqlIntrospector.js +1 -2
- package/dist/migrate/introspection/postgresIntrospector.js +1 -2
- package/dist/migrate/introspection/sqliteIntrospector.js +1 -2
- package/dist/migrate/migrator.d.ts +34 -20
- package/dist/migrate/migrator.js +90 -35
- package/dist/migrate/schemaGenerator.d.ts +20 -5
- package/dist/migrate/schemaGenerator.js +105 -30
- package/dist/schema/schemaASTBuilder.d.ts +23 -2
- package/dist/schema/schemaASTBuilder.js +3 -2
- package/dist/schema/schemaASTDiffer.d.ts +11 -1
- package/dist/schema/schemaASTDiffer.js +23 -7
- package/dist/schema/types.d.ts +19 -4
- package/dist/sqlite/sqliteDialect.d.ts +1 -1
- package/dist/sqlite/sqliteDialect.js +1 -1
- package/dist/type/entity.d.ts +14 -1
- package/dist/type/migration.d.ts +55 -9
- package/dist/type/queryWhere.d.ts +13 -3
- package/dist/util/field.util.d.ts +7 -2
- package/dist/util/field.util.js +9 -12
- package/dist/util/object.util.d.ts +3 -3
- package/dist/util/object.util.js +3 -3
- package/package.json +3 -3
|
@@ -16,6 +16,7 @@ export declare class TableBuilder implements ITableBuilder {
|
|
|
16
16
|
private _foreignKeyBuilders;
|
|
17
17
|
private _comment?;
|
|
18
18
|
constructor(name: string);
|
|
19
|
+
/** Big, matching an entity's `@Id`: a key is spelled from this type, so it has to state the real one. */
|
|
19
20
|
id(name?: string, options?: BaseColumnOptions): IColumnBuilder;
|
|
20
21
|
integer(name: string, options?: BaseColumnOptions): IColumnBuilder;
|
|
21
22
|
smallint(name: string, options?: BaseColumnOptions): IColumnBuilder;
|
|
@@ -12,8 +12,8 @@ import { expr } from './expressions.js';
|
|
|
12
12
|
*/
|
|
13
13
|
class TableForeignKeyBuilder {
|
|
14
14
|
_columns;
|
|
15
|
-
|
|
16
|
-
|
|
15
|
+
_referencedTable;
|
|
16
|
+
_referencedColumns = [];
|
|
17
17
|
_onDelete = 'NO ACTION';
|
|
18
18
|
_onUpdate = 'NO ACTION';
|
|
19
19
|
_name;
|
|
@@ -21,8 +21,8 @@ class TableForeignKeyBuilder {
|
|
|
21
21
|
this._columns = columns;
|
|
22
22
|
}
|
|
23
23
|
references(table, columns) {
|
|
24
|
-
this.
|
|
25
|
-
this.
|
|
24
|
+
this._referencedTable = table;
|
|
25
|
+
this._referencedColumns = columns;
|
|
26
26
|
return this;
|
|
27
27
|
}
|
|
28
28
|
onDelete(action) {
|
|
@@ -41,13 +41,12 @@ class TableForeignKeyBuilder {
|
|
|
41
41
|
* Build the foreign key definition.
|
|
42
42
|
*/
|
|
43
43
|
build() {
|
|
44
|
-
if (!this.
|
|
44
|
+
if (!this._referencedTable)
|
|
45
45
|
return undefined;
|
|
46
46
|
return {
|
|
47
47
|
name: this._name,
|
|
48
48
|
columns: this._columns,
|
|
49
|
-
|
|
50
|
-
referencesColumns: this._referencesColumns,
|
|
49
|
+
references: { table: this._referencedTable, columns: this._referencedColumns },
|
|
51
50
|
onDelete: this._onDelete,
|
|
52
51
|
onUpdate: this._onUpdate,
|
|
53
52
|
};
|
|
@@ -66,8 +65,9 @@ export class TableBuilder {
|
|
|
66
65
|
constructor(name) {
|
|
67
66
|
this._name = name;
|
|
68
67
|
}
|
|
68
|
+
/** Big, matching an entity's `@Id`: a key is spelled from this type, so it has to state the real one. */
|
|
69
69
|
id(name = 'id', options = {}) {
|
|
70
|
-
return this.add(name, { category: 'integer' }, { ...options, primaryKey: true, autoIncrement: true });
|
|
70
|
+
return this.add(name, { category: 'integer', size: 'big' }, { ...options, primaryKey: true, autoIncrement: true });
|
|
71
71
|
}
|
|
72
72
|
integer(name, options) {
|
|
73
73
|
return this.add(name, { category: 'integer' }, options);
|
|
@@ -217,8 +217,7 @@ export class TableBuilder {
|
|
|
217
217
|
foreignKeys.push({
|
|
218
218
|
name: col.foreignKey.name,
|
|
219
219
|
columns: [col.name],
|
|
220
|
-
|
|
221
|
-
referencesColumns: col.foreignKey.columns,
|
|
220
|
+
references: { table: col.foreignKey.table, columns: col.foreignKey.columns },
|
|
222
221
|
onDelete: col.foreignKey.onDelete,
|
|
223
222
|
onUpdate: col.foreignKey.onUpdate,
|
|
224
223
|
});
|
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
*/
|
|
7
7
|
import type { CanonicalType, ForeignKeyAction } from '../../schema/types.js';
|
|
8
8
|
import type { IndexColumnInput, IndexOptions, IndexSchema } from '../../type/index.js';
|
|
9
|
+
import type { ForeignKeySchema } from '../../type/migration.js';
|
|
9
10
|
/**
|
|
10
11
|
* Foreign key reference options.
|
|
11
12
|
*/
|
|
@@ -124,27 +125,10 @@ export interface TableDefinition {
|
|
|
124
125
|
/** Index definitions */
|
|
125
126
|
indexes: IndexSchema[];
|
|
126
127
|
/** Foreign key definitions at table level */
|
|
127
|
-
foreignKeys:
|
|
128
|
+
foreignKeys: ForeignKeySchema[];
|
|
128
129
|
/** Table comment */
|
|
129
130
|
comment?: string;
|
|
130
131
|
}
|
|
131
|
-
/**
|
|
132
|
-
* Table-level foreign key (for composite FKs).
|
|
133
|
-
*/
|
|
134
|
-
export interface TableForeignKeyDefinition {
|
|
135
|
-
/** Constraint name */
|
|
136
|
-
name?: string;
|
|
137
|
-
/** Local columns */
|
|
138
|
-
columns: string[];
|
|
139
|
-
/** Referenced table */
|
|
140
|
-
referencesTable: string;
|
|
141
|
-
/** Referenced columns */
|
|
142
|
-
referencesColumns: string[];
|
|
143
|
-
/** Action on delete */
|
|
144
|
-
onDelete: ForeignKeyAction;
|
|
145
|
-
/** Action on update */
|
|
146
|
-
onUpdate: ForeignKeyAction;
|
|
147
|
-
}
|
|
148
132
|
/**
|
|
149
133
|
* Type of migration operation.
|
|
150
134
|
*/
|
|
@@ -238,7 +222,7 @@ export interface DropIndexOperation extends MigrationOperation {
|
|
|
238
222
|
export interface AddForeignKeyOperation extends MigrationOperation {
|
|
239
223
|
type: 'addForeignKey';
|
|
240
224
|
tableName: string;
|
|
241
|
-
foreignKey:
|
|
225
|
+
foreignKey: ForeignKeySchema;
|
|
242
226
|
}
|
|
243
227
|
/**
|
|
244
228
|
* Drop foreign key operation.
|
package/dist/migrate/cli.d.ts
CHANGED
|
@@ -14,6 +14,11 @@ export declare function runStatus(migrator: Migrator): Promise<void>;
|
|
|
14
14
|
export declare function runPending(migrator: Migrator): Promise<void>;
|
|
15
15
|
export declare function runGenerate(migrator: Migrator, args: string[]): Promise<void>;
|
|
16
16
|
export declare function runGenerateFromEntities(migrator: Migrator, args: string[]): Promise<void>;
|
|
17
|
+
/**
|
|
18
|
+
* Writes a `.d.ts` for the registered entities. The point is a schema defined at runtime: the same
|
|
19
|
+
* registration that made the tables is what the compiler then checks queries against.
|
|
20
|
+
*/
|
|
21
|
+
export declare function runTypes(migrator: Migrator, args: string[]): void;
|
|
17
22
|
export declare function runSync(migrator: Migrator, args: string[], config: Partial<Config>): Promise<void>;
|
|
18
23
|
export declare function runGenerateFromDb(migrator: Migrator, args: string[], config: Partial<Config>): Promise<void>;
|
|
19
24
|
export declare function runDriftCheck(migrator: Migrator, config: Partial<Config>): Promise<void>;
|
package/dist/migrate/cli.js
CHANGED
|
@@ -4,6 +4,7 @@ import * as path from 'node:path';
|
|
|
4
4
|
import { assertCliConfig } from './assertCliConfig.js';
|
|
5
5
|
import { loadConfig } from './cli-config.js';
|
|
6
6
|
import { createEntityCodeGenerator } from './codegen/entityCodeGenerator.js';
|
|
7
|
+
import { entityTypesSource } from './codegen/entityTypes.js';
|
|
7
8
|
import { detectDrift } from './drift/driftDetector.js';
|
|
8
9
|
import { Migrator } from './migrator.js';
|
|
9
10
|
import { buildEntityAST, createSchemaGenerator } from './schemaGenerator.js';
|
|
@@ -74,6 +75,9 @@ export async function main(args = process.argv.slice(2)) {
|
|
|
74
75
|
case 'sync':
|
|
75
76
|
await runSync(migrator, filteredArgs.slice(1), config);
|
|
76
77
|
break;
|
|
78
|
+
case 'types':
|
|
79
|
+
runTypes(migrator, filteredArgs.slice(1));
|
|
80
|
+
break;
|
|
77
81
|
case 'pending':
|
|
78
82
|
await runPending(migrator);
|
|
79
83
|
break;
|
|
@@ -189,35 +193,45 @@ export async function runGenerateFromEntities(migrator, args) {
|
|
|
189
193
|
const filePath = await migrator.generateFromEntities(name);
|
|
190
194
|
console.log(`\nCreated migration from entities: ${filePath}`);
|
|
191
195
|
}
|
|
196
|
+
/**
|
|
197
|
+
* Writes a `.d.ts` for the registered entities. The point is a schema defined at runtime: the same
|
|
198
|
+
* registration that made the tables is what the compiler then checks queries against.
|
|
199
|
+
*/
|
|
200
|
+
export function runTypes(migrator, args) {
|
|
201
|
+
const output = readOutput(args) ?? './uql-entities.d.ts';
|
|
202
|
+
fs.mkdirSync(path.dirname(output), { recursive: true });
|
|
203
|
+
fs.writeFileSync(output, entityTypesSource(migrator.entities), 'utf-8');
|
|
204
|
+
console.log(`Wrote ${migrator.entities.length} entities to ${output}`);
|
|
205
|
+
}
|
|
206
|
+
/** `--output`/`-o`, wherever a command takes one. */
|
|
207
|
+
function readOutput(args) {
|
|
208
|
+
const at = args.findIndex((arg) => arg === '--output' || arg === '-o');
|
|
209
|
+
return at === -1 ? undefined : args[at + 1];
|
|
210
|
+
}
|
|
192
211
|
export async function runSync(migrator, args, config) {
|
|
193
|
-
if (args.includes('--force')) {
|
|
194
|
-
console.log('\n⚠️ WARNING: This will drop and recreate all tables!');
|
|
195
|
-
console.log(' All data will be lost. This should only be used in development.\n');
|
|
196
|
-
await migrator.sync({ force: true });
|
|
197
|
-
console.log('\nSchema sync completed.');
|
|
198
|
-
return;
|
|
199
|
-
}
|
|
200
212
|
// Pulling the database into entity files is what `generate:from-db` does; one implementation.
|
|
201
213
|
if (args.includes('--pull')) {
|
|
202
214
|
return runGenerateFromDb(migrator, args, config);
|
|
203
215
|
}
|
|
216
|
+
const force = args.includes('--force');
|
|
204
217
|
const safe = !args.includes('--unsafe');
|
|
218
|
+
const options = { force, safe, drop: !safe };
|
|
219
|
+
// Ahead of the warning as well as of the run: `--dry-run` means the same thing whatever else was
|
|
220
|
+
// asked for, and it used to be ignored beside `--force`.
|
|
205
221
|
if (args.includes('--dry-run')) {
|
|
206
|
-
const statements = await migrator.planSync(
|
|
222
|
+
const statements = await migrator.planSync(options);
|
|
207
223
|
console.log(statements.length ? `\n${statements.join('\n')}` : '\nSchema is already in sync.');
|
|
208
224
|
return;
|
|
209
225
|
}
|
|
210
|
-
|
|
226
|
+
if (force) {
|
|
227
|
+
console.log('\n⚠️ WARNING: This will drop and recreate all tables!');
|
|
228
|
+
console.log(' All data will be lost. This should only be used in development.\n');
|
|
229
|
+
}
|
|
230
|
+
await migrator.sync({ ...options, logging: true });
|
|
211
231
|
console.log('\nSchema sync completed.');
|
|
212
232
|
}
|
|
213
233
|
export async function runGenerateFromDb(migrator, args, config) {
|
|
214
|
-
|
|
215
|
-
let outputDir = './src/entities';
|
|
216
|
-
for (let i = 0; i < args.length; i++) {
|
|
217
|
-
if ((args[i] === '--output' || args[i] === '-o') && args[i + 1]) {
|
|
218
|
-
outputDir = args[++i];
|
|
219
|
-
}
|
|
220
|
-
}
|
|
234
|
+
const outputDir = readOutput(args) ?? './src/entities';
|
|
221
235
|
if (!migrator.schemaIntrospector) {
|
|
222
236
|
console.error('No introspector available. Check your pool configuration.');
|
|
223
237
|
process.exit(1);
|
|
@@ -342,6 +356,9 @@ Commands:
|
|
|
342
356
|
--pull Go the other way: generate entities from the database
|
|
343
357
|
--force Drop and recreate all tables (dangerous!)
|
|
344
358
|
|
|
359
|
+
types Write a .d.ts for the registered entities
|
|
360
|
+
--output, -o <file> Output path (default: ./uql-entities.d.ts)
|
|
361
|
+
|
|
345
362
|
drift:check Check for schema drift between entities and database
|
|
346
363
|
|
|
347
364
|
Configuration:
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { Type } from '../../type/index.js';
|
|
2
|
+
/**
|
|
3
|
+
* A `.d.ts` for the entities as registered, so a shape that only exists at runtime reaches the
|
|
4
|
+
* compiler too. Interfaces, not the entity classes `generate:from-db` writes: those are the source of
|
|
5
|
+
* a schema, these describe one already defined elsewhere.
|
|
6
|
+
*/
|
|
7
|
+
export declare function entityTypesSource(entities: readonly Type<unknown>[]): string;
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { getMeta } from '../../entity/index.js';
|
|
2
|
+
import { canonicalToTypeScript } from '../../schema/canonicalType.js';
|
|
3
|
+
import { resolveColumnCanonicalType } from '../../schema/schemaASTBuilder.js';
|
|
4
|
+
import { isToManyRelation, upperFirst } from '../../util/index.js';
|
|
5
|
+
/**
|
|
6
|
+
* A `.d.ts` for the entities as registered, so a shape that only exists at runtime reaches the
|
|
7
|
+
* compiler too. Interfaces, not the entity classes `generate:from-db` writes: those are the source of
|
|
8
|
+
* a schema, these describe one already defined elsewhere.
|
|
9
|
+
*/
|
|
10
|
+
export function entityTypesSource(entities) {
|
|
11
|
+
const metas = [...entities]
|
|
12
|
+
.map((entity) => getMeta(entity))
|
|
13
|
+
.sort((a, b) => a.entity.name.localeCompare(b.entity.name));
|
|
14
|
+
const names = interfaceNames(metas);
|
|
15
|
+
const interfaces = metas.map((meta) => {
|
|
16
|
+
const members = [
|
|
17
|
+
...Object.entries(meta.fields).map(([key, field]) => member(key, fieldType(field))),
|
|
18
|
+
...Object.entries(meta.relations).map(([key, rel]) => member(key, relationType(rel, names))),
|
|
19
|
+
];
|
|
20
|
+
return `export interface ${names.get(meta.entity)} {\n${members.join('\n')}\n}`;
|
|
21
|
+
});
|
|
22
|
+
return ['// Generated by `uql-migrate types`. Do not edit.', '', ...interfaces, ''].join('\n');
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* One interface name per entity, settled before anything is written so a relation and its target
|
|
26
|
+
* agree. A class minted at runtime is named after the content type it came from, which nothing stops
|
|
27
|
+
* from carrying a dash or colliding with another once the dashes are gone - and either would emit a
|
|
28
|
+
* file that does not compile.
|
|
29
|
+
*/
|
|
30
|
+
function interfaceNames(metas) {
|
|
31
|
+
const taken = new Set();
|
|
32
|
+
return new Map(metas.map((meta) => {
|
|
33
|
+
const base = identifier(upperFirst(meta.entity.name));
|
|
34
|
+
let name = base;
|
|
35
|
+
for (let n = 2; taken.has(name); n++) {
|
|
36
|
+
name = `${base}${n}`;
|
|
37
|
+
}
|
|
38
|
+
taken.add(name);
|
|
39
|
+
return [meta.entity, name];
|
|
40
|
+
}));
|
|
41
|
+
}
|
|
42
|
+
/** `text` as an identifier: what cannot be in one is dropped, and what cannot start one is prefixed. */
|
|
43
|
+
function identifier(text) {
|
|
44
|
+
const stripped = text.replace(/[^A-Za-z0-9_$]/g, '');
|
|
45
|
+
return /^[A-Za-z_$]/.test(stripped) ? stripped : `Entity${stripped}`;
|
|
46
|
+
}
|
|
47
|
+
/** A column name a property cannot hold - `hero-image` - is quoted rather than dropped. */
|
|
48
|
+
function member(key, type) {
|
|
49
|
+
const name = key === identifier(key) ? key : JSON.stringify(key);
|
|
50
|
+
return ` ${name}?: ${type};`;
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* The property type a column reads back as, resolved the way the DDL resolves it - so a foreign key
|
|
54
|
+
* reports the type of the key it points at rather than the fallback its own options carry.
|
|
55
|
+
*/
|
|
56
|
+
function fieldType(field) {
|
|
57
|
+
return field ? canonicalToTypeScript(resolveColumnCanonicalType(field)) : 'unknown';
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* A relation is the related interface, a list where the cardinality says so - and `unknown` where the
|
|
61
|
+
* target is outside the set, since naming an interface the file does not declare would not compile.
|
|
62
|
+
*/
|
|
63
|
+
function relationType(relation, names) {
|
|
64
|
+
const target = relation && names.get(relation.entity());
|
|
65
|
+
if (!target) {
|
|
66
|
+
return 'unknown';
|
|
67
|
+
}
|
|
68
|
+
return isToManyRelation(relation) ? `${target}[]` : target;
|
|
69
|
+
}
|
|
@@ -4,4 +4,5 @@
|
|
|
4
4
|
* Generates TypeScript entity code from database schemas.
|
|
5
5
|
*/
|
|
6
6
|
export { createEntityCodeGenerator, EntityCodeGenerator, type EntityCodeGeneratorOptions, type GeneratedEntity, } from './entityCodeGenerator.js';
|
|
7
|
+
export { entityTypesSource } from './entityTypes.js';
|
|
7
8
|
export { buildSqlQuerierMigrationModule, EMPTY_MANUAL_MIGRATION_DOWN_INNER, EMPTY_MANUAL_MIGRATION_UP_INNER, emitSqlRunCall, emitSqlRunCalls, type SqlMigrationModuleOptions, } from './migrationFile.js';
|
|
@@ -5,4 +5,5 @@
|
|
|
5
5
|
*/
|
|
6
6
|
// Entity code generator
|
|
7
7
|
export { createEntityCodeGenerator, EntityCodeGenerator, } from './entityCodeGenerator.js';
|
|
8
|
+
export { entityTypesSource } from './entityTypes.js';
|
|
8
9
|
export { buildSqlQuerierMigrationModule, EMPTY_MANUAL_MIGRATION_DOWN_INNER, EMPTY_MANUAL_MIGRATION_UP_INNER, emitSqlRunCall, emitSqlRunCalls, } from './migrationFile.js';
|
|
@@ -40,8 +40,8 @@ export function tableDefinitionToNode(def) {
|
|
|
40
40
|
columns: fkDef.columns.map((name) => columns.get(name)).filter((c) => c !== undefined),
|
|
41
41
|
},
|
|
42
42
|
to: {
|
|
43
|
-
table: { name: fkDef.
|
|
44
|
-
columns: fkDef.
|
|
43
|
+
table: { name: fkDef.references.table },
|
|
44
|
+
columns: fkDef.references.columns.map((name) => ({ name })),
|
|
45
45
|
},
|
|
46
46
|
onDelete: fkDef.onDelete,
|
|
47
47
|
onUpdate: fkDef.onUpdate,
|
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, TableSchema, } from '../type/index.js';
|
|
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';
|
|
2
2
|
export { type Config, isSqlQuerier } from '../type/index.js';
|
|
3
3
|
export { acquireQuerierForMigrations } from './acquireQuerierForMigrations.js';
|
|
4
4
|
export { assertCliConfig } from './assertCliConfig.js';
|
|
@@ -1,9 +1,6 @@
|
|
|
1
|
+
import type { ForeignKeyAction } from '../../schema/types.js';
|
|
1
2
|
import type { ColumnSchema, ForeignKeySchema, IndexSchema, QuerierPool, RawRow, SchemaIntrospector, SqlQuerier, TableSchema } from '../../type/index.js';
|
|
2
3
|
import { BaseSqlIntrospector } from './baseSqlIntrospector.js';
|
|
3
|
-
/**
|
|
4
|
-
* Referential action type for foreign key constraints.
|
|
5
|
-
*/
|
|
6
|
-
export type ReferentialAction = 'CASCADE' | 'SET NULL' | 'RESTRICT' | 'NO ACTION';
|
|
7
4
|
/**
|
|
8
5
|
* Reads the rows of one statement while introspecting a table.
|
|
9
6
|
*
|
|
@@ -72,7 +69,7 @@ export declare abstract class AbstractSqlSchemaIntrospector extends BaseSqlIntro
|
|
|
72
69
|
/**
|
|
73
70
|
* Normalize referential action string to standard type.
|
|
74
71
|
*/
|
|
75
|
-
protected normalizeReferentialAction(action: string):
|
|
72
|
+
protected normalizeReferentialAction(action: string): ForeignKeyAction | undefined;
|
|
76
73
|
/**
|
|
77
74
|
* Convert bigint/null values to number safely.
|
|
78
75
|
*/
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { canonicalColumnType } from '../../schema/canonicalType.js';
|
|
2
2
|
import { createTableNode, SchemaAST } from '../../schema/schemaAST.js';
|
|
3
3
|
import { escapeSqlId } from '../../util/index.js';
|
|
4
|
+
import { derivedForeignKeyName } from '../../util/sql.util.js';
|
|
4
5
|
/**
|
|
5
6
|
* Base class for SQL introspectors with shared AST building logic.
|
|
6
7
|
*/
|
|
@@ -83,14 +84,14 @@ export class BaseSqlIntrospector {
|
|
|
83
84
|
if (!fromTable)
|
|
84
85
|
continue;
|
|
85
86
|
for (const fk of schema.foreignKeys) {
|
|
86
|
-
const toTable = tableNodes.get(fk.
|
|
87
|
+
const toTable = tableNodes.get(fk.references.table);
|
|
87
88
|
if (!toTable)
|
|
88
89
|
continue;
|
|
89
90
|
const fromColumns = fk.columns.flatMap((name) => fromTable.columns.get(name) ?? []);
|
|
90
|
-
const toColumns = fk.
|
|
91
|
+
const toColumns = fk.references.columns.flatMap((name) => toTable.columns.get(name) ?? []);
|
|
91
92
|
if (fromColumns.length > 0 && toColumns.length > 0) {
|
|
92
93
|
const rel = {
|
|
93
|
-
name: fk.name,
|
|
94
|
+
name: fk.name ?? derivedForeignKeyName(schema.name, fk.columns),
|
|
94
95
|
type: fromColumns[0].isUnique ? 'OneToOne' : 'ManyToOne',
|
|
95
96
|
from: { table: fromTable, columns: fromColumns },
|
|
96
97
|
to: { table: toTable, columns: toColumns },
|
|
@@ -123,8 +123,7 @@ export class MysqlSchemaIntrospector extends AbstractSqlSchemaIntrospector {
|
|
|
123
123
|
return results.map((row) => ({
|
|
124
124
|
name: row.constraint_name,
|
|
125
125
|
columns: (row.columns || '').split(','),
|
|
126
|
-
|
|
127
|
-
referencedColumns: (row.referenced_columns || '').split(','),
|
|
126
|
+
references: { table: row.referenced_table, columns: (row.referenced_columns || '').split(',') },
|
|
128
127
|
onDelete: this.normalizeReferentialAction(row.delete_rule),
|
|
129
128
|
onUpdate: this.normalizeReferentialAction(row.update_rule),
|
|
130
129
|
}));
|
|
@@ -204,8 +204,7 @@ export class PostgresSchemaIntrospector extends AbstractSqlSchemaIntrospector {
|
|
|
204
204
|
return results.map((row) => ({
|
|
205
205
|
name: row.constraint_name,
|
|
206
206
|
columns: row.columns,
|
|
207
|
-
|
|
208
|
-
referencedColumns: row.referenced_columns,
|
|
207
|
+
references: { table: row.referenced_table, columns: row.referenced_columns },
|
|
209
208
|
onDelete: this.normalizeReferentialAction(row.delete_rule),
|
|
210
209
|
onUpdate: this.normalizeReferentialAction(row.update_rule),
|
|
211
210
|
}));
|
|
@@ -113,8 +113,7 @@ export class SqliteSchemaIntrospector extends AbstractSqlSchemaIntrospector {
|
|
|
113
113
|
// derives it. Seeded from the columns, not the PRAGMA's row id, which nothing else knows.
|
|
114
114
|
name: derivedForeignKeyName(tableName, columns),
|
|
115
115
|
columns,
|
|
116
|
-
|
|
117
|
-
referencedColumns: rows.map((r) => r.to),
|
|
116
|
+
references: { table: first.table, columns: rows.map((r) => r.to) },
|
|
118
117
|
onDelete: this.normalizeReferentialAction(first.on_delete),
|
|
119
118
|
onUpdate: this.normalizeReferentialAction(first.on_update),
|
|
120
119
|
};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { DialectName, LoggingOptions, Migration, MigrationDefinition, MigrationResult, MigrationStorage, MigratorOptions, MongoQuerier, Querier, QuerierPool, SchemaDiff, SchemaGenerator, SchemaIntrospector, Type } from '../type/index.js';
|
|
1
|
+
import type { DialectName, LoggingOptions, Migration, MigrationDefinition, MigrationResult, MigrationStorage, MigratorOptions, MongoQuerier, Querier, QuerierPool, SchemaDiff, SchemaGenerator, SchemaIntrospector, SyncOptions, Type } from '../type/index.js';
|
|
2
2
|
import { LoggerWrapper } from '../util/index.js';
|
|
3
3
|
import type { IMigrationBuilder } from './builder/types.js';
|
|
4
4
|
/**
|
|
@@ -88,31 +88,45 @@ export declare class Migrator {
|
|
|
88
88
|
private introspectClaimedSchemas;
|
|
89
89
|
findEntityForTable(tableName: string): Promise<Type<unknown> | undefined>;
|
|
90
90
|
/**
|
|
91
|
-
*
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
/**
|
|
97
|
-
* Drops and recreates all tables (Development only!)
|
|
91
|
+
* Applies the entity schema to the database: every registered entity, or the one `entity` names.
|
|
92
|
+
*
|
|
93
|
+
* The whole surface is this and {@link planSync}, which answers the same question without running
|
|
94
|
+
* it - `force` and a single entity included, so `--dry-run` means the same thing whatever else was
|
|
95
|
+
* asked for.
|
|
98
96
|
*/
|
|
99
|
-
|
|
97
|
+
sync(options?: SyncOptions): Promise<void>;
|
|
100
98
|
/**
|
|
101
|
-
*
|
|
99
|
+
* Every table dropped and recreated.
|
|
100
|
+
*
|
|
101
|
+
* Both directions span the whole entity set rather than looping an entity at a time. A per-entity
|
|
102
|
+
* AST cannot resolve a cross-entity foreign key, so the old create loop silently produced a schema
|
|
103
|
+
* with no referential integrity; and the old drop loop went in reverse *declaration* order, which
|
|
104
|
+
* says nothing about the relation graph and is rejected as soon as the constraints are really there.
|
|
102
105
|
*/
|
|
103
|
-
|
|
104
|
-
safe?: boolean;
|
|
105
|
-
drop?: boolean;
|
|
106
|
-
logging?: boolean;
|
|
107
|
-
}): Promise<void>;
|
|
106
|
+
private forceStatements;
|
|
108
107
|
/**
|
|
109
|
-
*
|
|
108
|
+
* Sync one entity, for a schema that grows while the process runs: a content type an admin just
|
|
109
|
+
* created is one table to add, where the whole set would read the catalogue to work that out.
|
|
110
|
+
*
|
|
111
|
+
* The new-table case costs one existence check and creates with `IF NOT EXISTS`, so instances racing
|
|
112
|
+
* the same admin save settle instead of colliding. An existing table still pays for introspection,
|
|
113
|
+
* since a column diff needs the columns.
|
|
114
|
+
*/
|
|
115
|
+
/** The DDL for one entity: {@link planSync} narrowed to the table it names. */
|
|
116
|
+
private planEntity;
|
|
117
|
+
/** An alter diff as statements, narrowed to what the caller allows. */
|
|
118
|
+
private alterFromDiff;
|
|
119
|
+
/** The same for one entity against the table it already has, and nothing where the two agree. */
|
|
120
|
+
private alterFromEntity;
|
|
121
|
+
/** The configured entities, with `entity` among them however the migrator was built. */
|
|
122
|
+
private entitiesWith;
|
|
123
|
+
/** The introspector for a claimed schema, which is the connection's own where none is claimed. */
|
|
124
|
+
private introspectorFor;
|
|
125
|
+
/**
|
|
126
|
+
* The DDL {@link sync} would run, without running it. Separate so `--dry-run` shows the real
|
|
110
127
|
* statements rather than a summary of a second, differently-computed diff.
|
|
111
128
|
*/
|
|
112
|
-
planSync(options?:
|
|
113
|
-
safe?: boolean;
|
|
114
|
-
drop?: boolean;
|
|
115
|
-
}): Promise<string[]>;
|
|
129
|
+
planSync(options?: SyncOptions): Promise<string[]>;
|
|
116
130
|
/**
|
|
117
131
|
* New tables are emitted together, never one at a time: a single-entity AST has no other table for a
|
|
118
132
|
* relation to resolve against, so every cross-entity foreign key was dropped and generated schemas
|