Refactor event bus and queue system; detect cycles in DI realization and make
Some checks failed
continuous-integration/drone/push Build is failing

This commit is contained in:
2022-01-26 19:37:54 -06:00
parent 506fb55c74
commit 6d1cf18680
69 changed files with 1673 additions and 720 deletions

View File

@@ -2,12 +2,12 @@ import {Container, Inject, Injectable} from '../../di'
import {Awaitable, collect, ErrorWithContext} from '../../util'
import {Migration} from './Migration'
import {Migrations} from '../services/Migrations'
import {EventBus} from '../../event/EventBus'
import {ApplyingMigrationEvent} from './events/ApplyingMigrationEvent'
import {AppliedMigrationEvent} from './events/AppliedMigrationEvent'
import {RollingBackMigrationEvent} from './events/RollingBackMigrationEvent'
import {RolledBackMigrationEvent} from './events/RolledBackMigrationEvent'
import {NothingToMigrateError} from './NothingToMigrateError'
import {Bus} from '../../support/bus'
/**
* Manages single-run patches/migrations.
@@ -18,7 +18,7 @@ export abstract class Migrator {
protected readonly migrations!: Migrations
@Inject()
protected readonly bus!: EventBus
protected readonly bus!: Bus
@Inject('injector')
protected readonly injector!: Container
@@ -193,31 +193,11 @@ export abstract class Migrator {
* @protected
*/
protected async filterAppliedMigrations(identifiers: string[]): Promise<string[]> {
return collect(identifiers)
.partialMap(identifier => {
const migration = this.migrations.get(identifier)
if ( migration ) {
return {
identifier,
migration,
}
}
})
.asyncPipe()
.tap(coll => {
return coll.promiseMap(async group => {
return {
...group,
has: await this.has(group.migration),
}
})
})
.tap(coll => {
return coll.filter(group => !group.has)
.pluck<string>('identifier')
.all()
})
.resolve()
const ids = await collect(identifiers)
.toAsync()
.filterOut(async id => this.has(this.migrations.getOrFail(id)))
return ids.all()
}
/**
@@ -226,31 +206,11 @@ export abstract class Migrator {
* @protected
*/
protected async filterPendingMigrations(identifiers: string[]): Promise<string[]> {
return collect(identifiers)
.partialMap(identifier => {
const migration = this.migrations.get(identifier)
if ( migration ) {
return {
identifier,
migration,
}
}
})
.asyncPipe()
.tap(coll => {
return coll.promiseMap(async group => {
return {
...group,
has: await this.has(group.migration),
}
})
})
.tap(coll => {
return coll.filter(group => group.has)
.pluck<string>('identifier')
.all()
})
.resolve()
const ids = await collect(identifiers)
.toAsync()
.filter(async id => this.has(this.migrations.getOrFail(id)))
return ids.all()
}
/**
@@ -260,7 +220,7 @@ export abstract class Migrator {
*/
protected async applying(migration: Migration): Promise<void> {
const event = <ApplyingMigrationEvent> this.injector.make(ApplyingMigrationEvent, migration)
await this.bus.dispatch(event)
await this.bus.push(event)
}
/**
@@ -270,7 +230,7 @@ export abstract class Migrator {
*/
protected async applied(migration: Migration): Promise<void> {
const event = <AppliedMigrationEvent> this.injector.make(AppliedMigrationEvent, migration)
await this.bus.dispatch(event)
await this.bus.push(event)
}
/**
@@ -280,7 +240,7 @@ export abstract class Migrator {
*/
protected async rollingBack(migration: Migration): Promise<void> {
const event = <RollingBackMigrationEvent> this.injector.make(RollingBackMigrationEvent, migration)
await this.bus.dispatch(event)
await this.bus.push(event)
}
/**
@@ -290,6 +250,6 @@ export abstract class Migrator {
*/
protected async rolledBack(migration: Migration): Promise<void> {
const event = <RolledBackMigrationEvent> this.injector.make(RolledBackMigrationEvent, migration)
await this.bus.dispatch(event)
await this.bus.push(event)
}
}

View File

@@ -5,4 +5,6 @@ import {MigrationEvent} from './MigrationEvent'
* Event fired after a migration is applied.
*/
@Injectable()
export class AppliedMigrationEvent extends MigrationEvent {}
export class AppliedMigrationEvent extends MigrationEvent {
eventName = '@extollo/lib.AppliedMigrationEvent'
}

View File

@@ -5,4 +5,6 @@ import {MigrationEvent} from './MigrationEvent'
* Event fired before a migration is applied.
*/
@Injectable()
export class ApplyingMigrationEvent extends MigrationEvent {}
export class ApplyingMigrationEvent extends MigrationEvent {
eventName = '@extollo/lib.ApplyingMigrationEvent'
}

View File

@@ -1,49 +1,13 @@
import {Event} from '../../../event/Event'
import {Migration} from '../Migration'
import {Inject, Injectable} from '../../../di'
import {Migrations} from '../../services/Migrations'
import {ErrorWithContext} from '../../../util'
import {BaseEvent} from '../../../support/bus'
/**
* Generic base-class for migration-related events.
*/
@Injectable()
export abstract class MigrationEvent extends Event {
@Inject()
protected readonly migrations!: Migrations
/** The migration relevant to this event. */
private internalMigration: Migration
/**
* Get the relevant migration.
*/
public get migration(): Migration {
return this.internalMigration
}
export abstract class MigrationEvent extends BaseEvent {
constructor(
migration: Migration,
public readonly migration: Migration,
) {
super()
this.internalMigration = migration
}
dehydrate(): {identifier: string} {
return {
identifier: this.migration.identifier,
}
}
rehydrate(state: {identifier: string}): void {
const migration = this.migrations.get(state.identifier)
if ( !migration ) {
throw new ErrorWithContext(`Unable to find migration with identifier: ${state.identifier}`, {
identifier: state.identifier,
})
}
this.internalMigration = migration
}
}

View File

@@ -0,0 +1,59 @@
import {BaseSerializer} from '../../../support/bus'
import {ObjectSerializer} from '../../../support/bus/serial/decorators'
import {Injectable, Instantiable} from '../../../di'
import {Awaitable, ErrorWithContext, JSONState} from '../../../util'
import {MigrationEvent} from './MigrationEvent'
import {Migrations} from '../../services/Migrations'
import {AppliedMigrationEvent} from './AppliedMigrationEvent'
import {ApplyingMigrationEvent} from './ApplyingMigrationEvent'
import {RolledBackMigrationEvent} from './RolledBackMigrationEvent'
import {RollingBackMigrationEvent} from './RollingBackMigrationEvent'
export interface MigrationEventSerialPayload extends JSONState {
identifier: string
eventType: string
}
@ObjectSerializer()
@Injectable()
export class MigrationEventSerializer extends BaseSerializer<MigrationEvent, MigrationEventSerialPayload> {
protected decodeSerial(serial: MigrationEventSerialPayload): Awaitable<MigrationEvent> {
const migration = this.make<Migrations>(Migrations).get(serial.identifier)
if ( !migration ) {
throw new ErrorWithContext(`Invalid serialized migration identifier: ${serial.identifier}`)
}
return (new (this.stringToEvent(serial.eventType))(migration))
}
protected encodeActual(actual: MigrationEvent): Awaitable<MigrationEventSerialPayload> {
return {
identifier: actual.migration.identifier,
eventType: actual.eventName,
}
}
protected getName(): string {
return '@extollo/lib.MigrationEventSerializer'
}
matchActual(some: MigrationEvent): boolean {
return some instanceof MigrationEvent
}
private stringToEvent(name: string): Instantiable<MigrationEvent> {
if ( name === '@extollo/lib.AppliedMigrationEvent' ) {
return AppliedMigrationEvent
} else if ( name === '@extollo/lib.ApplyingMigrationEvent' ) {
return ApplyingMigrationEvent
} else if ( name === '@extollo/lib.RollingBackMigrationEvent' ) {
return RollingBackMigrationEvent
} else if ( name === '@extollo/lib.RolledBackMigrationEvent' ) {
return RolledBackMigrationEvent
}
throw new ErrorWithContext(`Invalid migration event name: ${name}`, {
name,
})
}
}

View File

@@ -5,4 +5,6 @@ import {MigrationEvent} from './MigrationEvent'
* Event fired after a migration has been rolled-back.
*/
@Injectable()
export class RolledBackMigrationEvent extends MigrationEvent {}
export class RolledBackMigrationEvent extends MigrationEvent {
eventName = '@extollo/lib.RolledBackMigrationEvent'
}

View File

@@ -5,4 +5,6 @@ import {MigrationEvent} from './MigrationEvent'
* Event fired before a migration is rolled back.
*/
@Injectable()
export class RollingBackMigrationEvent extends MigrationEvent {}
export class RollingBackMigrationEvent extends MigrationEvent {
eventName = '@extollo/lib.RollingBackMigrationEvent'
}