Skip to content

Commit

Permalink
feat(sql): add database when path is provided to migration commands
Browse files Browse the repository at this point in the history
  • Loading branch information
marcus-sa committed Sep 17, 2024
1 parent be915e8 commit 3db084e
Show file tree
Hide file tree
Showing 7 changed files with 69 additions and 10 deletions.
10 changes: 10 additions & 0 deletions packages/core/src/core.ts
Original file line number Diff line number Diff line change
Expand Up @@ -889,3 +889,13 @@ export function assertDefined<T>(value: T): asserts value is NonNullable<T> {
throw new Error(`Value is not defined`);
}
}

export function isEsm(): boolean {
try {
// @ts-ignore
import.meta;
return true;
} catch {
return false;
}
}
5 changes: 5 additions & 0 deletions packages/sql/src/cli/base-command.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,9 @@ export class BaseCommand {
* @description Sets the migration directory.
*/
protected migrationDir: string & Flag = '';

/**
* @description Sets the database path
*/
protected path?: string & Flag;
}
1 change: 1 addition & 0 deletions packages/sql/src/cli/migration-create-command.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ export class MigrationCreateController extends BaseCommand implements Command {
empty: boolean & Flag = false,
): Promise<void> {
if (this.migrationDir) this.provider.setMigrationDir(this.migrationDir);
if (this.path) await this.provider.addDatabase(this.path);

if (!this.provider.databases.getDatabases().length) {
this.logger.error('No databases detected. Use --path path/to/database.ts');
Expand Down
1 change: 1 addition & 0 deletions packages/sql/src/cli/migration-down-command.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ export class MigrationDownCommand extends BaseCommand {
fake: boolean & Flag = false,
): Promise<void> {
if (this.migrationDir) this.provider.setMigrationDir(this.migrationDir);
if (this.path) await this.provider.addDatabase(this.path);

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

Expand Down
1 change: 1 addition & 0 deletions packages/sql/src/cli/migration-pending-command.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ export class MigrationPendingCommand extends BaseCommand {
database?: string & Flag<{ char: 'db' }>,
): Promise<void> {
if (this.migrationDir) this.provider.setMigrationDir(this.migrationDir);
if (this.path) await this.provider.addDatabase(this.path);

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

Expand Down
1 change: 1 addition & 0 deletions packages/sql/src/cli/migration-up-command.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ export class MigrationUpCommand extends BaseCommand {
all: boolean & Flag = false,
): Promise<void> {
if (this.migrationDir) this.provider.setMigrationDir(this.migrationDir);
if (this.path) await this.provider.addDatabase(this.path);

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

Expand Down
60 changes: 50 additions & 10 deletions packages/sql/src/migration/migration-provider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
* You should have received a copy of the MIT License along with this program.
*/

import { ClassType } from '@deepkit/core';
import { ClassType, isEsm } from '@deepkit/core';
import { Database, DatabaseRegistry } from '@deepkit/orm';
import glob from 'fast-glob';
import { basename, join } from 'path';
Expand Down Expand Up @@ -51,24 +51,64 @@ export class MigrationProvider {
return migrationsPerDatabase;
}

async getMigrations(migrationDir: string): Promise<Migration[]> {
let migrations: Migration[] = [];

const files = await glob('**/*.ts', { cwd: migrationDir });
require('ts-node').register({
private async registerTsNode() {
const esm = isEsm();
const { register } = await import('ts-node');
register({
esm,
compilerOptions: {
experimentalDecorators: true,
module: 'undefined' !== typeof require ? 'CommonJS' : 'ESNext',
module: esm ? 'ESNext' : 'CommonJS',
},
transpileOnly: true,
});
}

async addDatabase(path: string): Promise<void> {
await this.registerTsNode();

const exports = Object.values((await import(path) || {}));
if (!exports.length) {
throw new Error(`No database found in path ${path}`);
}

let databaseInstance: Database | undefined;
let foundDatabaseClass: ClassType<Database> | undefined;

for (const value of exports) {
if (typeof value !== 'object' || value == null) continue;
if (value instanceof Database) {
databaseInstance = value;
break;
}
if ('prototype' in value && value.prototype instanceof Database) {
foundDatabaseClass = value as ClassType<Database>;
}
}

if (!databaseInstance) {
if (foundDatabaseClass) {
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}(/* ... */);`);
}
throw new Error(`No database found in path ${path}`);
}

this.databases.addDatabaseInstance(databaseInstance);
}

async getMigrations(migrationDir: string): Promise<Migration[]> {
let migrations: Migration[] = [];

const files = await glob('**/*.ts', { cwd: migrationDir });

await this.registerTsNode();

for (const file of files) {
const path = join(process.cwd(), migrationDir, file);
const name = basename(file.replace('.ts', ''));
const migration = require(path);
if (migration && migration.SchemaMigration) {
const jo = new class extends (migration.SchemaMigration as ClassType<Migration>) {
const { SchemaMigration } = (await import(path) || {});
if (SchemaMigration) {
const jo = new class extends (SchemaMigration as ClassType<Migration>) {
constructor() {
super();
if (!this.name) this.name = name;
Expand Down

0 comments on commit 3db084e

Please sign in to comment.