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

Commit 322ae24a by Jan Aagaard Meier

Made addIndexQuery more DRY

1 parent a3dbf684
......@@ -10,7 +10,15 @@ AbstractDialect.prototype.supports = {
'DEFAULT VALUES': false,
'VALUES ()': 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;
\ No newline at end of file
module.exports = AbstractDialect;
......@@ -3,7 +3,8 @@
var Utils = require('../../utils')
, SqlString = require('../../sql-string')
, Model = require('../../model')
, _ = require('lodash');
, _ = require('lodash')
, util = require('util');
module.exports = (function() {
var QueryGenerator = {
......@@ -321,7 +322,7 @@ module.exports = (function() {
/*
Returns an add index query.
Parameters:
- tableName -> Name of an existing table.
- tableName -> Name of an existing table, possibly with schema.
- attributes:
An array of attributes as string or as hash.
If the attribute is a hash, it must have the following content:
......@@ -332,9 +333,72 @@ module.exports = (function() {
- indicesType: UNIQUE|FULLTEXT|SPATIAL
- indexName: The name of the index. Default is <tableName>_<attrName1>_<attrName2>
- parser
- rawTablename, the name of the table, without schema. Used to create the name of the index
*/
addIndexQuery: function(tableName, attributes, options) {
throwMethodUndefined('addIndexQuery');
addIndexQuery: function(tableName, attributes, options, rawTablename) {
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(' ');
},
/*
......
......@@ -11,12 +11,19 @@ var MysqlDialect = function(sequelize) {
this.connectionManager.initPools();
};
MysqlDialect.prototype.supports = _.defaults({
MysqlDialect.prototype.supports = _.merge(Abstract.prototype.supports, {
'VALUES ()': true,
'LIMIT ON UPDATE': true,
lock: true,
forShare: 'LOCK IN SHARE MODE'
}, Abstract.prototype.supports);
forShare: 'LOCK IN SHARE MODE',
index: {
collate: false,
length: true,
parser: true,
type: true,
using: 1,
}
});
MysqlDialect.prototype.Query = Query;
......
......@@ -221,59 +221,6 @@ module.exports = (function() {
return 'DELETE FROM ' + table + ' WHERE ' + where + limit;
},
addIndexQuery: function(tableName, attributes, options) {
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 (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));
if (options.unique) {
options.indicesType = 'UNIQUE';
} else {
options.indicesType = options.indicesType || options.type;
}
options = Utils._.extend({
indexType: options.method || undefined,
indicesType: null,
indexName: options.name || 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) {
var sql = 'SHOW INDEX FROM <%= tableName %><%= options %>';
return Utils._.template(sql)({
......
......@@ -11,13 +11,17 @@ var PostgresDialect = function(sequelize) {
this.connectionManager.initPools();
};
PostgresDialect.prototype.supports = _.defaults({
PostgresDialect.prototype.supports = _.merge(Abstract.prototype.supports, {
'RETURNING': true,
'DEFAULT VALUES': true,
schemas: true,
lock: true,
forShare: 'FOR SHARE'
}, Abstract.prototype.supports);
forShare: 'FOR SHARE',
index: {
concurrently: true,
using: 2,
}
});
PostgresDialect.prototype.Query = Query;
......
......@@ -352,60 +352,6 @@ module.exports = (function() {
return Utils._.template(query)(replacements);
},
addIndexQuery: function(tableName, attributes, options) {
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 (attribute.collate) {
result += ' COLLATE ' + this.quoteIdentifier(attribute.collate);
}
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._.defaults(options, {
indexType: options.method || undefined,
indicesType: '',
type: '',
indexName: options.name || Utils.inflection.underscore(indexTable[indexTable.length - 1] + '_' + onlyAttributeNames.join('_')),
parser: null
});
if (options.unique || options.indicesType.toLowerCase() === 'unique' || options.type.toLowerCase() === 'unique') {
options.indicesType = 'UNIQUE';
} else {
delete options.indicesType;
}
return Utils._.compact([
'CREATE', options.indicesType, 'INDEX',
options.concurrently ? 'CONCURRENTLY' : undefined,
this.quoteIdentifiers(options.indexName),
'ON', this.quoteIdentifiers(tableName), (options.indexType ? ('USING ' + options.indexType) : undefined),
'(' + transformedAttributes.join(', ') + ')'
]).join(' ');
},
showIndexQuery: function(tableName, options) {
// 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;";
......
......@@ -10,10 +10,13 @@ var SqliteDialect = function(sequelize) {
this.connectionManager = new ConnectionManager(this, sequelize);
};
SqliteDialect.prototype.supports = _.defaults({
SqliteDialect.prototype.supports = _.merge(Abstract.prototype.supports, {
'DEFAULT': false,
'DEFAULT VALUES': true
}, Abstract.prototype.supports);
'DEFAULT VALUES': true,
index: {
using: false
}
});
SqliteDialect.prototype.Query = Query;
SqliteDialect.prototype.name = 'sqlite';
......
......@@ -306,56 +306,6 @@ module.exports = (function() {
return fields;
},
addIndexQuery: function(tableName, attributes, options) {
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 (attribute.collate) {
result += 'COLLATE ' + attribute.collate;
}
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: '',
type: '',
indexName: options.name || Utils.inflection.underscore(tableName + '_' + onlyAttributeNames.join('_')),
parser: null
}, options);
if (options.unique || options.indicesType.toLowerCase() === 'unique' || options.type.toLowerCase() === 'unique') {
options.indicesType = 'UNIQUE';
} else {
delete options.indicesType;
}
return Utils._.compact([
'CREATE', options.indicesType, 'INDEX', options.indexName,
'ON', this.quoteIdentifiers(tableName), '(' + transformedAttributes.join(', ') + ')'
]).join(' ');
},
showIndexQuery: function(tableName) {
var sql = "PRAGMA INDEX_LIST(<%= tableName %>)";
return Utils._.template(sql, { tableName: this.quoteIdentifiers(tableName) });
......
......@@ -391,7 +391,7 @@ module.exports = (function() {
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);
return self.QueryInterface.addIndex(self.getTableName(options), index.fields, index, self.tableName);
});
}).return(this);
};
......
......@@ -373,8 +373,29 @@ module.exports = (function() {
}.bind(this));
};
QueryInterface.prototype.addIndex = function(tableName, attributes, options) {
var sql = this.QueryGenerator.addIndexQuery(tableName, attributes, options);
QueryInterface.prototype.addIndex = function(tableName, _attributes, _options, _rawTablename) {
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});
};
......
"use strict";
/* jshint camelcase: false */
var chai = require('chai')
, expect = chai.expect
......@@ -186,7 +188,7 @@ if (Support.dialectIsMySQL()) {
arguments: ['myTable', function (sequelize) {
return {
order: [[sequelize.fn('f1', sequelize.fn('f2', sequelize.col('id'))), 'DESC']]
}
};
}],
expectation: "SELECT * FROM `myTable` ORDER BY f1(f2(`id`)) DESC;",
context: QueryGenerator,
......@@ -199,7 +201,7 @@ if (Support.dialectIsMySQL()) {
[sequelize.fn('f1', sequelize.col('myTable.id')), 'DESC'],
[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;",
context: QueryGenerator,
......@@ -218,7 +220,7 @@ if (Support.dialectIsMySQL()) {
arguments: ['myTable', function (sequelize) {
return {
group: [sequelize.fn('YEAR', sequelize.col('createdAt'))]
}
};
}],
expectation: "SELECT * FROM `myTable` GROUP BY YEAR(`createdAt`);",
context: QueryGenerator,
......@@ -228,7 +230,7 @@ if (Support.dialectIsMySQL()) {
arguments: ['myTable', function (sequelize) {
return {
group: [sequelize.fn('YEAR', sequelize.col('createdAt')), 'title']
}
};
}],
expectation: "SELECT * FROM `myTable` GROUP BY YEAR(`createdAt`), `title`;",
context: QueryGenerator,
......@@ -244,7 +246,7 @@ if (Support.dialectIsMySQL()) {
attributes: ['*', [sequelize.fn('YEAR', sequelize.col('createdAt')), 'creationYear']],
group: ['creationYear', 'title'],
having: ['creationYear > ?', 2002]
}
};
}],
expectation: "SELECT *, YEAR(`createdAt`) AS `creationYear` FROM `myTable` GROUP BY `creationYear`, `title` HAVING creationYear > 2002;",
context: QueryGenerator,
......@@ -256,7 +258,7 @@ if (Support.dialectIsMySQL()) {
attributes: ['*', [sequelize.fn('YEAR', sequelize.col('createdAt')), 'creationYear']],
group: ['creationYear', 'title'],
having: { creationYear: { gt: 2002 } }
}
};
}],
expectation: "SELECT *, YEAR(`createdAt`) AS `creationYear` FROM `myTable` GROUP BY `creationYear`, `title` HAVING `creationYear` > 2002;",
context: QueryGenerator,
......@@ -353,7 +355,7 @@ if (Support.dialectIsMySQL()) {
arguments: ['myTable', function (sequelize) {
return {
foo: sequelize.fn('NOW')
}
};
}],
expectation: "INSERT INTO `myTable` (`foo`) VALUES (NOW());",
needsSequelize: true
......@@ -431,7 +433,7 @@ if (Support.dialectIsMySQL()) {
arguments: ['myTable', function (sequelize) {
return {
bar: sequelize.fn('NOW')
}
};
}, {name: 'foo'}],
expectation: "UPDATE `myTable` SET `bar`=NOW() WHERE `name`='foo'",
needsSequelize: true
......@@ -439,7 +441,7 @@ if (Support.dialectIsMySQL()) {
arguments: ['myTable', function (sequelize) {
return {
bar: sequelize.col('foo')
}
};
}, {name: 'foo'}],
expectation: "UPDATE `myTable` SET `bar`=`foo` WHERE `name`='foo'",
needsSequelize: true
......@@ -473,27 +475,42 @@ if (Support.dialectIsMySQL()) {
addIndexQuery: [
{
arguments: ['User', ['username', 'isAdmin']],
expectation: 'CREATE INDEX user_username_is_admin ON `User` (`username`, `isAdmin`)'
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`(10) ASC, `isAdmin`)"
expectation: "CREATE INDEX `user_username_is_admin` ON `User` (`username`(10) ASC, `isAdmin`)"
}, {
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: [
'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: [
......@@ -547,26 +564,25 @@ if (Support.dialectIsMySQL()) {
expectation: "`birthday` IN ('2011-07-01 10:01:55','2013-07-02 10:01:22')"
}
]
}
};
_.each(suites, function(tests, suiteTitle) {
describe(suiteTitle, function() {
tests.forEach(function(test) {
var title = test.title || 'MySQL correctly returns ' + test.expectation + ' for ' + JSON.stringify(test.arguments)
it(title, function(done) {
var title = test.title || 'MySQL correctly returns ' + test.expectation + ' for ' + JSON.stringify(test.arguments);
it(title, function() {
// 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: {}};
if (test.needsSequelize) {
test.arguments[1] = test.arguments[1](this.sequelize)
test.arguments[1] = test.arguments[1](this.sequelize);
}
QueryGenerator.options = context.options
QueryGenerator._dialect = this.sequelize.dialect
var conditions = QueryGenerator[suiteTitle].apply(QueryGenerator, test.arguments)
expect(conditions).to.deep.equal(test.expectation)
done()
})
})
})
})
})
QueryGenerator.options = context.options;
QueryGenerator._dialect = this.sequelize.dialect;
var conditions = QueryGenerator[suiteTitle].apply(QueryGenerator, test.arguments);
expect(conditions).to.deep.equal(test.expectation);
});
});
});
});
});
}
"use strict";
/* jshint camelcase: false */
var chai = require('chai')
, expect = chai.expect
......@@ -7,23 +9,21 @@ var chai = require('chai')
, DataTypes = require(__dirname + "/../../lib/data-types")
, moment = require('moment')
, util = require("util")
, _ = require('lodash')
, _ = require('lodash');
chai.config.includeStack = true
chai.config.includeStack = true;
if (dialect.match(/^postgres/)) {
describe('[POSTGRES Specific] QueryGenerator', function() {
beforeEach(function(done) {
beforeEach(function() {
this.User = this.sequelize.define('User', {
username: DataTypes.STRING,
email: {type: DataTypes.ARRAY(DataTypes.TEXT)},
numbers: {type: DataTypes.ARRAY(DataTypes.FLOAT)},
document: {type: DataTypes.HSTORE, defaultValue: '"default"=>"value"'}
})
this.User.sync({ force: true }).success(function() {
done()
})
})
});
return this.User.sync({ force: true });
});
var suites = {
attributesToSQL: [
......@@ -274,7 +274,7 @@ if (dialect.match(/^postgres/)) {
arguments: ['myTable', function (sequelize) {
return {
order: [[sequelize.fn('f1', sequelize.fn('f2', sequelize.col('id'))), 'DESC']]
}
};
}],
expectation: 'SELECT * FROM "myTable" ORDER BY f1(f2("id")) DESC;',
context: QueryGenerator,
......@@ -287,7 +287,7 @@ if (dialect.match(/^postgres/)) {
[sequelize.fn('f1', sequelize.col('myTable.id')), 'DESC'],
[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;',
context: QueryGenerator,
......@@ -304,7 +304,7 @@ if (dialect.match(/^postgres/)) {
arguments: ['myTable', function (sequelize) {
return {
group: [sequelize.fn('YEAR', sequelize.col('createdAt'))]
}
};
}],
expectation: "SELECT * FROM \"myTable\" GROUP BY YEAR(\"createdAt\");",
needsSequelize: true
......@@ -313,7 +313,7 @@ if (dialect.match(/^postgres/)) {
arguments: ['myTable', function (sequelize) {
return {
group: [sequelize.fn('YEAR', sequelize.col('createdAt')), 'title']
}
};
}],
expectation: "SELECT * FROM \"myTable\" GROUP BY YEAR(\"createdAt\"), \"title\";",
context: QueryGenerator,
......@@ -328,7 +328,7 @@ if (dialect.match(/^postgres/)) {
attributes: ['*', [sequelize.fn('YEAR', sequelize.col('createdAt')), 'creationYear']],
group: ['creationYear', 'title'],
having: ['creationYear > ?', 2002]
}
};
}],
expectation: "SELECT *, YEAR(\"createdAt\") AS \"creationYear\" FROM \"myTable\" GROUP BY \"creationYear\", \"title\" HAVING creationYear > 2002;",
context: QueryGenerator,
......@@ -340,7 +340,7 @@ if (dialect.match(/^postgres/)) {
attributes: ['*', [sequelize.fn('YEAR', sequelize.col('createdAt')), 'creationYear']],
group: ['creationYear', 'title'],
having: { creationYear: { gt: 2002 } }
}
};
}],
expectation: "SELECT *, YEAR(\"createdAt\") AS \"creationYear\" FROM \"myTable\" GROUP BY \"creationYear\", \"title\" HAVING \"creationYear\" > 2002;",
context: QueryGenerator,
......@@ -505,7 +505,7 @@ if (dialect.match(/^postgres/)) {
arguments: ['myTable', function (sequelize) {
return {
foo: sequelize.fn('NOW')
}
};
}],
expectation: "INSERT INTO \"myTable\" (\"foo\") VALUES (NOW());",
needsSequelize: true
......@@ -698,7 +698,7 @@ if (dialect.match(/^postgres/)) {
arguments: ['myTable', function (sequelize) {
return {
bar: sequelize.fn('NOW')
}
};
}, {name: 'foo'}],
expectation: "UPDATE \"myTable\" SET \"bar\"=NOW() WHERE \"name\"='foo'",
needsSequelize: true
......@@ -706,7 +706,7 @@ if (dialect.match(/^postgres/)) {
arguments: ['myTable', function (sequelize) {
return {
bar: sequelize.col('foo')
}
};
}, {name: 'foo'}],
expectation: "UPDATE \"myTable\" SET \"bar\"=\"foo\" WHERE \"name\"='foo'",
needsSequelize: true
......@@ -827,29 +827,42 @@ if (dialect.match(/^postgres/)) {
addIndexQuery: [
{
arguments: ['User', ['username', 'isAdmin']],
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'}
],
arguments: ['User', ['username', 'isAdmin'], { indexName: 'bar'}, {}, 'User'],
expectation: "CREATE 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\")'
}, {
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
{
arguments: ['User', ['username', 'isAdmin']],
arguments: ['User', ['username', 'isAdmin'], {}, 'User'],
expectation: 'CREATE INDEX user_username_is_admin ON User (username, isAdmin)',
context: {options: {quoteIdentifiers: false}}
}, {
......@@ -857,34 +870,23 @@ if (dialect.match(/^postgres/)) {
'User', [
{ attribute: 'username', length: 10, order: 'ASC'},
'isAdmin'
]
],
{},
'User'
],
expectation: "CREATE INDEX user_username_is_admin ON User (username ASC, isAdmin)",
context: {options: {quoteIdentifiers: false}}
}, {
arguments: [
'User', ['username', 'isAdmin'], { indexName: 'bar'}
],
arguments: ['User', ['username', 'isAdmin'], { indexName: 'bar'}, {}, 'User'],
expectation: "CREATE INDEX bar ON User (username, isAdmin)",
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)',
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: [
{
arguments: ['User', 'user_foo_bar'],
......@@ -953,32 +955,30 @@ if (dialect.match(/^postgres/)) {
context: {options: {quoteIdentifiers: false}}
}
]
}
};
_.each(suites, function(tests, suiteTitle) {
describe(suiteTitle, function() {
afterEach(function(done) {
this.sequelize.options.quoteIdentifiers = true
QueryGenerator.options.quoteIdentifiers = true
done()
})
afterEach(function() {
this.sequelize.options.quoteIdentifiers = true;
QueryGenerator.options.quoteIdentifiers = true;
});
tests.forEach(function(test) {
var title = test.title || 'Postgres correctly returns ' + test.expectation + ' for ' + JSON.stringify(test.arguments)
it(title, function(done) {
var title = test.title || 'Postgres correctly returns ' + test.expectation + ' for ' + JSON.stringify(test.arguments);
it(title, function() {
// 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: {}};
if (test.needsSequelize) {
test.arguments[1] = test.arguments[1](this.sequelize)
test.arguments[1] = test.arguments[1](this.sequelize);
}
QueryGenerator.options = context.options
QueryGenerator._dialect = this.sequelize.dialect
var conditions = QueryGenerator[suiteTitle].apply(QueryGenerator, test.arguments)
expect(conditions).to.deep.equal(test.expectation)
done()
})
})
})
})
})
QueryGenerator.options = context.options;
QueryGenerator._dialect = this.sequelize.dialect;
var conditions = QueryGenerator[suiteTitle].apply(QueryGenerator, test.arguments);
expect(conditions).to.deep.equal(test.expectation);
});
});
});
});
});
}
"use strict";
var chai = require('chai')
, expect = chai.expect
, Support = require(__dirname + '/../support')
......@@ -6,20 +8,18 @@ var chai = require('chai')
, util = require("util")
, _ = require('lodash')
, 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') {
describe('[SQLITE Specific] QueryGenerator', function() {
beforeEach(function(done) {
beforeEach(function() {
this.User = this.sequelize.define('User', {
username: DataTypes.STRING
})
this.User.sync({ force: true }).success(function() {
done()
})
})
});
return this.User.sync({ force: true });
});
var suites = {
attributesToSQL: [
......@@ -167,7 +167,7 @@ if (dialect === 'sqlite') {
arguments: ['myTable', function (sequelize) {
return {
order: [[sequelize.fn('f1', sequelize.fn('f2', sequelize.col('id'))), 'DESC']]
}
};
}],
expectation: "SELECT * FROM `myTable` ORDER BY f1(f2(`id`)) DESC;",
context: QueryGenerator,
......@@ -180,7 +180,7 @@ if (dialect === 'sqlite') {
[sequelize.fn('f1', sequelize.col('myTable.id')), 'DESC'],
[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;",
context: QueryGenerator,
......@@ -199,7 +199,7 @@ if (dialect === 'sqlite') {
arguments: ['myTable', function (sequelize) {
return {
group: [sequelize.fn('YEAR', sequelize.col('createdAt'))]
}
};
}],
expectation: "SELECT * FROM `myTable` GROUP BY YEAR(`createdAt`);",
context: QueryGenerator,
......@@ -209,7 +209,7 @@ if (dialect === 'sqlite') {
arguments: ['myTable', function (sequelize) {
return {
group: [sequelize.fn('YEAR', sequelize.col('createdAt')), 'title']
}
};
}],
expectation: "SELECT * FROM `myTable` GROUP BY YEAR(`createdAt`), `title`;",
context: QueryGenerator,
......@@ -229,7 +229,7 @@ if (dialect === 'sqlite') {
attributes: ['*', [sequelize.fn('YEAR', sequelize.col('createdAt')), 'creationYear']],
group: ['creationYear', 'title'],
having: ['creationYear > ?', 2002]
}
};
}],
expectation: "SELECT *, YEAR(`createdAt`) AS `creationYear` FROM `myTable` GROUP BY `creationYear`, `title` HAVING creationYear > 2002;",
context: QueryGenerator,
......@@ -241,7 +241,7 @@ if (dialect === 'sqlite') {
attributes: ['*', [sequelize.fn('YEAR', sequelize.col('createdAt')), 'creationYear']],
group: ['creationYear', 'title'],
having: { creationYear: { gt: 2002 } }
}
};
}],
expectation: "SELECT *, YEAR(`createdAt`) AS `creationYear` FROM `myTable` GROUP BY `creationYear`, `title` HAVING `creationYear` > 2002;",
context: QueryGenerator,
......@@ -341,7 +341,7 @@ if (dialect === 'sqlite') {
arguments: ['myTable', function (sequelize) {
return {
foo: sequelize.fn('NOW')
}
};
}],
expectation: "INSERT INTO `myTable` (`foo`) VALUES (NOW());",
needsSequelize: true
......@@ -431,7 +431,7 @@ if (dialect === 'sqlite') {
arguments: ['myTable', function (sequelize) {
return {
bar: sequelize.fn('NOW')
}
};
}, {name: 'foo'}],
expectation: "UPDATE `myTable` SET `bar`=NOW() WHERE `name`='foo'",
needsSequelize: true
......@@ -439,7 +439,7 @@ if (dialect === 'sqlite') {
arguments: ['myTable', function (sequelize) {
return {
bar: sequelize.col('foo')
}
};
}, {name: 'foo'}],
expectation: "UPDATE `myTable` SET `bar`=`foo` WHERE `name`='foo'",
needsSequelize: true
......@@ -466,28 +466,59 @@ if (dialect === 'sqlite') {
arguments: ['myTable', {name: 'foo'}, {limit: null}],
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) {
describe(suiteTitle, function() {
tests.forEach(function(test) {
var title = test.title || 'SQLite correctly returns ' + test.expectation + ' for ' + JSON.stringify(test.arguments)
it(title, function(done) {
var title = test.title || 'SQLite correctly returns ' + test.expectation + ' for ' + JSON.stringify(test.arguments);
it(title, function() {
// 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: {}};
if (test.needsSequelize) {
test.arguments[1] = test.arguments[1](this.sequelize)
test.arguments[1] = test.arguments[1](this.sequelize);
}
QueryGenerator.options = context.options
QueryGenerator._dialect = this.sequelize.dialect
var conditions = QueryGenerator[suiteTitle].apply(QueryGenerator, test.arguments)
expect(conditions).to.deep.equal(test.expectation)
done()
})
})
})
})
})
QueryGenerator.options = context.options;
QueryGenerator._dialect = this.sequelize.dialect;
var conditions = QueryGenerator[suiteTitle].apply(QueryGenerator, test.arguments);
expect(conditions).to.deep.equal(test.expectation);
});
});
});
});
});
}
Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!