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

typeorm / typeorm / 15219332477

23 May 2025 09:13PM UTC coverage: 17.216% (-59.1%) from 76.346%
15219332477

Pull #11332

github

naorpeled
cr comments - move if block
Pull Request #11332: feat: add new undefined and null behavior flags

1603 of 12759 branches covered (12.56%)

Branch coverage included in aggregate %.

0 of 31 new or added lines in 3 files covered. (0.0%)

14132 existing lines in 166 files now uncovered.

4731 of 24033 relevant lines covered (19.69%)

60.22 hits per line

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

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

12
/**
13
 * Table in the database represented in this class.
14
 */
15
export class Table {
1✔
UNCOV
16
    readonly "@instanceof" = Symbol.for("Table")
×
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
     */
UNCOV
42
    columns: TableColumn[] = []
×
43

44
    /**
45
     * Table indices.
46
     */
UNCOV
47
    indices: TableIndex[] = []
×
48

49
    /**
50
     * Table foreign keys.
51
     */
UNCOV
52
    foreignKeys: TableForeignKey[] = []
×
53

54
    /**
55
     * Table unique constraints.
56
     */
UNCOV
57
    uniques: TableUnique[] = []
×
58

59
    /**
60
     * Table check constraints.
61
     */
UNCOV
62
    checks: TableCheck[] = []
×
63

64
    /**
65
     * Table exclusion constraints.
66
     */
UNCOV
67
    exclusions: TableExclusion[] = []
×
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
     */
UNCOV
74
    justCreated: boolean = false
×
75

76
    /**
77
     * Enables Sqlite "WITHOUT ROWID" modifier for the "CREATE TABLE" statement
78
     */
UNCOV
79
    withoutRowid?: boolean = false
×
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) {
UNCOV
96
        if (options) {
×
UNCOV
97
            this.database = options.database
×
UNCOV
98
            this.schema = options.schema
×
UNCOV
99
            this.name = options.name
×
100

UNCOV
101
            if (options.columns)
×
UNCOV
102
                this.columns = options.columns.map(
×
UNCOV
103
                    (column) => new TableColumn(column),
×
104
                )
105

UNCOV
106
            if (options.indices)
×
UNCOV
107
                this.indices = options.indices.map(
×
UNCOV
108
                    (index) => new TableIndex(index),
×
109
                )
110

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

UNCOV
124
            if (options.uniques)
×
UNCOV
125
                this.uniques = options.uniques.map(
×
UNCOV
126
                    (unique) => new TableUnique(unique),
×
127
                )
128

UNCOV
129
            if (options.checks)
×
UNCOV
130
                this.checks = options.checks.map(
×
UNCOV
131
                    (check) => new TableCheck(check),
×
132
                )
133

UNCOV
134
            if (options.exclusions)
×
UNCOV
135
                this.exclusions = options.exclusions.map(
×
UNCOV
136
                    (exclusion) => new TableExclusion(exclusion),
×
137
                )
138

UNCOV
139
            if (options.justCreated !== undefined)
×
UNCOV
140
                this.justCreated = options.justCreated
×
141

UNCOV
142
            if (options.withoutRowid) this.withoutRowid = options.withoutRowid
×
143

UNCOV
144
            this.engine = options.engine
×
145

UNCOV
146
            this.comment = options.comment
×
147
        }
148
    }
149

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

154
    get primaryColumns(): TableColumn[] {
UNCOV
155
        return this.columns.filter((column) => column.isPrimary)
×
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 {
UNCOV
166
        return new Table({
×
167
            schema: this.schema,
168
            database: this.database,
169
            name: this.name,
UNCOV
170
            columns: this.columns.map((column) => column.clone()),
×
UNCOV
171
            indices: this.indices.map((constraint) => constraint.clone()),
×
172
            foreignKeys: this.foreignKeys.map((constraint) =>
UNCOV
173
                constraint.clone(),
×
174
            ),
UNCOV
175
            uniques: this.uniques.map((constraint) => constraint.clone()),
×
UNCOV
176
            checks: this.checks.map((constraint) => constraint.clone()),
×
UNCOV
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 {
UNCOV
189
        this.columns.push(column)
×
190
    }
191

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

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

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

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

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

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

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

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

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

287
    /**
288
     * Adds index.
289
     */
290
    addIndex(index: TableIndex, isMysql: boolean = false): void {
×
UNCOV
291
        this.indices.push(index)
×
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
UNCOV
295
        if (index.columnNames.length === 1 && index.isUnique && isMysql) {
×
UNCOV
296
            const column = this.columns.find(
×
UNCOV
297
                (c) => c.name === index.columnNames[0],
×
298
            )
UNCOV
299
            if (column) column.isUnique = true
×
300
        }
301
    }
302

303
    /**
304
     * Removes index.
305
     */
306
    removeIndex(tableIndex: TableIndex, isMysql: boolean = false): void {
×
UNCOV
307
        const index = this.indices.find(
×
UNCOV
308
            (index) => index.name === tableIndex.name,
×
309
        )
UNCOV
310
        if (index) {
×
UNCOV
311
            this.indices.splice(this.indices.indexOf(index), 1)
×
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
UNCOV
315
            if (index.columnNames.length === 1 && index.isUnique && isMysql) {
×
UNCOV
316
                const column = this.columns.find(
×
UNCOV
317
                    (c) => c.name === index.columnNames[0],
×
318
                )
UNCOV
319
                if (column)
×
UNCOV
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 {
UNCOV
331
        return this.columns.find((column) => column.name === name)
×
332
    }
333

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

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

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

367
    /**
368
     * Returns all column checks.
369
     */
370
    findColumnChecks(column: TableColumn): TableCheck[] {
UNCOV
371
        return this.checks.filter((check) => {
×
UNCOV
372
            return !!check.columnNames!.find(
×
UNCOV
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 =
UNCOV
387
            entityMetadata.database === driver.database
×
388
                ? undefined
389
                : entityMetadata.database
390
        const schema =
UNCOV
391
            entityMetadata.schema === (driver.options as any).schema
×
392
                ? undefined
393
                : entityMetadata.schema
394

UNCOV
395
        const options: TableOptions = {
×
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
UNCOV
406
                .filter((column) => column && !column.isVirtualProperty)
×
407
                .map((column) =>
UNCOV
408
                    TableUtils.createTableColumnOptions(column, driver),
×
409
                ),
410
            indices: entityMetadata.indices
UNCOV
411
                .filter((index) => index.synchronize === true)
×
UNCOV
412
                .map((index) => TableIndex.create(index)),
×
413
            uniques: entityMetadata.uniques.map((unique) =>
UNCOV
414
                TableUnique.create(unique),
×
415
            ),
416
            checks: entityMetadata.checks.map((check) =>
UNCOV
417
                TableCheck.create(check),
×
418
            ),
419
            exclusions: entityMetadata.exclusions.map((exclusion) =>
UNCOV
420
                TableExclusion.create(exclusion),
×
421
            ),
422
            comment: entityMetadata.comment,
423
        }
424

UNCOV
425
        return new Table(options)
×
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