shyft-storage-connector
Version:
Storage connector for Shyft
413 lines (333 loc) • 14.9 kB
JavaScript
;
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.buildWhereQuery = exports.buildWhereTypeQuery = exports.processAndConvertFilter = exports.purifyFilter = void 0;
var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
var _shyft = require("shyft");
var _typeorm = require("typeorm");
var _util = require("./util");
var noResultClause = 'TRUE IS FALSE';
var purifyFilter = function purifyFilter(filter) {
if ((0, _shyft.isMap)(filter)) {
if ((0, _shyft.isMap)(filter, true)) {
var ret = {};
Object.keys(filter).map(function (key) {
var isOperator = key.indexOf('$') === 0;
if (['$in', '$notIn'].includes(key) && (0, _shyft.isArray)(filter[key])) {
ret[key] = filter[key];
} else if (filter[key] === null && (key === '$ne' || !isOperator)) {
ret[key] = filter[key];
} else {
var pureFilter = purifyFilter(filter[key]);
if (pureFilter !== null && typeof pureFilter !== 'undefined') {
ret[key] = pureFilter;
}
}
});
if ((0, _shyft.isMap)(ret, true)) {
return ret;
}
}
} else if ((0, _shyft.isArray)(filter)) {
if ((0, _shyft.isArray)(filter, true)) {
var _ret = [];
filter.map(function (subFilter) {
var pureFilter = purifyFilter(subFilter);
if (pureFilter !== null && typeof pureFilter !== 'undefined') {
_ret.push(pureFilter);
}
});
if (_ret.length) {
return _ret;
}
}
} else if (filter !== null && typeof filter !== 'undefined') {
return filter;
}
return null;
};
exports.purifyFilter = purifyFilter;
var processAndConvertFilter = function processAndConvertFilter(entity, filterShaper, args, StorageTypePostgres) {
var where = (0, _shyft.processFilter)(entity, args, StorageTypePostgres);
var convertedWhere = (0, _shyft.convertFilterLevel)(filterShaper, where);
return convertedWhere;
};
exports.processAndConvertFilter = processAndConvertFilter;
var escapeILikePattern = function escapeILikePattern(pattern) {
return pattern.replace(/%/g, '\\%').replace(/_/g, '\\_');
};
var defaultTransformFilterAttributeName = function defaultTransformFilterAttributeName(attributeName) {
return attributeName;
};
var buildWhereAttributeOperatorConditionQuery = function buildWhereAttributeOperatorConditionQuery(qBuilder, attributeName, operator, value) {
var transformFilterAttributeNameFn = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : defaultTransformFilterAttributeName;
var _placeholderIdx = arguments.length > 5 && arguments[5] !== undefined ? arguments[5] : null;
var placeholderIdx = _placeholderIdx || {
idx: 0
};
placeholderIdx.idx++;
var placeholderName = "".concat(attributeName, "__").concat(placeholderIdx.idx).replace('.', '__');
var data = (0, _defineProperty2["default"])({}, placeholderName, value);
var leftExpression = (0, _util.quote)(transformFilterAttributeNameFn(attributeName));
switch (operator) {
case '$eq':
if (value === null) {
qBuilder.andWhere("".concat(leftExpression, " IS NULL"));
} else {
qBuilder.andWhere("".concat(leftExpression, " = :").concat(placeholderName), data);
}
break;
case '$ne':
if (value === null) {
qBuilder.andWhere("".concat(leftExpression, " IS NOT NULL"), data);
} else {
qBuilder.andWhere("".concat(leftExpression, " <> :").concat(placeholderName), data);
}
break;
case '$in':
if (!value || !value.length) {
qBuilder.andWhere(noResultClause);
} else {
qBuilder.andWhere("".concat(leftExpression, " IN (:...").concat(placeholderName, ")"), data);
}
break;
case '$notIn':
if (!value || !value.length) {
qBuilder.andWhere(noResultClause);
} else {
qBuilder.andWhere("".concat(leftExpression, " NOT IN (:...").concat(placeholderName, ")"), data);
}
break;
case '$lt':
qBuilder.andWhere("".concat(leftExpression, " < :").concat(placeholderName), data);
break;
case '$lte':
qBuilder.andWhere("".concat(leftExpression, " <= :").concat(placeholderName), data);
break;
case '$gt':
qBuilder.andWhere("".concat(leftExpression, " > :").concat(placeholderName), data);
break;
case '$gte':
qBuilder.andWhere("".concat(leftExpression, " >= :").concat(placeholderName), data);
break;
case '$contains':
qBuilder.andWhere("".concat(leftExpression, " ILIKE :").concat(placeholderName), (0, _defineProperty2["default"])({}, placeholderName, "%".concat(escapeILikePattern(value), "%")));
break;
case '$startsWith':
qBuilder.andWhere("".concat(leftExpression, " ILIKE :").concat(placeholderName), (0, _defineProperty2["default"])({}, placeholderName, "".concat(escapeILikePattern(value), "%")));
break;
case '$endsWith':
qBuilder.andWhere("".concat(leftExpression, " ILIKE :").concat(placeholderName), (0, _defineProperty2["default"])({}, placeholderName, "%".concat(escapeILikePattern(value))));
break;
case '$notContains':
qBuilder.andWhere("".concat(leftExpression, " NOT ILIKE :").concat(placeholderName), (0, _defineProperty2["default"])({}, placeholderName, "%".concat(escapeILikePattern(value), "%")));
break;
case '$notStartsWith':
qBuilder.andWhere("".concat(leftExpression, " NOT ILIKE :").concat(placeholderName), (0, _defineProperty2["default"])({}, placeholderName, "".concat(escapeILikePattern(value), "%")));
break;
case '$notEndsWith':
qBuilder.andWhere("".concat(leftExpression, " NOT ILIKE :").concat(placeholderName), (0, _defineProperty2["default"])({}, placeholderName, "%".concat(escapeILikePattern(value))));
break;
case '$includes':
qBuilder.andWhere("".concat(leftExpression, " ? :").concat(placeholderName), data);
break;
case '$notIncludes':
qBuilder.andWhere("NOT ".concat(leftExpression, " ? :").concat(placeholderName), data);
break;
case '$isNull':
if (!!value) {
qBuilder.andWhere("".concat(leftExpression, " IS NULL"), data);
} else {
qBuilder.andWhere("".concat(leftExpression, " IS NOT NULL"), data);
}
break;
case '$noResult':
qBuilder.andWhere(noResultClause);
break;
default:
throw new Error("Unknown filter operator: ".concat(operator));
}
};
var buildWhereAttributeConditionQuery = function buildWhereAttributeConditionQuery(qBuilder, attributeName, filter, transformFilterAttributeNameFn, _placeholderIdx) {
var placeholderIdx = _placeholderIdx || {
idx: 0
};
placeholderIdx.idx++;
if ((0, _shyft.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 buildWhereTypeSubQuery(qBuilder, filter, entityName, modelRegistry, isGetMany, transformFilterAttributeNameFn, _placeholderIdx) {
if (!filter.entity) {
throw new Error('$sub expects an entity name');
}
if (!(0, _shyft.isArray)(filter.condition, true)) {
throw new Error('$sub expects an array of conditions');
}
var dataShaperMap = modelRegistry[entityName].dataShaperMap;
var _modelRegistry$filter = modelRegistry[filter.entity],
targetDataShaperMap = _modelRegistry$filter.dataShaperMap,
filterEntityStorageTableName = _modelRegistry$filter.storageTableName;
var isSelfLookup = entityName === filter.entity;
var inOperatorLink;
if (isGetMany) {
inOperatorLink = filter.condition.find(function (_ref) {
var sourceAttribute = _ref.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 (_ref2) {
var targetAttribute = _ref2.targetAttribute,
operator = _ref2.operator,
sourceAttribute = _ref2.sourceAttribute,
value = _ref2.value;
var targetAttributeName = targetDataShaperMap[targetAttribute] || targetAttribute;
if (sourceAttribute) {
var storageTableName = modelRegistry[entityName].storageTableName;
var sourceAttributeName = "".concat(storageTableName, ".").concat(dataShaperMap[sourceAttribute] || sourceAttribute);
subQuery.andWhere("".concat((0, _util.quote)(targetAttributeName), " = ").concat((0, _util.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 = "".concat((0, _util.quote)(sourceAttributeName), " IN ").concat(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 buildWhereTypeQuery(filter, entityName, modelRegistry, isGetMany, transformFilterAttributeNameFn, _placeholderIdx) {
var placeholderIdx = _placeholderIdx || {
idx: 0
};
placeholderIdx.idx++;
var dataShaperMap = modelRegistry[entityName].dataShaperMap;
if ((0, _shyft.isMap)(filter)) {
if ((0, _shyft.isMap)(filter, true)) {
return new _typeorm.Brackets(function (qbAnd) {
var keys = Object.keys(filter);
keys.map(function (key) {
var newFilter = filter[key];
if (key === '$and') {
if (!(0, _shyft.isArray)(newFilter)) {
throw new Error('$and expects an array of filters');
}
var andFilters = [];
newFilter.map(function (andFilter) {
if ((0, _shyft.isMap)(andFilter, true)) {
andFilters.push(andFilter);
}
});
if (andFilters.length) {
newFilter.map(function (val) {
var where = buildWhereTypeQuery(val, entityName, modelRegistry, isGetMany, transformFilterAttributeNameFn, placeholderIdx);
if (where) {
qbAnd.andWhere(where);
}
});
}
} else if (key === '$or') {
if (!(0, _shyft.isArray)(newFilter)) {
throw new Error('$or expects an array of filters');
}
var orFilters = [];
newFilter.map(function (orFilter) {
if ((0, _shyft.isMap)(orFilter, true)) {
orFilters.push(orFilter);
}
});
if (orFilters.length) {
var orBrackets = new _typeorm.Brackets(function (qbOr) {
newFilter.map(function (val) {
var where = 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 (!(0, _shyft.isMap)(newFilter)) {
throw new Error('$not expects a filter');
}
if ((0, _shyft.isMap)(newFilter, true)) {
var where = buildWhereTypeQuery(newFilter, entityName, modelRegistry, isGetMany, transformFilterAttributeNameFn, placeholderIdx);
if (where) {
var notBrackets = new _typeorm.Brackets(function (qbNot) {
qbNot.andWhere(where);
}); // tiny workaround to get the brackets conditions negated
qbAnd.expressionMap.wheres.push({
type: 'simple',
condition: 'NOT'
});
qbAnd.expressionMap.wheres.push({
type: 'simple',
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 buildWhereQuery(qBuilder, filter, entityName, modelRegistry, isGetMany, transformFilterAttributeNameFn) {
if (!modelRegistry || !modelRegistry[entityName]) {
throw new Error('buildWhereQuery() is missing a valid modelRegistry parameter');
}
var pureFilter = purifyFilter(filter);
var where = buildWhereTypeQuery(pureFilter, entityName, modelRegistry, isGetMany, transformFilterAttributeNameFn);
if (where) {
qBuilder.andWhere(where);
}
};
exports.buildWhereQuery = buildWhereQuery;