src/helpers/check-course-against-query.js
import all from 'lodash/collection/all'
import any from 'lodash/collection/any'
import compact from 'lodash/array/compact'
import contains from 'lodash/collection/contains'
import curry from 'lodash/function/curry'
import has from 'lodash/object/has'
import indexOf from 'lodash/array/indexOf'
import isArray from 'lodash/lang/isArray'
import map from 'lodash/collection/map'
import pairs from 'lodash/object/pairs'
import rest from 'lodash/array/rest'
import size from 'lodash/collection/size'
import takeWhile from 'lodash/array/takeWhile'
let checkCourseAgainstQueryBit = curry((course, [key, values]) => {
if (!has(course, key)) {
return false
}
let substring = false
// values is either:
// - a 1-long array
// - an $AND, $OR, $NOT, or $XOR query
// - one of the above, but substring
let hasBool = indexOf(values[0], '$') === 0
let OR = values[0] === '$OR'
let NOR = values[0] === '$NOR'
let AND = values[0] === '$AND'
let NOT = values[0] === '$NOT'
let XOR = values[0] === '$XOR'
if (hasBool) {
// remove the first value from the array
// by returning all but the first element
values = rest(values)
}
if (contains(['title', 'name', 'description', 'notes', 'instructors', 'times', 'locations'], key)) {
substring = true
}
let internalMatches = map(values, val => {
// dept, gereqs, etc.
if (isArray(course[key]) && !substring) {
return contains(course[key], val)
}
else if (isArray(course[key]) && substring) {
return any(map(course[key], item => contains(item.toLowerCase(), val.toLowerCase())))
}
else if (substring) {
return contains(course[key].toLowerCase(), val.toLowerCase())
}
return course[key] === val
})
if (!hasBool) {
return all(internalMatches)
}
let result = false
if (OR) result = any(internalMatches)
if (NOR) result = !any(internalMatches)
if (AND) result = all(internalMatches)
if (NOT) result = !all(internalMatches)
if (XOR) result = compact(internalMatches).length === 1
return result
})
/**
* Checks if a course passes a query check.
*
* @param {Object} query - the query object that comes out of buildQueryFromString
* @param {Course} course - the course to check
* @returns {Boolean}
*/
let checkCourseAgainstQuery = curry((query, course) => {
let kvPairs = pairs(query)
let matches = takeWhile(kvPairs, checkCourseAgainstQueryBit(course))
return size(kvPairs) === size(matches) && all(matches)
})
export default checkCourseAgainstQuery