不要怂,就是干,撸起袖子干!

Commit 66dc7694 by Jan Aagaard Meier

Merge pull request #2057 from sequelize/indexes

Support for specifying indexes on a model
2 parents 2c5b46e9 779dc404
...@@ -3,6 +3,8 @@ Notice: All 1.7.x changes are present in 2.0.x aswell ...@@ -3,6 +3,8 @@ Notice: All 1.7.x changes are present in 2.0.x aswell
# Next # Next
- [FEATURE] Added to option of setting a timezone offset in the sequelize constructor (`timezone` option). This timezone is used when initializing a connection (using `SET TIME ZONE` or equivalent), and when converting a timestamp string from the DB to a JS date with mysql (postgres stores the timezone, so for postgres we rely on what's in the DB). - [FEATURE] Added to option of setting a timezone offset in the sequelize constructor (`timezone` option). This timezone is used when initializing a connection (using `SET TIME ZONE` or equivalent), and when converting a timestamp string from the DB to a JS date with mysql (postgres stores the timezone, so for postgres we rely on what's in the DB).
- [FEATURE] Allow setting plural and singular name on the model (`options.name` in `sequelize.define`) and in associations (`options.as`) to circumvent issues with weird pluralization. - [FEATURE] Allow setting plural and singular name on the model (`options.name` in `sequelize.define`) and in associations (`options.as`) to circumvent issues with weird pluralization.
- [FEATURE] Added support for passing an `indexes` array in options to `sequelize.define`. [#1485](https://github.com/sequelize/sequelize/issues/1485). See API reference for details.
- [FEATURE/INTERNALS] Standardized the output from `QueryInterface.showIndex`.
- [FEATURE] Include deleted rows in find [#2083](https://github.com/sequelize/sequelize/pull/2083) - [FEATURE] Include deleted rows in find [#2083](https://github.com/sequelize/sequelize/pull/2083)
- [BUG] Hid `dottie.transform` on raw queries behind a flag (`nest`) [#2064](https://github.com/sequelize/sequelize/pull/2064) - [BUG] Hid `dottie.transform` on raw queries behind a flag (`nest`) [#2064](https://github.com/sequelize/sequelize/pull/2064)
- [BUG] Fixed problems with transcation parameter being removed / not passed on in associations [#1789](https://github.com/sequelize/sequelize/issues/1789) and [#1968](https://github.com/sequelize/sequelize/issues/1968) - [BUG] Fixed problems with transcation parameter being removed / not passed on in associations [#1789](https://github.com/sequelize/sequelize/issues/1789) and [#1968](https://github.com/sequelize/sequelize/issues/1968)
......
...@@ -10,7 +10,15 @@ AbstractDialect.prototype.supports = { ...@@ -10,7 +10,15 @@ AbstractDialect.prototype.supports = {
'DEFAULT VALUES': false, 'DEFAULT VALUES': false,
'VALUES ()': false, 'VALUES ()': false,
'LIMIT ON UPDATE': false, 'LIMIT ON UPDATE': false,
schemas: false schemas: false,
index: {
collate: true,
length: false,
parser: false,
concurrently: false,
type: false,
using: true,
},
}; };
module.exports = AbstractDialect; module.exports = AbstractDialect;
\ No newline at end of file
...@@ -3,7 +3,8 @@ ...@@ -3,7 +3,8 @@
var Utils = require('../../utils') var Utils = require('../../utils')
, SqlString = require('../../sql-string') , SqlString = require('../../sql-string')
, Model = require('../../model') , Model = require('../../model')
, _ = require('lodash'); , _ = require('lodash')
, util = require('util');
module.exports = (function() { module.exports = (function() {
var QueryGenerator = { var QueryGenerator = {
...@@ -321,7 +322,7 @@ module.exports = (function() { ...@@ -321,7 +322,7 @@ module.exports = (function() {
/* /*
Returns an add index query. Returns an add index query.
Parameters: Parameters:
- tableName -> Name of an existing table. - tableName -> Name of an existing table, possibly with schema.
- attributes: - attributes:
An array of attributes as string or as hash. An array of attributes as string or as hash.
If the attribute is a hash, it must have the following content: If the attribute is a hash, it must have the following content:
...@@ -332,9 +333,72 @@ module.exports = (function() { ...@@ -332,9 +333,72 @@ module.exports = (function() {
- indicesType: UNIQUE|FULLTEXT|SPATIAL - indicesType: UNIQUE|FULLTEXT|SPATIAL
- indexName: The name of the index. Default is <tableName>_<attrName1>_<attrName2> - indexName: The name of the index. Default is <tableName>_<attrName1>_<attrName2>
- parser - parser
- rawTablename, the name of the table, without schema. Used to create the name of the index
*/ */
addIndexQuery: function(tableName, attributes, options) { addIndexQuery: function(tableName, attributes, options, rawTablename) {
throwMethodUndefined('addIndexQuery'); options = options || {};
var transformedAttributes = attributes.map(function(attribute) {
if (typeof attribute === 'string') {
return this.quoteIdentifier(attribute);
} else {
var result = '';
if (!attribute.attribute) {
throw new Error('The following index attribute has no attribute: ' + util.inspect(attribute));
}
result += this.quoteIdentifier(attribute.attribute);
if (this._dialect.supports.index.collate && attribute.collate) {
result += ' COLLATE ' + this.quoteIdentifier(attribute.collate);
}
if (this._dialect.supports.index.length && attribute.length) {
result += '(' + attribute.length + ')';
}
if (attribute.order) {
result += ' ' + attribute.order;
}
return result;
}
}.bind(this));
var onlyAttributeNames = attributes.map(function(attribute) {
return (typeof attribute === 'string') ? attribute : attribute.attribute;
}.bind(this));
options = Utils._.defaults(options, {
type: '',
indicesType: options.type || '',
indexType: options.method || undefined,
indexName: options.name || Utils.inflection.underscore(rawTablename + '_' + onlyAttributeNames.join('_')),
parser: null
});
if (options.indicesType.toLowerCase() === 'unique') {
options.unique = true;
delete options.indicesType;
}
if (!this._dialect.supports.index.type) {
delete options.indicesType;
}
return Utils._.compact([
'CREATE',
options.unique ? 'UNIQUE' : '',
options.indicesType, 'INDEX',
this._dialect.supports.index.concurrently && options.concurrently ? 'CONCURRENTLY' : undefined,
this.quoteIdentifiers(options.indexName),
this._dialect.supports.index.using === 1 && options.indexType ? 'USING ' + options.indexType : '',
'ON', this.quoteIdentifiers(tableName),
this._dialect.supports.index.using === 2 && options.indexType ? 'USING ' + options.indexType : '',
'(' + transformedAttributes.join(', ') + ')',
(this._dialect.supports.index.parser && options.parser ? 'WITH PARSER ' + options.parser : undefined)
]).join(' ');
}, },
/* /*
...@@ -676,6 +740,7 @@ module.exports = (function() { ...@@ -676,6 +740,7 @@ module.exports = (function() {
mainAttributes = [mainTableAs + '.*']; mainAttributes = [mainTableAs + '.*'];
} }
if (options.include) { if (options.include) {
var generateJoinQueries = function(include, parentTable) { var generateJoinQueries = function(include, parentTable) {
var table = include.model.getTableName() var table = include.model.getTableName()
...@@ -946,7 +1011,6 @@ module.exports = (function() { ...@@ -946,7 +1011,6 @@ module.exports = (function() {
mainQueryItems.push(' HAVING ' + options.having); mainQueryItems.push(' HAVING ' + options.having);
} }
} }
// Add ORDER to sub or main query // Add ORDER to sub or main query
if (options.order) { if (options.order) {
var mainQueryOrder = []; var mainQueryOrder = [];
......
...@@ -86,16 +86,8 @@ module.exports = (function() { ...@@ -86,16 +86,8 @@ module.exports = (function() {
defaultValue: _result.Default defaultValue: _result.Default
}; };
}); });
} else if (this.sql.toLowerCase().indexOf('show index from') === 0) { } else if (this.isShowIndexesQuery()) {
result = Utils._.uniq(result.map(function(result) { result = this.handleShowIndexesQuery(data);
return {
name: result.Key_name,
tableName: result.Table,
unique: (result.Non_unique !== 1)
};
}), false, function(row) {
return row.name;
});
} }
} else if (this.isCallQuery()) { } else if (this.isCallQuery()) {
result = data[0]; result = data[0];
......
...@@ -11,9 +11,7 @@ var MariaDialect = function(sequelize) { ...@@ -11,9 +11,7 @@ var MariaDialect = function(sequelize) {
this.connectionManager.initPools(); this.connectionManager.initPools();
}; };
MariaDialect.prototype = _.defaults({ MariaDialect.prototype = MySQL.prototype;
'LIMIT ON UPDATE': true
}, MySQL.prototype);
MariaDialect.prototype.Query = Query; MariaDialect.prototype.Query = Query;
......
'use strict'; 'use strict';
var Utils = require('../../utils') var Utils = require('../../utils')
, AbstractQuery = require('../abstract/query'); , MysqlQuery = require('../mysql/query');
module.exports = (function() { module.exports = (function() {
var Query = function(client, sequelize, callee, options) { var Query = function(client, sequelize, callee, options) {
...@@ -22,7 +22,7 @@ module.exports = (function() { ...@@ -22,7 +22,7 @@ module.exports = (function() {
}); });
}; };
Utils.inherit(Query, AbstractQuery); Utils.inherit(Query, MysqlQuery);
Query.prototype.run = function(sql) { Query.prototype.run = function(sql) {
this.sql = sql; this.sql = sql;
......
...@@ -11,12 +11,19 @@ var MysqlDialect = function(sequelize) { ...@@ -11,12 +11,19 @@ var MysqlDialect = function(sequelize) {
this.connectionManager.initPools(); this.connectionManager.initPools();
}; };
MysqlDialect.prototype.supports = _.defaults({ MysqlDialect.prototype.supports = _.merge(_.cloneDeep(Abstract.prototype.supports), {
'VALUES ()': true, 'VALUES ()': true,
'LIMIT ON UPDATE': true, 'LIMIT ON UPDATE': true,
lock: true, lock: true,
forShare: 'LOCK IN SHARE MODE' forShare: 'LOCK IN SHARE MODE',
}, Abstract.prototype.supports); index: {
collate: false,
length: true,
parser: true,
type: true,
using: 1,
}
});
MysqlDialect.prototype.Query = Query; MysqlDialect.prototype.Query = Query;
......
...@@ -221,49 +221,6 @@ module.exports = (function() { ...@@ -221,49 +221,6 @@ module.exports = (function() {
return 'DELETE FROM ' + table + ' WHERE ' + where + limit; return 'DELETE FROM ' + table + ' WHERE ' + where + limit;
}, },
addIndexQuery: function(tableName, attributes, options) {
var transformedAttributes = attributes.map(function(attribute) {
if (typeof attribute === 'string') {
return this.quoteIdentifier(attribute);
} else {
var result = '';
if (!attribute.attribute) {
throw new Error('The following index attribute has no attribute: ' + util.inspect(attribute));
}
result += this.quoteIdentifier(attribute.attribute);
if (attribute.length) {
result += '(' + attribute.length + ')';
}
if (attribute.order) {
result += ' ' + attribute.order;
}
return result;
}
}.bind(this));
var onlyAttributeNames = attributes.map(function(attribute) {
return (typeof attribute === 'string') ? attribute : attribute.attribute;
}.bind(this));
options = Utils._.extend({
indicesType: null,
indexName: Utils.inflection.underscore(tableName + '_' + onlyAttributeNames.join('_')),
parser: null
}, options || {});
return Utils._.compact([
'CREATE', options.indicesType, 'INDEX', options.indexName,
(options.indexType ? ('USING ' + options.indexType) : undefined),
'ON', this.quoteIdentifiers(tableName), '(' + transformedAttributes.join(', ') + ')',
(options.parser ? 'WITH PARSER ' + options.parser : undefined)
]).join(' ');
},
showIndexQuery: function(tableName, options) { showIndexQuery: function(tableName, options) {
var sql = 'SHOW INDEX FROM <%= tableName %><%= options %>'; var sql = 'SHOW INDEX FROM <%= tableName %><%= options %>';
return Utils._.template(sql)({ return Utils._.template(sql)({
......
...@@ -46,5 +46,39 @@ module.exports = (function() { ...@@ -46,5 +46,39 @@ module.exports = (function() {
return promise; return promise;
}; };
Query.prototype.isShowIndexesQuery = function () {
return this.sql.toLowerCase().indexOf('show index from') === 0;
};
Query.prototype.handleShowIndexesQuery = function (data) {
// Group by index name, and collect all fields
data = Utils._.foldl(data, function (acc, item) {
if (!(item.Key_name in acc)) {
acc[item.Key_name] = item;
item.fields = [];
}
acc[item.Key_name].fields[item.Seq_in_index - 1] = {
attribute: item.Column_name,
length: item.Sub_part || undefined,
order: item.Collation === 'A' ? 'ASC' : undefined
};
delete item.column_name;
return acc;
}, {});
return Utils._.map(data, function(item) {
return {
primary: item.Key_name === 'PRIMARY',
fields: item.fields,
name: item.Key_name,
tableName: item.Table,
unique: (item.Non_unique !== 1),
type: item.Index_type,
};
});
};
return Query; return Query;
})(); })();
...@@ -11,13 +11,17 @@ var PostgresDialect = function(sequelize) { ...@@ -11,13 +11,17 @@ var PostgresDialect = function(sequelize) {
this.connectionManager.initPools(); this.connectionManager.initPools();
}; };
PostgresDialect.prototype.supports = _.defaults({ PostgresDialect.prototype.supports = _.merge(_.cloneDeep(Abstract.prototype.supports), {
'RETURNING': true, 'RETURNING': true,
'DEFAULT VALUES': true, 'DEFAULT VALUES': true,
schemas: true, schemas: true,
lock: true, lock: true,
forShare: 'FOR SHARE' forShare: 'FOR SHARE',
}, Abstract.prototype.supports); index: {
concurrently: true,
using: 2,
}
});
PostgresDialect.prototype.Query = Query; PostgresDialect.prototype.Query = Query;
......
...@@ -352,51 +352,10 @@ module.exports = (function() { ...@@ -352,51 +352,10 @@ module.exports = (function() {
return Utils._.template(query)(replacements); return Utils._.template(query)(replacements);
}, },
addIndexQuery: function(tableName, attributes, options) {
var transformedAttributes = attributes.map(function(attribute) {
if (typeof attribute === 'string') {
return this.quoteIdentifier(attribute);
} else {
var result = '';
if (!attribute.attribute) {
throw new Error('The following index attribute has no attribute: ' + util.inspect(attribute));
}
result += this.quoteIdentifier(attribute.attribute);
if (attribute.length) {
result += '(' + attribute.length + ')';
}
if (attribute.order) {
result += ' ' + attribute.order;
}
return result;
}
}.bind(this));
var onlyAttributeNames = attributes.map(function(attribute) {
return (typeof attribute === 'string') ? attribute : attribute.attribute;
}.bind(this));
var indexTable = tableName.split('.');
options = Utils._.extend({
indicesType: null,
indexName: Utils.inflection.underscore(indexTable[indexTable.length - 1] + '_' + onlyAttributeNames.join('_')),
parser: null
}, options || {});
return Utils._.compact([
'CREATE', options.indicesType, 'INDEX', this.quoteIdentifiers(options.indexName),
'ON', this.quoteIdentifiers(tableName), (options.indexType ? ('USING ' + options.indexType) : undefined),
'(' + transformedAttributes.join(', ') + ')'
]).join(' ');
},
showIndexQuery: function(tableName, options) { showIndexQuery: function(tableName, options) {
var query = "SELECT relname FROM pg_class WHERE oid IN ( SELECT indexrelid FROM pg_index, pg_class WHERE pg_class.relname='<%= tableName %>' AND pg_class.oid=pg_index.indrelid);"; // This is ARCANE!
var query = "SELECT i.relname AS name, ix.indisprimary AS primary, ix.indisunique AS unique, ix.indkey AS indkey, array_agg(a.attnum) as column_indexes, array_agg(a.attname) AS column_names, pg_get_indexdef(ix.indexrelid) AS definition FROM pg_class t, pg_class i, pg_index ix, pg_attribute a WHERE t.oid = ix.indrelid AND i.oid = ix.indexrelid AND a.attrelid = t.oid AND a.attnum = ANY(ix.indkey) AND t.relkind = 'r' and t.relname = '<%= tableName %>' GROUP BY i.relname, ix.indexrelid, ix.indisprimary, ix.indisunique, ix.indkey ORDER BY i.relname;";
return Utils._.template(query)({ tableName: tableName }); return Utils._.template(query)({ tableName: tableName });
}, },
......
...@@ -91,7 +91,36 @@ module.exports = (function() { ...@@ -91,7 +91,36 @@ module.exports = (function() {
return results; return results;
} }
if (self.isSelectQuery()) { if (self.isShowIndexesQuery()) {
results.forEach(function (result) {
var attributes = /ON .*? (?:USING .*?\s)?\((.*)\)/gi.exec(result.definition)[1].split(',')
, field
, attribute
, columns;
// Map column index in table to column name
columns = Utils._.zipObject(
result.column_indexes,
self.sequelize.queryInterface.QueryGenerator.fromArray(result.column_names)
);
delete result.column_indexes;
delete result.column_names;
// Indkey is the order of attributes in the index, specified by a string of attribute indexes
result.fields = result.indkey.split(' ').map(function (indKey, index) {
field = columns[indKey];
attribute = attributes[index];
return {
attribute: field,
collate: attribute.match(/COLLATE "(.*?)"/) ? /COLLATE "(.*?)"/.exec(attribute)[1] : undefined,
order: attribute.indexOf('DESC') !== -1 ? 'DESC' : attribute.indexOf('ASC') !== -1 ? 'ASC': undefined,
length: undefined,
};
});
delete result.columns;
});
return results;
} else if (self.isSelectQuery()) {
if (self.sql.toLowerCase().indexOf('select c.column_name') === 0) { if (self.sql.toLowerCase().indexOf('select c.column_name') === 0) {
result = {}; result = {};
...@@ -192,6 +221,10 @@ module.exports = (function() { ...@@ -192,6 +221,10 @@ module.exports = (function() {
return this; return this;
}; };
Query.prototype.isShowIndexesQuery = function () {
return this.sql.indexOf('pg_get_indexdef') !== -1;
};
Query.prototype.getInsertIdField = function() { Query.prototype.getInsertIdField = function() {
return 'id'; return 'id';
}; };
......
...@@ -10,10 +10,13 @@ var SqliteDialect = function(sequelize) { ...@@ -10,10 +10,13 @@ var SqliteDialect = function(sequelize) {
this.connectionManager = new ConnectionManager(this, sequelize); this.connectionManager = new ConnectionManager(this, sequelize);
}; };
SqliteDialect.prototype.supports = _.defaults({ SqliteDialect.prototype.supports = _.merge(_.cloneDeep(Abstract.prototype.supports), {
'DEFAULT': false, 'DEFAULT': false,
'DEFAULT VALUES': true 'DEFAULT VALUES': true,
}, Abstract.prototype.supports); index: {
using: false
}
});
SqliteDialect.prototype.Query = Query; SqliteDialect.prototype.Query = Query;
SqliteDialect.prototype.name = 'sqlite'; SqliteDialect.prototype.name = 'sqlite';
......
...@@ -3,7 +3,8 @@ ...@@ -3,7 +3,8 @@
var Utils = require('../../utils') var Utils = require('../../utils')
, DataTypes = require('../../data-types') , DataTypes = require('../../data-types')
, SqlString = require('../../sql-string') , SqlString = require('../../sql-string')
, Transaction = require('../../transaction'); , Transaction = require('../../transaction')
, util = require('util');
var MySqlQueryGenerator = Utils._.extend( var MySqlQueryGenerator = Utils._.extend(
Utils._.clone(require('../abstract/query-generator')), Utils._.clone(require('../abstract/query-generator')),
......
...@@ -97,14 +97,9 @@ module.exports = (function() { ...@@ -97,14 +97,9 @@ module.exports = (function() {
} else if (self.isShowOrDescribeQuery()) { } else if (self.isShowOrDescribeQuery()) {
result = results; result = results;
} else if (self.sql.indexOf('PRAGMA INDEX_LIST') !== -1) { } else if (self.sql.indexOf('PRAGMA INDEX_LIST') !== -1) {
// this is the sqlite way of getting the indexes of a table result = self.handleShowIndexesQuery(results);
result = results.map(function(result) { } else if (self.sql.indexOf('PRAGMA INDEX_INFO') !== -1) {
return { result = results;
name: result.name,
tableName: result.name.split('_')[0],
unique: (result.unique === 0)
};
});
} else if (self.sql.indexOf('PRAGMA TABLE_INFO') !== -1) { } else if (self.sql.indexOf('PRAGMA TABLE_INFO') !== -1) {
// this is the sqlite way of getting the metadata of a table // this is the sqlite way of getting the metadata of a table
result = {}; result = {};
...@@ -159,7 +154,7 @@ module.exports = (function() { ...@@ -159,7 +154,7 @@ module.exports = (function() {
if (tableName !== 'sqlite_master') { if (tableName !== 'sqlite_master') {
return new Utils.Promise(function(resolve) { return new Utils.Promise(function(resolve) {
// get the column types // get the column types
self.database.all('PRAGMA table_info(' + tableName + ')', function(err, results) { self.database.all('PRAGMA table_info(`' + tableName + '`)', function(err, results) {
if (!err) { if (!err) {
for (var i = 0, l = results.length; i < l; i++) { for (var i = 0, l = results.length; i < l; i++) {
columnTypes[tableName + '.' + results[i].name] = columnTypes[results[i].name] = results[i].type; columnTypes[tableName + '.' + results[i].name] = columnTypes[results[i].name] = results[i].type;
...@@ -178,6 +173,29 @@ module.exports = (function() { ...@@ -178,6 +173,29 @@ module.exports = (function() {
}); });
}; };
Query.prototype.handleShowIndexesQuery = function (data) {
var self = this;
// Sqlite returns indexes so the one that was defined last is returned first. Lets reverse that!
return this.sequelize.Promise.map(data.reverse(), function (item) {
item.fields = [];
item.primary = false;
item.unique = !!item.unique;
return self.run('PRAGMA INDEX_INFO(' + item.name + ')').then(function (columns) {
columns.forEach(function (column) {
item.fields[column.seqno] = {
attribute: column.name,
length: undefined,
order: undefined,
};
});
return item;
});
});
};
Query.prototype.getDatabaseMethod = function() { Query.prototype.getDatabaseMethod = function() {
if (this.isInsertQuery() || this.isUpdateQuery() || (this.sql.toLowerCase().indexOf('CREATE TEMPORARY TABLE'.toLowerCase()) !== -1) || this.options.type === QueryTypes.BULKDELETE) { if (this.isInsertQuery() || this.isUpdateQuery() || (this.sql.toLowerCase().indexOf('CREATE TEMPORARY TABLE'.toLowerCase()) !== -1) || this.options.type === QueryTypes.BULKDELETE) {
return 'run'; return 'run';
......
...@@ -389,6 +389,10 @@ module.exports = (function() { ...@@ -389,6 +389,10 @@ module.exports = (function() {
} }
}).then(function () { }).then(function () {
return self.QueryInterface.createTable(self.getTableName(options), attributes, options); return self.QueryInterface.createTable(self.getTableName(options), attributes, options);
}).then(function () {
return Promise.map(self.options.indexes, function (index) {
return self.QueryInterface.addIndex(self.getTableName(options), index.fields, index, self.tableName);
});
}).return(this); }).return(this);
}; };
......
...@@ -199,7 +199,6 @@ module.exports = (function() { ...@@ -199,7 +199,6 @@ module.exports = (function() {
}; };
var skip = options.skip || []; var skip = options.skip || [];
return self.showAllTables().then(function(tableNames) { return self.showAllTables().then(function(tableNames) {
if (self.sequelize.options.dialect === 'sqlite') { if (self.sequelize.options.dialect === 'sqlite') {
return self.sequelize.query('PRAGMA foreign_keys;').then(function(result) { return self.sequelize.query('PRAGMA foreign_keys;').then(function(result) {
...@@ -374,8 +373,29 @@ module.exports = (function() { ...@@ -374,8 +373,29 @@ module.exports = (function() {
}.bind(this)); }.bind(this));
}; };
QueryInterface.prototype.addIndex = function(tableName, attributes, options) { QueryInterface.prototype.addIndex = function(tableName, _attributes, _options, _rawTablename) {
var sql = this.QueryGenerator.addIndexQuery(tableName, attributes, options); var attributes, options, rawTablename;
// Support for passing tableName, attributes, options or tableName, options (with a fields param which is the attributes)
if (Array.isArray(_attributes)) {
attributes = _attributes;
options = _options;
rawTablename = _rawTablename;
} else {
// Support for passing an options object with a fields attribute instead of attributes, options
options = _attributes;
attributes = options.fields;
rawTablename = _options;
}
if (!rawTablename) {
// Map for backwards compat
rawTablename = tableName;
}
var sql = this.QueryGenerator.addIndexQuery(tableName, attributes, options, rawTablename);
return this.sequelize.query(sql, null, {logging: this.sequelize.options.logging}); return this.sequelize.query(sql, null, {logging: this.sequelize.options.logging});
}; };
......
...@@ -351,6 +351,13 @@ module.exports = (function() { ...@@ -351,6 +351,13 @@ module.exports = (function() {
* @param {Object} [options.name] An object with two attributes, `singular` and `plural`, which are used when this model is associated to others. * @param {Object} [options.name] An object with two attributes, `singular` and `plural`, which are used when this model is associated to others.
* @param {String} [options.name.singular=inflection.singularize(modelName)] * @param {String} [options.name.singular=inflection.singularize(modelName)]
* @param {String} [options.name.plural=inflection.pluralize(modelName)] * @param {String} [options.name.plural=inflection.pluralize(modelName)]
* @param {Array<Object>} [options.indexes]
* @param {String} [options.indexes[].name] The name of the index. Defaults to model name + _ + fields concatenated
* @param {String} [options.indexes[].type] Index type. Only used by mysql. One of `UNIQUE`, `FULLTEXT` and `SPATIAL`
* @param {String} [options.indexes[].method] The method to create the index by (`USING` statement in SQL). BTREE and HASH are supported by mysql and postgres, and postgres additionally supports GIST and GIN.
* @param {Boolean} [options.indexes[].unique=false] Should the index by unique? Can also be triggered by setting type to `UNIQUE`
* @param {Boolean} [options.indexes[].concurrently=false] PostgreSQL will build the index without taking any write locks. Postgres only
* @param {Array<String|Object} [options.indexes[].fields] An array of the fields to index. Each field can either be a string containing the name of the field, or an object with the following attributes: `attribute` (field name), `length` (create a prefix index of length chars), `order` (the direction the column should be sorted in), `collate` (the collation (sort order) for the column)
* @param {String|Boolean} [options.createdAt] Override the name of the createdAt column if a string is provided, or disable it if false. Timestamps must be true * @param {String|Boolean} [options.createdAt] Override the name of the createdAt column if a string is provided, or disable it if false. Timestamps must be true
* @param {String|Boolean} [options.updatedAt] Override the name of the updatedAt column if a string is provided, or disable it if false. Timestamps must be true * @param {String|Boolean} [options.updatedAt] Override the name of the updatedAt column if a string is provided, or disable it if false. Timestamps must be true
* @param {String|Boolean} [options.deletedAt] Override the name of the deletedAt column if a string is provided, or disable it if false. Timestamps must be true * @param {String|Boolean} [options.deletedAt] Override the name of the deletedAt column if a string is provided, or disable it if false. Timestamps must be true
...@@ -388,7 +395,8 @@ module.exports = (function() { ...@@ -388,7 +395,8 @@ module.exports = (function() {
name: { name: {
plural: Utils.inflection.pluralize(modelName), plural: Utils.inflection.pluralize(modelName),
singular: Utils.inflection.singularize(modelName) singular: Utils.inflection.singularize(modelName)
} },
indexes: [],
}, options); }, options);
options.omitNull = globalOptions.omitNull; options.omitNull = globalOptions.omitNull;
......
...@@ -1297,7 +1297,7 @@ describe(Support.getTestDialectTeaser("HasMany"), function() { ...@@ -1297,7 +1297,7 @@ describe(Support.getTestDialectTeaser("HasMany"), function() {
}); });
it('makes join table non-paranoid by default', function () { it('makes join table non-paranoid by default', function () {
var paranoidSequelize = new Sequelize('','','', { var paranoidSequelize = Support.createSequelizeInstance({
define: { define: {
paranoid: true paranoid: true
} }
......
...@@ -328,6 +328,89 @@ describe(Support.getTestDialectTeaser("DAOFactory"), function () { ...@@ -328,6 +328,89 @@ describe(Support.getTestDialectTeaser("DAOFactory"), function () {
}) })
}) })
}) })
it('should allow the user to specify indexes in options', function () {
var Model = this.sequelize.define('model', {
fieldA: Sequelize.STRING,
fieldB: Sequelize.INTEGER,
fieldC: Sequelize.STRING
}, {
indexes: [
{
name: 'a_b_uniq',
unique: true,
method: 'BTREE',
fields: ['fieldB', {attribute:'fieldA', collate: dialect === 'sqlite' ? 'RTRIM' : 'en_US', order: 'DESC', length: 5}]
},
{
type: 'FULLTEXT',
fields: ['fieldC'],
concurrently: true
},
],
engine: 'MyISAM'
})
return this.sequelize.sync().bind(this).then(function () {
return this.sequelize.queryInterface.showIndex(Model.tableName);
}).spread(function () {
var primary, idx1, idx2;
if (dialect === 'sqlite') {
// PRAGMA index_info does not return the primary index
idx1 = arguments[0];
idx2 = arguments[1];
expect(idx1.fields).to.deep.equal([
{ attribute: 'fieldB', length: undefined, order: undefined},
{ attribute: 'fieldA', length: undefined, order: undefined},
]);
expect(idx2.fields).to.deep.equal([
{ attribute: 'fieldC', length: undefined, order: undefined}
]);
} else if (dialect === 'postgres') {
// Postgres returns indexes in alphabetical order
primary = arguments[2];
idx1 = arguments[0];
idx2 = arguments[1];
expect(idx1.fields).to.deep.equal([
{ attribute: 'fieldB', length: undefined, order: undefined, collate: undefined},
{ attribute: 'fieldA', length: undefined, order: 'DESC', collate: 'en_US'},
]);
expect(idx2.fields).to.deep.equal([
{ attribute: 'fieldC', length: undefined, order: undefined, collate: undefined}
]);
} else {
// And finally mysql returns the primary first, and then the rest in the order they were defined
primary = arguments[0];
idx1 = arguments[1];
idx2 = arguments[2];
expect(primary.primary).to.be.ok;
expect(idx1.type).to.equal('BTREE');
expect(idx2.type).to.equal('FULLTEXT');
expect(idx1.fields).to.deep.equal([
{ attribute: 'fieldB', length: undefined, order: 'ASC'},
{ attribute: 'fieldA', length: 5, order: 'ASC'},
]);
expect(idx2.fields).to.deep.equal([
{ attribute: 'fieldC', length: undefined, order: undefined}
]);
}
expect(idx1.name).to.equal('a_b_uniq');
expect(idx1.unique).to.be.ok;
expect(idx2.name).to.equal('models_field_c');
expect(idx2.unique).not.to.be.ok;
});
});
}) })
describe('build', function() { describe('build', function() {
......
"use strict";
/* jshint camelcase: false */ /* jshint camelcase: false */
var chai = require('chai') var chai = require('chai')
, expect = chai.expect , expect = chai.expect
...@@ -186,7 +188,7 @@ if (Support.dialectIsMySQL()) { ...@@ -186,7 +188,7 @@ if (Support.dialectIsMySQL()) {
arguments: ['myTable', function (sequelize) { arguments: ['myTable', function (sequelize) {
return { return {
order: [[sequelize.fn('f1', sequelize.fn('f2', sequelize.col('id'))), 'DESC']] order: [[sequelize.fn('f1', sequelize.fn('f2', sequelize.col('id'))), 'DESC']]
} };
}], }],
expectation: "SELECT * FROM `myTable` ORDER BY f1(f2(`id`)) DESC;", expectation: "SELECT * FROM `myTable` ORDER BY f1(f2(`id`)) DESC;",
context: QueryGenerator, context: QueryGenerator,
...@@ -199,7 +201,7 @@ if (Support.dialectIsMySQL()) { ...@@ -199,7 +201,7 @@ if (Support.dialectIsMySQL()) {
[sequelize.fn('f1', sequelize.col('myTable.id')), 'DESC'], [sequelize.fn('f1', sequelize.col('myTable.id')), 'DESC'],
[sequelize.fn('f2', 12, 'lalala', new Date(Date.UTC(2011, 2, 27, 10, 1, 55))), 'ASC'] [sequelize.fn('f2', 12, 'lalala', new Date(Date.UTC(2011, 2, 27, 10, 1, 55))), 'ASC']
] ]
} };
}], }],
expectation: "SELECT * FROM `myTable` ORDER BY f1(`myTable`.`id`) DESC, f2(12, 'lalala', '2011-03-27 10:01:55') ASC;", expectation: "SELECT * FROM `myTable` ORDER BY f1(`myTable`.`id`) DESC, f2(12, 'lalala', '2011-03-27 10:01:55') ASC;",
context: QueryGenerator, context: QueryGenerator,
...@@ -218,7 +220,7 @@ if (Support.dialectIsMySQL()) { ...@@ -218,7 +220,7 @@ if (Support.dialectIsMySQL()) {
arguments: ['myTable', function (sequelize) { arguments: ['myTable', function (sequelize) {
return { return {
group: [sequelize.fn('YEAR', sequelize.col('createdAt'))] group: [sequelize.fn('YEAR', sequelize.col('createdAt'))]
} };
}], }],
expectation: "SELECT * FROM `myTable` GROUP BY YEAR(`createdAt`);", expectation: "SELECT * FROM `myTable` GROUP BY YEAR(`createdAt`);",
context: QueryGenerator, context: QueryGenerator,
...@@ -228,7 +230,7 @@ if (Support.dialectIsMySQL()) { ...@@ -228,7 +230,7 @@ if (Support.dialectIsMySQL()) {
arguments: ['myTable', function (sequelize) { arguments: ['myTable', function (sequelize) {
return { return {
group: [sequelize.fn('YEAR', sequelize.col('createdAt')), 'title'] group: [sequelize.fn('YEAR', sequelize.col('createdAt')), 'title']
} };
}], }],
expectation: "SELECT * FROM `myTable` GROUP BY YEAR(`createdAt`), `title`;", expectation: "SELECT * FROM `myTable` GROUP BY YEAR(`createdAt`), `title`;",
context: QueryGenerator, context: QueryGenerator,
...@@ -244,7 +246,7 @@ if (Support.dialectIsMySQL()) { ...@@ -244,7 +246,7 @@ if (Support.dialectIsMySQL()) {
attributes: ['*', [sequelize.fn('YEAR', sequelize.col('createdAt')), 'creationYear']], attributes: ['*', [sequelize.fn('YEAR', sequelize.col('createdAt')), 'creationYear']],
group: ['creationYear', 'title'], group: ['creationYear', 'title'],
having: ['creationYear > ?', 2002] having: ['creationYear > ?', 2002]
} };
}], }],
expectation: "SELECT *, YEAR(`createdAt`) AS `creationYear` FROM `myTable` GROUP BY `creationYear`, `title` HAVING creationYear > 2002;", expectation: "SELECT *, YEAR(`createdAt`) AS `creationYear` FROM `myTable` GROUP BY `creationYear`, `title` HAVING creationYear > 2002;",
context: QueryGenerator, context: QueryGenerator,
...@@ -256,7 +258,7 @@ if (Support.dialectIsMySQL()) { ...@@ -256,7 +258,7 @@ if (Support.dialectIsMySQL()) {
attributes: ['*', [sequelize.fn('YEAR', sequelize.col('createdAt')), 'creationYear']], attributes: ['*', [sequelize.fn('YEAR', sequelize.col('createdAt')), 'creationYear']],
group: ['creationYear', 'title'], group: ['creationYear', 'title'],
having: { creationYear: { gt: 2002 } } having: { creationYear: { gt: 2002 } }
} };
}], }],
expectation: "SELECT *, YEAR(`createdAt`) AS `creationYear` FROM `myTable` GROUP BY `creationYear`, `title` HAVING `creationYear` > 2002;", expectation: "SELECT *, YEAR(`createdAt`) AS `creationYear` FROM `myTable` GROUP BY `creationYear`, `title` HAVING `creationYear` > 2002;",
context: QueryGenerator, context: QueryGenerator,
...@@ -353,7 +355,7 @@ if (Support.dialectIsMySQL()) { ...@@ -353,7 +355,7 @@ if (Support.dialectIsMySQL()) {
arguments: ['myTable', function (sequelize) { arguments: ['myTable', function (sequelize) {
return { return {
foo: sequelize.fn('NOW') foo: sequelize.fn('NOW')
} };
}], }],
expectation: "INSERT INTO `myTable` (`foo`) VALUES (NOW());", expectation: "INSERT INTO `myTable` (`foo`) VALUES (NOW());",
needsSequelize: true needsSequelize: true
...@@ -431,7 +433,7 @@ if (Support.dialectIsMySQL()) { ...@@ -431,7 +433,7 @@ if (Support.dialectIsMySQL()) {
arguments: ['myTable', function (sequelize) { arguments: ['myTable', function (sequelize) {
return { return {
bar: sequelize.fn('NOW') bar: sequelize.fn('NOW')
} };
}, {name: 'foo'}], }, {name: 'foo'}],
expectation: "UPDATE `myTable` SET `bar`=NOW() WHERE `name`='foo'", expectation: "UPDATE `myTable` SET `bar`=NOW() WHERE `name`='foo'",
needsSequelize: true needsSequelize: true
...@@ -439,7 +441,7 @@ if (Support.dialectIsMySQL()) { ...@@ -439,7 +441,7 @@ if (Support.dialectIsMySQL()) {
arguments: ['myTable', function (sequelize) { arguments: ['myTable', function (sequelize) {
return { return {
bar: sequelize.col('foo') bar: sequelize.col('foo')
} };
}, {name: 'foo'}], }, {name: 'foo'}],
expectation: "UPDATE `myTable` SET `bar`=`foo` WHERE `name`='foo'", expectation: "UPDATE `myTable` SET `bar`=`foo` WHERE `name`='foo'",
needsSequelize: true needsSequelize: true
...@@ -473,27 +475,42 @@ if (Support.dialectIsMySQL()) { ...@@ -473,27 +475,42 @@ if (Support.dialectIsMySQL()) {
addIndexQuery: [ addIndexQuery: [
{ {
arguments: ['User', ['username', 'isAdmin']], arguments: ['User', ['username', 'isAdmin'], {}, 'User'],
expectation: 'CREATE INDEX user_username_is_admin ON `User` (`username`, `isAdmin`)' expectation: 'CREATE INDEX `user_username_is_admin` ON `User` (`username`, `isAdmin`)'
}, { }, {
arguments: [ arguments: [
'User', [ 'User', [
{ attribute: 'username', length: 10, order: 'ASC'}, { attribute: 'username', length: 10, order: 'ASC'},
'isAdmin' 'isAdmin'
] ],
{},
'User'
], ],
expectation: "CREATE INDEX user_username_is_admin ON `User` (`username`(10) ASC, `isAdmin`)" expectation: "CREATE INDEX `user_username_is_admin` ON `User` (`username`(10) ASC, `isAdmin`)"
}, { }, {
arguments: [ arguments: [
'User', ['username', 'isAdmin'], { parser: 'foo', indicesType: 'FULLTEXT', indexName: 'bar'} 'User', ['username', 'isAdmin'], { parser: 'foo', indicesType: 'FULLTEXT', indexName: 'bar'}, 'User'
], ],
expectation: "CREATE FULLTEXT INDEX bar ON `User` (`username`, `isAdmin`) WITH PARSER foo" expectation: "CREATE FULLTEXT INDEX `bar` ON `User` (`username`, `isAdmin`) WITH PARSER foo"
}, { }, {
arguments: [ arguments: [
'User', ['username', 'isAdmin'], { indicesType: 'UNIQUE'} 'User', ['username', 'isAdmin'], { indicesType: 'UNIQUE'}, 'User'
], ],
expectation: "CREATE UNIQUE INDEX user_username_is_admin ON `User` (`username`, `isAdmin`)" expectation: "CREATE UNIQUE INDEX `user_username_is_admin` ON `User` (`username`, `isAdmin`)"
} }, {
arguments: ['User', ['fieldB', {attribute:'fieldA', collate: 'en_US', order: 'DESC', length: 5}], {
name: 'a_b_uniq',
unique: true,
method: 'BTREE'
}, 'User'],
expectation: 'CREATE UNIQUE INDEX `a_b_uniq` USING BTREE ON `User` (`fieldB`, `fieldA`(5) DESC)'
}, {
arguments: ['User', ['fieldC'], {
type: 'FULLTEXT',
concurrently: true
}, 'User'],
expectation: 'CREATE FULLTEXT INDEX `user_field_c` ON `User` (`fieldC`)'
},
], ],
showIndexQuery: [ showIndexQuery: [
...@@ -547,26 +564,25 @@ if (Support.dialectIsMySQL()) { ...@@ -547,26 +564,25 @@ if (Support.dialectIsMySQL()) {
expectation: "`birthday` IN ('2011-07-01 10:01:55','2013-07-02 10:01:22')" expectation: "`birthday` IN ('2011-07-01 10:01:55','2013-07-02 10:01:22')"
} }
] ]
} };
_.each(suites, function(tests, suiteTitle) { _.each(suites, function(tests, suiteTitle) {
describe(suiteTitle, function() { describe(suiteTitle, function() {
tests.forEach(function(test) { tests.forEach(function(test) {
var title = test.title || 'MySQL correctly returns ' + test.expectation + ' for ' + JSON.stringify(test.arguments) var title = test.title || 'MySQL correctly returns ' + test.expectation + ' for ' + JSON.stringify(test.arguments);
it(title, function(done) { it(title, function() {
// Options would normally be set by the query interface that instantiates the query-generator, but here we specify it explicitly // Options would normally be set by the query interface that instantiates the query-generator, but here we specify it explicitly
var context = test.context || {options: {}}; var context = test.context || {options: {}};
if (test.needsSequelize) { if (test.needsSequelize) {
test.arguments[1] = test.arguments[1](this.sequelize) test.arguments[1] = test.arguments[1](this.sequelize);
} }
QueryGenerator.options = context.options QueryGenerator.options = context.options;
QueryGenerator._dialect = this.sequelize.dialect QueryGenerator._dialect = this.sequelize.dialect;
var conditions = QueryGenerator[suiteTitle].apply(QueryGenerator, test.arguments) var conditions = QueryGenerator[suiteTitle].apply(QueryGenerator, test.arguments);
expect(conditions).to.deep.equal(test.expectation) expect(conditions).to.deep.equal(test.expectation);
done() });
}) });
}) });
}) });
}) });
})
} }
"use strict";
/* jshint camelcase: false */ /* jshint camelcase: false */
var chai = require('chai') var chai = require('chai')
, expect = chai.expect , expect = chai.expect
...@@ -7,23 +9,21 @@ var chai = require('chai') ...@@ -7,23 +9,21 @@ var chai = require('chai')
, DataTypes = require(__dirname + "/../../lib/data-types") , DataTypes = require(__dirname + "/../../lib/data-types")
, moment = require('moment') , moment = require('moment')
, util = require("util") , util = require("util")
, _ = require('lodash') , _ = require('lodash');
chai.config.includeStack = true chai.config.includeStack = true;
if (dialect.match(/^postgres/)) { if (dialect.match(/^postgres/)) {
describe('[POSTGRES Specific] QueryGenerator', function() { describe('[POSTGRES Specific] QueryGenerator', function() {
beforeEach(function(done) { beforeEach(function() {
this.User = this.sequelize.define('User', { this.User = this.sequelize.define('User', {
username: DataTypes.STRING, username: DataTypes.STRING,
email: {type: DataTypes.ARRAY(DataTypes.TEXT)}, email: {type: DataTypes.ARRAY(DataTypes.TEXT)},
numbers: {type: DataTypes.ARRAY(DataTypes.FLOAT)}, numbers: {type: DataTypes.ARRAY(DataTypes.FLOAT)},
document: {type: DataTypes.HSTORE, defaultValue: '"default"=>"value"'} document: {type: DataTypes.HSTORE, defaultValue: '"default"=>"value"'}
}) });
this.User.sync({ force: true }).success(function() { return this.User.sync({ force: true });
done() });
})
})
var suites = { var suites = {
attributesToSQL: [ attributesToSQL: [
...@@ -274,7 +274,7 @@ if (dialect.match(/^postgres/)) { ...@@ -274,7 +274,7 @@ if (dialect.match(/^postgres/)) {
arguments: ['myTable', function (sequelize) { arguments: ['myTable', function (sequelize) {
return { return {
order: [[sequelize.fn('f1', sequelize.fn('f2', sequelize.col('id'))), 'DESC']] order: [[sequelize.fn('f1', sequelize.fn('f2', sequelize.col('id'))), 'DESC']]
} };
}], }],
expectation: 'SELECT * FROM "myTable" ORDER BY f1(f2("id")) DESC;', expectation: 'SELECT * FROM "myTable" ORDER BY f1(f2("id")) DESC;',
context: QueryGenerator, context: QueryGenerator,
...@@ -287,7 +287,7 @@ if (dialect.match(/^postgres/)) { ...@@ -287,7 +287,7 @@ if (dialect.match(/^postgres/)) {
[sequelize.fn('f1', sequelize.col('myTable.id')), 'DESC'], [sequelize.fn('f1', sequelize.col('myTable.id')), 'DESC'],
[sequelize.fn('f2', 12, 'lalala', new Date(Date.UTC(2011, 2, 27, 10, 1, 55))), 'ASC'] [sequelize.fn('f2', 12, 'lalala', new Date(Date.UTC(2011, 2, 27, 10, 1, 55))), 'ASC']
] ]
} };
}], }],
expectation: 'SELECT * FROM "myTable" ORDER BY f1("myTable"."id") DESC, f2(12, \'lalala\', \'2011-03-27 10:01:55.000 +00:00\') ASC;', expectation: 'SELECT * FROM "myTable" ORDER BY f1("myTable"."id") DESC, f2(12, \'lalala\', \'2011-03-27 10:01:55.000 +00:00\') ASC;',
context: QueryGenerator, context: QueryGenerator,
...@@ -304,7 +304,7 @@ if (dialect.match(/^postgres/)) { ...@@ -304,7 +304,7 @@ if (dialect.match(/^postgres/)) {
arguments: ['myTable', function (sequelize) { arguments: ['myTable', function (sequelize) {
return { return {
group: [sequelize.fn('YEAR', sequelize.col('createdAt'))] group: [sequelize.fn('YEAR', sequelize.col('createdAt'))]
} };
}], }],
expectation: "SELECT * FROM \"myTable\" GROUP BY YEAR(\"createdAt\");", expectation: "SELECT * FROM \"myTable\" GROUP BY YEAR(\"createdAt\");",
needsSequelize: true needsSequelize: true
...@@ -313,7 +313,7 @@ if (dialect.match(/^postgres/)) { ...@@ -313,7 +313,7 @@ if (dialect.match(/^postgres/)) {
arguments: ['myTable', function (sequelize) { arguments: ['myTable', function (sequelize) {
return { return {
group: [sequelize.fn('YEAR', sequelize.col('createdAt')), 'title'] group: [sequelize.fn('YEAR', sequelize.col('createdAt')), 'title']
} };
}], }],
expectation: "SELECT * FROM \"myTable\" GROUP BY YEAR(\"createdAt\"), \"title\";", expectation: "SELECT * FROM \"myTable\" GROUP BY YEAR(\"createdAt\"), \"title\";",
context: QueryGenerator, context: QueryGenerator,
...@@ -328,7 +328,7 @@ if (dialect.match(/^postgres/)) { ...@@ -328,7 +328,7 @@ if (dialect.match(/^postgres/)) {
attributes: ['*', [sequelize.fn('YEAR', sequelize.col('createdAt')), 'creationYear']], attributes: ['*', [sequelize.fn('YEAR', sequelize.col('createdAt')), 'creationYear']],
group: ['creationYear', 'title'], group: ['creationYear', 'title'],
having: ['creationYear > ?', 2002] having: ['creationYear > ?', 2002]
} };
}], }],
expectation: "SELECT *, YEAR(\"createdAt\") AS \"creationYear\" FROM \"myTable\" GROUP BY \"creationYear\", \"title\" HAVING creationYear > 2002;", expectation: "SELECT *, YEAR(\"createdAt\") AS \"creationYear\" FROM \"myTable\" GROUP BY \"creationYear\", \"title\" HAVING creationYear > 2002;",
context: QueryGenerator, context: QueryGenerator,
...@@ -340,7 +340,7 @@ if (dialect.match(/^postgres/)) { ...@@ -340,7 +340,7 @@ if (dialect.match(/^postgres/)) {
attributes: ['*', [sequelize.fn('YEAR', sequelize.col('createdAt')), 'creationYear']], attributes: ['*', [sequelize.fn('YEAR', sequelize.col('createdAt')), 'creationYear']],
group: ['creationYear', 'title'], group: ['creationYear', 'title'],
having: { creationYear: { gt: 2002 } } having: { creationYear: { gt: 2002 } }
} };
}], }],
expectation: "SELECT *, YEAR(\"createdAt\") AS \"creationYear\" FROM \"myTable\" GROUP BY \"creationYear\", \"title\" HAVING \"creationYear\" > 2002;", expectation: "SELECT *, YEAR(\"createdAt\") AS \"creationYear\" FROM \"myTable\" GROUP BY \"creationYear\", \"title\" HAVING \"creationYear\" > 2002;",
context: QueryGenerator, context: QueryGenerator,
...@@ -505,7 +505,7 @@ if (dialect.match(/^postgres/)) { ...@@ -505,7 +505,7 @@ if (dialect.match(/^postgres/)) {
arguments: ['myTable', function (sequelize) { arguments: ['myTable', function (sequelize) {
return { return {
foo: sequelize.fn('NOW') foo: sequelize.fn('NOW')
} };
}], }],
expectation: "INSERT INTO \"myTable\" (\"foo\") VALUES (NOW());", expectation: "INSERT INTO \"myTable\" (\"foo\") VALUES (NOW());",
needsSequelize: true needsSequelize: true
...@@ -698,7 +698,7 @@ if (dialect.match(/^postgres/)) { ...@@ -698,7 +698,7 @@ if (dialect.match(/^postgres/)) {
arguments: ['myTable', function (sequelize) { arguments: ['myTable', function (sequelize) {
return { return {
bar: sequelize.fn('NOW') bar: sequelize.fn('NOW')
} };
}, {name: 'foo'}], }, {name: 'foo'}],
expectation: "UPDATE \"myTable\" SET \"bar\"=NOW() WHERE \"name\"='foo'", expectation: "UPDATE \"myTable\" SET \"bar\"=NOW() WHERE \"name\"='foo'",
needsSequelize: true needsSequelize: true
...@@ -706,7 +706,7 @@ if (dialect.match(/^postgres/)) { ...@@ -706,7 +706,7 @@ if (dialect.match(/^postgres/)) {
arguments: ['myTable', function (sequelize) { arguments: ['myTable', function (sequelize) {
return { return {
bar: sequelize.col('foo') bar: sequelize.col('foo')
} };
}, {name: 'foo'}], }, {name: 'foo'}],
expectation: "UPDATE \"myTable\" SET \"bar\"=\"foo\" WHERE \"name\"='foo'", expectation: "UPDATE \"myTable\" SET \"bar\"=\"foo\" WHERE \"name\"='foo'",
needsSequelize: true needsSequelize: true
...@@ -827,29 +827,42 @@ if (dialect.match(/^postgres/)) { ...@@ -827,29 +827,42 @@ if (dialect.match(/^postgres/)) {
addIndexQuery: [ addIndexQuery: [
{ {
arguments: ['User', ['username', 'isAdmin']], arguments: ['User', ['username', 'isAdmin'], {}, 'User'],
expectation: 'CREATE INDEX \"user_username_is_admin\" ON \"User\" (\"username\", \"isAdmin\")' expectation: 'CREATE INDEX \"user_username_is_admin\" ON \"User\" (\"username\", \"isAdmin\")'
}, { }, {
arguments: [ arguments: [
'User', [ 'User', [
{ attribute: 'username', length: 10, order: 'ASC'}, { attribute: 'username', length: 10, order: 'ASC'},
'isAdmin' 'isAdmin'
] ],
{},
'User'
], ],
expectation: "CREATE INDEX \"user_username_is_admin\" ON \"User\" (\"username\"(10) ASC, \"isAdmin\")" expectation: "CREATE INDEX \"user_username_is_admin\" ON \"User\" (\"username\" ASC, \"isAdmin\")"
}, { }, {
arguments: [ arguments: ['User', ['username', 'isAdmin'], { indexName: 'bar'}, {}, 'User'],
'User', ['username', 'isAdmin'], { indicesType: 'FULLTEXT', indexName: 'bar'} expectation: "CREATE INDEX \"bar\" ON \"User\" (\"username\", \"isAdmin\")"
],
expectation: "CREATE FULLTEXT INDEX \"bar\" ON \"User\" (\"username\", \"isAdmin\")"
}, { }, {
arguments: ['mySchema.User', ['username', 'isAdmin']], arguments: ['mySchema.User', ['username', 'isAdmin'], {}, 'User'],
expectation: 'CREATE INDEX \"user_username_is_admin\" ON \"mySchema\".\"User\" (\"username\", \"isAdmin\")' expectation: 'CREATE INDEX \"user_username_is_admin\" ON \"mySchema\".\"User\" (\"username\", \"isAdmin\")'
}, {
arguments: ['User', ['fieldB', {attribute:'fieldA', collate: 'en_US', order: 'DESC', length: 5}], {
name: 'a_b_uniq',
unique: true,
method: 'BTREE'
}, 'User'],
expectation: 'CREATE UNIQUE INDEX "a_b_uniq" ON "User" USING BTREE ("fieldB", "fieldA" COLLATE "en_US" DESC)'
}, {
arguments: ['User', ['fieldC'], {
type: 'FULLTEXT',
concurrently: true
}, 'User'],
expectation: 'CREATE INDEX CONCURRENTLY "user_field_c" ON "User" ("fieldC")'
}, },
// Variants when quoteIdentifiers is false // Variants when quoteIdentifiers is false
{ {
arguments: ['User', ['username', 'isAdmin']], arguments: ['User', ['username', 'isAdmin'], {}, 'User'],
expectation: 'CREATE INDEX user_username_is_admin ON User (username, isAdmin)', expectation: 'CREATE INDEX user_username_is_admin ON User (username, isAdmin)',
context: {options: {quoteIdentifiers: false}} context: {options: {quoteIdentifiers: false}}
}, { }, {
...@@ -857,34 +870,23 @@ if (dialect.match(/^postgres/)) { ...@@ -857,34 +870,23 @@ if (dialect.match(/^postgres/)) {
'User', [ 'User', [
{ attribute: 'username', length: 10, order: 'ASC'}, { attribute: 'username', length: 10, order: 'ASC'},
'isAdmin' 'isAdmin'
] ],
{},
'User'
], ],
expectation: "CREATE INDEX user_username_is_admin ON User (username(10) ASC, isAdmin)", expectation: "CREATE INDEX user_username_is_admin ON User (username ASC, isAdmin)",
context: {options: {quoteIdentifiers: false}} context: {options: {quoteIdentifiers: false}}
}, { }, {
arguments: [ arguments: ['User', ['username', 'isAdmin'], { indexName: 'bar'}, {}, 'User'],
'User', ['username', 'isAdmin'], { indicesType: 'FULLTEXT', indexName: 'bar'} expectation: "CREATE INDEX bar ON User (username, isAdmin)",
],
expectation: "CREATE FULLTEXT INDEX bar ON User (username, isAdmin)",
context: {options: {quoteIdentifiers: false}} context: {options: {quoteIdentifiers: false}}
}, { }, {
arguments: ['mySchema.User', ['username', 'isAdmin']], arguments: ['mySchema.User', ['username', 'isAdmin'], {}, 'User'],
expectation: 'CREATE INDEX user_username_is_admin ON mySchema.User (username, isAdmin)', expectation: 'CREATE INDEX user_username_is_admin ON mySchema.User (username, isAdmin)',
context: {options: {quoteIdentifiers: false}} context: {options: {quoteIdentifiers: false}}
} }
], ],
// FIXME: not implemented
//showIndexQuery: [
// {
// arguments: ['User'],
// expectation: 'SHOW INDEX FROM \"User\"'
// }, {
// arguments: ['User', { database: 'sequelize' }],
// expectation: "SHOW INDEX FROM \"User\" FROM \"sequelize\""
// }
//],
removeIndexQuery: [ removeIndexQuery: [
{ {
arguments: ['User', 'user_foo_bar'], arguments: ['User', 'user_foo_bar'],
...@@ -953,32 +955,30 @@ if (dialect.match(/^postgres/)) { ...@@ -953,32 +955,30 @@ if (dialect.match(/^postgres/)) {
context: {options: {quoteIdentifiers: false}} context: {options: {quoteIdentifiers: false}}
} }
] ]
} };
_.each(suites, function(tests, suiteTitle) { _.each(suites, function(tests, suiteTitle) {
describe(suiteTitle, function() { describe(suiteTitle, function() {
afterEach(function(done) { afterEach(function() {
this.sequelize.options.quoteIdentifiers = true this.sequelize.options.quoteIdentifiers = true;
QueryGenerator.options.quoteIdentifiers = true QueryGenerator.options.quoteIdentifiers = true;
done() });
})
tests.forEach(function(test) { tests.forEach(function(test) {
var title = test.title || 'Postgres correctly returns ' + test.expectation + ' for ' + JSON.stringify(test.arguments) var title = test.title || 'Postgres correctly returns ' + test.expectation + ' for ' + JSON.stringify(test.arguments);
it(title, function(done) { it(title, function() {
// Options would normally be set by the query interface that instantiates the query-generator, but here we specify it explicitly // Options would normally be set by the query interface that instantiates the query-generator, but here we specify it explicitly
var context = test.context || {options: {}}; var context = test.context || {options: {}};
if (test.needsSequelize) { if (test.needsSequelize) {
test.arguments[1] = test.arguments[1](this.sequelize) test.arguments[1] = test.arguments[1](this.sequelize);
} }
QueryGenerator.options = context.options QueryGenerator.options = context.options;
QueryGenerator._dialect = this.sequelize.dialect QueryGenerator._dialect = this.sequelize.dialect;
var conditions = QueryGenerator[suiteTitle].apply(QueryGenerator, test.arguments) var conditions = QueryGenerator[suiteTitle].apply(QueryGenerator, test.arguments);
expect(conditions).to.deep.equal(test.expectation) expect(conditions).to.deep.equal(test.expectation);
done() });
}) });
}) });
}) });
}) });
})
} }
"use strict";
/* jshint multistr: true */ /* jshint multistr: true */
var chai = require('chai') var chai = require('chai')
, expect = chai.expect , expect = chai.expect
, Support = require(__dirname + '/support') , Support = require(__dirname + '/support')
, DataTypes = require(__dirname + "/../lib/data-types") , DataTypes = require(__dirname + "/../lib/data-types")
, dialect = Support.getTestDialect() , dialect = Support.getTestDialect()
, _ = require('lodash') , _ = require('lodash');
chai.config.includeStack = true chai.config.includeStack = true;
describe(Support.getTestDialectTeaser("QueryGenerators"), function () { describe(Support.getTestDialectTeaser("QueryGenerators"), function () {
describe("comments", function() { describe("comments", function() {
it("should create a comment for a column", function(done) { it("should create a comment for a column", function() {
var self = this var self = this
, User = this.sequelize.define('User', { , User = this.sequelize.define('User', {
username: {type: DataTypes.STRING, comment: 'Some lovely info for my DBA'} username: {type: DataTypes.STRING, comment: 'Some lovely info for my DBA'}
}) });
User.sync({ force: true }).success(function() { return User.sync({ force: true }).then(function() {
var sql = '' var sql = '';
if (Support.dialectIsMySQL()) { if (Support.dialectIsMySQL()) {
sql = 'SELECT COLUMN_COMMENT as cmt FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = \'' + self.sequelize.config.database + '\' AND TABLE_NAME = \'Users\' AND COLUMN_NAME = \'username\''; sql = 'SELECT COLUMN_COMMENT as cmt FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = \'' + self.sequelize.config.database + '\' AND TABLE_NAME = \'Users\' AND COLUMN_NAME = \'username\'';
} }
...@@ -30,19 +32,14 @@ describe(Support.getTestDialectTeaser("QueryGenerators"), function () { ...@@ -30,19 +32,14 @@ describe(Support.getTestDialectTeaser("QueryGenerators"), function () {
} }
else if (dialect === "sqlite") { else if (dialect === "sqlite") {
// sqlite doesn't support comments except for explicit comments in the file // sqlite doesn't support comments except for explicit comments in the file
expect(true).to.be.true expect(true).to.be.true;
return done() return;
} else {
console.log('FIXME: This dialect is not supported :(');
expect(true).to.be.true
return done()
} }
self.sequelize.query(sql, null, {raw: true}).success(function(result) { return self.sequelize.query(sql, null, {raw: true}).then(function(result) {
expect(result[0].cmt).to.equal('Some lovely info for my DBA'); expect(result[0].cmt).to.equal('Some lovely info for my DBA');
done() });
}) });
}) });
}) });
}) });
})
...@@ -32,7 +32,6 @@ describe(Support.getTestDialectTeaser("Sequelize"), function () { ...@@ -32,7 +32,6 @@ describe(Support.getTestDialectTeaser("Sequelize"), function () {
, connectionSpy = ConnectionManager.prototype.connect = chai.spy(ConnectionManager.prototype.connect); , connectionSpy = ConnectionManager.prototype.connect = chai.spy(ConnectionManager.prototype.connect);
var sequelize = Support.createSequelizeInstance({ var sequelize = Support.createSequelizeInstance({
dialect: dialect,
pool: { pool: {
minConnections: 2 minConnections: 2
} }
......
...@@ -87,7 +87,7 @@ describe(Support.getTestDialectTeaser("Sequelize#transaction"), function () { ...@@ -87,7 +87,7 @@ describe(Support.getTestDialectTeaser("Sequelize#transaction"), function () {
// how could we enforce an authentication error in sqlite? // how could we enforce an authentication error in sqlite?
} else { } else {
it("gets triggered once an error occurs", function(done) { it("gets triggered once an error occurs", function(done) {
var sequelize = Support.createSequelizeInstance({ dialect: Support.getTestDialect() }); var sequelize = Support.createSequelizeInstance();
// lets overwrite the host to get an error // lets overwrite the host to get an error
sequelize.config.username = 'foobarbaz'; sequelize.config.username = 'foobarbaz';
......
"use strict";
var chai = require('chai') var chai = require('chai')
, expect = chai.expect , expect = chai.expect
, Support = require(__dirname + '/../support') , Support = require(__dirname + '/../support')
...@@ -6,20 +8,18 @@ var chai = require('chai') ...@@ -6,20 +8,18 @@ var chai = require('chai')
, util = require("util") , util = require("util")
, _ = require('lodash') , _ = require('lodash')
, moment = require('moment') , moment = require('moment')
, QueryGenerator = require("../../lib/dialects/sqlite/query-generator") , QueryGenerator = require("../../lib/dialects/sqlite/query-generator");
chai.config.includeStack = true chai.config.includeStack = true;
if (dialect === 'sqlite') { if (dialect === 'sqlite') {
describe('[SQLITE Specific] QueryGenerator', function() { describe('[SQLITE Specific] QueryGenerator', function() {
beforeEach(function(done) { beforeEach(function() {
this.User = this.sequelize.define('User', { this.User = this.sequelize.define('User', {
username: DataTypes.STRING username: DataTypes.STRING
}) });
this.User.sync({ force: true }).success(function() { return this.User.sync({ force: true });
done() });
})
})
var suites = { var suites = {
attributesToSQL: [ attributesToSQL: [
...@@ -167,7 +167,7 @@ if (dialect === 'sqlite') { ...@@ -167,7 +167,7 @@ if (dialect === 'sqlite') {
arguments: ['myTable', function (sequelize) { arguments: ['myTable', function (sequelize) {
return { return {
order: [[sequelize.fn('f1', sequelize.fn('f2', sequelize.col('id'))), 'DESC']] order: [[sequelize.fn('f1', sequelize.fn('f2', sequelize.col('id'))), 'DESC']]
} };
}], }],
expectation: "SELECT * FROM `myTable` ORDER BY f1(f2(`id`)) DESC;", expectation: "SELECT * FROM `myTable` ORDER BY f1(f2(`id`)) DESC;",
context: QueryGenerator, context: QueryGenerator,
...@@ -180,7 +180,7 @@ if (dialect === 'sqlite') { ...@@ -180,7 +180,7 @@ if (dialect === 'sqlite') {
[sequelize.fn('f1', sequelize.col('myTable.id')), 'DESC'], [sequelize.fn('f1', sequelize.col('myTable.id')), 'DESC'],
[sequelize.fn('f2', 12, 'lalala', new Date(Date.UTC(2011, 2, 27, 10, 1, 55))), 'ASC'] [sequelize.fn('f2', 12, 'lalala', new Date(Date.UTC(2011, 2, 27, 10, 1, 55))), 'ASC']
] ]
} };
}], }],
expectation: "SELECT * FROM `myTable` ORDER BY f1(`myTable`.`id`) DESC, f2(12, 'lalala', '2011-03-27 10:01:55.000 +00:00') ASC;", expectation: "SELECT * FROM `myTable` ORDER BY f1(`myTable`.`id`) DESC, f2(12, 'lalala', '2011-03-27 10:01:55.000 +00:00') ASC;",
context: QueryGenerator, context: QueryGenerator,
...@@ -199,7 +199,7 @@ if (dialect === 'sqlite') { ...@@ -199,7 +199,7 @@ if (dialect === 'sqlite') {
arguments: ['myTable', function (sequelize) { arguments: ['myTable', function (sequelize) {
return { return {
group: [sequelize.fn('YEAR', sequelize.col('createdAt'))] group: [sequelize.fn('YEAR', sequelize.col('createdAt'))]
} };
}], }],
expectation: "SELECT * FROM `myTable` GROUP BY YEAR(`createdAt`);", expectation: "SELECT * FROM `myTable` GROUP BY YEAR(`createdAt`);",
context: QueryGenerator, context: QueryGenerator,
...@@ -209,7 +209,7 @@ if (dialect === 'sqlite') { ...@@ -209,7 +209,7 @@ if (dialect === 'sqlite') {
arguments: ['myTable', function (sequelize) { arguments: ['myTable', function (sequelize) {
return { return {
group: [sequelize.fn('YEAR', sequelize.col('createdAt')), 'title'] group: [sequelize.fn('YEAR', sequelize.col('createdAt')), 'title']
} };
}], }],
expectation: "SELECT * FROM `myTable` GROUP BY YEAR(`createdAt`), `title`;", expectation: "SELECT * FROM `myTable` GROUP BY YEAR(`createdAt`), `title`;",
context: QueryGenerator, context: QueryGenerator,
...@@ -229,7 +229,7 @@ if (dialect === 'sqlite') { ...@@ -229,7 +229,7 @@ if (dialect === 'sqlite') {
attributes: ['*', [sequelize.fn('YEAR', sequelize.col('createdAt')), 'creationYear']], attributes: ['*', [sequelize.fn('YEAR', sequelize.col('createdAt')), 'creationYear']],
group: ['creationYear', 'title'], group: ['creationYear', 'title'],
having: ['creationYear > ?', 2002] having: ['creationYear > ?', 2002]
} };
}], }],
expectation: "SELECT *, YEAR(`createdAt`) AS `creationYear` FROM `myTable` GROUP BY `creationYear`, `title` HAVING creationYear > 2002;", expectation: "SELECT *, YEAR(`createdAt`) AS `creationYear` FROM `myTable` GROUP BY `creationYear`, `title` HAVING creationYear > 2002;",
context: QueryGenerator, context: QueryGenerator,
...@@ -241,7 +241,7 @@ if (dialect === 'sqlite') { ...@@ -241,7 +241,7 @@ if (dialect === 'sqlite') {
attributes: ['*', [sequelize.fn('YEAR', sequelize.col('createdAt')), 'creationYear']], attributes: ['*', [sequelize.fn('YEAR', sequelize.col('createdAt')), 'creationYear']],
group: ['creationYear', 'title'], group: ['creationYear', 'title'],
having: { creationYear: { gt: 2002 } } having: { creationYear: { gt: 2002 } }
} };
}], }],
expectation: "SELECT *, YEAR(`createdAt`) AS `creationYear` FROM `myTable` GROUP BY `creationYear`, `title` HAVING `creationYear` > 2002;", expectation: "SELECT *, YEAR(`createdAt`) AS `creationYear` FROM `myTable` GROUP BY `creationYear`, `title` HAVING `creationYear` > 2002;",
context: QueryGenerator, context: QueryGenerator,
...@@ -341,7 +341,7 @@ if (dialect === 'sqlite') { ...@@ -341,7 +341,7 @@ if (dialect === 'sqlite') {
arguments: ['myTable', function (sequelize) { arguments: ['myTable', function (sequelize) {
return { return {
foo: sequelize.fn('NOW') foo: sequelize.fn('NOW')
} };
}], }],
expectation: "INSERT INTO `myTable` (`foo`) VALUES (NOW());", expectation: "INSERT INTO `myTable` (`foo`) VALUES (NOW());",
needsSequelize: true needsSequelize: true
...@@ -431,7 +431,7 @@ if (dialect === 'sqlite') { ...@@ -431,7 +431,7 @@ if (dialect === 'sqlite') {
arguments: ['myTable', function (sequelize) { arguments: ['myTable', function (sequelize) {
return { return {
bar: sequelize.fn('NOW') bar: sequelize.fn('NOW')
} };
}, {name: 'foo'}], }, {name: 'foo'}],
expectation: "UPDATE `myTable` SET `bar`=NOW() WHERE `name`='foo'", expectation: "UPDATE `myTable` SET `bar`=NOW() WHERE `name`='foo'",
needsSequelize: true needsSequelize: true
...@@ -439,7 +439,7 @@ if (dialect === 'sqlite') { ...@@ -439,7 +439,7 @@ if (dialect === 'sqlite') {
arguments: ['myTable', function (sequelize) { arguments: ['myTable', function (sequelize) {
return { return {
bar: sequelize.col('foo') bar: sequelize.col('foo')
} };
}, {name: 'foo'}], }, {name: 'foo'}],
expectation: "UPDATE `myTable` SET `bar`=`foo` WHERE `name`='foo'", expectation: "UPDATE `myTable` SET `bar`=`foo` WHERE `name`='foo'",
needsSequelize: true needsSequelize: true
...@@ -466,28 +466,59 @@ if (dialect === 'sqlite') { ...@@ -466,28 +466,59 @@ if (dialect === 'sqlite') {
arguments: ['myTable', {name: 'foo'}, {limit: null}], arguments: ['myTable', {name: 'foo'}, {limit: null}],
expectation: "DELETE FROM `myTable` WHERE `name`='foo'" expectation: "DELETE FROM `myTable` WHERE `name`='foo'"
} }
] ],
}
addIndexQuery: [
{
arguments: ['User', ['username', 'isAdmin'], {}, 'User'],
expectation: 'CREATE INDEX `user_username_is_admin` ON `User` (`username`, `isAdmin`)'
}, {
arguments: [
'User', [
{ attribute: 'username', length: 10, order: 'ASC'},
'isAdmin'
],
{},
'User'
],
expectation: "CREATE INDEX `user_username_is_admin` ON `User` (`username` ASC, `isAdmin`)"
}, {
arguments: ['User', ['username', 'isAdmin'], { indexName: 'bar'}, {}, 'User'],
expectation: "CREATE INDEX `bar` ON `User` (`username`, `isAdmin`)"
}, {
arguments: ['User', ['fieldB', {attribute:'fieldA', collate: 'en_US', order: 'DESC', length: 5}], {
name: 'a_b_uniq',
unique: true,
method: 'BTREE'
}, 'User'],
expectation: 'CREATE UNIQUE INDEX `a_b_uniq` ON `User` (`fieldB`, `fieldA` COLLATE `en_US` DESC)'
}, {
arguments: ['User', ['fieldC'], {
type: 'FULLTEXT',
concurrently: true
}, 'User'],
expectation: 'CREATE INDEX `user_field_c` ON `User` (`fieldC`)'
},
],
};
_.each(suites, function(tests, suiteTitle) { _.each(suites, function(tests, suiteTitle) {
describe(suiteTitle, function() { describe(suiteTitle, function() {
tests.forEach(function(test) { tests.forEach(function(test) {
var title = test.title || 'SQLite correctly returns ' + test.expectation + ' for ' + JSON.stringify(test.arguments) var title = test.title || 'SQLite correctly returns ' + test.expectation + ' for ' + JSON.stringify(test.arguments);
it(title, function(done) { it(title, function() {
// Options would normally be set by the query interface that instantiates the query-generator, but here we specify it explicitly // Options would normally be set by the query interface that instantiates the query-generator, but here we specify it explicitly
var context = test.context || {options: {}}; var context = test.context || {options: {}};
if (test.needsSequelize) { if (test.needsSequelize) {
test.arguments[1] = test.arguments[1](this.sequelize) test.arguments[1] = test.arguments[1](this.sequelize);
} }
QueryGenerator.options = context.options QueryGenerator.options = context.options;
QueryGenerator._dialect = this.sequelize.dialect QueryGenerator._dialect = this.sequelize.dialect;
var conditions = QueryGenerator[suiteTitle].apply(QueryGenerator, test.arguments) var conditions = QueryGenerator[suiteTitle].apply(QueryGenerator, test.arguments);
expect(conditions).to.deep.equal(test.expectation) expect(conditions).to.deep.equal(test.expectation);
done() });
}) });
}) });
}) });
}) });
})
} }
...@@ -68,7 +68,7 @@ var Support = { ...@@ -68,7 +68,7 @@ var Support = {
createSequelizeInstance: function(options) { createSequelizeInstance: function(options) {
options = options || {}; options = options || {};
options.dialect = options.dialect || 'mysql'; options.dialect = this.getTestDialect();
var config = Config[options.dialect]; var config = Config[options.dialect];
...@@ -187,7 +187,7 @@ var Support = { ...@@ -187,7 +187,7 @@ var Support = {
} }
}; };
var sequelize = Support.createSequelizeInstance({ dialect: Support.getTestDialect() }); var sequelize = Support.createSequelizeInstance();
// For Postgres' HSTORE functionality and to properly execute it's commands we'll need this... // For Postgres' HSTORE functionality and to properly execute it's commands we'll need this...
before(function() { before(function() {
......
...@@ -16,7 +16,6 @@ if (dialect !== 'sqlite') { ...@@ -16,7 +16,6 @@ if (dialect !== 'sqlite') {
beforeEach(function () { beforeEach(function () {
this.sequelizeWithTimezone = Support.createSequelizeInstance({ this.sequelizeWithTimezone = Support.createSequelizeInstance({
timezone: '+07:00', timezone: '+07:00',
dialect: dialect
}); });
}); });
......
Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!