sql-ddl-to-json-schema
Version:
Parse and convert SQL DDL statements to a JSON Schema.
353 lines (352 loc) • 11.4 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.AlterTable = void 0;
const utils_1 = require("../../../../../shared/utils");
const table_options_1 = require("../table-options");
const column_1 = require("../column");
const index_1 = require("../index");
const primary_key_1 = require("../primary-key");
const unique_key_1 = require("../unique-key");
const fulltext_index_1 = require("../fulltext-index");
const spatial_index_1 = require("../spatial-index");
const foreign_key_1 = require("../foreign-key");
const column_options_1 = require("../column-options");
const datatype_1 = require("../datatype");
/**
* Formatter for P_ALTER_TABLE rule's parsed JSON.
*/
class AlterTable {
database;
/**
* Get table with given name.
*
* @param name Table name.
*/
getTable(name) {
return this.database.getTable(name);
}
/**
* Setter for database.
*
* @param database Database instance.
*/
setDatabase(database) {
this.database = database;
}
/**
* Alters one of the tables.
*
* @param json JSON format parsed from SQL.
*/
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];
if ((0, utils_1.isFunction)(fn)) {
fn(def, table);
}
}
else if (tableOptions) {
if (!table.options) {
table.options = new table_options_1.TableOptions();
}
table.options.mergeWith(table_options_1.TableOptions.fromDef(tableOptions));
}
});
return;
}
throw new TypeError(`Expected P_ALTER_TABLE rule to be handled but received ${json.id}`);
}
/**
* Performs action in ALTER TABLE statement.
*
* @param json O_ALTER_TABLE_SPEC def object in JSON.
* @param table Table to be altered.
*/
static addColumn(json, table) {
const column = column_1.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);
}
/**
* Performs action in ALTER TABLE statement.
*
* @param json O_ALTER_TABLE_SPEC def object in JSON.
* @param table Table to be altered.
*/
static addColumns(json, table) {
json.columns.forEach((c) => {
const column = column_1.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);
});
}
/**
* Performs action in ALTER TABLE statement.
*
* @param json O_ALTER_TABLE_SPEC def object in JSON.
* @param table Table to be altered.
*/
static addIndex(json, table) {
const index = index_1.Index.fromObject(json);
table.pushIndex(index);
}
/**
* Performs action in ALTER TABLE statement.
*
* @param json O_ALTER_TABLE_SPEC def object in JSON.
* @param table Table to be altered.
*/
static addPrimaryKey(json, table) {
const key = primary_key_1.PrimaryKey.fromObject(json);
table.setPrimaryKey(key);
}
/**
* Performs action in ALTER TABLE statement.
*
* @param json O_ALTER_TABLE_SPEC def object in JSON.
* @param table Table to be altered.
*/
static addUniqueKey(json, table) {
const key = unique_key_1.UniqueKey.fromObject(json);
table.pushUniqueKey(key);
}
/**
* Performs action in ALTER TABLE statement.
*
* @param json O_ALTER_TABLE_SPEC def object in JSON.
* @param table Table to be altered.
*/
static addFulltextIndex(json, table) {
const index = fulltext_index_1.FulltextIndex.fromObject(json);
table.pushFulltextIndex(index);
}
/**
* Performs action in ALTER TABLE statement.
*
* @param json O_ALTER_TABLE_SPEC def object in JSON.
* @param table Table to be altered.
*/
static addSpatialIndex(json, table) {
const index = spatial_index_1.SpatialIndex.fromObject(json);
table.pushFulltextIndex(index);
}
/**
* Performs action in ALTER TABLE statement.
*
* @param json O_ALTER_TABLE_SPEC def object in JSON.
* @param table Table to be altered.
*/
static addForeignKey(json, table) {
const key = foreign_key_1.ForeignKey.fromObject(json);
table.pushForeignKey(key);
}
/**
* Performs action in ALTER TABLE statement.
*
* @param json O_ALTER_TABLE_SPEC def object in JSON.
* @param table Table to be altered.
*/
static setDefaultColumnValue(json, table) {
const column = table.getColumn(json.column);
if (!(0, utils_1.isDefined)(column) || !(0, utils_1.isDefined)(column.options)) {
return;
}
column.options.default = json.value;
}
/**
* Performs action in ALTER TABLE statement.
*
* @param json O_ALTER_TABLE_SPEC def object in JSON.
* @param table Table to be altered.
*/
static dropDefaultColumnValue(json, table) {
const column = table.getColumn(json.column);
if (!(0, utils_1.isDefined)(column) || !(0, utils_1.isDefined)(column.options)) {
return;
}
delete column.options.default;
}
/**
* Performs action in ALTER TABLE statement.
*
* @param json O_ALTER_TABLE_SPEC def object in JSON.
* @param table Table to be altered.
*/
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_1.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 = column_options_1.ColumnOptions.fromArray(json.columnDefinition);
}
/**
* Stop if anything went wrong parsing new column options.
*/
if (!(0, utils_1.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);
}
}
/**
* Performs action in ALTER TABLE statement.
*
* @param json O_ALTER_TABLE_SPEC def object in JSON.
* @param table Table to be altered.
*/
static dropColumn(json, table) {
const column = table.getColumn(json.column);
if (!column) {
return;
}
table.dropColumn(column);
}
/**
* Performs action in ALTER TABLE statement.
*
* @param json O_ALTER_TABLE_SPEC def object in JSON.
* @param table Table to be altered.
*/
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);
}
/**
* Performs action in ALTER TABLE statement.
*
* @param json O_ALTER_TABLE_SPEC def object in JSON.
* @param table Table to be altered.
*/
static dropPrimaryKey(json, table) {
table.dropPrimaryKey();
}
/**
* Performs action in ALTER TABLE statement.
*
* @param json O_ALTER_TABLE_SPEC def object in JSON.
* @param table Table to be altered.
*/
static dropForeignKey(json, table) {
const foreignKey = table.getForeignKey(json.key);
if (!foreignKey) {
return;
}
table.dropForeignKey(foreignKey);
}
/**
* Performs action in ALTER TABLE statement.
*
* @param json O_ALTER_TABLE_SPEC def object in JSON.
* @param table Table to be altered.
*/
static renameIndex(json, table) {
const index = table.getIndexByName(json.index);
if (!index) {
return;
}
index.name = json.newName;
}
/**
* Performs action in ALTER TABLE statement.
*
* @param json O_ALTER_TABLE_SPEC def object in JSON.
* @param table Table to be altered.
*/
static rename(json, table) {
table.renameTo(json.newName);
}
}
exports.AlterTable = AlterTable;