UNPKG

sails-arangojs

Version:

A sails-arangojs adapter for Sails / Waterline

298 lines (263 loc) 7.36 kB
/* eslint-disable no-use-before-define */ // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // Sync function that returns a friendly sql statement for easy manipulation in the ArangoJs driver // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - const _ = require('@sailshq/lodash'); const normalizeUpdateValues = require('./normalizeUpdateValues'); const stringifyUpdateValues = require('./stringifyUpdateValues'); const getFilterStatement = require('./helpers/getFilterStatement'); module.exports = function compileStatement(options) { const { model, method, numericAttrName, values, pkColumnName, edgeCollections, distanceCriteria, aggregateCriteria, } = options; if (!pkColumnName) { throw new Error( 'SQL Statement cannot compile because the pkColumnName is not passed' ); } const passedcriteria = options.criteria || {}; const primarywhere = { ...(passedcriteria.where || {}) }; if (primarywhere[pkColumnName] && !primarywhere._id) { primarywhere._id = `${model}/${primarywhere[pkColumnName]}`; } if (passedcriteria.whereVertex) { if (_.isString(passedcriteria.whereVertex)) { passedcriteria.whereVertex = { [pkColumnName]: passedcriteria.whereVertex, }; } } if (passedcriteria.whereEdge) { if (_.isString(passedcriteria.whereEdge)) { passedcriteria.whereEdge = { [pkColumnName]: passedcriteria.whereEdge }; } } // Hold the final query value // Validate options if (!model) { throw new Error('Convert must contain a model to use to build the query.'); } if (!method) { throw new Error('Convert must contain a method to use to build the query.'); } // Validate Criteria Input is a dictionary if (passedcriteria && !_.isPlainObject(passedcriteria)) { throw new Error('Criteria must be a dictionary.'); } // Validate Criteria Input contains a WHERE clause if ( passedcriteria && _.keys(passedcriteria).length && !_.has(passedcriteria, 'where') ) { throw new Error('Criteria must contain a WHERE clause.'); } const { getAndStatement, getLetStatements } = getFilterStatement({ pkColumnName, }); function hasSelectFields() { if ( _.isEqual(passedcriteria.select, ['*']) || _.isEqual(passedcriteria.select, '*') ) { return false; } if (Array.isArray(passedcriteria.select)) { if (passedcriteria.select.length > 0) { return true; } } return false; } function selectAttributes(vals) { if (vals && Array.isArray(vals)) { let fields = [...vals].filter((f) => { const arr = [ 'sort', 'limit', 'skip', 'select', 'filter', 'like', 'notlike', 'not', 'in', 'for', 'return', 'search', 'let', 'collect', 'remove', 'update', 'replace', 'insert', 'upsert', 'with', 'all', 'distinct', 'outbound', 'any', 'into', 'none', ]; return !_.includes(arr, f); }); if (!_.includes(fields, pkColumnName)) { fields = [...fields, pkColumnName]; } if (!_.includes(fields, '_id')) { fields = [...fields, '_id']; } return fields; } return [pkColumnName, '_id']; } function getNumericAttrName() { if (Array.isArray(numericAttrName)) { return numericAttrName.map((n) => `record.${n}`).join(' + '); } if (numericAttrName) { return numericAttrName; } return null; } function getEdgeCollections() { if (Array.isArray(edgeCollections)) { return edgeCollections.map((n) => n).join(', '); } if (edgeCollections) { return edgeCollections; } return null; } function getGeoAttrName() { let attrName; if (distanceCriteria) { _.each(distanceCriteria, (value, key) => { if (key !== 'radius') { attrName = key; } }); } return attrName; } function getGeoRadius() { let radius = 0; if (distanceCriteria) { _.each(distanceCriteria, (value, key) => { if (key === 'radius') { radius = Number(value || 0); } }); } return radius; } function getDistanceCriteria() { let criteria = ''; if (distanceCriteria) { _.each(distanceCriteria, (value, key) => { if (key !== 'radius') { criteria = `${value.longitude}, ${value.latitude}`; } }); } return criteria; } // Check for sort let sortClauseArray = []; if (passedcriteria.sort) { if (passedcriteria.sort.length > 0) { sortClauseArray = passedcriteria.sort .map((c) => getSortClause(c)) .filter((c) => !!c); } } function getSortClause(sortObj) { let str = ''; if (_.isObject(sortObj)) { _.each(sortObj, (value, key) => { str += `record.${key} ${value}`; }); } return str; } const letStatements = getLetStatements(passedcriteria.let || {}); const compiledwhere = getAndStatement(passedcriteria.where || {}); const compiledwherevertex = getAndStatement(passedcriteria.whereVertex || {}); const compiledwhereedge = getAndStatement(passedcriteria.whereEdge || {}); const obj = { ...passedcriteria, letStatements, method, select: hasSelectFields() ? selectAttributes(passedcriteria.select) : ['_key'], from: model, tableName: model, model, selectClause: hasSelectFields() ? selectAttributes(passedcriteria.select).join(', ') : '*', whereClause: compiledwhere, primarywhere, whereVertexClause: compiledwherevertex.replace(/record./g, 'vertex.'), whereEdgeClause: compiledwhereedge.replace(/record./g, 'edge.'), sortClauseArray, sortClause: sortClauseArray.join(', '), graphSort: sortClauseArray.join(', ').replace(/record./, ''), numericAttrName: getNumericAttrName(), edgeCollections: getEdgeCollections(), geoAttrName: getGeoAttrName(), geoRadius: getGeoRadius(), distanceCriteria: getDistanceCriteria(), values: values || {}, }; if (method === 'upsert' || method === 'update' || method === 'replace') { obj.criteria = stringifyUpdateValues( { ...passedcriteria.where, }, method, passedcriteria.let || {} ); obj.insertvalues = stringifyUpdateValues( { ...passedcriteria.where, ...(values || {}), createdAt: new Date().getTime(), }, method, passedcriteria.let || {} ); obj.values = stringifyUpdateValues( values || {}, method, passedcriteria.let || {} ); obj.valuesToSet = normalizeUpdateValues( values || {}, passedcriteria.let || {} ); } if (method === 'create' || method === 'createEach') { obj.values = values || []; } if (method === 'aggregate') { const getAggregateStatement = require('./helpers/getAggregateStatement'); return { aggregatestatement: getAggregateStatement({ aggregateCriteria, pkColumnName, model, }), }; } return obj; };