uql-orm 0.21.0 → 0.23.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 +5 -4
- package/dist/browser/uql-browser.min.js.map +3 -3
- package/dist/bunSql/bunSqlCockroachDialect.d.ts +2 -2
- package/dist/bunSql/bunSqlCockroachDialect.js +4 -10
- package/dist/bunSql/bunSqlPostgresDialect.d.ts +2 -2
- package/dist/bunSql/bunSqlPostgresDialect.js +4 -10
- package/dist/cockroachdb/cockroachDialect.d.ts +20 -4
- package/dist/cockroachdb/cockroachDialect.js +33 -18
- package/dist/d1/d1Querier.d.ts +4 -3
- package/dist/d1/d1Querier.js +0 -3
- package/dist/d1/d1SqliteDialect.d.ts +7 -0
- package/dist/d1/d1SqliteDialect.js +9 -0
- package/dist/dialect/abstractDialect.d.ts +8 -3
- package/dist/dialect/abstractDialect.js +9 -4
- package/dist/dialect/abstractSqlDialect.d.ts +49 -8
- package/dist/dialect/abstractSqlDialect.js +95 -47
- package/dist/dialect/index.d.ts +1 -0
- package/dist/dialect/index.js +1 -0
- package/dist/dialect/indexSqlDialect.d.ts +57 -0
- package/dist/dialect/indexSqlDialect.js +101 -0
- package/dist/dialect/mysqlLikeSqlDialect.d.ts +26 -1
- package/dist/dialect/mysqlLikeSqlDialect.js +57 -1
- package/dist/dialect/pgLikeSqlDialect.d.ts +37 -22
- package/dist/dialect/pgLikeSqlDialect.js +97 -68
- package/dist/dialect/vectorCast.d.ts +21 -0
- package/dist/dialect/vectorCast.js +28 -0
- package/dist/dialect/vectorSqlDialect.d.ts +10 -3
- package/dist/dialect/vectorSqlDialect.js +19 -8
- package/dist/entity/decorator/bag.d.ts +35 -0
- package/dist/entity/decorator/bag.js +54 -0
- package/dist/entity/decorator/entity.d.ts +28 -2
- package/dist/entity/decorator/entity.js +40 -2
- package/dist/entity/decorator/members.d.ts +51 -0
- package/dist/entity/decorator/members.js +51 -0
- package/dist/entity/index.d.ts +3 -1
- package/dist/entity/index.js +3 -1
- package/dist/entity/metadata/definition.d.ts +23 -8
- package/dist/entity/metadata/definition.js +56 -100
- package/dist/http/contract.js +1 -2
- package/dist/http/handler.js +5 -26
- package/dist/http/query.js +1 -1
- package/dist/libsql/libsqlDialect.d.ts +12 -2
- package/dist/libsql/libsqlDialect.js +14 -2
- package/dist/libsql/libsqlQuerier.d.ts +9 -22
- package/dist/libsql/libsqlQuerier.js +9 -85
- package/dist/libsql/libsqlQuerierPool.d.ts +10 -8
- package/dist/libsql/libsqlQuerierPool.js +17 -15
- package/dist/maria/mariaDialect.d.ts +26 -4
- package/dist/maria/mariaDialect.js +54 -15
- package/dist/migrate/acquireQuerierForMigrations.d.ts +13 -1
- package/dist/migrate/acquireQuerierForMigrations.js +28 -0
- package/dist/migrate/builder/migrationBuilder.d.ts +9 -29
- package/dist/migrate/builder/migrationBuilder.js +58 -76
- package/dist/migrate/builder/splitSqlStatements.d.ts +0 -2
- package/dist/migrate/builder/splitSqlStatements.js +0 -2
- package/dist/migrate/builder/tableBuilder.d.ts +12 -2
- package/dist/migrate/builder/tableBuilder.js +71 -119
- package/dist/migrate/builder/types.d.ts +30 -41
- package/dist/migrate/cli-config.js +24 -8
- package/dist/migrate/cli.d.ts +3 -2
- package/dist/migrate/cli.js +26 -49
- package/dist/migrate/codegen/entityCodeGenerator.d.ts +0 -4
- package/dist/migrate/codegen/entityCodeGenerator.js +8 -67
- package/dist/migrate/codegen/fieldOptionsSource.d.ts +10 -0
- package/dist/migrate/codegen/fieldOptionsSource.js +55 -0
- package/dist/migrate/codegen/index.d.ts +0 -3
- package/dist/migrate/codegen/index.js +0 -6
- package/dist/migrate/drift/driftDetector.d.ts +10 -1
- package/dist/migrate/drift/driftDetector.js +22 -5
- package/dist/migrate/generator/indexNodeToSchema.d.ts +9 -0
- package/dist/migrate/generator/indexNodeToSchema.js +14 -0
- package/dist/migrate/generator/mongoCommand.d.ts +57 -0
- package/dist/migrate/generator/mongoCommand.js +26 -0
- package/dist/migrate/generator/mongoSchemaGenerator.d.ts +9 -20
- package/dist/migrate/generator/mongoSchemaGenerator.js +40 -82
- package/dist/migrate/index.d.ts +0 -1
- package/dist/migrate/index.js +0 -1
- package/dist/migrate/introspection/abstractSqlSchemaIntrospector.d.ts +30 -11
- package/dist/migrate/introspection/abstractSqlSchemaIntrospector.js +61 -57
- package/dist/migrate/introspection/baseSqlIntrospector.d.ts +0 -1
- package/dist/migrate/introspection/baseSqlIntrospector.js +3 -12
- package/dist/migrate/introspection/mongoIntrospector.js +9 -15
- package/dist/migrate/introspection/mysqlIntrospector.d.ts +5 -8
- package/dist/migrate/introspection/mysqlIntrospector.js +4 -10
- package/dist/migrate/introspection/postgresIntrospector.d.ts +5 -8
- package/dist/migrate/introspection/postgresIntrospector.js +4 -10
- package/dist/migrate/introspection/sqliteIntrospector.d.ts +6 -5
- package/dist/migrate/introspection/sqliteIntrospector.js +26 -18
- package/dist/migrate/migrator.d.ts +23 -3
- package/dist/migrate/migrator.js +101 -150
- package/dist/migrate/schemaGenerator.d.ts +26 -37
- package/dist/migrate/schemaGenerator.js +69 -174
- package/dist/migrate/schemaGeneratorAsync.d.ts +2 -2
- package/dist/migrate/schemaGeneratorAsync.js +3 -3
- package/dist/migrate/storage/databaseStorage.d.ts +2 -0
- package/dist/migrate/storage/databaseStorage.js +12 -27
- package/dist/mongo/mongoDialect.d.ts +2 -0
- package/dist/mongo/mongoDialect.js +14 -3
- package/dist/mongo/mongodbQuerier.js +171 -229
- package/dist/mysql/mysqlDialect.d.ts +8 -0
- package/dist/mysql/mysqlDialect.js +13 -0
- package/dist/nestjs/uqlContextInterceptor.js +58 -22
- package/dist/nestjs/uqlModule.d.ts +2 -11
- package/dist/nestjs/uqlModule.js +93 -44
- package/dist/postgres/postgresDialect.js +2 -2
- package/dist/querier/abstractQuerier.d.ts +28 -0
- package/dist/querier/abstractQuerier.js +47 -22
- package/dist/querier/abstractQuerierPool.d.ts +3 -0
- package/dist/querier/abstractQuerierPool.js +5 -3
- package/dist/querier/abstractSqlQuerier.d.ts +1 -3
- package/dist/querier/abstractSqlQuerier.js +48 -96
- package/dist/querier/index.d.ts +3 -1
- package/dist/querier/index.js +3 -1
- package/dist/querier/querierContext.browser.d.ts +12 -0
- package/dist/querier/querierContext.browser.js +18 -0
- package/dist/querier/querierContext.d.ts +22 -0
- package/dist/querier/querierContext.js +42 -0
- package/dist/querier/queryError.d.ts +22 -0
- package/dist/querier/queryError.js +20 -0
- package/dist/querier/transactional.d.ts +26 -0
- package/dist/querier/transactional.js +43 -0
- package/dist/schema/canonicalType.d.ts +14 -2
- package/dist/schema/canonicalType.js +41 -31
- package/dist/schema/index.d.ts +1 -1
- package/dist/schema/schemaASTBuilder.d.ts +9 -2
- package/dist/schema/schemaASTBuilder.js +58 -49
- package/dist/schema/types.d.ts +10 -58
- package/dist/sqlite/abstractSqliteQuerier.d.ts +46 -0
- package/dist/sqlite/abstractSqliteQuerier.js +44 -0
- package/dist/sqlite/bunSqliteAdapter.bun.d.ts +26 -0
- package/dist/sqlite/bunSqliteAdapter.bun.js +25 -0
- package/dist/sqlite/hranaQuerier.d.ts +54 -0
- package/dist/sqlite/hranaQuerier.js +68 -0
- package/dist/sqlite/hranaQuerierPool.d.ts +21 -0
- package/dist/sqlite/hranaQuerierPool.js +25 -0
- package/dist/sqlite/index.d.ts +3 -1
- package/dist/sqlite/index.js +3 -1
- package/dist/sqlite/localSqliteQuerierPool.d.ts +31 -0
- package/dist/sqlite/localSqliteQuerierPool.js +34 -0
- package/dist/sqlite/nodeSqliteAdapter.d.ts +35 -0
- package/dist/sqlite/nodeSqliteAdapter.js +28 -0
- package/dist/sqlite/nodeSqliteQuerierPool.d.ts +28 -0
- package/dist/sqlite/nodeSqliteQuerierPool.js +29 -0
- package/dist/sqlite/sqliteDialect.d.ts +18 -5
- package/dist/sqlite/sqliteDialect.js +23 -36
- package/dist/sqlite/sqliteQuerier.d.ts +16 -9
- package/dist/sqlite/sqliteQuerier.js +4 -27
- package/dist/sqlite/sqliteQuerierPool.d.ts +11 -14
- package/dist/sqlite/sqliteQuerierPool.js +16 -24
- package/dist/turso/index.d.ts +3 -0
- package/dist/turso/index.js +3 -0
- package/dist/turso/local.d.ts +3 -0
- package/dist/turso/local.js +3 -0
- package/dist/turso/tursoDialect.d.ts +15 -0
- package/dist/turso/tursoDialect.js +18 -0
- package/dist/turso/tursoLocalQuerier.d.ts +25 -0
- package/dist/turso/tursoLocalQuerier.js +20 -0
- package/dist/turso/tursoLocalQuerierPool.d.ts +32 -0
- package/dist/turso/tursoLocalQuerierPool.js +39 -0
- package/dist/turso/tursoQuerier.d.ts +10 -0
- package/dist/turso/tursoQuerier.js +10 -0
- package/dist/turso/tursoQuerierPool.d.ts +39 -0
- package/dist/turso/tursoQuerierPool.js +38 -0
- package/dist/type/config.d.ts +0 -6
- package/dist/type/dialect.d.ts +12 -4
- package/dist/type/dialect.js +7 -1
- package/dist/type/entity.d.ts +154 -26
- package/dist/type/migration.d.ts +32 -23
- package/dist/type/querier.d.ts +6 -0
- package/dist/type/vector.d.ts +5 -2
- package/dist/util/hook.util.js +1 -1
- package/dist/util/index.d.ts +1 -0
- package/dist/util/index.js +1 -0
- package/dist/util/indexColumn.util.d.ts +6 -0
- package/dist/util/indexColumn.util.js +26 -0
- package/package.json +21 -16
- package/dist/entity/decorator/field.d.ts +0 -2
- package/dist/entity/decorator/field.js +0 -7
- package/dist/entity/decorator/filter.d.ts +0 -7
- package/dist/entity/decorator/filter.js +0 -11
- package/dist/entity/decorator/hook.d.ts +0 -7
- package/dist/entity/decorator/hook.js +0 -14
- package/dist/entity/decorator/id.d.ts +0 -2
- package/dist/entity/decorator/id.js +0 -7
- package/dist/entity/decorator/index-decorator.d.ts +0 -29
- package/dist/entity/decorator/index-decorator.js +0 -26
- package/dist/entity/decorator/index.d.ts +0 -8
- package/dist/entity/decorator/index.js +0 -8
- package/dist/entity/decorator/relation.d.ts +0 -8
- package/dist/entity/decorator/relation.js +0 -19
- package/dist/migrate/codegen/entityMerger.d.ts +0 -114
- package/dist/migrate/codegen/entityMerger.js +0 -293
- package/dist/migrate/codegen/migrationCodeGenerator.d.ts +0 -61
- package/dist/migrate/codegen/migrationCodeGenerator.js +0 -355
- package/dist/migrate/codegen/smartRelationDetector.d.ts +0 -47
- package/dist/migrate/codegen/smartRelationDetector.js +0 -134
- package/dist/migrate/generator/index.d.ts +0 -2
- package/dist/migrate/generator/index.js +0 -2
- package/dist/migrate/sync/index.d.ts +0 -6
- package/dist/migrate/sync/index.js +0 -6
- package/dist/migrate/sync/schemaSync.d.ts +0 -131
- package/dist/migrate/sync/schemaSync.js +0 -259
- package/dist/querier/decorator/index.d.ts +0 -4
- package/dist/querier/decorator/index.js +0 -4
- package/dist/querier/decorator/injectQuerier.d.ts +0 -3
- package/dist/querier/decorator/injectQuerier.js +0 -33
- package/dist/querier/decorator/log.d.ts +0 -32
- package/dist/querier/decorator/log.js +0 -52
- package/dist/querier/decorator/serialized.d.ts +0 -6
- package/dist/querier/decorator/serialized.js +0 -13
- package/dist/querier/decorator/transactional.d.ts +0 -6
- package/dist/querier/decorator/transactional.js +0 -48
- package/dist/sqlite/betterSqlite3Dialect.d.ts +0 -9
- package/dist/sqlite/betterSqlite3Dialect.js +0 -9
package/dist/migrate/migrator.js
CHANGED
|
@@ -5,8 +5,9 @@ import { getEntities, getMeta } from '../entity/index.js';
|
|
|
5
5
|
import { introspectSchema } from '../schema/index.js';
|
|
6
6
|
import { isKnownMigratorDialect, isSqlQuerier } from '../type/index.js';
|
|
7
7
|
import { LoggerWrapper } from '../util/index.js';
|
|
8
|
-
import {
|
|
8
|
+
import { withQuerierForMigrations, withSqlQuerierForMigrations } from './acquireQuerierForMigrations.js';
|
|
9
9
|
import { buildSqlQuerierMigrationModule, EMPTY_MANUAL_MIGRATION_DOWN_INNER, EMPTY_MANUAL_MIGRATION_UP_INNER, emitSqlRunCalls, } from './codegen/migrationFile.js';
|
|
10
|
+
import { runMongoCommand } from './generator/mongoCommand.js';
|
|
10
11
|
import { MongoSchemaIntrospector, MysqlSchemaIntrospector, PostgresSchemaIntrospector, SqliteSchemaIntrospector, } from './introspection/index.js';
|
|
11
12
|
import { createSchemaGenerator } from './schemaGenerator.js';
|
|
12
13
|
import { createSchemaGeneratorAsync } from './schemaGeneratorAsync.js';
|
|
@@ -32,12 +33,12 @@ export class Migrator {
|
|
|
32
33
|
dialectName;
|
|
33
34
|
schemaGenerator;
|
|
34
35
|
schemaIntrospector;
|
|
35
|
-
|
|
36
|
+
_defaultForeignKeyAction;
|
|
36
37
|
_mongoSchemaLoadPromise;
|
|
37
38
|
constructor(pool, options = {}) {
|
|
38
39
|
this.pool = pool;
|
|
39
40
|
this.dialectName = pool.dialect.dialectName ?? 'postgres';
|
|
40
|
-
this.
|
|
41
|
+
this._defaultForeignKeyAction = options.defaultForeignKeyAction;
|
|
41
42
|
this.storage =
|
|
42
43
|
options.storage ??
|
|
43
44
|
new DatabaseMigrationStorage(pool, {
|
|
@@ -48,8 +49,7 @@ export class Migrator {
|
|
|
48
49
|
this._entities = options.entities;
|
|
49
50
|
this.schemaIntrospector = this.createIntrospector();
|
|
50
51
|
this.schemaGenerator =
|
|
51
|
-
options.schemaGenerator ??
|
|
52
|
-
(this.dialectName === 'mongodb' ? undefined : this.createGenerator(options.namingStrategy));
|
|
52
|
+
options.schemaGenerator ?? (this.dialectName === 'mongodb' ? undefined : this.createGenerator());
|
|
53
53
|
}
|
|
54
54
|
/** Loads MongoDB schema generator on first use; SQL generators are set in the constructor (or via {@link setSchemaGenerator}). */
|
|
55
55
|
async ensureSchemaGenerator() {
|
|
@@ -57,7 +57,7 @@ export class Migrator {
|
|
|
57
57
|
return;
|
|
58
58
|
}
|
|
59
59
|
if (!this._mongoSchemaLoadPromise) {
|
|
60
|
-
this._mongoSchemaLoadPromise = createSchemaGeneratorAsync(this.pool.dialect, this.
|
|
60
|
+
this._mongoSchemaLoadPromise = createSchemaGeneratorAsync(this.pool.dialect, this._defaultForeignKeyAction).then((gen) => {
|
|
61
61
|
if (gen) {
|
|
62
62
|
this.schemaGenerator = gen;
|
|
63
63
|
}
|
|
@@ -91,11 +91,11 @@ export class Migrator {
|
|
|
91
91
|
return undefined;
|
|
92
92
|
}
|
|
93
93
|
}
|
|
94
|
-
createGenerator(
|
|
94
|
+
createGenerator() {
|
|
95
95
|
if (!isKnownMigratorDialect(this.dialectName)) {
|
|
96
96
|
return undefined;
|
|
97
97
|
}
|
|
98
|
-
return createSchemaGenerator(this.pool.dialect,
|
|
98
|
+
return createSchemaGenerator(this.pool.dialect, this._defaultForeignKeyAction);
|
|
99
99
|
}
|
|
100
100
|
/**
|
|
101
101
|
* Get all discovered migrations from the migrations directory
|
|
@@ -185,49 +185,42 @@ export class Migrator {
|
|
|
185
185
|
*/
|
|
186
186
|
async runMigration(migration, direction) {
|
|
187
187
|
const startTime = Date.now();
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
188
|
+
return withSqlQuerierForMigrations(this.pool, 'Migrator', async (querier) => {
|
|
189
|
+
try {
|
|
190
|
+
this.logger.logMigration(`${direction === 'up' ? 'Running' : 'Reverting'} migration: ${migration.name}`);
|
|
191
|
+
await querier.transaction(async () => {
|
|
192
|
+
if (direction === 'up') {
|
|
193
|
+
await migration.up(querier);
|
|
194
|
+
// Log within the same transaction
|
|
195
|
+
await this.storage.logWithQuerier(querier, migration.name);
|
|
196
|
+
}
|
|
197
|
+
else {
|
|
198
|
+
await migration.down(querier);
|
|
199
|
+
// Unlog within the same transaction
|
|
200
|
+
await this.storage.unlogWithQuerier(querier, migration.name);
|
|
201
|
+
}
|
|
202
|
+
});
|
|
203
|
+
const duration = Date.now() - startTime;
|
|
204
|
+
this.logger.logMigration(`Migration ${migration.name} ${direction === 'up' ? 'applied' : 'reverted'} in ${duration}ms`);
|
|
205
|
+
return {
|
|
206
|
+
name: migration.name,
|
|
207
|
+
direction,
|
|
208
|
+
duration,
|
|
209
|
+
success: true,
|
|
210
|
+
};
|
|
200
211
|
}
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
212
|
+
catch (error) {
|
|
213
|
+
const duration = Date.now() - startTime;
|
|
214
|
+
this.logger.logError(`Migration ${migration.name} failed: ${error.message}`, error);
|
|
215
|
+
return {
|
|
216
|
+
name: migration.name,
|
|
217
|
+
direction,
|
|
218
|
+
duration,
|
|
219
|
+
success: false,
|
|
220
|
+
error: error,
|
|
221
|
+
};
|
|
205
222
|
}
|
|
206
|
-
|
|
207
|
-
const duration = Date.now() - startTime;
|
|
208
|
-
this.logger.logMigration(`Migration ${migration.name} ${direction === 'up' ? 'applied' : 'reverted'} in ${duration}ms`);
|
|
209
|
-
return {
|
|
210
|
-
name: migration.name,
|
|
211
|
-
direction,
|
|
212
|
-
duration,
|
|
213
|
-
success: true,
|
|
214
|
-
};
|
|
215
|
-
}
|
|
216
|
-
catch (error) {
|
|
217
|
-
await querier.rollbackTransaction();
|
|
218
|
-
const duration = Date.now() - startTime;
|
|
219
|
-
this.logger.logError(`Migration ${migration.name} failed: ${error.message}`, error);
|
|
220
|
-
return {
|
|
221
|
-
name: migration.name,
|
|
222
|
-
direction,
|
|
223
|
-
duration,
|
|
224
|
-
success: false,
|
|
225
|
-
error: error,
|
|
226
|
-
};
|
|
227
|
-
}
|
|
228
|
-
finally {
|
|
229
|
-
await querier.release();
|
|
230
|
-
}
|
|
223
|
+
});
|
|
231
224
|
}
|
|
232
225
|
/**
|
|
233
226
|
* Generate a new migration file
|
|
@@ -251,26 +244,18 @@ export class Migrator {
|
|
|
251
244
|
* Generate a migration based on entity schema differences
|
|
252
245
|
*/
|
|
253
246
|
async generateFromEntities(name) {
|
|
254
|
-
await this.ensureSchemaGenerator();
|
|
255
|
-
if (!this.schemaGenerator) {
|
|
256
|
-
throw new Error('Schema generator not set. Call setSchemaGenerator() first.');
|
|
257
|
-
}
|
|
258
|
-
const diffs = await this.getDiffs();
|
|
259
247
|
const upStatements = [];
|
|
260
248
|
const downStatements = [];
|
|
261
|
-
for (const diff of
|
|
249
|
+
for (const { diff, entity } of await this.pendingDiffs()) {
|
|
262
250
|
if (diff.type === 'create') {
|
|
263
|
-
const entity = await this.findEntityForTable(diff.tableName);
|
|
264
251
|
if (entity) {
|
|
265
|
-
upStatements.push(...this.
|
|
266
|
-
downStatements.push(this.
|
|
252
|
+
upStatements.push(...this.generator.generateCreateTable(entity));
|
|
253
|
+
downStatements.push(this.generator.generateDropTable(diff.tableName, { ifExists: true }));
|
|
267
254
|
}
|
|
268
255
|
}
|
|
269
256
|
else if (diff.type === 'alter') {
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
const alterDownStatements = this.schemaGenerator.generateAlterTableDown(diff);
|
|
273
|
-
downStatements.push(...alterDownStatements);
|
|
257
|
+
upStatements.push(...this.generator.generateAlterTable(diff));
|
|
258
|
+
downStatements.push(...this.generator.generateAlterTableDown(diff));
|
|
274
259
|
}
|
|
275
260
|
}
|
|
276
261
|
if (upStatements.length === 0) {
|
|
@@ -342,70 +327,76 @@ export class Migrator {
|
|
|
342
327
|
*/
|
|
343
328
|
async syncForce() {
|
|
344
329
|
await this.ensureSchemaGenerator();
|
|
345
|
-
|
|
346
|
-
throw new Error('Schema generator not set. Call setSchemaGenerator() first.');
|
|
347
|
-
}
|
|
348
|
-
const querier = await acquireQuerierForMigrations(this.pool);
|
|
349
|
-
if (!isSqlQuerier(querier)) {
|
|
350
|
-
await querier.release();
|
|
351
|
-
throw new Error('Migrator requires a SQL-based querier');
|
|
352
|
-
}
|
|
353
|
-
try {
|
|
354
|
-
await querier.beginTransaction();
|
|
330
|
+
await withSqlQuerierForMigrations(this.pool, 'Migrator', (querier) => querier.transaction(async () => {
|
|
355
331
|
// Drop all tables first (in reverse order for foreign keys)
|
|
356
332
|
for (const entity of [...this.entities].reverse()) {
|
|
357
|
-
const
|
|
333
|
+
const tableName = this.generator.resolveTableName(entity, getMeta(entity));
|
|
334
|
+
const dropSql = this.generator.generateDropTable(tableName, { ifExists: true });
|
|
358
335
|
this.logger.logSchema(`Executing: ${dropSql}`);
|
|
359
336
|
await querier.run(dropSql);
|
|
360
337
|
}
|
|
361
338
|
// Create all tables
|
|
362
339
|
for (const entity of this.entities) {
|
|
363
|
-
const createStmts = this.
|
|
340
|
+
const createStmts = this.generator.generateCreateTable(entity);
|
|
364
341
|
for (const createSql of createStmts) {
|
|
365
342
|
this.logger.logSchema(`Executing: ${createSql}`);
|
|
366
343
|
await querier.run(createSql);
|
|
367
344
|
}
|
|
368
345
|
}
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
}
|
|
372
|
-
catch (error) {
|
|
373
|
-
await querier.rollbackTransaction();
|
|
374
|
-
throw error;
|
|
375
|
-
}
|
|
376
|
-
finally {
|
|
377
|
-
await querier.release();
|
|
378
|
-
}
|
|
346
|
+
}));
|
|
347
|
+
this.logger.logSchema('Schema sync (force) completed');
|
|
379
348
|
}
|
|
380
349
|
/**
|
|
381
350
|
* Safely synchronizes the schema by only adding missing tables and columns.
|
|
382
351
|
*/
|
|
383
352
|
async autoSync(options = {}) {
|
|
384
|
-
await this.
|
|
385
|
-
if (
|
|
386
|
-
|
|
353
|
+
const statements = await this.planSync(options);
|
|
354
|
+
if (statements.length === 0) {
|
|
355
|
+
if (options.logging)
|
|
356
|
+
this.logger.logSchema('Schema is already in sync.');
|
|
357
|
+
return;
|
|
387
358
|
}
|
|
388
|
-
|
|
359
|
+
await this.executeSyncStatements(statements, options);
|
|
360
|
+
}
|
|
361
|
+
/**
|
|
362
|
+
* The DDL {@link autoSync} would run, without running it. Separate so `--dry-run` shows the real
|
|
363
|
+
* statements rather than a summary of a second, differently-computed diff.
|
|
364
|
+
*/
|
|
365
|
+
async planSync(options = {}) {
|
|
389
366
|
const statements = [];
|
|
390
|
-
for (const diff of
|
|
367
|
+
for (const { diff, entity } of await this.pendingDiffs()) {
|
|
391
368
|
if (diff.type === 'create') {
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
statements.push(...this.schemaGenerator.generateCreateTable(entity));
|
|
395
|
-
}
|
|
369
|
+
if (entity)
|
|
370
|
+
statements.push(...this.generator.generateCreateTable(entity));
|
|
396
371
|
}
|
|
397
372
|
else if (diff.type === 'alter') {
|
|
398
|
-
|
|
399
|
-
const alterStatements = this.schemaGenerator.generateAlterTable(filteredDiff);
|
|
400
|
-
statements.push(...alterStatements);
|
|
373
|
+
statements.push(...this.generator.generateAlterTable(this.filterDiff(diff, options)));
|
|
401
374
|
}
|
|
402
375
|
}
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
376
|
+
return statements;
|
|
377
|
+
}
|
|
378
|
+
/**
|
|
379
|
+
* Each pending diff with the entity it came from, since resolving that is async and every caller
|
|
380
|
+
* needs it. What to emit stays with the caller: a sync narrows the forward direction to what the
|
|
381
|
+
* caller allows and never asks for the rollback, which on SQLite cannot even be expressed (no
|
|
382
|
+
* `ALTER COLUMN`), so computing it eagerly for everyone would throw there.
|
|
383
|
+
*/
|
|
384
|
+
async pendingDiffs() {
|
|
385
|
+
const diffs = await this.getDiffs();
|
|
386
|
+
return Promise.all(diffs.map(async (diff) => ({
|
|
387
|
+
diff,
|
|
388
|
+
entity: diff.type === 'create' ? await this.findEntityForTable(diff.tableName) : undefined,
|
|
389
|
+
})));
|
|
390
|
+
}
|
|
391
|
+
/**
|
|
392
|
+
* The schema generator. A getter because MongoDB's loads lazily (see {@link ensureSchemaGenerator}),
|
|
393
|
+
* so every caller had to repeat the same assertion after awaiting it.
|
|
394
|
+
*/
|
|
395
|
+
get generator() {
|
|
396
|
+
if (!this.schemaGenerator) {
|
|
397
|
+
throw new Error('Schema generator not set. Call setSchemaGenerator() first.');
|
|
407
398
|
}
|
|
408
|
-
|
|
399
|
+
return this.schemaGenerator;
|
|
409
400
|
}
|
|
410
401
|
filterDiff(diff, options) {
|
|
411
402
|
const filteredDiff = { ...diff };
|
|
@@ -430,69 +421,29 @@ export class Migrator {
|
|
|
430
421
|
return filteredDiff;
|
|
431
422
|
}
|
|
432
423
|
async executeSyncStatements(statements, options) {
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
await this.executeSqlSyncStatements(statements, options, querier);
|
|
440
|
-
}
|
|
441
|
-
if (options.logging)
|
|
442
|
-
this.logger.logSchema('Schema synchronization completed');
|
|
443
|
-
}
|
|
444
|
-
catch (error) {
|
|
445
|
-
if (this.dialectName !== 'mongodb' && isSqlQuerier(querier)) {
|
|
446
|
-
await querier.rollbackTransaction();
|
|
447
|
-
}
|
|
448
|
-
throw error;
|
|
449
|
-
}
|
|
450
|
-
finally {
|
|
451
|
-
await querier.release();
|
|
452
|
-
}
|
|
424
|
+
// Mongo creates collections and indexes outside any transaction, so only the SQL path opens one.
|
|
425
|
+
await withQuerierForMigrations(this.pool, (querier) => this.dialectName === 'mongodb'
|
|
426
|
+
? this.executeMongoSyncStatements(statements, options, querier)
|
|
427
|
+
: querier.transaction(() => this.executeSqlSyncStatements(statements, options, querier)));
|
|
428
|
+
if (options.logging)
|
|
429
|
+
this.logger.logSchema('Schema synchronization completed');
|
|
453
430
|
}
|
|
454
431
|
async executeMongoSyncStatements(statements, options, querier) {
|
|
455
|
-
const
|
|
456
|
-
for (const stmt of statements) {
|
|
457
|
-
const cmd = JSON.parse(stmt);
|
|
432
|
+
for (const statement of statements) {
|
|
458
433
|
if (options.logging)
|
|
459
|
-
this.logger.logSchema(`Executing MongoDB: ${
|
|
460
|
-
|
|
461
|
-
if (!collectionName) {
|
|
462
|
-
throw new Error(`MongoDB command missing collection name: ${stmt}`);
|
|
463
|
-
}
|
|
464
|
-
const collection = db.collection(collectionName);
|
|
465
|
-
if (cmd.action === 'createCollection') {
|
|
466
|
-
await db.createCollection(cmd.name);
|
|
467
|
-
if (cmd.indexes?.length) {
|
|
468
|
-
for (const idx of cmd.indexes) {
|
|
469
|
-
const key = Object.fromEntries(idx.columns.map((c) => [c, 1]));
|
|
470
|
-
await collection.createIndex(key, { unique: idx.unique, name: idx.name });
|
|
471
|
-
}
|
|
472
|
-
}
|
|
473
|
-
}
|
|
474
|
-
else if (cmd.action === 'dropCollection') {
|
|
475
|
-
await collection.drop();
|
|
476
|
-
}
|
|
477
|
-
else if (cmd.action === 'createIndex') {
|
|
478
|
-
await collection.createIndex(cmd.key, cmd.options);
|
|
479
|
-
}
|
|
480
|
-
else if (cmd.action === 'dropIndex') {
|
|
481
|
-
await collection.dropIndex(cmd.name);
|
|
482
|
-
}
|
|
434
|
+
this.logger.logSchema(`Executing MongoDB: ${statement}`);
|
|
435
|
+
await runMongoCommand(querier.db, statement);
|
|
483
436
|
}
|
|
484
437
|
}
|
|
485
438
|
async executeSqlSyncStatements(statements, options, querier) {
|
|
486
439
|
if (!isSqlQuerier(querier)) {
|
|
487
440
|
throw new Error('Migrator requires a SQL-based querier for this dialect');
|
|
488
441
|
}
|
|
489
|
-
await querier.beginTransaction();
|
|
490
442
|
for (const sql of statements) {
|
|
491
443
|
if (options.logging)
|
|
492
444
|
this.logger.logSchema(`Executing: ${sql}`);
|
|
493
445
|
await querier.run(sql);
|
|
494
446
|
}
|
|
495
|
-
await querier.commitTransaction();
|
|
496
447
|
}
|
|
497
448
|
/**
|
|
498
449
|
* Get migration status
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import { type AbstractDialect, AbstractSqlDialect } from '../dialect/index.js';
|
|
2
2
|
import type { CanonicalType, ColumnNode, ForeignKeyAction, IndexNode, TableNode } from '../schema/types.js';
|
|
3
|
-
import type { ColumnSchema, DialectFeatures, EntityMeta, FieldOptions, IndexSchema, NamingStrategy, SchemaDiff,
|
|
3
|
+
import type { ColumnSchema, DialectFeatures, EntityMeta, FieldOptions, IndexSchema, NamingStrategy, SchemaDiff, SqlDdlGenerator, Type } from '../type/index.js';
|
|
4
4
|
import type { FullColumnDefinition, TableDefinition, TableForeignKeyDefinition } from './builder/types.js';
|
|
5
5
|
/**
|
|
6
6
|
* Unified SQL schema generator.
|
|
7
7
|
* Parameterized by dialect to handle Postgres, MySQL, MariaDB, and SQLite.
|
|
8
8
|
*/
|
|
9
|
-
export declare class SqlSchemaGenerator implements
|
|
9
|
+
export declare class SqlSchemaGenerator implements SqlDdlGenerator {
|
|
10
10
|
protected readonly dialect: AbstractSqlDialect;
|
|
11
11
|
protected readonly defaultForeignKeyAction: ForeignKeyAction;
|
|
12
12
|
constructor(dialect: AbstractSqlDialect, defaultForeignKeyAction?: ForeignKeyAction);
|
|
@@ -26,15 +26,14 @@ export declare class SqlSchemaGenerator implements SchemaGenerator {
|
|
|
26
26
|
* Convert FieldOptions to CanonicalType using the unified type system.
|
|
27
27
|
*/
|
|
28
28
|
protected getCanonicalType(field: FieldOptions, fieldType?: unknown): CanonicalType;
|
|
29
|
-
|
|
30
|
-
* Convert CanonicalType to SQL type string for this dialect.
|
|
31
|
-
* Also handles legacy string types for backward compatibility.
|
|
32
|
-
*/
|
|
33
|
-
protected canonicalTypeToSql(type: CanonicalType | string): string;
|
|
29
|
+
protected canonicalTypeToSql(type: CanonicalType): string;
|
|
34
30
|
generateCreateTable<E>(entity: Type<E>, options?: {
|
|
35
31
|
ifNotExists?: boolean;
|
|
36
32
|
}): string[];
|
|
37
|
-
generateDropTable
|
|
33
|
+
generateDropTable(tableName: string, options?: {
|
|
34
|
+
ifExists?: boolean;
|
|
35
|
+
cascade?: boolean;
|
|
36
|
+
}): string;
|
|
38
37
|
generateAlterTable(diff: SchemaDiff): string[];
|
|
39
38
|
generateAlterTableDown(diff: SchemaDiff): string[];
|
|
40
39
|
generateCreateIndex(tableName: string, index: IndexSchema, options?: {
|
|
@@ -42,25 +41,24 @@ export declare class SqlSchemaGenerator implements SchemaGenerator {
|
|
|
42
41
|
}): string;
|
|
43
42
|
generateDropIndex(tableName: string, indexName: string): string;
|
|
44
43
|
/**
|
|
45
|
-
* Generate column definition from a ColumnSchema
|
|
44
|
+
* Generate a column definition from a {@link ColumnSchema}, whose type is the engine's own spelling
|
|
45
|
+
* and may already carry its precision (or even `PRIMARY KEY`, for a serial).
|
|
46
46
|
*/
|
|
47
47
|
generateColumnDefinitionFromSchema(column: ColumnSchema, options?: {
|
|
48
48
|
includePrimaryKey?: boolean;
|
|
49
49
|
includeUnique?: boolean;
|
|
50
50
|
}): string;
|
|
51
|
-
getSqlType(field: FieldOptions, fieldType?: unknown): string;
|
|
52
51
|
/**
|
|
53
|
-
*
|
|
52
|
+
* The one place a column definition is spelled. Both callers reach it - the `ColumnSchema` path above
|
|
53
|
+
* and the `ColumnNode` path below - because the clause order and the "no NOT NULL on a primary key"
|
|
54
|
+
* rules are the same everywhere, and having them written twice is how the two paths drifted.
|
|
54
55
|
*/
|
|
55
|
-
|
|
56
|
+
private renderColumn;
|
|
57
|
+
getSqlType(field: FieldOptions, fieldType?: unknown): string;
|
|
56
58
|
/**
|
|
57
59
|
* Generate ALTER COLUMN statements (database-specific)
|
|
58
60
|
*/
|
|
59
61
|
generateAlterColumnStatements(tableName: string, column: ColumnSchema, newDefinition: string): string[];
|
|
60
|
-
/**
|
|
61
|
-
* Get table options (e.g., ENGINE for MySQL)
|
|
62
|
-
*/
|
|
63
|
-
getTableOptions<E>(_meta: EntityMeta<E>): string;
|
|
64
62
|
/**
|
|
65
63
|
* Generate column comment clause (if supported)
|
|
66
64
|
*/
|
|
@@ -75,7 +73,8 @@ export declare class SqlSchemaGenerator implements SchemaGenerator {
|
|
|
75
73
|
diffSchema<E>(entity: Type<E>, currentTable: TableNode | undefined): SchemaDiff | undefined;
|
|
76
74
|
private columnNodeToSchema;
|
|
77
75
|
/**
|
|
78
|
-
* Convert field options to ColumnSchema
|
|
76
|
+
* Convert field options to ColumnSchema. Both sides of a diff are the engine's SQL spelling: what it
|
|
77
|
+
* would create for this field, against what it reported for the existing column.
|
|
79
78
|
*/
|
|
80
79
|
protected fieldToColumnSchema<E>(fieldKey: string, field: FieldOptions, meta: EntityMeta<E>): ColumnSchema;
|
|
81
80
|
/**
|
|
@@ -83,7 +82,13 @@ export declare class SqlSchemaGenerator implements SchemaGenerator {
|
|
|
83
82
|
*/
|
|
84
83
|
protected columnsNeedAlteration(current: ColumnSchema, desired: ColumnSchema): boolean;
|
|
85
84
|
/**
|
|
86
|
-
*
|
|
85
|
+
* Whether two column types are the same *as this engine stores them*.
|
|
86
|
+
*
|
|
87
|
+
* Both sides are SQL spellings, parsed back to canonical so that `INT` and `INTEGER`, or `DATETIME`
|
|
88
|
+
* and `TIMESTAMP`, do not read as a change. Do not "simplify" this into comparing the entity's
|
|
89
|
+
* canonical type against the column's: several canonical types share one storage type per engine
|
|
90
|
+
* (`boolean` is `TINYINT(1)` on MySQL and `INTEGER` on SQLite), so that comparison reports an
|
|
91
|
+
* alteration for those columns on every single sync.
|
|
87
92
|
*/
|
|
88
93
|
protected isTypeEqual(current: ColumnSchema, desired: ColumnSchema): boolean;
|
|
89
94
|
/**
|
|
@@ -94,14 +99,10 @@ export declare class SqlSchemaGenerator implements SchemaGenerator {
|
|
|
94
99
|
ifNotExists?: boolean;
|
|
95
100
|
}): string[];
|
|
96
101
|
/**
|
|
97
|
-
* Generate a column definition from a ColumnNode.
|
|
102
|
+
* Generate a column definition from a ColumnNode. A composite key is declared as a table constraint,
|
|
103
|
+
* so only a lone primary key column carries `PRIMARY KEY` inline.
|
|
98
104
|
*/
|
|
99
105
|
protected generateColumnFromNode(col: ColumnNode): string;
|
|
100
|
-
/**
|
|
101
|
-
* Generate an inline VECTOR INDEX clause for use inside CREATE TABLE.
|
|
102
|
-
* Syntax: `VECTOR INDEX (col) M=n DISTANCE=metric`
|
|
103
|
-
*/
|
|
104
|
-
private generateInlineVectorIndex;
|
|
105
106
|
/**
|
|
106
107
|
* Generate CREATE INDEX SQL from an IndexNode.
|
|
107
108
|
* Delegates to `generateCreateIndex` for unified SQL assembly.
|
|
@@ -109,26 +110,14 @@ export declare class SqlSchemaGenerator implements SchemaGenerator {
|
|
|
109
110
|
generateCreateIndexFromNode(index: IndexNode, options?: {
|
|
110
111
|
ifNotExists: boolean;
|
|
111
112
|
}): string;
|
|
112
|
-
/**
|
|
113
|
-
* Generate DROP TABLE SQL from a TableNode.
|
|
114
|
-
*/
|
|
115
|
-
generateDropTableFromNode(table: TableNode, options?: {
|
|
116
|
-
ifExists?: boolean;
|
|
117
|
-
}): string;
|
|
118
113
|
generateCreateTableFromDefinition(table: TableDefinition, options?: {
|
|
119
114
|
ifNotExists?: boolean;
|
|
120
115
|
}): string[];
|
|
121
|
-
generateDropTableSql(tableName: string, options?: {
|
|
122
|
-
ifExists?: boolean;
|
|
123
|
-
cascade?: boolean;
|
|
124
|
-
}): string;
|
|
125
116
|
generateRenameTableSql(oldName: string, newName: string): string;
|
|
126
117
|
generateAddColumnSql(tableName: string, column: FullColumnDefinition): string;
|
|
127
118
|
generateAlterColumnSql(tableName: string, columnName: string, column: FullColumnDefinition): string;
|
|
128
119
|
generateDropColumnSql(tableName: string, columnName: string): string;
|
|
129
120
|
generateRenameColumnSql(tableName: string, oldName: string, newName: string): string;
|
|
130
|
-
generateCreateIndexSql(tableName: string, index: IndexSchema): string;
|
|
131
|
-
generateDropIndexSql(tableName: string, indexName: string): string;
|
|
132
121
|
generateAddForeignKeySql(tableName: string, foreignKey: TableForeignKeyDefinition): string;
|
|
133
122
|
generateDropForeignKeySql(tableName: string, constraintName: string): string;
|
|
134
123
|
private tableDefinitionToNode;
|
|
@@ -138,4 +127,4 @@ export declare class SqlSchemaGenerator implements SchemaGenerator {
|
|
|
138
127
|
* Synchronous factory for SQL schema generators only.
|
|
139
128
|
* For MongoDB, use `createSchemaGeneratorAsync` from `./schemaGeneratorAsync.js` so the optional `mongodb` peer is not loaded at import time.
|
|
140
129
|
*/
|
|
141
|
-
export declare function createSchemaGenerator(dialect: AbstractDialect,
|
|
130
|
+
export declare function createSchemaGenerator(dialect: AbstractDialect, defaultForeignKeyAction?: ForeignKeyAction): SqlSchemaGenerator | undefined;
|