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

typeorm / typeorm / 15089093306

17 May 2025 09:03PM UTC coverage: 50.109% (-26.2%) from 76.346%
15089093306

Pull #11437

github

naorpeled
add comment about vector <#>
Pull Request #11437: feat(postgres): support vector data type

5836 of 12767 branches covered (45.71%)

Branch coverage included in aggregate %.

16 of 17 new or added lines in 4 files covered. (94.12%)

6283 existing lines in 64 files now uncovered.

12600 of 24025 relevant lines covered (52.45%)

28708.0 hits per line

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

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

26
/**
27
 * Builds EntityMetadata objects and all its sub-metadatas.
28
 */
29
export class EntityMetadataBuilder {
6✔
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,
5,956✔
55
        private metadataArgsStorage: MetadataArgsStorage,
5,956✔
56
    ) {
57
        this.junctionEntityMetadataBuilder = new JunctionEntityMetadataBuilder(
5,956✔
58
            connection,
59
        )
60
        this.closureJunctionEntityMetadataBuilder =
5,956✔
61
            new ClosureJunctionEntityMetadataBuilder(connection)
62
        this.relationJoinColumnBuilder = new RelationJoinColumnBuilder(
5,956✔
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
5,956✔
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(
5,956✔
82
            (table) =>
83
                table.type === "regular" ||
6,726✔
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) =>
5,956✔
91
            this.createEntityMetadata(tableArgs),
6,726✔
92
        )
93

94
        // compute parent entity metadatas for table inheritance
95
        entityMetadatas.forEach((entityMetadata) =>
5,956✔
96
            this.computeParentEntityMetadata(entityMetadatas, entityMetadata),
6,726✔
97
        )
98

99
        // after all metadatas created we set child entity metadatas for table inheritance
100
        entityMetadatas.forEach((metadata) => {
5,956✔
101
            metadata.childEntityMetadatas = entityMetadatas.filter(
6,726✔
102
                (childMetadata) => {
103
                    return (
25,554✔
104
                        typeof metadata.target === "function" &&
76,100✔
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
5,956✔
117
            .filter(
118
                (entityMetadata) => entityMetadata.tableType !== "entity-child",
6,726✔
119
            )
120
            .forEach((entityMetadata) => entityMetadata.build())
6,429✔
121

122
        // build entity metadata (step0), now for single-table-inherited entity metadatas (dependant)
123
        entityMetadatas
5,956✔
124
            .filter(
125
                (entityMetadata) => entityMetadata.tableType === "entity-child",
6,726✔
126
            )
127
            .forEach((entityMetadata) => entityMetadata.build())
297✔
128

129
        // compute entity metadata columns, relations, etc. first for the regular, non-single-table-inherited entity metadatas
130
        entityMetadatas
5,956✔
131
            .filter(
132
                (entityMetadata) => entityMetadata.tableType !== "entity-child",
6,726✔
133
            )
134
            .forEach((entityMetadata) =>
135
                this.computeEntityMetadataStep1(
6,429✔
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
5,956✔
143
            .filter(
144
                (entityMetadata) => entityMetadata.tableType === "entity-child",
6,726✔
145
            )
146
            .forEach((entityMetadata) =>
147
                this.computeEntityMetadataStep1(
297✔
148
                    entityMetadatas,
149
                    entityMetadata,
150
                ),
151
            )
152

153
        // calculate entity metadata computed properties and all its sub-metadatas
154
        entityMetadatas.forEach((entityMetadata) =>
5,956✔
155
            this.computeEntityMetadataStep2(entityMetadata),
6,726✔
156
        )
157

158
        // calculate entity metadata's inverse properties
159
        entityMetadatas.forEach((entityMetadata) =>
5,956✔
160
            this.computeInverseProperties(entityMetadata, entityMetadatas),
6,726✔
161
        )
162

163
        // go through all entity metadatas and create foreign keys / junction entity metadatas for their relations
164
        entityMetadatas
5,956✔
165
            .filter(
166
                (entityMetadata) => entityMetadata.tableType !== "entity-child",
6,726✔
167
            )
168
            .forEach((entityMetadata) => {
169
                // create entity's relations join columns (for many-to-one and one-to-one owner)
170
                entityMetadata.relations
6,429✔
171
                    .filter(
172
                        (relation) =>
173
                            relation.isOneToOne || relation.isManyToOne,
4,709✔
174
                    )
175
                    .forEach((relation) => {
176
                        const joinColumns =
177
                            this.metadataArgsStorage.filterJoinColumns(
2,534✔
178
                                relation.target,
179
                                relation.propertyName,
180
                            )
181
                        const { foreignKey, columns, uniqueConstraint } =
182
                            this.relationJoinColumnBuilder.build(
2,534✔
183
                                joinColumns,
184
                                relation,
185
                            ) // create a foreign key based on its metadata args
186
                        if (foreignKey) {
2,534✔
187
                            relation.registerForeignKeys(foreignKey) // push it to the relation and thus register there a join column
2,273✔
188
                            entityMetadata.foreignKeys.push(foreignKey)
2,273✔
189
                        }
190
                        if (columns) {
2,534✔
191
                            relation.registerJoinColumns(columns)
2,534✔
192
                        }
193
                        if (uniqueConstraint) {
2,534✔
194
                            if (
496✔
195
                                DriverUtils.isMySQLFamily(
2,312✔
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({
42✔
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 (
42!
219
                                    this.connection.driver.options.type ===
220
                                    "mssql"
221
                                ) {
UNCOV
222
                                    index.where = index.columns
×
223
                                        .map((column) => {
UNCOV
224
                                            return `${this.connection.driver.escape(
×
225
                                                column.databaseName,
226
                                            )} IS NOT NULL`
227
                                        })
228
                                        .join(" AND ")
229
                                }
230

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

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

262
                        if (
2,534!
263
                            foreignKey &&
4,807✔
264
                            this.connection.driver.options.type ===
265
                                "cockroachdb"
266
                        ) {
UNCOV
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
                            })
UNCOV
275
                            if (relation.embeddedMetadata) {
×
UNCOV
276
                                relation.embeddedMetadata.indices.push(index)
×
277
                            } else {
UNCOV
278
                                relation.entityMetadata.ownIndices.push(index)
×
279
                            }
UNCOV
280
                            this.computeEntityMetadataStep2(entityMetadata)
×
281
                        }
282
                    })
283

284
                // create junction entity metadatas for entity many-to-many relations
285
                entityMetadata.relations
6,429✔
286
                    .filter((relation) => relation.isManyToMany)
4,709✔
287
                    .forEach((relation) => {
288
                        const joinTable =
289
                            this.metadataArgsStorage.findJoinTable(
1,059✔
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)
1,059✔
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(
680✔
298
                                relation,
299
                                joinTable,
300
                            )
301
                        relation.registerForeignKeys(
680✔
302
                            ...junctionEntityMetadata.foreignKeys,
303
                        )
304
                        relation.registerJoinColumns(
680✔
305
                            junctionEntityMetadata.ownIndices[0].columns,
306
                            junctionEntityMetadata.ownIndices[1].columns,
307
                        )
308
                        relation.registerJunctionEntityMetadata(
680✔
309
                            junctionEntityMetadata,
310
                        )
311

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

322
        // update entity metadata depend properties
323
        entityMetadatas.forEach((entityMetadata) => {
5,956✔
324
            entityMetadata.relationsWithJoinColumns =
7,406✔
325
                entityMetadata.relations.filter(
326
                    (relation) => relation.isWithJoinColumn,
4,842✔
327
                )
328
            entityMetadata.hasNonNullableRelations =
7,406✔
329
                entityMetadata.relationsWithJoinColumns.some(
330
                    (relation) => !relation.isNullable || relation.isPrimary,
2,299✔
331
                )
332
        })
333

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

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

363
        // build all indices (need to do it after relations and their join columns are built)
364
        entityMetadatas.forEach((entityMetadata) => {
5,956✔
365
            entityMetadata.indices.forEach((index) =>
7,520✔
366
                index.build(this.connection.namingStrategy),
2,756✔
367
            )
368
        })
369

370
        // build all unique constraints (need to do it after relations and their join columns are built)
371
        entityMetadatas.forEach((entityMetadata) => {
5,956✔
372
            entityMetadata.uniques.forEach((unique) =>
7,520✔
373
                unique.build(this.connection.namingStrategy),
1,245✔
374
            )
375
        })
376

377
        // build all check constraints
378
        entityMetadatas.forEach((entityMetadata) => {
5,956✔
379
            entityMetadata.checks.forEach((check) =>
7,520✔
380
                check.build(this.connection.namingStrategy),
166✔
381
            )
382
        })
383

384
        // build all exclusion constraints
385
        entityMetadatas.forEach((entityMetadata) => {
5,956✔
386
            entityMetadata.exclusions.forEach((exclusion) =>
7,520✔
387
                exclusion.build(this.connection.namingStrategy),
33✔
388
            )
389
        })
390

391
        // generate foreign keys for tables
392
        entityMetadatas.forEach((entityMetadata) =>
5,956✔
393
            this.createForeignKeys(entityMetadata, entityMetadatas),
7,520✔
394
        )
395

396
        // add lazy initializer for entity relations
397
        entityMetadatas
5,956✔
398
            .filter((metadata) => typeof metadata.target === "function")
7,520✔
399
            .forEach((entityMetadata) => {
400
                entityMetadata.relations
6,616✔
401
                    .filter((relation) => relation.isLazy)
4,802✔
402
                    .forEach((relation) => {
403
                        this.connection.relationLoader.enableLazyLoad(
110✔
404
                            relation,
405
                            (entityMetadata.target as Function).prototype,
406
                        )
407
                    })
408
            })
409

410
        entityMetadatas.forEach((entityMetadata) => {
5,956✔
411
            entityMetadata.columns.forEach((column) => {
7,520✔
412
                // const target = column.embeddedMetadata ? column.embeddedMetadata.type : column.target;
413
                const generated = this.metadataArgsStorage.findGenerated(
23,480✔
414
                    column.target,
415
                    column.propertyName,
416
                )
417
                if (generated) {
23,480✔
418
                    column.isGenerated = true
4,467✔
419
                    column.generationStrategy = generated.strategy
4,467✔
420
                    if (generated.strategy === "uuid") {
4,467✔
421
                        column.type = "uuid"
186✔
422
                    } else if (generated.strategy === "rowid") {
4,281!
UNCOV
423
                        column.type = "int"
×
424
                    } else {
425
                        column.type = column.type || Number
4,281!
426
                    }
427
                    column.build(this.connection)
4,467✔
428
                    this.computeEntityMetadataStep2(entityMetadata)
4,467✔
429
                }
430
            })
431
        })
432

433
        return entityMetadatas
5,956✔
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"
6,726✔
452
                ? MetadataUtils.getInheritanceTree(tableArgs.target)
453
                : [tableArgs.target] // todo: implement later here inheritance for string-targets
454

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

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

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

474
        return new EntityMetadata({
6,726✔
475
            connection: this.connection,
476
            args: tableArgs,
477
            inheritanceTree: inheritanceTree,
478
            tableTree: tableTree,
479
            inheritancePattern: tableInheritance
6,726✔
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") {
6,726✔
491
            entityMetadata.parentEntityMetadata = allEntityMetadatas.find(
297✔
492
                (allEntityMetadata) => {
493
                    return (
425✔
494
                        allEntityMetadata.inheritanceTree.indexOf(
722✔
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(
6,726✔
509
            entityMetadata.target,
510
        )
511

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

517
        if (typeof discriminatorValue !== "undefined") {
6,726✔
518
            entityMetadata.discriminatorValue = discriminatorValue.value
134✔
519
        } else {
520
            entityMetadata.discriminatorValue = (
6,592✔
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(
6,726✔
527
            entityMetadata,
528
            this.metadataArgsStorage.filterEmbeddeds(
529
                entityMetadata.inheritanceTree,
530
            ),
531
        ).map((embedded: EmbeddedMetadata): EmbeddedMetadata => {
532
            if (entityMetadata.inheritancePattern === "STI") {
430✔
533
                embedded.columns = embedded.columns.map(
12✔
534
                    (column: ColumnMetadata): ColumnMetadata => {
535
                        column.isNullable = true
24✔
536
                        return column
24✔
537
                    },
538
                )
539
            }
540
            return embedded
430✔
541
        })
542

543
        entityMetadata.ownColumns = this.metadataArgsStorage
6,726✔
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")
17,495✔
548
                    return entityMetadata.parentEntityMetadata.ownColumns.find(
1,015✔
549
                        (column) => column.propertyName === args.propertyName,
2,575✔
550
                    )!
551

552
                // for multiple table inheritance we can override default column values
553
                if (
16,480✔
554
                    entityMetadata.tableType === "regular" &&
32,850✔
555
                    args.target !== entityMetadata.target
556
                ) {
557
                    const childArgs = this.metadataArgsStorage.columns.find(
379✔
558
                        (c) =>
559
                            c.propertyName === args.propertyName &&
1,553,574✔
560
                            c.target === entityMetadata.target,
561
                    )
562
                    if (childArgs && childArgs.options.default) {
379✔
563
                        args.options.default = childArgs.options.default
6✔
564
                    }
565
                }
566

567
                const column = new ColumnMetadata({
16,480✔
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(
16,480✔
576
                        (otherEntityMetadata) =>
577
                            otherEntityMetadata.tableType === "entity-child" &&
62,558✔
578
                            otherEntityMetadata.target === args.target,
579
                    )
580
                if (columnInSingleTableInheritedChild) column.isNullable = true
16,480✔
581
                return column
16,480✔
582
            })
583

584
        // for table inheritance we need to add a discriminator column
585
        //
586
        if (entityInheritance && entityInheritance.column) {
6,726✔
587
            const discriminatorColumnName =
588
                entityInheritance.column && entityInheritance.column.name
162✔
589
                    ? entityInheritance.column.name
590
                    : "type"
591
            let discriminatorColumn = entityMetadata.ownColumns.find(
162✔
592
                (column) => column.propertyName === discriminatorColumnName,
527✔
593
            )
594
            if (!discriminatorColumn) {
162✔
595
                discriminatorColumn = new ColumnMetadata({
120✔
596
                    connection: this.connection,
597
                    entityMetadata: entityMetadata,
598
                    args: {
599
                        target: entityMetadata.target,
600
                        mode: "virtual",
601
                        propertyName: discriminatorColumnName,
602
                        options: entityInheritance.column || {
120!
603
                            name: discriminatorColumnName,
604
                            type: "varchar",
605
                            nullable: false,
606
                        },
607
                    },
608
                })
609
                discriminatorColumn.isVirtual = true
120✔
610
                discriminatorColumn.isDiscriminator = true
120✔
611
                entityMetadata.ownColumns.push(discriminatorColumn)
120✔
612
            } else {
613
                discriminatorColumn.isDiscriminator = true
42✔
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") {
6,726✔
620
            const discriminatorColumn =
621
                entityMetadata.parentEntityMetadata.ownColumns.find(
297✔
622
                    (column) => column.isDiscriminator,
1,181✔
623
                )
624
            if (
297✔
625
                discriminatorColumn &&
594✔
626
                !entityMetadata.ownColumns.find(
627
                    (column) => column === discriminatorColumn,
853✔
628
                )
629
            ) {
630
                entityMetadata.ownColumns.push(discriminatorColumn)
207✔
631
            }
632
            // also copy the inheritance pattern & tree metadata
633
            // this comes in handy when inheritance and trees are used together
634
            entityMetadata.inheritancePattern =
297✔
635
                entityMetadata.parentEntityMetadata.inheritancePattern
636
            if (
297✔
637
                !entityMetadata.treeType &&
594✔
638
                !!entityMetadata.parentEntityMetadata.treeType
639
            ) {
640
                entityMetadata.treeType =
12✔
641
                    entityMetadata.parentEntityMetadata.treeType
642
                entityMetadata.treeOptions =
12✔
643
                    entityMetadata.parentEntityMetadata.treeOptions
644
                entityMetadata.treeParentRelation =
12✔
645
                    entityMetadata.parentEntityMetadata.treeParentRelation
646
                entityMetadata.treeLevelColumn =
12✔
647
                    entityMetadata.parentEntityMetadata.treeLevelColumn
648
            }
649
        }
650

651
        const { namingStrategy } = this.connection
6,726✔
652

653
        // check if tree is used then we need to add extra columns for specific tree types
654
        if (entityMetadata.treeType === "materialized-path") {
6,726✔
655
            entityMetadata.ownColumns.push(
51✔
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") {
6,675✔
674
            const { left, right } = namingStrategy.nestedSetColumnNames
16✔
675
            entityMetadata.ownColumns.push(
16✔
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(
16✔
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
6,726✔
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") {
4,613✔
718
                    const parentRelation =
719
                        entityMetadata.parentEntityMetadata.ownRelations.find(
133✔
720
                            (relation) =>
721
                                relation.propertyName === args.propertyName,
199✔
722
                        )!
723
                    const type =
724
                        typeof args.type === "function"
133!
725
                            ? (args.type as () => any)()
726
                            : args.type
727
                    if (parentRelation.type !== type) {
133✔
728
                        const clone = Object.create(parentRelation)
12✔
729
                        clone.type = type
12✔
730
                        return clone
12✔
731
                    }
732

733
                    return parentRelation
121✔
734
                }
735

736
                return new RelationMetadata({ entityMetadata, args })
4,480✔
737
            })
738
        entityMetadata.relationIds = this.metadataArgsStorage
6,726✔
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")
205!
743
                    return entityMetadata.parentEntityMetadata.relationIds.find(
×
744
                        (relationId) =>
745
                            relationId.propertyName === args.propertyName,
×
746
                    )!
747

748
                return new RelationIdMetadata({ entityMetadata, args })
205✔
749
            })
750
        entityMetadata.relationCounts = this.metadataArgsStorage
6,726✔
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")
78!
755
                    return entityMetadata.parentEntityMetadata.relationCounts.find(
×
756
                        (relationCount) =>
757
                            relationCount.propertyName === args.propertyName,
×
758
                    )!
759

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

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

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

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

815
        // This drivers stores unique constraints as unique indices.
816
        if (
6,726✔
817
            DriverUtils.isMySQLFamily(this.connection.driver) ||
26,616✔
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
96✔
823
                .filterUniques(entityMetadata.inheritanceTree)
824
                .map((args) => {
UNCOV
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)
96✔
837
        } else {
838
            const uniques = this.metadataArgsStorage
6,630✔
839
                .filterUniques(entityMetadata.inheritanceTree)
840
                .map((args) => {
841
                    return new UniqueMetadata({ entityMetadata, args })
784✔
842
                })
843
            entityMetadata.ownUniques.push(...uniques)
6,630✔
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) => {
7,389✔
856
            const embeddedMetadata = new EmbeddedMetadata({
663✔
857
                entityMetadata: entityMetadata,
858
                args: embeddedArgs,
859
            })
860
            const targets: any[] =
861
                typeof embeddedMetadata.type === "function"
663✔
862
                    ? MetadataUtils.getInheritanceTree(embeddedMetadata.type)
863
                    : [embeddedMetadata.type] // todo: implement later here inheritance for string-targets
864

865
            embeddedMetadata.columns = this.metadataArgsStorage
663✔
866
                .filterColumns(targets)
867
                .map((args) => {
868
                    return new ColumnMetadata({
1,607✔
869
                        connection: this.connection,
870
                        entityMetadata,
871
                        embeddedMetadata,
872
                        args,
873
                    })
874
                })
875
            embeddedMetadata.relations = this.metadataArgsStorage
663✔
876
                .filterRelations(targets)
877
                .map((args) => {
878
                    return new RelationMetadata({
229✔
879
                        entityMetadata,
880
                        embeddedMetadata,
881
                        args,
882
                    })
883
                })
884
            embeddedMetadata.listeners = this.metadataArgsStorage
663✔
885
                .filterListeners(targets)
886
                .map((args) => {
887
                    return new EntityListenerMetadata({
22✔
888
                        entityMetadata,
889
                        embeddedMetadata,
890
                        args,
891
                    })
892
                })
893
            embeddedMetadata.indices = this.metadataArgsStorage
663✔
894
                .filterIndices(targets)
895
                .map((args) => {
896
                    return new IndexMetadata({
36✔
897
                        entityMetadata,
898
                        embeddedMetadata,
899
                        args,
900
                    })
901
                })
902
            embeddedMetadata.uniques = this.metadataArgsStorage
663✔
903
                .filterUniques(targets)
904
                .map((args) => {
905
                    return new UniqueMetadata({
7✔
906
                        entityMetadata,
907
                        embeddedMetadata,
908
                        args,
909
                    })
910
                })
911
            embeddedMetadata.relationIds = this.metadataArgsStorage
663✔
912
                .filterRelationIds(targets)
913
                .map((args) => {
914
                    return new RelationIdMetadata({ entityMetadata, args })
×
915
                })
916
            embeddedMetadata.relationCounts = this.metadataArgsStorage
663✔
917
                .filterRelationCounts(targets)
918
                .map((args) => {
919
                    return new RelationCountMetadata({ entityMetadata, args })
×
920
                })
921
            embeddedMetadata.embeddeds = this.createEmbeddedsRecursively(
663✔
922
                entityMetadata,
923
                this.metadataArgsStorage.filterEmbeddeds(targets),
924
            )
925
            embeddedMetadata.embeddeds.forEach(
663✔
926
                (subEmbedded) =>
927
                    (subEmbedded.parentEmbeddedMetadata = embeddedMetadata),
233✔
928
            )
929
            entityMetadata.allEmbeddeds.push(embeddedMetadata)
663✔
930
            return embeddedMetadata
663✔
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) =>
12,483✔
939
            embedded.build(this.connection),
698✔
940
        )
941
        entityMetadata.embeddeds.forEach((embedded) => {
12,483✔
942
            embedded.columnsFromTree.forEach((column) =>
698✔
943
                column.build(this.connection),
2,542✔
944
            )
945
            embedded.relationsFromTree.forEach((relation) => relation.build())
698✔
946
        })
947
        entityMetadata.ownColumns.forEach((column) =>
12,483✔
948
            column.build(this.connection),
35,041✔
949
        )
950
        entityMetadata.ownRelations.forEach((relation) => relation.build())
12,483✔
951
        entityMetadata.relations = entityMetadata.embeddeds.reduce(
12,483✔
952
            (relations, embedded) =>
953
                relations.concat(embedded.relationsFromTree),
698✔
954
            entityMetadata.ownRelations,
955
        )
956
        entityMetadata.eagerRelations = entityMetadata.relations.filter(
12,483✔
957
            (relation) => relation.isEager,
9,558✔
958
        )
959
        entityMetadata.lazyRelations = entityMetadata.relations.filter(
12,483✔
960
            (relation) => relation.isLazy,
9,558✔
961
        )
962
        entityMetadata.oneToOneRelations = entityMetadata.relations.filter(
12,483✔
963
            (relation) => relation.isOneToOne,
9,558✔
964
        )
965
        entityMetadata.oneToManyRelations = entityMetadata.relations.filter(
12,483✔
966
            (relation) => relation.isOneToMany,
9,558✔
967
        )
968
        entityMetadata.manyToOneRelations = entityMetadata.relations.filter(
12,483✔
969
            (relation) => relation.isManyToOne,
9,558✔
970
        )
971
        entityMetadata.manyToManyRelations = entityMetadata.relations.filter(
12,483✔
972
            (relation) => relation.isManyToMany,
9,558✔
973
        )
974
        entityMetadata.ownerOneToOneRelations = entityMetadata.relations.filter(
12,483✔
975
            (relation) => relation.isOneToOneOwner,
9,558✔
976
        )
977
        entityMetadata.ownerManyToManyRelations =
12,483✔
978
            entityMetadata.relations.filter(
979
                (relation) => relation.isManyToManyOwner,
9,558✔
980
            )
981
        entityMetadata.treeParentRelation = entityMetadata.relations.find(
12,483✔
982
            (relation) => relation.isTreeParent,
9,188✔
983
        )
984
        entityMetadata.treeChildrenRelation = entityMetadata.relations.find(
12,483✔
985
            (relation) => relation.isTreeChildren,
9,436✔
986
        )
987
        entityMetadata.columns = entityMetadata.embeddeds.reduce(
12,483✔
988
            (columns, embedded) => columns.concat(embedded.columnsFromTree),
698✔
989
            entityMetadata.ownColumns,
990
        )
991
        entityMetadata.listeners = entityMetadata.embeddeds.reduce(
12,483✔
992
            (listeners, embedded) =>
993
                listeners.concat(embedded.listenersFromTree),
698✔
994
            entityMetadata.ownListeners,
995
        )
996
        entityMetadata.afterLoadListeners = entityMetadata.listeners.filter(
12,483✔
997
            (listener) => listener.type === EventListenerTypes.AFTER_LOAD,
176✔
998
        )
999
        entityMetadata.afterInsertListeners = entityMetadata.listeners.filter(
12,483✔
1000
            (listener) => listener.type === EventListenerTypes.AFTER_INSERT,
176✔
1001
        )
1002
        entityMetadata.afterUpdateListeners = entityMetadata.listeners.filter(
12,483✔
1003
            (listener) => listener.type === EventListenerTypes.AFTER_UPDATE,
176✔
1004
        )
1005
        entityMetadata.afterRemoveListeners = entityMetadata.listeners.filter(
12,483✔
1006
            (listener) => listener.type === EventListenerTypes.AFTER_REMOVE,
176✔
1007
        )
1008
        entityMetadata.afterSoftRemoveListeners =
12,483✔
1009
            entityMetadata.listeners.filter(
1010
                (listener) =>
1011
                    listener.type === EventListenerTypes.AFTER_SOFT_REMOVE,
176✔
1012
            )
1013
        entityMetadata.afterRecoverListeners = entityMetadata.listeners.filter(
12,483✔
1014
            (listener) => listener.type === EventListenerTypes.AFTER_RECOVER,
176✔
1015
        )
1016
        entityMetadata.beforeInsertListeners = entityMetadata.listeners.filter(
12,483✔
1017
            (listener) => listener.type === EventListenerTypes.BEFORE_INSERT,
176✔
1018
        )
1019
        entityMetadata.beforeUpdateListeners = entityMetadata.listeners.filter(
12,483✔
1020
            (listener) => listener.type === EventListenerTypes.BEFORE_UPDATE,
176✔
1021
        )
1022
        entityMetadata.beforeRemoveListeners = entityMetadata.listeners.filter(
12,483✔
1023
            (listener) => listener.type === EventListenerTypes.BEFORE_REMOVE,
176✔
1024
        )
1025
        entityMetadata.beforeSoftRemoveListeners =
12,483✔
1026
            entityMetadata.listeners.filter(
1027
                (listener) =>
1028
                    listener.type === EventListenerTypes.BEFORE_SOFT_REMOVE,
176✔
1029
            )
1030
        entityMetadata.beforeRecoverListeners = entityMetadata.listeners.filter(
12,483✔
1031
            (listener) => listener.type === EventListenerTypes.BEFORE_RECOVER,
176✔
1032
        )
1033
        entityMetadata.indices = entityMetadata.embeddeds.reduce(
12,483✔
1034
            (indices, embedded) => indices.concat(embedded.indicesFromTree),
698✔
1035
            entityMetadata.ownIndices,
1036
        )
1037
        entityMetadata.uniques = entityMetadata.embeddeds.reduce(
12,483✔
1038
            (uniques, embedded) => uniques.concat(embedded.uniquesFromTree),
698✔
1039
            entityMetadata.ownUniques,
1040
        )
1041
        entityMetadata.primaryColumns = entityMetadata.columns.filter(
12,483✔
1042
            (column) => column.isPrimary,
37,583✔
1043
        )
1044
        entityMetadata.nonVirtualColumns = entityMetadata.columns.filter(
12,483✔
1045
            (column) => !column.isVirtual,
37,583✔
1046
        )
1047
        entityMetadata.ancestorColumns = entityMetadata.columns.filter(
12,483✔
1048
            (column) => column.closureType === "ancestor",
37,583✔
1049
        )
1050
        entityMetadata.descendantColumns = entityMetadata.columns.filter(
12,483✔
1051
            (column) => column.closureType === "descendant",
37,583✔
1052
        )
1053
        entityMetadata.hasMultiplePrimaryKeys =
12,483✔
1054
            entityMetadata.primaryColumns.length > 1
1055
        entityMetadata.generatedColumns = entityMetadata.columns.filter(
12,483✔
1056
            (column) => column.isGenerated || column.isObjectId,
37,583✔
1057
        )
1058
        entityMetadata.hasUUIDGeneratedColumns =
12,483✔
1059
            entityMetadata.columns.filter(
1060
                (column) =>
1061
                    column.isGenerated || column.generationStrategy === "uuid",
37,583✔
1062
            ).length > 0
1063
        entityMetadata.createDateColumn = entityMetadata.columns.find(
12,483✔
1064
            (column) => column.isCreateDate,
36,622✔
1065
        )
1066
        entityMetadata.updateDateColumn = entityMetadata.columns.find(
12,483✔
1067
            (column) => column.isUpdateDate,
36,939✔
1068
        )
1069
        entityMetadata.deleteDateColumn = entityMetadata.columns.find(
12,483✔
1070
            (column) => column.isDeleteDate,
37,277✔
1071
        )
1072
        entityMetadata.versionColumn = entityMetadata.columns.find(
12,483✔
1073
            (column) => column.isVersion,
37,522✔
1074
        )
1075
        entityMetadata.discriminatorColumn = entityMetadata.columns.find(
12,483✔
1076
            (column) => column.isDiscriminator,
36,861✔
1077
        )
1078
        entityMetadata.treeLevelColumn = entityMetadata.columns.find(
12,483✔
1079
            (column) => column.isTreeLevel,
37,543✔
1080
        )
1081
        entityMetadata.nestedSetLeftColumn = entityMetadata.columns.find(
12,483✔
1082
            (column) => column.isNestedSetLeft,
37,528✔
1083
        )
1084
        entityMetadata.nestedSetRightColumn = entityMetadata.columns.find(
12,483✔
1085
            (column) => column.isNestedSetRight,
37,561✔
1086
        )
1087
        entityMetadata.materializedPathColumn = entityMetadata.columns.find(
12,483✔
1088
            (column) => column.isMaterializedPath,
37,526✔
1089
        )
1090
        entityMetadata.objectIdColumn = entityMetadata.columns.find(
12,483✔
1091
            (column) => column.isObjectId,
37,583✔
1092
        )
1093
        entityMetadata.foreignKeys.forEach((foreignKey) =>
12,483✔
1094
            foreignKey.build(this.connection.namingStrategy),
4,139✔
1095
        )
1096
        entityMetadata.propertiesMap = entityMetadata.createPropertiesMap()
12,483✔
1097
        entityMetadata.relationIds.forEach((relationId) => relationId.build())
12,483✔
1098
        entityMetadata.relationCounts.forEach((relationCount) =>
12,483✔
1099
            relationCount.build(),
90✔
1100
        )
1101
        entityMetadata.embeddeds.forEach((embedded) => {
12,483✔
1102
            embedded.relationIdsFromTree.forEach((relationId) =>
698✔
1103
                relationId.build(),
×
1104
            )
1105
            embedded.relationCountsFromTree.forEach((relationCount) =>
698✔
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) => {
7,520✔
1119
            // compute inverse side (related) entity metadatas for all relation metadatas
1120
            const inverseEntityMetadata = entityMetadatas.find(
4,842✔
1121
                (m) =>
1122
                    m.target === relation.type ||
11,486✔
1123
                    (typeof relation.type === "string" &&
1124
                        (m.targetName === relation.type ||
1125
                            m.givenTableName === relation.type)),
1126
            )
1127
            if (!inverseEntityMetadata)
4,842!
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
4,842✔
1137
            relation.inverseSidePropertyPath =
4,842✔
1138
                relation.buildInverseSidePropertyPath()
1139

1140
            // and compute inverse relation and mark if it has such
1141
            relation.inverseRelation = inverseEntityMetadata.relations.find(
4,842✔
1142
                (foundRelation) =>
1143
                    foundRelation.propertyPath ===
5,897✔
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(
459✔
1154
            ({ givenColumnNames }) =>
1155
                !!givenColumnNames &&
16✔
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) {
459✔
1165
            return
16✔
1166
        }
1167

1168
        entityMetadata.indices.push(
443✔
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
7,520✔
1188
            .filterForeignKeys(entityMetadata.inheritanceTree)
1189
            .forEach((foreignKeyArgs) => {
1190
                const foreignKeyType =
1191
                    typeof foreignKeyArgs.type === "function"
60✔
1192
                        ? (foreignKeyArgs.type as () => any)()
1193
                        : foreignKeyArgs.type
1194

1195
                const referencedEntityMetadata = entityMetadatas.find((m) =>
60✔
1196
                    typeof foreignKeyType === "string"
150✔
1197
                        ? m.targetName === foreignKeyType ||
132✔
1198
                          m.givenTableName === foreignKeyType
1199
                        : InstanceChecker.isEntitySchema(foreignKeyType)
78✔
1200
                        ? m.target === foreignKeyType.options.name ||
102✔
1201
                          m.target === foreignKeyType.options.target
1202
                        : m.target === foreignKeyType,
1203
                )
1204

1205
                if (!referencedEntityMetadata) {
60!
UNCOV
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 ?? []
60✔
1217
                const referencedColumnNames =
1218
                    foreignKeyArgs.referencedColumnNames ?? []
60✔
1219

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

1223
                if (foreignKeyArgs.propertyName) {
60✔
1224
                    columnNames.push(foreignKeyArgs.propertyName)
48✔
1225

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

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

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

1257
                    if (column) return column
120✔
1258

UNCOV
1259
                    const foreignKeyName = foreignKeyArgs.name
×
1260
                        ? '"' + foreignKeyArgs.name + '" '
1261
                        : ""
UNCOV
1262
                    const entityName = entityMetadata.targetName
×
UNCOV
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(
60✔
1269
                    ...columnNames.map((columnName) =>
1270
                        columnNameToColumn(columnName, entityMetadata),
72✔
1271
                    ),
1272
                )
1273

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

1283
                entityMetadata.foreignKeys.push(
60✔
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