• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

typeorm / typeorm / 14796576772

02 May 2025 01:52PM UTC coverage: 45.367% (-30.9%) from 76.309%
14796576772

Pull #11434

github

web-flow
Merge ec4ce2d00 into fadad1a74
Pull Request #11434: feat: release PR releases using pkg.pr.new

5216 of 12761 branches covered (40.87%)

Branch coverage included in aggregate %.

11439 of 23951 relevant lines covered (47.76%)

15712.55 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

90.61
/src/metadata-builder/EntityMetadataBuilder.ts
1
import { EntityMetadata } from "../metadata/EntityMetadata"
4✔
2
import { ColumnMetadata } from "../metadata/ColumnMetadata"
4✔
3
import { IndexMetadata } from "../metadata/IndexMetadata"
4✔
4
import { RelationMetadata } from "../metadata/RelationMetadata"
4✔
5
import { EmbeddedMetadata } from "../metadata/EmbeddedMetadata"
4✔
6
import { MetadataArgsStorage } from "../metadata-args/MetadataArgsStorage"
7
import { EmbeddedMetadataArgs } from "../metadata-args/EmbeddedMetadataArgs"
8
import { RelationIdMetadata } from "../metadata/RelationIdMetadata"
4✔
9
import { RelationCountMetadata } from "../metadata/RelationCountMetadata"
4✔
10
import { EventListenerTypes } from "../metadata/types/EventListenerTypes"
4✔
11
import { MetadataUtils } from "./MetadataUtils"
4✔
12
import { TableMetadataArgs } from "../metadata-args/TableMetadataArgs"
13
import { JunctionEntityMetadataBuilder } from "./JunctionEntityMetadataBuilder"
4✔
14
import { ClosureJunctionEntityMetadataBuilder } from "./ClosureJunctionEntityMetadataBuilder"
4✔
15
import { RelationJoinColumnBuilder } from "./RelationJoinColumnBuilder"
4✔
16
import { DataSource } from "../data-source/DataSource"
17
import { EntityListenerMetadata } from "../metadata/EntityListenerMetadata"
4✔
18
import { UniqueMetadata } from "../metadata/UniqueMetadata"
4✔
19
import { CheckMetadata } from "../metadata/CheckMetadata"
4✔
20
import { ExclusionMetadata } from "../metadata/ExclusionMetadata"
4✔
21
import { TypeORMError } from "../error"
4✔
22
import { DriverUtils } from "../driver/DriverUtils"
4✔
23
import { ForeignKeyMetadata } from "../metadata/ForeignKeyMetadata"
4✔
24
import { InstanceChecker } from "../util/InstanceChecker"
4✔
25

26
/**
27
 * Builds EntityMetadata objects and all its sub-metadatas.
28
 */
29
export class EntityMetadataBuilder {
4✔
30
    // -------------------------------------------------------------------------
31
    // Protected Properties
32
    // -------------------------------------------------------------------------
33

34
    /**
35
     * Used to build entity metadatas of the junction entities.
36
     */
37
    protected junctionEntityMetadataBuilder: JunctionEntityMetadataBuilder
38

39
    /**
40
     * Used to build entity metadatas of the closure junction entities.
41
     */
42
    protected closureJunctionEntityMetadataBuilder: ClosureJunctionEntityMetadataBuilder
43

44
    /**
45
     * Used to build join columns of the relations.
46
     */
47
    protected relationJoinColumnBuilder: RelationJoinColumnBuilder
48

49
    // -------------------------------------------------------------------------
50
    // Constructor
51
    // -------------------------------------------------------------------------
52

53
    constructor(
54
        private connection: DataSource,
3,704✔
55
        private metadataArgsStorage: MetadataArgsStorage,
3,704✔
56
    ) {
57
        this.junctionEntityMetadataBuilder = new JunctionEntityMetadataBuilder(
3,704✔
58
            connection,
59
        )
60
        this.closureJunctionEntityMetadataBuilder =
3,704✔
61
            new ClosureJunctionEntityMetadataBuilder(connection)
62
        this.relationJoinColumnBuilder = new RelationJoinColumnBuilder(
3,704✔
63
            connection,
64
        )
65
    }
66

67
    // -------------------------------------------------------------------------
68
    // Public Methods
69
    // -------------------------------------------------------------------------
70

71
    /**
72
     * Builds a complete entity metadatas for the given entity classes.
73
     */
74
    build(entityClasses?: Function[]): EntityMetadata[] {
75
        // if entity classes to filter entities by are given then do filtering, otherwise use all
76
        const allTables = entityClasses
3,704✔
77
            ? this.metadataArgsStorage.filterTables(entityClasses)
78
            : this.metadataArgsStorage.tables
79

80
        // filter out table metadata args for those we really create entity metadatas and tables in the db
81
        const realTables = allTables.filter(
3,704✔
82
            (table) =>
83
                table.type === "regular" ||
4,270✔
84
                table.type === "closure" ||
85
                table.type === "entity-child" ||
86
                table.type === "view",
87
        )
88

89
        // create entity metadatas for a user defined entities (marked with @Entity decorator or loaded from entity schemas)
90
        const entityMetadatas = realTables.map((tableArgs) =>
3,704✔
91
            this.createEntityMetadata(tableArgs),
4,270✔
92
        )
93

94
        // compute parent entity metadatas for table inheritance
95
        entityMetadatas.forEach((entityMetadata) =>
3,704✔
96
            this.computeParentEntityMetadata(entityMetadatas, entityMetadata),
4,270✔
97
        )
98

99
        // after all metadatas created we set child entity metadatas for table inheritance
100
        entityMetadatas.forEach((metadata) => {
3,704✔
101
            metadata.childEntityMetadatas = entityMetadatas.filter(
4,270✔
102
                (childMetadata) => {
103
                    return (
16,432✔
104
                        typeof metadata.target === "function" &&
48,930✔
105
                        typeof childMetadata.target === "function" &&
106
                        MetadataUtils.isInherited(
107
                            childMetadata.target,
108
                            metadata.target,
109
                        )
110
                    )
111
                },
112
            )
113
        })
114

115
        // build entity metadata (step0), first for non-single-table-inherited entity metadatas (dependant)
116
        entityMetadatas
3,704✔
117
            .filter(
118
                (entityMetadata) => entityMetadata.tableType !== "entity-child",
4,270✔
119
            )
120
            .forEach((entityMetadata) => entityMetadata.build())
4,078✔
121

122
        // build entity metadata (step0), now for single-table-inherited entity metadatas (dependant)
123
        entityMetadatas
3,704✔
124
            .filter(
125
                (entityMetadata) => entityMetadata.tableType === "entity-child",
4,270✔
126
            )
127
            .forEach((entityMetadata) => entityMetadata.build())
192✔
128

129
        // compute entity metadata columns, relations, etc. first for the regular, non-single-table-inherited entity metadatas
130
        entityMetadatas
3,704✔
131
            .filter(
132
                (entityMetadata) => entityMetadata.tableType !== "entity-child",
4,270✔
133
            )
134
            .forEach((entityMetadata) =>
135
                this.computeEntityMetadataStep1(
4,078✔
136
                    entityMetadatas,
137
                    entityMetadata,
138
                ),
139
            )
140

141
        // then do it for single table inheritance children (since they are depend on their parents to be built)
142
        entityMetadatas
3,704✔
143
            .filter(
144
                (entityMetadata) => entityMetadata.tableType === "entity-child",
4,270✔
145
            )
146
            .forEach((entityMetadata) =>
147
                this.computeEntityMetadataStep1(
192✔
148
                    entityMetadatas,
149
                    entityMetadata,
150
                ),
151
            )
152

153
        // calculate entity metadata computed properties and all its sub-metadatas
154
        entityMetadatas.forEach((entityMetadata) =>
3,704✔
155
            this.computeEntityMetadataStep2(entityMetadata),
4,270✔
156
        )
157

158
        // calculate entity metadata's inverse properties
159
        entityMetadatas.forEach((entityMetadata) =>
3,704✔
160
            this.computeInverseProperties(entityMetadata, entityMetadatas),
4,270✔
161
        )
162

163
        // go through all entity metadatas and create foreign keys / junction entity metadatas for their relations
164
        entityMetadatas
3,704✔
165
            .filter(
166
                (entityMetadata) => entityMetadata.tableType !== "entity-child",
4,270✔
167
            )
168
            .forEach((entityMetadata) => {
169
                // create entity's relations join columns (for many-to-one and one-to-one owner)
170
                entityMetadata.relations
4,078✔
171
                    .filter(
172
                        (relation) =>
173
                            relation.isOneToOne || relation.isManyToOne,
2,992✔
174
                    )
175
                    .forEach((relation) => {
176
                        const joinColumns =
177
                            this.metadataArgsStorage.filterJoinColumns(
1,601✔
178
                                relation.target,
179
                                relation.propertyName,
180
                            )
181
                        const { foreignKey, columns, uniqueConstraint } =
182
                            this.relationJoinColumnBuilder.build(
1,601✔
183
                                joinColumns,
184
                                relation,
185
                            ) // create a foreign key based on its metadata args
186
                        if (foreignKey) {
1,601✔
187
                            relation.registerForeignKeys(foreignKey) // push it to the relation and thus register there a join column
1,444✔
188
                            entityMetadata.foreignKeys.push(foreignKey)
1,444✔
189
                        }
190
                        if (columns) {
1,601✔
191
                            relation.registerJoinColumns(columns)
1,601✔
192
                        }
193
                        if (uniqueConstraint) {
1,601✔
194
                            if (
317✔
195
                                DriverUtils.isMySQLFamily(
1,473✔
196
                                    this.connection.driver,
197
                                ) ||
198
                                this.connection.driver.options.type ===
199
                                    "aurora-mysql" ||
200
                                this.connection.driver.options.type ===
201
                                    "mssql" ||
202
                                this.connection.driver.options.type === "sap" ||
203
                                this.connection.driver.options.type ===
204
                                    "spanner"
205
                            ) {
206
                                const index = new IndexMetadata({
28✔
207
                                    entityMetadata:
208
                                        uniqueConstraint.entityMetadata,
209
                                    columns: uniqueConstraint.columns,
210
                                    args: {
211
                                        target: uniqueConstraint.target!,
212
                                        name: uniqueConstraint.name,
213
                                        unique: true,
214
                                        synchronize: true,
215
                                    },
216
                                })
217

218
                                if (
28!
219
                                    this.connection.driver.options.type ===
220
                                    "mssql"
221
                                ) {
222
                                    index.where = index.columns
×
223
                                        .map((column) => {
224
                                            return `${this.connection.driver.escape(
×
225
                                                column.databaseName,
226
                                            )} IS NOT NULL`
227
                                        })
228
                                        .join(" AND ")
229
                                }
230

231
                                if (
28!
232
                                    this.connection.driver.options.type ===
233
                                    "spanner"
234
                                ) {
235
                                    index.isNullFiltered = true
×
236
                                }
237

238
                                if (relation.embeddedMetadata) {
28!
239
                                    relation.embeddedMetadata.indices.push(
×
240
                                        index,
241
                                    )
242
                                } else {
243
                                    relation.entityMetadata.ownIndices.push(
28✔
244
                                        index,
245
                                    )
246
                                }
247
                                this.computeEntityMetadataStep2(entityMetadata)
28✔
248
                            } else {
249
                                if (relation.embeddedMetadata) {
289✔
250
                                    relation.embeddedMetadata.uniques.push(
20✔
251
                                        uniqueConstraint,
252
                                    )
253
                                } else {
254
                                    relation.entityMetadata.ownUniques.push(
269✔
255
                                        uniqueConstraint,
256
                                    )
257
                                }
258
                                this.computeEntityMetadataStep2(entityMetadata)
289✔
259
                            }
260
                        }
261

262
                        if (
1,601!
263
                            foreignKey &&
3,045✔
264
                            this.connection.driver.options.type ===
265
                                "cockroachdb"
266
                        ) {
267
                            const index = new IndexMetadata({
×
268
                                entityMetadata: relation.entityMetadata,
269
                                columns: foreignKey.columns,
270
                                args: {
271
                                    target: relation.entityMetadata.target!,
272
                                    synchronize: true,
273
                                },
274
                            })
275
                            if (relation.embeddedMetadata) {
×
276
                                relation.embeddedMetadata.indices.push(index)
×
277
                            } else {
278
                                relation.entityMetadata.ownIndices.push(index)
×
279
                            }
280
                            this.computeEntityMetadataStep2(entityMetadata)
×
281
                        }
282
                    })
283

284
                // create junction entity metadatas for entity many-to-many relations
285
                entityMetadata.relations
4,078✔
286
                    .filter((relation) => relation.isManyToMany)
2,992✔
287
                    .forEach((relation) => {
288
                        const joinTable =
289
                            this.metadataArgsStorage.findJoinTable(
684✔
290
                                relation.target,
291
                                relation.propertyName,
292
                            )!
293
                        if (!joinTable) return // no join table set - no need to do anything (it means this is many-to-many inverse side)
684✔
294

295
                        // here we create a junction entity metadata for a new junction table of many-to-many relation
296
                        const junctionEntityMetadata =
297
                            this.junctionEntityMetadataBuilder.build(
439✔
298
                                relation,
299
                                joinTable,
300
                            )
301
                        relation.registerForeignKeys(
439✔
302
                            ...junctionEntityMetadata.foreignKeys,
303
                        )
304
                        relation.registerJoinColumns(
439✔
305
                            junctionEntityMetadata.ownIndices[0].columns,
306
                            junctionEntityMetadata.ownIndices[1].columns,
307
                        )
308
                        relation.registerJunctionEntityMetadata(
439✔
309
                            junctionEntityMetadata,
310
                        )
311

312
                        // compute new entity metadata properties and push it to entity metadatas pool
313
                        this.computeEntityMetadataStep2(junctionEntityMetadata)
439✔
314
                        this.computeInverseProperties(
439✔
315
                            junctionEntityMetadata,
316
                            entityMetadatas,
317
                        )
318
                        entityMetadatas.push(junctionEntityMetadata)
439✔
319
                    })
320
            })
321

322
        // update entity metadata depend properties
323
        entityMetadatas.forEach((entityMetadata) => {
3,704✔
324
            entityMetadata.relationsWithJoinColumns =
4,709✔
325
                entityMetadata.relations.filter(
326
                    (relation) => relation.isWithJoinColumn,
3,078✔
327
                )
328
            entityMetadata.hasNonNullableRelations =
4,709✔
329
                entityMetadata.relationsWithJoinColumns.some(
330
                    (relation) => !relation.isNullable || relation.isPrimary,
1,462✔
331
                )
332
        })
333

334
        // generate closure junction tables for all closure tables
335
        entityMetadatas
3,704✔
336
            .filter((metadata) => metadata.treeType === "closure-table")
4,709✔
337
            .forEach((entityMetadata) => {
338
                const closureJunctionEntityMetadata =
339
                    this.closureJunctionEntityMetadataBuilder.build(
67✔
340
                        entityMetadata,
341
                    )
342
                entityMetadata.closureJunctionTable =
67✔
343
                    closureJunctionEntityMetadata
344
                this.computeEntityMetadataStep2(closureJunctionEntityMetadata)
67✔
345
                this.computeInverseProperties(
67✔
346
                    closureJunctionEntityMetadata,
347
                    entityMetadatas,
348
                )
349
                entityMetadatas.push(closureJunctionEntityMetadata)
67✔
350
            })
351

352
        // generate keys for tables with single-table inheritance
353
        entityMetadatas
3,704✔
354
            .filter(
355
                (metadata) =>
356
                    metadata.inheritancePattern === "STI" &&
4,776✔
357
                    metadata.discriminatorColumn,
358
            )
359
            .forEach((entityMetadata) =>
360
                this.createKeysForTableInheritance(entityMetadata),
296✔
361
            )
362

363
        // build all indices (need to do it after relations and their join columns are built)
364
        entityMetadatas.forEach((entityMetadata) => {
3,704✔
365
            entityMetadata.indices.forEach((index) =>
4,776✔
366
                index.build(this.connection.namingStrategy),
1,753✔
367
            )
368
        })
369

370
        // build all unique constraints (need to do it after relations and their join columns are built)
371
        entityMetadatas.forEach((entityMetadata) => {
3,704✔
372
            entityMetadata.uniques.forEach((unique) =>
4,776✔
373
                unique.build(this.connection.namingStrategy),
799✔
374
            )
375
        })
376

377
        // build all check constraints
378
        entityMetadatas.forEach((entityMetadata) => {
3,704✔
379
            entityMetadata.checks.forEach((check) =>
4,776✔
380
                check.build(this.connection.namingStrategy),
109✔
381
            )
382
        })
383

384
        // build all exclusion constraints
385
        entityMetadatas.forEach((entityMetadata) => {
3,704✔
386
            entityMetadata.exclusions.forEach((exclusion) =>
4,776✔
387
                exclusion.build(this.connection.namingStrategy),
×
388
            )
389
        })
390

391
        // generate foreign keys for tables
392
        entityMetadatas.forEach((entityMetadata) =>
3,704✔
393
            this.createForeignKeys(entityMetadata, entityMetadatas),
4,776✔
394
        )
395

396
        // add lazy initializer for entity relations
397
        entityMetadatas
3,704✔
398
            .filter((metadata) => typeof metadata.target === "function")
4,776✔
399
            .forEach((entityMetadata) => {
400
                entityMetadata.relations
4,199✔
401
                    .filter((relation) => relation.isLazy)
3,054✔
402
                    .forEach((relation) => {
403
                        this.connection.relationLoader.enableLazyLoad(
40✔
404
                            relation,
405
                            (entityMetadata.target as Function).prototype,
406
                        )
407
                    })
408
            })
409

410
        entityMetadatas.forEach((entityMetadata) => {
3,704✔
411
            entityMetadata.columns.forEach((column) => {
4,776✔
412
                // const target = column.embeddedMetadata ? column.embeddedMetadata.type : column.target;
413
                const generated = this.metadataArgsStorage.findGenerated(
14,864✔
414
                    column.target,
415
                    column.propertyName,
416
                )
417
                if (generated) {
14,864✔
418
                    column.isGenerated = true
2,808✔
419
                    column.generationStrategy = generated.strategy
2,808✔
420
                    if (generated.strategy === "uuid") {
2,808✔
421
                        column.type = "uuid"
107✔
422
                    } else if (generated.strategy === "rowid") {
2,701!
423
                        column.type = "int"
×
424
                    } else {
425
                        column.type = column.type || Number
2,701!
426
                    }
427
                    column.build(this.connection)
2,808✔
428
                    this.computeEntityMetadataStep2(entityMetadata)
2,808✔
429
                }
430
            })
431
        })
432

433
        return entityMetadatas
3,704✔
434
    }
435

436
    // -------------------------------------------------------------------------
437
    // Protected Methods
438
    // -------------------------------------------------------------------------
439

440
    /**
441
     * Creates entity metadata from the given table args.
442
     * Creates column, relation, etc. metadatas for everything this entity metadata owns.
443
     */
444
    protected createEntityMetadata(
445
        tableArgs: TableMetadataArgs,
446
    ): EntityMetadata {
447
        // we take all "inheritance tree" from a target entity to collect all stored metadata args
448
        // (by decorators or inside entity schemas). For example for target Post < ContentModel < Unit
449
        // it will be an array of [Post, ContentModel, Unit] and we can then get all metadata args of those classes
450
        const inheritanceTree: any[] =
451
            typeof tableArgs.target === "function"
4,270✔
452
                ? MetadataUtils.getInheritanceTree(tableArgs.target)
453
                : [tableArgs.target] // todo: implement later here inheritance for string-targets
454

455
        const tableInheritance = this.metadataArgsStorage.findInheritanceType(
4,270✔
456
            tableArgs.target,
457
        )
458
        const tableTree = this.metadataArgsStorage.findTree(tableArgs.target)
4,270✔
459

460
        // if single table inheritance used, we need to copy all children columns in to parent table
461
        let singleTableChildrenTargets: any[]
462
        if (
4,270✔
463
            (tableInheritance && tableInheritance.pattern === "STI") ||
8,540✔
464
            tableArgs.type === "entity-child"
465
        ) {
466
            singleTableChildrenTargets = this.metadataArgsStorage
296✔
467
                .filterSingleTableChildren(tableArgs.target)
468
                .map((args) => args.target)
224✔
469
                .filter((target) => typeof target === "function")
224✔
470

471
            inheritanceTree.push(...singleTableChildrenTargets)
296✔
472
        }
473

474
        return new EntityMetadata({
4,270✔
475
            connection: this.connection,
476
            args: tableArgs,
477
            inheritanceTree: inheritanceTree,
478
            tableTree: tableTree,
479
            inheritancePattern: tableInheritance
4,270✔
480
                ? tableInheritance.pattern
481
                : undefined,
482
        })
483
    }
484

485
    protected computeParentEntityMetadata(
486
        allEntityMetadatas: EntityMetadata[],
487
        entityMetadata: EntityMetadata,
488
    ) {
489
        // after all metadatas created we set parent entity metadata for table inheritance
490
        if (entityMetadata.tableType === "entity-child") {
4,270✔
491
            entityMetadata.parentEntityMetadata = allEntityMetadatas.find(
192✔
492
                (allEntityMetadata) => {
493
                    return (
276✔
494
                        allEntityMetadata.inheritanceTree.indexOf(
468✔
495
                            entityMetadata.target as Function,
496
                        ) !== -1 &&
497
                        allEntityMetadata.inheritancePattern === "STI"
498
                    )
499
                },
500
            )!
501
        }
502
    }
503

504
    protected computeEntityMetadataStep1(
505
        allEntityMetadatas: EntityMetadata[],
506
        entityMetadata: EntityMetadata,
507
    ) {
508
        const entityInheritance = this.metadataArgsStorage.findInheritanceType(
4,270✔
509
            entityMetadata.target,
510
        )
511

512
        const discriminatorValue =
513
            this.metadataArgsStorage.findDiscriminatorValue(
4,270✔
514
                entityMetadata.target,
515
            )
516

517
        if (typeof discriminatorValue !== "undefined") {
4,270✔
518
            entityMetadata.discriminatorValue = discriminatorValue.value
86✔
519
        } else {
520
            entityMetadata.discriminatorValue = (
4,184✔
521
                entityMetadata.target as any
522
            ).name
523
        }
524

525
        // if single table inheritance is used, we need to mark all embedded columns as nullable
526
        entityMetadata.embeddeds = this.createEmbeddedsRecursively(
4,270✔
527
            entityMetadata,
528
            this.metadataArgsStorage.filterEmbeddeds(
529
                entityMetadata.inheritanceTree,
530
            ),
531
        ).map((embedded: EmbeddedMetadata): EmbeddedMetadata => {
532
            if (entityMetadata.inheritancePattern === "STI") {
283✔
533
                embedded.columns = embedded.columns.map(
8✔
534
                    (column: ColumnMetadata): ColumnMetadata => {
535
                        column.isNullable = true
16✔
536
                        return column
16✔
537
                    },
538
                )
539
            }
540
            return embedded
283✔
541
        })
542

543
        entityMetadata.ownColumns = this.metadataArgsStorage
4,270✔
544
            .filterColumns(entityMetadata.inheritanceTree)
545
            .map((args) => {
546
                // for single table children we reuse columns created for their parents
547
                if (entityMetadata.tableType === "entity-child")
11,025✔
548
                    return entityMetadata.parentEntityMetadata.ownColumns.find(
662✔
549
                        (column) => column.propertyName === args.propertyName,
1,686✔
550
                    )!
551

552
                // for multiple table inheritance we can override default column values
553
                if (
10,363✔
554
                    entityMetadata.tableType === "regular" &&
20,656✔
555
                    args.target !== entityMetadata.target
556
                ) {
557
                    const childArgs = this.metadataArgsStorage.columns.find(
245✔
558
                        (c) =>
559
                            c.propertyName === args.propertyName &&
986,184✔
560
                            c.target === entityMetadata.target,
561
                    )
562
                    if (childArgs && childArgs.options.default) {
245✔
563
                        args.options.default = childArgs.options.default
4✔
564
                    }
565
                }
566

567
                const column = new ColumnMetadata({
10,363✔
568
                    connection: this.connection,
569
                    entityMetadata,
570
                    args,
571
                })
572

573
                // if single table inheritance used, we need to mark all inherit table columns as nullable
574
                const columnInSingleTableInheritedChild =
575
                    allEntityMetadatas.find(
10,363✔
576
                        (otherEntityMetadata) =>
577
                            otherEntityMetadata.tableType === "entity-child" &&
39,784✔
578
                            otherEntityMetadata.target === args.target,
579
                    )
580
                if (columnInSingleTableInheritedChild) column.isNullable = true
10,363✔
581
                return column
10,363✔
582
            })
583

584
        // for table inheritance we need to add a discriminator column
585
        //
586
        if (entityInheritance && entityInheritance.column) {
4,270✔
587
            const discriminatorColumnName =
588
                entityInheritance.column && entityInheritance.column.name
104✔
589
                    ? entityInheritance.column.name
590
                    : "type"
591
            let discriminatorColumn = entityMetadata.ownColumns.find(
104✔
592
                (column) => column.propertyName === discriminatorColumnName,
335✔
593
            )
594
            if (!discriminatorColumn) {
104✔
595
                discriminatorColumn = new ColumnMetadata({
75✔
596
                    connection: this.connection,
597
                    entityMetadata: entityMetadata,
598
                    args: {
599
                        target: entityMetadata.target,
600
                        mode: "virtual",
601
                        propertyName: discriminatorColumnName,
602
                        options: entityInheritance.column || {
75!
603
                            name: discriminatorColumnName,
604
                            type: "varchar",
605
                            nullable: false,
606
                        },
607
                    },
608
                })
609
                discriminatorColumn.isVirtual = true
75✔
610
                discriminatorColumn.isDiscriminator = true
75✔
611
                entityMetadata.ownColumns.push(discriminatorColumn)
75✔
612
            } else {
613
                discriminatorColumn.isDiscriminator = true
29✔
614
            }
615
        }
616

617
        // add discriminator column to the child entity metadatas
618
        // discriminator column will not be there automatically since we are creating it in the code above
619
        if (entityMetadata.tableType === "entity-child") {
4,270✔
620
            const discriminatorColumn =
621
                entityMetadata.parentEntityMetadata.ownColumns.find(
192✔
622
                    (column) => column.isDiscriminator,
746✔
623
                )
624
            if (
192✔
625
                discriminatorColumn &&
384✔
626
                !entityMetadata.ownColumns.find(
627
                    (column) => column === discriminatorColumn,
545✔
628
                )
629
            ) {
630
                entityMetadata.ownColumns.push(discriminatorColumn)
129✔
631
            }
632
            // also copy the inheritance pattern & tree metadata
633
            // this comes in handy when inheritance and trees are used together
634
            entityMetadata.inheritancePattern =
192✔
635
                entityMetadata.parentEntityMetadata.inheritancePattern
636
            if (
192✔
637
                !entityMetadata.treeType &&
384✔
638
                !!entityMetadata.parentEntityMetadata.treeType
639
            ) {
640
                entityMetadata.treeType =
8✔
641
                    entityMetadata.parentEntityMetadata.treeType
642
                entityMetadata.treeOptions =
8✔
643
                    entityMetadata.parentEntityMetadata.treeOptions
644
                entityMetadata.treeParentRelation =
8✔
645
                    entityMetadata.parentEntityMetadata.treeParentRelation
646
                entityMetadata.treeLevelColumn =
8✔
647
                    entityMetadata.parentEntityMetadata.treeLevelColumn
648
            }
649
        }
650

651
        const { namingStrategy } = this.connection
4,270✔
652

653
        // check if tree is used then we need to add extra columns for specific tree types
654
        if (entityMetadata.treeType === "materialized-path") {
4,270✔
655
            entityMetadata.ownColumns.push(
32✔
656
                new ColumnMetadata({
657
                    connection: this.connection,
658
                    entityMetadata: entityMetadata,
659
                    materializedPath: true,
660
                    args: {
661
                        target: entityMetadata.target,
662
                        mode: "virtual",
663
                        propertyName: "mpath",
664
                        options: /*tree.column || */ {
665
                            name: namingStrategy.materializedPathColumnName,
666
                            type: String,
667
                            nullable: true,
668
                            default: "",
669
                        },
670
                    },
671
                }),
672
            )
673
        } else if (entityMetadata.treeType === "nested-set") {
4,238✔
674
            const { left, right } = namingStrategy.nestedSetColumnNames
8✔
675
            entityMetadata.ownColumns.push(
8✔
676
                new ColumnMetadata({
677
                    connection: this.connection,
678
                    entityMetadata: entityMetadata,
679
                    nestedSetLeft: true,
680
                    args: {
681
                        target: entityMetadata.target,
682
                        mode: "virtual",
683
                        propertyName: left,
684
                        options: /*tree.column || */ {
685
                            name: left,
686
                            type: Number,
687
                            nullable: false,
688
                            default: 1,
689
                        },
690
                    },
691
                }),
692
            )
693
            entityMetadata.ownColumns.push(
8✔
694
                new ColumnMetadata({
695
                    connection: this.connection,
696
                    entityMetadata: entityMetadata,
697
                    nestedSetRight: true,
698
                    args: {
699
                        target: entityMetadata.target,
700
                        mode: "virtual",
701
                        propertyName: right,
702
                        options: /*tree.column || */ {
703
                            name: right,
704
                            type: Number,
705
                            nullable: false,
706
                            default: 2,
707
                        },
708
                    },
709
                }),
710
            )
711
        }
712

713
        entityMetadata.ownRelations = this.metadataArgsStorage
4,270✔
714
            .filterRelations(entityMetadata.inheritanceTree)
715
            .map((args) => {
716
                // for single table children we reuse relations created for their parents
717
                if (entityMetadata.tableType === "entity-child") {
2,926✔
718
                    const parentRelation =
719
                        entityMetadata.parentEntityMetadata.ownRelations.find(
86✔
720
                            (relation) =>
721
                                relation.propertyName === args.propertyName,
130✔
722
                        )!
723
                    const type =
724
                        typeof args.type === "function"
86!
725
                            ? (args.type as () => any)()
726
                            : args.type
727
                    if (parentRelation.type !== type) {
86✔
728
                        const clone = Object.create(parentRelation)
8✔
729
                        clone.type = type
8✔
730
                        return clone
8✔
731
                    }
732

733
                    return parentRelation
78✔
734
                }
735

736
                return new RelationMetadata({ entityMetadata, args })
2,840✔
737
            })
738
        entityMetadata.relationIds = this.metadataArgsStorage
4,270✔
739
            .filterRelationIds(entityMetadata.inheritanceTree)
740
            .map((args) => {
741
                // for single table children we reuse relation ids created for their parents
742
                if (entityMetadata.tableType === "entity-child")
136!
743
                    return entityMetadata.parentEntityMetadata.relationIds.find(
×
744
                        (relationId) =>
745
                            relationId.propertyName === args.propertyName,
×
746
                    )!
747

748
                return new RelationIdMetadata({ entityMetadata, args })
136✔
749
            })
750
        entityMetadata.relationCounts = this.metadataArgsStorage
4,270✔
751
            .filterRelationCounts(entityMetadata.inheritanceTree)
752
            .map((args) => {
753
                // for single table children we reuse relation counts created for their parents
754
                if (entityMetadata.tableType === "entity-child")
52!
755
                    return entityMetadata.parentEntityMetadata.relationCounts.find(
×
756
                        (relationCount) =>
757
                            relationCount.propertyName === args.propertyName,
×
758
                    )!
759

760
                return new RelationCountMetadata({ entityMetadata, args })
52✔
761
            })
762
        entityMetadata.ownListeners = this.metadataArgsStorage
4,270✔
763
            .filterListeners(entityMetadata.inheritanceTree)
764
            .map((args) => {
765
                return new EntityListenerMetadata({
48✔
766
                    entityMetadata: entityMetadata,
767
                    args: args,
768
                })
769
            })
770
        entityMetadata.checks = this.metadataArgsStorage
4,270✔
771
            .filterChecks(entityMetadata.inheritanceTree)
772
            .map((args) => {
773
                return new CheckMetadata({ entityMetadata, args })
109✔
774
            })
775

776
        // Only PostgreSQL supports exclusion constraints.
777
        if (this.connection.driver.options.type === "postgres") {
4,270!
778
            entityMetadata.exclusions = this.metadataArgsStorage
×
779
                .filterExclusions(entityMetadata.inheritanceTree)
780
                .map((args) => {
781
                    return new ExclusionMetadata({ entityMetadata, args })
×
782
                })
783
        }
784

785
        if (this.connection.driver.options.type === "cockroachdb") {
4,270!
786
            entityMetadata.ownIndices = this.metadataArgsStorage
×
787
                .filterIndices(entityMetadata.inheritanceTree)
788
                .filter((args) => !args.unique)
×
789
                .map((args) => {
790
                    return new IndexMetadata({ entityMetadata, args })
×
791
                })
792

793
            const uniques = this.metadataArgsStorage
×
794
                .filterIndices(entityMetadata.inheritanceTree)
795
                .filter((args) => args.unique)
×
796
                .map((args) => {
797
                    return new UniqueMetadata({
×
798
                        entityMetadata: entityMetadata,
799
                        args: {
800
                            target: args.target,
801
                            name: args.name,
802
                            columns: args.columns,
803
                        },
804
                    })
805
                })
806
            entityMetadata.ownUniques.push(...uniques)
×
807
        } else {
808
            entityMetadata.ownIndices = this.metadataArgsStorage
4,270✔
809
                .filterIndices(entityMetadata.inheritanceTree)
810
                .map((args) => {
811
                    return new IndexMetadata({ entityMetadata, args })
405✔
812
                })
813
        }
814

815
        // This drivers stores unique constraints as unique indices.
816
        if (
4,270✔
817
            DriverUtils.isMySQLFamily(this.connection.driver) ||
16,888✔
818
            this.connection.driver.options.type === "aurora-mysql" ||
819
            this.connection.driver.options.type === "sap" ||
820
            this.connection.driver.options.type === "spanner"
821
        ) {
822
            const indices = this.metadataArgsStorage
64✔
823
                .filterUniques(entityMetadata.inheritanceTree)
824
                .map((args) => {
825
                    return new IndexMetadata({
×
826
                        entityMetadata: entityMetadata,
827
                        args: {
828
                            target: args.target,
829
                            name: args.name,
830
                            columns: args.columns,
831
                            unique: true,
832
                            synchronize: true,
833
                        },
834
                    })
835
                })
836
            entityMetadata.ownIndices.push(...indices)
64✔
837
        } else {
838
            const uniques = this.metadataArgsStorage
4,206✔
839
                .filterUniques(entityMetadata.inheritanceTree)
840
                .map((args) => {
841
                    return new UniqueMetadata({ entityMetadata, args })
506✔
842
                })
843
            entityMetadata.ownUniques.push(...uniques)
4,206✔
844
        }
845
    }
846

847
    /**
848
     * Creates from the given embedded metadata args real embedded metadatas with its columns and relations,
849
     * and does the same for all its sub-embeddeds (goes recursively).
850
     */
851
    protected createEmbeddedsRecursively(
852
        entityMetadata: EntityMetadata,
853
        embeddedArgs: EmbeddedMetadataArgs[],
854
    ): EmbeddedMetadata[] {
855
        return embeddedArgs.map((embeddedArgs) => {
4,708✔
856
            const embeddedMetadata = new EmbeddedMetadata({
438✔
857
                entityMetadata: entityMetadata,
858
                args: embeddedArgs,
859
            })
860
            const targets: any[] =
861
                typeof embeddedMetadata.type === "function"
438✔
862
                    ? MetadataUtils.getInheritanceTree(embeddedMetadata.type)
863
                    : [embeddedMetadata.type] // todo: implement later here inheritance for string-targets
864

865
            embeddedMetadata.columns = this.metadataArgsStorage
438✔
866
                .filterColumns(targets)
867
                .map((args) => {
868
                    return new ColumnMetadata({
1,066✔
869
                        connection: this.connection,
870
                        entityMetadata,
871
                        embeddedMetadata,
872
                        args,
873
                    })
874
                })
875
            embeddedMetadata.relations = this.metadataArgsStorage
438✔
876
                .filterRelations(targets)
877
                .map((args) => {
878
                    return new RelationMetadata({
152✔
879
                        entityMetadata,
880
                        embeddedMetadata,
881
                        args,
882
                    })
883
                })
884
            embeddedMetadata.listeners = this.metadataArgsStorage
438✔
885
                .filterListeners(targets)
886
                .map((args) => {
887
                    return new EntityListenerMetadata({
12✔
888
                        entityMetadata,
889
                        embeddedMetadata,
890
                        args,
891
                    })
892
                })
893
            embeddedMetadata.indices = this.metadataArgsStorage
438✔
894
                .filterIndices(targets)
895
                .map((args) => {
896
                    return new IndexMetadata({
24✔
897
                        entityMetadata,
898
                        embeddedMetadata,
899
                        args,
900
                    })
901
                })
902
            embeddedMetadata.uniques = this.metadataArgsStorage
438✔
903
                .filterUniques(targets)
904
                .map((args) => {
905
                    return new UniqueMetadata({
4✔
906
                        entityMetadata,
907
                        embeddedMetadata,
908
                        args,
909
                    })
910
                })
911
            embeddedMetadata.relationIds = this.metadataArgsStorage
438✔
912
                .filterRelationIds(targets)
913
                .map((args) => {
914
                    return new RelationIdMetadata({ entityMetadata, args })
×
915
                })
916
            embeddedMetadata.relationCounts = this.metadataArgsStorage
438✔
917
                .filterRelationCounts(targets)
918
                .map((args) => {
919
                    return new RelationCountMetadata({ entityMetadata, args })
×
920
                })
921
            embeddedMetadata.embeddeds = this.createEmbeddedsRecursively(
438✔
922
                entityMetadata,
923
                this.metadataArgsStorage.filterEmbeddeds(targets),
924
            )
925
            embeddedMetadata.embeddeds.forEach(
438✔
926
                (subEmbedded) =>
927
                    (subEmbedded.parentEmbeddedMetadata = embeddedMetadata),
155✔
928
            )
929
            entityMetadata.allEmbeddeds.push(embeddedMetadata)
438✔
930
            return embeddedMetadata
438✔
931
        })
932
    }
933

934
    /**
935
     * Computes all entity metadata's computed properties, and all its sub-metadatas (relations, columns, embeds, etc).
936
     */
937
    protected computeEntityMetadataStep2(entityMetadata: EntityMetadata) {
938
        entityMetadata.embeddeds.forEach((embedded) =>
7,901✔
939
            embedded.build(this.connection),
458✔
940
        )
941
        entityMetadata.embeddeds.forEach((embedded) => {
7,901✔
942
            embedded.columnsFromTree.forEach((column) =>
458✔
943
                column.build(this.connection),
1,684✔
944
            )
945
            embedded.relationsFromTree.forEach((relation) => relation.build())
458✔
946
        })
947
        entityMetadata.ownColumns.forEach((column) =>
7,901✔
948
            column.build(this.connection),
22,043✔
949
        )
950
        entityMetadata.ownRelations.forEach((relation) => relation.build())
7,901✔
951
        entityMetadata.relations = entityMetadata.embeddeds.reduce(
7,901✔
952
            (relations, embedded) =>
953
                relations.concat(embedded.relationsFromTree),
458✔
954
            entityMetadata.ownRelations,
955
        )
956
        entityMetadata.eagerRelations = entityMetadata.relations.filter(
7,901✔
957
            (relation) => relation.isEager,
6,029✔
958
        )
959
        entityMetadata.lazyRelations = entityMetadata.relations.filter(
7,901✔
960
            (relation) => relation.isLazy,
6,029✔
961
        )
962
        entityMetadata.oneToOneRelations = entityMetadata.relations.filter(
7,901✔
963
            (relation) => relation.isOneToOne,
6,029✔
964
        )
965
        entityMetadata.oneToManyRelations = entityMetadata.relations.filter(
7,901✔
966
            (relation) => relation.isOneToMany,
6,029✔
967
        )
968
        entityMetadata.manyToOneRelations = entityMetadata.relations.filter(
7,901✔
969
            (relation) => relation.isManyToOne,
6,029✔
970
        )
971
        entityMetadata.manyToManyRelations = entityMetadata.relations.filter(
7,901✔
972
            (relation) => relation.isManyToMany,
6,029✔
973
        )
974
        entityMetadata.ownerOneToOneRelations = entityMetadata.relations.filter(
7,901✔
975
            (relation) => relation.isOneToOneOwner,
6,029✔
976
        )
977
        entityMetadata.ownerManyToManyRelations =
7,901✔
978
            entityMetadata.relations.filter(
979
                (relation) => relation.isManyToManyOwner,
6,029✔
980
            )
981
        entityMetadata.treeParentRelation = entityMetadata.relations.find(
7,901✔
982
            (relation) => relation.isTreeParent,
5,815✔
983
        )
984
        entityMetadata.treeChildrenRelation = entityMetadata.relations.find(
7,901✔
985
            (relation) => relation.isTreeChildren,
5,977✔
986
        )
987
        entityMetadata.columns = entityMetadata.embeddeds.reduce(
7,901✔
988
            (columns, embedded) => columns.concat(embedded.columnsFromTree),
458✔
989
            entityMetadata.ownColumns,
990
        )
991
        entityMetadata.listeners = entityMetadata.embeddeds.reduce(
7,901✔
992
            (listeners, embedded) =>
993
                listeners.concat(embedded.listenersFromTree),
458✔
994
            entityMetadata.ownListeners,
995
        )
996
        entityMetadata.afterLoadListeners = entityMetadata.listeners.filter(
7,901✔
997
            (listener) => listener.type === EventListenerTypes.AFTER_LOAD,
112✔
998
        )
999
        entityMetadata.afterInsertListeners = entityMetadata.listeners.filter(
7,901✔
1000
            (listener) => listener.type === EventListenerTypes.AFTER_INSERT,
112✔
1001
        )
1002
        entityMetadata.afterUpdateListeners = entityMetadata.listeners.filter(
7,901✔
1003
            (listener) => listener.type === EventListenerTypes.AFTER_UPDATE,
112✔
1004
        )
1005
        entityMetadata.afterRemoveListeners = entityMetadata.listeners.filter(
7,901✔
1006
            (listener) => listener.type === EventListenerTypes.AFTER_REMOVE,
112✔
1007
        )
1008
        entityMetadata.afterSoftRemoveListeners =
7,901✔
1009
            entityMetadata.listeners.filter(
1010
                (listener) =>
1011
                    listener.type === EventListenerTypes.AFTER_SOFT_REMOVE,
112✔
1012
            )
1013
        entityMetadata.afterRecoverListeners = entityMetadata.listeners.filter(
7,901✔
1014
            (listener) => listener.type === EventListenerTypes.AFTER_RECOVER,
112✔
1015
        )
1016
        entityMetadata.beforeInsertListeners = entityMetadata.listeners.filter(
7,901✔
1017
            (listener) => listener.type === EventListenerTypes.BEFORE_INSERT,
112✔
1018
        )
1019
        entityMetadata.beforeUpdateListeners = entityMetadata.listeners.filter(
7,901✔
1020
            (listener) => listener.type === EventListenerTypes.BEFORE_UPDATE,
112✔
1021
        )
1022
        entityMetadata.beforeRemoveListeners = entityMetadata.listeners.filter(
7,901✔
1023
            (listener) => listener.type === EventListenerTypes.BEFORE_REMOVE,
112✔
1024
        )
1025
        entityMetadata.beforeSoftRemoveListeners =
7,901✔
1026
            entityMetadata.listeners.filter(
1027
                (listener) =>
1028
                    listener.type === EventListenerTypes.BEFORE_SOFT_REMOVE,
112✔
1029
            )
1030
        entityMetadata.beforeRecoverListeners = entityMetadata.listeners.filter(
7,901✔
1031
            (listener) => listener.type === EventListenerTypes.BEFORE_RECOVER,
112✔
1032
        )
1033
        entityMetadata.indices = entityMetadata.embeddeds.reduce(
7,901✔
1034
            (indices, embedded) => indices.concat(embedded.indicesFromTree),
458✔
1035
            entityMetadata.ownIndices,
1036
        )
1037
        entityMetadata.uniques = entityMetadata.embeddeds.reduce(
7,901✔
1038
            (uniques, embedded) => uniques.concat(embedded.uniquesFromTree),
458✔
1039
            entityMetadata.ownUniques,
1040
        )
1041
        entityMetadata.primaryColumns = entityMetadata.columns.filter(
7,901✔
1042
            (column) => column.isPrimary,
23,727✔
1043
        )
1044
        entityMetadata.nonVirtualColumns = entityMetadata.columns.filter(
7,901✔
1045
            (column) => !column.isVirtual,
23,727✔
1046
        )
1047
        entityMetadata.ancestorColumns = entityMetadata.columns.filter(
7,901✔
1048
            (column) => column.closureType === "ancestor",
23,727✔
1049
        )
1050
        entityMetadata.descendantColumns = entityMetadata.columns.filter(
7,901✔
1051
            (column) => column.closureType === "descendant",
23,727✔
1052
        )
1053
        entityMetadata.hasMultiplePrimaryKeys =
7,901✔
1054
            entityMetadata.primaryColumns.length > 1
1055
        entityMetadata.generatedColumns = entityMetadata.columns.filter(
7,901✔
1056
            (column) => column.isGenerated || column.isObjectId,
23,727✔
1057
        )
1058
        entityMetadata.hasUUIDGeneratedColumns =
7,901✔
1059
            entityMetadata.columns.filter(
1060
                (column) =>
1061
                    column.isGenerated || column.generationStrategy === "uuid",
23,727✔
1062
            ).length > 0
1063
        entityMetadata.createDateColumn = entityMetadata.columns.find(
7,901✔
1064
            (column) => column.isCreateDate,
23,055✔
1065
        )
1066
        entityMetadata.updateDateColumn = entityMetadata.columns.find(
7,901✔
1067
            (column) => column.isUpdateDate,
23,279✔
1068
        )
1069
        entityMetadata.deleteDateColumn = entityMetadata.columns.find(
7,901✔
1070
            (column) => column.isDeleteDate,
23,523✔
1071
        )
1072
        entityMetadata.versionColumn = entityMetadata.columns.find(
7,901✔
1073
            (column) => column.isVersion,
23,690✔
1074
        )
1075
        entityMetadata.discriminatorColumn = entityMetadata.columns.find(
7,901✔
1076
            (column) => column.isDiscriminator,
23,221✔
1077
        )
1078
        entityMetadata.treeLevelColumn = entityMetadata.columns.find(
7,901✔
1079
            (column) => column.isTreeLevel,
23,707✔
1080
        )
1081
        entityMetadata.nestedSetLeftColumn = entityMetadata.columns.find(
7,901✔
1082
            (column) => column.isNestedSetLeft,
23,703✔
1083
        )
1084
        entityMetadata.nestedSetRightColumn = entityMetadata.columns.find(
7,901✔
1085
            (column) => column.isNestedSetRight,
23,719✔
1086
        )
1087
        entityMetadata.materializedPathColumn = entityMetadata.columns.find(
7,901✔
1088
            (column) => column.isMaterializedPath,
23,695✔
1089
        )
1090
        entityMetadata.objectIdColumn = entityMetadata.columns.find(
7,901✔
1091
            (column) => column.isObjectId,
23,727✔
1092
        )
1093
        entityMetadata.foreignKeys.forEach((foreignKey) =>
7,901✔
1094
            foreignKey.build(this.connection.namingStrategy),
2,622✔
1095
        )
1096
        entityMetadata.propertiesMap = entityMetadata.createPropertiesMap()
7,901✔
1097
        entityMetadata.relationIds.forEach((relationId) => relationId.build())
7,901✔
1098
        entityMetadata.relationCounts.forEach((relationCount) =>
7,901✔
1099
            relationCount.build(),
60✔
1100
        )
1101
        entityMetadata.embeddeds.forEach((embedded) => {
7,901✔
1102
            embedded.relationIdsFromTree.forEach((relationId) =>
458✔
1103
                relationId.build(),
×
1104
            )
1105
            embedded.relationCountsFromTree.forEach((relationCount) =>
458✔
1106
                relationCount.build(),
×
1107
            )
1108
        })
1109
    }
1110

1111
    /**
1112
     * Computes entity metadata's relations inverse side properties.
1113
     */
1114
    protected computeInverseProperties(
1115
        entityMetadata: EntityMetadata,
1116
        entityMetadatas: EntityMetadata[],
1117
    ) {
1118
        entityMetadata.relations.forEach((relation) => {
4,776✔
1119
            // compute inverse side (related) entity metadatas for all relation metadatas
1120
            const inverseEntityMetadata = entityMetadatas.find(
3,078✔
1121
                (m) =>
1122
                    m.target === relation.type ||
7,289✔
1123
                    (typeof relation.type === "string" &&
1124
                        (m.targetName === relation.type ||
1125
                            m.givenTableName === relation.type)),
1126
            )
1127
            if (!inverseEntityMetadata)
3,078!
1128
                throw new TypeORMError(
×
1129
                    "Entity metadata for " +
1130
                        entityMetadata.name +
1131
                        "#" +
1132
                        relation.propertyPath +
1133
                        " was not found. Check if you specified a correct entity object and if it's connected in the connection options.",
1134
                )
1135

1136
            relation.inverseEntityMetadata = inverseEntityMetadata
3,078✔
1137
            relation.inverseSidePropertyPath =
3,078✔
1138
                relation.buildInverseSidePropertyPath()
1139

1140
            // and compute inverse relation and mark if it has such
1141
            relation.inverseRelation = inverseEntityMetadata.relations.find(
3,078✔
1142
                (foundRelation) =>
1143
                    foundRelation.propertyPath ===
3,612✔
1144
                    relation.inverseSidePropertyPath,
1145
            )
1146
        })
1147
    }
1148

1149
    /**
1150
     * Creates indices for the table of single table inheritance.
1151
     */
1152
    protected createKeysForTableInheritance(entityMetadata: EntityMetadata) {
1153
        const isDiscriminatorColumnAlreadyIndexed = entityMetadata.indices.some(
296✔
1154
            ({ givenColumnNames }) =>
1155
                !!givenColumnNames &&
12✔
1156
                Array.isArray(givenColumnNames) &&
1157
                givenColumnNames.length === 1 &&
1158
                givenColumnNames[0] ===
1159
                    entityMetadata.discriminatorColumn?.databaseName,
1160
        )
1161

1162
        // If the discriminator column is already indexed, there is no need to
1163
        // add another index on top of it.
1164
        if (isDiscriminatorColumnAlreadyIndexed) {
296✔
1165
            return
12✔
1166
        }
1167

1168
        entityMetadata.indices.push(
284✔
1169
            new IndexMetadata({
1170
                entityMetadata: entityMetadata,
1171
                columns: [entityMetadata.discriminatorColumn!],
1172
                args: {
1173
                    target: entityMetadata.target,
1174
                    unique: false,
1175
                },
1176
            }),
1177
        )
1178
    }
1179

1180
    /**
1181
     * Creates from the given foreign key metadata args real foreign key metadatas.
1182
     */
1183
    protected createForeignKeys(
1184
        entityMetadata: EntityMetadata,
1185
        entityMetadatas: EntityMetadata[],
1186
    ) {
1187
        this.metadataArgsStorage
4,776✔
1188
            .filterForeignKeys(entityMetadata.inheritanceTree)
1189
            .forEach((foreignKeyArgs) => {
1190
                const foreignKeyType =
1191
                    typeof foreignKeyArgs.type === "function"
40✔
1192
                        ? (foreignKeyArgs.type as () => any)()
1193
                        : foreignKeyArgs.type
1194

1195
                const referencedEntityMetadata = entityMetadatas.find((m) =>
40✔
1196
                    typeof foreignKeyType === "string"
100✔
1197
                        ? m.targetName === foreignKeyType ||
88✔
1198
                          m.givenTableName === foreignKeyType
1199
                        : InstanceChecker.isEntitySchema(foreignKeyType)
52✔
1200
                        ? m.target === foreignKeyType.options.name ||
68✔
1201
                          m.target === foreignKeyType.options.target
1202
                        : m.target === foreignKeyType,
1203
                )
1204

1205
                if (!referencedEntityMetadata) {
40!
1206
                    throw new TypeORMError(
×
1207
                        "Entity metadata for " +
1208
                            entityMetadata.name +
1209
                            (foreignKeyArgs.propertyName
×
1210
                                ? "#" + foreignKeyArgs.propertyName
1211
                                : "") +
1212
                            " was not found. Check if you specified a correct entity object and if it's connected in the connection options.",
1213
                    )
1214
                }
1215

1216
                const columnNames = foreignKeyArgs.columnNames ?? []
40✔
1217
                const referencedColumnNames =
1218
                    foreignKeyArgs.referencedColumnNames ?? []
40✔
1219

1220
                const columns: ColumnMetadata[] = []
40✔
1221
                const referencedColumns: ColumnMetadata[] = []
40✔
1222

1223
                if (foreignKeyArgs.propertyName) {
40✔
1224
                    columnNames.push(foreignKeyArgs.propertyName)
32✔
1225

1226
                    if (foreignKeyArgs.inverseSide) {
32✔
1227
                        if (typeof foreignKeyArgs.inverseSide === "function") {
16✔
1228
                            referencedColumnNames.push(
4✔
1229
                                foreignKeyArgs.inverseSide(
1230
                                    referencedEntityMetadata.propertiesMap,
1231
                                ),
1232
                            )
1233
                        } else {
1234
                            referencedColumnNames.push(
12✔
1235
                                foreignKeyArgs.inverseSide,
1236
                            )
1237
                        }
1238
                    }
1239
                }
1240

1241
                if (!referencedColumnNames.length) {
40✔
1242
                    referencedColumns.push(
16✔
1243
                        ...referencedEntityMetadata.primaryColumns,
1244
                    )
1245
                }
1246

1247
                const columnNameToColumn = (
40✔
1248
                    columnName: string,
1249
                    entityMetadata: EntityMetadata,
1250
                ): ColumnMetadata => {
1251
                    const column = entityMetadata.columns.find(
80✔
1252
                        (column) =>
1253
                            column.propertyName === columnName ||
192✔
1254
                            column.databaseName === columnName,
1255
                    )
1256

1257
                    if (column) return column
80✔
1258

1259
                    const foreignKeyName = foreignKeyArgs.name
×
1260
                        ? '"' + foreignKeyArgs.name + '" '
1261
                        : ""
1262
                    const entityName = entityMetadata.targetName
×
1263
                    throw new TypeORMError(
×
1264
                        `Foreign key constraint ${foreignKeyName}contains column that is missing in the entity (${entityName}): ${columnName}`,
1265
                    )
1266
                }
1267

1268
                columns.push(
40✔
1269
                    ...columnNames.map((columnName) =>
1270
                        columnNameToColumn(columnName, entityMetadata),
48✔
1271
                    ),
1272
                )
1273

1274
                referencedColumns.push(
40✔
1275
                    ...referencedColumnNames.map((columnName) =>
1276
                        columnNameToColumn(
32✔
1277
                            columnName,
1278
                            referencedEntityMetadata,
1279
                        ),
1280
                    ),
1281
                )
1282

1283
                entityMetadata.foreignKeys.push(
40✔
1284
                    new ForeignKeyMetadata({
1285
                        entityMetadata,
1286
                        referencedEntityMetadata,
1287
                        namingStrategy: this.connection.namingStrategy,
1288
                        columns,
1289
                        referencedColumns,
1290
                        ...foreignKeyArgs,
1291
                    }),
1292
                )
1293
            })
1294
    }
1295
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc