import { EntityMetadata } from "../../metadata/EntityMetadata" import { QueryBuilderUtils } from "../QueryBuilderUtils" import { RelationMetadata } from "../../metadata/RelationMetadata" import { QueryExpressionMap } from "../QueryExpressionMap" import { SelectQueryBuilder } from "../SelectQueryBuilder" import { ObjectUtils } from "../../util/ObjectUtils" import { TypeORMError } from "../../error/TypeORMError" export class RelationCountAttribute { /** * Alias of the joined (destination) table. */ alias?: string /** * Name of relation. */ relationName: string /** * Property + alias of the object where to joined data should be mapped. */ mapToProperty: string /** * Extra condition applied to "ON" section of join. */ queryBuilderFactory?: ( qb: SelectQueryBuilder, ) => SelectQueryBuilder // ------------------------------------------------------------------------- // Constructor // ------------------------------------------------------------------------- constructor( private expressionMap: QueryExpressionMap, relationCountAttribute?: Partial, ) { ObjectUtils.assign(this, relationCountAttribute || {}) } // ------------------------------------------------------------------------- // Public Methods // ------------------------------------------------------------------------- get joinInverseSideMetadata(): EntityMetadata { return this.relation.inverseEntityMetadata } /** * 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(): string { if (!QueryBuilderUtils.isAliasProperty(this.relationName)) throw new TypeORMError( `Given value must be a string representation of alias property`, ) return this.relationName.split(".")[0] } /** * 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 relationProperty(): string | undefined { if (!QueryBuilderUtils.isAliasProperty(this.relationName)) throw new TypeORMError( `Given value is a string representation of alias property`, ) return this.relationName.split(".")[1] } get junctionAlias(): string { const [parentAlias, relationProperty] = this.relationName.split(".") return parentAlias + "_" + relationProperty + "_rc" } /** * Relation of the parent. * This is used to understand what is joined. * This is available when join was made using "post.category" syntax. */ get relation(): RelationMetadata { if (!QueryBuilderUtils.isAliasProperty(this.relationName)) throw new TypeORMError( `Given value is a string representation of alias property`, ) const [parentAlias, propertyPath] = this.relationName.split(".") const relationOwnerSelection = this.expressionMap.findAliasByName(parentAlias) const relation = relationOwnerSelection.metadata.findRelationWithPropertyPath( propertyPath, ) if (!relation) throw new TypeORMError( `Relation with property path ${propertyPath} in entity was not found.`, ) return relation } /** * Metadata of the joined entity. * If table without entity was joined, then it will return undefined. */ get metadata(): EntityMetadata { if (!QueryBuilderUtils.isAliasProperty(this.relationName)) throw new TypeORMError( `Given value is a string representation of alias property`, ) const parentAlias = this.relationName.split(".")[0] const selection = this.expressionMap.findAliasByName(parentAlias) return selection.metadata } get mapToPropertyPropertyName(): string { return this.mapToProperty!.split(".")[1] } }