docorm
Version:
Persistence layer with ORM features for JSON documents
169 lines • 6.03 kB
JavaScript
import _ from 'lodash';
export function queryExpressionIsCoalesce(expression) {
return (expression.coalesce !== undefined);
}
export function queryExpressionIsConstant(expression) {
return (expression.constant !== undefined)
&& !Array.isArray(expression.constant);
}
export function queryExpressionIsConstantList(expression) {
return (expression.constant !== undefined)
&& Array.isArray(expression.constant);
}
export function queryExpressionIsFunction(expression) {
return (expression.function !== undefined);
}
export function queryExpressionIsOperator(expression) {
return (expression.operator !== undefined);
}
export function queryExpressionIsFullText(expression) {
return (expression.text == 'default');
}
export function queryExpressionIsPath(expression) {
return expression.path !== undefined;
}
export function queryExpressionIsRange(expression) {
return expression.range !== undefined;
}
export function queryClauseIsBetween(clause) {
return clause.operator == 'between';
}
export function queryClauseIsComparison(clause) {
const operator = clause.operator;
return !queryClauseIsFullTextSearch(clause) && [undefined, '=', '<', '>', '<=', '>=', '!='].includes(operator);
}
export function queryClauseIsIn(clause) {
return clause.operator == 'in';
}
export function queryClauseIsFullTextSearch(clause) {
const l = clause.l;
const r = clause.r;
return clause.operator == 'contains'
&& queryExpressionIsFullText(l)
&& (queryExpressionIsConstant(r) || queryExpressionIsPath(r));
}
export function queryClauseIsSimple(clause) {
return queryClauseIsBetween(clause) || queryClauseIsComparison(clause) || queryClauseIsIn(clause)
|| queryClauseIsFullTextSearch(clause);
}
export function queryClauseIsAnd(clause) {
return clause.and != null;
}
export function queryClauseIsOr(clause) {
return clause.or != null;
}
export function queryClauseIsNot(clause) {
return clause.not != null;
}
export function calculateExpression(context, expression) {
if (queryExpressionIsCoalesce(expression)) {
for (const subexpression of expression.coalesce) {
if (subexpression != null) {
return subexpression;
}
}
return null;
}
else if (queryExpressionIsConstant(expression)) {
return expression.constant;
}
else if (queryExpressionIsConstantList(expression)) {
return expression.constant;
}
else if (queryExpressionIsFullText(expression)) {
return expression.text;
}
else if (queryExpressionIsFunction(expression)) {
throw 'Functions are not supported in query expressions outside a database context.';
}
else if (queryExpressionIsOperator(expression)) {
throw 'Operators are not supported in query expressions outside a database context.';
}
else if (queryExpressionIsPath(expression)) {
return _.get(context, expression.path);
// TODO Should we support type enforcement when the optional sqlType property is present?
}
else if (queryExpressionIsRange(expression)) {
return expression.range;
}
}
export function applyQuery(x, query) {
if (query === true) {
return true;
}
else if (query === false) {
return false;
}
else if (queryClauseIsAnd(query)) {
for (const subclause of query.and) {
if (!applyQuery(x, subclause)) {
return false;
}
return true;
}
}
else if (queryClauseIsOr(query)) {
for (const subclause of query.or) {
if (applyQuery(x, subclause)) {
return true;
}
return false;
}
}
else if (queryClauseIsNot(query)) {
return !applyQuery(x, query.not);
}
else { // queryClauseIsSimple
if (queryClauseIsBetween(query)) {
const left = calculateExpression(x, query.l);
const right = calculateExpression(x, query.r);
if (!_.isArray(right) || right.length != 2) {
throw 'For "between" queries, the right side must be a range (an array of size 2).';
}
if (typeof left == 'number') {
if (typeof right[0] != 'number' || typeof right[1] != 'number') {
throw 'For "between" queries, the range must consist of numbers if the left side is a number.';
}
return right[0] <= left && left <= right[1];
}
else if (typeof left == 'string') {
return right[0].toString() <= left && left <= right[1].toString();
}
else {
return right[0] <= left && left <= right[1];
}
}
else if (queryClauseIsComparison(query)) {
const left = calculateExpression(x, query.l);
const right = calculateExpression(x, query.r);
switch (query.operator) {
case '<':
return left < right;
case '>':
return left > right;
case '<=':
return left <= right;
case '>=':
return left >= right;
case '!=':
return left != right;
case '=':
default:
return left == right;
}
}
else if (queryClauseIsIn(query)) {
const left = calculateExpression(x, query.l);
const right = calculateExpression(x, query.r);
if (!_.isArray(right)) {
throw 'For "in" queries, the right side must be an array.';
}
return right.includes(left);
}
else if (queryClauseIsFullTextSearch(query)) {
throw 'Full text search queries are not supported outside a database context.';
}
}
return false;
}
//# sourceMappingURL=queries.js.map