UNPKG

keystone

Version:

Web Application Framework and Admin GUI / Content Management System built on Express.js and Mongoose

247 lines (222 loc) 6.67 kB
var _ = require('lodash'); var moment = require('moment'); var utils = require('keystone-utils'); var debug = require('debug')('keystone:core:list:getSearchFilters'); /** * Gets filters for a Mongoose query that will search for the provided string, * based on the searchFields List option. * * Also accepts a filters object from `processFilters()`, any of which may * override the search string. * * NOTE: This function is deprecated in favor of List.prototype.addSearchToQuery * and will be removed in a later version. * * Example: * list.getSearchFilters('jed') // returns { name: /jed/i } * * @param {String} query * @param {Object} additional filters */ function getSearchFilters (search, add) { var filters = {}; var list = this; search = String(search || '').trim(); if (search.length) { // Use the text index the behaviour is enabled by the list schema // Usually, when searchUsesTextIndex is true, list.register() will maintain an index using ensureTextIndex() // However, it's possible for searchUsesTextIndex to be true while there is an existing text index on the collection that *isn't* described in the list schema // If this occurs, an error will be reported when list.register() is called and the existing index will not be replaced, meaning it will be used here if (this.options.searchUsesTextIndex) { filters.$text = { $search: search }; } else { var searchFilter; var searchParts = search.split(' '); var searchRx = new RegExp(utils.escapeRegExp(search), 'i'); var splitSearchRx = new RegExp((searchParts.length > 1) ? _.map(searchParts, utils.escapeRegExp).join('|') : search, 'i'); var searchFields = this.get('searchFields'); var searchFilters = []; var searchIdField = utils.isValidObjectId(search); if (typeof searchFields === 'string') { searchFields = searchFields.split(','); } searchFields.forEach(function (path) { path = path.trim(); if (path === '__name__') { path = list.mappings.name; } var field = list.fields[path]; if (field && field.type === 'name') { var first = {}; first[field.paths.first] = splitSearchRx; var last = {}; last[field.paths.last] = splitSearchRx; searchFilter = {}; searchFilter.$or = [first, last]; searchFilters.push(searchFilter); } else { searchFilter = {}; searchFilter[path] = searchRx; searchFilters.push(searchFilter); } }); if (list.autokey) { searchFilter = {}; searchFilter[list.autokey.path] = searchRx; searchFilters.push(searchFilter); } if (searchIdField) { searchFilter = {}; searchFilter._id = search; searchFilters.push(searchFilter); } if (searchFilters.length > 1) { filters.$or = searchFilters; } else if (searchFilters.length) { filters = searchFilters[0]; } } } if (add) { _.forEach(add, function (filter) { var cond; var path = filter.key; var value = filter.value; switch (filter.field.type) { case 'boolean': if (!value || value === 'false') { filters[path] = { $ne: true }; } else { filters[path] = true; } break; case 'localfile': case 'cloudinaryimage': case 'cloudinaryimages': case 's3file': case 'name': case 'password': // TODO break; case 'location': _.forEach(['street1', 'suburb', 'state', 'postcode', 'country'], function (pathKey, i) { var value = filter.value[i]; if (value) { filters[filter.field.paths[pathKey]] = new RegExp(utils.escapeRegExp(value), 'i'); } }); break; case 'relationship': if (value) { if (filter.field.many) { filters[path] = (filter.inverse) ? { $nin: [value] } : { $in: [value] }; } else { filters[path] = (filter.inverse) ? { $ne: value } : value; } } else { if (filter.field.many) { filters[path] = (filter.inverse) ? { $not: { $size: 0 } } : { $size: 0 }; } else { filters[path] = (filter.inverse) ? { $ne: null } : null; } } break; case 'select': if (filter.value) { filters[path] = (filter.inverse) ? { $ne: value } : value; } else { filters[path] = (filter.inverse) ? { $nin: ['', null] } : { $in: ['', null] }; } break; case 'number': case 'money': if (filter.operator === 'bt') { value = [ utils.number(value[0]), utils.number(value[1]), ]; if (!isNaN(value[0]) && !isNaN(value[1])) { filters[path] = { $gte: value[0], $lte: value[1], }; } else { filters[path] = null; } } else { value = utils.number(value); if (!isNaN(value)) { if (filter.operator === 'gt') { filters[path] = { $gt: value }; } else if (filter.operator === 'lt') { filters[path] = { $lt: value }; } else { filters[path] = value; } } else { filters[path] = null; } } break; case 'date': case 'datetime': if (filter.operator === 'bt') { value = [ moment(value[0]), moment(value[1]), ]; if ((value[0] && value[0].isValid()) && (value[1] && value[0].isValid())) { filters[path] = { $gte: moment(value[0]).startOf('day').toDate(), $lte: moment(value[1]).endOf('day').toDate(), }; } } else { value = moment(value); if (value && value.isValid()) { var start = moment(value).startOf('day').toDate(); var end = moment(value).endOf('day').toDate(); if (filter.operator === 'gt') { filters[path] = { $gt: end }; } else if (filter.operator === 'lt') { filters[path] = { $lt: start }; } else { filters[path] = { $lte: end, $gte: start }; } } } break; case 'text': case 'textarea': case 'html': case 'email': case 'url': case 'key': if (filter.exact) { if (value) { cond = new RegExp('^' + utils.escapeRegExp(value) + '$', 'i'); filters[path] = filter.inverse ? { $not: cond } : cond; } else { if (filter.inverse) { filters[path] = { $nin: ['', null] }; } else { filters[path] = { $in: ['', null] }; } } } else if (value) { cond = new RegExp(utils.escapeRegExp(value), 'i'); filters[path] = filter.inverse ? { $not: cond } : cond; } break; } }); } debug('Applying filters to list \'' + list.key + '\':', filters); return filters; } module.exports = getSearchFilters;