2014-05-13 15:09:54 -04:00
|
|
|
LocalMongo = module.exports
|
|
|
|
|
2014-05-14 08:47:44 -04:00
|
|
|
# Checks whether func(l, r) is true for at least one value of left for at least one value of right
|
|
|
|
mapred = (left, right, func) ->
|
|
|
|
_.reduce(left, ((result, singleLeft) ->
|
|
|
|
result or (_.reduce (_.map right, (singleRight) -> func(singleLeft, singleRight)),
|
|
|
|
((intermediate, value) -> intermediate or value), false)), false)
|
|
|
|
|
2016-08-30 18:46:34 -04:00
|
|
|
doQuerySelector = (originalValue, operatorObj) ->
|
|
|
|
value = if _.isArray originalValue then originalValue else [originalValue] # left hand can be an array too
|
|
|
|
for operator, originalBody of operatorObj
|
|
|
|
body = if _.isArray originalBody then originalBody else [originalBody] # right hand can be an array too
|
2014-05-13 15:09:54 -04:00
|
|
|
switch operator
|
2014-05-14 08:47:44 -04:00
|
|
|
when '$gt' then return false unless mapred value, body, (l, r) -> l > r
|
|
|
|
when '$gte' then return false unless mapred value, body, (l, r) -> l >= r
|
|
|
|
when '$lt' then return false unless mapred value, body, (l, r) -> l < r
|
|
|
|
when '$lte' then return false unless mapred value, body, (l, r) -> l <= r
|
|
|
|
when '$ne' then return false if mapred value, body, (l, r) -> l == r
|
2014-05-13 18:08:22 -04:00
|
|
|
when '$in' then return false unless _.reduce value, ((result, val) -> result or val in body), false
|
2014-05-14 08:47:44 -04:00
|
|
|
when '$nin' then return false if _.reduce value, ((result, val) -> result or val in body), false
|
2014-06-04 14:47:32 -04:00
|
|
|
when '$exists' then return false if value[0]? isnt body[0]
|
2016-08-30 18:46:34 -04:00
|
|
|
else
|
|
|
|
trimmedOperator = _.pick(operatorObj, operator)
|
|
|
|
return false unless _.isObject(originalValue) and matchesQuery(originalValue, trimmedOperator)
|
2014-05-13 15:09:54 -04:00
|
|
|
true
|
|
|
|
|
2014-05-14 11:12:33 -04:00
|
|
|
matchesQuery = (target, queryObj) ->
|
2014-05-17 11:19:57 -04:00
|
|
|
return true unless queryObj
|
2014-06-14 14:12:17 -04:00
|
|
|
throw new Error 'Expected an object to match a query against, instead got null' unless target
|
2014-05-13 18:08:22 -04:00
|
|
|
for prop, query of queryObj
|
2014-05-14 11:12:33 -04:00
|
|
|
if prop[0] == '$'
|
|
|
|
switch prop
|
|
|
|
when '$or' then return false unless _.reduce query, ((res, obj) -> res or matchesQuery target, obj), false
|
|
|
|
when '$and' then return false unless _.reduce query, ((res, obj) -> res and matchesQuery target, obj), true
|
|
|
|
else return false
|
|
|
|
else
|
2014-05-17 11:19:57 -04:00
|
|
|
# Do nested properties
|
|
|
|
pieces = prop.split('.')
|
|
|
|
obj = target
|
|
|
|
for piece in pieces
|
2014-06-04 14:47:32 -04:00
|
|
|
unless piece of obj
|
|
|
|
obj = null
|
|
|
|
break
|
2014-05-17 11:19:57 -04:00
|
|
|
obj = obj[piece]
|
2014-05-14 11:12:33 -04:00
|
|
|
if typeof query != 'object' or _.isArray query
|
2014-05-17 11:19:57 -04:00
|
|
|
return false unless obj == query or (query in obj if _.isArray obj)
|
|
|
|
else return false unless doQuerySelector obj, query
|
2014-05-14 11:12:33 -04:00
|
|
|
true
|
|
|
|
|
2014-06-04 14:47:32 -04:00
|
|
|
LocalMongo.matchesQuery = matchesQuery
|