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

Commit 3e29e69f by Rafael Martins

Making filter throught relations to work with current functionalities

1 parent 1f661612
Showing with 206 additions and 97 deletions
...@@ -216,118 +216,243 @@ module.exports = (function() { ...@@ -216,118 +216,243 @@ 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) {
var filterValue = options.where[key];
key.split('.').forEach(function(attribute){
var isAssociation = false;
Object.keys(dao.associations).forEach(function(associationName){
if(!dao.associations[associationName]) return;
var accessor,
associationType = dao.associations[associationName].associationType;
if(associationType === 'HasMany') {
accessor = dao.associations[associationName].accessors.get.replace('get', '')
accessor = accessor[0].toLowerCase() + accessor.slice(1);
} else {
accessor = dao.associations[associationName].associationAccessor
accessor = Utils.singularize(accessor[0].toLowerCase() + accessor.slice(1))
}
accessor = accessor[0].toLowerCase() + accessor.slice(1);
if(attribute === accessor){
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)
innerQuery += '\r\nON ' + self.quoteIdentifier(targetTableName) + '.' + self.quoteIdentifier(targetColumnName) + ' = ' + self.quoteIdentifier(sourceTableName) + '.' + self.quoteIdentifier(sourceColumnName)
dao = dao.associations[associationName].target;
} else {
var targetTableName = dao.associations[associationName].target.tableName
, targetColumnName = dao.associations[associationName].identifier
, sourceTableName = dao.tableName
, sourceColumnName = dao.associations[associationName].source.autoIncrementField
innerQuery += '\r\n\r\nLEFT JOIN ' + self.quoteIdentifier(targetTableName)
innerQuery += '\r\nON ' + self.quoteIdentifier(targetTableName) + '.' + self.quoteIdentifier(targetColumnName) + ' = ' + self.quoteIdentifier(sourceTableName) + '.' + self.quoteIdentifier(sourceColumnName)
dao = dao.associations[associationName].target;
}
isAssociation = true;
}
});
if(!isAssociation){
var smth, result, hash = {};
hash[attribute] = filterValue;
smth = Utils.prependTableNameToHash(dao.tableName, hash)
result = self.hashToWhereConditions(smth)
whereClauses += ' AND ' + result
}
})
});
})();
innerQuery += " WHERE " + whereClauses
} }
if (options.group) { if (options.group) {
options.group = Array.isArray(options.group) ? options.group.map(function (t) { return this.quote(t) }.bind(this)).join(', ') : options.group options.group = Array.isArray(options.group) ? options.group.map(function (t) { return this.quote(t) }.bind(this)).join(', ') : options.group
innerQuery += " GROUP BY " + options.group query += " GROUP BY " + options.group
} }
if (options.order) { if (options.order) {
options.order = Array.isArray(options.order) ? options.order.map(function (t) { return this.quote(t) }.bind(this)).join(', ') : options.order options.order = Array.isArray(options.order) ? options.order.map(function (t) { return this.quote(t) }.bind(this)).join(', ') : options.order
innerQuery += " ORDER BY " + options.order query += " ORDER BY " + options.order
} }
if (options.offset && !options.limit) { if (options.offset && !options.limit) {
/* query += " LIMIT " + options.offset + ", " + 10000000000000;
* If no limit is defined, our best bet is to use the max number of rows in a table. From the SQLite docs:
* A 140 terabytes database can hold no more than approximately 1e+13 rows
*/
innerQuery += " LIMIT " + options.offset + ", " + 10000000000000;
} else if (options.limit && !(options.include && (options.limit === 1))) { } else if (options.limit && !(options.include && (options.limit === 1))) {
if (options.offset) { if (options.offset) {
innerQuery += " LIMIT " + options.offset + ", " + options.limit query += " LIMIT " + options.offset + ", " + options.limit
} else { } else {
innerQuery += " LIMIT " + options.limit query += " LIMIT " + options.limit
} }
} }
query = 'SELECT * FROM (\r\n' if (conditionalJoins) {
+ innerQuery query += ") AS " + options.table
+ ') as ' + options.table + '\r\n' query += joinQuery
+ joinQuery }
query += ";" query += ";"
return query return query
}, },
getWhereConditions: function(smth, tableName, factory) {
var result = null
, 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 {
primaryKeys = 'id'
}
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;
Object.keys(dao.associations).forEach(function(key){
if(!dao.associations[key]) return;
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);
}
if(associationName === attribute){
associationToReturn = association;
}
});
return associationToReturn;
},
getAssociationFilterDAO: function(filterStr, dao){
var associationParts = filterStr.split('.')
, self = this
associationParts.pop()
associationParts.forEach(function (attribute) {
dao = self.findAssociation(attribute, dao).target;
});
return dao;
},
isAssociationFilter: function(filterStr, dao){
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){
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 {
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;
});
}
});
}
return joins;
},
hashToWhereConditions: function(hash, dao) {
var result = []
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) {
attrValueHash = Utils.removeNullValuesFromHash(attrValueHash, this.options.omitNull, options) attrValueHash = Utils.removeNullValuesFromHash(attrValueHash, this.options.omitNull, 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!