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

Commit 0e543af0 by Michael Kaufman Committed by Sushant

7568 remove raw where (#7569)

* Removes support for $raw

* Removes interpretation of where array as a literal with replacements.

* Updates documentation to remove where object with literal replacements.

* Fixes some of the integration tests.

* Fixes integration tests and encapsulate subquery join where in a plain object.

* Adds unit tests for nested arrays in where object

* This should cover the rest of the diff.

* [ci skip] add BC break note to changelog

* Fixes changelog typo and removed the ternary because I edit in an abstract fashion.
1 parent 82b6c505
...@@ -68,6 +68,7 @@ ...@@ -68,6 +68,7 @@
- [REMOVED] Removes support for `{raw: 'injection goes here'}` for order and group. [#7188](https://github.com/sequelize/sequelize/issues/7188) - [REMOVED] Removes support for `{raw: 'injection goes here'}` for order and group. [#7188](https://github.com/sequelize/sequelize/issues/7188)
- [FIXED] `showIndex` breaks with newline characters [#7492](https://github.com/sequelize/sequelize/pull/7492) - [FIXED] `showIndex` breaks with newline characters [#7492](https://github.com/sequelize/sequelize/pull/7492)
- [FIXED] Update or soft delete breaks when querying on `JSON/JSONB` [#7376](https://github.com/sequelize/sequelize/issues/7376) [#7400](https://github.com/sequelize/sequelize/issues/7400) [#7444](https://github.com/sequelize/sequelize/issues/7444) - [FIXED] Update or soft delete breaks when querying on `JSON/JSONB` [#7376](https://github.com/sequelize/sequelize/issues/7376) [#7400](https://github.com/sequelize/sequelize/issues/7400) [#7444](https://github.com/sequelize/sequelize/issues/7444)
- [REMOVED] Removes support for interpretation of raw properties and values in the where object. [#7568](https://github.com/sequelize/sequelize/issues/7568)
- [FIXED] Upsert now updates all changed fields by default - [FIXED] Upsert now updates all changed fields by default
## BC breaks: ## BC breaks:
...@@ -77,6 +78,7 @@ ...@@ -77,6 +78,7 @@
- `options.order` Now only excepts values with type of array or Sequelize method. Support for string values (ie `{order: 'name DESC'}`) has been deprecated. - `options.order` Now only excepts values with type of array or Sequelize method. Support for string values (ie `{order: 'name DESC'}`) has been deprecated.
- `DataTypes.DATE` now uses `DATETIMEOFFSET` instead of `DATETIME2` sql datatype in case of MSSQL to record timezone [#5403](https://github.com/sequelize/sequelize/issues/5403) - `DataTypes.DATE` now uses `DATETIMEOFFSET` instead of `DATETIME2` sql datatype in case of MSSQL to record timezone [#5403](https://github.com/sequelize/sequelize/issues/5403)
- `DataTypes.DECIMAL` returns string for MySQL and Postgres - `DataTypes.DECIMAL` returns string for MySQL and Postgres
- `{ where: { $raw: "foo = 'bar'" } }` and `{ where: ['foo = ?', ['bar'] }` are no longer suported. Use `.literal` instead
# 4.0.0-2 # 4.0.0-2
- [ADDED] include now supports string as an argument (on top of model/association), string will expand into an association matched literally from Model.associations - [ADDED] include now supports string as an argument (on top of model/association), string will expand into an association matched literally from Model.associations
......
...@@ -162,11 +162,6 @@ Project.findAll({ where: { name: 'A Project' } }).then(function(projects) { ...@@ -162,11 +162,6 @@ Project.findAll({ where: { name: 'A Project' } }).then(function(projects) {
// projects will be an array of Project instances with the specified name // projects will be an array of Project instances with the specified name
}) })
// search with string replacements
Project.findAll({ where: ["id > ?", 25] }).then(function(projects) {
// projects will be an array of Projects having a greater id than 25
})
// search within a specific range // search within a specific range
Project.findAll({ where: { id: [1,2,3] } }).then(function(projects) { Project.findAll({ where: { id: [1,2,3] } }).then(function(projects) {
// projects will be an array of Projects having the id 1, 2 or 3 // projects will be an array of Projects having the id 1, 2 or 3
...@@ -346,7 +341,7 @@ Project.count().then(function(c) { ...@@ -346,7 +341,7 @@ Project.count().then(function(c) {
console.log("There are " + c + " projects!") console.log("There are " + c + " projects!")
}) })
Project.count({ where: ["id > ?", 25] }).then(function(c) { Project.count({ where: {'id': {$gt: 25}} }).then(function(c) {
console.log("There are " + c + " projects with an id greater than 25.") console.log("There are " + c + " projects with an id greater than 25.")
}) })
``` ```
......
...@@ -1295,7 +1295,7 @@ const QueryGenerator = { ...@@ -1295,7 +1295,7 @@ const QueryGenerator = {
const associationWhere = {}; const associationWhere = {};
associationWhere[association.identifierField] = { associationWhere[association.identifierField] = {
$raw: `${this.quoteTable(parentTableName.internalAs)}.${this.quoteIdentifier(association.sourceKeyField || association.source.primaryKeyField)}` $eq: this.sequelize.literal(`${this.quoteTable(parentTableName.internalAs)}.${this.quoteIdentifier(association.sourceKeyField || association.source.primaryKeyField)}`)
}; };
if (!topLevelInfo.options.where) { if (!topLevelInfo.options.where) {
...@@ -1903,7 +1903,7 @@ const QueryGenerator = { ...@@ -1903,7 +1903,7 @@ const QueryGenerator = {
} }
if (_.isString(where)) { if (_.isString(where)) {
throw new Error('where: "raw query" has been removed, please use where ["raw query", [replacements]]'); throw new Error('Support for `{where: \'raw query\'}` has been removed.');
} }
const items = []; const items = [];
...@@ -2026,7 +2026,7 @@ const QueryGenerator = { ...@@ -2026,7 +2026,7 @@ const QueryGenerator = {
if (Utils.canTreatArrayAsAnd(value)) { if (Utils.canTreatArrayAsAnd(value)) {
key = '$and'; key = '$and';
} else { } else {
return Utils.format(value, this.dialect); throw new Error('Support for literal replacements in the `where` object has been removed.');
} }
} }
// OR/AND/NOT grouping logic // OR/AND/NOT grouping logic
...@@ -2217,7 +2217,7 @@ const QueryGenerator = { ...@@ -2217,7 +2217,7 @@ const QueryGenerator = {
value = (value.$between || value.$notBetween).map(item => this.escape(item)).join(' AND '); value = (value.$between || value.$notBetween).map(item => this.escape(item)).join(' AND ');
} else if (value && value.$raw) { } else if (value && value.$raw) {
value = value.$raw; throw new Error('The `$raw` where property is no longer supported. Use `sequelize.literal` instead.');
} else if (value && value.$col) { } else if (value && value.$col) {
value = value.$col.split('.'); value = value.$col.split('.');
...@@ -2359,12 +2359,12 @@ const QueryGenerator = { ...@@ -2359,12 +2359,12 @@ const QueryGenerator = {
} else if (Buffer.isBuffer(smth)) { } else if (Buffer.isBuffer(smth)) {
result = this.escape(smth); result = this.escape(smth);
} else if (Array.isArray(smth)) { } else if (Array.isArray(smth)) {
if (smth.length === 0) return '1=1'; if (smth.length === 0 || smth.length > 0 && smth[0].length === 0) return '1=1';
if (Utils.canTreatArrayAsAnd(smth)) { if (Utils.canTreatArrayAsAnd(smth)) {
const _smth = { $and: smth }; const _smth = { $and: smth };
result = this.getWhereConditions(_smth, tableName, factory, options, prepend); result = this.getWhereConditions(_smth, tableName, factory, options, prepend);
} else { } else {
result = Utils.format(smth, this.dialect); throw new Error('Support for literal replacements in the `where` object has been removed.');
} }
} else if (smth === null) { } else if (smth === null) {
return this.whereItemsQuery(smth, { return this.whereItemsQuery(smth, {
......
...@@ -141,7 +141,7 @@ describe(Support.getTestDialectTeaser('BelongsToMany'), () => { ...@@ -141,7 +141,7 @@ describe(Support.getTestDialectTeaser('BelongsToMany'), () => {
it('only gets objects that fulfill options with a formatted value', function() { it('only gets objects that fulfill options with a formatted value', function() {
return this.User.find({where: {username: 'John'}}).then((john) => { return this.User.find({where: {username: 'John'}}).then((john) => {
return john.getTasks({where: ['active = ?', true]}); return john.getTasks({where: {active: true}});
}).then((tasks) => { }).then((tasks) => {
expect(tasks).to.have.length(1); expect(tasks).to.have.length(1);
}); });
......
...@@ -112,7 +112,7 @@ describe(Support.getTestDialectTeaser('BelongsTo'), () => { ...@@ -112,7 +112,7 @@ describe(Support.getTestDialectTeaser('BelongsTo'), () => {
]); ]);
}).spread((userA, userB, task) => { }).spread((userA, userB, task) => {
return task.setUserXYZ(userA).then(() => { return task.setUserXYZ(userA).then(() => {
return task.getUserXYZ({where: ['gender = ?', 'female']}); return task.getUserXYZ({where: {gender: 'female'}});
}); });
}).then((user) => { }).then((user) => {
expect(user).to.be.null; expect(user).to.be.null;
......
...@@ -876,7 +876,7 @@ describe(Support.getTestDialectTeaser('HasMany'), () => { ...@@ -876,7 +876,7 @@ describe(Support.getTestDialectTeaser('HasMany'), () => {
this.article = article; this.article = article;
return article.setLabels([label1, label2]); return article.setLabels([label1, label2]);
}).then(function() { }).then(function() {
return this.article.getLabels({where: ['until > ?', moment('2014-01-02').toDate()]}); return this.article.getLabels({where: {until: {$gt: moment('2014-01-02').toDate()}}});
}).then((labels) => { }).then((labels) => {
expect(labels).to.be.instanceof(Array); expect(labels).to.be.instanceof(Array);
expect(labels).to.have.length(1); expect(labels).to.have.length(1);
......
...@@ -108,7 +108,7 @@ describe(Support.getTestDialectTeaser('HasOne'), () => { ...@@ -108,7 +108,7 @@ describe(Support.getTestDialectTeaser('HasOne'), () => {
return User.create({ username: 'foo' }).then((user) => { return User.create({ username: 'foo' }).then((user) => {
return Task.create({ title: 'task', status: 'inactive' }).then((task) => { return Task.create({ title: 'task', status: 'inactive' }).then((task) => {
return user.setTaskXYZ(task).then(() => { return user.setTaskXYZ(task).then(() => {
return user.getTaskXYZ({where: ['status = ?', 'active']}).then((task) => { return user.getTaskXYZ({where: {status: 'active'}}).then((task) => {
expect(task).to.be.null; expect(task).to.be.null;
}); });
}); });
......
...@@ -430,7 +430,7 @@ describe(Support.getTestDialectTeaser('Instance'), () => { ...@@ -430,7 +430,7 @@ describe(Support.getTestDialectTeaser('Instance'), () => {
expect(download.finishedAt).to.not.be.ok; expect(download.finishedAt).to.not.be.ok;
return Download.findAll({ return Download.findAll({
where: dialect === 'postgres' || dialect === 'mssql' ? ['"finishedAt" IS NULL'] : ['`finishedAt` IS NULL'] where: {finishedAt: null}
}).then((downloads) => { }).then((downloads) => {
downloads.forEach((download) => { downloads.forEach((download) => {
expect(download.startedAt instanceof Date).to.be.true; expect(download.startedAt instanceof Date).to.be.true;
......
...@@ -1772,7 +1772,7 @@ describe(Support.getTestDialectTeaser('Model'), () => { ...@@ -1772,7 +1772,7 @@ describe(Support.getTestDialectTeaser('Model'), () => {
const self = this; const self = this;
return this.User.create({username: 'user1'}).then(() => { return this.User.create({username: 'user1'}).then(() => {
return self.User.create({username: 'foo'}).then(() => { return self.User.create({username: 'foo'}).then(() => {
return self.User.count({where: ["username LIKE '%us%'"]}).then((count) => { return self.User.count({where: {username: {$like: '%us%'}}}).then((count) => {
expect(count).to.equal(1); expect(count).to.equal(1);
}); });
}); });
...@@ -2545,11 +2545,15 @@ describe(Support.getTestDialectTeaser('Model'), () => { ...@@ -2545,11 +2545,15 @@ describe(Support.getTestDialectTeaser('Model'), () => {
}); });
}); });
it('should fail when array contains strings', function() {
return expect(this.User.findAll({
where: ['this is a mistake', ['dont do it!']]
})).to.eventually.be.rejectedWith(Error, 'Support for literal replacements in the `where` object has been removed.');
});
it('should not fail with an include', function() { it('should not fail with an include', function() {
return this.User.findAll({ return this.User.findAll({
where: [ where: this.sequelize.literal(this.sequelize.queryInterface.QueryGenerator.quoteIdentifiers('Projects.title') + ' = ' + this.sequelize.queryInterface.QueryGenerator.escape('republic')),
this.sequelize.queryInterface.QueryGenerator.quoteIdentifiers('Projects.title') + ' = ' + this.sequelize.queryInterface.QueryGenerator.escape('republic')
],
include: [ include: [
{model: this.Project} {model: this.Project}
] ]
...@@ -2566,9 +2570,7 @@ describe(Support.getTestDialectTeaser('Model'), () => { ...@@ -2566,9 +2570,7 @@ describe(Support.getTestDialectTeaser('Model'), () => {
} }
return this.User.findAll({ return this.User.findAll({
paranoid: false, paranoid: false,
where: [ where: this.sequelize.literal(tableName + this.sequelize.queryInterface.QueryGenerator.quoteIdentifier('deletedAt') + ' IS NOT NULL '),
tableName + this.sequelize.queryInterface.QueryGenerator.quoteIdentifier('deletedAt') + ' IS NOT NULL '
],
include: [ include: [
{model: this.Project} {model: this.Project}
] ]
......
...@@ -110,10 +110,10 @@ describe(Support.getTestDialectTeaser('Model'), () => { ...@@ -110,10 +110,10 @@ describe(Support.getTestDialectTeaser('Model'), () => {
it('treats questionmarks in an array', function() { it('treats questionmarks in an array', function() {
let test = false; let test = false;
return this.UserPrimary.findOne({ return this.UserPrimary.findOne({
where: ['specialkey = ?', 'awesome'], where: {'specialkey': 'awesome'},
logging(sql) { logging(sql) {
test = true; test = true;
expect(sql).to.match(/WHERE specialkey = N?'awesome'/); expect(sql).to.match(/WHERE ["|`|\[]UserPrimary["|`|\]]\.["|`|\[]specialkey["|`|\]] = N?'awesome'/);
} }
}).then(() => { }).then(() => {
expect(test).to.be.true; expect(test).to.be.true;
......
...@@ -182,17 +182,16 @@ describe(Support.getTestDialectTeaser('Model'), () => { ...@@ -182,17 +182,16 @@ describe(Support.getTestDialectTeaser('Model'), () => {
}); });
it('should be able to handle false/true values just fine...', function() { it('should be able to handle false/true values just fine...', function() {
const User = this.User, const User = this.User;
escapeChar = dialect === 'postgres' || dialect === 'mssql' ? '"' : '`';
return User.bulkCreate([ return User.bulkCreate([
{username: 'boo5', aBool: false}, {username: 'boo5', aBool: false},
{username: 'boo6', aBool: true} {username: 'boo6', aBool: true}
]).then(() => { ]).then(() => {
return User.findAll({where: [escapeChar + 'aBool' + escapeChar + ' = ?', false]}).then((users) => { return User.findAll({where: {aBool: false}}).then((users) => {
expect(users).to.have.length(1); expect(users).to.have.length(1);
expect(users[0].username).to.equal('boo5'); expect(users[0].username).to.equal('boo5');
return User.findAll({where: [escapeChar + 'aBool' + escapeChar + ' = ?', true]}).then((_users) => { return User.findAll({where: {aBool: true}}).then((_users) => {
expect(_users).to.have.length(1); expect(_users).to.have.length(1);
expect(_users[0].username).to.equal('boo6'); expect(_users[0].username).to.equal('boo6');
}); });
...@@ -202,7 +201,6 @@ describe(Support.getTestDialectTeaser('Model'), () => { ...@@ -202,7 +201,6 @@ describe(Support.getTestDialectTeaser('Model'), () => {
it('should be able to handle false/true values through associations as well...', function() { it('should be able to handle false/true values through associations as well...', function() {
const User = this.User, const User = this.User,
escapeChar = dialect === 'postgres' || dialect === 'mssql' ? '"' : '`',
Passports = this.sequelize.define('Passports', { Passports = this.sequelize.define('Passports', {
isActive: Sequelize.BOOLEAN isActive: Sequelize.BOOLEAN
}); });
...@@ -226,8 +224,8 @@ describe(Support.getTestDialectTeaser('Model'), () => { ...@@ -226,8 +224,8 @@ describe(Support.getTestDialectTeaser('Model'), () => {
return User.findById(2).then((_user) => { return User.findById(2).then((_user) => {
return Passports.findById(2).then((_passport) => { return Passports.findById(2).then((_passport) => {
return _user.setPassports([_passport]).then(() => { return _user.setPassports([_passport]).then(() => {
return _user.getPassports({where: [escapeChar + 'isActive' + escapeChar + ' = ?', false]}).then((theFalsePassport) => { return _user.getPassports({where: {isActive: false}}).then((theFalsePassport) => {
return user.getPassports({where: [escapeChar + 'isActive' + escapeChar + ' = ?', true]}).then((theTruePassport) => { return user.getPassports({where: {isActive: true}}).then((theTruePassport) => {
expect(theFalsePassport).to.have.length(1); expect(theFalsePassport).to.have.length(1);
expect(theFalsePassport[0].isActive).to.be.false; expect(theFalsePassport[0].isActive).to.be.false;
expect(theTruePassport).to.have.length(1); expect(theTruePassport).to.have.length(1);
...@@ -1204,9 +1202,9 @@ describe(Support.getTestDialectTeaser('Model'), () => { ...@@ -1204,9 +1202,9 @@ describe(Support.getTestDialectTeaser('Model'), () => {
}); });
}); });
it('can also handle array notation', function() { it('can also handle object notation', function() {
const self = this; const self = this;
return this.User.findAll({where: ['id = ?', this.users[1].id]}).then((users) => { return this.User.findAll({where: {id: this.users[1].id}}).then((users) => {
expect(users.length).to.equal(1); expect(users.length).to.equal(1);
expect(users[0].id).to.equal(self.users[1].id); expect(users[0].id).to.equal(self.users[1].id);
}); });
...@@ -1335,16 +1333,16 @@ describe(Support.getTestDialectTeaser('Model'), () => { ...@@ -1335,16 +1333,16 @@ describe(Support.getTestDialectTeaser('Model'), () => {
}); });
} }
it('handles where clause [only]', function() { it('handles where clause {only}', function() {
return this.User.findAndCountAll({where: ['id != ' + this.users[0].id]}).then((info) => { return this.User.findAndCountAll({where: {id: {$ne: this.users[0].id}}}).then((info) => {
expect(info.count).to.equal(2); expect(info.count).to.equal(2);
expect(Array.isArray(info.rows)).to.be.ok; expect(Array.isArray(info.rows)).to.be.ok;
expect(info.rows.length).to.equal(2); expect(info.rows.length).to.equal(2);
}); });
}); });
it('handles where clause with ordering [only]', function() { it('handles where clause with ordering {only}', function() {
return this.User.findAndCountAll({where: ['id != ' + this.users[0].id], order: [['id', 'ASC']]}).then((info) => { return this.User.findAndCountAll({where: {id: {$ne: this.users[0].id}}, order: [['id', 'ASC']]}).then((info) => {
expect(info.count).to.equal(2); expect(info.count).to.equal(2);
expect(Array.isArray(info.rows)).to.be.ok; expect(Array.isArray(info.rows)).to.be.ok;
expect(info.rows.length).to.equal(2); expect(info.rows.length).to.equal(2);
...@@ -1422,7 +1420,7 @@ describe(Support.getTestDialectTeaser('Model'), () => { ...@@ -1422,7 +1420,7 @@ describe(Support.getTestDialectTeaser('Model'), () => {
}); });
it('handles attributes', function() { it('handles attributes', function() {
return this.User.findAndCountAll({where: ['id != ' + this.users[0].id], attributes: ['data']}).then((info) => { return this.User.findAndCountAll({where: {id: {$ne: this.users[0].id}}, attributes: ['data']}).then((info) => {
expect(info.count).to.equal(2); expect(info.count).to.equal(2);
expect(Array.isArray(info.rows)).to.be.ok; expect(Array.isArray(info.rows)).to.be.ok;
expect(info.rows.length).to.equal(2); expect(info.rows.length).to.equal(2);
......
...@@ -181,10 +181,6 @@ if (dialect === 'mysql') { ...@@ -181,10 +181,6 @@ if (dialect === 'mysql') {
expectation: 'SELECT count(*) AS `count` FROM `foo`;', expectation: 'SELECT count(*) AS `count` FROM `foo`;',
context: QueryGenerator context: QueryGenerator
}, { }, {
arguments: ['myTable', {where: ["foo='bar'"]}],
expectation: "SELECT * FROM `myTable` WHERE foo='bar';",
context: QueryGenerator
}, {
arguments: ['myTable', {order: ['id']}], arguments: ['myTable', {order: ['id']}],
expectation: 'SELECT * FROM `myTable` ORDER BY `id`;', expectation: 'SELECT * FROM `myTable` ORDER BY `id`;',
context: QueryGenerator context: QueryGenerator
...@@ -293,18 +289,6 @@ if (dialect === 'mysql') { ...@@ -293,18 +289,6 @@ if (dialect === 'mysql') {
expectation: 'SELECT * FROM `myTable` GROUP BY name ORDER BY `id` DESC;', expectation: 'SELECT * FROM `myTable` GROUP BY name ORDER BY `id` DESC;',
context: QueryGenerator context: QueryGenerator
}, { }, {
title: 'HAVING clause works with string replacements',
arguments: ['myTable', function(sequelize) {
return {
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,
needsSequelize: true
}, {
title: 'HAVING clause works with where-like hash', title: 'HAVING clause works with where-like hash',
arguments: ['myTable', function(sequelize) { arguments: ['myTable', function(sequelize) {
return { return {
......
...@@ -255,9 +255,6 @@ if (dialect.match(/^postgres/)) { ...@@ -255,9 +255,6 @@ if (dialect.match(/^postgres/)) {
arguments: ['foo', { attributes: [['count(*)', 'count']] }], arguments: ['foo', { attributes: [['count(*)', 'count']] }],
expectation: 'SELECT count(*) AS \"count\" FROM \"foo\";' expectation: 'SELECT count(*) AS \"count\" FROM \"foo\";'
}, { }, {
arguments: ['myTable', {where: ["foo='bar'"]}],
expectation: "SELECT * FROM \"myTable\" WHERE foo='bar';"
}, {
arguments: ['myTable', {order: ['id']}], arguments: ['myTable', {order: ['id']}],
expectation: 'SELECT * FROM "myTable" ORDER BY "id";', expectation: 'SELECT * FROM "myTable" ORDER BY "id";',
context: QueryGenerator context: QueryGenerator
...@@ -385,18 +382,6 @@ if (dialect.match(/^postgres/)) { ...@@ -385,18 +382,6 @@ if (dialect.match(/^postgres/)) {
arguments: ['myTable', {group: ['name', 'title']}], arguments: ['myTable', {group: ['name', 'title']}],
expectation: 'SELECT * FROM \"myTable\" GROUP BY \"name\", \"title\";' expectation: 'SELECT * FROM \"myTable\" GROUP BY \"name\", \"title\";'
}, { }, {
title: 'HAVING clause works with string replacements',
arguments: ['myTable', function(sequelize) {
return {
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,
needsSequelize: true
}, {
title: 'HAVING clause works with where-like hash', title: 'HAVING clause works with where-like hash',
arguments: ['myTable', function(sequelize) { arguments: ['myTable', function(sequelize) {
return { return {
...@@ -461,10 +446,6 @@ if (dialect.match(/^postgres/)) { ...@@ -461,10 +446,6 @@ if (dialect.match(/^postgres/)) {
expectation: 'SELECT count(*) AS count FROM foo;', expectation: 'SELECT count(*) AS count FROM foo;',
context: {options: {quoteIdentifiers: false}} context: {options: {quoteIdentifiers: false}}
}, { }, {
arguments: ['myTable', {where: ["foo='bar'"]}],
expectation: "SELECT * FROM myTable WHERE foo='bar';",
context: {options: {quoteIdentifiers: false}}
}, {
arguments: ['myTable', {order: ['id DESC']}], arguments: ['myTable', {order: ['id DESC']}],
expectation: 'SELECT * FROM myTable ORDER BY id DESC;', expectation: 'SELECT * FROM myTable ORDER BY id DESC;',
context: {options: {quoteIdentifiers: false}} context: {options: {quoteIdentifiers: false}}
......
...@@ -283,18 +283,6 @@ if (dialect === 'sqlite') { ...@@ -283,18 +283,6 @@ if (dialect === 'sqlite') {
expectation: 'SELECT * FROM `myTable` GROUP BY name ORDER BY `id` DESC;', expectation: 'SELECT * FROM `myTable` GROUP BY name ORDER BY `id` DESC;',
context: QueryGenerator context: QueryGenerator
}, { }, {
title: 'HAVING clause works with string replacements',
arguments: ['myTable', function(sequelize) {
return {
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,
needsSequelize: true
}, {
title: 'HAVING clause works with where-like hash', title: 'HAVING clause works with where-like hash',
arguments: ['myTable', function(sequelize) { arguments: ['myTable', function(sequelize) {
return { return {
......
...@@ -4,6 +4,8 @@ const Support = require(__dirname + '/../support'), ...@@ -4,6 +4,8 @@ const Support = require(__dirname + '/../support'),
DataTypes = require(__dirname + '/../../../lib/data-types'), DataTypes = require(__dirname + '/../../../lib/data-types'),
Model = require(__dirname + '/../../../lib/model'), Model = require(__dirname + '/../../../lib/model'),
util = require('util'), util = require('util'),
chai = require('chai'),
expect = chai.expect,
expectsql = Support.expectsql, expectsql = Support.expectsql,
current = Support.sequelize, current = Support.sequelize,
sql = current.dialect.QueryGenerator; sql = current.dialect.QueryGenerator;
...@@ -478,14 +480,58 @@ suite(Support.getTestDialectTeaser('SQL'), () => { ...@@ -478,14 +480,58 @@ suite(Support.getTestDialectTeaser('SQL'), () => {
}); });
suite('raw query', () => { suite('raw query', () => {
test('raw replacements', () => { test('raw replacements for where', () => {
expectsql(sql.selectQuery('User', { expect(() => {
sql.selectQuery('User', {
attributes: ['*'],
where: ['name IN (?)', [1, 'test', 3, 'derp']]
});
}).to.throw(Error, 'Support for literal replacements in the `where` object has been removed.');
});
test('raw replacements for nested where', () => {
expect(() => {
sql.selectQuery('User', {
attributes: ['*'],
where: [['name IN (?)', [1, 'test', 3, 'derp']]]
});
}).to.throw(Error, 'Support for literal replacements in the `where` object has been removed.');
});
test('raw replacements for having', () => {
expect(() => {
sql.selectQuery('User', {
attributes: ['*'], attributes: ['*'],
having: ['name IN (?)', [1, 'test', 3, 'derp']] having: ['name IN (?)', [1, 'test', 3, 'derp']]
}), {
default: "SELECT * FROM [User] HAVING name IN (1,'test',3,'derp');",
mssql: "SELECT * FROM [User] HAVING name IN (1,N'test',3,N'derp');"
}); });
}).to.throw(Error, 'Support for literal replacements in the `where` object has been removed.');
});
test('raw replacements for nested having', () => {
expect(() => {
sql.selectQuery('User', {
attributes: ['*'],
having: [['name IN (?)', [1, 'test', 3, 'derp']]]
});
}).to.throw(Error, 'Support for literal replacements in the `where` object has been removed.');
});
test('raw string from where', () => {
expect(() => {
sql.selectQuery('User', {
attributes: ['*'],
where: 'name = \'something\''
});
}).to.throw(Error, 'Support for `{where: \'raw query\'}` has been removed.');
});
test('raw string from having', () => {
expect(() => {
sql.selectQuery('User', {
attributes: ['*'],
having: 'name = \'something\''
});
}).to.throw(Error, 'Support for `{where: \'raw query\'}` has been removed.');
}); });
}); });
}); });
...@@ -3,6 +3,8 @@ ...@@ -3,6 +3,8 @@
const Support = require(__dirname + '/../support'), const Support = require(__dirname + '/../support'),
DataTypes = require(__dirname + '/../../../lib/data-types'), DataTypes = require(__dirname + '/../../../lib/data-types'),
util = require('util'), util = require('util'),
chai = require('chai'),
expect = chai.expect,
expectsql = Support.expectsql, expectsql = Support.expectsql,
current = Support.sequelize, current = Support.sequelize,
sql = current.dialect.QueryGenerator; sql = current.dialect.QueryGenerator;
...@@ -397,10 +399,12 @@ suite(Support.getTestDialectTeaser('SQL'), () => { ...@@ -397,10 +399,12 @@ suite(Support.getTestDialectTeaser('SQL'), () => {
}); });
suite('$raw', () => { suite('$raw', () => {
testsql('rank', { test('should fail on $raw', () => {
expect(() => {
sql.whereItemQuery('rank', {
$raw: 'AGHJZ' $raw: 'AGHJZ'
}, { });
default: '[rank] = AGHJZ' }).to.throw(Error, 'The `$raw` where property is no longer supported. Use `sequelize.literal` instead.');
}); });
}); });
......
Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!