Skip to content

Commit f9abfb7

Browse files
committed
feat(sql): add database when path is provided to migration commands
1 parent be915e8 commit f9abfb7

7 files changed

+68
-10
lines changed

Diff for: packages/core/src/core.ts

+10
Original file line numberDiff line numberDiff line change
@@ -889,3 +889,13 @@ export function assertDefined<T>(value: T): asserts value is NonNullable<T> {
889889
throw new Error(`Value is not defined`);
890890
}
891891
}
892+
893+
export function isEsm(): boolean {
894+
try {
895+
// @ts-ignore
896+
import.meta;
897+
return true;
898+
} catch {
899+
return false;
900+
}
901+
}

Diff for: packages/sql/src/cli/base-command.ts

+5
Original file line numberDiff line numberDiff line change
@@ -5,4 +5,9 @@ export class BaseCommand {
55
* @description Sets the migration directory.
66
*/
77
protected migrationDir: string & Flag = '';
8+
9+
/**
10+
* @description Sets the database path
11+
*/
12+
protected path?: string & Flag;
813
}

Diff for: packages/sql/src/cli/migration-create-command.ts

+1
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ export class MigrationCreateController extends BaseCommand implements Command {
5151
empty: boolean & Flag = false,
5252
): Promise<void> {
5353
if (this.migrationDir) this.provider.setMigrationDir(this.migrationDir);
54+
if (this.path) await this.provider.addDatabase(this.path);
5455

5556
if (!this.provider.databases.getDatabases().length) {
5657
this.logger.error('No databases detected. Use --path path/to/database.ts');

Diff for: packages/sql/src/cli/migration-down-command.ts

+1
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ export class MigrationDownCommand extends BaseCommand {
3838
fake: boolean & Flag = false,
3939
): Promise<void> {
4040
if (this.migrationDir) this.provider.setMigrationDir(this.migrationDir);
41+
if (this.path) await this.provider.addDatabase(this.path);
4142

4243
const migrationsPerDatabase = await this.provider.getMigrationsPerDatabase(database);
4344

Diff for: packages/sql/src/cli/migration-pending-command.ts

+1
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ export class MigrationPendingCommand extends BaseCommand {
3838
database?: string & Flag<{ char: 'db' }>,
3939
): Promise<void> {
4040
if (this.migrationDir) this.provider.setMigrationDir(this.migrationDir);
41+
if (this.path) await this.provider.addDatabase(this.path);
4142

4243
const migrationsPerDatabase = await this.provider.getMigrationsPerDatabase(database);
4344

Diff for: packages/sql/src/cli/migration-up-command.ts

+1
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ export class MigrationUpCommand extends BaseCommand {
4444
all: boolean & Flag = false,
4545
): Promise<void> {
4646
if (this.migrationDir) this.provider.setMigrationDir(this.migrationDir);
47+
if (this.path) await this.provider.addDatabase(this.path);
4748

4849
const migrationsPerDatabase = await this.provider.getMigrationsPerDatabase(database);
4950

Diff for: packages/sql/src/migration/migration-provider.ts

+49-10
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
* You should have received a copy of the MIT License along with this program.
99
*/
1010

11-
import { ClassType } from '@deepkit/core';
11+
import { ClassType, isEsm } from '@deepkit/core';
1212
import { Database, DatabaseRegistry } from '@deepkit/orm';
1313
import glob from 'fast-glob';
1414
import { basename, join } from 'path';
@@ -51,24 +51,63 @@ export class MigrationProvider {
5151
return migrationsPerDatabase;
5252
}
5353

54-
async getMigrations(migrationDir: string): Promise<Migration[]> {
55-
let migrations: Migration[] = [];
56-
57-
const files = await glob('**/*.ts', { cwd: migrationDir });
58-
require('ts-node').register({
54+
private async registerTsNode() {
55+
const esm = isEsm();
56+
const { register } = await import('ts-node');
57+
register({
58+
esm,
5959
compilerOptions: {
6060
experimentalDecorators: true,
61-
module: 'undefined' !== typeof require ? 'CommonJS' : 'ESNext',
61+
module: esm ? 'ESNext' : 'CommonJS',
6262
},
6363
transpileOnly: true,
6464
});
65+
}
66+
67+
async addDatabase(path: string): Promise<void> {
68+
await this.registerTsNode();
69+
70+
const exports = Object.values((await import(path) || {}));
71+
if (!exports.length) {
72+
throw new Error(`No database found in path ${path}`);
73+
}
74+
75+
let databaseInstance: Database | undefined;
76+
let foundDatabaseClass: ClassType<Database> | undefined;
77+
78+
for (const value of exports) {
79+
if (value instanceof Database) {
80+
databaseInstance = value;
81+
break;
82+
}
83+
if (Object.getPrototypeOf(value) instanceof Database) {
84+
foundDatabaseClass = value as ClassType<Database>;
85+
}
86+
}
87+
88+
if (!databaseInstance) {
89+
if (foundDatabaseClass) {
90+
throw new Error(`Found database class ${foundDatabaseClass.name} in path ${path} but it has to be instantiated an exported. export const database = new ${foundDatabaseClass.name}(/* ... */);`);
91+
}
92+
throw new Error(`No database found in path ${path}`);
93+
}
94+
95+
this.databases.addDatabaseInstance(databaseInstance);
96+
}
97+
98+
async getMigrations(migrationDir: string): Promise<Migration[]> {
99+
let migrations: Migration[] = [];
100+
101+
const files = await glob('**/*.ts', { cwd: migrationDir });
102+
103+
await this.registerTsNode();
65104

66105
for (const file of files) {
67106
const path = join(process.cwd(), migrationDir, file);
68107
const name = basename(file.replace('.ts', ''));
69-
const migration = require(path);
70-
if (migration && migration.SchemaMigration) {
71-
const jo = new class extends (migration.SchemaMigration as ClassType<Migration>) {
108+
const { SchemaMigration } = (await import(path) || {});
109+
if (SchemaMigration) {
110+
const jo = new class extends (SchemaMigration as ClassType<Migration>) {
72111
constructor() {
73112
super();
74113
if (!this.name) this.name = name;

0 commit comments

Comments
 (0)