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

@@ -3,9 +3,9 @@ import {QueryResult} from '../types'
import {SQLDialect} from '../dialect/SQLDialect'
import {AppClass} from '../../lifecycle/AppClass'
import {Inject, Injectable} from '../../di'
import {EventBus} from '../../event/EventBus'
import {QueryExecutedEvent} from './event/QueryExecutedEvent'
import {Schema} from '../schema/Schema'
import {Bus} from '../../support/bus'
/**
* Error thrown when a connection is used before it is ready.
@@ -25,7 +25,7 @@ export class ConnectionNotReadyError extends ErrorWithContext {
@Injectable()
export abstract class Connection extends AppClass {
@Inject()
protected bus!: EventBus
protected readonly bus!: Bus
constructor(
/**
@@ -82,6 +82,6 @@ export abstract class Connection extends AppClass {
*/
protected async queryExecuted(query: string): Promise<void> {
const event = new QueryExecutedEvent(this.name, this, query)
await this.bus.dispatch(event)
await this.bus.push(event)
}
}

View File

@@ -1,67 +1,17 @@
import {Event} from '../../../event/Event'
import {Inject, Injectable} from '../../../di'
import {InvalidJSONStateError, JSONState} from '../../../util'
import {Connection} from '../Connection'
import {DatabaseService} from '../../DatabaseService'
import {BaseEvent} from '../../../support/bus'
/**
* Event fired when a query is executed.
*/
@Injectable()
export class QueryExecutedEvent extends Event {
@Inject()
protected database!: DatabaseService
/**
* The name of the connection where the query was executed.
* @protected
*/
public connectionName!: string
/**
* The connection where the query was executed.
*/
public connection!: Connection
/**
* The query that was executed.
*/
public query!: string
export class QueryExecutedEvent extends BaseEvent {
constructor(
connectionName?: string,
connection?: Connection,
query?: string,
public readonly connectionName: string,
public readonly connection: Connection,
public readonly query: string,
) {
super()
if ( connectionName ) {
this.connectionName = connectionName
}
if ( connection ) {
this.connection = connection
}
if ( query ) {
this.query = query
}
}
async dehydrate(): Promise<JSONState> {
return {
connectionName: this.connectionName,
query: this.query,
}
}
rehydrate(state: JSONState): void {
if ( !state.connectionName || !state.query ) {
throw new InvalidJSONStateError('Missing connectionName or query from QueryExecutedEvent state.')
}
this.query = String(state.query)
this.connectionName = String(state.connectionName)
this.connection = this.database.get(this.connectionName)
}
eventName = '@extollo/lib.QueryExecutedEvent'
}

View File

@@ -0,0 +1,38 @@
import {BaseSerializer} from '../../../support/bus'
import {QueryExecutedEvent} from './QueryExecutedEvent'
import {Awaitable, JSONState} from '../../../util'
import {Container, Inject, Injectable} from '../../../di'
import {DatabaseService} from '../../DatabaseService'
import {ObjectSerializer} from '../../../support/bus/serial/decorators'
export interface QueryExecutedEventSerialPayload extends JSONState {
connectionName: string
query: string
}
@ObjectSerializer()
@Injectable()
export class QueryExecutedEventSerializer extends BaseSerializer<QueryExecutedEvent, QueryExecutedEventSerialPayload> {
@Inject()
protected readonly injector!: Container
protected decodeSerial(serial: QueryExecutedEventSerialPayload): Awaitable<QueryExecutedEvent> {
const connection = this.injector.make<DatabaseService>(DatabaseService).get(serial.connectionName)
return new QueryExecutedEvent(serial.connectionName, connection, serial.query)
}
protected encodeActual(actual: QueryExecutedEvent): Awaitable<QueryExecutedEventSerialPayload> {
return {
connectionName: actual.connectionName,
query: actual.query,
}
}
protected getName(): string {
return '@extollo/lib.QueryExecutedEventSerializer'
}
matchActual(some: QueryExecutedEvent): boolean {
return some instanceof QueryExecutedEvent
}
}

View File

@@ -1,13 +1,12 @@
import {Directive, OptionDefinition} from '../../cli'
import {Directive, OptionDefinition, CLIDirective} from '../../cli'
import {Container, Inject, Injectable} from '../../di'
import {EventBus} from '../../event/EventBus'
import {Collection} from '../../util'
import {Bus, EventHandlerSubscription} from '../../support/bus'
import {Migrations} from '../services/Migrations'
import {Migrator} from '../migrations/Migrator'
import {ApplyingMigrationEvent} from '../migrations/events/ApplyingMigrationEvent'
import {AppliedMigrationEvent} from '../migrations/events/AppliedMigrationEvent'
import {EventSubscription} from '../../event/types'
import {NothingToMigrateError} from '../migrations/NothingToMigrateError'
import {CLIDirective} from '../../cli/decorators'
/**
* CLI directive that applies migrations using the default Migrator.
@@ -17,13 +16,13 @@ import {CLIDirective} from '../../cli/decorators'
@CLIDirective()
export class MigrateDirective extends Directive {
@Inject()
protected readonly bus!: EventBus
protected readonly bus!: Bus
@Inject('injector')
protected readonly injector!: Container
/** Event bus subscriptions. */
protected subscriptions: EventSubscription[] = []
protected subscriptions: Collection<EventHandlerSubscription> = new Collection()
getKeywords(): string | string[] {
return ['migrate']
@@ -113,7 +112,6 @@ export class MigrateDirective extends Directive {
/** Remove event bus listeners before finish. */
protected async removeListeners(): Promise<void> {
await Promise.all(this.subscriptions.map(x => x.unsubscribe()))
this.subscriptions = []
await this.subscriptions.awaitMapCall('unsubscribe')
}
}

View File

@@ -1,13 +1,12 @@
import {Directive, OptionDefinition} from '../../cli'
import {Directive, OptionDefinition, CLIDirective} from '../../cli'
import {Container, Inject, Injectable} from '../../di'
import {EventBus} from '../../event/EventBus'
import {Collection} from '../../util'
import {Bus, EventHandlerSubscription} from '../../support/bus'
import {Migrator} from '../migrations/Migrator'
import {Migrations} from '../services/Migrations'
import {RollingBackMigrationEvent} from '../migrations/events/RollingBackMigrationEvent'
import {RolledBackMigrationEvent} from '../migrations/events/RolledBackMigrationEvent'
import {EventSubscription} from '../../event/types'
import {NothingToMigrateError} from '../migrations/NothingToMigrateError'
import {CLIDirective} from '../../cli/decorators'
/**
* CLI directive that undoes applied migrations using the default Migrator.
@@ -17,7 +16,7 @@ import {CLIDirective} from '../../cli/decorators'
@CLIDirective()
export class RollbackDirective extends Directive {
@Inject()
protected readonly bus!: EventBus
protected readonly bus!: Bus
@Inject('injector')
protected readonly injector!: Container
@@ -26,7 +25,7 @@ export class RollbackDirective extends Directive {
protected readonly migrations!: Migrations
/** Event bus subscriptions. */
protected subscriptions: EventSubscription[] = []
protected subscriptions: Collection<EventHandlerSubscription> = new Collection()
getKeywords(): string | string[] {
return ['rollback']
@@ -98,7 +97,6 @@ export class RollbackDirective extends Directive {
/** Remove event bus listeners before finish. */
protected async removeListeners(): Promise<void> {
await Promise.all(this.subscriptions.map(x => x.unsubscribe()))
this.subscriptions = []
await this.subscriptions.awaitMapCall('unsubscribe')
}
}

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'
}

View File

@@ -1,14 +1,12 @@
import {ModelKey, QueryRow, QuerySource} from '../types'
import {Container, Inject, Instantiable, isInstantiable, StaticClass} from '../../di'
import {Container, Inject, Instantiable, isInstantiable} from '../../di'
import {DatabaseService} from '../DatabaseService'
import {ModelBuilder} from './ModelBuilder'
import {getFieldsMeta, ModelField} from './Field'
import {deepCopy, Collection, Awaitable, uuid4, isKeyof, Pipeline} from '../../util'
import {deepCopy, Collection, uuid4, isKeyof, Pipeline} from '../../util'
import {EscapeValueObject} from '../dialect/SQLDialect'
import {AppClass} from '../../lifecycle/AppClass'
import {Logging} from '../../service/Logging'
import {Connection} from '../connection/Connection'
import {Bus, Dispatchable, EventSubscriber, EventSubscriberEntry, EventSubscription} from '../../event/types'
import {ModelRetrievedEvent} from './events/ModelRetrievedEvent'
import {ModelSavingEvent} from './events/ModelSavingEvent'
import {ModelSavedEvent} from './events/ModelSavedEvent'
@@ -16,23 +14,21 @@ import {ModelUpdatingEvent} from './events/ModelUpdatingEvent'
import {ModelUpdatedEvent} from './events/ModelUpdatedEvent'
import {ModelCreatingEvent} from './events/ModelCreatingEvent'
import {ModelCreatedEvent} from './events/ModelCreatedEvent'
import {EventBus} from '../../event/EventBus'
import {Relation, RelationValue} from './relation/Relation'
import {HasOne} from './relation/HasOne'
import {HasMany} from './relation/HasMany'
import {HasOneOrMany} from './relation/HasOneOrMany'
import {Scope, ScopeClosure} from './scope/Scope'
import {LocalBus} from '../../support/bus/LocalBus'
import {ModelEvent} from './events/ModelEvent'
/**
* Base for classes that are mapped to tables in a database.
*/
export abstract class Model<T extends Model<T>> extends AppClass implements Bus {
export abstract class Model<T extends Model<T>> extends LocalBus<ModelEvent<T>> {
@Inject()
protected readonly logging!: Logging
@Inject()
protected readonly bus!: EventBus
/**
* The name of the connection this model should run through.
* @type string
@@ -100,12 +96,6 @@ export abstract class Model<T extends Model<T>> extends AppClass implements Bus
*/
protected originalSourceRow?: QueryRow
/**
* Collection of event subscribers, by their events.
* @protected
*/
protected modelEventBusSubscribers: Collection<EventSubscriberEntry<any>> = new Collection<EventSubscriberEntry<any>>()
/**
* Cache of relation instances by property accessor.
* This is used by the `@Relation()` decorator to cache Relation instances.
@@ -257,7 +247,7 @@ export abstract class Model<T extends Model<T>> extends AppClass implements Bus
this.setFieldFromObject(field.modelKey, field.databaseKey, row)
})
await this.dispatch(new ModelRetrievedEvent<T>(this as any))
await this.push(new ModelRetrievedEvent<T>(this as any))
return this
}
@@ -627,11 +617,11 @@ export abstract class Model<T extends Model<T>> extends AppClass implements Bus
* @param withoutTimestamps
*/
public async save({ withoutTimestamps = false } = {}): Promise<Model<T>> {
await this.dispatch(new ModelSavingEvent<T>(this as any))
await this.push(new ModelSavingEvent<T>(this as any))
const ctor = this.constructor as typeof Model
if ( this.exists() && this.isDirty() ) {
await this.dispatch(new ModelUpdatingEvent<T>(this as any))
await this.push(new ModelUpdatingEvent<T>(this as any))
if ( !withoutTimestamps && ctor.timestamps && ctor.UPDATED_AT ) {
(this as any)[ctor.UPDATED_AT] = new Date()
@@ -652,9 +642,9 @@ export abstract class Model<T extends Model<T>> extends AppClass implements Bus
await this.assumeFromSource(data)
}
await this.dispatch(new ModelUpdatedEvent<T>(this as any))
await this.push(new ModelUpdatedEvent<T>(this as any))
} else if ( !this.exists() ) {
await this.dispatch(new ModelCreatingEvent<T>(this as any))
await this.push(new ModelCreatingEvent<T>(this as any))
if ( !withoutTimestamps ) {
if ( ctor.timestamps && ctor.CREATED_AT ) {
@@ -685,10 +675,10 @@ export abstract class Model<T extends Model<T>> extends AppClass implements Bus
await this.assumeFromSource(data)
}
await this.dispatch(new ModelCreatedEvent<T>(this as any))
await this.push(new ModelCreatedEvent<T>(this as any))
}
await this.dispatch(new ModelSavedEvent<T>(this as any))
await this.push(new ModelSavedEvent<T>(this as any))
return this
}
@@ -825,13 +815,6 @@ export abstract class Model<T extends Model<T>> extends AppClass implements Bus
return !this.is(other)
}
/**
* Creates a new Pipe instance containing this model instance.
*/
public pipe<TOut>(pipeline: Pipeline<this, TOut>): TOut {
return pipeline.apply(this)
}
/**
* Get a wrapped function that compares whether the given model field
* on the current instance differs from the originally fetched value.
@@ -886,46 +869,6 @@ export abstract class Model<T extends Model<T>> extends AppClass implements Bus
(this as any)[thisFieldName] = object[objectFieldName]
}
subscribe<EventT extends Dispatchable>(event: StaticClass<EventT, Instantiable<EventT>>, subscriber: EventSubscriber<EventT>): Awaitable<EventSubscription> {
const entry: EventSubscriberEntry<EventT> = {
id: uuid4(),
event,
subscriber,
}
this.modelEventBusSubscribers.push(entry)
return this.buildSubscription(entry.id)
}
unsubscribe<EventT extends Dispatchable>(subscriber: EventSubscriber<EventT>): Awaitable<void> {
this.modelEventBusSubscribers = this.modelEventBusSubscribers.where('subscriber', '!=', subscriber)
}
async dispatch(event: Dispatchable): Promise<void> {
const eventClass: StaticClass<typeof event, typeof event> = event.constructor as StaticClass<Dispatchable, Dispatchable>
await this.modelEventBusSubscribers.where('event', '=', eventClass)
.promiseMap(entry => entry.subscriber(event))
await this.bus.dispatch(event)
}
/**
* Build an EventSubscription object for the subscriber of the given ID.
* @param id
* @protected
*/
protected buildSubscription(id: string): EventSubscription {
let subscribed = true
return {
unsubscribe: (): Awaitable<void> => {
if ( subscribed ) {
this.modelEventBusSubscribers = this.modelEventBusSubscribers.where('id', '!=', id)
subscribed = false
}
},
}
}
/**
* Create a new one-to-one relation instance. Should be called from a method on the model:
*

View File

@@ -5,5 +5,5 @@ import {ModelEvent} from './ModelEvent'
* Event fired right after a model is inserted.
*/
export class ModelCreatedEvent<T extends Model<T>> extends ModelEvent<T> {
eventName = '@extollo/lib.ModelCreatedEvent'
}

View File

@@ -5,5 +5,5 @@ import {ModelEvent} from './ModelEvent'
* Event fired right before a model is inserted.
*/
export class ModelCreatingEvent<T extends Model<T>> extends ModelEvent<T> {
eventName = '@extollo/lib.ModelCreatingEvent'
}

View File

@@ -5,5 +5,5 @@ import {ModelEvent} from './ModelEvent'
* Event fired right after a model is deleted.
*/
export class ModelDeletedEvent<T extends Model<T>> extends ModelEvent<T> {
eventName = '@extollo/lib.ModelDeletedEvent'
}

View File

@@ -5,5 +5,5 @@ import {ModelEvent} from './ModelEvent'
* Event fired right before a model is deleted.
*/
export class ModelDeletingEvent<T extends Model<T>> extends ModelEvent<T> {
eventName = '@extollo/lib.ModelDeletingEvent'
}

View File

@@ -1,31 +1,19 @@
import {Model} from '../Model'
import {Event} from '../../../event/Event'
import {JSONState} from '../../../util'
import {BaseEvent} from '../../../support/bus'
import {Awaitable} from '../../../util'
/**
* Base class for events that concern an instance of a model.
* @fixme support serialization
*/
export abstract class ModelEvent<T extends Model<T>> extends Event {
/**
* The instance of the model.
*/
public instance!: T
export abstract class ModelEvent<T extends Model<T>> extends BaseEvent {
constructor(
instance?: T,
public readonly instance: T,
) {
super()
if ( instance ) {
this.instance = instance
}
}
// TODO implement serialization here
dehydrate(): Promise<JSONState> {
return Promise.resolve({})
}
rehydrate(/* state: JSONState */): void | Promise<void> {
return undefined
shouldBroadcast(): Awaitable<boolean> {
return false
}
}

View File

@@ -5,5 +5,5 @@ import {ModelEvent} from './ModelEvent'
* Event fired right after a model's data is loaded from the source.
*/
export class ModelRetrievedEvent<T extends Model<T>> extends ModelEvent<T> {
eventName = '@extollo/lib.ModelRetrievedEvent'
}

View File

@@ -5,5 +5,5 @@ import {ModelEvent} from './ModelEvent'
* Event fired right after a model is persisted to the source.
*/
export class ModelSavedEvent<T extends Model<T>> extends ModelEvent<T> {
eventName = '@extollo/lib.ModelSavedEvent'
}

View File

@@ -5,5 +5,5 @@ import {ModelEvent} from './ModelEvent'
* Event fired right before a model is persisted to the source.
*/
export class ModelSavingEvent<T extends Model<T>> extends ModelEvent<T> {
eventName = '@extollo/lib.ModelSavingEvent'
}

View File

@@ -5,5 +5,5 @@ import {ModelEvent} from './ModelEvent'
* Event fired right after a model's data is updated.
*/
export class ModelUpdatedEvent<T extends Model<T>> extends ModelEvent<T> {
eventName = '@extollo/lib.ModelUpdatedEvent'
}

View File

@@ -5,5 +5,5 @@ import {ModelEvent} from './ModelEvent'
* Event fired right before a model's data is updated.
*/
export class ModelUpdatingEvent<T extends Model<T>> extends ModelEvent<T> {
eventName = '@extollo/lib.ModelUpdatingEvent'
}

View File

@@ -94,7 +94,7 @@ export class PostgresSchema extends Schema {
.type(ConstraintType.Unique)
.tap(constraint => {
collect<{column_name: string}>(uniques[key]) // eslint-disable-line camelcase
.pluck<string>('column_name')
.pluck('column_name')
.each(column => constraint.field(column))
})
.flagAsExistingInSchema()
@@ -125,7 +125,7 @@ export class PostgresSchema extends Schema {
}
})
.whereNotIn('column', nonNullable.pluck('column_name'))
.pluck<string>('column')
.pluck('column')
.each(column => {
table.column(column)
.nullable()
@@ -161,7 +161,7 @@ export class PostgresSchema extends Schema {
return builder
.peek(idx => {
collect<{column_name: string}>(groupedIndexes[key]) // eslint-disable-line camelcase
.pluck<string>('column_name')
.pluck('column_name')
.each(col => idx.field(col))
})
.when(groupedIndexes[key]?.[0]?.indisprimary, idx => idx.primary())