• 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

65.22
/src/metadata/UniqueMetadata.ts
1
import { EmbeddedMetadata } from "./EmbeddedMetadata"
2
import { EntityMetadata } from "./EntityMetadata"
3
import { NamingStrategyInterface } from "../naming-strategy/NamingStrategyInterface"
4
import { ColumnMetadata } from "./ColumnMetadata"
5
import { UniqueMetadataArgs } from "../metadata-args/UniqueMetadataArgs"
6
import { TypeORMError } from "../error"
4✔
7
import { DeferrableType } from "./types/DeferrableType"
8

9
/**
10
 * Unique metadata contains all information about table's unique constraints.
11
 */
12
export class UniqueMetadata {
4✔
13
    // ---------------------------------------------------------------------
14
    // Public Properties
15
    // ---------------------------------------------------------------------
16

17
    /**
18
     * Entity metadata of the class to which this unique constraint is applied.
19
     */
20
    entityMetadata: EntityMetadata
21

22
    /**
23
     * Embedded metadata if this unique was applied on embedded.
24
     */
25
    embeddedMetadata?: EmbeddedMetadata
26

27
    /**
28
     * Target class to which metadata is applied.
29
     */
30
    target?: Function | string
31

32
    /**
33
     * Unique columns.
34
     */
35
    columns: ColumnMetadata[] = []
831✔
36

37
    /**
38
     * Indicate if unique constraints can be deferred.
39
     */
40
    deferrable?: DeferrableType
41

42
    /**
43
     * User specified unique constraint name.
44
     */
45
    givenName?: string
46

47
    /**
48
     * User specified column names.
49
     */
50
    givenColumnNames?:
51
        | ((object?: any) => any[] | { [key: string]: number })
52
        | string[]
53

54
    /**
55
     * Final unique constraint name.
56
     * If unique constraint name was given by a user then it stores normalized (by naming strategy) givenName.
57
     * If unique constraint name was not given then its generated.
58
     */
59
    name: string
60

61
    /**
62
     * Map of column names with order set.
63
     * Used only by MongoDB driver.
64
     */
65
    columnNamesWithOrderingMap: { [key: string]: number } = {}
831✔
66

67
    // ---------------------------------------------------------------------
68
    // Constructor
69
    // ---------------------------------------------------------------------
70

71
    constructor(options: {
72
        entityMetadata: EntityMetadata
73
        embeddedMetadata?: EmbeddedMetadata
74
        columns?: ColumnMetadata[]
75
        args?: UniqueMetadataArgs
76
    }) {
77
        this.entityMetadata = options.entityMetadata
831✔
78
        this.embeddedMetadata = options.embeddedMetadata
831✔
79
        if (options.columns) this.columns = options.columns
831✔
80

81
        if (options.args) {
831✔
82
            this.target = options.args.target
831✔
83
            this.givenName = options.args.name
831✔
84
            this.givenColumnNames = options.args.columns
831✔
85
            this.deferrable = options.args.deferrable
831✔
86
        }
87
    }
88

89
    // ---------------------------------------------------------------------
90
    // Public Build Methods
91
    // ---------------------------------------------------------------------
92

93
    /**
94
     * Builds some depend unique constraint properties.
95
     * Must be called after all entity metadata's properties map, columns and relations are built.
96
     */
97
    build(namingStrategy: NamingStrategyInterface): this {
98
        const map: { [key: string]: number } = {}
1,120✔
99

100
        // if columns already an array of string then simply return it
101
        if (this.givenColumnNames) {
1,120✔
102
            let columnPropertyPaths: string[] = []
510✔
103
            if (Array.isArray(this.givenColumnNames)) {
510!
104
                columnPropertyPaths = this.givenColumnNames.map(
510✔
105
                    (columnName) => {
106
                        if (this.embeddedMetadata)
662✔
107
                            return (
4✔
108
                                this.embeddedMetadata.propertyPath +
109
                                "." +
110
                                columnName
111
                            )
112

113
                        return columnName.trim()
658✔
114
                    },
115
                )
116
                columnPropertyPaths.forEach(
510✔
117
                    (propertyPath) => (map[propertyPath] = 1),
662✔
118
                )
119
            } else {
120
                // if columns is a function that returns array of field names then execute it and get columns names from it
121
                const columnsFnResult = this.givenColumnNames(
×
122
                    this.entityMetadata.propertiesMap,
123
                )
124
                if (Array.isArray(columnsFnResult)) {
×
125
                    columnPropertyPaths = columnsFnResult.map((i: any) =>
×
126
                        String(i),
×
127
                    )
128
                    columnPropertyPaths.forEach((name) => (map[name] = 1))
×
129
                } else {
130
                    columnPropertyPaths = Object.keys(columnsFnResult).map(
×
131
                        (i: any) => String(i),
×
132
                    )
133
                    Object.keys(columnsFnResult).forEach(
×
134
                        (columnName) =>
135
                            (map[columnName] = columnsFnResult[columnName]),
×
136
                    )
137
                }
138
            }
139

140
            this.columns = columnPropertyPaths
510✔
141
                .map((propertyName) => {
142
                    const columnWithSameName = this.entityMetadata.columns.find(
662✔
143
                        (column) => column.propertyPath === propertyName,
2,077✔
144
                    )
145
                    if (columnWithSameName) {
662✔
146
                        return [columnWithSameName]
662✔
147
                    }
148
                    const relationWithSameName =
149
                        this.entityMetadata.relations.find(
×
150
                            (relation) =>
151
                                relation.isWithJoinColumn &&
×
152
                                relation.propertyName === propertyName,
153
                        )
154
                    if (relationWithSameName) {
×
155
                        return relationWithSameName.joinColumns
×
156
                    }
157
                    const indexName = this.givenName
×
158
                        ? '"' + this.givenName + '" '
159
                        : ""
160
                    const entityName = this.entityMetadata.targetName
×
161
                    throw new TypeORMError(
×
162
                        `Unique constraint ${indexName}contains column that is missing in the entity (${entityName}): ` +
163
                            propertyName,
164
                    )
165
                })
166
                .reduce((a, b) => a.concat(b))
152✔
167
        }
168

169
        this.columnNamesWithOrderingMap = Object.keys(map).reduce(
1,120✔
170
            (updatedMap, key) => {
171
                const column = this.entityMetadata.columns.find(
662✔
172
                    (column) => column.propertyPath === key,
2,077✔
173
                )
174
                if (column) updatedMap[column.databasePath] = map[key]
662✔
175

176
                return updatedMap
662✔
177
            },
178
            {} as { [key: string]: number },
179
        )
180

181
        this.name = this.givenName
1,120✔
182
            ? this.givenName
183
            : namingStrategy.uniqueConstraintName(
184
                  this.entityMetadata.tableName,
185
                  this.columns.map((column) => column.databaseName),
638✔
186
              )
187
        return this
1,120✔
188
    }
189
}
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