import { readFileSync } from 'fs-extra' ; import { join } from 'path' ; import { IMigration , IHistoryActions , IActionData } from '@materia/interfaces' ; import { App } from './app' ; readonly enum { string } export const MigrationType = { CREATE_ENTITY : 'create_entity' , RENAME_ENTITY : 'rename_entity' , DELETE_ENTITY : 'delete_entity' , ADD_FIELD : 'create_field' , CHANGE_FIELD : 'change_field' , DELETE_FIELD : 'delete_field' , ADD_RELATION : 'add_relation' , DELETE_RELATION : 'delete_relation' , ADD_QUERY : 'add_query' , DELETE_QUERY : 'delete_query' , UPDATE_QUERY : 'update_query' , ADD_ENDPOINT : 'add_endpoint' , DELETE_ENDPOINT : 'delete_endpoint' , UPDATE_ENDPOINT : 'update_endpoint' } ; class classdesc export class History { action : any ; diff : Array < IMigration > ; diffRedo : Array < IMigration > ; actions : IHistoryActions ; constructor ( private app ) { this . actions = { } ; this . diff = [ ] ; this . diffRedo = [ ] ; } cleanStacks ( ) { const diff = [ ] ; for ( const d of this . diff ) { diff . push ( { undo : d . undo , redo : d . redo } ) ; } const diff_redo = [ ] ; for ( const d of this . diffRedo ) { diff_redo . push ( { undo : d . undo , redo : d . redo } ) ; } this . diff = diff ; this . diffRedo = diff_redo ; } load ( ) { try { const changes = readFileSync ( join ( this . app . path , 'changes.json' ) ) ; this . diff = JSON . parse ( changes . toString ( ) ) ; } catch ( e ) { this . diff = [ ] ; } } param { object } param { object } push ( redo , undo ) { this . diff . push ( { undo : undo , redo : redo } ) ; this . diffRedo = [ ] ; } param { string } param { function } register ( type , action ) { this . actions [ type ] = action ; } returns { boolean } undoable ( ) { return this . diff . length > 0 ; } returns { boolean } redoable ( ) { return this . diffRedo . length > 0 ; } returns { Array } getUndoStack ( ) { return this . diff ; } returns { Array } getRedoStack ( ) { return this . diffRedo ; } param { object } returns { Promise < object > } undo ( opts ) { opts = opts || { history : false } ; if ( this . diff . length === 0 ) { return Promise . resolve ( { } ) ; } const actionobj = this . diff . pop ( ) ; this . diffRedo . push ( actionobj ) ; const action = this . actions [ actionobj . undo . type ] ; let p ; if ( actionobj . undo . table && ! this . app . entities . get ( actionobj . undo . table ) && actionobj . redo . type != MigrationType . CREATE_ENTITY && actionobj . undo . type != MigrationType . DELETE_ENTITY && actionobj . undo . type != MigrationType . RENAME_ENTITY ) { p = Promise . resolve ( ) ; } else { p = action ( actionobj . undo , opts ) ; } return p . then ( ( ) => { if ( opts . save ) { } return Promise . resolve ( actionobj . undo ) ; } ) . catch ( ( err ) => { if ( opts . save ) { } throw err ; } ) ; } param { object } returns { Promise < object > } redo ( opts ) { opts = opts || { history : false } ; if ( this . diffRedo . length == 0 ) { return Promise . resolve ( { } ) ; } const actionobj = this . diffRedo . pop ( ) ; this . diff . push ( actionobj ) ; const action = this . actions [ actionobj . redo . type ] ; let p ; if ( actionobj . redo . table && ! this . app . entities . get ( actionobj . redo . table ) && actionobj . redo . type != MigrationType . CREATE_ENTITY && actionobj . redo . type != MigrationType . DELETE_ENTITY && actionobj . redo . type != MigrationType . RENAME_ENTITY ) { p = Promise . resolve ( ) ; } else { p = action ( actionobj . redo , opts ) ; } return p . then ( ( ) => { if ( opts . save ) { } return Promise . resolve ( actionobj . redo ) ; } ) . catch ( ( err ) => { if ( opts . save ) { } throw err ; } ) ; } /**
    Clear the history
    */ clear ( ) { this . diff = [ ] ; this . diffRedo = [ ] ; } param { Array < object > } param { object } returns { Promise < Array > } revert ( diffs , opts ) { const diff_redo = this . diffRedo ; const diff_undo = this . diff ; this . diffRedo = [ ] ; this . diff = [ ] ; if ( diffs && diffs . length ) { for ( const diff of diffs ) { this . diff . push ( diff ) ; } } const actions = [ ] ; let p = Promise . resolve ( { type : null } ) ; this . diff . forEach ( ( ) => { p = p . then ( ( action ) => { if ( action . type ) { actions . push ( action ) ; } return this . undo ( opts ) ; } ) ; } ) ; return p . then ( ( action ) => { if ( action . type ) { actions . push ( action ) ; } this . diffRedo = diff_redo ; this . diff = diff_undo ; return Promise . resolve ( actions ) ; } ) . catch ( ( e ) => { console . error ( 'Could not revert' , e . stack ) ; this . diffRedo = diff_redo ; this . diff = diff_undo ; throw e ; } ) ; } param { Array < object > } param { object } returns { Promise < Array > } apply ( diffs , opts ) { const diff_redo = this . diffRedo ; const diff_undo = this . diff ; this . diffRedo = [ ] ; this . diff = [ ] ; if ( diffs && diffs . length ) { for ( const diff of diffs ) { this . diffRedo . unshift ( diff ) ; } } const actions = [ ] ; let p = Promise . resolve ( { type : null , table : null } as IActionData ) ; this . diffRedo . forEach ( ( ) => { p = p . then ( ( action ) => { if ( action . type ) { actions . push ( action ) ; } return this . redo ( opts ) ; } ) ; } ) ; return p . then ( ( action ) => { if ( action . type ) { actions . push ( action ) ; } this . diffRedo = diff_redo ; this . diff = diff_undo ; return Promise . resolve ( actions ) ; } ) . catch ( ( e ) => { this . diffRedo = diff_redo ; this . diff = diff_undo ; throw e ; } ) ; } }