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

Commit 6acb13dd by Joel Trost Committed by Matt Broadstone

Passes "and-or-where" tests

1 parent ba5e688e
......@@ -178,6 +178,7 @@ module.exports = (function() {
//console.log('here', where);
var query = [
SqlGenerator.updateSql(tableName, attrValueHash, attributes),
'WHERE',
this.getWhereConditions(where)
].join(' ') + ';';
console.log(query);
......@@ -355,7 +356,14 @@ module.exports = (function() {
Split an identifier into .-separated tokens and quote each part
*/
quoteIdentifiers: function(identifiers, force) {
throwMethodUndefined('quoteIdentifiers');
if (identifiers.indexOf('.') !== -1) {
identifiers = identifiers.split('.');
return SqlGenerator.quoteIdentifier(
identifiers.slice(0, identifiers.length - 1).join('.'))
+ '.' + SqlGenerator.quoteIdentifier(identifiers[identifiers.length - 1]);
} else {
return SqlGenerator.quoteIdentifier(identifiers);
}
},
/*
......@@ -421,6 +429,7 @@ module.exports = (function() {
}
}
if(options.hasOwnProperty('where')){
query.push('WHERE');
query.push(this.getWhereConditions(options.where, model.name, model, options));
}
//console.log(query.join(' ') + ';');
......@@ -447,8 +456,8 @@ module.exports = (function() {
if (options.parent) {
return;
}
return '';
//return 'SET SESSION TRANSACTION ISOLATION LEVEL ' + value + ';';
return 'SET TRANSACTION ISOLATION LEVEL ' + value + ';';
},
/**
* Returns a query that starts a transaction.
......@@ -459,10 +468,10 @@ module.exports = (function() {
*/
startTransactionQuery: function(transaction, options) {
if (options.parent) {
return 'SAVEPOINT ' + this.quoteIdentifier(transaction.name) + ';';
return 'SAVE TRANSACTION ' + this.quoteIdentifier(transaction.name) + ';';
}
return '';
//return 'BEGIN TRY\nBEGIN TRANSACTION';
return 'BEGIN TRANSACTION';
},
/**
* Returns a query that commits a transaction.
......@@ -475,7 +484,7 @@ module.exports = (function() {
return;
}
return 'COMMIT;';
return 'COMMIT TRANSACTION;';
},
/**
......@@ -487,10 +496,10 @@ module.exports = (function() {
*/
rollbackTransactionQuery: function(transaction, options) {
if (options.parent) {
return 'ROLLBACK TO SAVEPOINT ' + this.quoteIdentifier(transaction.name) + ';';
return 'ROLLBACK TRANSACTION ' + this.quoteIdentifier(transaction.name) + ';';
}
return 'ROLLBACK;';
return 'ROLLBACK TRANSACTION';
},
addLimitAndOffset: function(options, query) {
......@@ -513,21 +522,186 @@ module.exports = (function() {
/*
Takes something and transforms it into values of a where condition.
*/
getWhereConditions: function(where, tableName, model, options, prepend) {
//console.log('where:', model);
//console.log('logic', where);
//console.log('options', options);
/*
Takes something and transforms it into values of a where condition.
*/
getWhereConditions: function(smth, tableName, factory, options, prepend) {
var result = null
, where = {}
, self = this;
if (Array.isArray(tableName)) {
tableName = tableName[0];
if (Array.isArray(tableName)) {
tableName = tableName[1];
}
}
if(where){
return SqlGenerator.getWhereClause(where, tableName);
}else{
return '';
options = options || {};
if (typeof prepend === 'undefined') {
prepend = true;
}
if (smth && smth._isSequelizeMethod === true) { // Checking a property is cheaper than a lot of instanceof calls
result = this.handleSequelizeMethod(smth, tableName, factory, options, prepend);
} else if (Utils._.isPlainObject(smth)) {
if (prepend) {
if (tableName) options.keysEscaped = true;
smth = this.prependTableNameToHash(tableName, smth);
}
result = this.hashToWhereConditions(smth, factory, options);
} else if (typeof smth === 'number') {
var primaryKeys = !!factory ? Object.keys(factory.primaryKeys) : [];
if (primaryKeys.length > 0) {
// Since we're just a number, assume only the first key
primaryKeys = primaryKeys[0];
} else {
primaryKeys = 'id';
}
where[primaryKeys] = smth;
if (tableName) options.keysEscaped = true;
smth = this.prependTableNameToHash(tableName, where);
result = this.hashToWhereConditions(smth);
} else if (typeof smth === 'string') {
result = smth;
} else if (Buffer.isBuffer(smth)) {
result = this.escape(smth);
} else if (Array.isArray(smth)) {
if (Utils.canTreatArrayAsAnd(smth)) {
var _smth = self.sequelize.and.apply(null, smth);
result = self.getWhereConditions(_smth, tableName, factory, options, prepend);
} else {
result = Utils.format(smth, this.dialect);
}
} else if (smth === null) {
result = '1=1';
}
return result ? result : '1=1';
},
// getWhereConditions: function(where, tableName, model, options, prepend) {
// //console.log('where:', model);
// console.log('logic', where);
// //console.log('options', options);
// if(where){
// return SqlGenerator.getWhereClause(where, tableName);
// }else{
// return '';
// }
// },
handleSequelizeMethod: function (smth, tableName, factory, options, prepend) {
var self = this
, result;
if ((smth instanceof Utils.and) || (smth instanceof Utils.or)) {
var connector = (smth instanceof Utils.and) ? ' AND ' : ' OR ';
result = smth.args.filter(function(arg) {
return arg !== undefined;
}).map(function(arg) {
return self.getWhereConditions(arg, tableName, factory, options, prepend);
}).join(connector);
result = result.length && '(' + result + ')' || undefined;
} else if (smth instanceof Utils.where) {
var value = smth.logic
, key
, logic
, _result = []
, _value;
if (smth.attribute._isSequelizeMethod) {
key = this.getWhereConditions(smth.attribute, tableName, factory, options, prepend);
} else {
key = this.quoteTable(smth.attribute.Model.name) + '.' + this.quoteIdentifier(smth.attribute.fieldName);
}
if (value._isSequelizeMethod) {
value = this.getWhereConditions(value, tableName, factory, options, prepend);
result = (value === 'NULL') ? key + ' IS NULL' : [key, value].join(smth.comparator);
} else if (_.isObject(value)) {
if (value.join) {
//using as sentinel for join column => value
result = [key, value.join].join('=');
} else {
for (logic in value) {
_result.push([key, this.escape(value[logic])].join(' ' + Utils.getWhereLogic(logic, value[logic]) + ' '));
}
result = _result.join(' AND ');
}
} else {
if (typeof value === 'boolean') {
value = this.booleanValue(value);
} else {
value = this.escape(value);
}
result = (value === 'NULL') ? key + ' IS NULL' : [key, value].join(' ' + smth.comparator + ' ');
}
} else if (smth instanceof Utils.literal) {
result = smth.val;
} else if (smth instanceof Utils.cast) {
if (smth.val._isSequelizeMethod) {
result = this.handleSequelizeMethod(smth.val, tableName, factory, options, prepend);
} else {
result = this.escape(smth.val);
}
result = 'CAST(' + result + ' AS ' + smth.type.toUpperCase() + ')';
} else if (smth instanceof Utils.fn) {
result = smth.fn + '(' + smth.args.map(function(arg) {
if (arg._isSequelizeMethod) {
return self.handleSequelizeMethod(arg, tableName, factory, options, prepend);
} else {
return self.escape(arg);
}
}).join(', ') + ')';
} else if (smth instanceof Utils.col) {
if (Array.isArray(smth.col)) {
if (!factory) {
throw new Error('Cannot call Sequelize.col() with array outside of order / group clause');
}
} else if (smth.col.indexOf('*') === 0) {
return '*';
}
return this.quote(smth.col, factory);
} else {
result = smth.toString(this, factory);
}
return result;
},
prependTableNameToHash: function(tableName, hash) {
throwMethodUndefined('prependTableNameToHash');
if (tableName) {
var _hash = {};
for (var key in hash) {
if (key.indexOf('.') === -1) {
if (tableName instanceof Utils.literal) {
_hash[tableName.val + '.' + SqlGenerator.quoteIdentifier(key)] = hash[key];
} else {
_hash[SqlGenerator.quoteIdentifier(tableName) + '.' + SqlGenerator.quoteIdentifier(key)] = hash[key];
}
} else {
_hash[this.quoteIdentifiers(key)] = hash[key];
}
}
return _hash;
} else {
return hash;
}
},
findAssociation: function(attribute, dao) {
......@@ -539,7 +713,23 @@ module.exports = (function() {
},
isAssociationFilter: function(filterStr, dao, options) {
throwMethodUndefined('isAssociationFilter');
if (!dao) {
return false;
}
var pattern = /^[a-z][a-zA-Z0-9]+(\.[a-z][a-zA-Z0-9]+)+$/;
if (!pattern.test(filterStr)) return false;
var associationParts = filterStr.split('.')
, attributePart = associationParts.pop()
, self = this;
return associationParts.every(function(attribute) {
var association = self.findAssociation(attribute, dao);
if (!association) return false;
dao = association.target;
return !!dao;
}) && dao.rawAttributes.hasOwnProperty(attributePart);
},
getAssociationFilterColumn: function(filterStr, dao, options) {
......@@ -559,7 +749,67 @@ module.exports = (function() {
The values are transformed by the relevant datatype.
*/
hashToWhereConditions: function(hash, dao, options) {
throwMethodUndefined('hashToWhereConditions');
var result = [];
options = options || {};
// Closures are nice
Utils._.each(hash, function(value, key) {
var _key
, _value = null;
if (value && value._isSequelizeMethod === true && (value instanceof Utils.literal)) {
result.push(value.val);
return;
}
if (options.keysEscaped) {
_key = key;
} else {
if (this.isAssociationFilter(key, dao, options)) {
_key = key = this.getAssociationFilterColumn(key, dao, options);
} else {
_key = this.quoteIdentifiers(key);
}
}
if (Array.isArray(value)) {
result.push(this.arrayValue(value, key, _key, dao, 'IN'));
} else if ((value) && (typeof value === 'object') && !(value instanceof Date) && !Buffer.isBuffer(value)) {
if (!!value.join) {
//using as sentinel for join column => value
_value = this.quoteIdentifiers(value.join);
result.push([_key, _value].join('='));
} else {
for (var logic in value) {
var logicResult = Utils.getWhereLogic(logic, hash[key][logic]);
if (logicResult === 'IN' || logicResult === 'NOT IN') {
var values = Array.isArray(value[logic]) ? value[logic] : [value[logic]];
result.push(this.arrayValue(values, key, _key, dao, logicResult));
}
else if (logicResult === 'BETWEEN' || logicResult === 'NOT BETWEEN') {
_value = SqlGenerator.escape(value[logic][0]);
var _value2 = SqlGenerator.escape(value[logic][1]);
result.push(' (' + _key + ' ' + logicResult + ' ' + _value + ' AND ' + _value2 + ') ');
} else {
_value = SqlGenerator.escape(value[logic]);
result.push([_key, _value].join(' ' + logicResult + ' '));
}
}
}
} else {
if (typeof value === 'boolean') {
_value = this.booleanValue(value);
} else {
_value = SqlGenerator.escape(value);
}
result.push((_value === 'NULL') ? _key + ' IS NULL' : [_key, _value].join('='));
}
}.bind(this));
return result.join(' AND ');
},
booleanValue: function(value) {
......
......@@ -28,7 +28,6 @@ module.exports = (function() {
};
Query.prototype.run = function(sql) {
console.log(sql);
var self = this;
this.sql = sql;
......@@ -37,15 +36,22 @@ module.exports = (function() {
}
var promise = new Utils.Promise(function(resolve, reject) {
//console.log(self.sql);
console.log(self.sql);
self
.connection
.lib
.execute(self.connection.config, { query: self.sql })
.then(
function (data) { resolve(self.formatResults(data.result)); }
//function (err) { reject(self.formatError(err)); }
function (data) {
promise.emit('sql', self.sql, self.connection.uuid);
resolve(self.formatResults(data.result));
},
function (err) {
console.log('err:', err);
err.sql = sql;
reject(self.formatError(err));
}
);
});
......@@ -71,6 +77,7 @@ module.exports = (function() {
Query.prototype.formatResults = function(data) {
var result = this.callee;
//console.log(data);
if(data){
if (this.isInsertQuery(data)) {
this.handleInsertQuery(data);
} else if (this.isShowTableQuery()) {
......@@ -98,7 +105,9 @@ module.exports = (function() {
} else if (this.isBulkUpdateQuery() || this.isBulkDeleteQuery()) {
result = data.affectedRows;
}
}else{
result = null;
}
return result;
};
......
......@@ -169,7 +169,12 @@ module.exports = {
set sequelize(seq) {
_sequelize = seq;
},
quoteIdentifier: function(val){
return quoteIdentifier(val);
},
escape: function(value, field) {
return escape(value,field);
},
showTableSql: function(){
return 'SELECT name FROM sys.Tables;';
},
......@@ -620,7 +625,8 @@ module.exports = {
} else {
query.push(quoteIdentifier(key));
}
console.log('val', typeof val);
console.log('where', where);
console.log('here', val);
query.push(operator);
if(!val){
query.push('NULL');
......
......@@ -35,7 +35,11 @@ describe(Support.getTestDialectTeaser("Model"), function () {
this.User.find({
where: Sequelize[method]( "1=1", "2=2" )
}).on('sql', function(sql) {
if(dialect === 'mssql'){
expect(sql).to.contain("WHERE (1=1 " + word + " 2=2)")
}else{
expect(sql).to.contain("WHERE (1=1 " + word + " 2=2) LIMIT 1")
}
done()
})
})
......@@ -44,7 +48,11 @@ describe(Support.getTestDialectTeaser("Model"), function () {
this.User.find({
where: Sequelize[method]( ["1=?", 1], ["2=?", 2] )
}).on('sql', function(sql) {
if(dialect === 'mssql'){
expect(sql).to.contain("WHERE (1=1 " + word + " 2=2)")
}else{
expect(sql).to.contain("WHERE (1=1 " + word + " 2=2) LIMIT 1")
}
done()
})
})
......@@ -55,6 +63,7 @@ describe(Support.getTestDialectTeaser("Model"), function () {
}).on('sql', function(sql) {
var expectation = ({
mysql: "WHERE (`User`.`username`='foo' AND `User`.`intVal`=2 " + word + " `User`.`secretValue`='bar')",
mssql: 'WHERE ("User"."username"=\'foo\' AND "User"."intVal"=2 ' + word + ' "User"."secretValue"=\'bar\')',
sqlite: "WHERE (`User`.`username`='foo' AND `User`.`intVal`=2 " + word + " `User`.`secretValue`='bar')",
postgres: 'WHERE ("User"."username"=\'foo\' AND "User"."intVal"=2 ' + word + ' "User"."secretValue"=\'bar\')',
mariadb: "WHERE (`User`.`username`='foo' AND `User`.`intVal`=2 " + word + " `User`.`secretValue`='bar')"
......@@ -79,6 +88,7 @@ describe(Support.getTestDialectTeaser("Model"), function () {
mysql: "WHERE (`User`.`id`=1 " + word + " `User`.`id`=2)",
sqlite: "WHERE (`User`.`id`=1 " + word + " `User`.`id`=2)",
postgres: 'WHERE ("User"."id"=1 ' + word + ' "User"."id"=2)',
mssql: 'WHERE ("User"."id"=1 ' + word + ' "User"."id"=2)',
mariadb: "WHERE (`User`.`id`=1 " + word + " `User`.`id`=2)"
})[Support.getTestDialect()]
......@@ -100,7 +110,11 @@ describe(Support.getTestDialectTeaser("Model"), function () {
this.User.find({
where: Sequelize.and( Sequelize.or("1=1", "2=2"), Sequelize.or("3=3", "4=4") )
}).on('sql', function(sql) {
if(dialect === 'mssql'){
expect(sql).to.contain("WHERE ((1=1 OR 2=2) AND (3=3 OR 4=4))")
}else{
expect(sql).to.contain("WHERE ((1=1 OR 2=2) AND (3=3 OR 4=4)) LIMIT 1")
}
done()
})
})
......@@ -114,6 +128,7 @@ describe(Support.getTestDialectTeaser("Model"), function () {
mysql: "WHERE ((`User`.`username` = 'foo' OR `User`.`username` = 'bar') AND (`User`.`id` = 1 OR `User`.`id` = 4)) LIMIT 1",
sqlite: "WHERE ((`User`.`username` = 'foo' OR `User`.`username` = 'bar') AND (`User`.`id` = 1 OR `User`.`id` = 4)) LIMIT 1",
postgres: 'WHERE (("User"."username" = \'foo\' OR "User"."username" = \'bar\') AND ("User"."id" = 1 OR "User"."id" = 4)) LIMIT 1',
mssql: 'WHERE (("User"."username" = \'foo\' OR "User"."username" = \'bar\') AND ("User"."id" = 1 OR "User"."id" = 4))',
mariadb: "WHERE ((`User`.`username` = 'foo' OR `User`.`username` = 'bar') AND (`User`.`id` = 1 OR `User`.`id` = 4)) LIMIT 1"
})[Support.getTestDialect()]
......@@ -131,7 +146,11 @@ describe(Support.getTestDialectTeaser("Model"), function () {
this.User.find({
where: Sequelize.or( Sequelize.and("1=1", "2=2"), Sequelize.and("3=3", "4=4") )
}).on('sql', function(sql) {
if(dialect === 'mssql'){
expect(sql).to.contain("WHERE ((1=1 AND 2=2) OR (3=3 AND 4=4))")
}else{
expect(sql).to.contain("WHERE ((1=1 AND 2=2) OR (3=3 AND 4=4)) LIMIT 1")
}
done()
})
})
......@@ -145,6 +164,7 @@ describe(Support.getTestDialectTeaser("Model"), function () {
mysql: "WHERE ((`User`.`username` = 'foo' AND `User`.`username` = 'bar') OR (`User`.`id` = 1 AND `User`.`id` = 4)) LIMIT 1",
sqlite: "WHERE ((`User`.`username` = 'foo' AND `User`.`username` = 'bar') OR (`User`.`id` = 1 AND `User`.`id` = 4)) LIMIT 1",
postgres: 'WHERE (("User"."username" = \'foo\' AND "User"."username" = \'bar\') OR ("User"."id" = 1 AND "User"."id" = 4)) LIMIT 1',
mssql: 'WHERE (("User"."username" = \'foo\' AND "User"."username" = \'bar\') OR ("User"."id" = 1 AND "User"."id" = 4))',
mariadb: "WHERE ((`User`.`username` = 'foo' AND `User`.`username` = 'bar') OR (`User`.`id` = 1 AND `User`.`id` = 4)) LIMIT 1"
})[Support.getTestDialect()]
......@@ -186,7 +206,7 @@ describe(Support.getTestDialectTeaser("Model"), function () {
)
]
}).on('sql', function(sql) {
if (Support.getTestDialect() === 'postgres') {
if (Support.getTestDialect() === 'postgres' || dialect === 'mssql') {
expect(sql).to.contain(
'WHERE (' + [
'"User"."id"=42 AND 2=2 AND 1=1 AND "User"."username"=\'foo\' AND ',
......
......@@ -426,7 +426,7 @@ describe(Support.getTestDialectTeaser("QueryInterface"), function () {
var keys = Object.keys(fks[0]),
keys2 = Object.keys(fks[1]),
keys3 = Object.keys(fks[2])
if (dialect === "postgres" || dialect === "postgres-native") {
if (dialect === "postgres" || dialect === "postgres-native" || dialect == 'mssql') {
expect(keys).to.have.length(6)
expect(keys2).to.have.length(7)
expect(keys3).to.have.length(7)
......
Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!