UNPKG

massive

Version:

A small query tool for Postgres that embraces json and makes life simpler

74 lines (66 loc) 2.56 kB
'use strict'; const _ = require('lodash'); const stringify = require('../util/stringify'); /** * Generate a predicate for a document query. * * @module documentPredicate * @param {Object} condition - A condition object (generated by parseKey). * @param {String} key - The key corresponding to the condition in the criteria object. * @return {Object} A predicate object. */ exports = module.exports = function (condition, key) { const isArray = _.isArray(condition.value); // Contains queries using the @> operator can take advantage of a GIN index // on JSONB fields. This gives document queries a dramatic performance boost. if ( /* * type one: array of objects * * Here, the criteria {key: [{matchMe: true}, ...]} search for a * corresponding document {key: [..., {matchMe: true}, ...]}. At least one * object in the document array must match all conditions of the object(s) * in the criteria array. Multiple such objects are effectively merged. */ (isArray && _.isPlainObject(condition.value[0])) || /* * type two: shallow equality against an object * * Criteria in the format {matchMe: true} yield documents containing * {matchMe: true}. */ (condition.appended.operator === '=' && condition.jsonElements.length === 1 && !isArray) ) { const param = _.set({}, key, condition.value); condition.lhs = condition.path; condition.appended.operator = '@>'; condition.params.push(JSON.stringify(param)); condition.value = `$${condition.offset}`; } else if (condition.appended.operator !== 'IS' && condition.appended.operator !== 'IS NOT') { /* * We're querying a key on the document body! `IS` operations need no * further treatment. Comparisons use an as-text operator, so we need to * convert the value coming out of the JSON/JSONB field to the correct type * first. */ let cast = ''; if (_.isBoolean(condition.value)) { cast = '::boolean'; } else if (_.isNumber(condition.value)) { cast = '::decimal'; } else if (_.isDate(condition.value)) { cast = '::timestamptz'; condition.params.push(condition.value); condition.value = `$${condition.offset}`; } else if (condition.appended.mutator) { condition = condition.appended.mutator(condition); } else { condition.params.push(stringify(condition.value)); condition.value = `$${condition.offset}`; } condition.lhs = `(${condition.lhs})${cast || ''}`; } return condition; };