const _zipObject = require('lodash/zipObject'); function convertLeftOperandToMongoColumn(left) { if (left.exprType == 'placeholder') return '__placeholder__'; if (left.exprType == 'column') return left.columnName; throw new Error(`Unknown left operand type ${left.exprType}`); } function convertRightOperandToMongoValue(right) { if (right.exprType == 'value') return right.value; throw new Error(`Unknown right operand type ${right.exprType}`); } function convertRightEqualOperandToMongoCondition(right) { if (right.exprType != 'value') { throw new Error(`Unknown right operand type ${right.exprType}`); } const { value } = right; if (/^[0-9a-fA-F]{24}$/.test(value)) { return { $in: [value, { $oid: value }], }; } return { $eq: value, }; } function convertToMongoCondition(filter) { if (!filter) { return null; } switch (filter.conditionType) { case 'and': return { $and: filter.conditions.map((x) => convertToMongoCondition(x)), }; case 'or': return { $or: filter.conditions.map((x) => convertToMongoCondition(x)), }; case 'binary': switch (filter.operator) { case '=': return { [convertLeftOperandToMongoColumn(filter.left)]: convertRightEqualOperandToMongoCondition(filter.right), }; case '!=': case '<>': return { [convertLeftOperandToMongoColumn(filter.left)]: { $ne: convertRightOperandToMongoValue(filter.right), }, }; case '<': return { [convertLeftOperandToMongoColumn(filter.left)]: { $lt: convertRightOperandToMongoValue(filter.right), }, }; case '<=': return { [convertLeftOperandToMongoColumn(filter.left)]: { $lte: convertRightOperandToMongoValue(filter.right), }, }; case '>': return { [convertLeftOperandToMongoColumn(filter.left)]: { $gt: convertRightOperandToMongoValue(filter.right), }, }; case '>=': return { [convertLeftOperandToMongoColumn(filter.left)]: { $gte: convertRightOperandToMongoValue(filter.right), }, }; } break; case 'isNull': return { [convertLeftOperandToMongoColumn(filter.expr)]: { $exists: false, }, }; case 'isNotNull': return { [convertLeftOperandToMongoColumn(filter.expr)]: { $exists: true, }, }; case 'not': return { $not: convertToMongoCondition(filter.condition), }; case 'like': return { [convertLeftOperandToMongoColumn(filter.left)]: { $regex: `${convertRightOperandToMongoValue(filter.right)}`.replace(/%/g, '.*'), $options: 'i', }, }; case 'specificPredicate': switch (filter.predicate) { case 'exists': return { [convertLeftOperandToMongoColumn(filter.expr)]: { $exists: true, }, }; case 'notExists': return { [convertLeftOperandToMongoColumn(filter.expr)]: { $exists: false, }, }; case 'emptyArray': return { [convertLeftOperandToMongoColumn(filter.expr)]: { $exists: true, $eq: [], }, }; case 'notEmptyArray': return { [convertLeftOperandToMongoColumn(filter.expr)]: { $exists: true, $type: 'array', $ne: [], }, }; } case 'in': return { [convertLeftOperandToMongoColumn(filter.expr)]: { $in: filter.values, }, }; default: throw new Error(`Unknown condition type ${filter.conditionType}`); } } function convertToMongoAggregateFunction(aggregate) { switch (aggregate.aggregateFunction) { case 'count': return { $sum: 1 }; case 'sum': return { $sum: `$${aggregate.columnArgument}` }; case 'avg': return { $avg: `$${aggregate.columnArgument}` }; case 'min': return { $min: `$${aggregate.columnArgument}` }; case 'max': return { $max: `$${aggregate.columnArgument}` }; default: throw new Error(`Unknown aggregate function ${aggregate.aggregateFunction}`); } } function convertToMongoAggregate(collectionAggregate) { return [ { $match: convertToMongoCondition(collectionAggregate.condition) }, { $group: { _id: _zipObject( collectionAggregate.groupByColumns, collectionAggregate.groupByColumns.map((col) => '$' + col) ), ..._zipObject( collectionAggregate.aggregateColumns.map((col) => col.alias), collectionAggregate.aggregateColumns.map((col) => convertToMongoAggregateFunction(col)) ), count: { $sum: 1 }, }, }, ]; } function convertToMongoSort(sort) { if (!sort) return null; return _zipObject( sort.map((col) => col.columnName), sort.map((col) => (col.direction == 'DESC' ? -1 : 1)) ); } module.exports = { convertToMongoCondition, convertToMongoAggregate, convertToMongoSort, };