import { isFunction , isDefined } from '../../../../../shared/utils' ; import { O_ALTER_TABLE_SPEC_ADD_COLUMN , O_ALTER_TABLE_SPEC_ADD_COLUMNS , O_ALTER_TABLE_SPEC_ADD_INDEX , O_ALTER_TABLE_SPEC_ADD_PRIMARY_KEY , O_ALTER_TABLE_SPEC_ADD_UNIQUE_KEY , O_ALTER_TABLE_SPEC_ADD_FULLTEXT_INDEX , O_ALTER_TABLE_SPEC_ADD_SPATIAL_INDEX , O_ALTER_TABLE_SPEC_ADD_FOREIGN_KEY , O_ALTER_TABLE_SPEC_DROP_PRIMARY_KEY , O_ALTER_TABLE_SPEC_SET_DEFAULT_COLUMN_VALUE , O_ALTER_TABLE_SPEC_DROP_DEFAULT_COLUMN_VALUE , O_ALTER_TABLE_SPEC_CHANGE_COLUMN , O_ALTER_TABLE_SPEC_DROP_COLUMN , O_ALTER_TABLE_SPEC_DROP_INDEX , O_ALTER_TABLE_SPEC_DROP_FOREIGN_KEY , O_ALTER_TABLE_SPEC_RENAME_INDEX , O_ALTER_TABLE_SPEC_RENAME , P_ALTER_TABLE , P_ALTER_TABLE_ACTION , O_POSITION , } from '../../../../../typings' ; import { TableOptions } from '../table-options' ; import { Column } from '../column' ; import { Index } from '../index' ; import { PrimaryKey } from '../primary-key' ; import { UniqueKey } from '../unique-key' ; import { FulltextIndex } from '../fulltext-index' ; import { SpatialIndex } from '../spatial-index' ; import { ForeignKey } from '../foreign-key' ; import { ColumnOptions } from '../column-options' ; import { Datatype } from '../datatype' ; import { TableModelInterface , DatabaseModelInterface , RuleHandler } from '../typings' ; /**
 * Formatter for P_ALTER_TABLE rule's parsed JSON.
 */ export class AlterTable implements RuleHandler { database ! : DatabaseModelInterface ; param name getTable ( name ) { return this . database . getTable ( name ) ; } param database setDatabase ( database ) { this . database = database ; } param json handleDef ( json ) { if ( json . id === 'P_ALTER_TABLE' ) { const table = this . getTable ( json . def . table ) ; if ( ! table ) { return ; } /**
             * Runs methods in this class according to the
             * 'action' property of the ALTER TABLE spec.
             */ json . def . specs . forEach ( ( spec ) => { const changeSpec = spec . def . spec ; const tableOptions = spec . def . tableOptions ; if ( changeSpec ) { const def = changeSpec . def ; const action = def . action ; const fn = AlterTable [ action as P_ALTER_TABLE_ACTION ] ; if ( isFunction ( fn ) ) { fn ( def as never , table ) ; } } else if ( tableOptions ) { if ( ! table . options ) { table . options = new TableOptions ( ) ; } table . options . mergeWith ( TableOptions . fromDef ( tableOptions ) ) ; } } ) ; return ; } throw new TypeError ( `Expected P_ALTER_TABLE rule to be handled but received ${ json . id }` ) ; } param json param table private static addColumn ( json , table ) { const column = Column . fromObject ( json ) ; /**
         * Adding columns with REFERENCES should not create FK constraint.
         * https://github.com/duartealexf/sql-ddl-to-json-schema/issues/16
         */ if ( column . reference ) { delete column . reference ; } table . addColumn ( column , json . position ) ; } param json param table private static addColumns ( json , table ) { json . columns . forEach ( ( c ) => { const column = Column . fromObject ( c ) ; /**
             * Adding columns with REFERENCES should not create FK constraint.
             * https://github.com/duartealexf/sql-ddl-to-json-schema/issues/16
             */ if ( column . reference ) { delete column . reference ; } table . addColumn ( column ) ; } ) ; } param json param table private static addIndex ( json , table ) { const index = Index . fromObject ( json ) ; table . pushIndex ( index ) ; } param json param table private static addPrimaryKey ( json , table ) { const key = PrimaryKey . fromObject ( json ) ; table . setPrimaryKey ( key ) ; } param json param table private static addUniqueKey ( json , table ) { const key = UniqueKey . fromObject ( json ) ; table . pushUniqueKey ( key ) ; } param json param table private static addFulltextIndex ( json , table ) { const index = FulltextIndex . fromObject ( json ) ; table . pushFulltextIndex ( index ) ; } param json param table private static addSpatialIndex ( json , table ) { const index = SpatialIndex . fromObject ( json ) ; table . pushFulltextIndex ( index ) ; } param json param table private static addForeignKey ( json , table ) { const key = ForeignKey . fromObject ( json ) ; table . pushForeignKey ( key ) ; } param json param table private static setDefaultColumnValue ( json , table ) { const column = table . getColumn ( json . column ) ; if ( ! isDefined ( column ) || ! isDefined ( column . options ) ) { return ; } column . options . default = json . value ; } param json param table private static dropDefaultColumnValue ( json , table ) { const column = table . getColumn ( json . column ) ; if ( ! isDefined ( column ) || ! isDefined ( column . options ) ) { return ; } delete column . options . default ; } param json param table private static changeColumn ( json , table ) { const column = table . getColumn ( json . column ) ; if ( ! column ) { return ; } let position ; if ( json . position ) { if ( json . position . after ) { if ( ! table . getColumn ( json . position . after ) ) { /**
                     * Referential 'after' column does not exist.
                     */ return ; } } position = json . position ; } else { position = table . getColumnPosition ( column ) ; } const type = Datatype . fromDef ( json . datatype ) ; let options ; /**
         * Alter table change column should not bring old
         * column options, so we completely overwrite it.
         * https://github.com/duartealexf/sql-ddl-to-json-schema/issues/10
         */ if ( json . columnDefinition ) { options = ColumnOptions . fromArray ( json . columnDefinition ) ; } /**
         * Stop if anything went wrong parsing new column options.
         */ if ( ! isDefined ( options ) ) { return ; } /**
         * Alter table does not overwrite primary key.
         * Statements like these in the DBMS are canceled.
         */ if ( options . primary && table . primaryKey ) { return ; } /**
         * Table should have only one column with autoincrement,
         * except when column being modified is already autoincrement.
         * Statements like these in the DBMS are canceled.
         */ if ( options . autoincrement && ( table . columns ?? [ ] ) . some ( ( c ) => c !== column && c . options ?. autoincrement ) ) { return ; } /**
         * If there is an unique option that would
         * create duplicate unique key, remove it.
         */ if ( options . unique && table . uniqueKeys ?. some ( ( uniqueKey ) => uniqueKey . columns . length === 1 && uniqueKey . columns [ 0 ] . column === column . name ) ) { delete options . unique ; } /**
         * Finally change the column.
         */ if ( position && table . moveColumn ( column , position ) ) { /**
             * If there is a new column name in statement, that is different
             * from current name, rename column and references to it.
             */ if ( json . newName && json . newName !== column . name ) { table . renameColumn ( column , json . newName ) ; } column . type = type ; column . options = options ; table . extractColumnKeys ( column ) ; } } param json param table private static dropColumn ( json , table ) { const column = table . getColumn ( json . column ) ; if ( ! column ) { return ; } table . dropColumn ( column ) ; } param json param table private static dropIndex ( json , table ) { if ( json . index . toLowerCase ( ) === 'primary' ) { AlterTable . dropPrimaryKey ( json , table ) ; return ; } const index = table . getIndexByName ( json . index ) ; if ( ! index ) { return ; } table . dropIndexByInstance ( index ) ; } param json param table private static dropPrimaryKey ( json , table ) { table . dropPrimaryKey ( ) ; } param json param table private static dropForeignKey ( json , table ) { const foreignKey = table . getForeignKey ( json . key ) ; if ( ! foreignKey ) { return ; } table . dropForeignKey ( foreignKey ) ; } param json param table private static renameIndex ( json , table ) { const index = table . getIndexByName ( json . index ) ; if ( ! index ) { return ; } index . name = json . newName ; } param json param table private static rename ( json , table ) { table . renameTo ( json . newName ) ; } }