UNPKG

typeorm

Version:

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

979 lines (977 loc) • 75.1 kB
var __extends = (this && this.__extends) || (function () { var extendStatics = Object.setPrototypeOf || ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; }; return function (d, b) { extendStatics(d, b); function __() { this.constructor = d; } d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); }; })(); var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; var __generator = (this && this.__generator) || function (thisArg, body) { var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; function verb(n) { return function (v) { return step([n, v]); }; } function step(op) { if (f) throw new TypeError("Generator is already executing."); while (_) try { if (f = 1, y && (t = y[op[0] & 2 ? "return" : op[0] ? "throw" : "next"]) && !(t = t.call(y, op[1])).done) return t; if (y = 0, t) op = [0, t.value]; switch (op[0]) { case 0: case 1: t = op; break; case 4: _.label++; return { value: op[1], done: false }; case 5: _.label++; y = op[1]; op = [0]; continue; case 7: op = _.ops.pop(); _.trys.pop(); continue; default: if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } if (t[2]) _.ops.pop(); _.trys.pop(); continue; } op = body.call(thisArg, _); } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; } }; import { RawSqlResultsToEntityTransformer } from "./transformer/RawSqlResultsToEntityTransformer"; import { SqlServerDriver } from "../driver/sqlserver/SqlServerDriver"; import { PessimisticLockTransactionRequiredError } from "../error/PessimisticLockTransactionRequiredError"; import { NoVersionOrUpdateDateColumnError } from "../error/NoVersionOrUpdateDateColumnError"; import { OptimisticLockVersionMismatchError } from "../error/OptimisticLockVersionMismatchError"; import { OptimisticLockCanNotBeUsedError } from "../error/OptimisticLockCanNotBeUsedError"; import { JoinAttribute } from "./JoinAttribute"; import { RelationIdAttribute } from "./relation-id/RelationIdAttribute"; import { RelationCountAttribute } from "./relation-count/RelationCountAttribute"; import { RelationIdLoader } from "./relation-id/RelationIdLoader"; import { RelationIdMetadataToAttributeTransformer } from "./relation-id/RelationIdMetadataToAttributeTransformer"; import { RelationCountLoader } from "./relation-count/RelationCountLoader"; import { RelationCountMetadataToAttributeTransformer } from "./relation-count/RelationCountMetadataToAttributeTransformer"; import { Broadcaster } from "../subscriber/Broadcaster"; import { QueryBuilder } from "./QueryBuilder"; import { LockNotSupportedOnGivenDriverError } from "../error/LockNotSupportedOnGivenDriverError"; import { MysqlDriver } from "../driver/mysql/MysqlDriver"; import { PostgresDriver } from "../driver/postgres/PostgresDriver"; import { OracleDriver } from "../driver/oracle/OracleDriver"; import { AbstractSqliteDriver } from "../driver/sqlite-abstract/AbstractSqliteDriver"; import { OffsetWithoutLimitNotSupportedError } from "../error/OffsetWithoutLimitNotSupportedError"; /** * Allows to build complex sql queries in a fashion way and execute those queries. */ var SelectQueryBuilder = /** @class */ (function (_super) { __extends(SelectQueryBuilder, _super); function SelectQueryBuilder() { return _super !== null && _super.apply(this, arguments) || this; } // ------------------------------------------------------------------------- // Public Implemented Methods // ------------------------------------------------------------------------- /** * Gets generated sql query without parameters being replaced. */ SelectQueryBuilder.prototype.getQuery = function () { var sql = this.createSelectExpression(); sql += this.createJoinExpression(); sql += this.createWhereExpression(); sql += this.createGroupByExpression(); sql += this.createHavingExpression(); sql += this.createOrderByExpression(); sql += this.createLimitOffsetExpression(); sql += this.createLockExpression(); sql = this.createLimitOffsetOracleSpecificExpression(sql); sql = sql.trim(); if (this.expressionMap.subQuery) sql = "(" + sql + ")"; return sql; }; // ------------------------------------------------------------------------- // Public Methods // ------------------------------------------------------------------------- /** * Creates a subquery - query that can be used inside other queries. */ SelectQueryBuilder.prototype.subQuery = function () { var qb = this.createQueryBuilder(); qb.expressionMap.subQuery = true; qb.expressionMap.parentQueryBuilder = this; return qb; }; /** * Creates SELECT query and selects given data. * Replaces all previous selections if they exist. */ SelectQueryBuilder.prototype.select = function (selection, selectionAliasName) { this.expressionMap.queryType = "select"; if (selection instanceof Array) { this.expressionMap.selects = selection.map(function (selection) { return ({ selection: selection }); }); } else if (selection instanceof Function) { var subQueryBuilder = selection(this.subQuery()); this.setParameters(subQueryBuilder.getParameters()); this.expressionMap.selects.push({ selection: subQueryBuilder.getQuery(), aliasName: selectionAliasName }); } else if (selection) { this.expressionMap.selects = [{ selection: selection, aliasName: selectionAliasName }]; } return this; }; /** * Adds new selection to the SELECT query. */ SelectQueryBuilder.prototype.addSelect = function (selection, selectionAliasName) { if (!selection) return this; if (selection instanceof Array) { this.expressionMap.selects = this.expressionMap.selects.concat(selection.map(function (selection) { return ({ selection: selection }); })); } else if (selection instanceof Function) { var subQueryBuilder = selection(this.subQuery()); this.setParameters(subQueryBuilder.getParameters()); this.expressionMap.selects.push({ selection: subQueryBuilder.getQuery(), aliasName: selectionAliasName }); } else if (selection) { this.expressionMap.selects.push({ selection: selection, aliasName: selectionAliasName }); } return this; }; /** * Specifies FROM which entity's table select/update/delete will be executed. * Also sets a main string alias of the selection data. * Removes all previously set from-s. */ SelectQueryBuilder.prototype.from = function (entityTarget, aliasName) { var mainAlias = this.createFromAlias(entityTarget, aliasName); this.expressionMap.setMainAlias(mainAlias); return this; }; /** * Specifies FROM which entity's table select/update/delete will be executed. * Also sets a main string alias of the selection data. */ SelectQueryBuilder.prototype.addFrom = function (entityTarget, aliasName) { var alias = this.createFromAlias(entityTarget, aliasName); if (!this.expressionMap.mainAlias) this.expressionMap.setMainAlias(alias); return this; }; /** * INNER JOINs (without selection). * You also need to specify an alias of the joined data. * Optionally, you can add condition and parameters used in condition. */ SelectQueryBuilder.prototype.innerJoin = function (entityOrProperty, aliasName, condition, parameters) { if (condition === void 0) { condition = ""; } this.join("INNER", entityOrProperty, aliasName, condition, parameters); return this; }; /** * LEFT JOINs (without selection). * You also need to specify an alias of the joined data. * Optionally, you can add condition and parameters used in condition. */ SelectQueryBuilder.prototype.leftJoin = function (entityOrProperty, aliasName, condition, parameters) { if (condition === void 0) { condition = ""; } this.join("LEFT", entityOrProperty, aliasName, condition, parameters); return this; }; /** * INNER JOINs and adds all selection properties to SELECT. * You also need to specify an alias of the joined data. * Optionally, you can add condition and parameters used in condition. */ SelectQueryBuilder.prototype.innerJoinAndSelect = function (entityOrProperty, aliasName, condition, parameters) { if (condition === void 0) { condition = ""; } this.addSelect(aliasName); this.innerJoin(entityOrProperty, aliasName, condition, parameters); return this; }; /** * LEFT JOINs and adds all selection properties to SELECT. * You also need to specify an alias of the joined data. * Optionally, you can add condition and parameters used in condition. */ SelectQueryBuilder.prototype.leftJoinAndSelect = function (entityOrProperty, aliasName, condition, parameters) { if (condition === void 0) { condition = ""; } this.addSelect(aliasName); this.leftJoin(entityOrProperty, aliasName, condition, parameters); return this; }; /** * INNER JOINs, SELECTs the data returned by a join and MAPs all that data to some entity's property. * This is extremely useful when you want to select some data and map it to some virtual property. * It will assume that there are multiple rows of selecting data, and mapped result will be an array. * You also need to specify an alias of the joined data. * Optionally, you can add condition and parameters used in condition. */ SelectQueryBuilder.prototype.innerJoinAndMapMany = function (mapToProperty, entityOrProperty, aliasName, condition, parameters) { if (condition === void 0) { condition = ""; } this.addSelect(aliasName); this.join("INNER", entityOrProperty, aliasName, condition, parameters, mapToProperty, true); return this; }; /** * INNER JOINs, SELECTs the data returned by a join and MAPs all that data to some entity's property. * This is extremely useful when you want to select some data and map it to some virtual property. * It will assume that there is a single row of selecting data, and mapped result will be a single selected value. * You also need to specify an alias of the joined data. * Optionally, you can add condition and parameters used in condition. */ SelectQueryBuilder.prototype.innerJoinAndMapOne = function (mapToProperty, entityOrProperty, aliasName, condition, parameters) { if (condition === void 0) { condition = ""; } this.addSelect(aliasName); this.join("INNER", entityOrProperty, aliasName, condition, parameters, mapToProperty, false); return this; }; /** * LEFT JOINs, SELECTs the data returned by a join and MAPs all that data to some entity's property. * This is extremely useful when you want to select some data and map it to some virtual property. * It will assume that there are multiple rows of selecting data, and mapped result will be an array. * You also need to specify an alias of the joined data. * Optionally, you can add condition and parameters used in condition. */ SelectQueryBuilder.prototype.leftJoinAndMapMany = function (mapToProperty, entityOrProperty, aliasName, condition, parameters) { if (condition === void 0) { condition = ""; } this.addSelect(aliasName); this.join("LEFT", entityOrProperty, aliasName, condition, parameters, mapToProperty, true); return this; }; /** * LEFT JOINs, SELECTs the data returned by a join and MAPs all that data to some entity's property. * This is extremely useful when you want to select some data and map it to some virtual property. * It will assume that there is a single row of selecting data, and mapped result will be a single selected value. * You also need to specify an alias of the joined data. * Optionally, you can add condition and parameters used in condition. */ SelectQueryBuilder.prototype.leftJoinAndMapOne = function (mapToProperty, entityOrProperty, aliasName, condition, parameters) { if (condition === void 0) { condition = ""; } this.addSelect(aliasName); this.join("LEFT", entityOrProperty, aliasName, condition, parameters, mapToProperty, false); return this; }; /** * LEFT JOINs relation id and maps it into some entity's property. * Optionally, you can add condition and parameters used in condition. */ SelectQueryBuilder.prototype.loadRelationIdAndMap = function (mapToProperty, relationName, aliasNameOrOptions, queryBuilderFactory) { var relationIdAttribute = new RelationIdAttribute(this.expressionMap); relationIdAttribute.mapToProperty = mapToProperty; relationIdAttribute.relationName = relationName; if (typeof aliasNameOrOptions === "string") relationIdAttribute.alias = aliasNameOrOptions; if (aliasNameOrOptions instanceof Object && aliasNameOrOptions.disableMixedMap) relationIdAttribute.disableMixedMap = true; relationIdAttribute.queryBuilderFactory = queryBuilderFactory; this.expressionMap.relationIdAttributes.push(relationIdAttribute); if (relationIdAttribute.relation.junctionEntityMetadata) { this.expressionMap.createAlias({ type: "other", name: relationIdAttribute.junctionAlias, metadata: relationIdAttribute.relation.junctionEntityMetadata }); } return this; }; /** * Counts number of entities of entity's relation and maps the value into some entity's property. * Optionally, you can add condition and parameters used in condition. */ SelectQueryBuilder.prototype.loadRelationCountAndMap = function (mapToProperty, relationName, aliasName, queryBuilderFactory) { var relationCountAttribute = new RelationCountAttribute(this.expressionMap); relationCountAttribute.mapToProperty = mapToProperty; relationCountAttribute.relationName = relationName; relationCountAttribute.alias = aliasName; relationCountAttribute.queryBuilderFactory = queryBuilderFactory; this.expressionMap.relationCountAttributes.push(relationCountAttribute); this.expressionMap.createAlias({ type: "other", name: relationCountAttribute.junctionAlias }); if (relationCountAttribute.relation.junctionEntityMetadata) { this.expressionMap.createAlias({ type: "other", name: relationCountAttribute.junctionAlias, metadata: relationCountAttribute.relation.junctionEntityMetadata }); } return this; }; /** * Loads all relation ids for all relations of the selected entity. * All relation ids will be mapped to relation property themself. */ SelectQueryBuilder.prototype.loadAllRelationIds = function () { var _this = this; this.expressionMap.mainAlias.metadata.relations.forEach(function (relation) { _this.loadRelationIdAndMap(_this.expressionMap.mainAlias.name + "." + relation.propertyPath, _this.expressionMap.mainAlias.name + "." + relation.propertyPath, { disableMixedMap: true }); }); return this; }; /** * Sets WHERE condition in the query builder. * If you had previously WHERE expression defined, * calling this function will override previously set WHERE conditions. * Additionally you can add parameters used in where expression. */ SelectQueryBuilder.prototype.where = function (where, parameters) { this.expressionMap.wheres = []; // don't move this block below since computeWhereParameter can add where expressions var condition = this.computeWhereParameter(where); if (condition) this.expressionMap.wheres = [{ type: "simple", condition: condition }]; if (parameters) this.setParameters(parameters); return this; }; /** * Adds new AND WHERE condition in the query builder. * Additionally you can add parameters used in where expression. */ SelectQueryBuilder.prototype.andWhere = function (where, parameters) { this.expressionMap.wheres.push({ type: "and", condition: this.computeWhereParameter(where) }); if (parameters) this.setParameters(parameters); return this; }; /** * Adds new OR WHERE condition in the query builder. * Additionally you can add parameters used in where expression. */ SelectQueryBuilder.prototype.orWhere = function (where, parameters) { this.expressionMap.wheres.push({ type: "or", condition: this.computeWhereParameter(where) }); if (parameters) this.setParameters(parameters); return this; }; /** * Adds new AND WHERE with conditions for the given ids. * * Ids are mixed. * It means if you have single primary key you can pass a simple id values, for example [1, 2, 3]. * If you have multiple primary keys you need to pass object with property names and values specified, * for example [{ firstId: 1, secondId: 2 }, { firstId: 2, secondId: 3 }, ...] */ SelectQueryBuilder.prototype.whereInIds = function (ids) { ids = ids instanceof Array ? ids : [ids]; var _a = this.createWhereIdsExpression(ids), whereExpression = _a[0], parameters = _a[1]; this.where(whereExpression, parameters); return this; }; /** * Adds new AND WHERE with conditions for the given ids. * * Ids are mixed. * It means if you have single primary key you can pass a simple id values, for example [1, 2, 3]. * If you have multiple primary keys you need to pass object with property names and values specified, * for example [{ firstId: 1, secondId: 2 }, { firstId: 2, secondId: 3 }, ...] */ SelectQueryBuilder.prototype.andWhereInIds = function (ids) { var _a = this.createWhereIdsExpression(ids), whereExpression = _a[0], parameters = _a[1]; this.andWhere(whereExpression, parameters); return this; }; /** * Adds new OR WHERE with conditions for the given ids. * * Ids are mixed. * It means if you have single primary key you can pass a simple id values, for example [1, 2, 3]. * If you have multiple primary keys you need to pass object with property names and values specified, * for example [{ firstId: 1, secondId: 2 }, { firstId: 2, secondId: 3 }, ...] */ SelectQueryBuilder.prototype.orWhereInIds = function (ids) { var _a = this.createWhereIdsExpression(ids), whereExpression = _a[0], parameters = _a[1]; this.orWhere(whereExpression, parameters); return this; }; /** * Sets HAVING condition in the query builder. * If you had previously HAVING expression defined, * calling this function will override previously set HAVING conditions. * Additionally you can add parameters used in where expression. */ SelectQueryBuilder.prototype.having = function (having, parameters) { this.expressionMap.havings.push({ type: "simple", condition: having }); if (parameters) this.setParameters(parameters); return this; }; /** * Adds new AND HAVING condition in the query builder. * Additionally you can add parameters used in where expression. */ SelectQueryBuilder.prototype.andHaving = function (having, parameters) { this.expressionMap.havings.push({ type: "and", condition: having }); if (parameters) this.setParameters(parameters); return this; }; /** * Adds new OR HAVING condition in the query builder. * Additionally you can add parameters used in where expression. */ SelectQueryBuilder.prototype.orHaving = function (having, parameters) { this.expressionMap.havings.push({ type: "or", condition: having }); if (parameters) this.setParameters(parameters); return this; }; /** * Sets GROUP BY condition in the query builder. * If you had previously GROUP BY expression defined, * calling this function will override previously set GROUP BY conditions. */ SelectQueryBuilder.prototype.groupBy = function (groupBy) { if (groupBy) { this.expressionMap.groupBys = [groupBy]; } else { this.expressionMap.groupBys = []; } return this; }; /** * Adds GROUP BY condition in the query builder. */ SelectQueryBuilder.prototype.addGroupBy = function (groupBy) { this.expressionMap.groupBys.push(groupBy); return this; }; /** * Sets ORDER BY condition in the query builder. * If you had previously ORDER BY expression defined, * calling this function will override previously set ORDER BY conditions. */ SelectQueryBuilder.prototype.orderBy = function (sort, order, nulls) { if (order === void 0) { order = "ASC"; } if (sort) { if (sort instanceof Object) { this.expressionMap.orderBys = sort; } else { if (nulls) { this.expressionMap.orderBys = (_a = {}, _a[sort] = { order: order, nulls: nulls }, _a); } else { this.expressionMap.orderBys = (_b = {}, _b[sort] = order, _b); } } } else { this.expressionMap.orderBys = {}; } return this; var _a, _b; }; /** * Adds ORDER BY condition in the query builder. */ SelectQueryBuilder.prototype.addOrderBy = function (sort, order, nulls) { if (order === void 0) { order = "ASC"; } if (nulls) { this.expressionMap.orderBys[sort] = { order: order, nulls: nulls }; } else { this.expressionMap.orderBys[sort] = order; } return this; }; /** * Set's LIMIT - maximum number of rows to be selected. * NOTE that it may not work as you expect if you are using joins. * If you want to implement pagination, and you are having join in your query, * then use instead take method instead. */ SelectQueryBuilder.prototype.limit = function (limit) { this.expressionMap.limit = limit; return this; }; /** * Set's OFFSET - selection offset. * NOTE that it may not work as you expect if you are using joins. * If you want to implement pagination, and you are having join in your query, * then use instead skip method instead. */ SelectQueryBuilder.prototype.offset = function (offset) { this.expressionMap.offset = offset; return this; }; /** * Sets maximal number of entities to take. */ SelectQueryBuilder.prototype.take = function (take) { this.expressionMap.take = take; return this; }; /** * Sets number of entities to skip. */ SelectQueryBuilder.prototype.skip = function (skip) { this.expressionMap.skip = skip; return this; }; /** * Sets locking mode. */ SelectQueryBuilder.prototype.setLock = function (lockMode, lockVersion) { this.expressionMap.lockMode = lockMode; this.expressionMap.lockVersion = lockVersion; return this; }; /** * Gets first raw result returned by execution of generated query builder sql. */ SelectQueryBuilder.prototype.getRawOne = function () { return __awaiter(this, void 0, void 0, function () { return __generator(this, function (_a) { switch (_a.label) { case 0: return [4 /*yield*/, this.getRawMany()]; case 1: return [2 /*return*/, (_a.sent())[0]]; } }); }); }; /** * Gets all raw results returned by execution of generated query builder sql. */ SelectQueryBuilder.prototype.getRawMany = function () { return __awaiter(this, void 0, void 0, function () { var queryRunner; return __generator(this, function (_a) { switch (_a.label) { case 0: if (this.expressionMap.lockMode === "optimistic") throw new OptimisticLockCanNotBeUsedError(); this.expressionMap.queryEntity = false; queryRunner = this.obtainQueryRunner(); _a.label = 1; case 1: _a.trys.push([1, , 3, 6]); return [4 /*yield*/, this.loadRawResults(queryRunner)]; case 2: return [2 /*return*/, _a.sent()]; case 3: if (!(queryRunner !== this.queryRunner)) return [3 /*break*/, 5]; return [4 /*yield*/, queryRunner.release()]; case 4: _a.sent(); _a.label = 5; case 5: return [7 /*endfinally*/]; case 6: return [2 /*return*/]; } }); }); }; /** * Executes sql generated by query builder and returns object with raw results and entities created from them. */ SelectQueryBuilder.prototype.getRawAndEntities = function () { return __awaiter(this, void 0, void 0, function () { var queryRunner; return __generator(this, function (_a) { switch (_a.label) { case 0: queryRunner = this.obtainQueryRunner(); _a.label = 1; case 1: _a.trys.push([1, , 3, 6]); this.expressionMap.queryEntity = true; return [4 /*yield*/, this.executeEntitiesAndRawResults(queryRunner)]; case 2: return [2 /*return*/, _a.sent()]; case 3: if (!(queryRunner !== this.queryRunner)) return [3 /*break*/, 5]; return [4 /*yield*/, queryRunner.release()]; case 4: _a.sent(); _a.label = 5; case 5: return [7 /*endfinally*/]; case 6: return [2 /*return*/]; } }); }); }; /** * Gets single entity returned by execution of generated query builder sql. */ SelectQueryBuilder.prototype.getOne = function () { return __awaiter(this, void 0, void 0, function () { var results, result, metadata, actualVersion, actualVersion; return __generator(this, function (_a) { switch (_a.label) { case 0: return [4 /*yield*/, this.getRawAndEntities()]; case 1: results = _a.sent(); result = results.entities[0]; if (result && this.expressionMap.lockMode === "optimistic" && this.expressionMap.lockVersion) { metadata = this.expressionMap.mainAlias.metadata; if (this.expressionMap.lockVersion instanceof Date) { actualVersion = result[metadata.updateDateColumn.propertyName]; if (actualVersion.getTime() !== this.expressionMap.lockVersion.getTime()) throw new OptimisticLockVersionMismatchError(metadata.name, this.expressionMap.lockVersion, actualVersion); } else { actualVersion = result[metadata.versionColumn.propertyName]; if (actualVersion !== this.expressionMap.lockVersion) throw new OptimisticLockVersionMismatchError(metadata.name, this.expressionMap.lockVersion, actualVersion); } } return [2 /*return*/, result]; } }); }); }; /** * Gets entities returned by execution of generated query builder sql. */ SelectQueryBuilder.prototype.getMany = function () { return __awaiter(this, void 0, void 0, function () { var results; return __generator(this, function (_a) { switch (_a.label) { case 0: if (this.expressionMap.lockMode === "optimistic") throw new OptimisticLockCanNotBeUsedError(); return [4 /*yield*/, this.getRawAndEntities()]; case 1: results = _a.sent(); return [2 /*return*/, results.entities]; } }); }); }; /** * Gets count - number of entities selected by sql generated by this query builder. * Count excludes all limitations set by setFirstResult and setMaxResults methods call. */ SelectQueryBuilder.prototype.getCount = function () { return __awaiter(this, void 0, void 0, function () { var queryRunner; return __generator(this, function (_a) { switch (_a.label) { case 0: if (this.expressionMap.lockMode === "optimistic") throw new OptimisticLockCanNotBeUsedError(); queryRunner = this.obtainQueryRunner(); _a.label = 1; case 1: _a.trys.push([1, , 3, 6]); return [4 /*yield*/, this.executeCountQuery(queryRunner)]; case 2: return [2 /*return*/, _a.sent()]; case 3: if (!(queryRunner !== this.queryRunner)) return [3 /*break*/, 5]; return [4 /*yield*/, queryRunner.release()]; case 4: _a.sent(); _a.label = 5; case 5: return [7 /*endfinally*/]; case 6: return [2 /*return*/]; } }); }); }; /** * Executes built SQL query and returns entities and overall entities count (without limitation). * This method is useful to build pagination. */ SelectQueryBuilder.prototype.getManyAndCount = function () { return __awaiter(this, void 0, void 0, function () { var queryRunner, entitiesAndRaw, count; return __generator(this, function (_a) { switch (_a.label) { case 0: if (this.expressionMap.lockMode === "optimistic") throw new OptimisticLockCanNotBeUsedError(); queryRunner = this.obtainQueryRunner(); _a.label = 1; case 1: _a.trys.push([1, , 4, 7]); return [4 /*yield*/, this.executeEntitiesAndRawResults(queryRunner)]; case 2: entitiesAndRaw = _a.sent(); return [4 /*yield*/, this.executeCountQuery(queryRunner)]; case 3: count = _a.sent(); return [2 /*return*/, [entitiesAndRaw.entities, count]]; case 4: if (!(queryRunner !== this.queryRunner)) return [3 /*break*/, 6]; return [4 /*yield*/, queryRunner.release()]; case 5: _a.sent(); _a.label = 6; case 6: return [7 /*endfinally*/]; case 7: return [2 /*return*/]; } }); }); }; /** * Executes built SQL query and returns raw data stream. */ SelectQueryBuilder.prototype.stream = function () { return __awaiter(this, void 0, void 0, function () { var _this = this; var _a, sql, parameters, queryRunner, releaseFn; return __generator(this, function (_b) { switch (_b.label) { case 0: this.expressionMap.queryEntity = false; _a = this.getQueryAndParameters(), sql = _a[0], parameters = _a[1]; queryRunner = this.obtainQueryRunner(); _b.label = 1; case 1: _b.trys.push([1, , 2, 5]); releaseFn = function () { if (queryRunner !== _this.queryRunner) return queryRunner.release(); return; }; return [2 /*return*/, queryRunner.stream(sql, parameters, releaseFn, releaseFn)]; case 2: if (!(queryRunner !== this.queryRunner)) return [3 /*break*/, 4]; return [4 /*yield*/, queryRunner.release()]; case 3: _b.sent(); _b.label = 4; case 4: return [7 /*endfinally*/]; case 5: return [2 /*return*/]; } }); }); }; /** * Enables or disables query result caching. */ SelectQueryBuilder.prototype.cache = function (enabledOrMillisecondsOrId, maybeMilliseconds) { if (typeof enabledOrMillisecondsOrId === "boolean") { this.expressionMap.cache = enabledOrMillisecondsOrId; } else if (typeof enabledOrMillisecondsOrId === "number") { this.expressionMap.cache = true; this.expressionMap.cacheDuration = enabledOrMillisecondsOrId; } else if (typeof enabledOrMillisecondsOrId === "string" || typeof enabledOrMillisecondsOrId === "number") { this.expressionMap.cache = true; this.expressionMap.cacheId = enabledOrMillisecondsOrId; } if (maybeMilliseconds) { this.expressionMap.cacheDuration = maybeMilliseconds; } return this; }; // ------------------------------------------------------------------------- // Protected Methods // ------------------------------------------------------------------------- SelectQueryBuilder.prototype.join = function (direction, entityOrProperty, aliasName, condition, parameters, mapToProperty, isMappingMany) { this.setParameters(parameters || {}); var joinAttribute = new JoinAttribute(this.connection, this.expressionMap); joinAttribute.direction = direction; joinAttribute.mapToProperty = mapToProperty; joinAttribute.isMappingMany = isMappingMany; joinAttribute.entityOrProperty = entityOrProperty; // relationName joinAttribute.condition = condition; // joinInverseSideCondition // joinAttribute.junctionAlias = joinAttribute.relation.isOwning ? parentAlias + "_" + destinationTableAlias : destinationTableAlias + "_" + parentAlias; this.expressionMap.joinAttributes.push(joinAttribute); if (joinAttribute.metadata) { // todo: find and set metadata right there? joinAttribute.alias = this.expressionMap.createAlias({ type: "join", name: aliasName, metadata: joinAttribute.metadata }); if (joinAttribute.relation && joinAttribute.relation.junctionEntityMetadata) { this.expressionMap.createAlias({ type: "join", name: joinAttribute.junctionAlias, metadata: joinAttribute.relation.junctionEntityMetadata }); } } else { var subQuery = ""; if (entityOrProperty instanceof Function) { var subQueryBuilder = entityOrProperty(this.subQuery()); this.setParameters(subQueryBuilder.getParameters()); subQuery = subQueryBuilder.getQuery(); } else { subQuery = entityOrProperty; } var isSubQuery = entityOrProperty instanceof Function || entityOrProperty.substr(0, 1) === "(" && entityOrProperty.substr(-1) === ")"; joinAttribute.alias = this.expressionMap.createAlias({ type: "join", name: aliasName, tablePath: isSubQuery === false ? entityOrProperty : undefined, subQuery: isSubQuery === true ? subQuery : undefined, }); } }; /** * Creates "SELECT FROM" part of SQL query. */ SelectQueryBuilder.prototype.createSelectExpression = function () { var _this = this; if (!this.expressionMap.mainAlias) throw new Error("Cannot build query because main alias is not set (call qb#from method)"); // todo throw exception if selects or from is missing var allSelects = []; var excludedSelects = []; if (this.expressionMap.mainAlias.hasMetadata) { var metadata = this.expressionMap.mainAlias.metadata; allSelects.push.apply(allSelects, this.buildEscapedEntityColumnSelects(this.expressionMap.mainAlias.name, metadata)); excludedSelects.push.apply(excludedSelects, this.findEntityColumnSelects(this.expressionMap.mainAlias.name, metadata)); } // add selects from joins this.expressionMap.joinAttributes .forEach(function (join) { if (join.metadata) { allSelects.push.apply(allSelects, _this.buildEscapedEntityColumnSelects(join.alias.name, join.metadata)); excludedSelects.push.apply(excludedSelects, _this.findEntityColumnSelects(join.alias.name, join.metadata)); } else { var hasMainAlias = _this.expressionMap.selects.some(function (select) { return select.selection === join.alias.name; }); if (hasMainAlias) { allSelects.push({ selection: _this.escape(join.alias.name) + ".*" }); excludedSelects.push({ selection: _this.escape(join.alias.name) }); } } }); if (!this.expressionMap.ignoreParentTablesJoins && this.expressionMap.mainAlias.hasMetadata) { var metadata = this.expressionMap.mainAlias.metadata; if (metadata.parentEntityMetadata && metadata.parentEntityMetadata.inheritanceType === "class-table" && metadata.parentIdColumns) { var alias_1 = "parentIdColumn_" + metadata.parentEntityMetadata.tableName; metadata.parentEntityMetadata.columns.forEach(function (column) { // TODO implement partial select allSelects.push({ selection: _this.escape(alias_1) + "." + _this.escape(column.databaseName), aliasName: alias_1 + "_" + column.databaseName }); }); } } // add selects from relation id joins // this.relationIdAttributes.forEach(relationIdAttr => { // }); /*if (this.enableRelationIdValues) { const parentMetadata = this.aliasMap.getEntityMetadataByAlias(this.aliasMap.mainAlias); if (!parentMetadata) throw new Error("Cannot get entity metadata for the given alias " + this.aliasMap.mainAlias.name); const metadata = this.connection.entityMetadatas.findByTarget(this.aliasMap.mainAlias.target); metadata.manyToManyRelations.forEach(relation => { const junctionMetadata = relation.junctionEntityMetadata; junctionMetadata.columns.forEach(column => { const select = ea(this.aliasMap.mainAlias.name + "_" + junctionMetadata.table.name + "_ids") + "." + ec(column.name) + " AS " + ea(this.aliasMap.mainAlias.name + "_" + relation.name + "_ids_" + column.name); allSelects.push(select); }); }); }*/ // add all other selects this.expressionMap.selects .filter(function (select) { return excludedSelects.indexOf(select) === -1; }) .forEach(function (select) { return allSelects.push({ selection: _this.replacePropertyNames(select.selection), aliasName: select.aliasName }); }); // if still selection is empty, then simply set it to all (*) if (allSelects.length === 0) allSelects.push({ selection: "*" }); var lock = ""; if (this.connection.driver instanceof SqlServerDriver) { switch (this.expressionMap.lockMode) { case "pessimistic_read": lock = " WITH (HOLDLOCK, ROWLOCK)"; break; case "pessimistic_write": lock = " WITH (UPDLOCK, ROWLOCK)"; break; } } // create a selection query var froms = this.expressionMap.aliases .filter(function (alias) { return alias.type === "from" && (alias.tablePath || alias.subQuery); }) .map(function (alias) { if (alias.subQuery) return alias.subQuery + " " + _this.escape(alias.name); return _this.getTableName(alias.tablePath) + " " + _this.escape(alias.name); }); var selection = allSelects.map(function (select) { return select.selection + (select.aliasName ? " AS " + _this.escape(select.aliasName) : ""); }).join(", "); if ((this.expressionMap.limit || this.expressionMap.offset) && this.connection.driver instanceof OracleDriver) return "SELECT ROWNUM " + this.escape("RN") + "," + selection + " FROM " + froms.join(", ") + lock; return "SELECT " + selection + " FROM " + froms.join(", ") + lock; }; /** * Creates "JOIN" part of SQL query. */ SelectQueryBuilder.prototype.createJoinExpression = function () { // examples: // select from owning side // qb.select("post") // .leftJoinAndSelect("post.category", "category"); // select from non-owning side // qb.select("category") // .leftJoinAndSelect("category.post", "post"); var _this = this; var joins = this.expressionMap.joinAttributes.map(function (joinAttr) { var relation = joinAttr.relation; var destinationTableName = joinAttr.tablePath; var destinationTableAlias = joinAttr.alias.name; var appendedCondition = joinAttr.condition ? " AND (" + joinAttr.condition + ")" : ""; var parentAlias = joinAttr.parentAlias; // if join was build without relation (e.g. without "post.category") then it means that we have direct // table to join, without junction table involved. This means we simply join direct table. if (!parentAlias || !relation) { var destinationJoin = joinAttr.alias.subQuery ? joinAttr.alias.subQuery : _this.getTableName(destinationTableName); return " " + joinAttr.direction + " JOIN " + destinationJoin + " " + _this.escape(destinationTableAlias) + (joinAttr.condition ? " ON " + _this.replacePropertyNames(joinAttr.condition) : ""); } // if real entity relation is involved if (relation.isManyToOne || relation.isOneToOneOwner) { // JOIN `category` `category` ON `category`.`id` = `post`.`categoryId` var condition = relation.joinColumns.map(function (joinColumn) { return destinationTableAlias + "." + joinColumn.referencedColumn.propertyPath + "=" + parentAlias + "." + relation.propertyPath + "." + joinColumn.referencedColumn.propertyPath; }).join(" AND "); return " " + joinAttr.direction + " JOIN " + _this.getTableName(destinationTableName) + " " + _this.escape(destinationTableAlias) + " ON " + _this.replacePropertyNames(condition + appendedCondition); } else if (relation.isOneToMany || relation.isOneToOneNotOwner) { // JOIN `post` `post` ON `post`.`categoryId` = `category`.`id` var condition = relation.inverseRelation.joinColumns.map(function (joinColumn) { return destinationTableAlias + "." + relation.inverseRelation.propertyPath + "." + joinColumn.referencedColumn.propertyPath + "=" + parentAlias + "." + joinColumn.referencedColumn.propertyPath; }).join(" AND "); return " " + joinAttr.direction + " JOIN " + _this.getTableName(destinationTableName) + " " + _this.escape(destinationTableAlias) + " ON " + _this.replacePropertyNames(condition + appendedCondition); } else { var junctionTableName = relation.junctionEntityMetadata.tablePath; var junctionAlias_1 = joinAttr.junctionAlias; var junctionCondition = "", destinationCondition = ""; if (relation.isOwning) { junctionCondition = relation.joinColumns.map(function (joinColumn) { // `post_category`.`postId` = `post`.`id` return junctionAlias_1 + "." + joinColumn.propertyPath + "=" + parentAlias + "." + joinColumn.referencedColumn.propertyPath; }).join(" AND "); destinationCondition = relation.inverseJoinColumns.map(function (joinColumn) { // `category`.`id` = `post_category`.`categoryId` return destinationTableAlias + "." + joinColumn.referencedColumn.propertyPath + "=" + junctionAlias_1 + "." + joinColumn.propertyPath; }).join(" AND "); } else { junctionCondition = relation.inverseRelation.inverseJoinColumns.map(function (joinColumn) { // `post_category`.`categoryId` = `category`.`id` return junctionAlias_1 + "." + joinColumn.propertyPath + "=" + parentAlias + "." + joinColumn.referencedColumn.propertyPath; }).join(" AND "); destinationCondition = relation.inverseRelation.joinColumns.map(function (joinColumn) { // `post`.`id` = `post_category`.`postId` return destinationTableAlias + "." + joinColumn.referencedColumn.propertyPath + "=" + junctionAlias_1 + "." + joinColumn.propertyPath; }).join(" AND "); } return " " + joinAttr.direction + " JOIN " + _this.getTableName(junctionTableName) + " " + _this.escape(junctionAlias_1) + " ON " + _this.replacePropertyNames(junctionCondition) + " " + joinAttr.direction + " JOIN " + _this.getTableName(destinationTableName) + " " + _this.escape(destinationTableAlias) + " ON " + _this.replacePropertyNames(destinationCondition + appendedCondition); } }); if (!this.expressionMap.ignoreParentTablesJoins && this.expressionMap.mainAlias.hasMetadata) { var metadata = this.expressionMap.mainAlias.metadata; if (metadata.parentEntityMetadata && metadata.parentEntityMetadata.inheritanceType === "class-table" && metadata.parentIdColumns) { var alias_2 = "parentIdColumn_" + metadata.parentEntityMetadata.tableName; var condition = metadata.parentIdColumns.map(function (parentIdColumn) { return _this.expressionMap.mainAlias.name + "." + parentIdColumn.propertyPath + " = " + _this.escape(alias_2) +