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

Commit 3e29e69f by Rafael Martins

Making filter throught relations to work with current functionalities

1 parent 1f661612
Showing with 202 additions and 93 deletions
...@@ -216,116 +216,241 @@ module.exports = (function() { ...@@ -216,116 +216,241 @@ module.exports = (function() {
joinQuery += " LEFT OUTER JOIN " + this.quoteIdentifier(tableJunction) + " ON " + this.quoteIdentifier(tableSource) + "." + this.quoteIdentifier(attrSource) + " = " + this.quoteIdentifier(tableJunction) + "." + this.quoteIdentifier(identSource) joinQuery += " LEFT OUTER JOIN " + this.quoteIdentifier(tableJunction) + " ON " + this.quoteIdentifier(tableSource) + "." + this.quoteIdentifier(attrSource) + " = " + this.quoteIdentifier(tableJunction) + "." + this.quoteIdentifier(identSource)
joinQuery += " LEFT OUTER JOIN " + this.quoteIdentifier(table) + " AS " + this.quoteIdentifier(as) + " ON " + this.quoteIdentifier(tableTarget) + "." + this.quoteIdentifier(attrTarget) + " = " + this.quoteIdentifier(tableJunction) + "." + this.quoteIdentifier(identTarget) joinQuery += " LEFT OUTER JOIN " + this.quoteIdentifier(table) + " AS " + this.quoteIdentifier(as) + " ON " + this.quoteIdentifier(tableTarget) + "." + this.quoteIdentifier(attrTarget) + " = " + this.quoteIdentifier(tableJunction) + "." + this.quoteIdentifier(identTarget)
} }
}.bind(this)) }.bind(this))
options.attributes = optAttributes.join(', ') options.attributes = optAttributes.join(', ')
} }
var query = "SELECT " + options.attributes + " FROM " + options.table var conditionalJoins = this.getConditionalJoins(options, factory),
query += joinQuery query;
var innerQuery = "SELECT " + options.table + '.*\r\nFROM ' + options.table if (conditionalJoins) {
var whereClauses = '1=1'; query = "SELECT " + options.attributes + " FROM ( "
+ "SELECT * FROM " + options.table + this.getConditionalJoins(options, factory)
} else {
query = "SELECT " + options.attributes + " FROM " + options.table
query += joinQuery
}
if (options.hasOwnProperty('where')) { if (options.hasOwnProperty('where')) {
var self = this; options.where = this.getWhereConditions(options.where, tableName, factory)
(function(){ query += " WHERE " + options.where
var keys = Object.keys(options.where) }
, dao = factory;
keys.forEach(function (key) { if (options.group) {
var filterValue = options.where[key]; options.group = Array.isArray(options.group) ? options.group.map(function (t) { return this.quote(t) }.bind(this)).join(', ') : options.group
query += " GROUP BY " + options.group
key.split('.').forEach(function(attribute){ }
var isAssociation = false;
Object.keys(dao.associations).forEach(function(associationName){ if (options.order) {
if(!dao.associations[associationName]) return; options.order = Array.isArray(options.order) ? options.order.map(function (t) { return this.quote(t) }.bind(this)).join(', ') : options.order
query += " ORDER BY " + options.order
var accessor, }
associationType = dao.associations[associationName].associationType;
if (options.offset && !options.limit) {
if(associationType === 'HasMany') { query += " LIMIT " + options.offset + ", " + 10000000000000;
accessor = dao.associations[associationName].accessors.get.replace('get', '') } else if (options.limit && !(options.include && (options.limit === 1))) {
accessor = accessor[0].toLowerCase() + accessor.slice(1); if (options.offset) {
query += " LIMIT " + options.offset + ", " + options.limit
} else { } else {
accessor = dao.associations[associationName].associationAccessor query += " LIMIT " + options.limit
accessor = Utils.singularize(accessor[0].toLowerCase() + accessor.slice(1)) }
} }
accessor = accessor[0].toLowerCase() + accessor.slice(1); if (conditionalJoins) {
query += ") AS " + options.table
query += joinQuery
}
query += ";"
if(attribute === accessor){ return query
if(associationType === 'BelongsTo') { },
var targetTableName = dao.associations[associationName].target.tableName
, targetColumnName = dao.associations[associationName].target.autoIncrementField
, sourceTableName = dao.tableName
, sourceColumnName = dao.associations[associationName].identifier
innerQuery += '\r\n\r\nLEFT JOIN ' + self.quoteIdentifier(targetTableName) getWhereConditions: function(smth, tableName, factory) {
innerQuery += '\r\nON ' + self.quoteIdentifier(targetTableName) + '.' + self.quoteIdentifier(targetColumnName) + ' = ' + self.quoteIdentifier(sourceTableName) + '.' + self.quoteIdentifier(sourceColumnName) var result = null
dao = dao.associations[associationName].target; , where = {}
if (Utils.isHash(smth)) {
smth = Utils.prependTableNameToHash(tableName, smth)
result = this.hashToWhereConditions(smth, factory)
} 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 { } else {
var targetTableName = dao.associations[associationName].target.tableName primaryKeys = 'id'
, targetColumnName = dao.associations[associationName].identifier }
, sourceTableName = dao.tableName
, sourceColumnName = dao.associations[associationName].source.autoIncrementField where[primaryKeys] = smth
smth = Utils.prependTableNameToHash(tableName, where)
result = this.hashToWhereConditions(smth)
} else if (typeof smth === "string") {
result = smth
} else if (Array.isArray(smth)) {
result = Utils.format(smth, this.dialect)
}
return result ? result : '1=1'
},
findAssociation: function(attribute, dao){
var associationToReturn;
innerQuery += '\r\n\r\nLEFT JOIN ' + self.quoteIdentifier(targetTableName) Object.keys(dao.associations).forEach(function(key){
innerQuery += '\r\nON ' + self.quoteIdentifier(targetTableName) + '.' + self.quoteIdentifier(targetColumnName) + ' = ' + self.quoteIdentifier(sourceTableName) + '.' + self.quoteIdentifier(sourceColumnName) if(!dao.associations[key]) return;
dao = dao.associations[associationName].target;
var association = dao.associations[key]
, associationName
if (association.associationType === 'BelongsTo') {
associationName = Utils.singularize(association.associationAccessor[0].toLowerCase() + association.associationAccessor.slice(1));
} else {
associationName = association.accessors.get.replace('get', '')
associationName = associationName[0].toLowerCase() + associationName.slice(1);
} }
isAssociation = true;
if(associationName === attribute){
associationToReturn = association;
} }
}); });
if(!isAssociation){
var smth, result, hash = {};
hash[attribute] = filterValue;
smth = Utils.prependTableNameToHash(dao.tableName, hash) return associationToReturn;
result = self.hashToWhereConditions(smth) },
whereClauses += ' AND ' + result getAssociationFilterDAO: function(filterStr, dao){
} var associationParts = filterStr.split('.')
}) , self = this
associationParts.pop()
associationParts.forEach(function (attribute) {
dao = self.findAssociation(attribute, dao).target;
}); });
})();
innerQuery += " WHERE " + whereClauses return dao;
} },
if (options.group) { isAssociationFilter: function(filterStr, dao){
options.group = Array.isArray(options.group) ? options.group.map(function (t) { return this.quote(t) }.bind(this)).join(', ') : options.group if(!dao){
innerQuery += " GROUP BY " + options.group return false;
} }
if (options.order) { var pattern = /^[a-z][a-zA-Z0-9]+(\.[a-z][a-zA-Z0-9]+)+$/;
options.order = Array.isArray(options.order) ? options.order.map(function (t) { return this.quote(t) }.bind(this)).join(', ') : options.order if (!pattern.test(filterStr)) return false;
innerQuery += " ORDER BY " + options.order
}
if (options.offset && !options.limit) { var associationParts = filterStr.split('.')
/* , attributePart = associationParts.pop()
* If no limit is defined, our best bet is to use the max number of rows in a table. From the SQLite docs: , self = this
* A 140 terabytes database can hold no more than approximately 1e+13 rows
*/ return associationParts.every(function (attribute) {
innerQuery += " LIMIT " + options.offset + ", " + 10000000000000; var association = self.findAssociation(attribute, dao);
} else if (options.limit && !(options.include && (options.limit === 1))) { if (!association) return false;
if (options.offset) { dao = association.target;
innerQuery += " LIMIT " + options.offset + ", " + options.limit return !!dao;
}) && dao.rawAttributes.hasOwnProperty(attributePart);
},
getAssociationFilterColumn: function(filterStr, dao){
var associationParts = filterStr.split('.')
, attributePart = associationParts.pop()
, self = this
associationParts.forEach(function (attribute) {
dao = self.findAssociation(attribute, dao).target;
})
return dao.tableName + '.' + attributePart;
},
getConditionalJoins: function(options, dao){
var joins = ''
, self = this
if (Utils.isHash(options.where)) {
Object.keys(options.where).forEach(function(filterStr){
var associationParts = filterStr.split('.')
, attributePart = associationParts.pop()
if (self.isAssociationFilter(filterStr, dao)) {
associationParts.forEach(function (attribute) {
var association = self.findAssociation(attribute, dao);
if(association.associationType === 'BelongsTo'){
joins += ' LEFT JOIN ' + self.quoteIdentifiers(association.target.tableName)
joins += ' ON ' + self.quoteIdentifiers(association.source.tableName + '.' + association.identifier)
joins += ' = ' + self.quoteIdentifiers(association.target.tableName + '.' + association.target.autoIncrementField)
} else { } else {
innerQuery += " LIMIT " + options.limit joins += ' LEFT JOIN ' + self.quoteIdentifiers(association.target.tableName)
joins += ' ON ' + self.quoteIdentifiers(association.source.tableName + '.' + association.source.autoIncrementField)
joins += ' = ' + self.quoteIdentifiers(association.target.tableName + '.' + association.identifier)
} }
dao = association.target;
});
}
});
} }
query = 'SELECT * FROM (\r\n' return joins;
+ innerQuery },
+ ') as ' + options.table + '\r\n'
+ joinQuery
query += ";" hashToWhereConditions: function(hash, dao) {
var result = []
return query for (var key in hash) {
var value = hash[key]
if(this.isAssociationFilter(key, dao)){
key = this.getAssociationFilterColumn(key, dao);
}
//handle qualified key names
var _key = this.quoteIdentifiers(key)
, _value = null
if (Array.isArray(value)) {
// is value an array?
if (value.length === 0) { value = [null] }
_value = "(" + value.map(function(v) { return this.escape(v) }.bind(this)).join(',') + ")"
result.push([_key, _value].join(" IN "))
} else if ((value) && (typeof value == 'object') && !(value instanceof Date)) {
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)
if (logic === "IN" || logic === "NOT IN") {
var values = Array.isArray(where[i][ii]) ? where[i][ii] : [where[i][ii]]
_where[_where.length] = i + ' ' + logic + ' (' + values.map(function(){ return '?' }).join(',') + ')'
_whereArgs = _whereArgs.concat(values)
}
else if (logicResult === "BETWEEN" || logicResult === "NOT BETWEEN") {
_value = this.escape(value[logic][0])
var _value2 = this.escape(value[logic][1])
result.push(' (' + _key + ' ' + logicResult + ' ' + _value + ' AND ' + _value2 + ') ')
} else {
_value = this.escape(value[logic])
result.push([_key, _value].join(' ' + logicResult + ' '))
}
}
}
} else {
if (typeof value === 'boolean') {
_value = !!value ? 1 : 0
} else {
_value = this.escape(value)
result.push((_value == 'NULL') ? _key + " IS NULL" : [_key, _value].join("="))
}
}
}
return result.join(" AND ")
}, },
updateQuery: function(tableName, attrValueHash, where, options) { updateQuery: function(tableName, attrValueHash, where, options) {
...@@ -466,22 +591,6 @@ module.exports = (function() { ...@@ -466,22 +591,6 @@ module.exports = (function() {
return fields return fields
}, },
hashToWhereConditions: function(hash) {
for (var key in hash) {
if (hash.hasOwnProperty(key)) {
var value = hash[key]
if (typeof value === 'boolean') {
value = !!value ? 1 : 0
}
hash[key] = value
}
}
return hashToWhereConditions.call(this, hash).replace(/\\'/g, "''");
},
showIndexQuery: function(tableName) { showIndexQuery: function(tableName) {
var sql = "PRAGMA INDEX_LIST('<%= tableName %>')" var sql = "PRAGMA INDEX_LIST('<%= tableName %>')"
return Utils._.template(sql, { tableName: tableName }) return Utils._.template(sql, { tableName: tableName })
......
Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!