shyft
Version:
Model driven GraphQL API framework
362 lines (361 loc) • 16.8 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.buildWhereQuery = exports.buildWhereTypeQuery = exports.processAndConvertFilter = exports.purifyFilter = void 0;
var __1 = require("..");
var typeorm_1 = require("typeorm");
var util_1 = require("./util");
var noResultClause = 'TRUE IS FALSE';
var purifyFilter = function (filter) {
if (__1.isMap(filter)) {
if (__1.isMap(filter, true)) {
var ret_1 = {};
Object.keys(filter).map(function (key) {
var isOperator = key.indexOf('$') === 0;
if (['$in', '$notIn'].includes(key) && __1.isArray(filter[key])) {
ret_1[key] = filter[key];
}
else if (filter[key] === null && (key === '$ne' || !isOperator)) {
ret_1[key] = filter[key];
}
else {
var pureFilter = exports.purifyFilter(filter[key]);
if (pureFilter !== null && typeof pureFilter !== 'undefined') {
ret_1[key] = pureFilter;
}
}
});
if (__1.isMap(ret_1, true)) {
return ret_1;
}
}
}
else if (__1.isArray(filter)) {
if (__1.isArray(filter, true)) {
var ret_2 = [];
filter.map(function (subFilter) {
var pureFilter = exports.purifyFilter(subFilter);
if (pureFilter !== null && typeof pureFilter !== 'undefined') {
ret_2.push(pureFilter);
}
});
if (ret_2.length) {
return ret_2;
}
}
}
else if (filter !== null && typeof filter !== 'undefined') {
return filter;
}
return null;
};
exports.purifyFilter = purifyFilter;
var processAndConvertFilter = function (entity, filterShaper, args, StorageTypePostgres) {
var where = __1.processFilter(entity, args, StorageTypePostgres);
var convertedWhere = __1.convertFilterLevel(filterShaper, where);
return convertedWhere;
};
exports.processAndConvertFilter = processAndConvertFilter;
var escapeILikePattern = function (pattern) {
return pattern.replace(/%/g, '\\%').replace(/_/g, '\\_');
};
var defaultTransformFilterAttributeName = function (attributeName) { return attributeName; };
var buildWhereAttributeOperatorConditionQuery = function (qBuilder, attributeName, operator, value, transformFilterAttributeNameFn, _placeholderIdx) {
var _a, _b, _c, _d, _e, _f, _g;
if (transformFilterAttributeNameFn === void 0) { transformFilterAttributeNameFn = defaultTransformFilterAttributeName; }
if (_placeholderIdx === void 0) { _placeholderIdx = null; }
var placeholderIdx = _placeholderIdx || { idx: 0 };
placeholderIdx.idx++;
var placeholderName = (attributeName + "__" + placeholderIdx.idx).replace('.', '__');
var data = (_a = {}, _a[placeholderName] = value, _a);
var leftExpression = util_1.quote(transformFilterAttributeNameFn(attributeName));
switch (operator) {
case '$eq':
if (value === null) {
qBuilder.andWhere(leftExpression + " IS NULL");
}
else {
qBuilder.andWhere(leftExpression + " = :" + placeholderName, data);
}
break;
case '$ne':
if (value === null) {
qBuilder.andWhere(leftExpression + " IS NOT NULL", data);
}
else {
qBuilder.andWhere(leftExpression + " <> :" + placeholderName, data);
}
break;
case '$in':
if (!value || !value.length) {
qBuilder.andWhere(noResultClause);
}
else {
qBuilder.andWhere(leftExpression + " IN (:..." + placeholderName + ")", data);
}
break;
case '$notIn':
if (!value || !value.length) {
qBuilder.andWhere(noResultClause);
}
else {
qBuilder.andWhere(leftExpression + " NOT IN (:..." + placeholderName + ")", data);
}
break;
case '$lt':
qBuilder.andWhere(leftExpression + " < :" + placeholderName, data);
break;
case '$lte':
qBuilder.andWhere(leftExpression + " <= :" + placeholderName, data);
break;
case '$gt':
qBuilder.andWhere(leftExpression + " > :" + placeholderName, data);
break;
case '$gte':
qBuilder.andWhere(leftExpression + " >= :" + placeholderName, data);
break;
case '$contains':
qBuilder.andWhere(leftExpression + " ILIKE :" + placeholderName, (_b = {},
_b[placeholderName] = "%" + escapeILikePattern(value) + "%",
_b));
break;
case '$startsWith':
qBuilder.andWhere(leftExpression + " ILIKE :" + placeholderName, (_c = {},
_c[placeholderName] = escapeILikePattern(value) + "%",
_c));
break;
case '$endsWith':
qBuilder.andWhere(leftExpression + " ILIKE :" + placeholderName, (_d = {},
_d[placeholderName] = "%" + escapeILikePattern(value),
_d));
break;
case '$notContains':
qBuilder.andWhere(leftExpression + " NOT ILIKE :" + placeholderName, (_e = {},
_e[placeholderName] = "%" + escapeILikePattern(value) + "%",
_e));
break;
case '$notStartsWith':
qBuilder.andWhere(leftExpression + " NOT ILIKE :" + placeholderName, (_f = {},
_f[placeholderName] = escapeILikePattern(value) + "%",
_f));
break;
case '$notEndsWith':
qBuilder.andWhere(leftExpression + " NOT ILIKE :" + placeholderName, (_g = {},
_g[placeholderName] = "%" + escapeILikePattern(value),
_g));
break;
case '$includes':
qBuilder.andWhere(leftExpression + " ? :" + placeholderName, data);
break;
case '$notIncludes':
qBuilder.andWhere("NOT " + leftExpression + " ? :" + placeholderName, data);
break;
case '$isNull':
if (!!value) {
qBuilder.andWhere(leftExpression + " IS NULL", data);
}
else {
qBuilder.andWhere(leftExpression + " IS NOT NULL", data);
}
break;
case '$noResult':
qBuilder.andWhere(noResultClause);
break;
default:
throw new Error("Unknown filter operator: " + operator);
}
};
var buildWhereAttributeConditionQuery = function (qBuilder, attributeName, filter, transformFilterAttributeNameFn, _placeholderIdx) {
var placeholderIdx = _placeholderIdx || { idx: 0 };
placeholderIdx.idx++;
if (__1.isMap(filter)) {
var operators = Object.keys(filter);
operators.map(function (operator) {
var value = filter[operator];
buildWhereAttributeOperatorConditionQuery(qBuilder, attributeName, operator, value, transformFilterAttributeNameFn, placeholderIdx);
});
}
else {
buildWhereAttributeOperatorConditionQuery(qBuilder, attributeName, '$eq', filter, transformFilterAttributeNameFn, placeholderIdx);
}
};
var buildWhereTypeSubQuery = function (qBuilder, filter, entityName, modelRegistry, isGetMany, transformFilterAttributeNameFn, _placeholderIdx) {
if (!filter.entity) {
throw new Error('$sub expects an entity name');
}
if (!__1.isArray(filter.condition, true)) {
throw new Error('$sub expects an array of conditions');
}
var dataShaperMap = modelRegistry[entityName].dataShaperMap;
var _a = modelRegistry[filter.entity], targetDataShaperMap = _a.dataShaperMap, filterEntityStorageTableName = _a.storageTableName;
var isSelfLookup = entityName === filter.entity;
var inOperatorLink;
if (isGetMany) {
inOperatorLink = filter.condition.find(function (_a) {
var sourceAttribute = _a.sourceAttribute;
return !!sourceAttribute;
});
if (!inOperatorLink && isSelfLookup) {
inOperatorLink = {
targetAttribute: 'id',
operator: '$eq',
sourceAttribute: 'id',
};
}
}
qBuilder.andWhere(function (qbSub) {
var subQuery;
if (qbSub.subQuery) {
subQuery = qbSub.subQuery();
}
else {
// typeorm cannot run subqueries on delete queries so we need to create a fresh query,
// which will be injected in to the outer query at the end
subQuery = qbSub.connection.manager.createQueryBuilder();
}
if (isGetMany && inOperatorLink) {
var targetAttributeName = targetDataShaperMap[inOperatorLink.targetAttribute] ||
inOperatorLink.targetAttribute;
subQuery
.select(targetAttributeName)
.from(filterEntityStorageTableName, filterEntityStorageTableName);
}
else {
subQuery
.select('COUNT(*) > 0', 'found')
.from(filterEntityStorageTableName, filterEntityStorageTableName);
}
var conditions = isGetMany && inOperatorLink
? filter.condition.filter(function (condition) { return condition !== inOperatorLink; })
: filter.condition;
conditions.map(function (_a) {
var targetAttribute = _a.targetAttribute, operator = _a.operator, sourceAttribute = _a.sourceAttribute, value = _a.value;
var targetAttributeName = targetDataShaperMap[targetAttribute] || targetAttribute;
if (sourceAttribute) {
var storageTableName = modelRegistry[entityName].storageTableName;
var sourceAttributeName = storageTableName + "." + (dataShaperMap[sourceAttribute] || sourceAttribute);
subQuery.andWhere(util_1.quote(targetAttributeName) + " = " + util_1.quote(sourceAttributeName));
}
else {
buildWhereAttributeOperatorConditionQuery(subQuery, targetAttributeName, operator, value, transformFilterAttributeNameFn, _placeholderIdx);
}
});
var query = subQuery.getQuery();
if (isGetMany && inOperatorLink) {
var sourceAttributeName = dataShaperMap[inOperatorLink.sourceAttribute] ||
inOperatorLink.sourceAttribute;
query = util_1.quote(sourceAttributeName) + " IN " + query;
}
// inject query params into outer query (as typeorm cannot run subqueries on delete queries)
if (!qbSub.subQuery) {
qbSub.setParameters(subQuery.getParameters());
}
return query;
});
};
var buildWhereTypeQuery = function (filter, entityName, modelRegistry, isGetMany, transformFilterAttributeNameFn, _placeholderIdx) {
var placeholderIdx = _placeholderIdx || { idx: 0 };
placeholderIdx.idx++;
var dataShaperMap = modelRegistry[entityName].dataShaperMap;
if (__1.isMap(filter)) {
if (__1.isMap(filter, true)) {
return new typeorm_1.Brackets(function (qbAnd) {
var keys = Object.keys(filter);
keys.map(function (key) {
var newFilter = filter[key];
if (key === '$and') {
if (!__1.isArray(newFilter)) {
throw new Error('$and expects an array of filters');
}
var andFilters_1 = [];
newFilter.map(function (andFilter) {
if (__1.isMap(andFilter, true)) {
andFilters_1.push(andFilter);
}
});
if (andFilters_1.length) {
newFilter.map(function (val) {
var where = exports.buildWhereTypeQuery(val, entityName, modelRegistry, isGetMany, transformFilterAttributeNameFn, placeholderIdx);
if (where) {
qbAnd.andWhere(where);
}
});
}
}
else if (key === '$or') {
if (!__1.isArray(newFilter)) {
throw new Error('$or expects an array of filters');
}
var orFilters_1 = [];
newFilter.map(function (orFilter) {
if (__1.isMap(orFilter, true)) {
orFilters_1.push(orFilter);
}
});
if (orFilters_1.length) {
var orBrackets = new typeorm_1.Brackets(function (qbOr) {
newFilter.map(function (val) {
var where = exports.buildWhereTypeQuery(val, entityName, modelRegistry, isGetMany, transformFilterAttributeNameFn, placeholderIdx);
if (where) {
qbOr.orWhere(where);
}
});
});
qbAnd.andWhere(orBrackets);
}
}
else if (key === '$sub') {
buildWhereTypeSubQuery(qbAnd, newFilter, entityName, modelRegistry, isGetMany, transformFilterAttributeNameFn, _placeholderIdx);
}
else if (key === '$not') {
if (!__1.isMap(newFilter)) {
throw new Error('$not expects a filter');
}
if (__1.isMap(newFilter, true)) {
var where_1 = exports.buildWhereTypeQuery(newFilter, entityName, modelRegistry, isGetMany, transformFilterAttributeNameFn, placeholderIdx);
if (where_1) {
var notBrackets = new typeorm_1.Brackets(function (qbNot) {
qbNot.andWhere(where_1);
});
// tiny workaround to get the brackets conditions negated
// TODO: add expressionMap to WhereExpression type
// eslint-disable-next-line dot-notation
qbAnd['expressionMap'].wheres.push({
type: 'simple',
condition: 'NOT',
});
// TODO: add expressionMap to WhereExpression type
// eslint-disable-next-line dot-notation
qbAnd['expressionMap'].wheres.push({
type: 'simple',
// TODO: computeWhereParameter does not exist on WhereExpression
// eslint-disable-next-line dot-notation
condition: qbAnd['computeWhereParameter'](notBrackets),
});
}
}
}
else if (key.indexOf('$') === 0) {
throw new Error('missing attribute name for filter operator');
}
else {
var attributeName = dataShaperMap[key] || key;
buildWhereAttributeConditionQuery(qbAnd, attributeName, newFilter, transformFilterAttributeNameFn, placeholderIdx);
}
});
});
}
}
return null;
};
exports.buildWhereTypeQuery = buildWhereTypeQuery;
var buildWhereQuery = function (qBuilder, filter, entityName, modelRegistry, isGetMany, transformFilterAttributeNameFn) {
if (!modelRegistry || !modelRegistry[entityName]) {
throw new Error('buildWhereQuery() is missing a valid modelRegistry parameter');
}
var pureFilter = exports.purifyFilter(filter);
var where = exports.buildWhereTypeQuery(pureFilter, entityName, modelRegistry, isGetMany, transformFilterAttributeNameFn);
if (where) {
qBuilder.andWhere(where);
}
};
exports.buildWhereQuery = buildWhereQuery;