typeorm
Version:
Data-Mapper ORM for TypeScript and ES2021+. Supports MySQL/MariaDB, PostgreSQL, MS SQL Server, Oracle, SAP HANA, SQLite, MongoDB databases.
172 lines (168 loc) • 7.36 kB
JavaScript
import { QueryBuilderUtils } from "./QueryBuilderUtils";
import { ObjectUtils } from "../util/ObjectUtils";
import { TypeORMError } from "../error";
import { DriverUtils } from "../driver/DriverUtils";
/**
* Stores all join attributes which will be used to build a JOIN query.
*/
export class JoinAttribute {
// -------------------------------------------------------------------------
// Constructor
// -------------------------------------------------------------------------
constructor(connection, queryExpressionMap, joinAttribute) {
this.connection = connection;
this.queryExpressionMap = queryExpressionMap;
this.isSelectedEvaluated = false;
this.relationEvaluated = false;
if (joinAttribute) {
ObjectUtils.assign(this, joinAttribute);
}
}
// -------------------------------------------------------------------------
// Public Methods
// -------------------------------------------------------------------------
get isMany() {
if (this.isMappingMany !== undefined)
return this.isMappingMany;
if (this.relation)
return this.relation.isManyToMany || this.relation.isOneToMany;
return false;
}
/**
* Indicates if this join is selected.
*/
get isSelected() {
if (!this.isSelectedEvaluated) {
const getValue = () => {
for (const select of this.queryExpressionMap.selects) {
if (select.selection === this.alias.name)
return true;
if (this.metadata &&
!!this.metadata.columns.find((column) => select.selection ===
this.alias.name + "." + column.propertyPath))
return true;
}
return false;
};
this.isSelectedCache = getValue();
this.isSelectedEvaluated = true;
}
return this.isSelectedCache;
}
/**
* Name of the table which we should join.
*/
get tablePath() {
return this.metadata
? this.metadata.tablePath
: this.entityOrProperty;
}
/**
* Alias of the parent of this join.
* For example, if we join ("post.category", "categoryAlias") then "post" is a parent alias.
* This value is extracted from entityOrProperty value.
* This is available when join was made using "post.category" syntax.
*/
get parentAlias() {
if (!QueryBuilderUtils.isAliasProperty(this.entityOrProperty))
return undefined;
return this.entityOrProperty.substr(0, this.entityOrProperty.indexOf("."));
}
/**
* Relation property name of the parent.
* This is used to understand what is joined.
* For example, if we join ("post.category", "categoryAlias") then "category" is a relation property.
* This value is extracted from entityOrProperty value.
* This is available when join was made using "post.category" syntax.
*/
get relationPropertyPath() {
if (!QueryBuilderUtils.isAliasProperty(this.entityOrProperty))
return undefined;
return this.entityOrProperty.substr(this.entityOrProperty.indexOf(".") + 1);
}
/**
* Relation of the parent.
* This is used to understand what is joined.
* This is available when join was made using "post.category" syntax.
* Relation can be undefined if entityOrProperty is regular entity or custom table.
*/
get relation() {
if (!this.relationEvaluated) {
const getValue = () => {
if (!QueryBuilderUtils.isAliasProperty(this.entityOrProperty))
return undefined;
const relationOwnerSelection = this.queryExpressionMap.findAliasByName(this.parentAlias);
let relation = relationOwnerSelection.metadata.findRelationWithPropertyPath(this.relationPropertyPath);
if (relation) {
return relation;
}
if (relationOwnerSelection.metadata.parentEntityMetadata) {
relation =
relationOwnerSelection.metadata.parentEntityMetadata.findRelationWithPropertyPath(this.relationPropertyPath);
if (relation) {
return relation;
}
}
throw new TypeORMError(`Relation with property path ${this.relationPropertyPath} in entity was not found.`);
};
this.relationCache = getValue.bind(this)();
this.relationEvaluated = true;
}
return this.relationCache;
}
/**
* Metadata of the joined entity.
* If table without entity was joined, then it will return undefined.
*/
get metadata() {
// entityOrProperty is relation, e.g. "post.category"
if (this.relation)
return this.relation.inverseEntityMetadata;
// entityOrProperty is Entity class
if (this.connection.hasMetadata(this.entityOrProperty))
return this.connection.getMetadata(this.entityOrProperty);
// Overriden mapping entity provided for leftJoinAndMapOne with custom query builder
if (this.mapAsEntity && this.connection.hasMetadata(this.mapAsEntity)) {
return this.connection.getMetadata(this.mapAsEntity);
}
return undefined;
/*if (typeof this.entityOrProperty === "string") { // entityOrProperty is a custom table
// first try to find entity with such name, this is needed when entity does not have a target class,
// and its target is a string name (scenario when plain old javascript is used or entity schema is loaded from files)
const metadata = this.connection.entityMetadatas.find(metadata => metadata.name === this.entityOrProperty);
if (metadata)
return metadata;
// check if we have entity with such table name, and use its metadata if found
return this.connection.entityMetadatas.find(metadata => metadata.tableName === this.entityOrProperty);
}*/
}
/**
* Generates alias of junction table, whose ids we get.
*/
get junctionAlias() {
if (!this.relation) {
throw new TypeORMError(`Cannot get junction table for join without relation.`);
}
if (typeof this.entityOrProperty !== "string") {
throw new TypeORMError(`Junction property is not defined.`);
}
const aliasProperty = this.entityOrProperty.substr(0, this.entityOrProperty.indexOf("."));
if (this.relation.isOwning) {
return DriverUtils.buildAlias(this.connection.driver, undefined, aliasProperty, this.alias.name);
}
else {
return DriverUtils.buildAlias(this.connection.driver, undefined, this.alias.name, aliasProperty);
}
}
get mapToPropertyParentAlias() {
if (!this.mapToProperty)
return undefined;
return this.mapToProperty.split(".")[0];
}
get mapToPropertyPropertyName() {
if (!this.mapToProperty)
return undefined;
return this.mapToProperty.split(".")[1];
}
}
//# sourceMappingURL=JoinAttribute.js.map