933 lines
31 KiB
JavaScript
933 lines
31 KiB
JavaScript
|
|
'use strict';
|
||
|
|
|
||
|
|
var Utils = require('./utils')
|
||
|
|
, _ = require('lodash')
|
||
|
|
, DataTypes = require('./data-types')
|
||
|
|
, SQLiteQueryInterface = require('./dialects/sqlite/query-interface')
|
||
|
|
, Transaction = require('./transaction')
|
||
|
|
, Promise = require('./promise')
|
||
|
|
, QueryTypes = require('./query-types');
|
||
|
|
|
||
|
|
/*
|
||
|
|
* The interface that Sequelize uses to talk to all databases
|
||
|
|
* @class QueryInterface
|
||
|
|
**/
|
||
|
|
var QueryInterface = function(sequelize) {
|
||
|
|
this.sequelize = sequelize;
|
||
|
|
this.QueryGenerator = this.sequelize.dialect.QueryGenerator;
|
||
|
|
};
|
||
|
|
|
||
|
|
QueryInterface.prototype.createSchema = function(schema, options) {
|
||
|
|
options = options || {};
|
||
|
|
var sql = this.QueryGenerator.createSchema(schema);
|
||
|
|
return this.sequelize.query(sql, {logging: options.logging});
|
||
|
|
};
|
||
|
|
|
||
|
|
QueryInterface.prototype.dropSchema = function(schema, options) {
|
||
|
|
options = options || {};
|
||
|
|
var sql = this.QueryGenerator.dropSchema(schema);
|
||
|
|
return this.sequelize.query(sql, {logging: options.logging});
|
||
|
|
};
|
||
|
|
|
||
|
|
QueryInterface.prototype.dropAllSchemas = function(options) {
|
||
|
|
options = options || {};
|
||
|
|
|
||
|
|
var self = this;
|
||
|
|
if (!this.QueryGenerator._dialect.supports.schemas) {
|
||
|
|
return this.sequelize.drop({ logging: options.logging });
|
||
|
|
} else {
|
||
|
|
return this.showAllSchemas(options).map(function(schemaName) {
|
||
|
|
return self.dropSchema(schemaName, { logging: options.logging });
|
||
|
|
});
|
||
|
|
}
|
||
|
|
};
|
||
|
|
|
||
|
|
QueryInterface.prototype.showAllSchemas = function(options) {
|
||
|
|
var self = this;
|
||
|
|
|
||
|
|
options = Utils._.extend({
|
||
|
|
raw: true,
|
||
|
|
type: this.sequelize.QueryTypes.SELECT,
|
||
|
|
logging: false
|
||
|
|
}, options || {});
|
||
|
|
|
||
|
|
var showSchemasSql = self.QueryGenerator.showSchemasQuery();
|
||
|
|
|
||
|
|
return this.sequelize.query(showSchemasSql, options).then(function(schemaNames) {
|
||
|
|
return Utils._.flatten(
|
||
|
|
Utils._.map(schemaNames, function(value) {
|
||
|
|
return (!!value.schema_name ? value.schema_name : value);
|
||
|
|
})
|
||
|
|
);
|
||
|
|
});
|
||
|
|
};
|
||
|
|
|
||
|
|
QueryInterface.prototype.databaseVersion = function(options) {
|
||
|
|
options = options || {};
|
||
|
|
return this.sequelize.query(this.QueryGenerator.versionQuery(), {
|
||
|
|
raw: true,
|
||
|
|
type: QueryTypes.VERSION,
|
||
|
|
logging: options.logging
|
||
|
|
});
|
||
|
|
};
|
||
|
|
|
||
|
|
QueryInterface.prototype.createTable = function(tableName, attributes, options) {
|
||
|
|
var keys = Object.keys(attributes)
|
||
|
|
, keyLen = keys.length
|
||
|
|
, self = this
|
||
|
|
, sql = ''
|
||
|
|
, i = 0;
|
||
|
|
|
||
|
|
options = options || {};
|
||
|
|
|
||
|
|
attributes = Utils._.mapValues(attributes, function(attribute) {
|
||
|
|
if (!Utils._.isPlainObject(attribute)) {
|
||
|
|
attribute = { type: attribute, allowNull: true };
|
||
|
|
}
|
||
|
|
|
||
|
|
attribute.type = self.sequelize.normalizeDataType(attribute.type);
|
||
|
|
|
||
|
|
if (attribute.hasOwnProperty('defaultValue')) {
|
||
|
|
if (typeof attribute.defaultValue === 'function' && (
|
||
|
|
attribute.defaultValue === DataTypes.NOW ||
|
||
|
|
attribute.defaultValue === DataTypes.UUIDV4 ||
|
||
|
|
attribute.defaultValue === DataTypes.UUIDV4
|
||
|
|
)) {
|
||
|
|
attribute.defaultValue = new attribute.defaultValue();
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
if (attribute.type instanceof DataTypes.ENUM) {
|
||
|
|
// The ENUM is a special case where the type is an object containing the values
|
||
|
|
attribute.values = attribute.values || attribute.type.values || [];
|
||
|
|
|
||
|
|
if (!attribute.values.length) {
|
||
|
|
throw new Error('Values for ENUM haven\'t been defined.');
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
return attribute;
|
||
|
|
});
|
||
|
|
|
||
|
|
// Postgres requires a special SQL command for enums
|
||
|
|
if (self.sequelize.options.dialect === 'postgres') {
|
||
|
|
var promises = []
|
||
|
|
// For backwards-compatibility, public schemas don't need to
|
||
|
|
// explicitly state their schema when creating a new enum type
|
||
|
|
, getTableName = (!options || !options.schema || options.schema === 'public' ? '' : options.schema + '_') + tableName;
|
||
|
|
|
||
|
|
for (i = 0; i < keyLen; i++) {
|
||
|
|
if (attributes[keys[i]].type instanceof DataTypes.ENUM) {
|
||
|
|
sql = self.QueryGenerator.pgListEnums(getTableName, attributes[keys[i]].field || keys[i], options);
|
||
|
|
promises.push(self.sequelize.query(
|
||
|
|
sql, { plain: true, raw: true, type: QueryTypes.SELECT, logging: options.logging, transaction: options.transaction }
|
||
|
|
));
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
return Promise.all(promises).then(function(results) {
|
||
|
|
var promises = []
|
||
|
|
, instanceTable = self.sequelize.modelManager.models.filter(function(instance) { return instance.tableName === tableName; })
|
||
|
|
, enumIdx = 0;
|
||
|
|
|
||
|
|
instanceTable = instanceTable.length > 0 ? instanceTable[0] : null;
|
||
|
|
|
||
|
|
for (i = 0; i < keyLen; i++) {
|
||
|
|
if (attributes[keys[i]].type instanceof DataTypes.ENUM) {
|
||
|
|
// If the enum type doesn't exist then create it
|
||
|
|
if (!results[enumIdx]) {
|
||
|
|
sql = self.QueryGenerator.pgEnum(getTableName, attributes[keys[i]].field || keys[i], attributes[keys[i]], options);
|
||
|
|
promises.push(self.sequelize.query(
|
||
|
|
sql, { raw: true, logging: options.logging, transaction: options.transaction }
|
||
|
|
));
|
||
|
|
} else if (!!results[enumIdx] && !!instanceTable) {
|
||
|
|
var enumVals = self.QueryGenerator.fromArray(results[enumIdx].enum_value)
|
||
|
|
, vals = instanceTable.rawAttributes[keys[i]].values;
|
||
|
|
|
||
|
|
vals.forEach(function(value, idx) {
|
||
|
|
// reset out after/before options since it's for every enum value
|
||
|
|
options.before = null;
|
||
|
|
options.after = null;
|
||
|
|
|
||
|
|
if (enumVals.indexOf(value) === -1) {
|
||
|
|
if (!!vals[idx + 1]) {
|
||
|
|
options.before = vals[idx + 1];
|
||
|
|
}
|
||
|
|
else if (!!vals[idx - 1]) {
|
||
|
|
options.after = vals[idx - 1];
|
||
|
|
}
|
||
|
|
promises.push(self.sequelize.query(self.QueryGenerator.pgEnumAdd(getTableName, keys[i], value, options), options));
|
||
|
|
}
|
||
|
|
});
|
||
|
|
enumIdx++;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
if (!tableName.schema && options.schema) {
|
||
|
|
tableName = self.QueryGenerator.addSchema({
|
||
|
|
tableName: tableName,
|
||
|
|
schema: options.schema
|
||
|
|
});
|
||
|
|
}
|
||
|
|
|
||
|
|
attributes = self.QueryGenerator.attributesToSQL(attributes, {
|
||
|
|
context: 'createTable'
|
||
|
|
});
|
||
|
|
sql = self.QueryGenerator.createTableQuery(tableName, attributes, options);
|
||
|
|
|
||
|
|
return Promise.all(promises).then(function() {
|
||
|
|
return self.sequelize.query(sql, options);
|
||
|
|
});
|
||
|
|
});
|
||
|
|
} else {
|
||
|
|
if (!tableName.schema && options.schema) {
|
||
|
|
tableName = self.QueryGenerator.addSchema({
|
||
|
|
tableName: tableName,
|
||
|
|
schema: options.schema
|
||
|
|
});
|
||
|
|
}
|
||
|
|
|
||
|
|
attributes = self.QueryGenerator.attributesToSQL(attributes, {
|
||
|
|
context: 'createTable'
|
||
|
|
});
|
||
|
|
sql = self.QueryGenerator.createTableQuery(tableName, attributes, options);
|
||
|
|
|
||
|
|
return self.sequelize.query(sql, options);
|
||
|
|
}
|
||
|
|
};
|
||
|
|
|
||
|
|
QueryInterface.prototype.dropTable = function(tableName, options) {
|
||
|
|
// if we're forcing we should be cascading unless explicitly stated otherwise
|
||
|
|
options = options || {};
|
||
|
|
options.cascade = options.cascade || options.force || false;
|
||
|
|
|
||
|
|
var sql = this.QueryGenerator.dropTableQuery(tableName, options)
|
||
|
|
, self = this;
|
||
|
|
|
||
|
|
return this.sequelize.query(sql, options).then(function() {
|
||
|
|
var promises = [];
|
||
|
|
|
||
|
|
// Since postgres has a special case for enums, we should drop the related
|
||
|
|
// enum type within the table and attribute
|
||
|
|
if (self.sequelize.options.dialect === 'postgres') {
|
||
|
|
var instanceTable = self.sequelize.modelManager.getModel(tableName, { attribute: 'tableName' });
|
||
|
|
|
||
|
|
if (!!instanceTable) {
|
||
|
|
var getTableName = (!options || !options.schema || options.schema === 'public' ? '' : options.schema + '_') + tableName;
|
||
|
|
|
||
|
|
var keys = Object.keys(instanceTable.rawAttributes)
|
||
|
|
, keyLen = keys.length
|
||
|
|
, i = 0;
|
||
|
|
|
||
|
|
for (i = 0; i < keyLen; i++) {
|
||
|
|
if (instanceTable.rawAttributes[keys[i]].type instanceof DataTypes.ENUM) {
|
||
|
|
sql = self.QueryGenerator.pgEnumDrop(getTableName, keys[i]);
|
||
|
|
promises.push(self.sequelize.query(sql, { logging: options.logging, raw: true, transaction : options.transaction }));
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
return Promise.all(promises).get(0);
|
||
|
|
});
|
||
|
|
};
|
||
|
|
|
||
|
|
QueryInterface.prototype.dropAllTables = function(options) {
|
||
|
|
var self = this;
|
||
|
|
|
||
|
|
options = options || {};
|
||
|
|
|
||
|
|
var dropAllTables = function(tableNames) {
|
||
|
|
return Promise.each(tableNames, function(tableName) {
|
||
|
|
// if tableName is not in the Array of tables names then dont drop it
|
||
|
|
if (skip.indexOf(tableName.tableName || tableName) === -1) {
|
||
|
|
return self.dropTable(tableName, { cascade: true, logging: options.logging });
|
||
|
|
}
|
||
|
|
});
|
||
|
|
};
|
||
|
|
|
||
|
|
var skip = options.skip || [];
|
||
|
|
return self.showAllTables({logging: options.logging}).then(function(tableNames) {
|
||
|
|
if (self.sequelize.options.dialect === 'sqlite') {
|
||
|
|
return self.sequelize.query('PRAGMA foreign_keys;', options).then(function(result) {
|
||
|
|
var foreignKeysAreEnabled = result.foreign_keys === 1;
|
||
|
|
|
||
|
|
if (foreignKeysAreEnabled) {
|
||
|
|
return self.sequelize.query('PRAGMA foreign_keys = OFF', options).then(function() {
|
||
|
|
return dropAllTables(tableNames).then(function() {
|
||
|
|
return self.sequelize.query('PRAGMA foreign_keys = ON', options);
|
||
|
|
});
|
||
|
|
});
|
||
|
|
} else {
|
||
|
|
return dropAllTables(tableNames);
|
||
|
|
}
|
||
|
|
});
|
||
|
|
} else {
|
||
|
|
return self.getForeignKeysForTables(tableNames, {logging: options.logging}).then(function(foreignKeys) {
|
||
|
|
var promises = [];
|
||
|
|
|
||
|
|
tableNames.forEach(function(tableName) {
|
||
|
|
var normalizedTableName = tableName;
|
||
|
|
if (Utils._.isObject(tableName)) {
|
||
|
|
normalizedTableName = tableName.schema + '.' + tableName.tableName;
|
||
|
|
}
|
||
|
|
|
||
|
|
foreignKeys[normalizedTableName].forEach(function(foreignKey) {
|
||
|
|
var sql = self.QueryGenerator.dropForeignKeyQuery(tableName, foreignKey);
|
||
|
|
promises.push(self.sequelize.query(sql, options));
|
||
|
|
});
|
||
|
|
});
|
||
|
|
|
||
|
|
return Promise.all(promises).then(function() {
|
||
|
|
return dropAllTables(tableNames);
|
||
|
|
});
|
||
|
|
});
|
||
|
|
}
|
||
|
|
});
|
||
|
|
};
|
||
|
|
|
||
|
|
QueryInterface.prototype.dropAllEnums = function(options) {
|
||
|
|
if (this.sequelize.getDialect() !== 'postgres') {
|
||
|
|
return Promise.resolve();
|
||
|
|
}
|
||
|
|
|
||
|
|
options = options || {};
|
||
|
|
|
||
|
|
var self = this
|
||
|
|
, sql = this.QueryGenerator.pgListEnums();
|
||
|
|
|
||
|
|
return this.sequelize.query(
|
||
|
|
sql,
|
||
|
|
{ plain: false, raw: true, type: QueryTypes.SELECT, logging: options.logging, transaction: options.transaction }
|
||
|
|
).map(function(result) {
|
||
|
|
return self.sequelize.query(
|
||
|
|
self.QueryGenerator.pgEnumDrop(null, null, self.QueryGenerator.pgEscapeAndQuote(result.enum_name)),
|
||
|
|
{logging: options.logging, raw: true}
|
||
|
|
);
|
||
|
|
});
|
||
|
|
};
|
||
|
|
|
||
|
|
QueryInterface.prototype.renameTable = function(before, after, options) {
|
||
|
|
options = options || {};
|
||
|
|
var sql = this.QueryGenerator.renameTableQuery(before, after);
|
||
|
|
return this.sequelize.query(sql, { logging: options.logging });
|
||
|
|
};
|
||
|
|
|
||
|
|
QueryInterface.prototype.showAllTables = function(options) {
|
||
|
|
var self = this;
|
||
|
|
options = Utils._.extend({
|
||
|
|
raw: true,
|
||
|
|
type: QueryTypes.SHOWTABLES
|
||
|
|
}, options || {});
|
||
|
|
|
||
|
|
var showTablesSql = self.QueryGenerator.showTablesQuery();
|
||
|
|
return self.sequelize.query(showTablesSql, options).then(function(tableNames) {
|
||
|
|
return Utils._.flatten(tableNames);
|
||
|
|
});
|
||
|
|
};
|
||
|
|
|
||
|
|
QueryInterface.prototype.describeTable = function(tableName, options) {
|
||
|
|
var schema = null
|
||
|
|
, schemaDelimiter = null;
|
||
|
|
|
||
|
|
if (typeof options === 'string') {
|
||
|
|
schema = options;
|
||
|
|
} else if (typeof options === 'object' && options !== null) {
|
||
|
|
schema = options.schema || null;
|
||
|
|
schemaDelimiter = options.schemaDelimiter || null;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (typeof tableName === 'object' && tableName !== null) {
|
||
|
|
schema = tableName.schema;
|
||
|
|
tableName = tableName.tableName;
|
||
|
|
}
|
||
|
|
|
||
|
|
var sql = this.QueryGenerator.describeTableQuery(tableName, schema, schemaDelimiter);
|
||
|
|
|
||
|
|
return this.sequelize.query(sql, { type: QueryTypes.DESCRIBE, logging: options && options.logging }).then(function(data) {
|
||
|
|
// If no data is returned from the query, then the table name may be wrong.
|
||
|
|
// Query generators that use information_schema for retrieving table info will just return an empty result set,
|
||
|
|
// it will not throw an error like built-ins do (e.g. DESCRIBE on MySql).
|
||
|
|
if (Utils._.isEmpty(data)) {
|
||
|
|
return Promise.reject('No description found for "' + tableName + '" table. Check the table name and schema; remember, they _are_ case sensitive.');
|
||
|
|
} else {
|
||
|
|
return Promise.resolve(data);
|
||
|
|
}
|
||
|
|
});
|
||
|
|
};
|
||
|
|
|
||
|
|
QueryInterface.prototype.addColumn = function(table, key, attribute, options) {
|
||
|
|
options = options || {};
|
||
|
|
attribute = this.sequelize.normalizeAttribute(attribute);
|
||
|
|
return this.sequelize.query(this.QueryGenerator.addColumnQuery(table, key, attribute), { logging: options.logging });
|
||
|
|
};
|
||
|
|
|
||
|
|
QueryInterface.prototype.removeColumn = function(tableName, attributeName, options) {
|
||
|
|
options = options || {};
|
||
|
|
if (this.sequelize.options.dialect === 'sqlite') {
|
||
|
|
// sqlite needs some special treatment as it cannot drop a column
|
||
|
|
return SQLiteQueryInterface.removeColumn.call(this, tableName, attributeName, {logging: options.logging});
|
||
|
|
} else {
|
||
|
|
var sql = this.QueryGenerator.removeColumnQuery(tableName, attributeName);
|
||
|
|
return this.sequelize.query(sql, {logging: options.logging});
|
||
|
|
}
|
||
|
|
};
|
||
|
|
|
||
|
|
QueryInterface.prototype.changeColumn = function(tableName, attributeName, dataTypeOrOptions, options) {
|
||
|
|
var attributes = {};
|
||
|
|
options = options || {};
|
||
|
|
|
||
|
|
if (Utils._.values(DataTypes).indexOf(dataTypeOrOptions) > -1) {
|
||
|
|
attributes[attributeName] = { type: dataTypeOrOptions, allowNull: true };
|
||
|
|
} else {
|
||
|
|
attributes[attributeName] = dataTypeOrOptions;
|
||
|
|
}
|
||
|
|
|
||
|
|
attributes[attributeName].type = this.sequelize.normalizeDataType(attributes[attributeName].type);
|
||
|
|
|
||
|
|
if (this.sequelize.options.dialect === 'sqlite') {
|
||
|
|
// sqlite needs some special treatment as it cannot change a column
|
||
|
|
return SQLiteQueryInterface.changeColumn.call(this, tableName, attributes, {logging: options.logging});
|
||
|
|
} else {
|
||
|
|
var query = this.QueryGenerator.attributesToSQL(attributes)
|
||
|
|
, sql = this.QueryGenerator.changeColumnQuery(tableName, query);
|
||
|
|
|
||
|
|
return this.sequelize.query(sql, {logging: options.logging});
|
||
|
|
}
|
||
|
|
};
|
||
|
|
|
||
|
|
QueryInterface.prototype.renameColumn = function(tableName, attrNameBefore, attrNameAfter, options) {
|
||
|
|
options = options || {};
|
||
|
|
return this.describeTable(tableName, options).then(function(data) {
|
||
|
|
data = data[attrNameBefore] || {};
|
||
|
|
|
||
|
|
var _options = {};
|
||
|
|
|
||
|
|
_options[attrNameAfter] = {
|
||
|
|
attribute: attrNameAfter,
|
||
|
|
type: data.type,
|
||
|
|
allowNull: data.allowNull,
|
||
|
|
defaultValue: data.defaultValue
|
||
|
|
};
|
||
|
|
|
||
|
|
// fix: a not-null column cannot have null as default value
|
||
|
|
if (data.defaultValue === null && !data.allowNull) {
|
||
|
|
delete _options[attrNameAfter].defaultValue;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (this.sequelize.options.dialect === 'sqlite') {
|
||
|
|
// sqlite needs some special treatment as it cannot rename a column
|
||
|
|
return SQLiteQueryInterface.renameColumn.call(this, tableName, attrNameBefore, attrNameAfter, {logging: options.logging});
|
||
|
|
} else {
|
||
|
|
var sql = this.QueryGenerator.renameColumnQuery(
|
||
|
|
tableName,
|
||
|
|
attrNameBefore,
|
||
|
|
this.QueryGenerator.attributesToSQL(_options)
|
||
|
|
);
|
||
|
|
return this.sequelize.query(sql, {logging: options.logging});
|
||
|
|
}
|
||
|
|
}.bind(this));
|
||
|
|
};
|
||
|
|
|
||
|
|
QueryInterface.prototype.addIndex = function(tableName, attributes, options, rawTablename) {
|
||
|
|
// Support for passing tableName, attributes, options or tableName, options (with a fields param which is the attributes)
|
||
|
|
if (!Array.isArray(attributes)) {
|
||
|
|
rawTablename = options;
|
||
|
|
options = attributes;
|
||
|
|
attributes = options.fields;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (!rawTablename) {
|
||
|
|
// Map for backwards compat
|
||
|
|
rawTablename = tableName;
|
||
|
|
}
|
||
|
|
|
||
|
|
options = options || {};
|
||
|
|
options.fields = attributes;
|
||
|
|
var sql = this.QueryGenerator.addIndexQuery(tableName, options, rawTablename);
|
||
|
|
return this.sequelize.query(sql, { logging: options.logging });
|
||
|
|
};
|
||
|
|
|
||
|
|
QueryInterface.prototype.showIndex = function(tableName, options) {
|
||
|
|
var sql = this.QueryGenerator.showIndexesQuery(tableName, options);
|
||
|
|
options = options || {};
|
||
|
|
return this.sequelize.query(sql, {
|
||
|
|
transaction: options.transaction,
|
||
|
|
logging: options.logging,
|
||
|
|
type: QueryTypes.SHOWINDEXES
|
||
|
|
});
|
||
|
|
};
|
||
|
|
|
||
|
|
QueryInterface.prototype.nameIndexes = function(indexes, rawTablename) {
|
||
|
|
return this.QueryGenerator.nameIndexes(indexes, rawTablename);
|
||
|
|
};
|
||
|
|
|
||
|
|
QueryInterface.prototype.getForeignKeysForTables = function(tableNames, options) {
|
||
|
|
var self = this;
|
||
|
|
options = options || {};
|
||
|
|
|
||
|
|
if (tableNames.length === 0) {
|
||
|
|
return Promise.resolve({});
|
||
|
|
}
|
||
|
|
|
||
|
|
return Promise.map(tableNames, function(tableName) {
|
||
|
|
return self.sequelize.query(self.QueryGenerator.getForeignKeysQuery(tableName, self.sequelize.config.database), {logging: options.logging}).get(0);
|
||
|
|
}).then(function(results) {
|
||
|
|
var result = {};
|
||
|
|
|
||
|
|
tableNames.forEach(function(tableName, i) {
|
||
|
|
if (Utils._.isObject(tableName)) {
|
||
|
|
tableName = tableName.schema + '.' + tableName.tableName;
|
||
|
|
}
|
||
|
|
|
||
|
|
result[tableName] = Utils._.compact(results[i]).map(function(r) {
|
||
|
|
return r.constraint_name;
|
||
|
|
});
|
||
|
|
});
|
||
|
|
|
||
|
|
return result;
|
||
|
|
});
|
||
|
|
};
|
||
|
|
|
||
|
|
QueryInterface.prototype.removeIndex = function(tableName, indexNameOrAttributes, options) {
|
||
|
|
options = options || {};
|
||
|
|
var sql = this.QueryGenerator.removeIndexQuery(tableName, indexNameOrAttributes);
|
||
|
|
return this.sequelize.query(sql, {logging: options.logging});
|
||
|
|
};
|
||
|
|
|
||
|
|
QueryInterface.prototype.insert = function(instance, tableName, values, options) {
|
||
|
|
options = options || {};
|
||
|
|
options.hasTrigger = instance && instance.Model.options.hasTrigger;
|
||
|
|
var sql = this.QueryGenerator.insertQuery(tableName, values, instance && instance.Model.rawAttributes, options);
|
||
|
|
|
||
|
|
options.type = QueryTypes.INSERT;
|
||
|
|
options.instance = instance;
|
||
|
|
|
||
|
|
return this.sequelize.query(sql, options).then(function(result) {
|
||
|
|
if (instance) result.isNewRecord = false;
|
||
|
|
return result;
|
||
|
|
});
|
||
|
|
};
|
||
|
|
|
||
|
|
QueryInterface.prototype.upsert = function(tableName, values, updateValues, model, options) {
|
||
|
|
var wheres = []
|
||
|
|
, where
|
||
|
|
, indexFields
|
||
|
|
, indexes = []
|
||
|
|
, attributes = Object.keys(values);
|
||
|
|
|
||
|
|
where = {};
|
||
|
|
for (var i = 0; i < model.primaryKeyAttributes.length; i++) {
|
||
|
|
var key = model.primaryKeyAttributes[i];
|
||
|
|
if(key in values){
|
||
|
|
where[key] = values[key];
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
if (!Utils._.isEmpty(where)) {
|
||
|
|
wheres.push(where);
|
||
|
|
}
|
||
|
|
|
||
|
|
// Lets combine uniquekeys and indexes into one
|
||
|
|
indexes = Utils._.map(model.options.uniqueKeys, function (value) {
|
||
|
|
return value.fields;
|
||
|
|
});
|
||
|
|
|
||
|
|
Utils._.each(model.options.indexes, function (value) {
|
||
|
|
if (value.unique === true) {
|
||
|
|
// fields in the index may both the strings or objects with an attribute property - lets sanitize that
|
||
|
|
indexFields = Utils._.map(value.fields, function (field) {
|
||
|
|
if (Utils._.isPlainObject(field)) {
|
||
|
|
return field.attribute;
|
||
|
|
}
|
||
|
|
return field;
|
||
|
|
});
|
||
|
|
indexes.push(indexFields);
|
||
|
|
}
|
||
|
|
});
|
||
|
|
|
||
|
|
indexes.forEach(function (index) {
|
||
|
|
if (Utils._.intersection(attributes, index).length === index.length) {
|
||
|
|
where = {};
|
||
|
|
index.forEach(function (field) {
|
||
|
|
where[field] = values[field];
|
||
|
|
});
|
||
|
|
wheres.push(where);
|
||
|
|
}
|
||
|
|
});
|
||
|
|
|
||
|
|
where = this.sequelize.or.apply(this.sequelize, wheres);
|
||
|
|
|
||
|
|
options.type = QueryTypes.UPSERT;
|
||
|
|
options.raw = true;
|
||
|
|
|
||
|
|
var sql = this.QueryGenerator.upsertQuery(tableName, values, updateValues, where, model.rawAttributes, options);
|
||
|
|
return this.sequelize.query(sql, options).then(function (rowCount) {
|
||
|
|
if (rowCount === undefined) {
|
||
|
|
return rowCount;
|
||
|
|
}
|
||
|
|
|
||
|
|
// MySQL returns 1 for inserted, 2 for updated http://dev.mysql.com/doc/refman/5.0/en/insert-on-duplicate.html. Postgres has been modded to do the same
|
||
|
|
|
||
|
|
return rowCount === 1;
|
||
|
|
});
|
||
|
|
};
|
||
|
|
|
||
|
|
QueryInterface.prototype.bulkInsert = function(tableName, records, options, attributes) {
|
||
|
|
options.type = QueryTypes.INSERT;
|
||
|
|
var sql = this.QueryGenerator.bulkInsertQuery(tableName, records, options, attributes);
|
||
|
|
return this.sequelize.query(sql, options);
|
||
|
|
};
|
||
|
|
|
||
|
|
QueryInterface.prototype.update = function(instance, tableName, values, identifier, options) {
|
||
|
|
options = options || {};
|
||
|
|
options.hasTrigger = !!(instance && instance.__options && instance.__options.hasTrigger);
|
||
|
|
|
||
|
|
|
||
|
|
var self = this
|
||
|
|
, restrict = false
|
||
|
|
, sql = self.QueryGenerator.updateQuery(tableName, values, identifier, options, instance.Model.rawAttributes);
|
||
|
|
|
||
|
|
|
||
|
|
options.type = QueryTypes.UPDATE;
|
||
|
|
|
||
|
|
// Check for a restrict field
|
||
|
|
if (!!instance.Model && !!instance.Model.associations) {
|
||
|
|
var keys = Object.keys(instance.Model.associations)
|
||
|
|
, length = keys.length;
|
||
|
|
|
||
|
|
for (var i = 0; i < length; i++) {
|
||
|
|
if (instance.Model.associations[keys[i]].options && instance.Model.associations[keys[i]].options.onUpdate && instance.Model.associations[keys[i]].options.onUpdate === 'restrict') {
|
||
|
|
restrict = true;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
options.instance = instance;
|
||
|
|
return this.sequelize.query(sql, options);
|
||
|
|
};
|
||
|
|
|
||
|
|
QueryInterface.prototype.bulkUpdate = function(tableName, values, identifier, options, attributes) {
|
||
|
|
var sql = this.QueryGenerator.updateQuery(tableName, values, identifier, options, attributes)
|
||
|
|
, table = Utils._.isObject(tableName) ? tableName : { tableName: tableName }
|
||
|
|
, model = Utils._.find(this.sequelize.modelManager.models, { tableName: table.tableName });
|
||
|
|
|
||
|
|
options = options || {};
|
||
|
|
options.model = model;
|
||
|
|
return this.sequelize.query(sql, options);
|
||
|
|
};
|
||
|
|
|
||
|
|
QueryInterface.prototype.delete = function(instance, tableName, identifier, options) {
|
||
|
|
var self = this
|
||
|
|
, cascades = []
|
||
|
|
, sql = self.QueryGenerator.deleteQuery(tableName, identifier, null, instance.Model);
|
||
|
|
|
||
|
|
options = options || {};
|
||
|
|
|
||
|
|
// Check for a restrict field
|
||
|
|
if (!!instance.Model && !!instance.Model.associations) {
|
||
|
|
var keys = Object.keys(instance.Model.associations)
|
||
|
|
, length = keys.length;
|
||
|
|
|
||
|
|
for (var i = 0; i < length; i++) {
|
||
|
|
if (instance.Model.associations[keys[i]].options && instance.Model.associations[keys[i]].options.onDelete) {
|
||
|
|
if (instance.Model.associations[keys[i]].options.onDelete === 'cascade' && instance.Model.associations[keys[i]].options.useHooks === true) {
|
||
|
|
cascades.push(instance.Model.associations[keys[i]].accessors.get);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
return Promise.each(cascades, function (cascade) {
|
||
|
|
return instance[cascade]({
|
||
|
|
transaction: options.transaction,
|
||
|
|
logging: options.logging
|
||
|
|
}).then(function (instances) {
|
||
|
|
// Check for hasOne relationship with non-existing associate ("has zero")
|
||
|
|
if (!instances) {
|
||
|
|
return Promise.resolve();
|
||
|
|
}
|
||
|
|
|
||
|
|
if (!Array.isArray(instances)) instances = [instances];
|
||
|
|
|
||
|
|
return Promise.each(instances, function (instance) {
|
||
|
|
return instance.destroy({
|
||
|
|
transaction: options.transaction,
|
||
|
|
logging: options.logging
|
||
|
|
});
|
||
|
|
});
|
||
|
|
});
|
||
|
|
}).then(function () {
|
||
|
|
options.instance = instance;
|
||
|
|
return self.sequelize.query(sql, options);
|
||
|
|
});
|
||
|
|
};
|
||
|
|
|
||
|
|
QueryInterface.prototype.bulkDelete = function(tableName, identifier, options, model) {
|
||
|
|
var sql = this.QueryGenerator.deleteQuery(tableName, identifier, Utils._.defaults(options || {}, {limit: null}), model);
|
||
|
|
return this.sequelize.query(sql, options);
|
||
|
|
};
|
||
|
|
|
||
|
|
QueryInterface.prototype.select = function(model, tableName, options) {
|
||
|
|
options = options || {};
|
||
|
|
options.type = QueryTypes.SELECT;
|
||
|
|
options.model = model;
|
||
|
|
return this.sequelize.query(
|
||
|
|
this.QueryGenerator.selectQuery(tableName, options, model),
|
||
|
|
options
|
||
|
|
);
|
||
|
|
};
|
||
|
|
|
||
|
|
QueryInterface.prototype.increment = function(instance, tableName, values, identifier, options) {
|
||
|
|
var sql = this.QueryGenerator.incrementQuery(tableName, values, identifier, options.attributes);
|
||
|
|
|
||
|
|
options = options || {};
|
||
|
|
|
||
|
|
options.type = QueryTypes.RAW;
|
||
|
|
options.instance = instance;
|
||
|
|
return this.sequelize.query(sql, options);
|
||
|
|
};
|
||
|
|
|
||
|
|
QueryInterface.prototype.rawSelect = function(tableName, options, attributeSelector, Model) {
|
||
|
|
if (options.schema) {
|
||
|
|
tableName = this.QueryGenerator.addSchema({
|
||
|
|
tableName: tableName,
|
||
|
|
schema: options.schema
|
||
|
|
});
|
||
|
|
}
|
||
|
|
|
||
|
|
options = _.defaults(options || {}, {
|
||
|
|
raw: true,
|
||
|
|
plain: true,
|
||
|
|
type: QueryTypes.SELECT
|
||
|
|
});
|
||
|
|
|
||
|
|
var sql = this.QueryGenerator.selectQuery(tableName, options, Model);
|
||
|
|
|
||
|
|
if (attributeSelector === undefined) {
|
||
|
|
throw new Error('Please pass an attribute selector!');
|
||
|
|
}
|
||
|
|
|
||
|
|
return this.sequelize.query(sql, options).then(function(data) {
|
||
|
|
if (!options.plain) {
|
||
|
|
return data;
|
||
|
|
}
|
||
|
|
|
||
|
|
var result = data ? data[attributeSelector] : null;
|
||
|
|
|
||
|
|
if (options && options.dataType) {
|
||
|
|
var dataType = options.dataType;
|
||
|
|
|
||
|
|
if (dataType instanceof DataTypes.DECIMAL || dataType instanceof DataTypes.FLOAT) {
|
||
|
|
result = parseFloat(result);
|
||
|
|
} else if (dataType instanceof DataTypes.INTEGER || dataType instanceof DataTypes.BIGINT) {
|
||
|
|
result = parseInt(result, 10);
|
||
|
|
} else if (dataType instanceof DataTypes.DATE) {
|
||
|
|
if (!Utils._.isNull(result) && !Utils._.isDate(result)) {
|
||
|
|
result = new Date(result);
|
||
|
|
}
|
||
|
|
} else if (dataType instanceof DataTypes.STRING) {
|
||
|
|
// Nothing to do, result is already a string.
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
return result;
|
||
|
|
});
|
||
|
|
};
|
||
|
|
|
||
|
|
QueryInterface.prototype.createTrigger = function(tableName, triggerName, timingType, fireOnArray, functionName, functionParams, optionsArray, options) {
|
||
|
|
var sql = this.QueryGenerator.createTrigger(tableName, triggerName, timingType, fireOnArray, functionName, functionParams, optionsArray);
|
||
|
|
options = options || {};
|
||
|
|
if (sql) {
|
||
|
|
return this.sequelize.query(sql, {logging: options.logging});
|
||
|
|
} else {
|
||
|
|
return Promise.resolve();
|
||
|
|
}
|
||
|
|
};
|
||
|
|
|
||
|
|
QueryInterface.prototype.dropTrigger = function(tableName, triggerName, options) {
|
||
|
|
var sql = this.QueryGenerator.dropTrigger(tableName, triggerName);
|
||
|
|
options = options || {};
|
||
|
|
|
||
|
|
if (sql) {
|
||
|
|
return this.sequelize.query(sql, {logging: options.logging});
|
||
|
|
} else {
|
||
|
|
return Promise.resolve();
|
||
|
|
}
|
||
|
|
};
|
||
|
|
|
||
|
|
QueryInterface.prototype.renameTrigger = function(tableName, oldTriggerName, newTriggerName, options) {
|
||
|
|
var sql = this.QueryGenerator.renameTrigger(tableName, oldTriggerName, newTriggerName);
|
||
|
|
options = options || {};
|
||
|
|
|
||
|
|
if (sql) {
|
||
|
|
return this.sequelize.query(sql, {logging: options.logging});
|
||
|
|
} else {
|
||
|
|
return Promise.resolve();
|
||
|
|
}
|
||
|
|
};
|
||
|
|
|
||
|
|
QueryInterface.prototype.createFunction = function(functionName, params, returnType, language, body, options) {
|
||
|
|
var sql = this.QueryGenerator.createFunction(functionName, params, returnType, language, body, options);
|
||
|
|
options = options || {};
|
||
|
|
|
||
|
|
if (sql) {
|
||
|
|
return this.sequelize.query(sql, {logging: options.logging});
|
||
|
|
} else {
|
||
|
|
return Promise.resolve();
|
||
|
|
}
|
||
|
|
};
|
||
|
|
|
||
|
|
QueryInterface.prototype.dropFunction = function(functionName, params, options) {
|
||
|
|
var sql = this.QueryGenerator.dropFunction(functionName, params);
|
||
|
|
options = options || {};
|
||
|
|
|
||
|
|
if (sql) {
|
||
|
|
return this.sequelize.query(sql, {logging: options.logging});
|
||
|
|
} else {
|
||
|
|
return Promise.resolve();
|
||
|
|
}
|
||
|
|
};
|
||
|
|
|
||
|
|
QueryInterface.prototype.renameFunction = function(oldFunctionName, params, newFunctionName, options) {
|
||
|
|
var sql = this.QueryGenerator.renameFunction(oldFunctionName, params, newFunctionName);
|
||
|
|
options = options || {};
|
||
|
|
|
||
|
|
if (sql) {
|
||
|
|
return this.sequelize.query(sql, {logging: options.logging});
|
||
|
|
} else {
|
||
|
|
return Promise.resolve();
|
||
|
|
}
|
||
|
|
};
|
||
|
|
|
||
|
|
// Helper methods useful for querying
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Escape an identifier (e.g. a table or attribute name). If force is true,
|
||
|
|
* the identifier will be quoted even if the `quoteIdentifiers` option is
|
||
|
|
* false.
|
||
|
|
*/
|
||
|
|
QueryInterface.prototype.quoteIdentifier = function(identifier, force) {
|
||
|
|
return this.QueryGenerator.quoteIdentifier(identifier, force);
|
||
|
|
};
|
||
|
|
|
||
|
|
QueryInterface.prototype.quoteTable = function(identifier) {
|
||
|
|
return this.QueryGenerator.quoteTable(identifier);
|
||
|
|
};
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Split an identifier into .-separated tokens and quote each part.
|
||
|
|
* If force is true, the identifier will be quoted even if the
|
||
|
|
* `quoteIdentifiers` option is false.
|
||
|
|
*/
|
||
|
|
QueryInterface.prototype.quoteIdentifiers = function(identifiers, force) {
|
||
|
|
return this.QueryGenerator.quoteIdentifiers(identifiers, force);
|
||
|
|
};
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Escape a value (e.g. a string, number or date)
|
||
|
|
*/
|
||
|
|
QueryInterface.prototype.escape = function(value) {
|
||
|
|
return this.QueryGenerator.escape(value);
|
||
|
|
};
|
||
|
|
|
||
|
|
QueryInterface.prototype.setAutocommit = function(transaction, value, options) {
|
||
|
|
if (!transaction || !(transaction instanceof Transaction)) {
|
||
|
|
throw new Error('Unable to set autocommit for a transaction without transaction object!');
|
||
|
|
}
|
||
|
|
|
||
|
|
options = Utils._.extend({
|
||
|
|
parent: options.transaction
|
||
|
|
}, options || {});
|
||
|
|
|
||
|
|
var sql = this.QueryGenerator.setAutocommitQuery(value, options);
|
||
|
|
if (sql) {
|
||
|
|
return this.sequelize.query(sql, { transaction: transaction, logging: options.logging });
|
||
|
|
} else {
|
||
|
|
return Promise.resolve();
|
||
|
|
}
|
||
|
|
};
|
||
|
|
|
||
|
|
QueryInterface.prototype.setIsolationLevel = function(transaction, value, options) {
|
||
|
|
if (!transaction || !(transaction instanceof Transaction)) {
|
||
|
|
throw new Error('Unable to set isolation level for a transaction without transaction object!');
|
||
|
|
}
|
||
|
|
|
||
|
|
options = Utils._.extend({
|
||
|
|
parent: options.transaction
|
||
|
|
}, options || {});
|
||
|
|
|
||
|
|
var sql = this.QueryGenerator.setIsolationLevelQuery(value, options);
|
||
|
|
|
||
|
|
if (sql) {
|
||
|
|
return this.sequelize.query(sql, { transaction: transaction, logging: options.logging });
|
||
|
|
} else {
|
||
|
|
return Promise.resolve();
|
||
|
|
}
|
||
|
|
};
|
||
|
|
|
||
|
|
QueryInterface.prototype.startTransaction = function(transaction, options) {
|
||
|
|
if (!transaction || !(transaction instanceof Transaction)) {
|
||
|
|
throw new Error('Unable to start a transaction without transaction object!');
|
||
|
|
}
|
||
|
|
|
||
|
|
options = Utils._.extend({
|
||
|
|
transaction: transaction,
|
||
|
|
parent: options.transaction
|
||
|
|
}, options || {});
|
||
|
|
|
||
|
|
var sql = this.QueryGenerator.startTransactionQuery(transaction, options);
|
||
|
|
return this.sequelize.query(sql, options);
|
||
|
|
};
|
||
|
|
|
||
|
|
QueryInterface.prototype.deferConstraints = function (transaction, options) {
|
||
|
|
options = Utils._.extend({
|
||
|
|
transaction: transaction,
|
||
|
|
parent: options.transaction
|
||
|
|
}, options || {});
|
||
|
|
|
||
|
|
var sql = this.QueryGenerator.deferConstraintsQuery(options);
|
||
|
|
|
||
|
|
if (sql) {
|
||
|
|
return this.sequelize.query(sql, options);
|
||
|
|
}
|
||
|
|
|
||
|
|
return Promise.resolve();
|
||
|
|
};
|
||
|
|
|
||
|
|
QueryInterface.prototype.commitTransaction = function(transaction, options) {
|
||
|
|
if (!transaction || !(transaction instanceof Transaction)) {
|
||
|
|
throw new Error('Unable to commit a transaction without transaction object!');
|
||
|
|
}
|
||
|
|
|
||
|
|
options = Utils._.extend({
|
||
|
|
transaction: transaction,
|
||
|
|
parent: options.transaction
|
||
|
|
}, options || {});
|
||
|
|
|
||
|
|
var sql = this.QueryGenerator.commitTransactionQuery(options);
|
||
|
|
|
||
|
|
if (sql) {
|
||
|
|
return this.sequelize.query(sql, options);
|
||
|
|
} else {
|
||
|
|
return Promise.resolve();
|
||
|
|
}
|
||
|
|
};
|
||
|
|
|
||
|
|
QueryInterface.prototype.rollbackTransaction = function(transaction, options) {
|
||
|
|
if (!transaction || !(transaction instanceof Transaction)) {
|
||
|
|
throw new Error('Unable to rollback a transaction without transaction object!');
|
||
|
|
}
|
||
|
|
|
||
|
|
options = Utils._.extend({
|
||
|
|
transaction: transaction,
|
||
|
|
parent: options.transaction
|
||
|
|
}, options || {});
|
||
|
|
|
||
|
|
var sql = this.QueryGenerator.rollbackTransactionQuery(transaction, options);
|
||
|
|
return this.sequelize.query(sql, options);
|
||
|
|
};
|
||
|
|
|
||
|
|
module.exports = QueryInterface;
|