UNPKG

typeorm

Version:

Data-Mapper ORM for TypeScript, ES7, ES6, ES5. Supports MySQL, PostgreSQL, MariaDB, SQLite, MS SQL Server, Oracle, MongoDB databases.

300 lines (298 loc) • 14.6 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.FindOptionsUtils = void 0; var tslib_1 = require("tslib"); var FindRelationsNotFoundError_1 = require("../error/FindRelationsNotFoundError"); var DriverUtils_1 = require("../driver/DriverUtils"); var error_1 = require("../error"); /** * Utilities to work with FindOptions. */ var FindOptionsUtils = /** @class */ (function () { function FindOptionsUtils() { } // ------------------------------------------------------------------------- // Public Static Methods // ------------------------------------------------------------------------- /** * Checks if given object is really instance of FindOneOptions interface. */ FindOptionsUtils.isFindOneOptions = function (obj) { var possibleOptions = obj; return possibleOptions && (Array.isArray(possibleOptions.select) || possibleOptions.where instanceof Object || typeof possibleOptions.where === "string" || Array.isArray(possibleOptions.relations) || possibleOptions.join instanceof Object || possibleOptions.order instanceof Object || possibleOptions.cache instanceof Object || typeof possibleOptions.cache === "boolean" || typeof possibleOptions.cache === "number" || possibleOptions.lock instanceof Object || possibleOptions.loadRelationIds instanceof Object || typeof possibleOptions.loadRelationIds === "boolean" || typeof possibleOptions.loadEagerRelations === "boolean" || typeof possibleOptions.withDeleted === "boolean" || typeof possibleOptions.transaction === "boolean"); }; /** * Checks if given object is really instance of FindManyOptions interface. */ FindOptionsUtils.isFindManyOptions = function (obj) { var possibleOptions = obj; return possibleOptions && (this.isFindOneOptions(possibleOptions) || typeof possibleOptions.skip === "number" || typeof possibleOptions.take === "number" || typeof possibleOptions.skip === "string" || typeof possibleOptions.take === "string"); }; /** * Checks if given object is really instance of FindOptions interface. */ FindOptionsUtils.extractFindManyOptionsAlias = function (object) { if (this.isFindManyOptions(object) && object.join) return object.join.alias; return undefined; }; /** * Applies give find many options to the given query builder. */ FindOptionsUtils.applyFindManyOptionsOrConditionsToQueryBuilder = function (qb, options) { if (this.isFindManyOptions(options)) return this.applyOptionsToQueryBuilder(qb, options); if (options) return qb.where(options); return qb; }; /** * Applies give find options to the given query builder. */ FindOptionsUtils.applyOptionsToQueryBuilder = function (qb, options) { // if options are not set then simply return query builder. This is made for simplicity of usage. if (!options || (!this.isFindOneOptions(options) && !this.isFindManyOptions(options))) return qb; if (options.transaction === true) { qb.expressionMap.useTransaction = true; } if (!qb.expressionMap.mainAlias || !qb.expressionMap.mainAlias.hasMetadata) return qb; var metadata = qb.expressionMap.mainAlias.metadata; // apply all options from FindOptions if (options.withDeleted) { qb.withDeleted(); } if (options.select) { qb.select([]); options.select.forEach(function (select) { var e_1, _a; if (!metadata.hasColumnWithPropertyPath("" + select)) throw new error_1.TypeORMError(select + " column was not found in the " + metadata.name + " entity."); var columns = metadata.findColumnsWithPropertyPath("" + select); try { for (var columns_1 = tslib_1.__values(columns), columns_1_1 = columns_1.next(); !columns_1_1.done; columns_1_1 = columns_1.next()) { var column = columns_1_1.value; qb.addSelect(qb.alias + "." + column.propertyPath); } } catch (e_1_1) { e_1 = { error: e_1_1 }; } finally { try { if (columns_1_1 && !columns_1_1.done && (_a = columns_1.return)) _a.call(columns_1); } finally { if (e_1) throw e_1.error; } } }); } if (options.relations) { // Copy because `applyRelationsRecursively` modifies it var allRelations = tslib_1.__spreadArray([], tslib_1.__read(options.relations)); this.applyRelationsRecursively(qb, allRelations, qb.expressionMap.mainAlias.name, qb.expressionMap.mainAlias.metadata, ""); // recursive removes found relations from allRelations array // if there are relations left in this array it means those relations were not found in the entity structure // so, we give an exception about not found relations if (allRelations.length > 0) throw new FindRelationsNotFoundError_1.FindRelationsNotFoundError(allRelations); } if (options.join) { if (options.join.leftJoin) Object.keys(options.join.leftJoin).forEach(function (key) { qb.leftJoin(options.join.leftJoin[key], key); }); if (options.join.innerJoin) Object.keys(options.join.innerJoin).forEach(function (key) { qb.innerJoin(options.join.innerJoin[key], key); }); if (options.join.leftJoinAndSelect) Object.keys(options.join.leftJoinAndSelect).forEach(function (key) { qb.leftJoinAndSelect(options.join.leftJoinAndSelect[key], key); }); if (options.join.innerJoinAndSelect) Object.keys(options.join.innerJoinAndSelect).forEach(function (key) { qb.innerJoinAndSelect(options.join.innerJoinAndSelect[key], key); }); } if (options.cache) { if (options.cache instanceof Object) { var cache = options.cache; qb.cache(cache.id, cache.milliseconds); } else { qb.cache(options.cache); } } if (options.lock) { if (options.lock.mode === "optimistic") { qb.setLock(options.lock.mode, options.lock.version); } else if (options.lock.mode === "pessimistic_read" || options.lock.mode === "pessimistic_write" || options.lock.mode === "dirty_read" || options.lock.mode === "pessimistic_partial_write" || options.lock.mode === "pessimistic_write_or_fail") { var tableNames = options.lock.tables ? options.lock.tables.map(function (table) { var tableAlias = qb.expressionMap.aliases.find(function (alias) { return alias.metadata.tableNameWithoutPrefix === table; }); if (!tableAlias) { throw new error_1.TypeORMError("\"" + table + "\" is not part of this query"); } return qb.escape(tableAlias.name); }) : undefined; qb.setLock(options.lock.mode, undefined, tableNames); } } if (options.loadRelationIds === true) { qb.loadAllRelationIds(); } else if (options.loadRelationIds instanceof Object) { qb.loadAllRelationIds(options.loadRelationIds); } if (options.where) qb.where(options.where); if (options.skip) qb.skip(options.skip); if (options.take) qb.take(options.take); if (options.order) Object.keys(options.order).forEach(function (key) { var order = options.order[key]; if (!metadata.findColumnWithPropertyPath(key)) throw new Error(key + " column was not found in the " + metadata.name + " entity."); switch (order) { case 1: qb.addOrderBy(qb.alias + "." + key, "ASC"); break; case -1: qb.addOrderBy(qb.alias + "." + key, "DESC"); break; case "ASC": qb.addOrderBy(qb.alias + "." + key, "ASC"); break; case "DESC": qb.addOrderBy(qb.alias + "." + key, "DESC"); break; } }); return qb; }; // ------------------------------------------------------------------------- // Protected Static Methods // ------------------------------------------------------------------------- /** * Adds joins for all relations and sub-relations of the given relations provided in the find options. */ FindOptionsUtils.applyRelationsRecursively = function (qb, allRelations, alias, metadata, prefix) { var _this = this; // find all relations that match given prefix var matchedBaseRelations = []; if (prefix) { var regexp_1 = new RegExp("^" + prefix.replace(".", "\\.") + "\\."); matchedBaseRelations = allRelations .filter(function (relation) { return relation.match(regexp_1); }) .map(function (relation) { return relation.replace(regexp_1, ""); }) .filter(function (relation) { return metadata.findRelationWithPropertyPath(relation); }); } else { matchedBaseRelations = allRelations.filter(function (relation) { return metadata.findRelationWithPropertyPath(relation); }); } // go through all matched relations and add join for them matchedBaseRelations.forEach(function (relation) { // generate a relation alias var relationAlias = DriverUtils_1.DriverUtils.buildAlias(qb.connection.driver, { shorten: true, joiner: "__" }, alias, relation); // add a join for the found relation var selection = alias + "." + relation; qb.leftJoinAndSelect(selection, relationAlias); // remove added relations from the allRelations array, this is needed to find all not found relations at the end allRelations.splice(allRelations.indexOf(prefix ? prefix + "." + relation : relation), 1); // try to find sub-relations var join = qb.expressionMap.joinAttributes.find(function (join) { return join.entityOrProperty === selection; }); _this.applyRelationsRecursively(qb, allRelations, join.alias.name, join.metadata, prefix ? prefix + "." + relation : relation); // join the eager relations of the found relation var relMetadata = metadata.relations.find(function (metadata) { return metadata.propertyName === relation; }); if (relMetadata) { _this.joinEagerRelations(qb, relationAlias, relMetadata.inverseEntityMetadata); } }); }; FindOptionsUtils.joinEagerRelations = function (qb, alias, metadata) { var _this = this; metadata.eagerRelations.forEach(function (relation) { var e_2, _a, e_3, _b; // generate a relation alias var relationAlias = DriverUtils_1.DriverUtils.buildAlias(qb.connection.driver, { shorten: true }, qb.connection.namingStrategy.eagerJoinRelationAlias(alias, relation.propertyPath)); // add a join for the relation // Checking whether the relation wasn't joined yet. var addJoin = true; try { for (var _c = tslib_1.__values(qb.expressionMap.joinAttributes), _d = _c.next(); !_d.done; _d = _c.next()) { var join = _d.value; if (join.condition !== undefined || join.mapToProperty !== undefined || join.isMappingMany !== undefined || join.direction !== "LEFT" || join.entityOrProperty !== alias + "." + relation.propertyPath) { continue; } addJoin = false; relationAlias = join.alias.name; break; } } catch (e_2_1) { e_2 = { error: e_2_1 }; } finally { try { if (_d && !_d.done && (_a = _c.return)) _a.call(_c); } finally { if (e_2) throw e_2.error; } } if (addJoin) { qb.leftJoin(alias + "." + relation.propertyPath, relationAlias); } // Checking whether the relation wasn't selected yet. // This check shall be after the join check to detect relationAlias. var addSelect = true; try { for (var _e = tslib_1.__values(qb.expressionMap.selects), _f = _e.next(); !_f.done; _f = _e.next()) { var select = _f.value; if (select.aliasName !== undefined || select.virtual !== undefined || select.selection !== relationAlias) { continue; } addSelect = false; break; } } catch (e_3_1) { e_3 = { error: e_3_1 }; } finally { try { if (_f && !_f.done && (_b = _e.return)) _b.call(_e); } finally { if (e_3) throw e_3.error; } } if (addSelect) { qb.addSelect(relationAlias); } // (recursive) join the eager relations _this.joinEagerRelations(qb, relationAlias, relation.inverseEntityMetadata); }); }; return FindOptionsUtils; }()); exports.FindOptionsUtils = FindOptionsUtils; //# sourceMappingURL=FindOptionsUtils.js.map