import { EntityManager , EntityMetadata , EventSubscriber , InsertEvent , RemoveEvent , UpdateEvent , } from 'typeorm' ; import { HistoryActionType , HistoryEntitySubscriberInterface , } from './typeorm-history.interface' ; import { TYPEORM_HISTORY_SNAPSHOT_COLUMN , TYPEORM_HISTORY_MAPPED_COLUMNS , TYPEORM_HISTORY_ACTION_COLUMN , } from './typeorm-history.constants' ; export const createHistorySubscriber = < E , H extends Record < string , any > > ( entity , historyEntity ) => { return new HistoryEntitySubscriber < E , H > ( entity , historyEntity ) ; } ; @ EventSubscriber ( ) export class HistoryEntitySubscriber < E , H extends Record < string , any > > implements HistoryEntitySubscriberInterface < E , H > { constructor ( readonly entity , readonly historyEntity ) { } public beforeInsertHistory ( history ) { return history ; } public afterInsertHistory ( _history ) { } public beforeUpdateHistory ( history ) { return history ; } public afterUpdateHistory ( _history ) { } public beforeRemoveHistory ( history ) { return history ; } public afterRemoveHistory ( _history ) { } public listenTo ( ) { return this . entity ; } public createHistoryEntity ( manager , entity ) { const e = manager . create ( this . entity , entity ) ; const hist = manager . create ( this . historyEntity ) ; const props = Reflect . getMetadata ( TYPEORM_HISTORY_MAPPED_COLUMNS , hist ) || [ ] ; const snapshotProp = Reflect . getMetadata ( TYPEORM_HISTORY_SNAPSHOT_COLUMN , hist ) ; if ( ! snapshotProp ) { throw new Error ( 'No @SnapshotColumn found. Please make sure that your history entity has one.' ) ; } props . forEach ( ( [ prop , mappingFn ] ) => ( ( hist as any ) [ prop ] = mappingFn ( e ) ) ) ; ( hist as any ) [ snapshotProp ] = e ; return hist ; } public async afterInsert ( event ) { await this . createHistory ( event . manager , event . metadata , this . beforeInsertHistory , this . afterInsertHistory , HistoryActionType . Created , event . entity ) ; } public async afterUpdate ( event ) { await this . createHistory ( event . manager , event . metadata , this . beforeUpdateHistory , this . afterUpdateHistory , HistoryActionType . Updated , event . entity as E ) ; } public async beforeRemove ( event ) { await this . createHistory ( event . manager , event . metadata , this . beforeRemoveHistory , this . afterRemoveHistory , HistoryActionType . Deleted , event . entity ) ; } private async createHistory ( manager , metadata , beforeHistoryFunction , afterHistoryFunction , action , entity ? ) { if ( ! entity || Object . keys ( metadata . propertiesMap ) . includes ( 'action' ) ) { return ; } const history = await this . createHistoryEntity ( manager , entity ) ; const actionProp = Reflect . getMetadata ( TYPEORM_HISTORY_ACTION_COLUMN , history ) ; if ( ! actionProp ) { throw new Error ( 'No @HistoryActionColumn found. Please make sure that your history entity has one.' ) ; } ( history as any ) [ actionProp ] = action ; for ( const primaryColumn of metadata . primaryColumns ) { Reflect . deleteProperty ( history , primaryColumn . propertyName ) ; } await beforeHistoryFunction ( history ) ; await manager . save ( history ) ; await afterHistoryFunction ( history ) ; } }