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

typeorm / typeorm / 20153290793

12 Dec 2025 01:29AM UTC coverage: 80.807% (+0.04%) from 80.764%
20153290793

push

github

alumni
refactor(mysql)!: drop support for mysql package and default to mysql2 (#11766)

Co-authored-by: Lucian Mocanu <alumni@users.noreply.github.com>

26912 of 32666 branches covered (82.39%)

Branch coverage included in aggregate %.

13 of 15 new or added lines in 2 files covered. (86.67%)

694 existing lines in 23 files now uncovered.

91350 of 113685 relevant lines covered (80.35%)

68942.63 hits per line

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

91.05
/src/driver/oracle/OracleQueryRunner.ts
1
import { ObjectLiteral } from "../../common/ObjectLiteral"
26✔
2
import { TypeORMError } from "../../error"
26✔
3
import { QueryFailedError } from "../../error/QueryFailedError"
26✔
4
import { QueryRunnerAlreadyReleasedError } from "../../error/QueryRunnerAlreadyReleasedError"
26✔
5
import { TransactionNotStartedError } from "../../error/TransactionNotStartedError"
26✔
6
import { ReadStream } from "../../platform/PlatformTools"
26✔
7
import { BaseQueryRunner } from "../../query-runner/BaseQueryRunner"
26✔
8
import { QueryResult } from "../../query-runner/QueryResult"
26✔
9
import { QueryRunner } from "../../query-runner/QueryRunner"
26✔
10
import { Table } from "../../schema-builder/table/Table"
26✔
11
import { TableCheck } from "../../schema-builder/table/TableCheck"
26✔
12
import { TableColumn } from "../../schema-builder/table/TableColumn"
26✔
13
import { TableExclusion } from "../../schema-builder/table/TableExclusion"
26✔
14
import { TableForeignKey } from "../../schema-builder/table/TableForeignKey"
26✔
15
import { TableIndex } from "../../schema-builder/table/TableIndex"
26✔
16
import { TableUnique } from "../../schema-builder/table/TableUnique"
26✔
17
import { View } from "../../schema-builder/view/View"
26✔
18
import { Broadcaster } from "../../subscriber/Broadcaster"
26✔
19
import { BroadcasterResult } from "../../subscriber/BroadcasterResult"
26✔
20
import { InstanceChecker } from "../../util/InstanceChecker"
26✔
21
import { OrmUtils } from "../../util/OrmUtils"
26✔
22
import { Query } from "../Query"
26✔
23
import { ColumnType } from "../types/ColumnTypes"
26✔
24
import { IsolationLevel } from "../types/IsolationLevel"
26✔
25
import { MetadataTableType } from "../types/MetadataTableType"
26✔
26
import { ReplicationMode } from "../types/ReplicationMode"
26✔
27
import { OracleDriver } from "./OracleDriver"
26✔
28

26✔
29
/**
26✔
30
 * Runs queries on a single oracle database connection.
26✔
31
 */
26✔
32
export class OracleQueryRunner extends BaseQueryRunner implements QueryRunner {
26✔
33
    // -------------------------------------------------------------------------
26✔
34
    // Public Implemented Properties
26✔
35
    // -------------------------------------------------------------------------
26✔
36

26✔
37
    /**
26✔
38
     * Database driver used by connection.
26✔
39
     */
26✔
40
    driver: OracleDriver
26✔
41

26✔
42
    // -------------------------------------------------------------------------
26✔
43
    // Protected Properties
26✔
44
    // -------------------------------------------------------------------------
26✔
45

26✔
46
    /**
26✔
47
     * Promise used to obtain a database connection for a first time.
26✔
48
     */
26✔
49
    protected databaseConnectionPromise: Promise<any>
26✔
50

26✔
51
    // -------------------------------------------------------------------------
26✔
52
    // Constructor
26✔
53
    // -------------------------------------------------------------------------
26✔
54

26✔
55
    constructor(driver: OracleDriver, mode: ReplicationMode) {
26✔
56
        super()
23,188✔
57
        this.driver = driver
23,188✔
58
        this.connection = driver.connection
23,188✔
59
        this.broadcaster = new Broadcaster(this)
23,188✔
60
        this.mode = mode
23,188✔
61
    }
23,188✔
62

26✔
63
    // -------------------------------------------------------------------------
26✔
64
    // Public Methods
26✔
65
    // -------------------------------------------------------------------------
26✔
66

26✔
67
    /**
26✔
68
     * Creates/uses database connection from the connection pool to perform further operations.
26✔
69
     * Returns obtained database connection.
26✔
70
     */
26✔
71
    connect(): Promise<any> {
26✔
72
        if (this.databaseConnection)
121,530✔
73
            return Promise.resolve(this.databaseConnection)
121,530✔
74

22,378✔
75
        if (this.databaseConnectionPromise)
22,378✔
76
            return this.databaseConnectionPromise
121,530✔
77

22,252✔
78
        if (this.mode === "slave" && this.driver.isReplicated) {
121,530!
79
            this.databaseConnectionPromise = this.driver
×
80
                .obtainSlaveConnection()
×
81
                .then((connection) => {
×
82
                    this.databaseConnection = connection
×
83
                    return this.databaseConnection
×
84
                })
×
85
        } else {
121,530✔
86
            // master
22,252✔
87
            this.databaseConnectionPromise = this.driver
22,252✔
88
                .obtainMasterConnection()
22,252✔
89
                .then((connection) => {
22,252✔
90
                    this.databaseConnection = connection
22,252✔
91
                    return this.databaseConnection
22,252✔
92
                })
22,252✔
93
        }
22,252✔
94

22,252✔
95
        return this.databaseConnectionPromise
22,252✔
96
    }
22,252✔
97

26✔
98
    /**
26✔
99
     * Releases used database connection.
26✔
100
     * You cannot use query runner methods once its released.
26✔
101
     */
26✔
102
    async release(): Promise<void> {
26✔
103
        this.isReleased = true
23,188✔
104

23,188✔
105
        if (!this.databaseConnection) {
23,188✔
106
            return
936✔
107
        }
936✔
108

22,252✔
109
        await this.databaseConnection.close()
22,252✔
110
    }
22,252✔
111

26✔
112
    /**
26✔
113
     * Starts transaction.
26✔
114
     */
26✔
115
    async startTransaction(
26✔
116
        isolationLevel: IsolationLevel = "READ COMMITTED",
17,402✔
117
    ): Promise<void> {
17,402✔
118
        if (this.isReleased) throw new QueryRunnerAlreadyReleasedError()
17,402!
119

17,402✔
120
        // await this.query("START TRANSACTION");
17,402✔
121
        if (
17,402✔
122
            isolationLevel !== "SERIALIZABLE" &&
17,402✔
123
            isolationLevel !== "READ COMMITTED"
17,398✔
124
        ) {
17,402!
125
            throw new TypeORMError(
×
126
                `Oracle only supports SERIALIZABLE and READ COMMITTED isolation`,
×
127
            )
×
128
        }
×
129

17,402✔
130
        this.isTransactionActive = true
17,402✔
131
        try {
17,402✔
132
            await this.broadcaster.broadcast("BeforeTransactionStart")
17,402✔
133
        } catch (err) {
17,402!
134
            this.isTransactionActive = false
×
135
            throw err
×
136
        }
×
137

17,402✔
138
        if (this.transactionDepth === 0) {
17,402✔
139
            await this.query(
17,370✔
140
                "SET TRANSACTION ISOLATION LEVEL " + isolationLevel,
17,370✔
141
            )
17,370✔
142
        } else {
17,402✔
143
            await this.query(`SAVEPOINT typeorm_${this.transactionDepth}`)
32✔
144
        }
32✔
145
        this.transactionDepth += 1
17,402✔
146

17,402✔
147
        await this.broadcaster.broadcast("AfterTransactionStart")
17,402✔
148
    }
17,402✔
149

26✔
150
    /**
26✔
151
     * Commits transaction.
26✔
152
     * Error will be thrown if transaction was not started.
26✔
153
     */
26✔
154
    async commitTransaction(): Promise<void> {
26✔
155
        if (!this.isTransactionActive) throw new TransactionNotStartedError()
17,356!
156

17,356✔
157
        await this.broadcaster.broadcast("BeforeTransactionCommit")
17,356✔
158

17,356✔
159
        if (this.transactionDepth === 1) {
17,356✔
160
            await this.query("COMMIT")
17,336✔
161
            this.isTransactionActive = false
17,336✔
162
        }
17,336✔
163
        this.transactionDepth -= 1
17,356✔
164

17,356✔
165
        await this.broadcaster.broadcast("AfterTransactionCommit")
17,356✔
166
    }
17,356✔
167

26✔
168
    /**
26✔
169
     * Rollbacks transaction.
26✔
170
     * Error will be thrown if transaction was not started.
26✔
171
     */
26✔
172
    async rollbackTransaction(): Promise<void> {
26✔
173
        if (!this.isTransactionActive) throw new TransactionNotStartedError()
46!
174

46✔
175
        await this.broadcaster.broadcast("BeforeTransactionRollback")
46✔
176

46✔
177
        if (this.transactionDepth > 1) {
46✔
178
            await this.query(
12✔
179
                `ROLLBACK TO SAVEPOINT typeorm_${this.transactionDepth - 1}`,
12✔
180
            )
12✔
181
        } else {
46✔
182
            await this.query("ROLLBACK")
34✔
183
            this.isTransactionActive = false
34✔
184
        }
34✔
185
        this.transactionDepth -= 1
46✔
186

46✔
187
        await this.broadcaster.broadcast("AfterTransactionRollback")
46✔
188
    }
46✔
189

26✔
190
    /**
26✔
191
     * Executes a given SQL query.
26✔
192
     */
26✔
193
    async query(
26✔
194
        query: string,
121,520✔
195
        parameters?: any[],
121,520✔
196
        useStructuredResult = false,
121,520✔
197
    ): Promise<any> {
121,520✔
198
        if (this.isReleased) throw new QueryRunnerAlreadyReleasedError()
121,520!
199

121,520✔
200
        const databaseConnection = await this.connect()
121,520✔
201

121,520✔
202
        this.driver.connection.logger.logQuery(query, parameters, this)
121,520✔
203
        await this.broadcaster.broadcast("BeforeQuery", query, parameters)
121,520✔
204

121,520✔
205
        const broadcasterResult = new BroadcasterResult()
121,520✔
206
        const queryStartTime = Date.now()
121,520✔
207

121,520✔
208
        try {
121,520✔
209
            const executionOptions = {
121,520✔
210
                autoCommit: !this.isTransactionActive,
121,520✔
211
                outFormat: this.driver.oracle.OUT_FORMAT_OBJECT,
121,520✔
212
            }
121,520✔
213

121,520✔
214
            const raw = await databaseConnection.execute(
121,520✔
215
                query,
121,520✔
216
                parameters || {},
121,520✔
217
                executionOptions,
121,520✔
218
            )
121,520✔
219

121,506✔
220
            // log slow queries if maxQueryExecution time is set
121,506✔
221
            const maxQueryExecutionTime =
121,506✔
222
                this.driver.options.maxQueryExecutionTime
121,506✔
223
            const queryEndTime = Date.now()
121,506✔
224
            const queryExecutionTime = queryEndTime - queryStartTime
121,506✔
225

121,506✔
226
            this.broadcaster.broadcastAfterQueryEvent(
121,506✔
227
                broadcasterResult,
121,506✔
228
                query,
121,506✔
229
                parameters,
121,506✔
230
                true,
121,506✔
231
                queryExecutionTime,
121,506✔
232
                raw,
121,506✔
233
                undefined,
121,506✔
234
            )
121,506✔
235

121,506✔
236
            if (
121,506✔
237
                maxQueryExecutionTime &&
121,506!
238
                queryExecutionTime > maxQueryExecutionTime
×
239
            )
121,520✔
240
                this.driver.connection.logger.logQuerySlow(
121,520!
241
                    queryExecutionTime,
×
242
                    query,
×
243
                    parameters,
×
244
                    this,
×
245
                )
×
246

121,506✔
247
            const result = new QueryResult()
121,506✔
248

121,506✔
249
            result.raw =
121,506✔
250
                raw.rows ||
121,506✔
251
                raw.outBinds ||
121,520✔
252
                raw.rowsAffected ||
121,520✔
253
                raw.implicitResults
62,488✔
254

121,520✔
255
            if (raw?.hasOwnProperty("rows") && Array.isArray(raw.rows)) {
121,520✔
256
                result.records = raw.rows
38,174✔
257
            }
38,174✔
258

121,506✔
259
            if (
121,506✔
260
                raw?.hasOwnProperty("outBinds") &&
121,520✔
261
                Array.isArray(raw.outBinds)
7,248✔
262
            ) {
121,520✔
263
                result.records = raw.outBinds
7,248✔
264
            }
7,248✔
265

121,506✔
266
            if (
121,506✔
267
                raw?.hasOwnProperty("implicitResults") &&
121,520✔
268
                Array.isArray(raw.implicitResults)
2✔
269
            ) {
121,520✔
270
                result.records = raw.implicitResults
2✔
271
            }
2✔
272

121,506✔
273
            if (raw?.hasOwnProperty("rowsAffected")) {
121,520✔
274
                result.affected = raw.rowsAffected
83,330✔
275
            }
83,330✔
276

121,506✔
277
            if (useStructuredResult) {
121,520✔
278
                return result
33,650✔
279
            } else {
121,520✔
280
                return result.raw
87,856✔
281
            }
87,856✔
282
        } catch (err) {
121,520✔
283
            this.driver.connection.logger.logQueryError(
14✔
284
                err,
14✔
285
                query,
14✔
286
                parameters,
14✔
287
                this,
14✔
288
            )
14✔
289
            this.broadcaster.broadcastAfterQueryEvent(
14✔
290
                broadcasterResult,
14✔
291
                query,
14✔
292
                parameters,
14✔
293
                false,
14✔
294
                undefined,
14✔
295
                undefined,
14✔
296
                err,
14✔
297
            )
14✔
298

14✔
299
            throw new QueryFailedError(query, parameters, err)
14✔
300
        } finally {
121,520!
301
            await broadcasterResult.wait()
121,520✔
302
        }
121,520✔
303
    }
121,520✔
304

26✔
305
    /**
26✔
306
     * Returns raw data stream.
26✔
307
     */
26✔
308
    async stream(
26✔
309
        query: string,
2✔
310
        parameters?: any[],
2✔
311
        onEnd?: Function,
2✔
312
        onError?: Function,
2✔
313
    ): Promise<ReadStream> {
2✔
314
        if (this.isReleased) {
2!
315
            throw new QueryRunnerAlreadyReleasedError()
×
316
        }
×
317

2✔
318
        const executionOptions = {
2✔
319
            autoCommit: !this.isTransactionActive,
2✔
320
            outFormat: this.driver.oracle.OUT_FORMAT_OBJECT,
2✔
321
        }
2✔
322

2✔
323
        const databaseConnection = await this.connect()
2✔
324

2✔
325
        this.driver.connection.logger.logQuery(query, parameters, this)
2✔
326

2✔
327
        try {
2✔
328
            const stream = databaseConnection.queryStream(
2✔
329
                query,
2✔
330
                parameters,
2✔
331
                executionOptions,
2✔
332
            )
2✔
333
            if (onEnd) {
2!
334
                stream.on("end", onEnd)
×
335
            }
×
336

2✔
337
            if (onError) {
2!
338
                stream.on("error", onError)
×
339
            }
×
340

2✔
341
            return stream
2✔
342
        } catch (err) {
2!
343
            this.driver.connection.logger.logQueryError(
×
344
                err,
×
345
                query,
×
346
                parameters,
×
347
                this,
×
348
            )
×
349
            throw new QueryFailedError(query, parameters, err)
×
350
        }
×
351
    }
2✔
352

26✔
353
    /**
26✔
354
     * Returns all available database names including system databases.
26✔
355
     */
26✔
356
    async getDatabases(): Promise<string[]> {
26✔
357
        return Promise.resolve([])
×
358
    }
×
359

26✔
360
    /**
26✔
361
     * Returns all available schema names including system schemas.
26✔
362
     * If database parameter specified, returns schemas of that database.
26✔
363
     */
26✔
364
    async getSchemas(database?: string): Promise<string[]> {
26✔
365
        return Promise.resolve([])
×
366
    }
×
367

26✔
368
    /**
26✔
369
     * Checks if database with the given name exist.
26✔
370
     */
26✔
371
    async hasDatabase(database: string): Promise<boolean> {
26✔
372
        try {
×
373
            const query = await this.query(
×
374
                `SELECT 1 AS "exists" FROM global_name@"${database}"`,
×
375
            )
×
376

×
377
            return query.length > 0
×
378
        } catch (e) {
×
379
            return false
×
380
        }
×
381
    }
×
382

26✔
383
    /**
26✔
384
     * Loads currently using database
26✔
385
     */
26✔
386
    async getCurrentDatabase(): Promise<undefined> {
26✔
387
        const query = await this.query(
4,218✔
388
            `SELECT SYS_CONTEXT('USERENV','DB_NAME') AS "db_name" FROM dual`,
4,218✔
389
        )
4,218✔
390
        return query[0]["db_name"]
4,218✔
391
    }
4,218✔
392

26✔
393
    /**
26✔
394
     * Checks if schema with the given name exist.
26✔
395
     */
26✔
396
    async hasSchema(schema: string): Promise<boolean> {
26✔
397
        return Promise.resolve(false)
×
398
    }
×
399

26✔
400
    /**
26✔
401
     * Loads currently using database schema
26✔
402
     */
26✔
403
    async getCurrentSchema(): Promise<string> {
26✔
404
        const query = await this.query(
4,218✔
405
            `SELECT SYS_CONTEXT('USERENV','CURRENT_SCHEMA') AS "schema_name" FROM dual`,
4,218✔
406
        )
4,218✔
407
        return query[0]["schema_name"]
4,218✔
408
    }
4,218✔
409

26✔
410
    /**
26✔
411
     * Checks if table with the given name exist in the database.
26✔
412
     */
26✔
413
    async hasTable(tableOrName: Table | string): Promise<boolean> {
26✔
414
        const { tableName } = this.driver.parseTableName(tableOrName)
2,870✔
415
        const sql = `SELECT "TABLE_NAME" FROM "USER_TABLES" WHERE "TABLE_NAME" = '${tableName}'`
2,870✔
416
        const result = await this.query(sql)
2,870✔
417
        return result.length ? true : false
2,870✔
418
    }
2,870✔
419

26✔
420
    /**
26✔
421
     * Checks if column with the given name exist in the given table.
26✔
422
     */
26✔
423
    async hasColumn(
26✔
424
        tableOrName: Table | string,
8✔
425
        columnName: string,
8✔
426
    ): Promise<boolean> {
8✔
427
        const { tableName } = this.driver.parseTableName(tableOrName)
8✔
428
        const sql = `SELECT "COLUMN_NAME" FROM "USER_TAB_COLS" WHERE "TABLE_NAME" = '${tableName}' AND "COLUMN_NAME" = '${columnName}'`
8✔
429
        const result = await this.query(sql)
8✔
430
        return result.length ? true : false
8✔
431
    }
8✔
432

26✔
433
    /**
26✔
434
     * Creates a new database.
26✔
435
     */
26✔
436
    async createDatabase(
26✔
437
        database: string,
×
438
        ifNotExist?: boolean,
×
439
    ): Promise<void> {
×
440
        // Even with `IF NOT EXISTS` we get:
×
441
        //   ORA-01501: CREATE DATABASE failed
×
442
        //   ORA-01100: database already mounted
×
443
        if (ifNotExist) {
×
444
            try {
×
445
                await this.query(`CREATE DATABASE IF NOT EXISTS "${database}";`)
×
446
            } catch (e) {
×
447
                // if (e instanceof QueryFailedError) {
×
448
                if (e.message.includes("ORA-01100: database already mounted")) {
×
449
                    return
×
450
                }
×
451
                // }
×
452

×
453
                throw e
×
454
            }
×
455
        } else {
×
456
            await this.query(`CREATE DATABASE "${database}"`)
×
457
        }
×
458
    }
×
459

26✔
460
    /**
26✔
461
     * Drops database.
26✔
462
     */
26✔
463
    async dropDatabase(database: string, ifExist?: boolean): Promise<void> {
26✔
464
        return Promise.resolve()
×
465
    }
×
466

26✔
467
    /**
26✔
468
     * Creates a new table schema.
26✔
469
     */
26✔
470
    async createSchema(
26✔
471
        schemaPath: string,
2✔
472
        ifNotExist?: boolean,
2✔
473
    ): Promise<void> {
2✔
474
        throw new TypeORMError(
2✔
475
            `Schema create queries are not supported by Oracle driver.`,
2✔
476
        )
2✔
477
    }
2✔
478

26✔
479
    /**
26✔
480
     * Drops table schema.
26✔
481
     */
26✔
482
    async dropSchema(schemaPath: string, ifExist?: boolean): Promise<void> {
26✔
483
        throw new TypeORMError(
×
484
            `Schema drop queries are not supported by Oracle driver.`,
×
485
        )
×
486
    }
×
487

26✔
488
    /**
26✔
489
     * Creates a new table.
26✔
490
     */
26✔
491
    async createTable(
26✔
492
        table: Table,
9,068✔
493
        ifNotExist: boolean = false,
9,068✔
494
        createForeignKeys: boolean = true,
9,068✔
495
        createIndices: boolean = true,
9,068✔
496
    ): Promise<void> {
9,068✔
497
        if (ifNotExist) {
9,068✔
498
            const isTableExist = await this.hasTable(table)
80✔
499
            if (isTableExist) return Promise.resolve()
80✔
500
        }
80✔
501
        const upQueries: Query[] = []
9,066✔
502
        const downQueries: Query[] = []
9,066✔
503

9,066✔
504
        upQueries.push(this.createTableSql(table, createForeignKeys))
9,066✔
505
        downQueries.push(this.dropTableSql(table))
9,066✔
506

9,066✔
507
        // if createForeignKeys is true, we must drop created foreign keys in down query.
9,066✔
508
        // createTable does not need separate method to create foreign keys, because it create fk's in the same query with table creation.
9,066✔
509
        if (createForeignKeys)
9,066✔
510
            table.foreignKeys.forEach((foreignKey) =>
9,068✔
511
                downQueries.push(this.dropForeignKeySql(table, foreignKey)),
124✔
512
            )
124✔
513

9,066✔
514
        if (createIndices) {
9,066✔
515
            table.indices.forEach((index) => {
9,066✔
516
                // new index may be passed without name. In this case we generate index name manually.
3,120✔
517
                if (!index.name)
3,120✔
518
                    index.name = this.connection.namingStrategy.indexName(
3,120✔
519
                        table,
6✔
520
                        index.columnNames,
6✔
521
                        index.where,
6✔
522
                    )
6✔
523
                upQueries.push(this.createIndexSql(table, index))
3,120✔
524
                downQueries.push(this.dropIndexSql(index))
3,120✔
525
            })
9,066✔
526
        }
9,066✔
527

9,066✔
528
        // if table have column with generated type, we must add the expression to the metadata table
9,066✔
529
        const generatedColumns = table.columns.filter(
9,066✔
530
            (column) => column.generatedType && column.asExpression,
9,066✔
531
        )
9,066✔
532

9,066✔
533
        for (const column of generatedColumns) {
9,068✔
534
            const insertQuery = this.insertTypeormMetadataSql({
42✔
535
                table: table.name,
42✔
536
                type: MetadataTableType.GENERATED_COLUMN,
42✔
537
                name: column.name,
42✔
538
                value: column.asExpression,
42✔
539
            })
42✔
540

42✔
541
            const deleteQuery = this.deleteTypeormMetadataSql({
42✔
542
                table: table.name,
42✔
543
                type: MetadataTableType.GENERATED_COLUMN,
42✔
544
                name: column.name,
42✔
545
            })
42✔
546

42✔
547
            upQueries.push(insertQuery)
42✔
548
            downQueries.push(deleteQuery)
42✔
549
        }
42✔
550

9,066✔
551
        await this.executeQueries(upQueries, downQueries)
9,066✔
552
    }
9,066✔
553

26✔
554
    /**
26✔
555
     * Drops the table.
26✔
556
     */
26✔
557
    async dropTable(
26✔
558
        tableOrName: Table | string,
20✔
559
        ifExist?: boolean,
20✔
560
        dropForeignKeys: boolean = true,
20✔
561
        dropIndices: boolean = true,
20✔
562
    ): Promise<void> {
20✔
563
        // It needs because if table does not exist and dropForeignKeys or dropIndices is true, we don't need
20✔
564
        // to perform drop queries for foreign keys and indices.
20✔
565
        if (ifExist) {
20!
566
            const isTableExist = await this.hasTable(tableOrName)
×
567
            if (!isTableExist) return Promise.resolve()
×
568
        }
×
569

20✔
570
        // if dropTable called with dropForeignKeys = true, we must create foreign keys in down query.
20✔
571
        const createForeignKeys: boolean = dropForeignKeys
20✔
572
        const table = InstanceChecker.isTable(tableOrName)
20✔
573
            ? tableOrName
20✔
574
            : await this.getCachedTable(tableOrName)
20✔
575
        const upQueries: Query[] = []
12✔
576
        const downQueries: Query[] = []
12✔
577

12✔
578
        if (dropIndices) {
20✔
579
            table.indices.forEach((index) => {
20✔
580
                upQueries.push(this.dropIndexSql(index))
2✔
581
                downQueries.push(this.createIndexSql(table, index))
2✔
582
            })
20✔
583
        }
20✔
584

20✔
585
        // if dropForeignKeys is true, we just drop the table, otherwise we also drop table foreign keys.
20✔
586
        // createTable does not need separate method to create foreign keys, because it create fk's in the same query with table creation.
20✔
587
        if (dropForeignKeys)
20✔
588
            table.foreignKeys.forEach((foreignKey) =>
20✔
589
                upQueries.push(this.dropForeignKeySql(table, foreignKey)),
20✔
590
            )
20✔
591

20✔
592
        upQueries.push(this.dropTableSql(table))
20✔
593
        downQueries.push(this.createTableSql(table, createForeignKeys))
20✔
594

20✔
595
        // if table had columns with generated type, we must remove the expression from the metadata table
20✔
596
        const generatedColumns = table.columns.filter(
20✔
597
            (column) => column.generatedType && column.asExpression,
20✔
598
        )
20✔
599

20✔
600
        for (const column of generatedColumns) {
20✔
601
            const deleteQuery = this.deleteTypeormMetadataSql({
6✔
602
                table: table.name,
6✔
603
                type: MetadataTableType.GENERATED_COLUMN,
6✔
604
                name: column.name,
6✔
605
            })
6✔
606

6✔
607
            const insertQuery = this.insertTypeormMetadataSql({
6✔
608
                table: table.name,
6✔
609
                type: MetadataTableType.GENERATED_COLUMN,
6✔
610
                name: column.name,
6✔
611
                value: column.asExpression,
6✔
612
            })
6✔
613

6✔
614
            upQueries.push(deleteQuery)
6✔
615
            downQueries.push(insertQuery)
6✔
616
        }
6✔
617

20✔
618
        await this.executeQueries(upQueries, downQueries)
20✔
619
    }
20✔
620

26✔
621
    /**
26✔
622
     * Creates a new view.
26✔
623
     */
26✔
624
    async createView(
26✔
625
        view: View,
52✔
626
        syncWithMetadata: boolean = false,
52✔
627
    ): Promise<void> {
52✔
628
        const upQueries: Query[] = []
52✔
629
        const downQueries: Query[] = []
52✔
630
        upQueries.push(this.createViewSql(view))
52✔
631
        if (syncWithMetadata) upQueries.push(this.insertViewDefinitionSql(view))
52✔
632
        downQueries.push(this.dropViewSql(view))
52✔
633
        if (syncWithMetadata)
52✔
634
            downQueries.push(this.deleteViewDefinitionSql(view))
52✔
635
        await this.executeQueries(upQueries, downQueries)
52✔
636
    }
52✔
637

26✔
638
    /**
26✔
639
     * Drops the view.
26✔
640
     */
26✔
641
    async dropView(target: View | string): Promise<void> {
26✔
642
        const viewName = InstanceChecker.isView(target) ? target.name : target
4!
643
        const view = await this.getCachedView(viewName)
4✔
644

4✔
645
        const upQueries: Query[] = []
4✔
646
        const downQueries: Query[] = []
4✔
647
        upQueries.push(this.deleteViewDefinitionSql(view))
4✔
648
        upQueries.push(this.dropViewSql(view))
4✔
649
        downQueries.push(this.insertViewDefinitionSql(view))
4✔
650
        downQueries.push(this.createViewSql(view))
4✔
651
        await this.executeQueries(upQueries, downQueries)
4✔
652
    }
4✔
653

26✔
654
    /**
26✔
655
     * Renames the given table.
26✔
656
     */
26✔
657
    async renameTable(
26✔
658
        oldTableOrName: Table | string,
34✔
659
        newTableName: string,
34✔
660
    ): Promise<void> {
34✔
661
        const upQueries: Query[] = []
34✔
662
        const downQueries: Query[] = []
34✔
663
        const oldTable = InstanceChecker.isTable(oldTableOrName)
34✔
664
            ? oldTableOrName
34✔
665
            : await this.getCachedTable(oldTableOrName)
34✔
666
        const newTable = oldTable.clone()
30✔
667

30✔
668
        const { database: dbName, tableName: oldTableName } =
30✔
669
            this.driver.parseTableName(oldTable)
30✔
670

30✔
671
        newTable.name = dbName ? `${dbName}.${newTableName}` : newTableName
34!
672

34✔
673
        // rename table
34✔
674
        upQueries.push(
34✔
675
            new Query(
34✔
676
                `ALTER TABLE ${this.escapePath(
34✔
677
                    oldTable,
34✔
678
                )} RENAME TO "${newTableName}"`,
34✔
679
            ),
34✔
680
        )
34✔
681
        downQueries.push(
34✔
682
            new Query(
34✔
683
                `ALTER TABLE ${this.escapePath(
34✔
684
                    newTable,
34✔
685
                )} RENAME TO "${oldTableName}"`,
34✔
686
            ),
34✔
687
        )
34✔
688

34✔
689
        // rename primary key constraint
34✔
690
        if (
34✔
691
            newTable.primaryColumns.length > 0 &&
34✔
692
            !newTable.primaryColumns[0].primaryKeyConstraintName
34✔
693
        ) {
34✔
694
            const columnNames = newTable.primaryColumns.map(
26✔
695
                (column) => column.name,
26✔
696
            )
26✔
697

26✔
698
            const oldPkName = this.connection.namingStrategy.primaryKeyName(
26✔
699
                oldTable,
26✔
700
                columnNames,
26✔
701
            )
26✔
702
            const newPkName = this.connection.namingStrategy.primaryKeyName(
26✔
703
                newTable,
26✔
704
                columnNames,
26✔
705
            )
26✔
706

26✔
707
            // build queries
26✔
708
            upQueries.push(
26✔
709
                new Query(
26✔
710
                    `ALTER TABLE ${this.escapePath(
26✔
711
                        newTable,
26✔
712
                    )} RENAME CONSTRAINT "${oldPkName}" TO "${newPkName}"`,
26✔
713
                ),
26✔
714
            )
26✔
715
            downQueries.push(
26✔
716
                new Query(
26✔
717
                    `ALTER TABLE ${this.escapePath(
26✔
718
                        newTable,
26✔
719
                    )} RENAME CONSTRAINT "${newPkName}" TO "${oldPkName}"`,
26✔
720
                ),
26✔
721
            )
26✔
722
        }
26✔
723

34✔
724
        // rename unique constraints
34✔
725
        newTable.uniques.forEach((unique) => {
34✔
726
            const oldUniqueName =
14✔
727
                this.connection.namingStrategy.uniqueConstraintName(
14✔
728
                    oldTable,
14✔
729
                    unique.columnNames,
14✔
730
                )
14✔
731

14✔
732
            // Skip renaming if Unique has user defined constraint name
14✔
733
            if (unique.name !== oldUniqueName) return
14✔
734

6✔
735
            // build new constraint name
6✔
736
            const newUniqueName =
6✔
737
                this.connection.namingStrategy.uniqueConstraintName(
6✔
738
                    newTable,
6✔
739
                    unique.columnNames,
6✔
740
                )
6✔
741

6✔
742
            // build queries
6✔
743
            upQueries.push(
6✔
744
                new Query(
6✔
745
                    `ALTER TABLE ${this.escapePath(
6✔
746
                        newTable,
6✔
747
                    )} RENAME CONSTRAINT "${
6✔
748
                        unique.name
6✔
749
                    }" TO "${newUniqueName}"`,
6✔
750
                ),
6✔
751
            )
6✔
752
            downQueries.push(
6✔
753
                new Query(
6✔
754
                    `ALTER TABLE ${this.escapePath(
6✔
755
                        newTable,
6✔
756
                    )} RENAME CONSTRAINT "${newUniqueName}" TO "${
6✔
757
                        unique.name
6✔
758
                    }"`,
6✔
759
                ),
6✔
760
            )
6✔
761

6✔
762
            // replace constraint name
6✔
763
            unique.name = newUniqueName
6✔
764
        })
34✔
765

34✔
766
        // rename index constraints
34✔
767
        newTable.indices.forEach((index) => {
34✔
768
            const oldIndexName = this.connection.namingStrategy.indexName(
20✔
769
                oldTable,
20✔
770
                index.columnNames,
20✔
771
                index.where,
20✔
772
            )
20✔
773

20✔
774
            // Skip renaming if Index has user defined constraint name
20✔
775
            if (index.name !== oldIndexName) return
20✔
776

10✔
777
            // build new constraint name
10✔
778
            const newIndexName = this.connection.namingStrategy.indexName(
10✔
779
                newTable,
10✔
780
                index.columnNames,
10✔
781
                index.where,
10✔
782
            )
10✔
783

10✔
784
            // build queries
10✔
785
            upQueries.push(
10✔
786
                new Query(
10✔
787
                    `ALTER INDEX "${index.name}" RENAME TO "${newIndexName}"`,
10✔
788
                ),
10✔
789
            )
10✔
790
            downQueries.push(
10✔
791
                new Query(
10✔
792
                    `ALTER INDEX "${newIndexName}" RENAME TO "${index.name}"`,
10✔
793
                ),
10✔
794
            )
10✔
795

10✔
796
            // replace constraint name
10✔
797
            index.name = newIndexName
10✔
798
        })
34✔
799

34✔
800
        // rename foreign key constraints
34✔
801
        newTable.foreignKeys.forEach((foreignKey) => {
34✔
802
            const oldForeignKeyName =
18✔
803
                this.connection.namingStrategy.foreignKeyName(
18✔
804
                    oldTable,
18✔
805
                    foreignKey.columnNames,
18✔
806
                    this.getTablePath(foreignKey),
18✔
807
                    foreignKey.referencedColumnNames,
18✔
808
                )
18✔
809

18✔
810
            // Skip renaming if foreign key has user defined constraint name
18✔
811
            if (foreignKey.name !== oldForeignKeyName) return
18✔
812

2✔
813
            // build new constraint name
2✔
814
            const newForeignKeyName =
2✔
815
                this.connection.namingStrategy.foreignKeyName(
2✔
816
                    newTable,
2✔
817
                    foreignKey.columnNames,
2✔
818
                    this.getTablePath(foreignKey),
2✔
819
                    foreignKey.referencedColumnNames,
2✔
820
                )
2✔
821

2✔
822
            // build queries
2✔
823
            upQueries.push(
2✔
824
                new Query(
2✔
825
                    `ALTER TABLE ${this.escapePath(
2✔
826
                        newTable,
2✔
827
                    )} RENAME CONSTRAINT "${
2✔
828
                        foreignKey.name
2✔
829
                    }" TO "${newForeignKeyName}"`,
2✔
830
                ),
2✔
831
            )
2✔
832
            downQueries.push(
2✔
833
                new Query(
2✔
834
                    `ALTER TABLE ${this.escapePath(
2✔
835
                        newTable,
2✔
836
                    )} RENAME CONSTRAINT "${newForeignKeyName}" TO "${
2✔
837
                        foreignKey.name
2✔
838
                    }"`,
2✔
839
                ),
2✔
840
            )
2✔
841

2✔
842
            // replace constraint name
2✔
843
            foreignKey.name = newForeignKeyName
2✔
844
        })
34✔
845

34✔
846
        await this.executeQueries(upQueries, downQueries)
34✔
847

34✔
848
        // rename old table and replace it in cached tabled;
34✔
849
        oldTable.name = newTable.name
34✔
850
        this.replaceCachedTable(oldTable, newTable)
34✔
851
    }
34✔
852

26✔
853
    /**
26✔
854
     * Creates a new column from the column in the table.
26✔
855
     */
26✔
856
    async addColumn(
26✔
857
        tableOrName: Table | string,
50✔
858
        column: TableColumn,
50✔
859
    ): Promise<void> {
50✔
860
        const table = InstanceChecker.isTable(tableOrName)
50✔
861
            ? tableOrName
50✔
862
            : await this.getCachedTable(tableOrName)
50✔
863
        const clonedTable = table.clone()
4✔
864
        const upQueries: Query[] = []
4✔
865
        const downQueries: Query[] = []
4✔
866

4✔
867
        upQueries.push(
4✔
868
            new Query(
4✔
869
                `ALTER TABLE ${this.escapePath(
4✔
870
                    table,
4✔
871
                )} ADD ${this.buildCreateColumnSql(column)}`,
4✔
872
            ),
4✔
873
        )
4✔
874
        downQueries.push(
4✔
875
            new Query(
4✔
876
                `ALTER TABLE ${this.escapePath(table)} DROP COLUMN "${
4✔
877
                    column.name
4✔
878
                }"`,
4✔
879
            ),
4✔
880
        )
4✔
881

4✔
882
        // create or update primary key constraint
4✔
883
        if (column.isPrimary) {
50✔
884
            const primaryColumns = clonedTable.primaryColumns
14✔
885
            // if table already have primary key, me must drop it and recreate again
14✔
886
            if (primaryColumns.length > 0) {
14✔
887
                const pkName = primaryColumns[0].primaryKeyConstraintName
2✔
888
                    ? primaryColumns[0].primaryKeyConstraintName
2!
889
                    : this.connection.namingStrategy.primaryKeyName(
2✔
890
                          clonedTable,
2✔
891
                          primaryColumns.map((column) => column.name),
2✔
892
                      )
2✔
893

2✔
894
                const columnNames = primaryColumns
2✔
895
                    .map((column) => `"${column.name}"`)
2✔
896
                    .join(", ")
2✔
897

2✔
898
                upQueries.push(
2✔
899
                    new Query(
2✔
900
                        `ALTER TABLE ${this.escapePath(
2✔
901
                            table,
2✔
902
                        )} DROP CONSTRAINT "${pkName}"`,
2✔
903
                    ),
2✔
904
                )
2✔
905
                downQueries.push(
2✔
906
                    new Query(
2✔
907
                        `ALTER TABLE ${this.escapePath(
2✔
908
                            table,
2✔
909
                        )} ADD CONSTRAINT "${pkName}" PRIMARY KEY (${columnNames})`,
2✔
910
                    ),
2✔
911
                )
2✔
912
            }
2✔
913

14✔
914
            primaryColumns.push(column)
14✔
915
            const pkName = primaryColumns[0].primaryKeyConstraintName
14✔
916
                ? primaryColumns[0].primaryKeyConstraintName
14!
917
                : this.connection.namingStrategy.primaryKeyName(
14✔
918
                      clonedTable,
14✔
919
                      primaryColumns.map((column) => column.name),
14✔
920
                  )
14✔
921

14✔
922
            const columnNames = primaryColumns
14✔
923
                .map((column) => `"${column.name}"`)
14✔
924
                .join(", ")
14✔
925

14✔
926
            upQueries.push(
14✔
927
                new Query(
14✔
928
                    `ALTER TABLE ${this.escapePath(
14✔
929
                        table,
14✔
930
                    )} ADD CONSTRAINT "${pkName}" PRIMARY KEY (${columnNames})`,
14✔
931
                ),
14✔
932
            )
14✔
933
            downQueries.push(
14✔
934
                new Query(
14✔
935
                    `ALTER TABLE ${this.escapePath(
14✔
936
                        table,
14✔
937
                    )} DROP CONSTRAINT "${pkName}"`,
14✔
938
                ),
14✔
939
            )
14✔
940
        }
14✔
941

50✔
942
        // create column index
50✔
943
        const columnIndex = clonedTable.indices.find(
50✔
944
            (index) =>
50✔
945
                index.columnNames.length === 1 &&
2✔
946
                index.columnNames[0] === column.name,
50✔
947
        )
50✔
948
        if (columnIndex) {
50!
949
            clonedTable.indices.splice(
×
950
                clonedTable.indices.indexOf(columnIndex),
×
951
                1,
×
952
            )
×
953
            upQueries.push(this.createIndexSql(table, columnIndex))
×
954
            downQueries.push(this.dropIndexSql(columnIndex))
×
955
        }
×
956

50✔
957
        // create unique constraint
50✔
958
        if (column.isUnique) {
50✔
959
            const uniqueConstraint = new TableUnique({
6✔
960
                name: this.connection.namingStrategy.uniqueConstraintName(
6✔
961
                    table,
6✔
962
                    [column.name],
6✔
963
                ),
6✔
964
                columnNames: [column.name],
6✔
965
            })
6✔
966
            clonedTable.uniques.push(uniqueConstraint)
6✔
967
            upQueries.push(
6✔
968
                new Query(
6✔
969
                    `ALTER TABLE ${this.escapePath(table)} ADD CONSTRAINT "${
6✔
970
                        uniqueConstraint.name
6✔
971
                    }" UNIQUE ("${column.name}")`,
6✔
972
                ),
6✔
973
            )
6✔
974
            downQueries.push(
6✔
975
                new Query(
6✔
976
                    `ALTER TABLE ${this.escapePath(table)} DROP CONSTRAINT "${
6✔
977
                        uniqueConstraint.name
6✔
978
                    }"`,
6✔
979
                ),
6✔
980
            )
6✔
981
        }
6✔
982

50✔
983
        if (column.generatedType && column.asExpression) {
50✔
984
            const insertQuery = this.insertTypeormMetadataSql({
4✔
985
                table: table.name,
4✔
986
                type: MetadataTableType.GENERATED_COLUMN,
4✔
987
                name: column.name,
4✔
988
                value: column.asExpression,
4✔
989
            })
4✔
990

4✔
991
            const deleteQuery = this.deleteTypeormMetadataSql({
4✔
992
                table: table.name,
4✔
993
                type: MetadataTableType.GENERATED_COLUMN,
4✔
994
                name: column.name,
4✔
995
            })
4✔
996

4✔
997
            upQueries.push(insertQuery)
4✔
998
            downQueries.push(deleteQuery)
4✔
999
        }
4✔
1000

50✔
1001
        await this.executeQueries(upQueries, downQueries)
50✔
1002

48✔
1003
        clonedTable.addColumn(column)
48✔
1004
        this.replaceCachedTable(table, clonedTable)
48✔
1005
    }
48✔
1006

26✔
1007
    /**
26✔
1008
     * Creates a new columns from the column in the table.
26✔
1009
     */
26✔
1010
    async addColumns(
26✔
1011
        tableOrName: Table | string,
8✔
1012
        columns: TableColumn[],
8✔
1013
    ): Promise<void> {
8✔
1014
        for (const column of columns) {
8✔
1015
            await this.addColumn(tableOrName, column)
10✔
1016
        }
10✔
1017
    }
8✔
1018

26✔
1019
    /**
26✔
1020
     * Renames column in the given table.
26✔
1021
     */
26✔
1022
    async renameColumn(
26✔
1023
        tableOrName: Table | string,
26✔
1024
        oldTableColumnOrName: TableColumn | string,
26✔
1025
        newTableColumnOrName: TableColumn | string,
26✔
1026
    ): Promise<void> {
26✔
1027
        const table = InstanceChecker.isTable(tableOrName)
26✔
1028
            ? tableOrName
26✔
1029
            : await this.getCachedTable(tableOrName)
26✔
1030
        const oldColumn = InstanceChecker.isTableColumn(oldTableColumnOrName)
4✔
1031
            ? oldTableColumnOrName
26✔
1032
            : table.columns.find((c) => c.name === oldTableColumnOrName)
26✔
1033
        if (!oldColumn)
26✔
1034
            throw new TypeORMError(
26!
1035
                `Column "${oldTableColumnOrName}" was not found in the ${this.escapePath(
×
1036
                    table,
×
1037
                )} table.`,
×
1038
            )
×
1039

26✔
1040
        let newColumn: TableColumn | undefined = undefined
26✔
1041
        if (InstanceChecker.isTableColumn(newTableColumnOrName)) {
26✔
1042
            newColumn = newTableColumnOrName
16✔
1043
        } else {
26✔
1044
            newColumn = oldColumn.clone()
10✔
1045
            newColumn.name = newTableColumnOrName
10✔
1046
        }
10✔
1047

26✔
1048
        await this.changeColumn(table, oldColumn, newColumn)
26✔
1049
    }
26✔
1050

26✔
1051
    /**
26✔
1052
     * Changes a column in the table.
26✔
1053
     */
26✔
1054
    async changeColumn(
26✔
1055
        tableOrName: Table | string,
96✔
1056
        oldTableColumnOrName: TableColumn | string,
96✔
1057
        newColumn: TableColumn,
96✔
1058
    ): Promise<void> {
96✔
1059
        const table = InstanceChecker.isTable(tableOrName)
96✔
1060
            ? tableOrName
96✔
1061
            : await this.getCachedTable(tableOrName)
96!
1062
        let clonedTable = table.clone()
×
1063
        const upQueries: Query[] = []
×
1064
        const downQueries: Query[] = []
×
1065

×
1066
        const oldColumn = InstanceChecker.isTableColumn(oldTableColumnOrName)
×
1067
            ? oldTableColumnOrName
96✔
1068
            : table.columns.find(
96!
1069
                  (column) => column.name === oldTableColumnOrName,
×
1070
              )
96✔
1071
        if (!oldColumn)
96✔
1072
            throw new TypeORMError(
96!
1073
                `Column "${oldTableColumnOrName}" was not found in the ${this.escapePath(
×
1074
                    table,
×
1075
                )} table.`,
×
1076
            )
×
1077

96✔
1078
        if (
96✔
1079
            (newColumn.isGenerated !== oldColumn.isGenerated &&
96✔
1080
                newColumn.generationStrategy !== "uuid") ||
96✔
1081
            oldColumn.type !== newColumn.type ||
96✔
1082
            oldColumn.length !== newColumn.length ||
96✔
1083
            oldColumn.generatedType !== newColumn.generatedType ||
96✔
1084
            oldColumn.asExpression !== newColumn.asExpression
66✔
1085
        ) {
96✔
1086
            // Oracle does not support changing of IDENTITY column, so we must drop column and recreate it again.
32✔
1087
            // Also, we recreate column if column type changed
32✔
1088
            await this.dropColumn(table, oldColumn)
32✔
1089
            await this.addColumn(table, newColumn)
32✔
1090

32✔
1091
            // update cloned table
32✔
1092
            clonedTable = table.clone()
32✔
1093
        } else {
96✔
1094
            if (newColumn.name !== oldColumn.name) {
64✔
1095
                // rename column
44✔
1096
                upQueries.push(
44✔
1097
                    new Query(
44✔
1098
                        `ALTER TABLE ${this.escapePath(table)} RENAME COLUMN "${
44✔
1099
                            oldColumn.name
44✔
1100
                        }" TO "${newColumn.name}"`,
44✔
1101
                    ),
44✔
1102
                )
44✔
1103
                downQueries.push(
44✔
1104
                    new Query(
44✔
1105
                        `ALTER TABLE ${this.escapePath(table)} RENAME COLUMN "${
44✔
1106
                            newColumn.name
44✔
1107
                        }" TO "${oldColumn.name}"`,
44✔
1108
                    ),
44✔
1109
                )
44✔
1110

44✔
1111
                // rename column primary key constraint
44✔
1112
                if (
44✔
1113
                    oldColumn.isPrimary === true &&
44✔
1114
                    !oldColumn.primaryKeyConstraintName
14✔
1115
                ) {
44✔
1116
                    const primaryColumns = clonedTable.primaryColumns
10✔
1117

10✔
1118
                    // build old primary constraint name
10✔
1119
                    const columnNames = primaryColumns.map(
10✔
1120
                        (column) => column.name,
10✔
1121
                    )
10✔
1122
                    const oldPkName =
10✔
1123
                        this.connection.namingStrategy.primaryKeyName(
10✔
1124
                            clonedTable,
10✔
1125
                            columnNames,
10✔
1126
                        )
10✔
1127

10✔
1128
                    // replace old column name with new column name
10✔
1129
                    columnNames.splice(columnNames.indexOf(oldColumn.name), 1)
10✔
1130
                    columnNames.push(newColumn.name)
10✔
1131

10✔
1132
                    // build new primary constraint name
10✔
1133
                    const newPkName =
10✔
1134
                        this.connection.namingStrategy.primaryKeyName(
10✔
1135
                            clonedTable,
10✔
1136
                            columnNames,
10✔
1137
                        )
10✔
1138

10✔
1139
                    upQueries.push(
10✔
1140
                        new Query(
10✔
1141
                            `ALTER TABLE ${this.escapePath(
10✔
1142
                                table,
10✔
1143
                            )} RENAME CONSTRAINT "${oldPkName}" TO "${newPkName}"`,
10✔
1144
                        ),
10✔
1145
                    )
10✔
1146
                    downQueries.push(
10✔
1147
                        new Query(
10✔
1148
                            `ALTER TABLE ${this.escapePath(
10✔
1149
                                table,
10✔
1150
                            )} RENAME CONSTRAINT "${newPkName}" TO "${oldPkName}"`,
10✔
1151
                        ),
10✔
1152
                    )
10✔
1153
                }
10✔
1154

44✔
1155
                // rename unique constraints
44✔
1156
                clonedTable.findColumnUniques(oldColumn).forEach((unique) => {
44✔
1157
                    const oldUniqueName =
16✔
1158
                        this.connection.namingStrategy.uniqueConstraintName(
16✔
1159
                            clonedTable,
16✔
1160
                            unique.columnNames,
16✔
1161
                        )
16✔
1162

16✔
1163
                    // Skip renaming if Unique has user defined constraint name
16✔
1164
                    if (unique.name !== oldUniqueName) return
16✔
1165

8✔
1166
                    // build new constraint name
8✔
1167
                    unique.columnNames.splice(
8✔
1168
                        unique.columnNames.indexOf(oldColumn.name),
8✔
1169
                        1,
8✔
1170
                    )
8✔
1171
                    unique.columnNames.push(newColumn.name)
8✔
1172
                    const newUniqueName =
8✔
1173
                        this.connection.namingStrategy.uniqueConstraintName(
8✔
1174
                            clonedTable,
8✔
1175
                            unique.columnNames,
8✔
1176
                        )
8✔
1177

8✔
1178
                    // build queries
8✔
1179
                    upQueries.push(
8✔
1180
                        new Query(
8✔
1181
                            `ALTER TABLE ${this.escapePath(
8✔
1182
                                table,
8✔
1183
                            )} RENAME CONSTRAINT "${
8✔
1184
                                unique.name
8✔
1185
                            }" TO "${newUniqueName}"`,
8✔
1186
                        ),
8✔
1187
                    )
8✔
1188
                    downQueries.push(
8✔
1189
                        new Query(
8✔
1190
                            `ALTER TABLE ${this.escapePath(
8✔
1191
                                table,
8✔
1192
                            )} RENAME CONSTRAINT "${newUniqueName}" TO "${
8✔
1193
                                unique.name
8✔
1194
                            }"`,
8✔
1195
                        ),
8✔
1196
                    )
8✔
1197

8✔
1198
                    // replace constraint name
8✔
1199
                    unique.name = newUniqueName
8✔
1200
                })
44✔
1201

44✔
1202
                // rename index constraints
44✔
1203
                clonedTable.findColumnIndices(oldColumn).forEach((index) => {
44✔
1204
                    const oldIndexName =
14✔
1205
                        this.connection.namingStrategy.indexName(
14✔
1206
                            clonedTable,
14✔
1207
                            index.columnNames,
14✔
1208
                            index.where,
14✔
1209
                        )
14✔
1210

14✔
1211
                    // Skip renaming if Index has user defined constraint name
14✔
1212
                    if (index.name !== oldIndexName) return
14✔
1213

10✔
1214
                    // build new constraint name
10✔
1215
                    index.columnNames.splice(
10✔
1216
                        index.columnNames.indexOf(oldColumn.name),
10✔
1217
                        1,
10✔
1218
                    )
10✔
1219
                    index.columnNames.push(newColumn.name)
10✔
1220
                    const newIndexName =
10✔
1221
                        this.connection.namingStrategy.indexName(
10✔
1222
                            clonedTable,
10✔
1223
                            index.columnNames,
10✔
1224
                            index.where,
10✔
1225
                        )
10✔
1226

10✔
1227
                    // build queries
10✔
1228
                    upQueries.push(
10✔
1229
                        new Query(
10✔
1230
                            `ALTER INDEX "${index.name}" RENAME TO "${newIndexName}"`,
10✔
1231
                        ),
10✔
1232
                    )
10✔
1233
                    downQueries.push(
10✔
1234
                        new Query(
10✔
1235
                            `ALTER INDEX "${newIndexName}" RENAME TO "${index.name}"`,
10✔
1236
                        ),
10✔
1237
                    )
10✔
1238

10✔
1239
                    // replace constraint name
10✔
1240
                    index.name = newIndexName
10✔
1241
                })
44✔
1242

44✔
1243
                // rename foreign key constraints
44✔
1244
                clonedTable
44✔
1245
                    .findColumnForeignKeys(oldColumn)
44✔
1246
                    .forEach((foreignKey) => {
44✔
1247
                        const foreignKeyName =
18✔
1248
                            this.connection.namingStrategy.foreignKeyName(
18✔
1249
                                clonedTable,
18✔
1250
                                foreignKey.columnNames,
18✔
1251
                                this.getTablePath(foreignKey),
18✔
1252
                                foreignKey.referencedColumnNames,
18✔
1253
                            )
18✔
1254

18✔
1255
                        // Skip renaming if foreign key has user defined constraint name
18✔
1256
                        if (foreignKey.name !== foreignKeyName) return
18✔
1257

2✔
1258
                        // build new constraint name
2✔
1259
                        foreignKey.columnNames.splice(
2✔
1260
                            foreignKey.columnNames.indexOf(oldColumn.name),
2✔
1261
                            1,
2✔
1262
                        )
2✔
1263
                        foreignKey.columnNames.push(newColumn.name)
2✔
1264
                        const newForeignKeyName =
2✔
1265
                            this.connection.namingStrategy.foreignKeyName(
2✔
1266
                                clonedTable,
2✔
1267
                                foreignKey.columnNames,
2✔
1268
                                this.getTablePath(foreignKey),
2✔
1269
                                foreignKey.referencedColumnNames,
2✔
1270
                            )
2✔
1271

2✔
1272
                        // build queries
2✔
1273
                        upQueries.push(
2✔
1274
                            new Query(
2✔
1275
                                `ALTER TABLE ${this.escapePath(
2✔
1276
                                    table,
2✔
1277
                                )} RENAME CONSTRAINT "${
2✔
1278
                                    foreignKey.name
2✔
1279
                                }" TO "${newForeignKeyName}"`,
2✔
1280
                            ),
2✔
1281
                        )
2✔
1282
                        downQueries.push(
2✔
1283
                            new Query(
2✔
1284
                                `ALTER TABLE ${this.escapePath(
2✔
1285
                                    table,
2✔
1286
                                )} RENAME CONSTRAINT "${newForeignKeyName}" TO "${
2✔
1287
                                    foreignKey.name
2✔
1288
                                }"`,
2✔
1289
                            ),
2✔
1290
                        )
2✔
1291

2✔
1292
                        // replace constraint name
2✔
1293
                        foreignKey.name = newForeignKeyName
2✔
1294
                    })
44✔
1295

44✔
1296
                // rename old column in the Table object
44✔
1297
                const oldTableColumn = clonedTable.columns.find(
44✔
1298
                    (column) => column.name === oldColumn.name,
44✔
1299
                )
44✔
1300
                clonedTable.columns[
44✔
1301
                    clonedTable.columns.indexOf(oldTableColumn!)
44✔
1302
                ].name = newColumn.name
44✔
1303
                oldColumn.name = newColumn.name
44✔
1304
            }
44✔
1305

64✔
1306
            if (this.isColumnChanged(oldColumn, newColumn, true)) {
64✔
1307
                let defaultUp: string = ""
4✔
1308
                let defaultDown: string = ""
4✔
1309
                let nullableUp: string = ""
4✔
1310
                let nullableDown: string = ""
4✔
1311

4✔
1312
                // changing column default
4✔
1313
                if (
4✔
1314
                    newColumn.default !== null &&
4✔
1315
                    newColumn.default !== undefined
4✔
1316
                ) {
4✔
1317
                    defaultUp = `DEFAULT ${newColumn.default}`
4✔
1318

4✔
1319
                    if (
4✔
1320
                        oldColumn.default !== null &&
4✔
1321
                        oldColumn.default !== undefined
4✔
1322
                    ) {
4✔
1323
                        defaultDown = `DEFAULT ${oldColumn.default}`
2✔
1324
                    } else {
2✔
1325
                        defaultDown = "DEFAULT NULL"
2✔
1326
                    }
2✔
1327
                } else if (
4!
1328
                    oldColumn.default !== null &&
×
1329
                    oldColumn.default !== undefined
×
1330
                ) {
×
1331
                    defaultUp = "DEFAULT NULL"
×
1332
                    defaultDown = `DEFAULT ${oldColumn.default}`
×
1333
                }
×
1334

4✔
1335
                // changing column isNullable property
4✔
1336
                if (newColumn.isNullable !== oldColumn.isNullable) {
4!
1337
                    if (newColumn.isNullable === true) {
×
1338
                        nullableUp = "NULL"
×
1339
                        nullableDown = "NOT NULL"
×
1340
                    } else {
×
1341
                        nullableUp = "NOT NULL"
×
1342
                        nullableDown = "NULL"
×
1343
                    }
×
1344
                }
×
1345

4✔
1346
                upQueries.push(
4✔
1347
                    new Query(
4✔
1348
                        `ALTER TABLE ${this.escapePath(table)} MODIFY "${
4✔
1349
                            oldColumn.name
4✔
1350
                        }" ${this.connection.driver.createFullType(
4✔
1351
                            newColumn,
4✔
1352
                        )} ${defaultUp} ${nullableUp}`,
4✔
1353
                    ),
4✔
1354
                )
4✔
1355
                downQueries.push(
4✔
1356
                    new Query(
4✔
1357
                        `ALTER TABLE ${this.escapePath(table)} MODIFY "${
4✔
1358
                            oldColumn.name
4✔
1359
                        }" ${this.connection.driver.createFullType(
4✔
1360
                            oldColumn,
4✔
1361
                        )} ${defaultDown} ${nullableDown}`,
4✔
1362
                    ),
4✔
1363
                )
4✔
1364
            }
4✔
1365

64✔
1366
            if (newColumn.isPrimary !== oldColumn.isPrimary) {
64✔
1367
                const primaryColumns = clonedTable.primaryColumns
6✔
1368

6✔
1369
                // if primary column state changed, we must always drop existed constraint.
6✔
1370
                if (primaryColumns.length > 0) {
6✔
1371
                    const pkName = primaryColumns[0].primaryKeyConstraintName
6✔
1372
                        ? primaryColumns[0].primaryKeyConstraintName
6!
1373
                        : this.connection.namingStrategy.primaryKeyName(
6✔
1374
                              clonedTable,
6✔
1375
                              primaryColumns.map((column) => column.name),
6✔
1376
                          )
6✔
1377

6✔
1378
                    const columnNames = primaryColumns
6✔
1379
                        .map((column) => `"${column.name}"`)
6✔
1380
                        .join(", ")
6✔
1381

6✔
1382
                    upQueries.push(
6✔
1383
                        new Query(
6✔
1384
                            `ALTER TABLE ${this.escapePath(
6✔
1385
                                table,
6✔
1386
                            )} DROP CONSTRAINT "${pkName}"`,
6✔
1387
                        ),
6✔
1388
                    )
6✔
1389
                    downQueries.push(
6✔
1390
                        new Query(
6✔
1391
                            `ALTER TABLE ${this.escapePath(
6✔
1392
                                table,
6✔
1393
                            )} ADD CONSTRAINT "${pkName}" PRIMARY KEY (${columnNames})`,
6✔
1394
                        ),
6✔
1395
                    )
6✔
1396
                }
6✔
1397

6✔
1398
                if (newColumn.isPrimary === true) {
6✔
1399
                    primaryColumns.push(newColumn)
2✔
1400
                    // update column in table
2✔
1401
                    const column = clonedTable.columns.find(
2✔
1402
                        (column) => column.name === newColumn.name,
2✔
1403
                    )
2✔
1404
                    column!.isPrimary = true
2✔
1405
                    const pkName = primaryColumns[0].primaryKeyConstraintName
2✔
1406
                        ? primaryColumns[0].primaryKeyConstraintName
2!
1407
                        : this.connection.namingStrategy.primaryKeyName(
2✔
1408
                              clonedTable,
2✔
1409
                              primaryColumns.map((column) => column.name),
2✔
1410
                          )
2✔
1411

2✔
1412
                    const columnNames = primaryColumns
2✔
1413
                        .map((column) => `"${column.name}"`)
2✔
1414
                        .join(", ")
2✔
1415

2✔
1416
                    upQueries.push(
2✔
1417
                        new Query(
2✔
1418
                            `ALTER TABLE ${this.escapePath(
2✔
1419
                                table,
2✔
1420
                            )} ADD CONSTRAINT "${pkName}" PRIMARY KEY (${columnNames})`,
2✔
1421
                        ),
2✔
1422
                    )
2✔
1423
                    downQueries.push(
2✔
1424
                        new Query(
2✔
1425
                            `ALTER TABLE ${this.escapePath(
2✔
1426
                                table,
2✔
1427
                            )} DROP CONSTRAINT "${pkName}"`,
2✔
1428
                        ),
2✔
1429
                    )
2✔
1430
                } else {
6✔
1431
                    const primaryColumn = primaryColumns.find(
4✔
1432
                        (c) => c.name === newColumn.name,
4✔
1433
                    )
4✔
1434
                    primaryColumns.splice(
4✔
1435
                        primaryColumns.indexOf(primaryColumn!),
4✔
1436
                        1,
4✔
1437
                    )
4✔
1438

4✔
1439
                    // update column in table
4✔
1440
                    const column = clonedTable.columns.find(
4✔
1441
                        (column) => column.name === newColumn.name,
4✔
1442
                    )
4✔
1443
                    column!.isPrimary = false
4✔
1444

4✔
1445
                    // if we have another primary keys, we must recreate constraint.
4✔
1446
                    if (primaryColumns.length > 0) {
4✔
1447
                        const pkName = primaryColumns[0]
2✔
1448
                            .primaryKeyConstraintName
2✔
1449
                            ? primaryColumns[0].primaryKeyConstraintName
2!
1450
                            : this.connection.namingStrategy.primaryKeyName(
2✔
1451
                                  clonedTable,
2✔
1452
                                  primaryColumns.map((column) => column.name),
2✔
1453
                              )
2✔
1454

2✔
1455
                        const columnNames = primaryColumns
2✔
1456
                            .map((column) => `"${column.name}"`)
2✔
1457
                            .join(", ")
2✔
1458

2✔
1459
                        upQueries.push(
2✔
1460
                            new Query(
2✔
1461
                                `ALTER TABLE ${this.escapePath(
2✔
1462
                                    table,
2✔
1463
                                )} ADD CONSTRAINT "${pkName}" PRIMARY KEY (${columnNames})`,
2✔
1464
                            ),
2✔
1465
                        )
2✔
1466
                        downQueries.push(
2✔
1467
                            new Query(
2✔
1468
                                `ALTER TABLE ${this.escapePath(
2✔
1469
                                    table,
2✔
1470
                                )} DROP CONSTRAINT "${pkName}"`,
2✔
1471
                            ),
2✔
1472
                        )
2✔
1473
                    }
2✔
1474
                }
4✔
1475
            }
6✔
1476

64✔
1477
            if (newColumn.isUnique !== oldColumn.isUnique) {
64✔
1478
                if (newColumn.isUnique === true) {
2✔
1479
                    const uniqueConstraint = new TableUnique({
2✔
1480
                        name: this.connection.namingStrategy.uniqueConstraintName(
2✔
1481
                            table,
2✔
1482
                            [newColumn.name],
2✔
1483
                        ),
2✔
1484
                        columnNames: [newColumn.name],
2✔
1485
                    })
2✔
1486
                    clonedTable.uniques.push(uniqueConstraint)
2✔
1487
                    upQueries.push(
2✔
1488
                        new Query(
2✔
1489
                            `ALTER TABLE ${this.escapePath(
2✔
1490
                                table,
2✔
1491
                            )} ADD CONSTRAINT "${
2✔
1492
                                uniqueConstraint.name
2✔
1493
                            }" UNIQUE ("${newColumn.name}")`,
2✔
1494
                        ),
2✔
1495
                    )
2✔
1496
                    downQueries.push(
2✔
1497
                        new Query(
2✔
1498
                            `ALTER TABLE ${this.escapePath(
2✔
1499
                                table,
2✔
1500
                            )} DROP CONSTRAINT "${uniqueConstraint.name}"`,
2✔
1501
                        ),
2✔
1502
                    )
2✔
1503
                } else {
2!
1504
                    const uniqueConstraint = clonedTable.uniques.find(
×
1505
                        (unique) => {
×
1506
                            return (
×
1507
                                unique.columnNames.length === 1 &&
×
1508
                                !!unique.columnNames.find(
×
1509
                                    (columnName) =>
×
1510
                                        columnName === newColumn.name,
×
1511
                                )
×
1512
                            )
×
1513
                        },
×
1514
                    )
×
1515
                    clonedTable.uniques.splice(
×
1516
                        clonedTable.uniques.indexOf(uniqueConstraint!),
×
1517
                        1,
×
1518
                    )
×
1519
                    upQueries.push(
×
1520
                        new Query(
×
1521
                            `ALTER TABLE ${this.escapePath(
×
1522
                                table,
×
1523
                            )} DROP CONSTRAINT "${uniqueConstraint!.name}"`,
×
1524
                        ),
×
1525
                    )
×
1526
                    downQueries.push(
×
1527
                        new Query(
×
1528
                            `ALTER TABLE ${this.escapePath(
×
1529
                                table,
×
1530
                            )} ADD CONSTRAINT "${
×
1531
                                uniqueConstraint!.name
×
1532
                            }" UNIQUE ("${newColumn.name}")`,
×
1533
                        ),
×
1534
                    )
×
1535
                }
×
1536
            }
2✔
1537

64✔
1538
            await this.executeQueries(upQueries, downQueries)
64✔
1539
            this.replaceCachedTable(table, clonedTable)
64✔
1540
        }
64✔
1541
    }
96✔
1542

26✔
1543
    /**
26✔
1544
     * Changes a column in the table.
26✔
1545
     */
26✔
1546
    async changeColumns(
26✔
1547
        tableOrName: Table | string,
46✔
1548
        changedColumns: { newColumn: TableColumn; oldColumn: TableColumn }[],
46✔
1549
    ): Promise<void> {
46✔
1550
        for (const { oldColumn, newColumn } of changedColumns) {
46✔
1551
            await this.changeColumn(tableOrName, oldColumn, newColumn)
58✔
1552
        }
58✔
1553
    }
46✔
1554

26✔
1555
    /**
26✔
1556
     * Drops column in the table.
26✔
1557
     */
26✔
1558
    async dropColumn(
26✔
1559
        tableOrName: Table | string,
66✔
1560
        columnOrName: TableColumn | string,
66✔
1561
    ): Promise<void> {
66✔
1562
        const table = InstanceChecker.isTable(tableOrName)
66✔
1563
            ? tableOrName
66✔
1564
            : await this.getCachedTable(tableOrName)
66✔
1565
        const column = InstanceChecker.isTableColumn(columnOrName)
6✔
1566
            ? columnOrName
66✔
1567
            : table.findColumnByName(columnOrName)
66✔
1568
        if (!column)
66✔
1569
            throw new TypeORMError(
66✔
1570
                `Column "${columnOrName}" was not found in table ${this.escapePath(
2✔
1571
                    table,
2✔
1572
                )}`,
2✔
1573
            )
2✔
1574

64✔
1575
        const clonedTable = table.clone()
64✔
1576
        const upQueries: Query[] = []
64✔
1577
        const downQueries: Query[] = []
64✔
1578

64✔
1579
        // drop primary key constraint
64✔
1580
        if (column.isPrimary) {
66✔
1581
            const pkName = column.primaryKeyConstraintName
14✔
1582
                ? column.primaryKeyConstraintName
14!
1583
                : this.connection.namingStrategy.primaryKeyName(
14✔
1584
                      clonedTable,
14✔
1585
                      clonedTable.primaryColumns.map((column) => column.name),
14✔
1586
                  )
14✔
1587

14✔
1588
            const columnNames = clonedTable.primaryColumns
14✔
1589
                .map((primaryColumn) => `"${primaryColumn.name}"`)
14✔
1590
                .join(", ")
14✔
1591

14✔
1592
            upQueries.push(
14✔
1593
                new Query(
14✔
1594
                    `ALTER TABLE ${this.escapePath(
14✔
1595
                        clonedTable,
14✔
1596
                    )} DROP CONSTRAINT "${pkName}"`,
14✔
1597
                ),
14✔
1598
            )
14✔
1599
            downQueries.push(
14✔
1600
                new Query(
14✔
1601
                    `ALTER TABLE ${this.escapePath(
14✔
1602
                        clonedTable,
14✔
1603
                    )} ADD CONSTRAINT "${pkName}" PRIMARY KEY (${columnNames})`,
14✔
1604
                ),
14✔
1605
            )
14✔
1606

14✔
1607
            // update column in table
14✔
1608
            const tableColumn = clonedTable.findColumnByName(column.name)
14✔
1609
            tableColumn!.isPrimary = false
14✔
1610

14✔
1611
            // if primary key have multiple columns, we must recreate it without dropped column
14✔
1612
            if (clonedTable.primaryColumns.length > 0) {
14!
1613
                const pkName = clonedTable.primaryColumns[0]
×
1614
                    .primaryKeyConstraintName
×
1615
                    ? clonedTable.primaryColumns[0].primaryKeyConstraintName
×
1616
                    : this.connection.namingStrategy.primaryKeyName(
×
1617
                          clonedTable,
×
1618
                          clonedTable.primaryColumns.map(
×
1619
                              (column) => column.name,
×
1620
                          ),
×
1621
                      )
×
1622

×
1623
                const columnNames = clonedTable.primaryColumns
×
1624
                    .map((primaryColumn) => `"${primaryColumn.name}"`)
×
1625
                    .join(", ")
×
1626

×
1627
                upQueries.push(
×
1628
                    new Query(
×
1629
                        `ALTER TABLE ${this.escapePath(
×
1630
                            clonedTable,
×
1631
                        )} ADD CONSTRAINT "${pkName}" PRIMARY KEY (${columnNames})`,
×
1632
                    ),
×
1633
                )
×
1634
                downQueries.push(
×
1635
                    new Query(
×
1636
                        `ALTER TABLE ${this.escapePath(
×
1637
                            clonedTable,
×
1638
                        )} DROP CONSTRAINT "${pkName}"`,
×
1639
                    ),
×
1640
                )
×
1641
            }
×
1642
        }
14✔
1643

64✔
1644
        // drop column index
64✔
1645
        const columnIndex = clonedTable.indices.find(
64✔
1646
            (index) =>
64✔
1647
                index.columnNames.length === 1 &&
2✔
1648
                index.columnNames[0] === column.name,
64✔
1649
        )
64✔
1650
        if (columnIndex) {
66!
1651
            upQueries.push(this.dropIndexSql(columnIndex))
×
1652
            downQueries.push(this.createIndexSql(table, columnIndex))
×
1653
        }
×
1654

64✔
1655
        // drop column check
64✔
1656
        const columnCheck = clonedTable.checks.find(
64✔
1657
            (check) =>
64✔
1658
                !!check.columnNames &&
32✔
1659
                check.columnNames.length === 1 &&
32✔
1660
                check.columnNames[0] === column.name,
64✔
1661
        )
64✔
1662
        if (columnCheck) {
66✔
1663
            clonedTable.checks.splice(
4✔
1664
                clonedTable.checks.indexOf(columnCheck),
4✔
1665
                1,
4✔
1666
            )
4✔
1667
            upQueries.push(this.dropCheckConstraintSql(table, columnCheck))
4✔
1668
            downQueries.push(this.createCheckConstraintSql(table, columnCheck))
4✔
1669
        }
4✔
1670

64✔
1671
        // drop column unique
64✔
1672
        const columnUnique = clonedTable.uniques.find(
64✔
1673
            (unique) =>
64✔
1674
                unique.columnNames.length === 1 &&
54✔
1675
                unique.columnNames[0] === column.name,
64✔
1676
        )
64✔
1677
        if (columnUnique) {
66✔
1678
            clonedTable.uniques.splice(
6✔
1679
                clonedTable.uniques.indexOf(columnUnique),
6✔
1680
                1,
6✔
1681
            )
6✔
1682
            upQueries.push(this.dropUniqueConstraintSql(table, columnUnique))
6✔
1683
            downQueries.push(
6✔
1684
                this.createUniqueConstraintSql(table, columnUnique),
6✔
1685
            )
6✔
1686
        }
6✔
1687

64✔
1688
        upQueries.push(
64✔
1689
            new Query(
64✔
1690
                `ALTER TABLE ${this.escapePath(table)} DROP COLUMN "${
64✔
1691
                    column.name
64✔
1692
                }"`,
64✔
1693
            ),
64✔
1694
        )
64✔
1695
        downQueries.push(
64✔
1696
            new Query(
64✔
1697
                `ALTER TABLE ${this.escapePath(
64✔
1698
                    table,
64✔
1699
                )} ADD ${this.buildCreateColumnSql(column)}`,
64✔
1700
            ),
64✔
1701
        )
64✔
1702

64✔
1703
        if (column.generatedType && column.asExpression) {
66✔
1704
            const deleteQuery = this.deleteTypeormMetadataSql({
6✔
1705
                table: table.name,
6✔
1706
                type: MetadataTableType.GENERATED_COLUMN,
6✔
1707
                name: column.name,
6✔
1708
            })
6✔
1709
            const insertQuery = this.insertTypeormMetadataSql({
6✔
1710
                table: table.name,
6✔
1711
                type: MetadataTableType.GENERATED_COLUMN,
6✔
1712
                name: column.name,
6✔
1713
                value: column.asExpression,
6✔
1714
            })
6✔
1715

6✔
1716
            upQueries.push(deleteQuery)
6✔
1717
            downQueries.push(insertQuery)
6✔
1718
        }
6✔
1719

64✔
1720
        await this.executeQueries(upQueries, downQueries)
64✔
1721

64✔
1722
        clonedTable.removeColumn(column)
64✔
1723
        this.replaceCachedTable(table, clonedTable)
64✔
1724
    }
64✔
1725

26✔
1726
    /**
26✔
1727
     * Drops the columns in the table.
26✔
1728
     */
26✔
1729
    async dropColumns(
26✔
1730
        tableOrName: Table | string,
10✔
1731
        columns: TableColumn[] | string[],
10✔
1732
    ): Promise<void> {
10✔
1733
        for (const column of [...columns]) {
10✔
1734
            await this.dropColumn(tableOrName, column)
26✔
1735
        }
26✔
1736
    }
10✔
1737

26✔
1738
    /**
26✔
1739
     * Creates a new primary key.
26✔
1740
     */
26✔
1741
    async createPrimaryKey(
26✔
1742
        tableOrName: Table | string,
4✔
1743
        columnNames: string[],
4✔
1744
        constraintName?: string,
4✔
1745
    ): Promise<void> {
4✔
1746
        const table = InstanceChecker.isTable(tableOrName)
4✔
1747
            ? tableOrName
4!
1748
            : await this.getCachedTable(tableOrName)
4✔
1749
        const clonedTable = table.clone()
4✔
1750

4✔
1751
        const up = this.createPrimaryKeySql(table, columnNames, constraintName)
4✔
1752

4✔
1753
        // mark columns as primary, because dropPrimaryKeySql build constraint name from table primary column names.
4✔
1754
        clonedTable.columns.forEach((column) => {
4✔
1755
            if (columnNames.find((columnName) => columnName === column.name))
10✔
1756
                column.isPrimary = true
10✔
1757
        })
4✔
1758
        const down = this.dropPrimaryKeySql(clonedTable)
4✔
1759

4✔
1760
        await this.executeQueries(up, down)
4✔
1761
        this.replaceCachedTable(table, clonedTable)
4✔
1762
    }
4✔
1763

26✔
1764
    /**
26✔
1765
     * Updates composite primary keys.
26✔
1766
     */
26✔
1767
    async updatePrimaryKeys(
26✔
1768
        tableOrName: Table | string,
4✔
1769
        columns: TableColumn[],
4✔
1770
    ): Promise<void> {
4✔
1771
        const table = InstanceChecker.isTable(tableOrName)
4✔
1772
            ? tableOrName
4✔
1773
            : await this.getCachedTable(tableOrName)
4!
1774
        const columnNames = columns.map((column) => column.name)
×
1775
        const clonedTable = table.clone()
×
1776
        const upQueries: Query[] = []
×
1777
        const downQueries: Query[] = []
×
1778

×
1779
        // if table already have primary columns, we must drop them.
×
1780
        const primaryColumns = clonedTable.primaryColumns
×
1781
        if (primaryColumns.length > 0) {
4✔
1782
            const pkName = primaryColumns[0].primaryKeyConstraintName
4✔
1783
                ? primaryColumns[0].primaryKeyConstraintName
4!
1784
                : this.connection.namingStrategy.primaryKeyName(
4✔
1785
                      clonedTable,
4✔
1786
                      primaryColumns.map((column) => column.name),
4✔
1787
                  )
4✔
1788

4✔
1789
            const columnNamesString = primaryColumns
4✔
1790
                .map((column) => `"${column.name}"`)
4✔
1791
                .join(", ")
4✔
1792

4✔
1793
            upQueries.push(
4✔
1794
                new Query(
4✔
1795
                    `ALTER TABLE ${this.escapePath(
4✔
1796
                        table,
4✔
1797
                    )} DROP CONSTRAINT "${pkName}"`,
4✔
1798
                ),
4✔
1799
            )
4✔
1800
            downQueries.push(
4✔
1801
                new Query(
4✔
1802
                    `ALTER TABLE ${this.escapePath(
4✔
1803
                        table,
4✔
1804
                    )} ADD CONSTRAINT "${pkName}" PRIMARY KEY (${columnNamesString})`,
4✔
1805
                ),
4✔
1806
            )
4✔
1807
        }
4✔
1808

4✔
1809
        // update columns in table.
4✔
1810
        clonedTable.columns
4✔
1811
            .filter((column) => columnNames.indexOf(column.name) !== -1)
4✔
1812
            .forEach((column) => (column.isPrimary = true))
4✔
1813

4✔
1814
        const pkName = primaryColumns[0].primaryKeyConstraintName
4✔
1815
            ? primaryColumns[0].primaryKeyConstraintName
4!
1816
            : this.connection.namingStrategy.primaryKeyName(
4✔
1817
                  clonedTable,
4✔
1818
                  columnNames,
4✔
1819
              )
4✔
1820

4✔
1821
        const columnNamesString = columnNames
4✔
1822
            .map((columnName) => `"${columnName}"`)
4✔
1823
            .join(", ")
4✔
1824
        upQueries.push(
4✔
1825
            new Query(
4✔
1826
                `ALTER TABLE ${this.escapePath(
4✔
1827
                    table,
4✔
1828
                )} ADD CONSTRAINT "${pkName}" PRIMARY KEY (${columnNamesString})`,
4✔
1829
            ),
4✔
1830
        )
4✔
1831
        downQueries.push(
4✔
1832
            new Query(
4✔
1833
                `ALTER TABLE ${this.escapePath(
4✔
1834
                    table,
4✔
1835
                )} DROP CONSTRAINT "${pkName}"`,
4✔
1836
            ),
4✔
1837
        )
4✔
1838

4✔
1839
        await this.executeQueries(upQueries, downQueries)
4✔
1840
        this.replaceCachedTable(table, clonedTable)
4✔
1841
    }
4✔
1842

26✔
1843
    /**
26✔
1844
     * Drops a primary key.
26✔
1845
     */
26✔
1846
    async dropPrimaryKey(
26✔
1847
        tableOrName: Table | string,
6✔
1848
        constraintName?: string,
6✔
1849
    ): Promise<void> {
6✔
1850
        const table = InstanceChecker.isTable(tableOrName)
6✔
1851
            ? tableOrName
6✔
1852
            : await this.getCachedTable(tableOrName)
6!
1853
        const up = this.dropPrimaryKeySql(table)
×
1854
        const down = this.createPrimaryKeySql(
×
1855
            table,
×
1856
            table.primaryColumns.map((column) => column.name),
✔
1857
            constraintName,
×
1858
        )
×
1859
        await this.executeQueries(up, down)
×
1860
        table.primaryColumns.forEach((column) => {
6✔
1861
            column.isPrimary = false
6✔
1862
        })
6✔
1863
    }
6✔
1864

26✔
1865
    /**
26✔
1866
     * Creates a new unique constraint.
26✔
1867
     */
26✔
1868
    async createUniqueConstraint(
26✔
1869
        tableOrName: Table | string,
16✔
1870
        uniqueConstraint: TableUnique,
16✔
1871
    ): Promise<void> {
16✔
1872
        const table = InstanceChecker.isTable(tableOrName)
16✔
1873
            ? tableOrName
16✔
1874
            : await this.getCachedTable(tableOrName)
16✔
1875

12✔
1876
        // new unique constraint may be passed without name. In this case we generate unique name manually.
12✔
1877
        if (!uniqueConstraint.name)
12✔
1878
            uniqueConstraint.name =
16✔
1879
                this.connection.namingStrategy.uniqueConstraintName(
4✔
1880
                    table,
4✔
1881
                    uniqueConstraint.columnNames,
4✔
1882
                )
4✔
1883

16✔
1884
        const up = this.createUniqueConstraintSql(table, uniqueConstraint)
16✔
1885
        const down = this.dropUniqueConstraintSql(table, uniqueConstraint)
16✔
1886
        await this.executeQueries(up, down)
16✔
1887
        table.addUniqueConstraint(uniqueConstraint)
16✔
1888
    }
16✔
1889

26✔
1890
    /**
26✔
1891
     * Creates a new unique constraints.
26✔
1892
     */
26✔
1893
    async createUniqueConstraints(
26✔
1894
        tableOrName: Table | string,
6✔
1895
        uniqueConstraints: TableUnique[],
6✔
1896
    ): Promise<void> {
6✔
1897
        const promises = uniqueConstraints.map((uniqueConstraint) =>
6✔
1898
            this.createUniqueConstraint(tableOrName, uniqueConstraint),
6✔
1899
        )
6✔
1900
        await Promise.all(promises)
6✔
1901
    }
6✔
1902

26✔
1903
    /**
26✔
1904
     * Drops a unique constraint.
26✔
1905
     */
26✔
1906
    async dropUniqueConstraint(
26✔
1907
        tableOrName: Table | string,
16✔
1908
        uniqueOrName: TableUnique | string,
16✔
1909
    ): Promise<void> {
16✔
1910
        const table = InstanceChecker.isTable(tableOrName)
16✔
1911
            ? tableOrName
16✔
1912
            : await this.getCachedTable(tableOrName)
16✔
1913
        const uniqueConstraint = InstanceChecker.isTableUnique(uniqueOrName)
8✔
1914
            ? uniqueOrName
16✔
1915
            : table.uniques.find((u) => u.name === uniqueOrName)
16!
1916
        if (!uniqueConstraint)
16✔
1917
            throw new TypeORMError(
16!
1918
                `Supplied unique constraint was not found in table ${table.name}`,
×
1919
            )
×
1920

16✔
1921
        const up = this.dropUniqueConstraintSql(table, uniqueConstraint)
16✔
1922
        const down = this.createUniqueConstraintSql(table, uniqueConstraint)
16✔
1923
        await this.executeQueries(up, down)
16✔
1924
        table.removeUniqueConstraint(uniqueConstraint)
16✔
1925
    }
16✔
1926

26✔
1927
    /**
26✔
1928
     * Creates a unique constraints.
26✔
1929
     */
26✔
1930
    async dropUniqueConstraints(
26✔
1931
        tableOrName: Table | string,
8✔
1932
        uniqueConstraints: TableUnique[],
8✔
1933
    ): Promise<void> {
8✔
1934
        const promises = uniqueConstraints.map((uniqueConstraint) =>
8✔
1935
            this.dropUniqueConstraint(tableOrName, uniqueConstraint),
8✔
1936
        )
8✔
1937
        await Promise.all(promises)
8✔
1938
    }
8✔
1939

26✔
1940
    /**
26✔
1941
     * Creates new check constraint.
26✔
1942
     */
26✔
1943
    async createCheckConstraint(
26✔
1944
        tableOrName: Table | string,
10✔
1945
        checkConstraint: TableCheck,
10✔
1946
    ): Promise<void> {
10✔
1947
        const table = InstanceChecker.isTable(tableOrName)
10✔
1948
            ? tableOrName
10✔
1949
            : await this.getCachedTable(tableOrName)
10✔
1950

6✔
1951
        // new unique constraint may be passed without name. In this case we generate unique name manually.
6✔
1952
        if (!checkConstraint.name)
6✔
1953
            checkConstraint.name =
6✔
1954
                this.connection.namingStrategy.checkConstraintName(
6✔
1955
                    table,
6✔
1956
                    checkConstraint.expression!,
6✔
1957
                )
6✔
1958

10✔
1959
        const up = this.createCheckConstraintSql(table, checkConstraint)
10✔
1960
        const down = this.dropCheckConstraintSql(table, checkConstraint)
10✔
1961
        await this.executeQueries(up, down)
10✔
1962
        table.addCheckConstraint(checkConstraint)
10✔
1963
    }
10✔
1964

26✔
1965
    /**
26✔
1966
     * Creates new check constraints.
26✔
1967
     */
26✔
1968
    async createCheckConstraints(
26✔
1969
        tableOrName: Table | string,
4✔
1970
        checkConstraints: TableCheck[],
4✔
1971
    ): Promise<void> {
4✔
1972
        const promises = checkConstraints.map((checkConstraint) =>
4✔
1973
            this.createCheckConstraint(tableOrName, checkConstraint),
4✔
1974
        )
4✔
1975
        await Promise.all(promises)
4✔
1976
    }
4✔
1977

26✔
1978
    /**
26✔
1979
     * Drops check constraint.
26✔
1980
     */
26✔
1981
    async dropCheckConstraint(
26✔
1982
        tableOrName: Table | string,
6✔
1983
        checkOrName: TableCheck | string,
6✔
1984
    ): Promise<void> {
6✔
1985
        const table = InstanceChecker.isTable(tableOrName)
6✔
1986
            ? tableOrName
6✔
1987
            : await this.getCachedTable(tableOrName)
6!
1988
        const checkConstraint = InstanceChecker.isTableCheck(checkOrName)
×
1989
            ? checkOrName
6✔
1990
            : table.checks.find((c) => c.name === checkOrName)
6!
1991
        if (!checkConstraint)
6✔
1992
            throw new TypeORMError(
6!
1993
                `Supplied check constraint was not found in table ${table.name}`,
×
1994
            )
×
1995

6✔
1996
        const up = this.dropCheckConstraintSql(table, checkConstraint)
6✔
1997
        const down = this.createCheckConstraintSql(table, checkConstraint)
6✔
1998
        await this.executeQueries(up, down)
6✔
1999
        table.removeCheckConstraint(checkConstraint)
6✔
2000
    }
6✔
2001

26✔
2002
    /**
26✔
2003
     * Drops check constraints.
26✔
2004
     */
26✔
2005
    async dropCheckConstraints(
26✔
2006
        tableOrName: Table | string,
4✔
2007
        checkConstraints: TableCheck[],
4✔
2008
    ): Promise<void> {
4✔
2009
        const promises = checkConstraints.map((checkConstraint) =>
4✔
2010
            this.dropCheckConstraint(tableOrName, checkConstraint),
4✔
2011
        )
4✔
2012
        await Promise.all(promises)
4✔
2013
    }
4✔
2014

26✔
2015
    /**
26✔
2016
     * Creates a new exclusion constraint.
26✔
2017
     */
26✔
2018
    async createExclusionConstraint(
26✔
2019
        tableOrName: Table | string,
×
2020
        exclusionConstraint: TableExclusion,
×
2021
    ): Promise<void> {
×
2022
        throw new TypeORMError(`Oracle does not support exclusion constraints.`)
×
2023
    }
×
2024

26✔
2025
    /**
26✔
2026
     * Creates a new exclusion constraints.
26✔
2027
     */
26✔
2028
    async createExclusionConstraints(
26✔
2029
        tableOrName: Table | string,
×
2030
        exclusionConstraints: TableExclusion[],
×
2031
    ): Promise<void> {
×
2032
        throw new TypeORMError(`Oracle does not support exclusion constraints.`)
×
2033
    }
×
2034

26✔
2035
    /**
26✔
2036
     * Drops exclusion constraint.
26✔
2037
     */
26✔
2038
    async dropExclusionConstraint(
26✔
2039
        tableOrName: Table | string,
×
2040
        exclusionOrName: TableExclusion | string,
×
2041
    ): Promise<void> {
×
2042
        throw new TypeORMError(`Oracle does not support exclusion constraints.`)
×
2043
    }
×
2044

26✔
2045
    /**
26✔
2046
     * Drops exclusion constraints.
26✔
2047
     */
26✔
2048
    async dropExclusionConstraints(
26✔
2049
        tableOrName: Table | string,
×
2050
        exclusionConstraints: TableExclusion[],
×
2051
    ): Promise<void> {
×
2052
        throw new TypeORMError(`Oracle does not support exclusion constraints.`)
×
2053
    }
×
2054

26✔
2055
    /**
26✔
2056
     * Creates a new foreign key.
26✔
2057
     */
26✔
2058
    async createForeignKey(
26✔
2059
        tableOrName: Table | string,
5,722✔
2060
        foreignKey: TableForeignKey,
5,722✔
2061
    ): Promise<void> {
5,722✔
2062
        const table = InstanceChecker.isTable(tableOrName)
5,722✔
2063
            ? tableOrName
5,722✔
2064
            : await this.getCachedTable(tableOrName)
5,722✔
2065

10✔
2066
        // new FK may be passed without name. In this case we generate FK name manually.
10✔
2067
        if (!foreignKey.name)
10✔
2068
            foreignKey.name = this.connection.namingStrategy.foreignKeyName(
5,722✔
2069
                table,
2✔
2070
                foreignKey.columnNames,
2✔
2071
                this.getTablePath(foreignKey),
2✔
2072
                foreignKey.referencedColumnNames,
2✔
2073
            )
2✔
2074

5,722✔
2075
        const up = this.createForeignKeySql(table, foreignKey)
5,722✔
2076
        const down = this.dropForeignKeySql(table, foreignKey)
5,722✔
2077
        await this.executeQueries(up, down)
5,722✔
2078
        table.addForeignKey(foreignKey)
5,722✔
2079
    }
5,722✔
2080

26✔
2081
    /**
26✔
2082
     * Creates a new foreign keys.
26✔
2083
     */
26✔
2084
    async createForeignKeys(
26✔
2085
        tableOrName: Table | string,
3,328✔
2086
        foreignKeys: TableForeignKey[],
3,328✔
2087
    ): Promise<void> {
3,328✔
2088
        const promises = foreignKeys.map((foreignKey) =>
3,328✔
2089
            this.createForeignKey(tableOrName, foreignKey),
3,328✔
2090
        )
3,328✔
2091
        await Promise.all(promises)
3,328✔
2092
    }
3,328✔
2093

26✔
2094
    /**
26✔
2095
     * Drops a foreign key from the table.
26✔
2096
     */
26✔
2097
    async dropForeignKey(
26✔
2098
        tableOrName: Table | string,
20✔
2099
        foreignKeyOrName: TableForeignKey | string,
20✔
2100
    ): Promise<void> {
20✔
2101
        const table = InstanceChecker.isTable(tableOrName)
20✔
2102
            ? tableOrName
20✔
2103
            : await this.getCachedTable(tableOrName)
20✔
2104
        const foreignKey = InstanceChecker.isTableForeignKey(foreignKeyOrName)
8✔
2105
            ? foreignKeyOrName
20✔
2106
            : table.foreignKeys.find((fk) => fk.name === foreignKeyOrName)
20!
2107
        if (!foreignKey)
20✔
2108
            throw new TypeORMError(
20!
2109
                `Supplied foreign key was not found in table ${table.name}`,
×
2110
            )
×
2111

20✔
2112
        const up = this.dropForeignKeySql(table, foreignKey)
20✔
2113
        const down = this.createForeignKeySql(table, foreignKey)
20✔
2114
        await this.executeQueries(up, down)
20✔
2115
        table.removeForeignKey(foreignKey)
20✔
2116
    }
20✔
2117

26✔
2118
    /**
26✔
2119
     * Drops a foreign keys from the table.
26✔
2120
     */
26✔
2121
    async dropForeignKeys(
26✔
2122
        tableOrName: Table | string,
12✔
2123
        foreignKeys: TableForeignKey[],
12✔
2124
    ): Promise<void> {
12✔
2125
        const promises = foreignKeys.map((foreignKey) =>
12✔
2126
            this.dropForeignKey(tableOrName, foreignKey),
12✔
2127
        )
12✔
2128
        await Promise.all(promises)
12✔
2129
    }
12✔
2130

26✔
2131
    /**
26✔
2132
     * Creates a new index.
26✔
2133
     */
26✔
2134
    async createIndex(
26✔
2135
        tableOrName: Table | string,
28✔
2136
        index: TableIndex,
28✔
2137
    ): Promise<void> {
28✔
2138
        const table = InstanceChecker.isTable(tableOrName)
28✔
2139
            ? tableOrName
28✔
2140
            : await this.getCachedTable(tableOrName)
28✔
2141

14✔
2142
        // new index may be passed without name. In this case we generate index name manually.
14✔
2143
        if (!index.name) index.name = this.generateIndexName(table, index)
28✔
2144

28✔
2145
        const up = this.createIndexSql(table, index)
28✔
2146
        const down = this.dropIndexSql(index)
28✔
2147
        await this.executeQueries(up, down)
28✔
2148
        table.addIndex(index)
28✔
2149
    }
28✔
2150

26✔
2151
    /**
26✔
2152
     * Creates a new indices
26✔
2153
     */
26✔
2154
    async createIndices(
26✔
2155
        tableOrName: Table | string,
14✔
2156
        indices: TableIndex[],
14✔
2157
    ): Promise<void> {
14✔
2158
        const promises = indices.map((index) =>
14✔
2159
            this.createIndex(tableOrName, index),
14✔
2160
        )
14✔
2161
        await Promise.all(promises)
14✔
2162
    }
14✔
2163

26✔
2164
    /**
26✔
2165
     * Drops an index from the table.
26✔
2166
     */
26✔
2167
    async dropIndex(
26✔
2168
        tableOrName: Table | string,
28✔
2169
        indexOrName: TableIndex | string,
28✔
2170
    ): Promise<void> {
28✔
2171
        const table = InstanceChecker.isTable(tableOrName)
28✔
2172
            ? tableOrName
28✔
2173
            : await this.getCachedTable(tableOrName)
28✔
2174
        const index = InstanceChecker.isTableIndex(indexOrName)
10✔
2175
            ? indexOrName
28✔
2176
            : table.indices.find((i) => i.name === indexOrName)
28!
2177
        if (!index)
28✔
2178
            throw new TypeORMError(
28!
2179
                `Supplied index ${indexOrName} was not found in table ${table.name}`,
×
2180
            )
×
2181
        // old index may be passed without name. In this case we generate index name manually.
28✔
2182
        if (!index.name) index.name = this.generateIndexName(table, index)
28✔
2183

28✔
2184
        const up = this.dropIndexSql(index)
28✔
2185
        const down = this.createIndexSql(table, index)
28✔
2186
        await this.executeQueries(up, down)
28✔
2187
        table.removeIndex(index)
28✔
2188
    }
28✔
2189

26✔
2190
    /**
26✔
2191
     * Drops an indices from the table.
26✔
2192
     */
26✔
2193
    async dropIndices(
26✔
2194
        tableOrName: Table | string,
2✔
2195
        indices: TableIndex[],
2✔
2196
    ): Promise<void> {
2✔
2197
        const promises = indices.map((index) =>
2✔
2198
            this.dropIndex(tableOrName, index),
2✔
2199
        )
2✔
2200
        await Promise.all(promises)
2✔
2201
    }
2✔
2202

26✔
2203
    /**
26✔
2204
     * Clears all table contents.
26✔
2205
     * Note: this operation uses SQL's TRUNCATE query which cannot be reverted in transactions.
26✔
2206
     */
26✔
2207
    async clearTable(tableName: string): Promise<void> {
26✔
2208
        await this.query(`TRUNCATE TABLE ${this.escapePath(tableName)}`)
4✔
2209
    }
4✔
2210

26✔
2211
    /**
26✔
2212
     * Removes all tables from the currently connected database.
26✔
2213
     */
26✔
2214
    async clearDatabase(): Promise<void> {
26✔
2215
        const isAnotherTransactionActive = this.isTransactionActive
2,612✔
2216
        if (!isAnotherTransactionActive) await this.startTransaction()
2,612✔
2217
        try {
2,612✔
2218
            // drop views
2,612✔
2219
            const dropViewsQuery = `SELECT 'DROP VIEW "' || VIEW_NAME || '"' AS "query" FROM "USER_VIEWS"`
2,612✔
2220
            const dropViewQueries: ObjectLiteral[] =
2,612✔
2221
                await this.query(dropViewsQuery)
2,612✔
2222
            await Promise.all(
2,612✔
2223
                dropViewQueries.map((query) => this.query(query["query"])),
2,612✔
2224
            )
2,612✔
2225

2,612✔
2226
            // drop materialized views
2,612✔
2227
            const dropMatViewsQuery = `SELECT 'DROP MATERIALIZED VIEW "' || MVIEW_NAME || '"' AS "query" FROM "USER_MVIEWS"`
2,612✔
2228
            const dropMatViewQueries: ObjectLiteral[] =
2,612✔
2229
                await this.query(dropMatViewsQuery)
2,612✔
2230
            await Promise.all(
2,612✔
2231
                dropMatViewQueries.map((query) => this.query(query["query"])),
2,612✔
2232
            )
2,612✔
2233

2,612✔
2234
            // drop tables
2,612✔
2235
            const dropTablesQuery = `SELECT 'DROP TABLE "' || TABLE_NAME || '" CASCADE CONSTRAINTS' AS "query" FROM "USER_TABLES"`
2,612✔
2236
            const dropTableQueries: ObjectLiteral[] =
2,612✔
2237
                await this.query(dropTablesQuery)
2,612✔
2238
            await Promise.all(
2,612✔
2239
                dropTableQueries.map((query) => this.query(query["query"])),
2,612✔
2240
            )
2,612✔
2241
            if (!isAnotherTransactionActive) await this.commitTransaction()
2,612✔
2242
        } catch (error) {
2,612!
UNCOV
2243
            try {
×
UNCOV
2244
                // we throw original error even if rollback thrown an error
×
UNCOV
2245
                if (!isAnotherTransactionActive)
×
2246
                    await this.rollbackTransaction()
×
2247
            } catch (rollbackError) {}
×
2248
            throw error
×
2249
        }
×
2250
    }
2,612✔
2251

26✔
2252
    // -------------------------------------------------------------------------
26✔
2253
    // Protected Methods
26✔
2254
    // -------------------------------------------------------------------------
26✔
2255

26✔
2256
    protected async loadViews(viewNames?: string[]): Promise<View[]> {
26✔
2257
        const hasTable = await this.hasTable(this.getTypeormMetadataTableName())
2,742✔
2258
        if (!hasTable) {
2,742✔
2259
            return []
2,674✔
2260
        }
2,674✔
2261

68✔
2262
        if (!viewNames) {
2,742!
UNCOV
2263
            viewNames = []
×
UNCOV
2264
        }
×
2265

68✔
2266
        const currentDatabase = await this.getCurrentDatabase()
68✔
2267
        const currentSchema = await this.getCurrentSchema()
68✔
2268

68✔
2269
        const viewsCondition = viewNames
68✔
2270
            .map((viewName) => this.driver.parseTableName(viewName))
68✔
2271
            .map(({ schema, tableName }) => {
68✔
2272
                if (!schema) {
74!
UNCOV
2273
                    schema = this.driver.options.schema || currentSchema
×
UNCOV
2274
                }
×
2275

74✔
2276
                return `("T"."schema" = '${schema}' AND "T"."name" = '${tableName}')`
74✔
2277
            })
68✔
2278
            .join(" OR ")
68✔
2279

68✔
2280
        let query =
68✔
2281
            `SELECT "T".* FROM ${this.escapePath(
68✔
2282
                this.getTypeormMetadataTableName(),
68✔
2283
            )} "T" ` +
68✔
2284
            `INNER JOIN "USER_OBJECTS" "O" ON "O"."OBJECT_NAME" = "T"."name" AND "O"."OBJECT_TYPE" IN ( 'MATERIALIZED VIEW', 'VIEW' ) ` +
68✔
2285
            `WHERE "T"."type" IN ('${MetadataTableType.MATERIALIZED_VIEW}', '${MetadataTableType.VIEW}')`
68✔
2286
        if (viewsCondition.length > 0) query += ` AND ${viewsCondition}`
2,742✔
2287

68✔
2288
        const dbViews = await this.query(query)
68✔
2289
        return dbViews.map((dbView: any) => {
68✔
2290
            const parsedName = this.driver.parseTableName(dbView["name"])
20✔
2291

20✔
2292
            const view = new View()
20✔
2293
            view.database =
20✔
2294
                parsedName.database || dbView["database"] || currentDatabase
20!
2295
            view.schema = parsedName.schema || dbView["schema"] || currentSchema
20!
2296
            view.name = parsedName.tableName
20✔
2297
            view.expression = dbView["value"]
20✔
2298
            view.materialized =
20✔
2299
                dbView["type"] === MetadataTableType.MATERIALIZED_VIEW
20✔
2300
            return view
20✔
2301
        })
68✔
2302
    }
68✔
2303

26✔
2304
    /**
26✔
2305
     * Loads all tables (with given names) from the database and creates a Table from them.
26✔
2306
     */
26✔
2307
    protected async loadTables(tableNames?: string[]): Promise<Table[]> {
26✔
2308
        if (tableNames && tableNames.length === 0) {
3,254✔
2309
            return []
12✔
2310
        }
12✔
2311

3,242✔
2312
        const dbTables: { TABLE_NAME: string; OWNER: string }[] = []
3,242✔
2313

3,242✔
2314
        const currentSchema = await this.getCurrentSchema()
3,242✔
2315
        const currentDatabase = await this.getCurrentDatabase()
3,242✔
2316

3,242✔
2317
        if (!tableNames) {
3,254!
UNCOV
2318
            const tablesSql = `SELECT "TABLE_NAME", "OWNER" FROM "ALL_TABLES"`
×
UNCOV
2319
            dbTables.push(...(await this.query(tablesSql)))
×
2320
        } else {
3,254✔
2321
            const tablesCondition = tableNames
3,242✔
2322
                .map((tableName) => {
3,242✔
2323
                    const parts = tableName.split(".")
9,916✔
2324

9,916✔
2325
                    if (parts.length >= 3) {
9,916!
UNCOV
2326
                        const [, schema, name] = parts
×
UNCOV
2327
                        return `("OWNER" = '${schema}' AND "TABLE_NAME" = '${name}')`
×
2328
                    } else if (parts.length === 2) {
9,916✔
2329
                        const [schema, name] = parts
9,378✔
2330
                        return `("OWNER" = '${schema}' AND "TABLE_NAME" = '${name}')`
9,378✔
2331
                    } else if (parts.length === 1) {
9,916✔
2332
                        const [name] = parts
538✔
2333
                        return `("TABLE_NAME" = '${name}')`
538✔
2334
                    } else {
538!
UNCOV
2335
                        return `(1=0)`
×
UNCOV
2336
                    }
×
2337
                })
3,242✔
2338
                .join(" OR ")
3,242✔
2339
            const tablesSql = `SELECT "TABLE_NAME", "OWNER" FROM "ALL_TABLES" WHERE ${tablesCondition}`
3,242✔
2340
            dbTables.push(...(await this.query(tablesSql)))
3,242✔
2341
        }
3,242✔
2342

3,242✔
2343
        // if tables were not found in the db, no need to proceed
3,242✔
2344
        if (dbTables.length === 0) {
3,254✔
2345
            return []
2,638✔
2346
        }
2,638✔
2347

604✔
2348
        // load tables, columns, indices and foreign keys
604✔
2349
        const columnsCondition = dbTables
604✔
2350
            .map(({ TABLE_NAME, OWNER }) => {
604✔
2351
                return `("C"."OWNER" = '${OWNER}' AND "C"."TABLE_NAME" = '${TABLE_NAME}')`
924✔
2352
            })
604✔
2353
            .join(" OR ")
604✔
2354
        const columnsSql = `SELECT * FROM "ALL_TAB_COLS" "C" WHERE (${columnsCondition})`
604✔
2355

604✔
2356
        const indicesSql =
604✔
2357
            `SELECT "C"."INDEX_NAME", "C"."OWNER", "C"."TABLE_NAME", "C"."UNIQUENESS", ` +
604✔
2358
            `LISTAGG ("COL"."COLUMN_NAME", ',') WITHIN GROUP (ORDER BY "COL"."COLUMN_NAME") AS "COLUMN_NAMES" ` +
604✔
2359
            `FROM "ALL_INDEXES" "C" ` +
604✔
2360
            `INNER JOIN "ALL_IND_COLUMNS" "COL" ON "COL"."INDEX_OWNER" = "C"."OWNER" AND "COL"."INDEX_NAME" = "C"."INDEX_NAME" ` +
604✔
2361
            `LEFT JOIN "ALL_CONSTRAINTS" "CON" ON "CON"."OWNER" = "C"."OWNER" AND "CON"."CONSTRAINT_NAME" = "C"."INDEX_NAME" ` +
604✔
2362
            `WHERE (${columnsCondition}) AND "CON"."CONSTRAINT_NAME" IS NULL ` +
604✔
2363
            `GROUP BY "C"."INDEX_NAME", "C"."OWNER", "C"."TABLE_NAME", "C"."UNIQUENESS"`
604✔
2364

604✔
2365
        const foreignKeysSql =
604✔
2366
            `SELECT "C"."CONSTRAINT_NAME", "C"."OWNER", "C"."TABLE_NAME", "COL"."COLUMN_NAME", "REF_COL"."TABLE_NAME" AS "REFERENCED_TABLE_NAME", ` +
604✔
2367
            `"REF_COL"."COLUMN_NAME" AS "REFERENCED_COLUMN_NAME", "C"."DELETE_RULE" AS "ON_DELETE" ` +
604✔
2368
            `FROM "ALL_CONSTRAINTS" "C" ` +
604✔
2369
            `INNER JOIN "ALL_CONS_COLUMNS" "COL" ON "COL"."OWNER" = "C"."OWNER" AND "COL"."CONSTRAINT_NAME" = "C"."CONSTRAINT_NAME" ` +
604✔
2370
            `INNER JOIN "ALL_CONS_COLUMNS" "REF_COL" ON "REF_COL"."OWNER" = "C"."R_OWNER" AND "REF_COL"."CONSTRAINT_NAME" = "C"."R_CONSTRAINT_NAME" AND "REF_COL"."POSITION" = "COL"."POSITION" ` +
604✔
2371
            `WHERE (${columnsCondition}) AND "C"."CONSTRAINT_TYPE" = 'R'`
604✔
2372

604✔
2373
        const constraintsSql =
604✔
2374
            `SELECT "C"."CONSTRAINT_NAME", "C"."CONSTRAINT_TYPE", "C"."OWNER", "C"."TABLE_NAME", "COL"."COLUMN_NAME", "C"."SEARCH_CONDITION" ` +
604✔
2375
            `FROM "ALL_CONSTRAINTS" "C" ` +
604✔
2376
            `INNER JOIN "ALL_CONS_COLUMNS" "COL" ON "COL"."OWNER" = "C"."OWNER" AND "COL"."CONSTRAINT_NAME" = "C"."CONSTRAINT_NAME" ` +
604✔
2377
            `WHERE (${columnsCondition}) AND "C"."CONSTRAINT_TYPE" IN ('C', 'U', 'P') AND "C"."GENERATED" = 'USER NAME'`
604✔
2378

604✔
2379
        const [
604✔
2380
            dbColumns,
604✔
2381
            dbIndices,
604✔
2382
            dbForeignKeys,
604✔
2383
            dbConstraints,
604✔
2384
        ]: ObjectLiteral[][] = await Promise.all([
604✔
2385
            this.query(columnsSql),
604✔
2386
            this.query(indicesSql),
604✔
2387
            this.query(foreignKeysSql),
604✔
2388
            this.query(constraintsSql),
604✔
2389
        ])
604✔
2390

604✔
2391
        // create tables for loaded tables
604✔
2392
        return await Promise.all(
604✔
2393
            dbTables.map(async (dbTable) => {
604✔
2394
                const table = new Table()
924✔
2395
                const owner =
924✔
2396
                    dbTable["OWNER"] === currentSchema &&
924✔
2397
                    (!this.driver.options.schema ||
924!
2398
                        this.driver.options.schema === currentSchema)
924✔
2399
                        ? undefined
924✔
2400
                        : dbTable["OWNER"]
924!
2401
                table.database = currentDatabase
924✔
2402
                table.schema = dbTable["OWNER"]
924✔
2403
                table.name = this.driver.buildTableName(
924✔
2404
                    dbTable["TABLE_NAME"],
924✔
2405
                    owner,
924✔
2406
                )
924✔
2407

924✔
2408
                // create columns from the loaded columns
924✔
2409
                table.columns = await Promise.all(
924✔
2410
                    dbColumns
924✔
2411
                        .filter(
924✔
2412
                            (dbColumn) =>
924✔
2413
                                dbColumn["OWNER"] === dbTable["OWNER"] &&
10,446✔
2414
                                dbColumn["TABLE_NAME"] ===
10,446✔
2415
                                    dbTable["TABLE_NAME"] &&
10,446✔
2416
                                // Filter out auto-generated virtual columns,
3,338✔
2417
                                // since TypeORM will have no info about them.
3,338✔
2418
                                !(
3,338✔
2419
                                    dbColumn["VIRTUAL_COLUMN"] === "YES" &&
3,338✔
2420
                                    dbColumn["USER_GENERATED"] === "NO"
74✔
2421
                                ),
924✔
2422
                        )
924✔
2423
                        .map(async (dbColumn) => {
924✔
2424
                            const columnConstraints = dbConstraints.filter(
3,334✔
2425
                                (dbConstraint) =>
3,334✔
2426
                                    dbConstraint["OWNER"] ===
18,242✔
2427
                                        dbColumn["OWNER"] &&
18,242✔
2428
                                    dbConstraint["TABLE_NAME"] ===
18,242✔
2429
                                        dbColumn["TABLE_NAME"] &&
18,242✔
2430
                                    dbConstraint["COLUMN_NAME"] ===
7,446✔
2431
                                        dbColumn["COLUMN_NAME"],
3,334✔
2432
                            )
3,334✔
2433

3,334✔
2434
                            const uniqueConstraints = columnConstraints.filter(
3,334✔
2435
                                (constraint) =>
3,334✔
2436
                                    constraint["CONSTRAINT_TYPE"] === "U",
3,334✔
2437
                            )
3,334✔
2438
                            const isConstraintComposite =
3,334✔
2439
                                uniqueConstraints.every((uniqueConstraint) => {
3,334✔
2440
                                    return dbConstraints.some(
616✔
2441
                                        (dbConstraint) =>
616✔
2442
                                            dbConstraint["OWNER"] ===
2,960✔
2443
                                                dbColumn["OWNER"] &&
2,960✔
2444
                                            dbConstraint["TABLE_NAME"] ===
2,960✔
2445
                                                dbColumn["TABLE_NAME"] &&
2,960✔
2446
                                            dbConstraint["COLUMN_NAME"] !==
2,530✔
2447
                                                dbColumn["COLUMN_NAME"] &&
2,960✔
2448
                                            dbConstraint["CONSTRAINT_NAME"] ===
1,984✔
2449
                                                uniqueConstraint[
1,984✔
2450
                                                    "CONSTRAINT_NAME"
1,984✔
2451
                                                ] &&
2,960✔
2452
                                            dbConstraint["CONSTRAINT_TYPE"] ===
348✔
2453
                                                "U",
616✔
2454
                                    )
616✔
2455
                                })
3,334✔
2456

3,334✔
2457
                            const tableColumn = new TableColumn()
3,334✔
2458
                            tableColumn.name = dbColumn["COLUMN_NAME"]
3,334✔
2459
                            tableColumn.type =
3,334✔
2460
                                dbColumn["DATA_TYPE"].toLowerCase()
3,334✔
2461
                            if (tableColumn.type.indexOf("(") !== -1)
3,334✔
2462
                                tableColumn.type = tableColumn.type.replace(
3,334✔
2463
                                    /\([0-9]*\)/,
100✔
2464
                                    "",
100✔
2465
                                )
100✔
2466

3,334✔
2467
                            // check only columns that have length property
3,334✔
2468
                            if (
3,334✔
2469
                                this.driver.withLengthColumnTypes.indexOf(
3,334✔
2470
                                    tableColumn.type as ColumnType,
3,334✔
2471
                                ) !== -1
3,334✔
2472
                            ) {
3,334✔
2473
                                const length =
1,760✔
2474
                                    tableColumn.type === "raw"
1,760✔
2475
                                        ? dbColumn["DATA_LENGTH"]
1,760✔
2476
                                        : dbColumn["CHAR_COL_DECL_LENGTH"]
1,760✔
2477
                                tableColumn.length =
1,760✔
2478
                                    length &&
1,760✔
2479
                                    !this.isDefaultColumnLength(
1,760✔
2480
                                        table,
1,760✔
2481
                                        tableColumn,
1,760✔
2482
                                        length,
1,760✔
2483
                                    )
1,760✔
2484
                                        ? length.toString()
1,760✔
2485
                                        : ""
1,760✔
2486
                            }
1,760✔
2487

3,334✔
2488
                            if (
3,334✔
2489
                                tableColumn.type === "number" ||
3,334✔
2490
                                tableColumn.type === "float"
1,888✔
2491
                            ) {
3,334✔
2492
                                if (
1,454✔
2493
                                    dbColumn["DATA_PRECISION"] !== null &&
1,454✔
2494
                                    !this.isDefaultColumnPrecision(
18✔
2495
                                        table,
18✔
2496
                                        tableColumn,
18✔
2497
                                        dbColumn["DATA_PRECISION"],
18✔
2498
                                    )
1,454✔
2499
                                )
1,454✔
2500
                                    tableColumn.precision =
1,454✔
2501
                                        dbColumn["DATA_PRECISION"]
12✔
2502
                                if (
1,454✔
2503
                                    dbColumn["DATA_SCALE"] !== null &&
1,454✔
2504
                                    !this.isDefaultColumnScale(
222✔
2505
                                        table,
222✔
2506
                                        tableColumn,
222✔
2507
                                        dbColumn["DATA_SCALE"],
222✔
2508
                                    )
1,454✔
2509
                                )
1,454✔
2510
                                    tableColumn.scale = dbColumn["DATA_SCALE"]
1,454✔
2511
                            } else if (
3,334✔
2512
                                (tableColumn.type === "timestamp" ||
1,880✔
2513
                                    tableColumn.type ===
1,790✔
2514
                                        "timestamp with time zone" ||
1,880✔
2515
                                    tableColumn.type ===
1,784✔
2516
                                        "timestamp with local time zone") &&
1,880✔
2517
                                dbColumn["DATA_SCALE"] !== null
100✔
2518
                            ) {
1,880✔
2519
                                tableColumn.precision =
100✔
2520
                                    !this.isDefaultColumnPrecision(
100✔
2521
                                        table,
100✔
2522
                                        tableColumn,
100✔
2523
                                        dbColumn["DATA_SCALE"],
100✔
2524
                                    )
100✔
2525
                                        ? dbColumn["DATA_SCALE"]
100✔
2526
                                        : undefined
100✔
2527
                            }
100✔
2528

3,334✔
2529
                            tableColumn.default =
3,334✔
2530
                                dbColumn["DATA_DEFAULT"] !== null &&
3,334✔
2531
                                dbColumn["DATA_DEFAULT"] !== undefined &&
3,334✔
2532
                                dbColumn["VIRTUAL_COLUMN"] === "NO" &&
3,334✔
2533
                                dbColumn["DATA_DEFAULT"].trim() !== "NULL"
792✔
2534
                                    ? (tableColumn.default =
3,334✔
2535
                                          dbColumn["DATA_DEFAULT"].trim())
776✔
2536
                                    : undefined
3,334✔
2537

3,334✔
2538
                            const primaryConstraint = columnConstraints.find(
3,334✔
2539
                                (constraint) =>
3,334✔
2540
                                    constraint["CONSTRAINT_TYPE"] === "P",
3,334✔
2541
                            )
3,334✔
2542
                            if (primaryConstraint) {
3,334✔
2543
                                tableColumn.isPrimary = true
966✔
2544
                                // find another columns involved in primary key constraint
966✔
2545
                                const anotherPrimaryConstraints =
966✔
2546
                                    dbConstraints.filter(
966✔
2547
                                        (constraint) =>
966✔
2548
                                            constraint["OWNER"] ===
5,400✔
2549
                                                dbColumn["OWNER"] &&
5,400✔
2550
                                            constraint["TABLE_NAME"] ===
5,400✔
2551
                                                dbColumn["TABLE_NAME"] &&
5,400✔
2552
                                            constraint["COLUMN_NAME"] !==
1,876✔
2553
                                                dbColumn["COLUMN_NAME"] &&
5,400✔
2554
                                            constraint["CONSTRAINT_TYPE"] ===
892✔
2555
                                                "P",
966✔
2556
                                    )
966✔
2557

966✔
2558
                                // collect all column names
966✔
2559
                                const columnNames =
966✔
2560
                                    anotherPrimaryConstraints.map(
966✔
2561
                                        (constraint) =>
966✔
2562
                                            constraint["COLUMN_NAME"],
966✔
2563
                                    )
966✔
2564
                                columnNames.push(dbColumn["COLUMN_NAME"])
966✔
2565

966✔
2566
                                // build default primary key constraint name
966✔
2567
                                const pkName =
966✔
2568
                                    this.connection.namingStrategy.primaryKeyName(
966✔
2569
                                        table,
966✔
2570
                                        columnNames,
966✔
2571
                                    )
966✔
2572

966✔
2573
                                // if primary key has user-defined constraint name, write it in table column
966✔
2574
                                if (
966✔
2575
                                    primaryConstraint["CONSTRAINT_NAME"] !==
966✔
2576
                                    pkName
966✔
2577
                                ) {
966✔
2578
                                    tableColumn.primaryKeyConstraintName =
52✔
2579
                                        primaryConstraint["CONSTRAINT_NAME"]
52✔
2580
                                }
52✔
2581
                            }
966✔
2582

3,334✔
2583
                            tableColumn.isNullable =
3,334✔
2584
                                dbColumn["NULLABLE"] === "Y"
3,334✔
2585
                            tableColumn.isUnique =
3,334✔
2586
                                uniqueConstraints.length > 0 &&
3,334✔
2587
                                !isConstraintComposite
610✔
2588
                            tableColumn.isGenerated =
3,334✔
2589
                                dbColumn["IDENTITY_COLUMN"] === "YES"
3,334✔
2590
                            if (tableColumn.isGenerated) {
3,334✔
2591
                                tableColumn.generationStrategy = "increment"
520✔
2592
                                tableColumn.default = undefined
520✔
2593
                            }
520✔
2594
                            tableColumn.comment = "" // todo
3,334✔
2595

3,334✔
2596
                            if (dbColumn["VIRTUAL_COLUMN"] === "YES") {
3,334✔
2597
                                tableColumn.generatedType = "VIRTUAL"
70✔
2598

70✔
2599
                                const asExpressionQuery =
70✔
2600
                                    this.selectTypeormMetadataSql({
70✔
2601
                                        table: dbTable["TABLE_NAME"],
70✔
2602
                                        type: MetadataTableType.GENERATED_COLUMN,
70✔
2603
                                        name: tableColumn.name,
70✔
2604
                                    })
70✔
2605

70✔
2606
                                const results = await this.query(
70✔
2607
                                    asExpressionQuery.query,
70✔
2608
                                    asExpressionQuery.parameters,
70✔
2609
                                )
70✔
2610
                                if (results[0] && results[0].value) {
70✔
2611
                                    tableColumn.asExpression = results[0].value
70✔
2612
                                } else {
70!
UNCOV
2613
                                    tableColumn.asExpression = ""
×
UNCOV
2614
                                }
×
2615
                            }
70✔
2616

3,334✔
2617
                            return tableColumn
3,334✔
2618
                        }),
924✔
2619
                )
924✔
2620

924✔
2621
                // find unique constraints of table, group them by constraint name and build TableUnique.
924✔
2622
                const tableUniqueConstraints = OrmUtils.uniq(
924✔
2623
                    dbConstraints.filter((dbConstraint) => {
924✔
2624
                        return (
5,262✔
2625
                            dbConstraint["TABLE_NAME"] ===
5,262✔
2626
                                dbTable["TABLE_NAME"] &&
5,262✔
2627
                            dbConstraint["OWNER"] === dbTable["OWNER"] &&
5,262✔
2628
                            dbConstraint["CONSTRAINT_TYPE"] === "U"
1,762✔
2629
                        )
5,262✔
2630
                    }),
924✔
2631
                    (dbConstraint) => dbConstraint["CONSTRAINT_NAME"],
924✔
2632
                )
924✔
2633

924✔
2634
                table.uniques = tableUniqueConstraints.map((constraint) => {
924✔
2635
                    const uniques = dbConstraints.filter(
442✔
2636
                        (dbC) =>
442✔
2637
                            dbC["CONSTRAINT_NAME"] ===
2,672✔
2638
                            constraint["CONSTRAINT_NAME"],
442✔
2639
                    )
442✔
2640
                    return new TableUnique({
442✔
2641
                        name: constraint["CONSTRAINT_NAME"],
442✔
2642
                        columnNames: uniques.map((u) => u["COLUMN_NAME"]),
442✔
2643
                    })
442✔
2644
                })
924✔
2645

924✔
2646
                // find check constraints of table, group them by constraint name and build TableCheck.
924✔
2647
                const tableCheckConstraints = OrmUtils.uniq(
924✔
2648
                    dbConstraints.filter((dbConstraint) => {
924✔
2649
                        return (
5,262✔
2650
                            dbConstraint["TABLE_NAME"] ===
5,262✔
2651
                                dbTable["TABLE_NAME"] &&
5,262✔
2652
                            dbConstraint["OWNER"] === dbTable["OWNER"] &&
5,262✔
2653
                            dbConstraint["CONSTRAINT_TYPE"] === "C"
1,762✔
2654
                        )
5,262✔
2655
                    }),
924✔
2656
                    (dbConstraint) => dbConstraint["CONSTRAINT_NAME"],
924✔
2657
                )
924✔
2658

924✔
2659
                table.checks = tableCheckConstraints.map((constraint) => {
924✔
2660
                    const checks = dbConstraints.filter(
172✔
2661
                        (dbC) =>
172✔
2662
                            dbC["TABLE_NAME"] === constraint["TABLE_NAME"] &&
1,202✔
2663
                            dbC["OWNER"] === constraint["OWNER"] &&
1,202✔
2664
                            dbC["CONSTRAINT_NAME"] ===
848✔
2665
                                constraint["CONSTRAINT_NAME"],
172✔
2666
                    )
172✔
2667
                    return new TableCheck({
172✔
2668
                        name: constraint["CONSTRAINT_NAME"],
172✔
2669
                        columnNames: checks.map((c) => c["COLUMN_NAME"]),
172✔
2670
                        expression: constraint["SEARCH_CONDITION"],
172✔
2671
                    })
172✔
2672
                })
924✔
2673

924✔
2674
                // find foreign key constraints of table, group them by constraint name and build TableForeignKey.
924✔
2675
                const tableForeignKeyConstraints = OrmUtils.uniq(
924✔
2676
                    dbForeignKeys.filter(
924✔
2677
                        (dbForeignKey) =>
924✔
2678
                            dbForeignKey["OWNER"] === dbTable["OWNER"] &&
1,300✔
2679
                            dbForeignKey["TABLE_NAME"] ===
1,300✔
2680
                                dbTable["TABLE_NAME"],
924✔
2681
                    ),
924✔
2682
                    (dbForeignKey) => dbForeignKey["CONSTRAINT_NAME"],
924✔
2683
                )
924✔
2684

924✔
2685
                table.foreignKeys = tableForeignKeyConstraints.map(
924✔
2686
                    (dbForeignKey) => {
924✔
2687
                        const foreignKeys = dbForeignKeys.filter(
360✔
2688
                            (dbFk) =>
360✔
2689
                                dbFk["TABLE_NAME"] ===
964✔
2690
                                    dbForeignKey["TABLE_NAME"] &&
964✔
2691
                                dbFk["OWNER"] === dbForeignKey["OWNER"] &&
964✔
2692
                                dbFk["CONSTRAINT_NAME"] ===
760✔
2693
                                    dbForeignKey["CONSTRAINT_NAME"],
360✔
2694
                        )
360✔
2695
                        return new TableForeignKey({
360✔
2696
                            name: dbForeignKey["CONSTRAINT_NAME"],
360✔
2697
                            columnNames: foreignKeys.map(
360✔
2698
                                (dbFk) => dbFk["COLUMN_NAME"],
360✔
2699
                            ),
360✔
2700
                            referencedDatabase: table.database,
360✔
2701
                            referencedSchema: dbForeignKey["OWNER"],
360✔
2702
                            referencedTableName:
360✔
2703
                                dbForeignKey["REFERENCED_TABLE_NAME"],
360✔
2704
                            referencedColumnNames: foreignKeys.map(
360✔
2705
                                (dbFk) => dbFk["REFERENCED_COLUMN_NAME"],
360✔
2706
                            ),
360✔
2707
                            onDelete: dbForeignKey["ON_DELETE"],
360✔
2708
                            onUpdate: "NO ACTION", // Oracle does not have onUpdate option in FK's, but we need it for proper synchronization
360✔
2709
                        })
360✔
2710
                    },
924✔
2711
                )
924✔
2712

924✔
2713
                // Attempt to map auto-generated virtual columns to their
924✔
2714
                // referenced columns, through its 'DATA_DEFAULT' property.
924✔
2715
                //
924✔
2716
                // An example of this happening is when a column of type
924✔
2717
                // TIMESTAMP WITH TIME ZONE is indexed. Oracle will create a
924✔
2718
                // virtual column of type TIMESTAMP with a default value of
924✔
2719
                // SYS_EXTRACT_UTC(<column>).
924✔
2720
                const autoGenVirtualDbColumns = dbColumns
924✔
2721
                    .filter(
924✔
2722
                        (dbColumn) =>
924✔
2723
                            dbColumn["OWNER"] === dbTable["OWNER"] &&
10,446✔
2724
                            dbColumn["TABLE_NAME"] === dbTable["TABLE_NAME"] &&
10,446✔
2725
                            dbColumn["VIRTUAL_COLUMN"] === "YES" &&
10,446✔
2726
                            dbColumn["USER_GENERATED"] === "NO",
924✔
2727
                    )
924✔
2728
                    .reduce((acc, x) => {
924✔
2729
                        const referencedDbColumn = dbColumns.find((dbColumn) =>
4✔
2730
                            x["DATA_DEFAULT"].includes(dbColumn["COLUMN_NAME"]),
4✔
2731
                        )
4✔
2732

4✔
2733
                        if (!referencedDbColumn) return acc
4!
2734

4✔
2735
                        return {
4✔
2736
                            ...acc,
4✔
2737
                            [x["COLUMN_NAME"]]:
4✔
2738
                                referencedDbColumn["COLUMN_NAME"],
4✔
2739
                        }
4✔
2740
                    }, {})
924✔
2741

924✔
2742
                // create TableIndex objects from the loaded indices
924✔
2743
                table.indices = dbIndices
924✔
2744
                    .filter(
924✔
2745
                        (dbIndex) =>
924✔
2746
                            dbIndex["TABLE_NAME"] === dbTable["TABLE_NAME"] &&
632✔
2747
                            dbIndex["OWNER"] === dbTable["OWNER"],
924✔
2748
                    )
924✔
2749
                    .map((dbIndex) => {
924✔
2750
                        //
288✔
2751
                        const columnNames = dbIndex["COLUMN_NAMES"]
288✔
2752
                            .split(",")
288✔
2753
                            .map(
288✔
2754
                                (
288✔
2755
                                    columnName: keyof typeof autoGenVirtualDbColumns,
330✔
2756
                                ) =>
330✔
2757
                                    autoGenVirtualDbColumns[columnName] ??
330✔
2758
                                    columnName,
288✔
2759
                            )
288✔
2760

288✔
2761
                        return new TableIndex({
288✔
2762
                            name: dbIndex["INDEX_NAME"],
288✔
2763
                            columnNames,
288✔
2764
                            isUnique: dbIndex["UNIQUENESS"] === "UNIQUE",
288✔
2765
                        })
288✔
2766
                    })
924✔
2767

924✔
2768
                return table
924✔
2769
            }),
604✔
2770
        )
604✔
2771
    }
604✔
2772

26✔
2773
    /**
26✔
2774
     * Builds and returns SQL for create table.
26✔
2775
     */
26✔
2776
    protected createTableSql(table: Table, createForeignKeys?: boolean): Query {
26✔
2777
        const columnDefinitions = table.columns
9,086✔
2778
            .map((column) => this.buildCreateColumnSql(column))
9,086✔
2779
            .join(", ")
9,086✔
2780
        let sql = `CREATE TABLE ${this.escapePath(table)} (${columnDefinitions}`
9,086✔
2781

9,086✔
2782
        table.columns
9,086✔
2783
            .filter((column) => column.isUnique)
9,086✔
2784
            .forEach((column) => {
9,086✔
2785
                const isUniqueExist = table.uniques.some(
1,284✔
2786
                    (unique) =>
1,284✔
2787
                        unique.columnNames.length === 1 &&
1,722✔
2788
                        unique.columnNames[0] === column.name,
1,284✔
2789
                )
1,284✔
2790
                if (!isUniqueExist)
1,284✔
2791
                    table.uniques.push(
1,284✔
2792
                        new TableUnique({
10✔
2793
                            name: this.connection.namingStrategy.uniqueConstraintName(
10✔
2794
                                table,
10✔
2795
                                [column.name],
10✔
2796
                            ),
10✔
2797
                            columnNames: [column.name],
10✔
2798
                        }),
10✔
2799
                    )
10✔
2800
            })
9,086✔
2801

9,086✔
2802
        if (table.uniques.length > 0) {
9,086✔
2803
            const uniquesSql = table.uniques
1,144✔
2804
                .map((unique) => {
1,144✔
2805
                    const uniqueName = unique.name
1,680✔
2806
                        ? unique.name
1,680✔
2807
                        : this.connection.namingStrategy.uniqueConstraintName(
1,680✔
2808
                              table,
4✔
2809
                              unique.columnNames,
4✔
2810
                          )
1,680✔
2811
                    const columnNames = unique.columnNames
1,680✔
2812
                        .map((columnName) => `"${columnName}"`)
1,680✔
2813
                        .join(", ")
1,680✔
2814
                    return `CONSTRAINT "${uniqueName}" UNIQUE (${columnNames})`
1,680✔
2815
                })
1,144✔
2816
                .join(", ")
1,144✔
2817

1,144✔
2818
            sql += `, ${uniquesSql}`
1,144✔
2819
        }
1,144✔
2820

9,086✔
2821
        if (table.checks.length > 0) {
9,086✔
2822
            const checksSql = table.checks
140✔
2823
                .map((check) => {
140✔
2824
                    const checkName = check.name
142✔
2825
                        ? check.name
142✔
2826
                        : this.connection.namingStrategy.checkConstraintName(
142✔
2827
                              table,
2✔
2828
                              check.expression!,
2✔
2829
                          )
142✔
2830
                    return `CONSTRAINT "${checkName}" CHECK (${check.expression})`
142✔
2831
                })
140✔
2832
                .join(", ")
140✔
2833

140✔
2834
            sql += `, ${checksSql}`
140✔
2835
        }
140✔
2836

9,086✔
2837
        if (table.foreignKeys.length > 0 && createForeignKeys) {
9,086✔
2838
            const foreignKeysSql = table.foreignKeys
10✔
2839
                .map((fk) => {
10✔
2840
                    const columnNames = fk.columnNames
12✔
2841
                        .map((columnName) => `"${columnName}"`)
12✔
2842
                        .join(", ")
12✔
2843
                    if (!fk.name)
12✔
2844
                        fk.name = this.connection.namingStrategy.foreignKeyName(
12✔
2845
                            table,
8✔
2846
                            fk.columnNames,
8✔
2847
                            this.getTablePath(fk),
8✔
2848
                            fk.referencedColumnNames,
8✔
2849
                        )
8✔
2850
                    const referencedColumnNames = fk.referencedColumnNames
12✔
2851
                        .map((columnName) => `"${columnName}"`)
12✔
2852
                        .join(", ")
12✔
2853
                    let constraint = `CONSTRAINT "${
12✔
2854
                        fk.name
12✔
2855
                    }" FOREIGN KEY (${columnNames}) REFERENCES ${this.escapePath(
12✔
2856
                        this.getTablePath(fk),
12✔
2857
                    )} (${referencedColumnNames})`
12✔
2858
                    if (fk.onDelete && fk.onDelete !== "NO ACTION") {
12!
UNCOV
2859
                        // Oracle does not support NO ACTION, but we set NO ACTION by default in EntityMetadata
×
UNCOV
2860
                        constraint += ` ON DELETE ${fk.onDelete}`
×
UNCOV
2861
                    }
×
2862
                    return constraint
12✔
2863
                })
10✔
2864
                .join(", ")
10✔
2865

10✔
2866
            sql += `, ${foreignKeysSql}`
10✔
2867
        }
10✔
2868

9,086✔
2869
        const primaryColumns = table.columns.filter(
9,086✔
2870
            (column) => column.isPrimary,
9,086✔
2871
        )
9,086✔
2872
        if (primaryColumns.length > 0) {
9,086✔
2873
            const primaryKeyName = primaryColumns[0].primaryKeyConstraintName
9,044✔
2874
                ? primaryColumns[0].primaryKeyConstraintName
9,044✔
2875
                : this.connection.namingStrategy.primaryKeyName(
9,044✔
2876
                      table,
9,012✔
2877
                      primaryColumns.map((column) => column.name),
9,012✔
2878
                  )
9,044✔
2879

9,044✔
2880
            const columnNames = primaryColumns
9,044✔
2881
                .map((column) => `"${column.name}"`)
9,044✔
2882
                .join(", ")
9,044✔
2883
            sql += `, CONSTRAINT "${primaryKeyName}" PRIMARY KEY (${columnNames})`
9,044✔
2884
        }
9,044✔
2885

9,086✔
2886
        sql += `)`
9,086✔
2887

9,086✔
2888
        return new Query(sql)
9,086✔
2889
    }
9,086✔
2890

26✔
2891
    /**
26✔
2892
     * Builds drop table sql.
26✔
2893
     */
26✔
2894
    protected dropTableSql(
26✔
2895
        tableOrName: Table | string,
9,086✔
2896
        ifExist?: boolean,
9,086✔
2897
    ): Query {
9,086✔
2898
        const query = ifExist
9,086✔
2899
            ? `DROP TABLE IF EXISTS ${this.escapePath(tableOrName)}`
9,086!
2900
            : `DROP TABLE ${this.escapePath(tableOrName)}`
9,086✔
2901
        return new Query(query)
9,086✔
2902
    }
9,086✔
2903

26✔
2904
    protected createViewSql(view: View): Query {
26✔
2905
        const materializedClause = view.materialized ? "MATERIALIZED " : ""
56✔
2906
        if (typeof view.expression === "string") {
56✔
2907
            return new Query(
40✔
2908
                `CREATE ${materializedClause}VIEW ${this.escapePath(view)} AS ${
40✔
2909
                    view.expression
40✔
2910
                }`,
40✔
2911
            )
40✔
2912
        } else {
56✔
2913
            return new Query(
16✔
2914
                `CREATE ${materializedClause}VIEW ${this.escapePath(
16✔
2915
                    view,
16✔
2916
                )} AS ${view.expression(this.connection).getQuery()}`,
16✔
2917
            )
16✔
2918
        }
16✔
2919
    }
56✔
2920

26✔
2921
    protected insertViewDefinitionSql(view: View): Query {
26✔
2922
        const expression =
56✔
2923
            typeof view.expression === "string"
56✔
2924
                ? view.expression.trim()
56✔
2925
                : view.expression(this.connection).getQuery()
56✔
2926
        const type = view.materialized
56✔
2927
            ? MetadataTableType.MATERIALIZED_VIEW
56✔
2928
            : MetadataTableType.VIEW
56✔
2929
        const { schema, tableName } = this.driver.parseTableName(view)
56✔
2930
        return this.insertTypeormMetadataSql({
56✔
2931
            type: type,
56✔
2932
            name: tableName,
56✔
2933
            schema: schema,
56✔
2934
            value: expression,
56✔
2935
        })
56✔
2936
    }
56✔
2937

26✔
2938
    /**
26✔
2939
     * Builds drop view sql.
26✔
2940
     */
26✔
2941
    protected dropViewSql(view: View): Query {
26✔
2942
        const materializedClause = view.materialized ? "MATERIALIZED " : ""
56✔
2943
        return new Query(
56✔
2944
            `DROP ${materializedClause}VIEW ${this.escapePath(view)}`,
56✔
2945
        )
56✔
2946
    }
56✔
2947

26✔
2948
    /**
26✔
2949
     * Builds remove view sql.
26✔
2950
     */
26✔
2951
    protected deleteViewDefinitionSql(view: View): Query {
26✔
2952
        const type = view.materialized
56✔
2953
            ? MetadataTableType.MATERIALIZED_VIEW
56✔
2954
            : MetadataTableType.VIEW
56✔
2955
        return this.deleteTypeormMetadataSql({ type, name: view.name })
56✔
2956
    }
56✔
2957

26✔
2958
    /**
26✔
2959
     * Builds create index sql.
26✔
2960
     */
26✔
2961
    protected createIndexSql(table: Table, index: TableIndex): Query {
26✔
2962
        const columns = index.columnNames
3,178✔
2963
            .map((columnName) => `"${columnName}"`)
3,178✔
2964
            .join(", ")
3,178✔
2965
        return new Query(
3,178✔
2966
            `CREATE ${index.isUnique ? "UNIQUE " : ""}INDEX "${
3,178✔
2967
                index.name
3,178✔
2968
            }" ON ${this.escapePath(table)} (${columns})`,
3,178✔
2969
        )
3,178✔
2970
    }
3,178✔
2971

26✔
2972
    /**
26✔
2973
     * Builds drop index sql.
26✔
2974
     */
26✔
2975
    protected dropIndexSql(indexOrName: TableIndex | string): Query {
26✔
2976
        const indexName = InstanceChecker.isTableIndex(indexOrName)
3,178✔
2977
            ? indexOrName.name
3,178✔
2978
            : indexOrName
3,178!
2979
        return new Query(`DROP INDEX "${indexName}"`)
3,178✔
2980
    }
3,178✔
2981

26✔
2982
    /**
26✔
2983
     * Builds create primary key sql.
26✔
2984
     */
26✔
2985
    protected createPrimaryKeySql(
26✔
2986
        table: Table,
10✔
2987
        columnNames: string[],
10✔
2988
        constraintName?: string,
10✔
2989
    ): Query {
10✔
2990
        const primaryKeyName = constraintName
10✔
2991
            ? constraintName
10!
2992
            : this.connection.namingStrategy.primaryKeyName(table, columnNames)
10✔
2993

10✔
2994
        const columnNamesString = columnNames
10✔
2995
            .map((columnName) => `"${columnName}"`)
10✔
2996
            .join(", ")
10✔
2997

10✔
2998
        return new Query(
10✔
2999
            `ALTER TABLE ${this.escapePath(
10✔
3000
                table,
10✔
3001
            )} ADD CONSTRAINT "${primaryKeyName}" PRIMARY KEY (${columnNamesString})`,
10✔
3002
        )
10✔
3003
    }
10✔
3004

26✔
3005
    /**
26✔
3006
     * Builds drop primary key sql.
26✔
3007
     */
26✔
3008
    protected dropPrimaryKeySql(table: Table): Query {
26✔
3009
        if (!table.primaryColumns.length)
10✔
3010
            throw new TypeORMError(`Table ${table} has no primary keys.`)
10!
3011

10✔
3012
        const columnNames = table.primaryColumns.map((column) => column.name)
10✔
3013
        const constraintName = table.primaryColumns[0].primaryKeyConstraintName
10✔
3014
        const primaryKeyName = constraintName
10✔
3015
            ? constraintName
10!
3016
            : this.connection.namingStrategy.primaryKeyName(table, columnNames)
10✔
3017

10✔
3018
        return new Query(
10✔
3019
            `ALTER TABLE ${this.escapePath(
10✔
3020
                table,
10✔
3021
            )} DROP CONSTRAINT "${primaryKeyName}"`,
10✔
3022
        )
10✔
3023
    }
10✔
3024

26✔
3025
    /**
26✔
3026
     * Builds create unique constraint sql.
26✔
3027
     */
26✔
3028
    protected createUniqueConstraintSql(
26✔
3029
        table: Table,
38✔
3030
        uniqueConstraint: TableUnique,
38✔
3031
    ): Query {
38✔
3032
        const columnNames = uniqueConstraint.columnNames
38✔
3033
            .map((column) => `"` + column + `"`)
38✔
3034
            .join(", ")
38✔
3035
        return new Query(
38✔
3036
            `ALTER TABLE ${this.escapePath(table)} ADD CONSTRAINT "${
38✔
3037
                uniqueConstraint.name
38✔
3038
            }" UNIQUE (${columnNames})`,
38✔
3039
        )
38✔
3040
    }
38✔
3041

26✔
3042
    /**
26✔
3043
     * Builds drop unique constraint sql.
26✔
3044
     */
26✔
3045
    protected dropUniqueConstraintSql(
26✔
3046
        table: Table,
38✔
3047
        uniqueOrName: TableUnique | string,
38✔
3048
    ): Query {
38✔
3049
        const uniqueName = InstanceChecker.isTableUnique(uniqueOrName)
38✔
3050
            ? uniqueOrName.name
38✔
3051
            : uniqueOrName
38!
3052
        return new Query(
38✔
3053
            `ALTER TABLE ${this.escapePath(
38✔
3054
                table,
38✔
3055
            )} DROP CONSTRAINT "${uniqueName}"`,
38✔
3056
        )
38✔
3057
    }
38✔
3058

26✔
3059
    /**
26✔
3060
     * Builds create check constraint sql.
26✔
3061
     */
26✔
3062
    protected createCheckConstraintSql(
26✔
3063
        table: Table,
20✔
3064
        checkConstraint: TableCheck,
20✔
3065
    ): Query {
20✔
3066
        return new Query(
20✔
3067
            `ALTER TABLE ${this.escapePath(table)} ADD CONSTRAINT "${
20✔
3068
                checkConstraint.name
20✔
3069
            }" CHECK (${checkConstraint.expression})`,
20✔
3070
        )
20✔
3071
    }
20✔
3072

26✔
3073
    /**
26✔
3074
     * Builds drop check constraint sql.
26✔
3075
     */
26✔
3076
    protected dropCheckConstraintSql(
26✔
3077
        table: Table,
20✔
3078
        checkOrName: TableCheck | string,
20✔
3079
    ): Query {
20✔
3080
        const checkName = InstanceChecker.isTableCheck(checkOrName)
20✔
3081
            ? checkOrName.name
20✔
3082
            : checkOrName
20!
3083
        return new Query(
20✔
3084
            `ALTER TABLE ${this.escapePath(
20✔
3085
                table,
20✔
3086
            )} DROP CONSTRAINT "${checkName}"`,
20✔
3087
        )
20✔
3088
    }
20✔
3089

26✔
3090
    /**
26✔
3091
     * Builds create foreign key sql.
26✔
3092
     */
26✔
3093
    protected createForeignKeySql(
26✔
3094
        table: Table,
5,742✔
3095
        foreignKey: TableForeignKey,
5,742✔
3096
    ): Query {
5,742✔
3097
        const columnNames = foreignKey.columnNames
5,742✔
3098
            .map((column) => `"` + column + `"`)
5,742✔
3099
            .join(", ")
5,742✔
3100
        const referencedColumnNames = foreignKey.referencedColumnNames
5,742✔
3101
            .map((column) => `"` + column + `"`)
5,742✔
3102
            .join(",")
5,742✔
3103
        let sql =
5,742✔
3104
            `ALTER TABLE ${this.escapePath(table)} ADD CONSTRAINT "${
5,742✔
3105
                foreignKey.name
5,742✔
3106
            }" FOREIGN KEY (${columnNames}) ` +
5,742✔
3107
            `REFERENCES ${this.escapePath(
5,742✔
3108
                this.getTablePath(foreignKey),
5,742✔
3109
            )} (${referencedColumnNames})`
5,742✔
3110
        // Oracle does not support NO ACTION, but we set NO ACTION by default in EntityMetadata
5,742✔
3111
        if (foreignKey.onDelete && foreignKey.onDelete !== "NO ACTION") {
5,742✔
3112
            sql += ` ON DELETE ${foreignKey.onDelete}`
2,006✔
3113
        }
2,006✔
3114
        return new Query(sql)
5,742✔
3115
    }
5,742✔
3116

26✔
3117
    /**
26✔
3118
     * Builds drop foreign key sql.
26✔
3119
     */
26✔
3120
    protected dropForeignKeySql(
26✔
3121
        table: Table,
5,754✔
3122
        foreignKeyOrName: TableForeignKey | string,
5,754✔
3123
    ): Query {
5,754✔
3124
        const foreignKeyName = InstanceChecker.isTableForeignKey(
5,754✔
3125
            foreignKeyOrName,
5,754✔
3126
        )
5,754✔
3127
            ? foreignKeyOrName.name
5,754✔
3128
            : foreignKeyOrName
5,754!
3129
        return new Query(
5,754✔
3130
            `ALTER TABLE ${this.escapePath(
5,754✔
3131
                table,
5,754✔
3132
            )} DROP CONSTRAINT "${foreignKeyName}"`,
5,754✔
3133
        )
5,754✔
3134
    }
5,754✔
3135

26✔
3136
    /**
26✔
3137
     * Builds a query for create column.
26✔
3138
     */
26✔
3139
    protected buildCreateColumnSql(column: TableColumn) {
26✔
3140
        let c =
28,678✔
3141
            `"${column.name}" ` + this.connection.driver.createFullType(column)
28,678✔
3142
        if (column.charset) c += " CHARACTER SET " + column.charset
28,678!
3143
        if (column.collation) c += " COLLATE " + column.collation
28,678!
3144

28,678✔
3145
        if (column.asExpression) c += ` AS (${column.asExpression}) VIRTUAL`
28,678✔
3146

28,678✔
3147
        if (column.default !== undefined && column.default !== null)
28,678✔
3148
            // DEFAULT must be placed before NOT NULL
28,678✔
3149
            c += " DEFAULT " + column.default
28,678✔
3150
        if (column.isNullable !== true && !column.isGenerated)
28,678✔
3151
            // NOT NULL is not supported with GENERATED
28,678✔
3152
            c += " NOT NULL"
28,678✔
3153
        if (
28,678✔
3154
            column.isGenerated === true &&
28,678✔
3155
            column.generationStrategy === "increment"
5,604✔
3156
        )
28,678✔
3157
            c += " GENERATED BY DEFAULT AS IDENTITY"
28,678✔
3158

28,678✔
3159
        return c
28,678✔
3160
    }
28,678✔
3161

26✔
3162
    /**
26✔
3163
     * Escapes given table or view path.
26✔
3164
     */
26✔
3165
    protected escapePath(target: Table | View | string): string {
26✔
3166
        // Ignore database when escaping paths
39,534✔
3167
        const { schema, tableName } = this.driver.parseTableName(target)
39,534✔
3168

39,534✔
3169
        if (schema && schema !== this.driver.schema) {
39,534!
UNCOV
3170
            return `"${schema}"."${tableName}"`
×
UNCOV
3171
        }
×
3172

39,534✔
3173
        return `"${tableName}"`
39,534✔
3174
    }
39,534✔
3175

26✔
3176
    /**
26✔
3177
     * Change table comment.
26✔
3178
     */
26✔
3179
    changeTableComment(
26✔
UNCOV
3180
        tableOrName: Table | string,
×
UNCOV
3181
        comment?: string,
×
UNCOV
3182
    ): Promise<void> {
×
3183
        throw new TypeORMError(
×
3184
            `oracle driver does not support change table comment.`,
×
3185
        )
×
3186
    }
×
3187
}
26✔
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

© 2026 Coveralls, Inc