(
qb: AnyQueryBuilder<T>,
meta: EntityMetadata<T>,
options: FieldsForJoinedLoadOptions<T>,
)
| 2488 | } |
| 2489 | |
| 2490 | protected getFieldsForJoinedLoad<T extends object>( |
| 2491 | qb: AnyQueryBuilder<T>, |
| 2492 | meta: EntityMetadata<T>, |
| 2493 | options: FieldsForJoinedLoadOptions<T>, |
| 2494 | ): InternalField<T>[] { |
| 2495 | const fields: InternalField<T>[] = []; |
| 2496 | const populate = options.populate ?? []; |
| 2497 | const joinedProps = this.joinedProps(meta, populate, options); |
| 2498 | const populateWhereAll = |
| 2499 | (options as Dictionary)?._populateWhere === 'all' || Utils.isEmpty((options as Dictionary)?._populateWhere); |
| 2500 | |
| 2501 | // Ensure TPT joins are applied early so that _tptAlias is available for join resolution |
| 2502 | // This is needed when populating relations that are inherited from TPT parent entities |
| 2503 | if (!options.parentJoinPath) { |
| 2504 | qb.ensureTPTJoins(); |
| 2505 | } |
| 2506 | |
| 2507 | // root entity is already handled, skip that |
| 2508 | if (options.parentJoinPath) { |
| 2509 | // alias all fields in the primary table |
| 2510 | meta.props |
| 2511 | .filter(prop => this.shouldHaveColumn(meta, prop, populate, options.explicitFields, options.exclude)) |
| 2512 | .forEach(prop => |
| 2513 | fields.push( |
| 2514 | ...this.mapPropToFieldNames( |
| 2515 | qb, |
| 2516 | prop, |
| 2517 | options.parentTableAlias, |
| 2518 | meta, |
| 2519 | options.schema, |
| 2520 | options.explicitFields, |
| 2521 | ), |
| 2522 | ), |
| 2523 | ); |
| 2524 | } |
| 2525 | |
| 2526 | for (const hint of joinedProps) { |
| 2527 | const [propName, ref] = hint.field.split(':', 2) as [EntityKey<T>, string | undefined]; |
| 2528 | const prop = meta.properties[propName]; |
| 2529 | |
| 2530 | // Polymorphic to-one: create a LEFT JOIN per target type |
| 2531 | // Skip regular :ref hints — polymorphic to-one already has FK + discriminator in the row |
| 2532 | // But allow filter :ref hints through to create per-target LEFT JOINs with filter checks |
| 2533 | if ( |
| 2534 | prop.polymorphic && |
| 2535 | prop.polymorphTargets?.length && |
| 2536 | (!ref || hint.filter) && |
| 2537 | [ReferenceKind.MANY_TO_ONE, ReferenceKind.ONE_TO_ONE].includes(prop.kind) |
| 2538 | ) { |
| 2539 | const basePath = options.parentJoinPath |
| 2540 | ? `${options.parentJoinPath}.${prop.name}` |
| 2541 | : `${meta.name}.${prop.name}`; |
| 2542 | const pathPrefix = |
| 2543 | !options.parentJoinPath && populateWhereAll && !basePath.startsWith('[populate]') ? '[populate]' : ''; |
| 2544 | |
| 2545 | for (const targetMeta of prop.polymorphTargets) { |
| 2546 | const tableAlias = qb.getNextAlias(targetMeta.className); |
| 2547 | const targetPath = `${pathPrefix}${basePath}[${targetMeta.className}]`; |
nothing calls this directly
no test coverage detected