Files
dbgate/plugins/dbgate-plugin-mongo/src/frontend/convertToMongoCondition.js
2025-04-30 08:36:56 +02:00

200 lines
5.3 KiB
JavaScript

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,
};