• 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

83.13
/src/schema-builder/table/Table.ts
1
import { TableColumn } from "./TableColumn"
4✔
2
import { TableIndex } from "./TableIndex"
4✔
3
import { TableForeignKey } from "./TableForeignKey"
4✔
4
import { Driver } from "../../driver/Driver"
5
import { TableOptions } from "../options/TableOptions"
6
import { EntityMetadata } from "../../metadata/EntityMetadata"
7
import { TableUtils } from "../util/TableUtils"
4✔
8
import { TableUnique } from "./TableUnique"
4✔
9
import { TableCheck } from "./TableCheck"
4✔
10
import { TableExclusion } from "./TableExclusion"
4✔
11

12
/**
13
 * Table in the database represented in this class.
14
 */
15
export class Table {
4✔
16
    readonly "@instanceof" = Symbol.for("Table")
24,277✔
17

18
    // -------------------------------------------------------------------------
19
    // Public Properties
20
    // -------------------------------------------------------------------------
21

22
    /**
23
     * Database name that this table resides in if it applies.
24
     */
25
    database?: string
26

27
    /**
28
     * Schema name that this table resides in if it applies.
29
     */
30
    schema?: string
31

32
    /**
33
     * May contain database name, schema name and table name, unless they're the current database.
34
     *
35
     * E.g. myDB.mySchema.myTable
36
     */
37
    name: string
38

39
    /**
40
     * Table columns.
41
     */
42
    columns: TableColumn[] = []
24,277✔
43

44
    /**
45
     * Table indices.
46
     */
47
    indices: TableIndex[] = []
24,277✔
48

49
    /**
50
     * Table foreign keys.
51
     */
52
    foreignKeys: TableForeignKey[] = []
24,277✔
53

54
    /**
55
     * Table unique constraints.
56
     */
57
    uniques: TableUnique[] = []
24,277✔
58

59
    /**
60
     * Table check constraints.
61
     */
62
    checks: TableCheck[] = []
24,277✔
63

64
    /**
65
     * Table exclusion constraints.
66
     */
67
    exclusions: TableExclusion[] = []
24,277✔
68

69
    /**
70
     * Indicates if table was just created.
71
     * This is needed, for example to check if we need to skip primary keys creation
72
     * for new tables.
73
     */
74
    justCreated: boolean = false
24,277✔
75

76
    /**
77
     * Enables Sqlite "WITHOUT ROWID" modifier for the "CREATE TABLE" statement
78
     */
79
    withoutRowid?: boolean = false
24,277✔
80

81
    /**
82
     * Table engine.
83
     */
84
    engine?: string
85

86
    /**
87
     * Table comment. Not supported by all database types.
88
     */
89
    comment?: string
90

91
    // -------------------------------------------------------------------------
92
    // Constructor
93
    // -------------------------------------------------------------------------
94

95
    constructor(options?: TableOptions) {
96
        if (options) {
24,277✔
97
            this.database = options.database
23,841✔
98
            this.schema = options.schema
23,841✔
99
            this.name = options.name
23,841✔
100

101
            if (options.columns)
23,841✔
102
                this.columns = options.columns.map(
22,635✔
103
                    (column) => new TableColumn(column),
72,531✔
104
                )
105

106
            if (options.indices)
23,841✔
107
                this.indices = options.indices.map(
22,458✔
108
                    (index) => new TableIndex(index),
10,613✔
109
                )
110

111
            if (options.foreignKeys)
23,841✔
112
                this.foreignKeys = options.foreignKeys.map(
5,233✔
113
                    (foreignKey) =>
114
                        new TableForeignKey({
161✔
115
                            ...foreignKey,
116
                            referencedDatabase:
117
                                foreignKey?.referencedDatabase ||
282✔
118
                                options.database,
119
                            referencedSchema:
120
                                foreignKey?.referencedSchema || options.schema,
282✔
121
                        }),
122
                )
123

124
            if (options.uniques)
23,841✔
125
                this.uniques = options.uniques.map(
22,447✔
126
                    (unique) => new TableUnique(unique),
5,044✔
127
                )
128

129
            if (options.checks)
23,841✔
130
                this.checks = options.checks.map(
22,443✔
131
                    (check) => new TableCheck(check),
434✔
132
                )
133

134
            if (options.exclusions)
23,841✔
135
                this.exclusions = options.exclusions.map(
22,439✔
136
                    (exclusion) => new TableExclusion(exclusion),
×
137
                )
138

139
            if (options.justCreated !== undefined)
23,841✔
140
                this.justCreated = options.justCreated
5,217✔
141

142
            if (options.withoutRowid) this.withoutRowid = options.withoutRowid
23,841✔
143

144
            this.engine = options.engine
23,841✔
145

146
            this.comment = options.comment
23,841✔
147
        }
148
    }
149

150
    // -------------------------------------------------------------------------
151
    // Accessors
152
    // -------------------------------------------------------------------------
153

154
    get primaryColumns(): TableColumn[] {
155
        return this.columns.filter((column) => column.isPrimary)
471✔
156
    }
157

158
    // -------------------------------------------------------------------------
159
    // Public Methods
160
    // -------------------------------------------------------------------------
161

162
    /**
163
     * Clones this table to a new table with all properties cloned.
164
     */
165
    clone(): Table {
166
        return new Table({
5,217✔
167
            schema: this.schema,
168
            database: this.database,
169
            name: this.name,
170
            columns: this.columns.map((column) => column.clone()),
18,330✔
171
            indices: this.indices.map((constraint) => constraint.clone()),
4,360✔
172
            foreignKeys: this.foreignKeys.map((constraint) =>
173
                constraint.clone(),
145✔
174
            ),
175
            uniques: this.uniques.map((constraint) => constraint.clone()),
1,753✔
176
            checks: this.checks.map((constraint) => constraint.clone()),
175✔
177
            exclusions: this.exclusions.map((constraint) => constraint.clone()),
×
178
            justCreated: this.justCreated,
179
            withoutRowid: this.withoutRowid,
180
            engine: this.engine,
181
            comment: this.comment,
182
        })
183
    }
184

185
    /**
186
     * Add column and creates its constraints.
187
     */
188
    addColumn(column: TableColumn): void {
189
        this.columns.push(column)
53✔
190
    }
191

192
    /**
193
     * Remove column and its constraints.
194
     */
195
    removeColumn(column: TableColumn): void {
196
        const foundColumn = this.columns.find((c) => c.name === column.name)
139✔
197
        if (foundColumn)
63✔
198
            this.columns.splice(this.columns.indexOf(foundColumn), 1)
63✔
199
    }
200

201
    /**
202
     * Adds unique constraint.
203
     */
204
    addUniqueConstraint(uniqueConstraint: TableUnique): void {
205
        this.uniques.push(uniqueConstraint)
12✔
206
        if (uniqueConstraint.columnNames.length === 1) {
12✔
207
            const uniqueColumn = this.columns.find(
3✔
208
                (column) => column.name === uniqueConstraint.columnNames[0],
6✔
209
            )
210
            if (uniqueColumn) uniqueColumn.isUnique = true
3✔
211
        }
212
    }
213

214
    /**
215
     * Removes unique constraint.
216
     */
217
    removeUniqueConstraint(removedUnique: TableUnique): void {
218
        const foundUnique = this.uniques.find(
18✔
219
            (unique) => unique.name === removedUnique.name,
25✔
220
        )
221
        if (foundUnique) {
18✔
222
            this.uniques.splice(this.uniques.indexOf(foundUnique), 1)
18✔
223
            if (foundUnique.columnNames.length === 1) {
18✔
224
                const uniqueColumn = this.columns.find(
6✔
225
                    (column) => column.name === foundUnique.columnNames[0],
12✔
226
                )
227
                if (uniqueColumn) uniqueColumn.isUnique = false
6!
228
            }
229
        }
230
    }
231

232
    /**
233
     * Adds check constraint.
234
     */
235
    addCheckConstraint(checkConstraint: TableCheck): void {
236
        this.checks.push(checkConstraint)
21✔
237
    }
238

239
    /**
240
     * Removes check constraint.
241
     */
242
    removeCheckConstraint(removedCheck: TableCheck): void {
243
        const foundCheck = this.checks.find(
14✔
244
            (check) => check.name === removedCheck.name,
14✔
245
        )
246
        if (foundCheck) {
14✔
247
            this.checks.splice(this.checks.indexOf(foundCheck), 1)
14✔
248
        }
249
    }
250

251
    /**
252
     * Adds exclusion constraint.
253
     */
254
    addExclusionConstraint(exclusionConstraint: TableExclusion): void {
255
        this.exclusions.push(exclusionConstraint)
×
256
    }
257

258
    /**
259
     * Removes exclusion constraint.
260
     */
261
    removeExclusionConstraint(removedExclusion: TableExclusion): void {
262
        const foundExclusion = this.exclusions.find(
×
263
            (exclusion) => exclusion.name === removedExclusion.name,
×
264
        )
265
        if (foundExclusion) {
×
266
            this.exclusions.splice(this.exclusions.indexOf(foundExclusion), 1)
×
267
        }
268
    }
269

270
    /**
271
     * Adds foreign keys.
272
     */
273
    addForeignKey(foreignKey: TableForeignKey): void {
274
        this.foreignKeys.push(foreignKey)
11,150✔
275
    }
276

277
    /**
278
     * Removes foreign key.
279
     */
280
    removeForeignKey(removedForeignKey: TableForeignKey): void {
281
        const fk = this.foreignKeys.find(
36✔
282
            (foreignKey) => foreignKey.name === removedForeignKey.name,
41✔
283
        )
284
        if (fk) this.foreignKeys.splice(this.foreignKeys.indexOf(fk), 1)
36✔
285
    }
286

287
    /**
288
     * Adds index.
289
     */
290
    addIndex(index: TableIndex, isMysql: boolean = false): void {
40✔
291
        this.indices.push(index)
40✔
292

293
        // in Mysql unique indices and unique constraints are the same thing
294
        // if index is unique and have only one column, we mark this column as unique
295
        if (index.columnNames.length === 1 && index.isUnique && isMysql) {
40!
296
            const column = this.columns.find(
×
297
                (c) => c.name === index.columnNames[0],
×
298
            )
299
            if (column) column.isUnique = true
×
300
        }
301
    }
302

303
    /**
304
     * Removes index.
305
     */
306
    removeIndex(tableIndex: TableIndex, isMysql: boolean = false): void {
44✔
307
        const index = this.indices.find(
44✔
308
            (index) => index.name === tableIndex.name,
44✔
309
        )
310
        if (index) {
44✔
311
            this.indices.splice(this.indices.indexOf(index), 1)
44✔
312

313
            // in Mysql unique indices and unique constraints are the same thing
314
            // if index is unique and have only one column, we move `unique` attribute from its column
315
            if (index.columnNames.length === 1 && index.isUnique && isMysql) {
44!
316
                const column = this.columns.find(
×
317
                    (c) => c.name === index.columnNames[0],
×
318
                )
319
                if (column)
×
320
                    column.isUnique = this.indices.some(
×
321
                        (ind) =>
322
                            ind.columnNames.length === 1 &&
×
323
                            ind.columnNames[0] === column.name &&
324
                            !!index.isUnique,
325
                    )
326
            }
327
        }
328
    }
329

330
    findColumnByName(name: string): TableColumn | undefined {
331
        return this.columns.find((column) => column.name === name)
4,012✔
332
    }
333

334
    /**
335
     * Returns all column indices.
336
     */
337
    findColumnIndices(column: TableColumn): TableIndex[] {
338
        return this.indices.filter((index) => {
119✔
339
            return !!index.columnNames.find(
52✔
340
                (columnName) => columnName === column.name,
52✔
341
            )
342
        })
343
    }
344

345
    /**
346
     * Returns all column foreign keys.
347
     */
348
    findColumnForeignKeys(column: TableColumn): TableForeignKey[] {
349
        return this.foreignKeys.filter((foreignKey) => {
119✔
350
            return !!foreignKey.columnNames.find(
74✔
351
                (columnName) => columnName === column.name,
74✔
352
            )
353
        })
354
    }
355

356
    /**
357
     * Returns all column uniques.
358
     */
359
    findColumnUniques(column: TableColumn): TableUnique[] {
360
        return this.uniques.filter((unique) => {
119✔
361
            return !!unique.columnNames.find(
116✔
362
                (columnName) => columnName === column.name,
146✔
363
            )
364
        })
365
    }
366

367
    /**
368
     * Returns all column checks.
369
     */
370
    findColumnChecks(column: TableColumn): TableCheck[] {
371
        return this.checks.filter((check) => {
×
372
            return !!check.columnNames!.find(
×
373
                (columnName) => columnName === column.name,
×
374
            )
375
        })
376
    }
377

378
    // -------------------------------------------------------------------------
379
    // Static Methods
380
    // -------------------------------------------------------------------------
381

382
    /**
383
     * Creates table from a given entity metadata.
384
     */
385
    static create(entityMetadata: EntityMetadata, driver: Driver): Table {
386
        const database =
387
            entityMetadata.database === driver.database
17,222✔
388
                ? undefined
389
                : entityMetadata.database
390
        const schema =
391
            entityMetadata.schema === (driver.options as any).schema
17,222✔
392
                ? undefined
393
                : entityMetadata.schema
394

395
        const options: TableOptions = {
17,222✔
396
            database: entityMetadata.database,
397
            schema: entityMetadata.schema,
398
            name: driver.buildTableName(
399
                entityMetadata.tableName,
400
                schema,
401
                database,
402
            ),
403
            withoutRowid: entityMetadata.withoutRowid,
404
            engine: entityMetadata.engine,
405
            columns: entityMetadata.columns
406
                .filter((column) => column && !column.isVirtualProperty)
53,351✔
407
                .map((column) =>
408
                    TableUtils.createTableColumnOptions(column, driver),
53,339✔
409
                ),
410
            indices: entityMetadata.indices
411
                .filter((index) => index.synchronize === true)
6,354✔
412
                .map((index) => TableIndex.create(index)),
6,234✔
413
            uniques: entityMetadata.uniques.map((unique) =>
414
                TableUnique.create(unique),
3,283✔
415
            ),
416
            checks: entityMetadata.checks.map((check) =>
417
                TableCheck.create(check),
255✔
418
            ),
419
            exclusions: entityMetadata.exclusions.map((exclusion) =>
420
                TableExclusion.create(exclusion),
×
421
            ),
422
            comment: entityMetadata.comment,
423
        }
424

425
        return new Table(options)
17,222✔
426
    }
427
}
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