skul
Version:
SKuL - SQL query manager
234 lines (175 loc) • 6.58 kB
JavaScript
/*
* lib/skul/search.js
*
* SKuL search methods
*
* Author: Paul Duthoit
* Copyright(c) 2016 Paul Duthoit
*/
// Dependencies
var _ = require('underscore');
var QueryException = require('./exceptions/query');
/*
* Search to filter
*
* @params {Object} filter
* @params {String} searchString
* @params {Object} fields
*
* @return {Object}
* @api public
*/
module.exports.searchToFilter = function(filter, searchString, fields) {
// Data
var dbConnection = this.dbConnection;
var parsedFields = this.parseFields(fields);
var searchableKeys = this.getSearchableKeys();
var searchFields = null;
// Return filter if search string is empty
if(typeof searchString !== 'string' || !searchString) {
return filter;
}
// Populate default and available search fields
var _populateSearchFields = function(model, fields, parentKey) {
// Data
var hasOneRelationships = model.getRelationships('hasOne');
var belongsToRelationships = model.getRelationships('belongsTo');
var hasOneRelationshipFields = model.parseRelationships('hasOne', fields);
var belongsToRelationshipFields = model.parseRelationships('belongsTo', fields);
// Loop over relationship hasOne fields
_.each(hasOneRelationshipFields, function(relObj, relKey) {
// Data
var relModel = hasOneRelationships[relKey].model;
var relSearchableKeys = relModel.getSearchableKeys();
var relDefaultSearchKeys = relModel.getDefaultSearchKeys();
var relFields = relObj['$fields'];
var relParsedFields = relModel.parseFields(relObj['$fields']);
// Loop over relationship available search fields
_.each(relSearchableKeys, function(key) {
searchableKeys.push(parentKey ? parentKey + '.' + relKey + '.' + key : relKey + '.' + key);
});
// If relationship fields is empty or set has $default
if(typeof relFields !== "object" || relFields === null || Object.keys(relFields).length === 0 || relFields['$default'] === 1) {
// Loop over relationship default search fields
_.each(relDefaultSearchKeys, function(key) {
parsedFields.push(parentKey ? parentKey + '.' + relKey + '.' + key : relKey + '.' + key);
});
}
// If relationship fields is set has $all
else if(relFields['$all'] === 1) {
// Loop over relationship default search fields
_.each(relSearchableKeys, function(key) {
parsedFields.push(parentKey ? parentKey + '.' + relKey + '.' + key : relKey + '.' + key);
});
}
// If relationship fields is not empty
else {
// Loop over relationship schema fields
_.each(relParsedFields, function(key) {
parsedFields.push(parentKey ? parentKey + '.' + relKey + '.' + key : relKey + '.' + key);
});
}
// Populate relationship fields
if(typeof relFields === "object" && relFields !== null && Object.keys(relFields).length > 0) {
_populateSearchFields(relModel, relFields, parentKey ? parentKey + '.' + relKey : relKey);
}
});
// Loop over relationship belongsTo fields
_.each(belongsToRelationshipFields, function(relObj, relKey) {
// Data
var relModel = belongsToRelationships[relKey].model;
var relSearchableKeys = relModel.getSearchableKeys();
var relDefaultSearchKeys = relModel.getDefaultSearchKeys();
var relFields = relObj['$fields'];
var relParsedFields = relModel.parseFields(relObj['$fields']);
// Loop over relationship available search fields
_.each(relSearchableKeys, function(key) {
searchableKeys.push(parentKey ? parentKey + '.' + relKey + '.' + key : relKey + '.' + key);
});
// If relationship fields is empty or set has $default
if(typeof relFields !== "object" || relFields === null || Object.keys(relFields).length === 0 || relFields['$default'] === 1) {
// Loop over relationship default search fields
_.each(relDefaultSearchKeys, function(key) {
parsedFields.push(parentKey ? parentKey + '.' + relKey + '.' + key : relKey + '.' + key);
});
}
// If relationship fields is set has $all
else if(relFields['$all'] === 1) {
// Loop over relationship default search fields
_.each(relSearchableKeys, function(key) {
parsedFields.push(parentKey ? parentKey + '.' + relKey + '.' + key : relKey + '.' + key);
});
}
// If relationship fields is not empty
else {
// Loop over relationship schema fields
_.each(relParsedFields, function(key) {
parsedFields.push(parentKey ? parentKey + '.' + relKey + '.' + key : relKey + '.' + key);
});
}
// Populate relationship fields
if(typeof relFields === "object" && relFields !== null && Object.keys(relFields).length > 0) {
_populateSearchFields(relModel, relFields, parentKey ? parentKey + '.' + relKey : relKey);
}
});
};
// Populate search fields
_populateSearchFields(this, fields);
// Check if we search on specific fields
var searchStringMatch = searchString.match(/^\$([a-z0-9_,.]+)\$:(.+)$/);
// If search on specific fields
if(searchStringMatch !== null) {
// Set search data
searchFields = searchStringMatch[1].split(',');
searchString = searchStringMatch[2];
// Check search data
searchFieldsDiff = _.difference(searchFields, searchableKeys);
// If some wrong fields found
if(searchFieldsDiff.length > 0) {
// Data
var invalidQueryData = {};
// For each wrong fields
_.each(searchFieldsDiff, function(key) {
invalidQueryData[key] = 'invalid';
});
// Reject
throw new QueryException('InvalidQueryData', invalidQueryData);
}
}
// If search on default fields
else {
// Set search data
searchFields = parsedFields.length > 0 ? parsedFields : searchableKeys;
searchString = searchString;
}
// Create new filter
var searchFilter = { '$or': [] };
// Loop over string
_.each(searchFields, function(fieldItem) {
// Set data
var splittedSearchString = searchString.split(' ');
var whereClause = null;
// Add to where clause
if(splittedSearchString.length === 1) {
whereClause = {};
whereClause[fieldItem] = { '$like': searchString };
} else {
whereClause = { '$and': [] };
_.each(splittedSearchString, function(item) {
whereItem = {};
whereItem[fieldItem] = { '$like': item };
whereClause['$and'].push(whereItem);
});
}
// Add to search filter
searchFilter['$or'].push(whereClause)
});
// Add to filter
if(Object.keys(filter).length === 0) {
filter = searchFilter;
} else {
filter = { '$and': [ searchFilter, filter ] };
}
// Return
return filter;
};