86 lines
2.9 KiB
JavaScript
86 lines
2.9 KiB
JavaScript
/**
|
|
* Utility functions for working with MongoDB queries and expansions.
|
|
* @module utils
|
|
*/
|
|
|
|
const mongoUtils = require('@tryghost/mongo-utils');
|
|
const nqlLang = require('@tryghost/nql-lang');
|
|
const _ = require('lodash');
|
|
|
|
/**
|
|
* Parses the expansions object and converts the expansion strings into parsed NQL expressions.
|
|
* @param {Object} expansions - The expansions object.
|
|
* @returns {Object[]} - The parsed expansions.
|
|
*/
|
|
const parseExpansions = (expansions) => {
|
|
if (!expansions || Object.keys(expansions).length === 0) {
|
|
return expansions;
|
|
}
|
|
|
|
return expansions.map((expansion) => {
|
|
const parsed = Object.assign({}, expansion);
|
|
|
|
if (parsed.expansion) {
|
|
parsed.expansion = nqlLang.parse(expansion.expansion);
|
|
}
|
|
|
|
return parsed;
|
|
});
|
|
};
|
|
|
|
/**
|
|
* Expands the filters in the given MongoDB query using the provided expansions.
|
|
* @param {Object} mongoJSON - The MongoDB query object.
|
|
* @param {Object[]} expansions - The parsed expansions.
|
|
* @returns {Object} - The expanded MongoDB query object.
|
|
*/
|
|
const expandFilters = (mongoJSON, expansions) => {
|
|
const parsedExpansions = parseExpansions(expansions);
|
|
|
|
return mongoUtils.expandFilters(mongoJSON, parsedExpansions);
|
|
};
|
|
|
|
/**
|
|
* Combines multiple '$ne' filters of the same type within an '$and' operator into a single '$nin' filter.
|
|
* Can handle nested '$and' operators.
|
|
*
|
|
* @param {Object} mongoJSON - The MongoDB query object.
|
|
* @returns {Object} - The modified MongoDB query object.
|
|
*/
|
|
const combineNeFilters = (mongoJSON) => {
|
|
// this should only be necessary when we have '$and' with multiple child '$ne' filters of the same type
|
|
if (mongoJSON.$and && mongoUtils.findStatement(mongoJSON, '$ne')) {
|
|
const andFilters = mongoJSON.$and;
|
|
const neFilters = andFilters.filter(filter => mongoUtils.findStatement(filter, '$ne'));
|
|
const neGroups = _.groupBy(neFilters, filter => Object.keys(filter)[0]);
|
|
const neKeys = Object.keys(neGroups);
|
|
const neKeysWithMultipleFilters = neKeys.filter(key => neGroups[key].length > 1);
|
|
neKeysWithMultipleFilters.forEach((key) => {
|
|
const neValues = neGroups[key].map(filter => filter[key].$ne);
|
|
mongoJSON[key] = {$nin: neValues};
|
|
neGroups[key].forEach((filter) => {
|
|
andFilters.splice(andFilters.indexOf(filter), 1);
|
|
});
|
|
});
|
|
if (andFilters.length === 0) {
|
|
delete mongoJSON.$and;
|
|
}
|
|
}
|
|
// recursively call to handle nested $and operators
|
|
for (const key in mongoJSON) {
|
|
if (key === '$and') {
|
|
mongoJSON[key] = mongoJSON[key].map((filter) => {
|
|
return combineNeFilters(filter);
|
|
});
|
|
}
|
|
}
|
|
return mongoJSON;
|
|
};
|
|
|
|
module.exports = {
|
|
mergeFilters: mongoUtils.mergeFilters,
|
|
parseExpansions: parseExpansions,
|
|
expandFilters: expandFilters,
|
|
combineNeFilters: combineNeFilters
|
|
};
|