You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
195 lines
7.3 KiB
195 lines
7.3 KiB
3 years ago
|
'use strict';
|
||
|
|
||
|
const _ = require('lodash');
|
||
|
const Promise = require('../../promise');
|
||
|
const UnknownConstraintError = require('../../errors').UnknownConstraintError;
|
||
|
|
||
|
/**
|
||
|
Returns an object that treats SQLite's inabilities to do certain queries.
|
||
|
|
||
|
@class QueryInterface
|
||
|
@static
|
||
|
@private
|
||
|
*/
|
||
|
|
||
|
/**
|
||
|
A wrapper that fixes SQLite's inability to remove columns from existing tables.
|
||
|
It will create a backup of the table, drop the table afterwards and create a
|
||
|
new table with the same name but without the obsolete column.
|
||
|
|
||
|
@method removeColumn
|
||
|
@for QueryInterface
|
||
|
|
||
|
@param {String} tableName The name of the table.
|
||
|
@param {String} attributeName The name of the attribute that we want to remove.
|
||
|
@param {Object} options
|
||
|
@param {Boolean|Function} [options.logging] A function that logs the sql queries, or false for explicitly not logging these queries
|
||
|
|
||
|
@since 1.6.0
|
||
|
@private
|
||
|
*/
|
||
|
function removeColumn(tableName, attributeName, options) {
|
||
|
options = options || {};
|
||
|
|
||
|
return this.describeTable(tableName, options).then(fields => {
|
||
|
delete fields[attributeName];
|
||
|
|
||
|
const sql = this.QueryGenerator.removeColumnQuery(tableName, fields);
|
||
|
const subQueries = sql.split(';').filter(q => q !== '');
|
||
|
|
||
|
return Promise.each(subQueries, subQuery => this.sequelize.query(subQuery + ';', _.assign({raw: true}, options)));
|
||
|
});
|
||
|
}
|
||
|
exports.removeColumn = removeColumn;
|
||
|
|
||
|
/**
|
||
|
A wrapper that fixes SQLite's inability to change columns from existing tables.
|
||
|
It will create a backup of the table, drop the table afterwards and create a
|
||
|
new table with the same name but with a modified version of the respective column.
|
||
|
|
||
|
@method changeColumn
|
||
|
@for QueryInterface
|
||
|
|
||
|
@param {String} tableName The name of the table.
|
||
|
@param {Object} attributes An object with the attribute's name as key and its options as value object.
|
||
|
@param {Object} options
|
||
|
@param {Boolean|Function} [options.logging] A function that logs the sql queries, or false for explicitly not logging these queries
|
||
|
|
||
|
@since 1.6.0
|
||
|
@private
|
||
|
*/
|
||
|
function changeColumn(tableName, attributes, options) {
|
||
|
const attributeName = Object.keys(attributes)[0];
|
||
|
options = options || {};
|
||
|
|
||
|
return this.describeTable(tableName, options).then(fields => {
|
||
|
fields[attributeName] = attributes[attributeName];
|
||
|
|
||
|
const sql = this.QueryGenerator.removeColumnQuery(tableName, fields);
|
||
|
const subQueries = sql.split(';').filter(q => q !== '');
|
||
|
|
||
|
return Promise.each(subQueries, subQuery => this.sequelize.query(subQuery + ';', _.assign({raw: true}, options)));
|
||
|
});
|
||
|
}
|
||
|
exports.changeColumn = changeColumn;
|
||
|
|
||
|
/**
|
||
|
A wrapper that fixes SQLite's inability to rename columns from existing tables.
|
||
|
It will create a backup of the table, drop the table afterwards and create a
|
||
|
new table with the same name but with a renamed version of the respective column.
|
||
|
|
||
|
@method renameColumn
|
||
|
@for QueryInterface
|
||
|
|
||
|
@param {String} tableName The name of the table.
|
||
|
@param {String} attrNameBefore The name of the attribute before it was renamed.
|
||
|
@param {String} attrNameAfter The name of the attribute after it was renamed.
|
||
|
@param {Object} options
|
||
|
@param {Boolean|Function} [options.logging] A function that logs the sql queries, or false for explicitly not logging these queries
|
||
|
|
||
|
@since 1.6.0
|
||
|
@private
|
||
|
*/
|
||
|
function renameColumn(tableName, attrNameBefore, attrNameAfter, options) {
|
||
|
options = options || {};
|
||
|
|
||
|
return this.describeTable(tableName, options).then(fields => {
|
||
|
fields[attrNameAfter] = _.clone(fields[attrNameBefore]);
|
||
|
delete fields[attrNameBefore];
|
||
|
|
||
|
const sql = this.QueryGenerator.renameColumnQuery(tableName, attrNameBefore, attrNameAfter, fields);
|
||
|
const subQueries = sql.split(';').filter(q => q !== '');
|
||
|
|
||
|
return Promise.each(subQueries, subQuery => this.sequelize.query(subQuery + ';', _.assign({raw: true}, options)));
|
||
|
});
|
||
|
}
|
||
|
exports.renameColumn = renameColumn;
|
||
|
|
||
|
function removeConstraint(tableName, constraintName, options) {
|
||
|
let createTableSql;
|
||
|
|
||
|
return this.showConstraint(tableName, constraintName)
|
||
|
.then(constraints => {
|
||
|
const constraint = constraints[0];
|
||
|
|
||
|
if (constraint) {
|
||
|
createTableSql = constraint.sql;
|
||
|
constraint.constraintName = this.QueryGenerator.quoteIdentifier(constraint.constraintName);
|
||
|
let constraintSnippet = `, CONSTRAINT ${constraint.constraintName} ${constraint.constraintType} ${constraint.constraintCondition}`;
|
||
|
|
||
|
if (constraint.constraintType === 'FOREIGN KEY') {
|
||
|
const referenceTableName = this.QueryGenerator.quoteTable(constraint.referenceTableName);
|
||
|
constraint.referenceTableKeys = constraint.referenceTableKeys.map(columnName => this.QueryGenerator.quoteIdentifier(columnName));
|
||
|
const referenceTableKeys = constraint.referenceTableKeys.join(', ');
|
||
|
constraintSnippet += ` REFERENCES ${referenceTableName} (${referenceTableKeys})`;
|
||
|
constraintSnippet += ` ON UPDATE ${constraint.updateAction}`;
|
||
|
constraintSnippet += ` ON DELETE ${constraint.deleteAction}`;
|
||
|
}
|
||
|
|
||
|
createTableSql = createTableSql.replace(constraintSnippet, '');
|
||
|
createTableSql += ';';
|
||
|
|
||
|
return this.describeTable(tableName, options);
|
||
|
} else {
|
||
|
throw new UnknownConstraintError(`Constraint ${constraintName} on table ${tableName} does not exist`);
|
||
|
}
|
||
|
})
|
||
|
.then(fields => {
|
||
|
const sql = this.QueryGenerator._alterConstraintQuery(tableName, fields, createTableSql);
|
||
|
const subQueries = sql.split(';').filter(q => q !== '');
|
||
|
|
||
|
return Promise.each(subQueries, subQuery => this.sequelize.query(subQuery + ';', _.assign({raw: true}, options)));
|
||
|
});
|
||
|
}
|
||
|
exports.removeConstraint = removeConstraint;
|
||
|
|
||
|
function addConstraint(tableName, options) {
|
||
|
const constraintSnippet = this.QueryGenerator.getConstraintSnippet(tableName, options);
|
||
|
const describeCreateTableSql = this.QueryGenerator.describeCreateTableQuery(tableName);
|
||
|
let createTableSql;
|
||
|
|
||
|
return this.sequelize.query(describeCreateTableSql, options)
|
||
|
.then(constraints => {
|
||
|
const sql = constraints[0].sql;
|
||
|
const index = sql.length - 1;
|
||
|
//Replace ending ')' with constraint snippet - Simulates String.replaceAt
|
||
|
//http://stackoverflow.com/questions/1431094
|
||
|
createTableSql = sql.substr(0, index) + `, ${constraintSnippet})` + sql.substr(index + 1) + ';';
|
||
|
|
||
|
return this.describeTable(tableName, options);
|
||
|
})
|
||
|
.then(fields => {
|
||
|
const sql = this.QueryGenerator._alterConstraintQuery(tableName, fields, createTableSql);
|
||
|
const subQueries = sql.split(';').filter(q => q !== '');
|
||
|
|
||
|
return Promise.each(subQueries, subQuery => this.sequelize.query(subQuery + ';', _.assign({raw: true}, options)));
|
||
|
});
|
||
|
}
|
||
|
exports.addConstraint = addConstraint;
|
||
|
|
||
|
/**
|
||
|
*
|
||
|
* @param {String} tableName
|
||
|
* @param {Object} options Query Options
|
||
|
*
|
||
|
* @private
|
||
|
* @returns {Promise}
|
||
|
*/
|
||
|
function getForeignKeyReferencesForTable(tableName, options) {
|
||
|
const database = this.sequelize.config.database;
|
||
|
const query = this.QueryGenerator.getForeignKeysQuery(tableName, database);
|
||
|
return this.sequelize.query(query, options)
|
||
|
.then(result => {
|
||
|
return result.map(row => ({
|
||
|
tableName,
|
||
|
columnName: row.from,
|
||
|
referencedTableName: row.table,
|
||
|
referencedColumnName: row.to,
|
||
|
tableCatalog: database,
|
||
|
referencedTableCatalog: database
|
||
|
}));
|
||
|
});
|
||
|
}
|
||
|
|
||
|
exports.getForeignKeyReferencesForTable = getForeignKeyReferencesForTable;
|