AsyncPipe; table schemata; migrations; File logging
All checks were successful
continuous-integration/drone/push Build is passing
All checks were successful
continuous-integration/drone/push Build is passing
This commit is contained in:
117
src/orm/directive/MigrateDirective.ts
Normal file
117
src/orm/directive/MigrateDirective.ts
Normal file
@@ -0,0 +1,117 @@
|
||||
import {Directive, OptionDefinition} from '../../cli'
|
||||
import {Container, Inject, Injectable} from '../../di'
|
||||
import {EventBus} from '../../event/EventBus'
|
||||
import {Migrator} from '../migrations/Migrator'
|
||||
import {Migrations} from '../services/Migrations'
|
||||
import {ApplyingMigrationEvent} from '../migrations/events/ApplyingMigrationEvent'
|
||||
import {AppliedMigrationEvent} from '../migrations/events/AppliedMigrationEvent'
|
||||
import {EventSubscription} from '../../event/types'
|
||||
import {NothingToMigrateError} from '../migrations/NothingToMigrateError'
|
||||
|
||||
/**
|
||||
* CLI directive that applies migrations using the default Migrator.
|
||||
* @fixme Support dry run mode
|
||||
*/
|
||||
@Injectable()
|
||||
export class MigrateDirective extends Directive {
|
||||
@Inject()
|
||||
protected readonly bus!: EventBus
|
||||
|
||||
@Inject('injector')
|
||||
protected readonly injector!: Container
|
||||
|
||||
/** Event bus subscriptions. */
|
||||
protected subscriptions: EventSubscription[] = []
|
||||
|
||||
getKeywords(): string | string[] {
|
||||
return ['migrate']
|
||||
}
|
||||
|
||||
getDescription(): string {
|
||||
return 'apply pending migrations'
|
||||
}
|
||||
|
||||
getOptions(): OptionDefinition[] {
|
||||
return [
|
||||
'--package -p {name} | apply migrations for a specific namespace',
|
||||
'--identifier -i {name} | apply a specific migration, by identifier',
|
||||
]
|
||||
}
|
||||
|
||||
getHelpText(): string {
|
||||
return [
|
||||
'Migrations are single-run code patches used to track changes to things like database schemata.',
|
||||
'',
|
||||
'You can create migrations in your app using the ./ex command and they can be applied and rolled-back.',
|
||||
'',
|
||||
'./ex migrate:create "Add version column to sessions table"',
|
||||
'',
|
||||
'Modules and packages can also register their own migrations. These are run by default.',
|
||||
'',
|
||||
'To run the migrations for a specific package, and no others, use the --package option. Example:',
|
||||
'',
|
||||
'./ex migrate --package @extollo',
|
||||
'',
|
||||
].join('\n')
|
||||
}
|
||||
|
||||
async handle(): Promise<void> {
|
||||
await this.registerListeners()
|
||||
|
||||
const namespace = this.option('package')
|
||||
const identifier = this.option('identifier')
|
||||
|
||||
let identifiers
|
||||
if ( namespace ) {
|
||||
identifiers = (this.injector.make<Migrations>(Migrations))
|
||||
.all(namespace)
|
||||
.map(id => `${namespace}:${id}`)
|
||||
}
|
||||
|
||||
if ( identifier ) {
|
||||
if ( !identifiers ) {
|
||||
identifiers = [identifier]
|
||||
}
|
||||
|
||||
identifiers = identifiers.filter(x => x === identifier)
|
||||
}
|
||||
|
||||
let error
|
||||
try {
|
||||
await (this.injector.make<Migrator>(Migrator)).migrate(identifiers)
|
||||
} catch (e) {
|
||||
if ( e instanceof NothingToMigrateError ) {
|
||||
this.info(e.message)
|
||||
} else {
|
||||
error = e
|
||||
this.error(e)
|
||||
}
|
||||
} finally {
|
||||
await this.removeListeners()
|
||||
}
|
||||
|
||||
if ( error ) {
|
||||
throw error
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Register event bus listeners to print messages for the user.
|
||||
* @protected
|
||||
*/
|
||||
protected async registerListeners(): Promise<void> {
|
||||
this.subscriptions.push(await this.bus.subscribe(ApplyingMigrationEvent, event => {
|
||||
this.info(`Applying migration ${event.migration.identifier}...`)
|
||||
}))
|
||||
|
||||
this.subscriptions.push(await this.bus.subscribe(AppliedMigrationEvent, event => {
|
||||
this.success(`Applied migration: ${event.migration.identifier}`)
|
||||
}))
|
||||
}
|
||||
|
||||
/** Remove event bus listeners before finish. */
|
||||
protected async removeListeners(): Promise<void> {
|
||||
await Promise.all(this.subscriptions.map(x => x.unsubscribe()))
|
||||
this.subscriptions = []
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user