UNPKG

shyft

Version:

Model driven GraphQL API framework

362 lines (361 loc) 16.8 kB
"use strict"; 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;