333
schangxiang@126.com
2025-09-19 18966e02fb573c7e2bb0c6426ed792b38b910940
1
{"version":3,"sources":["../../src/query-builder/relation-count/RelationCountLoader.ts"],"names":[],"mappings":"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","file":"RelationCountLoader.js","sourcesContent":["import {ColumnMetadata} from \"../../metadata/ColumnMetadata\";\nimport {Connection} from \"../../connection/Connection\";\nimport {RelationCountAttribute} from \"./RelationCountAttribute\";\nimport {RelationCountLoadResult} from \"./RelationCountLoadResult\";\nimport {QueryRunner} from \"../../query-runner/QueryRunner\";\n\nexport class RelationCountLoader {\n\n    // -------------------------------------------------------------------------\n    // Constructor\n    // -------------------------------------------------------------------------\n\n    constructor(protected connection: Connection,\n                protected queryRunner: QueryRunner|undefined,\n                protected relationCountAttributes: RelationCountAttribute[]) {\n    }\n\n    // -------------------------------------------------------------------------\n    // Public Methods\n    // -------------------------------------------------------------------------\n\n    async load(rawEntities: any[]): Promise<RelationCountLoadResult[]> {\n\n        const onlyUnique = (value: any, index: number, self: any) => {\n            return self.indexOf(value) === index;\n        };\n\n        const promises = this.relationCountAttributes.map(async relationCountAttr => {\n\n            if (relationCountAttr.relation.isOneToMany) {\n                // example: Post and Category\n                // loadRelationCountAndMap(\"post.categoryCount\", \"post.categories\")\n                // we expect it to load array of post ids\n\n                // todo(dima): fix issues wit multiple primary keys and remove joinColumns[0]\n                const relation = relationCountAttr.relation; // \"category.posts\"\n                const inverseRelation = relation.inverseRelation!; // \"post.category\"\n                const referenceColumnName = inverseRelation.joinColumns[0].referencedColumn!.propertyName; // post id\n                const inverseSideTable = relation.inverseEntityMetadata.target; // Post\n                const inverseSideTableName = relation.inverseEntityMetadata.tableName; // post\n                const inverseSideTableAlias = relationCountAttr.alias || inverseSideTableName; // if condition (custom query builder factory) is set then relationIdAttr.alias defined\n                const inverseSidePropertyName = inverseRelation.propertyName; // \"category\" from \"post.category\"\n\n                let referenceColumnValues = rawEntities\n                    .map(rawEntity => rawEntity[relationCountAttr.parentAlias + \"_\" + referenceColumnName])\n                    .filter(value => !!value);\n                referenceColumnValues = referenceColumnValues.filter(onlyUnique);\n\n                // ensure we won't perform redundant queries for joined data which was not found in selection\n                // example: if post.category was not found in db then no need to execute query for category.imageIds\n                if (referenceColumnValues.length === 0)\n                    return { relationCountAttribute: relationCountAttr, results: [] };\n\n                // generate query:\n                // SELECT category.post as parentId, COUNT(*) AS cnt FROM category category WHERE category.post IN (1, 2) GROUP BY category.post\n                const qb = this.connection.createQueryBuilder(this.queryRunner);\n                qb.select(inverseSideTableAlias + \".\" + inverseSidePropertyName, \"parentId\")\n                    .addSelect(\"COUNT(*)\", \"cnt\")\n                    .from(inverseSideTable, inverseSideTableAlias)\n                    .where(inverseSideTableAlias + \".\" + inverseSidePropertyName + \" IN (:...ids)\")\n                    .addGroupBy(inverseSideTableAlias + \".\" + inverseSidePropertyName)\n                    .setParameter(\"ids\", referenceColumnValues);\n\n                // apply condition (custom query builder factory)\n                if (relationCountAttr.queryBuilderFactory)\n                    relationCountAttr.queryBuilderFactory(qb);\n\n                return {\n                    relationCountAttribute: relationCountAttr,\n                    results: await qb.getRawMany()\n                };\n\n            } else {\n                // example: Post and Category\n                // owner side: loadRelationIdAndMap(\"post.categoryIds\", \"post.categories\")\n                // inverse side: loadRelationIdAndMap(\"category.postIds\", \"category.posts\")\n                // we expect it to load array of post ids\n\n                let joinTableColumnName: string;\n                let inverseJoinColumnName: string;\n                let firstJunctionColumn: ColumnMetadata;\n                let secondJunctionColumn: ColumnMetadata;\n\n                if (relationCountAttr.relation.isOwning) { // todo fix joinColumns[0] and inverseJoinColumns[0].\n                    joinTableColumnName = relationCountAttr.relation.joinColumns[0].referencedColumn!.databaseName;\n                    inverseJoinColumnName = relationCountAttr.relation.inverseJoinColumns[0].referencedColumn!.databaseName;\n                    firstJunctionColumn = relationCountAttr.relation.junctionEntityMetadata!.columns[0];\n                    secondJunctionColumn = relationCountAttr.relation.junctionEntityMetadata!.columns[1];\n\n                } else {\n                    joinTableColumnName = relationCountAttr.relation.inverseRelation!.inverseJoinColumns[0].referencedColumn!.databaseName;\n                    inverseJoinColumnName = relationCountAttr.relation.inverseRelation!.joinColumns[0].referencedColumn!.databaseName;\n                    firstJunctionColumn = relationCountAttr.relation.junctionEntityMetadata!.columns[1];\n                    secondJunctionColumn = relationCountAttr.relation.junctionEntityMetadata!.columns[0];\n                }\n\n                let referenceColumnValues = rawEntities\n                    .map(rawEntity => rawEntity[relationCountAttr.parentAlias + \"_\" + joinTableColumnName])\n                    .filter(value => !!value);\n                referenceColumnValues = referenceColumnValues.filter(onlyUnique);\n\n                // ensure we won't perform redundant queries for joined data which was not found in selection\n                // example: if post.category was not found in db then no need to execute query for category.imageIds\n                if (referenceColumnValues.length === 0)\n                    return { relationCountAttribute: relationCountAttr, results: [] };\n\n                const junctionAlias = relationCountAttr.junctionAlias;\n                const inverseSideTableName = relationCountAttr.joinInverseSideMetadata.tableName;\n                const inverseSideTableAlias = relationCountAttr.alias || inverseSideTableName;\n                const junctionTableName = relationCountAttr.relation.junctionEntityMetadata!.tableName;\n                const condition = junctionAlias + \".\" + firstJunctionColumn.propertyName + \" IN (\" + referenceColumnValues + \")\" +\n                    \" AND \" + junctionAlias + \".\" + secondJunctionColumn.propertyName + \" = \" + inverseSideTableAlias + \".\" + inverseJoinColumnName;\n\n                const qb = this.connection.createQueryBuilder(this.queryRunner);\n                qb.select(junctionAlias + \".\" + firstJunctionColumn.propertyName, \"parentId\")\n                    .addSelect(\"COUNT(\" + qb.escape(inverseSideTableAlias) + \".\" + qb.escape(inverseJoinColumnName) + \")\", \"cnt\")\n                    .from(inverseSideTableName, inverseSideTableAlias)\n                    .innerJoin(junctionTableName, junctionAlias, condition)\n                    .addGroupBy(junctionAlias + \".\" + firstJunctionColumn.propertyName);\n\n                // apply condition (custom query builder factory)\n                if (relationCountAttr.queryBuilderFactory)\n                    relationCountAttr.queryBuilderFactory(qb);\n\n                return {\n                    relationCountAttribute: relationCountAttr,\n                    results: await qb.getRawMany()\n                };\n            }\n        });\n\n        return Promise.all(promises);\n    }\n\n}\n"],"sourceRoot":"../.."}