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

typeorm / typeorm / 22831820825

08 Mar 2026 10:57PM UTC coverage: 74.734% (+0.07%) from 74.664%
22831820825

Pull #12121

github

web-flow
Merge 1a6f8d65b into cd72d2a03
Pull Request #12121: feat(QueryRunner): add ifExists parameter to all drop methods

26613 of 32154 branches covered (82.77%)

Branch coverage included in aggregate %.

631 of 907 new or added lines in 11 files covered. (69.57%)

5 existing lines in 4 files now uncovered.

84313 of 116273 relevant lines covered (72.51%)

65684.32 hits per line

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

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

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

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

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

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

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

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

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

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

23,296✔
75
        if (this.databaseConnectionPromise)
23,296✔
76
            return this.databaseConnectionPromise
126,400✔
77

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

23,168✔
95
        return this.databaseConnectionPromise
23,168✔
96
    }
23,168✔
97

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

24,114✔
105
        if (!this.databaseConnection) {
24,114✔
106
            return
946✔
107
        }
946✔
108

23,168✔
109
        await this.databaseConnection.close()
23,168✔
110
    }
23,168✔
111

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

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

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

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

18,114✔
148
        await this.broadcaster.broadcast("AfterTransactionStart")
18,114✔
149
    }
18,114✔
150

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

18,066✔
158
        await this.broadcaster.broadcast("BeforeTransactionCommit")
18,066✔
159

18,066✔
160
        if (this.transactionDepth === 1) {
18,066✔
161
            await this.query("COMMIT")
18,046✔
162
            this.isTransactionActive = false
18,046✔
163
        }
18,046✔
164
        this.transactionDepth -= 1
18,066✔
165

18,066✔
166
        await this.broadcaster.broadcast("AfterTransactionCommit")
18,066✔
167
    }
18,066✔
168

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

48✔
176
        await this.broadcaster.broadcast("BeforeTransactionRollback")
48✔
177

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

48✔
188
        await this.broadcaster.broadcast("AfterTransactionRollback")
48✔
189
    }
48✔
190

23✔
191
    /**
23✔
192
     * Executes a given SQL query.
23✔
193
     * @param query
23✔
194
     * @param parameters
23✔
195
     * @param useStructuredResult
23✔
196
     */
23✔
197
    async query(
23✔
198
        query: string,
126,390✔
199
        parameters?: any[],
126,390✔
200
        useStructuredResult = false,
126,390✔
201
    ): Promise<any> {
126,390✔
202
        if (this.isReleased) throw new QueryRunnerAlreadyReleasedError()
126,390!
203

126,390✔
204
        const databaseConnection = await this.connect()
126,390✔
205

126,390✔
206
        this.driver.connection.logger.logQuery(query, parameters, this)
126,390✔
207
        await this.broadcaster.broadcast("BeforeQuery", query, parameters)
126,390✔
208

126,390✔
209
        const broadcasterResult = new BroadcasterResult()
126,390✔
210
        const queryStartTime = Date.now()
126,390✔
211

126,390✔
212
        try {
126,390✔
213
            const executionOptions = {
126,390✔
214
                autoCommit: !this.isTransactionActive,
126,390✔
215
                outFormat: this.driver.oracle.OUT_FORMAT_OBJECT,
126,390✔
216
            }
126,390✔
217

126,390✔
218
            const raw = await databaseConnection.execute(
126,390✔
219
                query,
126,390✔
220
                parameters || {},
126,390✔
221
                executionOptions,
126,390✔
222
            )
126,390✔
223

126,370✔
224
            // log slow queries if maxQueryExecution time is set
126,370✔
225
            const maxQueryExecutionTime =
126,370✔
226
                this.driver.options.maxQueryExecutionTime
126,370✔
227
            const queryEndTime = Date.now()
126,370✔
228
            const queryExecutionTime = queryEndTime - queryStartTime
126,370✔
229

126,370✔
230
            this.broadcaster.broadcastAfterQueryEvent(
126,370✔
231
                broadcasterResult,
126,370✔
232
                query,
126,370✔
233
                parameters,
126,370✔
234
                true,
126,370✔
235
                queryExecutionTime,
126,370✔
236
                raw,
126,370✔
237
                undefined,
126,370✔
238
            )
126,370✔
239

126,370✔
240
            if (
126,370✔
241
                maxQueryExecutionTime &&
126,370!
242
                queryExecutionTime > maxQueryExecutionTime
×
243
            )
126,390✔
244
                this.driver.connection.logger.logQuerySlow(
126,390!
245
                    queryExecutionTime,
×
246
                    query,
×
247
                    parameters,
×
248
                    this,
×
249
                )
×
250

126,370✔
251
            const result = new QueryResult()
126,370✔
252

126,370✔
253
            result.raw =
126,370✔
254
                raw.rows ||
126,370✔
255
                raw.outBinds ||
126,390✔
256
                raw.rowsAffected ||
126,390✔
257
                raw.implicitResults
65,556✔
258

126,390✔
259
            if (raw?.hasOwnProperty("rows") && Array.isArray(raw.rows)) {
126,390✔
260
                result.records = raw.rows
39,370✔
261
            }
39,370✔
262

126,370✔
263
            if (
126,370✔
264
                raw?.hasOwnProperty("outBinds") &&
126,390✔
265
                Array.isArray(raw.outBinds)
7,742✔
266
            ) {
126,390✔
267
                result.records = raw.outBinds
7,742✔
268
            }
7,742✔
269

126,370✔
270
            if (
126,370✔
271
                raw?.hasOwnProperty("implicitResults") &&
126,390✔
272
                Array.isArray(raw.implicitResults)
2✔
273
            ) {
126,390✔
274
                result.records = raw.implicitResults
2✔
275
            }
2✔
276

126,370✔
277
            if (raw?.hasOwnProperty("rowsAffected")) {
126,390✔
278
                result.affected = raw.rowsAffected
86,998✔
279
            }
86,998✔
280

126,370✔
281
            if (useStructuredResult) {
126,390✔
282
                return result
34,424✔
283
            } else {
126,390✔
284
                return result.raw
91,946✔
285
            }
91,946✔
286
        } catch (err) {
126,390✔
287
            this.driver.connection.logger.logQueryError(
20✔
288
                err,
20✔
289
                query,
20✔
290
                parameters,
20✔
291
                this,
20✔
292
            )
20✔
293
            this.broadcaster.broadcastAfterQueryEvent(
20✔
294
                broadcasterResult,
20✔
295
                query,
20✔
296
                parameters,
20✔
297
                false,
20✔
298
                undefined,
20✔
299
                undefined,
20✔
300
                err,
20✔
301
            )
20✔
302

20✔
303
            throw new QueryFailedError(query, parameters, err)
20✔
304
        } finally {
126,390!
305
            await broadcasterResult.wait()
126,390✔
306
        }
126,390✔
307
    }
126,390✔
308

23✔
309
    /**
23✔
310
     * Returns raw data stream.
23✔
311
     * @param query
23✔
312
     * @param parameters
23✔
313
     * @param onEnd
23✔
314
     * @param onError
23✔
315
     */
23✔
316
    async stream(
23✔
317
        query: string,
2✔
318
        parameters?: any[],
2✔
319
        onEnd?: Function,
2✔
320
        onError?: Function,
2✔
321
    ): Promise<ReadStream> {
2✔
322
        if (this.isReleased) {
2!
323
            throw new QueryRunnerAlreadyReleasedError()
×
324
        }
×
325

2✔
326
        const executionOptions = {
2✔
327
            autoCommit: !this.isTransactionActive,
2✔
328
            outFormat: this.driver.oracle.OUT_FORMAT_OBJECT,
2✔
329
        }
2✔
330

2✔
331
        const databaseConnection = await this.connect()
2✔
332

2✔
333
        this.driver.connection.logger.logQuery(query, parameters, this)
2✔
334

2✔
335
        try {
2✔
336
            const stream = databaseConnection.queryStream(
2✔
337
                query,
2✔
338
                parameters,
2✔
339
                executionOptions,
2✔
340
            )
2✔
341
            if (onEnd) {
2!
342
                stream.on("end", onEnd)
×
343
            }
×
344

2✔
345
            if (onError) {
2!
346
                stream.on("error", onError)
×
347
            }
×
348

2✔
349
            return stream
2✔
350
        } catch (err) {
2!
351
            this.driver.connection.logger.logQueryError(
×
352
                err,
×
353
                query,
×
354
                parameters,
×
355
                this,
×
356
            )
×
357
            throw new QueryFailedError(query, parameters, err)
×
358
        }
×
359
    }
2✔
360

23✔
361
    /**
23✔
362
     * Returns all available database names including system databases.
23✔
363
     */
23✔
364
    async getDatabases(): Promise<string[]> {
23✔
365
        return Promise.resolve([])
×
366
    }
×
367

23✔
368
    /**
23✔
369
     * Returns all available schema names including system schemas.
23✔
370
     * If database parameter specified, returns schemas of that database.
23✔
371
     * @param database
23✔
372
     */
23✔
373
    async getSchemas(database?: string): Promise<string[]> {
23✔
374
        return Promise.resolve([])
×
375
    }
×
376

23✔
377
    /**
23✔
378
     * Checks if database with the given name exist.
23✔
379
     * @param database
23✔
380
     */
23✔
381
    async hasDatabase(database: string): Promise<boolean> {
23✔
382
        try {
×
383
            const query = await this.query(
×
384
                `SELECT 1 AS "exists" FROM global_name@"${database}"`,
×
385
            )
×
386

×
387
            return query.length > 0
×
388
        } catch (e) {
×
389
            return false
×
390
        }
×
391
    }
×
392

23✔
393
    /**
23✔
394
     * Loads currently using database
23✔
395
     */
23✔
396
    async getCurrentDatabase(): Promise<undefined> {
23✔
397
        const query = await this.query(
4,370✔
398
            `SELECT SYS_CONTEXT('USERENV','DB_NAME') AS "db_name" FROM dual`,
4,370✔
399
        )
4,370✔
400
        return query[0]["db_name"]
4,370✔
401
    }
4,370✔
402

23✔
403
    /**
23✔
404
     * Checks if schema with the given name exist.
23✔
405
     * @param schema
23✔
406
     */
23✔
407
    async hasSchema(schema: string): Promise<boolean> {
23✔
408
        return Promise.resolve(false)
×
409
    }
×
410

23✔
411
    /**
23✔
412
     * Loads currently using database schema
23✔
413
     */
23✔
414
    async getCurrentSchema(): Promise<string> {
23✔
415
        const query = await this.query(
4,370✔
416
            `SELECT SYS_CONTEXT('USERENV','CURRENT_SCHEMA') AS "schema_name" FROM dual`,
4,370✔
417
        )
4,370✔
418
        return query[0]["schema_name"]
4,370✔
419
    }
4,370✔
420

23✔
421
    /**
23✔
422
     * Checks if table with the given name exist in the database.
23✔
423
     * @param tableOrName
23✔
424
     */
23✔
425
    async hasTable(tableOrName: Table | string): Promise<boolean> {
23✔
426
        const { tableName } = this.driver.parseTableName(tableOrName)
3,002✔
427
        const sql = `SELECT "TABLE_NAME" FROM "USER_TABLES" WHERE "TABLE_NAME" = '${tableName}'`
3,002✔
428
        const result = await this.query(sql)
3,002✔
429
        return result.length ? true : false
3,002✔
430
    }
3,002✔
431

23✔
432
    /**
23✔
433
     * Checks if column with the given name exist in the given table.
23✔
434
     * @param tableOrName
23✔
435
     * @param columnName
23✔
436
     */
23✔
437
    async hasColumn(
23✔
438
        tableOrName: Table | string,
8✔
439
        columnName: string,
8✔
440
    ): Promise<boolean> {
8✔
441
        const { tableName } = this.driver.parseTableName(tableOrName)
8✔
442
        const sql = `SELECT "COLUMN_NAME" FROM "USER_TAB_COLS" WHERE "TABLE_NAME" = '${tableName}' AND "COLUMN_NAME" = '${columnName}'`
8✔
443
        const result = await this.query(sql)
8✔
444
        return result.length ? true : false
8✔
445
    }
8✔
446

23✔
447
    /**
23✔
448
     * Creates a new database.
23✔
449
     * @param database
23✔
450
     * @param ifNotExists
23✔
451
     */
23✔
452
    async createDatabase(
23✔
453
        database: string,
×
NEW
454
        ifNotExists?: boolean,
×
455
    ): Promise<void> {
×
456
        // Even with `IF NOT EXISTS` we get:
×
457
        //   ORA-01501: CREATE DATABASE failed
×
458
        //   ORA-01100: database already mounted
×
NEW
459
        if (ifNotExists) {
×
460
            try {
×
461
                await this.query(`CREATE DATABASE IF NOT EXISTS "${database}";`)
×
462
            } catch (e) {
×
463
                // if (e instanceof QueryFailedError) {
×
464
                if (e.message.includes("ORA-01100: database already mounted")) {
×
465
                    return
×
466
                }
×
467
                // }
×
468

×
469
                throw e
×
470
            }
×
471
        } else {
×
472
            await this.query(`CREATE DATABASE "${database}"`)
×
473
        }
×
474
    }
×
475

23✔
476
    /**
23✔
477
     * Drops database.
23✔
478
     * @param database
23✔
479
     * @param ifExists
23✔
480
     */
23✔
481
    async dropDatabase(database: string, ifExists?: boolean): Promise<void> {
23✔
482
        return Promise.resolve()
×
483
    }
×
484

23✔
485
    /**
23✔
486
     * Creates a new table schema.
23✔
487
     * @param schemaPath
23✔
488
     * @param ifNotExists
23✔
489
     */
23✔
490
    async createSchema(
23✔
491
        schemaPath: string,
2✔
492
        ifNotExists?: boolean,
2✔
493
    ): Promise<void> {
2✔
494
        throw new TypeORMError(
2✔
495
            `Schema create queries are not supported by Oracle driver.`,
2✔
496
        )
2✔
497
    }
2✔
498

23✔
499
    /**
23✔
500
     * Drops table schema.
23✔
501
     * @param schemaPath
23✔
502
     * @param ifExists
23✔
503
     */
23✔
504
    async dropSchema(schemaPath: string, ifExists?: boolean): Promise<void> {
23✔
505
        throw new TypeORMError(
×
506
            `Schema drop queries are not supported by Oracle driver.`,
×
507
        )
×
508
    }
×
509

23✔
510
    /**
23✔
511
     * Creates a new table.
23✔
512
     * @param table
23✔
513
     * @param ifNotExists
23✔
514
     * @param createForeignKeys
23✔
515
     * @param createIndices
23✔
516
     */
23✔
517
    async createTable(
23✔
518
        table: Table,
9,630✔
519
        ifNotExists: boolean = false,
9,630✔
520
        createForeignKeys: boolean = true,
9,630✔
521
        createIndices: boolean = true,
9,630✔
522
    ): Promise<void> {
9,630✔
523
        if (ifNotExists) {
9,630✔
524
            const isTableExist = await this.hasTable(table)
82✔
525
            if (isTableExist) return Promise.resolve()
82✔
526
        }
82✔
527
        const upQueries: Query[] = []
9,628✔
528
        const downQueries: Query[] = []
9,628✔
529

9,628✔
530
        upQueries.push(this.createTableSql(table, createForeignKeys))
9,628✔
531
        downQueries.push(this.dropTableSql(table))
9,628✔
532

9,628✔
533
        // if createForeignKeys is true, we must drop created foreign keys in down query.
9,628✔
534
        // createTable does not need separate method to create foreign keys, because it create fk's in the same query with table creation.
9,628✔
535
        if (createForeignKeys)
9,628✔
536
            table.foreignKeys.forEach((foreignKey) =>
9,630✔
537
                downQueries.push(this.dropForeignKeySql(table, foreignKey)),
126✔
538
            )
126✔
539

9,628✔
540
        if (createIndices) {
9,628✔
541
            table.indices.forEach((index) => {
9,628✔
542
                // new index may be passed without name. In this case we generate index name manually.
3,280✔
543
                if (!index.name)
3,280✔
544
                    index.name = this.connection.namingStrategy.indexName(
3,280✔
545
                        table,
6✔
546
                        index.columnNames,
6✔
547
                        index.where,
6✔
548
                    )
6✔
549
                upQueries.push(this.createIndexSql(table, index))
3,280✔
550
                downQueries.push(this.dropIndexSql(index))
3,280✔
551
            })
9,628✔
552
        }
9,628✔
553

9,628✔
554
        // if table have column with generated type, we must add the expression to the metadata table
9,628✔
555
        const generatedColumns = table.columns.filter(
9,628✔
556
            (column) => column.generatedType && column.asExpression,
9,628✔
557
        )
9,628✔
558

9,628✔
559
        for (const column of generatedColumns) {
9,630✔
560
            const insertQuery = this.insertTypeormMetadataSql({
42✔
561
                table: table.name,
42✔
562
                type: MetadataTableType.GENERATED_COLUMN,
42✔
563
                name: column.name,
42✔
564
                value: column.asExpression,
42✔
565
            })
42✔
566

42✔
567
            const deleteQuery = this.deleteTypeormMetadataSql({
42✔
568
                table: table.name,
42✔
569
                type: MetadataTableType.GENERATED_COLUMN,
42✔
570
                name: column.name,
42✔
571
            })
42✔
572

42✔
573
            upQueries.push(insertQuery)
42✔
574
            downQueries.push(deleteQuery)
42✔
575
        }
42✔
576

9,628✔
577
        await this.executeQueries(upQueries, downQueries)
9,628✔
578
    }
9,628✔
579

23✔
580
    /**
23✔
581
     * Drops the table.
23✔
582
     * @param tableOrName
23✔
583
     * @param ifExists
23✔
584
     * @param dropForeignKeys
23✔
585
     * @param dropIndices
23✔
586
     */
23✔
587
    async dropTable(
23✔
588
        tableOrName: Table | string,
22✔
589
        ifExists?: boolean,
22✔
590
        dropForeignKeys: boolean = true,
22✔
591
        dropIndices: boolean = true,
22✔
592
    ): Promise<void> {
22✔
593
        // It needs because if table does not exist and dropForeignKeys or dropIndices is true, we don't need
22✔
594
        // to perform drop queries for foreign keys and indices.
22✔
595
        if (ifExists) {
22✔
596
            const isTableExist = await this.hasTable(tableOrName)
2✔
597
            if (!isTableExist) return Promise.resolve()
2✔
598
        }
2✔
599

20✔
600
        // if dropTable called with dropForeignKeys = true, we must create foreign keys in down query.
20✔
601
        const createForeignKeys: boolean = dropForeignKeys
20✔
602
        const table = InstanceChecker.isTable(tableOrName)
20✔
603
            ? tableOrName
22✔
604
            : await this.getCachedTable(tableOrName)
22✔
605
        const upQueries: Query[] = []
12✔
606
        const downQueries: Query[] = []
12✔
607

12✔
608
        if (dropIndices) {
22✔
609
            table.indices.forEach((index) => {
20✔
610
                upQueries.push(this.dropIndexSql(index))
2✔
611
                downQueries.push(this.createIndexSql(table, index))
2✔
612
            })
20✔
613
        }
20✔
614

20✔
615
        // if dropForeignKeys is true, we just drop the table, otherwise we also drop table foreign keys.
20✔
616
        // createTable does not need separate method to create foreign keys, because it create fk's in the same query with table creation.
20✔
617
        if (dropForeignKeys)
20✔
618
            table.foreignKeys.forEach((foreignKey) =>
20✔
619
                upQueries.push(this.dropForeignKeySql(table, foreignKey)),
20✔
620
            )
20✔
621

20✔
622
        upQueries.push(this.dropTableSql(table))
20✔
623
        downQueries.push(this.createTableSql(table, createForeignKeys))
20✔
624

20✔
625
        // if table had columns with generated type, we must remove the expression from the metadata table
20✔
626
        const generatedColumns = table.columns.filter(
20✔
627
            (column) => column.generatedType && column.asExpression,
20✔
628
        )
20✔
629

20✔
630
        for (const column of generatedColumns) {
22✔
631
            const deleteQuery = this.deleteTypeormMetadataSql({
6✔
632
                table: table.name,
6✔
633
                type: MetadataTableType.GENERATED_COLUMN,
6✔
634
                name: column.name,
6✔
635
            })
6✔
636

6✔
637
            const insertQuery = this.insertTypeormMetadataSql({
6✔
638
                table: table.name,
6✔
639
                type: MetadataTableType.GENERATED_COLUMN,
6✔
640
                name: column.name,
6✔
641
                value: column.asExpression,
6✔
642
            })
6✔
643

6✔
644
            upQueries.push(deleteQuery)
6✔
645
            downQueries.push(insertQuery)
6✔
646
        }
6✔
647

20✔
648
        await this.executeQueries(upQueries, downQueries)
20✔
649
    }
20✔
650

23✔
651
    /**
23✔
652
     * Creates a new view.
23✔
653
     * @param view
23✔
654
     * @param syncWithMetadata
23✔
655
     */
23✔
656
    async createView(
23✔
657
        view: View,
56✔
658
        syncWithMetadata: boolean = false,
56✔
659
    ): Promise<void> {
56✔
660
        const upQueries: Query[] = []
56✔
661
        const downQueries: Query[] = []
56✔
662
        upQueries.push(this.createViewSql(view))
56✔
663
        if (syncWithMetadata) upQueries.push(this.insertViewDefinitionSql(view))
56✔
664
        downQueries.push(this.dropViewSql(view))
56✔
665
        if (syncWithMetadata)
56✔
666
            downQueries.push(this.deleteViewDefinitionSql(view))
56✔
667
        await this.executeQueries(upQueries, downQueries)
56✔
668
    }
56✔
669

23✔
670
    /**
23✔
671
     * Drops the view.
23✔
672
     * @param target
23✔
673
     * @param ifExists
23✔
674
     */
23✔
675
    async dropView(target: View | string, ifExists?: boolean): Promise<void> {
23✔
676
        const viewName = InstanceChecker.isView(target) ? target.name : target
6✔
677
        const view = ifExists
6✔
678
            ? await this.getCachedView(viewName).catch(() => undefined)
6✔
679
            : await this.getCachedView(viewName)
6✔
680
        if (!view) return
4✔
681

4✔
682
        const upQueries: Query[] = []
4✔
683
        const downQueries: Query[] = []
4✔
684
        upQueries.push(this.deleteViewDefinitionSql(view))
4✔
685
        upQueries.push(this.dropViewSql(view))
4✔
686
        downQueries.push(this.insertViewDefinitionSql(view))
4✔
687
        downQueries.push(this.createViewSql(view))
4✔
688
        await this.executeQueries(upQueries, downQueries)
4✔
689
    }
4✔
690

23✔
691
    /**
23✔
692
     * Renames the given table.
23✔
693
     * @param oldTableOrName
23✔
694
     * @param newTableName
23✔
695
     */
23✔
696
    async renameTable(
23✔
697
        oldTableOrName: Table | string,
34✔
698
        newTableName: string,
34✔
699
    ): Promise<void> {
34✔
700
        const upQueries: Query[] = []
34✔
701
        const downQueries: Query[] = []
34✔
702
        const oldTable = InstanceChecker.isTable(oldTableOrName)
34✔
703
            ? oldTableOrName
34✔
704
            : await this.getCachedTable(oldTableOrName)
34✔
705
        const newTable = oldTable.clone()
30✔
706

30✔
707
        const { database: dbName, tableName: oldTableName } =
30✔
708
            this.driver.parseTableName(oldTable)
30✔
709

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

34✔
712
        // rename table
34✔
713
        upQueries.push(
34✔
714
            new Query(
34✔
715
                `ALTER TABLE ${this.escapePath(
34✔
716
                    oldTable,
34✔
717
                )} RENAME TO "${newTableName}"`,
34✔
718
            ),
34✔
719
        )
34✔
720
        downQueries.push(
34✔
721
            new Query(
34✔
722
                `ALTER TABLE ${this.escapePath(
34✔
723
                    newTable,
34✔
724
                )} RENAME TO "${oldTableName}"`,
34✔
725
            ),
34✔
726
        )
34✔
727

34✔
728
        // rename primary key constraint
34✔
729
        if (
34✔
730
            newTable.primaryColumns.length > 0 &&
34✔
731
            !newTable.primaryColumns[0].primaryKeyConstraintName
34✔
732
        ) {
34✔
733
            const columnNames = newTable.primaryColumns.map(
26✔
734
                (column) => column.name,
26✔
735
            )
26✔
736

26✔
737
            const oldPkName = this.connection.namingStrategy.primaryKeyName(
26✔
738
                oldTable,
26✔
739
                columnNames,
26✔
740
            )
26✔
741
            const newPkName = this.connection.namingStrategy.primaryKeyName(
26✔
742
                newTable,
26✔
743
                columnNames,
26✔
744
            )
26✔
745

26✔
746
            // build queries
26✔
747
            upQueries.push(
26✔
748
                new Query(
26✔
749
                    `ALTER TABLE ${this.escapePath(
26✔
750
                        newTable,
26✔
751
                    )} RENAME CONSTRAINT "${oldPkName}" TO "${newPkName}"`,
26✔
752
                ),
26✔
753
            )
26✔
754
            downQueries.push(
26✔
755
                new Query(
26✔
756
                    `ALTER TABLE ${this.escapePath(
26✔
757
                        newTable,
26✔
758
                    )} RENAME CONSTRAINT "${newPkName}" TO "${oldPkName}"`,
26✔
759
                ),
26✔
760
            )
26✔
761
        }
26✔
762

34✔
763
        // rename unique constraints
34✔
764
        newTable.uniques.forEach((unique) => {
34✔
765
            const oldUniqueName =
14✔
766
                this.connection.namingStrategy.uniqueConstraintName(
14✔
767
                    oldTable,
14✔
768
                    unique.columnNames,
14✔
769
                )
14✔
770

14✔
771
            // Skip renaming if Unique has user defined constraint name
14✔
772
            if (unique.name !== oldUniqueName) return
14✔
773

6✔
774
            // build new constraint name
6✔
775
            const newUniqueName =
6✔
776
                this.connection.namingStrategy.uniqueConstraintName(
6✔
777
                    newTable,
6✔
778
                    unique.columnNames,
6✔
779
                )
6✔
780

6✔
781
            // build queries
6✔
782
            upQueries.push(
6✔
783
                new Query(
6✔
784
                    `ALTER TABLE ${this.escapePath(
6✔
785
                        newTable,
6✔
786
                    )} RENAME CONSTRAINT "${
6✔
787
                        unique.name
6✔
788
                    }" TO "${newUniqueName}"`,
6✔
789
                ),
6✔
790
            )
6✔
791
            downQueries.push(
6✔
792
                new Query(
6✔
793
                    `ALTER TABLE ${this.escapePath(
6✔
794
                        newTable,
6✔
795
                    )} RENAME CONSTRAINT "${newUniqueName}" TO "${
6✔
796
                        unique.name
6✔
797
                    }"`,
6✔
798
                ),
6✔
799
            )
6✔
800

6✔
801
            // replace constraint name
6✔
802
            unique.name = newUniqueName
6✔
803
        })
34✔
804

34✔
805
        // rename index constraints
34✔
806
        newTable.indices.forEach((index) => {
34✔
807
            const oldIndexName = this.connection.namingStrategy.indexName(
20✔
808
                oldTable,
20✔
809
                index.columnNames,
20✔
810
                index.where,
20✔
811
            )
20✔
812

20✔
813
            // Skip renaming if Index has user defined constraint name
20✔
814
            if (index.name !== oldIndexName) return
20✔
815

10✔
816
            // build new constraint name
10✔
817
            const newIndexName = this.connection.namingStrategy.indexName(
10✔
818
                newTable,
10✔
819
                index.columnNames,
10✔
820
                index.where,
10✔
821
            )
10✔
822

10✔
823
            // build queries
10✔
824
            upQueries.push(
10✔
825
                new Query(
10✔
826
                    `ALTER INDEX "${index.name}" RENAME TO "${newIndexName}"`,
10✔
827
                ),
10✔
828
            )
10✔
829
            downQueries.push(
10✔
830
                new Query(
10✔
831
                    `ALTER INDEX "${newIndexName}" RENAME TO "${index.name}"`,
10✔
832
                ),
10✔
833
            )
10✔
834

10✔
835
            // replace constraint name
10✔
836
            index.name = newIndexName
10✔
837
        })
34✔
838

34✔
839
        // rename foreign key constraints
34✔
840
        newTable.foreignKeys.forEach((foreignKey) => {
34✔
841
            const oldForeignKeyName =
18✔
842
                this.connection.namingStrategy.foreignKeyName(
18✔
843
                    oldTable,
18✔
844
                    foreignKey.columnNames,
18✔
845
                    this.getTablePath(foreignKey),
18✔
846
                    foreignKey.referencedColumnNames,
18✔
847
                )
18✔
848

18✔
849
            // Skip renaming if foreign key has user defined constraint name
18✔
850
            if (foreignKey.name !== oldForeignKeyName) return
18✔
851

2✔
852
            // build new constraint name
2✔
853
            const newForeignKeyName =
2✔
854
                this.connection.namingStrategy.foreignKeyName(
2✔
855
                    newTable,
2✔
856
                    foreignKey.columnNames,
2✔
857
                    this.getTablePath(foreignKey),
2✔
858
                    foreignKey.referencedColumnNames,
2✔
859
                )
2✔
860

2✔
861
            // build queries
2✔
862
            upQueries.push(
2✔
863
                new Query(
2✔
864
                    `ALTER TABLE ${this.escapePath(
2✔
865
                        newTable,
2✔
866
                    )} RENAME CONSTRAINT "${
2✔
867
                        foreignKey.name
2✔
868
                    }" TO "${newForeignKeyName}"`,
2✔
869
                ),
2✔
870
            )
2✔
871
            downQueries.push(
2✔
872
                new Query(
2✔
873
                    `ALTER TABLE ${this.escapePath(
2✔
874
                        newTable,
2✔
875
                    )} RENAME CONSTRAINT "${newForeignKeyName}" TO "${
2✔
876
                        foreignKey.name
2✔
877
                    }"`,
2✔
878
                ),
2✔
879
            )
2✔
880

2✔
881
            // replace constraint name
2✔
882
            foreignKey.name = newForeignKeyName
2✔
883
        })
34✔
884

34✔
885
        await this.executeQueries(upQueries, downQueries)
34✔
886

34✔
887
        // rename old table and replace it in cached tabled;
34✔
888
        oldTable.name = newTable.name
34✔
889
        this.replaceCachedTable(oldTable, newTable)
34✔
890
    }
34✔
891

23✔
892
    /**
23✔
893
     * Creates a new column from the column in the table.
23✔
894
     * @param tableOrName
23✔
895
     * @param column
23✔
896
     */
23✔
897
    async addColumn(
23✔
898
        tableOrName: Table | string,
50✔
899
        column: TableColumn,
50✔
900
    ): Promise<void> {
50✔
901
        const table = InstanceChecker.isTable(tableOrName)
50✔
902
            ? tableOrName
50✔
903
            : await this.getCachedTable(tableOrName)
50✔
904
        const clonedTable = table.clone()
4✔
905
        const upQueries: Query[] = []
4✔
906
        const downQueries: Query[] = []
4✔
907

4✔
908
        upQueries.push(
4✔
909
            new Query(
4✔
910
                `ALTER TABLE ${this.escapePath(
4✔
911
                    table,
4✔
912
                )} ADD ${this.buildCreateColumnSql(column)}`,
4✔
913
            ),
4✔
914
        )
4✔
915
        downQueries.push(
4✔
916
            new Query(
4✔
917
                `ALTER TABLE ${this.escapePath(table)} DROP COLUMN "${
4✔
918
                    column.name
4✔
919
                }"`,
4✔
920
            ),
4✔
921
        )
4✔
922

4✔
923
        // create or update primary key constraint
4✔
924
        if (column.isPrimary) {
50✔
925
            const primaryColumns = clonedTable.primaryColumns
14✔
926
            // if table already have primary key, me must drop it and recreate again
14✔
927
            if (primaryColumns.length > 0) {
14✔
928
                const pkName = primaryColumns[0].primaryKeyConstraintName
2✔
929
                    ? primaryColumns[0].primaryKeyConstraintName
2!
930
                    : this.connection.namingStrategy.primaryKeyName(
2✔
931
                          clonedTable,
2✔
932
                          primaryColumns.map((column) => column.name),
2✔
933
                      )
2✔
934

2✔
935
                const columnNames = primaryColumns
2✔
936
                    .map((column) => `"${column.name}"`)
2✔
937
                    .join(", ")
2✔
938

2✔
939
                upQueries.push(
2✔
940
                    new Query(
2✔
941
                        `ALTER TABLE ${this.escapePath(
2✔
942
                            table,
2✔
943
                        )} DROP CONSTRAINT "${pkName}"`,
2✔
944
                    ),
2✔
945
                )
2✔
946
                downQueries.push(
2✔
947
                    new Query(
2✔
948
                        `ALTER TABLE ${this.escapePath(
2✔
949
                            table,
2✔
950
                        )} ADD CONSTRAINT "${pkName}" PRIMARY KEY (${columnNames})`,
2✔
951
                    ),
2✔
952
                )
2✔
953
            }
2✔
954

14✔
955
            primaryColumns.push(column)
14✔
956
            const pkName = primaryColumns[0].primaryKeyConstraintName
14✔
957
                ? primaryColumns[0].primaryKeyConstraintName
14!
958
                : this.connection.namingStrategy.primaryKeyName(
14✔
959
                      clonedTable,
14✔
960
                      primaryColumns.map((column) => column.name),
14✔
961
                  )
14✔
962

14✔
963
            const columnNames = primaryColumns
14✔
964
                .map((column) => `"${column.name}"`)
14✔
965
                .join(", ")
14✔
966

14✔
967
            upQueries.push(
14✔
968
                new Query(
14✔
969
                    `ALTER TABLE ${this.escapePath(
14✔
970
                        table,
14✔
971
                    )} ADD CONSTRAINT "${pkName}" PRIMARY KEY (${columnNames})`,
14✔
972
                ),
14✔
973
            )
14✔
974
            downQueries.push(
14✔
975
                new Query(
14✔
976
                    `ALTER TABLE ${this.escapePath(
14✔
977
                        table,
14✔
978
                    )} DROP CONSTRAINT "${pkName}"`,
14✔
979
                ),
14✔
980
            )
14✔
981
        }
14✔
982

50✔
983
        // create column index
50✔
984
        const columnIndex = clonedTable.indices.find(
50✔
985
            (index) =>
50✔
986
                index.columnNames.length === 1 &&
2✔
987
                index.columnNames[0] === column.name,
50✔
988
        )
50✔
989
        if (columnIndex) {
50!
990
            clonedTable.indices.splice(
×
991
                clonedTable.indices.indexOf(columnIndex),
×
992
                1,
×
993
            )
×
994
            upQueries.push(this.createIndexSql(table, columnIndex))
×
995
            downQueries.push(this.dropIndexSql(columnIndex))
×
996
        }
×
997

50✔
998
        // create unique constraint
50✔
999
        if (column.isUnique) {
50✔
1000
            const uniqueConstraint = new TableUnique({
6✔
1001
                name: this.connection.namingStrategy.uniqueConstraintName(
6✔
1002
                    table,
6✔
1003
                    [column.name],
6✔
1004
                ),
6✔
1005
                columnNames: [column.name],
6✔
1006
            })
6✔
1007
            clonedTable.uniques.push(uniqueConstraint)
6✔
1008
            upQueries.push(
6✔
1009
                new Query(
6✔
1010
                    `ALTER TABLE ${this.escapePath(table)} ADD CONSTRAINT "${
6✔
1011
                        uniqueConstraint.name
6✔
1012
                    }" UNIQUE ("${column.name}")`,
6✔
1013
                ),
6✔
1014
            )
6✔
1015
            downQueries.push(
6✔
1016
                new Query(
6✔
1017
                    `ALTER TABLE ${this.escapePath(table)} DROP CONSTRAINT "${
6✔
1018
                        uniqueConstraint.name
6✔
1019
                    }"`,
6✔
1020
                ),
6✔
1021
            )
6✔
1022
        }
6✔
1023

50✔
1024
        if (column.generatedType && column.asExpression) {
50✔
1025
            const insertQuery = this.insertTypeormMetadataSql({
4✔
1026
                table: table.name,
4✔
1027
                type: MetadataTableType.GENERATED_COLUMN,
4✔
1028
                name: column.name,
4✔
1029
                value: column.asExpression,
4✔
1030
            })
4✔
1031

4✔
1032
            const deleteQuery = this.deleteTypeormMetadataSql({
4✔
1033
                table: table.name,
4✔
1034
                type: MetadataTableType.GENERATED_COLUMN,
4✔
1035
                name: column.name,
4✔
1036
            })
4✔
1037

4✔
1038
            upQueries.push(insertQuery)
4✔
1039
            downQueries.push(deleteQuery)
4✔
1040
        }
4✔
1041

50✔
1042
        await this.executeQueries(upQueries, downQueries)
50✔
1043

48✔
1044
        clonedTable.addColumn(column)
48✔
1045
        this.replaceCachedTable(table, clonedTable)
48✔
1046
    }
48✔
1047

23✔
1048
    /**
23✔
1049
     * Creates a new columns from the column in the table.
23✔
1050
     * @param tableOrName
23✔
1051
     * @param columns
23✔
1052
     */
23✔
1053
    async addColumns(
23✔
1054
        tableOrName: Table | string,
8✔
1055
        columns: TableColumn[],
8✔
1056
    ): Promise<void> {
8✔
1057
        for (const column of columns) {
8✔
1058
            await this.addColumn(tableOrName, column)
10✔
1059
        }
10✔
1060
    }
8✔
1061

23✔
1062
    /**
23✔
1063
     * Renames column in the given table.
23✔
1064
     * @param tableOrName
23✔
1065
     * @param oldTableColumnOrName
23✔
1066
     * @param newTableColumnOrName
23✔
1067
     */
23✔
1068
    async renameColumn(
23✔
1069
        tableOrName: Table | string,
26✔
1070
        oldTableColumnOrName: TableColumn | string,
26✔
1071
        newTableColumnOrName: TableColumn | string,
26✔
1072
    ): Promise<void> {
26✔
1073
        const table = InstanceChecker.isTable(tableOrName)
26✔
1074
            ? tableOrName
26✔
1075
            : await this.getCachedTable(tableOrName)
26✔
1076
        const oldColumn = InstanceChecker.isTableColumn(oldTableColumnOrName)
4✔
1077
            ? oldTableColumnOrName
26✔
1078
            : table.columns.find((c) => c.name === oldTableColumnOrName)
26✔
1079
        if (!oldColumn)
26✔
1080
            throw new TypeORMError(
26!
1081
                `Column "${oldTableColumnOrName}" was not found in the ${this.escapePath(
×
1082
                    table,
×
1083
                )} table.`,
×
1084
            )
×
1085

26✔
1086
        let newColumn: TableColumn
26✔
1087
        if (InstanceChecker.isTableColumn(newTableColumnOrName)) {
26✔
1088
            newColumn = newTableColumnOrName
16✔
1089
        } else {
26✔
1090
            newColumn = oldColumn.clone()
10✔
1091
            newColumn.name = newTableColumnOrName
10✔
1092
        }
10✔
1093

26✔
1094
        await this.changeColumn(table, oldColumn, newColumn)
26✔
1095
    }
26✔
1096

23✔
1097
    /**
23✔
1098
     * Changes a column in the table.
23✔
1099
     * @param tableOrName
23✔
1100
     * @param oldTableColumnOrName
23✔
1101
     * @param newColumn
23✔
1102
     */
23✔
1103
    async changeColumn(
23✔
1104
        tableOrName: Table | string,
98✔
1105
        oldTableColumnOrName: TableColumn | string,
98✔
1106
        newColumn: TableColumn,
98✔
1107
    ): Promise<void> {
98✔
1108
        const table = InstanceChecker.isTable(tableOrName)
98✔
1109
            ? tableOrName
98✔
1110
            : await this.getCachedTable(tableOrName)
98!
1111
        let clonedTable = table.clone()
×
1112
        const upQueries: Query[] = []
×
1113
        const downQueries: Query[] = []
×
1114

×
1115
        const oldColumn = InstanceChecker.isTableColumn(oldTableColumnOrName)
×
1116
            ? oldTableColumnOrName
98✔
1117
            : table.columns.find(
98!
1118
                  (column) => column.name === oldTableColumnOrName,
×
1119
              )
98✔
1120
        if (!oldColumn)
98✔
1121
            throw new TypeORMError(
98!
1122
                `Column "${oldTableColumnOrName}" was not found in the ${this.escapePath(
×
1123
                    table,
×
1124
                )} table.`,
×
1125
            )
×
1126

98✔
1127
        if (
98✔
1128
            (newColumn.isGenerated !== oldColumn.isGenerated &&
98✔
1129
                newColumn.generationStrategy !== "uuid") ||
98✔
1130
            oldColumn.type !== newColumn.type ||
98✔
1131
            oldColumn.length !== newColumn.length ||
98✔
1132
            oldColumn.generatedType !== newColumn.generatedType ||
98✔
1133
            oldColumn.asExpression !== newColumn.asExpression
68✔
1134
        ) {
98✔
1135
            // Oracle does not support changing of IDENTITY column, so we must drop column and recreate it again.
32✔
1136
            // Also, we recreate column if column type changed
32✔
1137
            await this.dropColumn(table, oldColumn)
32✔
1138
            await this.addColumn(table, newColumn)
32✔
1139

32✔
1140
            // update cloned table
32✔
1141
            clonedTable = table.clone()
32✔
1142
        } else {
98✔
1143
            if (newColumn.name !== oldColumn.name) {
66✔
1144
                // rename column
44✔
1145
                upQueries.push(
44✔
1146
                    new Query(
44✔
1147
                        `ALTER TABLE ${this.escapePath(table)} RENAME COLUMN "${
44✔
1148
                            oldColumn.name
44✔
1149
                        }" TO "${newColumn.name}"`,
44✔
1150
                    ),
44✔
1151
                )
44✔
1152
                downQueries.push(
44✔
1153
                    new Query(
44✔
1154
                        `ALTER TABLE ${this.escapePath(table)} RENAME COLUMN "${
44✔
1155
                            newColumn.name
44✔
1156
                        }" TO "${oldColumn.name}"`,
44✔
1157
                    ),
44✔
1158
                )
44✔
1159

44✔
1160
                // rename column primary key constraint
44✔
1161
                if (
44✔
1162
                    oldColumn.isPrimary === true &&
44✔
1163
                    !oldColumn.primaryKeyConstraintName
14✔
1164
                ) {
44✔
1165
                    const primaryColumns = clonedTable.primaryColumns
10✔
1166

10✔
1167
                    // build old primary constraint name
10✔
1168
                    const columnNames = primaryColumns.map(
10✔
1169
                        (column) => column.name,
10✔
1170
                    )
10✔
1171
                    const oldPkName =
10✔
1172
                        this.connection.namingStrategy.primaryKeyName(
10✔
1173
                            clonedTable,
10✔
1174
                            columnNames,
10✔
1175
                        )
10✔
1176

10✔
1177
                    // replace old column name with new column name
10✔
1178
                    columnNames.splice(columnNames.indexOf(oldColumn.name), 1)
10✔
1179
                    columnNames.push(newColumn.name)
10✔
1180

10✔
1181
                    // build new primary constraint name
10✔
1182
                    const newPkName =
10✔
1183
                        this.connection.namingStrategy.primaryKeyName(
10✔
1184
                            clonedTable,
10✔
1185
                            columnNames,
10✔
1186
                        )
10✔
1187

10✔
1188
                    upQueries.push(
10✔
1189
                        new Query(
10✔
1190
                            `ALTER TABLE ${this.escapePath(
10✔
1191
                                table,
10✔
1192
                            )} RENAME CONSTRAINT "${oldPkName}" TO "${newPkName}"`,
10✔
1193
                        ),
10✔
1194
                    )
10✔
1195
                    downQueries.push(
10✔
1196
                        new Query(
10✔
1197
                            `ALTER TABLE ${this.escapePath(
10✔
1198
                                table,
10✔
1199
                            )} RENAME CONSTRAINT "${newPkName}" TO "${oldPkName}"`,
10✔
1200
                        ),
10✔
1201
                    )
10✔
1202
                }
10✔
1203

44✔
1204
                // rename unique constraints
44✔
1205
                clonedTable.findColumnUniques(oldColumn).forEach((unique) => {
44✔
1206
                    const oldUniqueName =
16✔
1207
                        this.connection.namingStrategy.uniqueConstraintName(
16✔
1208
                            clonedTable,
16✔
1209
                            unique.columnNames,
16✔
1210
                        )
16✔
1211

16✔
1212
                    // Skip renaming if Unique has user defined constraint name
16✔
1213
                    if (unique.name !== oldUniqueName) return
16✔
1214

8✔
1215
                    // build new constraint name
8✔
1216
                    unique.columnNames.splice(
8✔
1217
                        unique.columnNames.indexOf(oldColumn.name),
8✔
1218
                        1,
8✔
1219
                    )
8✔
1220
                    unique.columnNames.push(newColumn.name)
8✔
1221
                    const newUniqueName =
8✔
1222
                        this.connection.namingStrategy.uniqueConstraintName(
8✔
1223
                            clonedTable,
8✔
1224
                            unique.columnNames,
8✔
1225
                        )
8✔
1226

8✔
1227
                    // build queries
8✔
1228
                    upQueries.push(
8✔
1229
                        new Query(
8✔
1230
                            `ALTER TABLE ${this.escapePath(
8✔
1231
                                table,
8✔
1232
                            )} RENAME CONSTRAINT "${
8✔
1233
                                unique.name
8✔
1234
                            }" TO "${newUniqueName}"`,
8✔
1235
                        ),
8✔
1236
                    )
8✔
1237
                    downQueries.push(
8✔
1238
                        new Query(
8✔
1239
                            `ALTER TABLE ${this.escapePath(
8✔
1240
                                table,
8✔
1241
                            )} RENAME CONSTRAINT "${newUniqueName}" TO "${
8✔
1242
                                unique.name
8✔
1243
                            }"`,
8✔
1244
                        ),
8✔
1245
                    )
8✔
1246

8✔
1247
                    // replace constraint name
8✔
1248
                    unique.name = newUniqueName
8✔
1249
                })
44✔
1250

44✔
1251
                // rename index constraints
44✔
1252
                clonedTable.findColumnIndices(oldColumn).forEach((index) => {
44✔
1253
                    const oldIndexName =
14✔
1254
                        this.connection.namingStrategy.indexName(
14✔
1255
                            clonedTable,
14✔
1256
                            index.columnNames,
14✔
1257
                            index.where,
14✔
1258
                        )
14✔
1259

14✔
1260
                    // Skip renaming if Index has user defined constraint name
14✔
1261
                    if (index.name !== oldIndexName) return
14✔
1262

10✔
1263
                    // build new constraint name
10✔
1264
                    index.columnNames.splice(
10✔
1265
                        index.columnNames.indexOf(oldColumn.name),
10✔
1266
                        1,
10✔
1267
                    )
10✔
1268
                    index.columnNames.push(newColumn.name)
10✔
1269
                    const newIndexName =
10✔
1270
                        this.connection.namingStrategy.indexName(
10✔
1271
                            clonedTable,
10✔
1272
                            index.columnNames,
10✔
1273
                            index.where,
10✔
1274
                        )
10✔
1275

10✔
1276
                    // build queries
10✔
1277
                    upQueries.push(
10✔
1278
                        new Query(
10✔
1279
                            `ALTER INDEX "${index.name}" RENAME TO "${newIndexName}"`,
10✔
1280
                        ),
10✔
1281
                    )
10✔
1282
                    downQueries.push(
10✔
1283
                        new Query(
10✔
1284
                            `ALTER INDEX "${newIndexName}" RENAME TO "${index.name}"`,
10✔
1285
                        ),
10✔
1286
                    )
10✔
1287

10✔
1288
                    // replace constraint name
10✔
1289
                    index.name = newIndexName
10✔
1290
                })
44✔
1291

44✔
1292
                // rename foreign key constraints
44✔
1293
                clonedTable
44✔
1294
                    .findColumnForeignKeys(oldColumn)
44✔
1295
                    .forEach((foreignKey) => {
44✔
1296
                        const foreignKeyName =
18✔
1297
                            this.connection.namingStrategy.foreignKeyName(
18✔
1298
                                clonedTable,
18✔
1299
                                foreignKey.columnNames,
18✔
1300
                                this.getTablePath(foreignKey),
18✔
1301
                                foreignKey.referencedColumnNames,
18✔
1302
                            )
18✔
1303

18✔
1304
                        // Skip renaming if foreign key has user defined constraint name
18✔
1305
                        if (foreignKey.name !== foreignKeyName) return
18✔
1306

2✔
1307
                        // build new constraint name
2✔
1308
                        foreignKey.columnNames.splice(
2✔
1309
                            foreignKey.columnNames.indexOf(oldColumn.name),
2✔
1310
                            1,
2✔
1311
                        )
2✔
1312
                        foreignKey.columnNames.push(newColumn.name)
2✔
1313
                        const newForeignKeyName =
2✔
1314
                            this.connection.namingStrategy.foreignKeyName(
2✔
1315
                                clonedTable,
2✔
1316
                                foreignKey.columnNames,
2✔
1317
                                this.getTablePath(foreignKey),
2✔
1318
                                foreignKey.referencedColumnNames,
2✔
1319
                            )
2✔
1320

2✔
1321
                        // build queries
2✔
1322
                        upQueries.push(
2✔
1323
                            new Query(
2✔
1324
                                `ALTER TABLE ${this.escapePath(
2✔
1325
                                    table,
2✔
1326
                                )} RENAME CONSTRAINT "${
2✔
1327
                                    foreignKey.name
2✔
1328
                                }" TO "${newForeignKeyName}"`,
2✔
1329
                            ),
2✔
1330
                        )
2✔
1331
                        downQueries.push(
2✔
1332
                            new Query(
2✔
1333
                                `ALTER TABLE ${this.escapePath(
2✔
1334
                                    table,
2✔
1335
                                )} RENAME CONSTRAINT "${newForeignKeyName}" TO "${
2✔
1336
                                    foreignKey.name
2✔
1337
                                }"`,
2✔
1338
                            ),
2✔
1339
                        )
2✔
1340

2✔
1341
                        // replace constraint name
2✔
1342
                        foreignKey.name = newForeignKeyName
2✔
1343
                    })
44✔
1344

44✔
1345
                // rename old column in the Table object
44✔
1346
                const oldTableColumn = clonedTable.columns.find(
44✔
1347
                    (column) => column.name === oldColumn.name,
44✔
1348
                )
44✔
1349
                clonedTable.columns[
44✔
1350
                    clonedTable.columns.indexOf(oldTableColumn!)
44✔
1351
                ].name = newColumn.name
44✔
1352
                oldColumn.name = newColumn.name
44✔
1353
            }
44✔
1354

66✔
1355
            if (this.isColumnChanged(oldColumn, newColumn, true)) {
66✔
1356
                let defaultUp: string = ""
4✔
1357
                let defaultDown: string = ""
4✔
1358
                let nullableUp: string = ""
4✔
1359
                let nullableDown: string = ""
4✔
1360

4✔
1361
                // changing column default
4✔
1362
                if (
4✔
1363
                    newColumn.default !== null &&
4✔
1364
                    newColumn.default !== undefined
4✔
1365
                ) {
4✔
1366
                    defaultUp = `DEFAULT ${newColumn.default}`
4✔
1367

4✔
1368
                    if (
4✔
1369
                        oldColumn.default !== null &&
4✔
1370
                        oldColumn.default !== undefined
4✔
1371
                    ) {
4✔
1372
                        defaultDown = `DEFAULT ${oldColumn.default}`
2✔
1373
                    } else {
2✔
1374
                        defaultDown = "DEFAULT NULL"
2✔
1375
                    }
2✔
1376
                } else if (
4!
1377
                    oldColumn.default !== null &&
×
1378
                    oldColumn.default !== undefined
×
1379
                ) {
×
1380
                    defaultUp = "DEFAULT NULL"
×
1381
                    defaultDown = `DEFAULT ${oldColumn.default}`
×
1382
                }
×
1383

4✔
1384
                // changing column isNullable property
4✔
1385
                if (newColumn.isNullable !== oldColumn.isNullable) {
4!
1386
                    if (newColumn.isNullable === true) {
×
1387
                        nullableUp = "NULL"
×
1388
                        nullableDown = "NOT NULL"
×
1389
                    } else {
×
1390
                        nullableUp = "NOT NULL"
×
1391
                        nullableDown = "NULL"
×
1392
                    }
×
1393
                }
×
1394

4✔
1395
                upQueries.push(
4✔
1396
                    new Query(
4✔
1397
                        `ALTER TABLE ${this.escapePath(table)} MODIFY "${
4✔
1398
                            oldColumn.name
4✔
1399
                        }" ${this.connection.driver.createFullType(
4✔
1400
                            newColumn,
4✔
1401
                        )} ${defaultUp} ${nullableUp}`,
4✔
1402
                    ),
4✔
1403
                )
4✔
1404
                downQueries.push(
4✔
1405
                    new Query(
4✔
1406
                        `ALTER TABLE ${this.escapePath(table)} MODIFY "${
4✔
1407
                            oldColumn.name
4✔
1408
                        }" ${this.connection.driver.createFullType(
4✔
1409
                            oldColumn,
4✔
1410
                        )} ${defaultDown} ${nullableDown}`,
4✔
1411
                    ),
4✔
1412
                )
4✔
1413
            }
4✔
1414

66✔
1415
            if (newColumn.isPrimary !== oldColumn.isPrimary) {
66✔
1416
                const primaryColumns = clonedTable.primaryColumns
8✔
1417

8✔
1418
                // if primary column state changed, we must always drop existed constraint.
8✔
1419
                if (primaryColumns.length > 0) {
8✔
1420
                    const pkName = primaryColumns[0].primaryKeyConstraintName
6✔
1421
                        ? primaryColumns[0].primaryKeyConstraintName
6!
1422
                        : this.connection.namingStrategy.primaryKeyName(
6✔
1423
                              clonedTable,
6✔
1424
                              primaryColumns.map((column) => column.name),
6✔
1425
                          )
6✔
1426

6✔
1427
                    const columnNames = primaryColumns
6✔
1428
                        .map((column) => `"${column.name}"`)
6✔
1429
                        .join(", ")
6✔
1430

6✔
1431
                    upQueries.push(
6✔
1432
                        new Query(
6✔
1433
                            `ALTER TABLE ${this.escapePath(
6✔
1434
                                table,
6✔
1435
                            )} DROP CONSTRAINT "${pkName}"`,
6✔
1436
                        ),
6✔
1437
                    )
6✔
1438
                    downQueries.push(
6✔
1439
                        new Query(
6✔
1440
                            `ALTER TABLE ${this.escapePath(
6✔
1441
                                table,
6✔
1442
                            )} ADD CONSTRAINT "${pkName}" PRIMARY KEY (${columnNames})`,
6✔
1443
                        ),
6✔
1444
                    )
6✔
1445
                }
6✔
1446

8✔
1447
                if (newColumn.isPrimary === true) {
8✔
1448
                    primaryColumns.push(newColumn)
4✔
1449
                    // update column in table
4✔
1450
                    const column = clonedTable.columns.find(
4✔
1451
                        (column) => column.name === newColumn.name,
4✔
1452
                    )
4✔
1453
                    column!.isPrimary = true
4✔
1454
                    const pkName = primaryColumns[0].primaryKeyConstraintName
4✔
1455
                        ? primaryColumns[0].primaryKeyConstraintName
4!
1456
                        : this.connection.namingStrategy.primaryKeyName(
4✔
1457
                              clonedTable,
4✔
1458
                              primaryColumns.map((column) => column.name),
4✔
1459
                          )
4✔
1460

4✔
1461
                    const columnNames = primaryColumns
4✔
1462
                        .map((column) => `"${column.name}"`)
4✔
1463
                        .join(", ")
4✔
1464

4✔
1465
                    upQueries.push(
4✔
1466
                        new Query(
4✔
1467
                            `ALTER TABLE ${this.escapePath(
4✔
1468
                                table,
4✔
1469
                            )} ADD CONSTRAINT "${pkName}" PRIMARY KEY (${columnNames})`,
4✔
1470
                        ),
4✔
1471
                    )
4✔
1472
                    downQueries.push(
4✔
1473
                        new Query(
4✔
1474
                            `ALTER TABLE ${this.escapePath(
4✔
1475
                                table,
4✔
1476
                            )} DROP CONSTRAINT "${pkName}"`,
4✔
1477
                        ),
4✔
1478
                    )
4✔
1479
                } else {
4✔
1480
                    const primaryColumn = primaryColumns.find(
4✔
1481
                        (c) => c.name === newColumn.name,
4✔
1482
                    )
4✔
1483
                    primaryColumns.splice(
4✔
1484
                        primaryColumns.indexOf(primaryColumn!),
4✔
1485
                        1,
4✔
1486
                    )
4✔
1487

4✔
1488
                    // update column in table
4✔
1489
                    const column = clonedTable.columns.find(
4✔
1490
                        (column) => column.name === newColumn.name,
4✔
1491
                    )
4✔
1492
                    column!.isPrimary = false
4✔
1493

4✔
1494
                    // if we have another primary keys, we must recreate constraint.
4✔
1495
                    if (primaryColumns.length > 0) {
4✔
1496
                        const pkName = primaryColumns[0]
2✔
1497
                            .primaryKeyConstraintName
2✔
1498
                            ? primaryColumns[0].primaryKeyConstraintName
2!
1499
                            : this.connection.namingStrategy.primaryKeyName(
2✔
1500
                                  clonedTable,
2✔
1501
                                  primaryColumns.map((column) => column.name),
2✔
1502
                              )
2✔
1503

2✔
1504
                        const columnNames = primaryColumns
2✔
1505
                            .map((column) => `"${column.name}"`)
2✔
1506
                            .join(", ")
2✔
1507

2✔
1508
                        upQueries.push(
2✔
1509
                            new Query(
2✔
1510
                                `ALTER TABLE ${this.escapePath(
2✔
1511
                                    table,
2✔
1512
                                )} ADD CONSTRAINT "${pkName}" PRIMARY KEY (${columnNames})`,
2✔
1513
                            ),
2✔
1514
                        )
2✔
1515
                        downQueries.push(
2✔
1516
                            new Query(
2✔
1517
                                `ALTER TABLE ${this.escapePath(
2✔
1518
                                    table,
2✔
1519
                                )} DROP CONSTRAINT "${pkName}"`,
2✔
1520
                            ),
2✔
1521
                        )
2✔
1522
                    }
2✔
1523
                }
4✔
1524
            }
8✔
1525

66✔
1526
            if (newColumn.isUnique !== oldColumn.isUnique) {
66✔
1527
                if (newColumn.isUnique === true) {
2✔
1528
                    const uniqueConstraint = new TableUnique({
2✔
1529
                        name: this.connection.namingStrategy.uniqueConstraintName(
2✔
1530
                            table,
2✔
1531
                            [newColumn.name],
2✔
1532
                        ),
2✔
1533
                        columnNames: [newColumn.name],
2✔
1534
                    })
2✔
1535
                    clonedTable.uniques.push(uniqueConstraint)
2✔
1536
                    upQueries.push(
2✔
1537
                        new Query(
2✔
1538
                            `ALTER TABLE ${this.escapePath(
2✔
1539
                                table,
2✔
1540
                            )} ADD CONSTRAINT "${
2✔
1541
                                uniqueConstraint.name
2✔
1542
                            }" UNIQUE ("${newColumn.name}")`,
2✔
1543
                        ),
2✔
1544
                    )
2✔
1545
                    downQueries.push(
2✔
1546
                        new Query(
2✔
1547
                            `ALTER TABLE ${this.escapePath(
2✔
1548
                                table,
2✔
1549
                            )} DROP CONSTRAINT "${uniqueConstraint.name}"`,
2✔
1550
                        ),
2✔
1551
                    )
2✔
1552
                } else {
2!
1553
                    const uniqueConstraint = clonedTable.uniques.find(
×
1554
                        (unique) => {
×
1555
                            return (
×
1556
                                unique.columnNames.length === 1 &&
×
1557
                                !!unique.columnNames.find(
×
1558
                                    (columnName) =>
×
1559
                                        columnName === newColumn.name,
×
1560
                                )
×
1561
                            )
×
1562
                        },
×
1563
                    )
×
1564
                    clonedTable.uniques.splice(
×
1565
                        clonedTable.uniques.indexOf(uniqueConstraint!),
×
1566
                        1,
×
1567
                    )
×
1568
                    upQueries.push(
×
1569
                        new Query(
×
1570
                            `ALTER TABLE ${this.escapePath(
×
1571
                                table,
×
1572
                            )} DROP CONSTRAINT "${uniqueConstraint!.name}"`,
×
1573
                        ),
×
1574
                    )
×
1575
                    downQueries.push(
×
1576
                        new Query(
×
1577
                            `ALTER TABLE ${this.escapePath(
×
1578
                                table,
×
1579
                            )} ADD CONSTRAINT "${
×
1580
                                uniqueConstraint!.name
×
1581
                            }" UNIQUE ("${newColumn.name}")`,
×
1582
                        ),
×
1583
                    )
×
1584
                }
×
1585
            }
2✔
1586

66✔
1587
            await this.executeQueries(upQueries, downQueries)
66✔
1588
            this.replaceCachedTable(table, clonedTable)
66✔
1589
        }
66✔
1590
    }
98✔
1591

23✔
1592
    /**
23✔
1593
     * Changes a column in the table.
23✔
1594
     * @param tableOrName
23✔
1595
     * @param changedColumns
23✔
1596
     */
23✔
1597
    async changeColumns(
23✔
1598
        tableOrName: Table | string,
48✔
1599
        changedColumns: { newColumn: TableColumn; oldColumn: TableColumn }[],
48✔
1600
    ): Promise<void> {
48✔
1601
        for (const { oldColumn, newColumn } of changedColumns) {
48✔
1602
            await this.changeColumn(tableOrName, oldColumn, newColumn)
60✔
1603
        }
60✔
1604
    }
48✔
1605

23✔
1606
    /**
23✔
1607
     * Drops column in the table.
23✔
1608
     * @param tableOrName
23✔
1609
     * @param columnOrName
23✔
1610
     * @param ifExists
23✔
1611
     */
23✔
1612
    async dropColumn(
23✔
1613
        tableOrName: Table | string,
68✔
1614
        columnOrName: TableColumn | string,
68✔
1615
        ifExists?: boolean,
68✔
1616
    ): Promise<void> {
68✔
1617
        const table = InstanceChecker.isTable(tableOrName)
68✔
1618
            ? tableOrName
68✔
1619
            : await this.getCachedTable(tableOrName)
68✔
1620
        const column = InstanceChecker.isTableColumn(columnOrName)
8✔
1621
            ? columnOrName
68✔
1622
            : table.findColumnByName(columnOrName)
68✔
1623
        if (!column) {
68✔
1624
            if (ifExists) return
4✔
1625
            throw new TypeORMError(
2✔
1626
                `Column "${columnOrName}" was not found in table ${this.escapePath(
2✔
1627
                    table,
2✔
1628
                )}`,
2✔
1629
            )
2✔
1630
        }
2✔
1631

64✔
1632
        const clonedTable = table.clone()
64✔
1633
        const upQueries: Query[] = []
64✔
1634
        const downQueries: Query[] = []
64✔
1635

64✔
1636
        // drop primary key constraint
64✔
1637
        if (column.isPrimary) {
68✔
1638
            const pkName = column.primaryKeyConstraintName
14✔
1639
                ? column.primaryKeyConstraintName
14!
1640
                : this.connection.namingStrategy.primaryKeyName(
14✔
1641
                      clonedTable,
14✔
1642
                      clonedTable.primaryColumns.map((column) => column.name),
14✔
1643
                  )
14✔
1644

14✔
1645
            const columnNames = clonedTable.primaryColumns
14✔
1646
                .map((primaryColumn) => `"${primaryColumn.name}"`)
14✔
1647
                .join(", ")
14✔
1648

14✔
1649
            upQueries.push(
14✔
1650
                new Query(
14✔
1651
                    `ALTER TABLE ${this.escapePath(
14✔
1652
                        clonedTable,
14✔
1653
                    )} DROP CONSTRAINT "${pkName}"`,
14✔
1654
                ),
14✔
1655
            )
14✔
1656
            downQueries.push(
14✔
1657
                new Query(
14✔
1658
                    `ALTER TABLE ${this.escapePath(
14✔
1659
                        clonedTable,
14✔
1660
                    )} ADD CONSTRAINT "${pkName}" PRIMARY KEY (${columnNames})`,
14✔
1661
                ),
14✔
1662
            )
14✔
1663

14✔
1664
            // update column in table
14✔
1665
            const tableColumn = clonedTable.findColumnByName(column.name)
14✔
1666
            tableColumn!.isPrimary = false
14✔
1667

14✔
1668
            // if primary key have multiple columns, we must recreate it without dropped column
14✔
1669
            if (clonedTable.primaryColumns.length > 0) {
14!
1670
                const pkName = clonedTable.primaryColumns[0]
×
1671
                    .primaryKeyConstraintName
×
1672
                    ? clonedTable.primaryColumns[0].primaryKeyConstraintName
×
1673
                    : this.connection.namingStrategy.primaryKeyName(
×
1674
                          clonedTable,
×
1675
                          clonedTable.primaryColumns.map(
×
1676
                              (column) => column.name,
×
1677
                          ),
×
1678
                      )
×
1679

×
1680
                const columnNames = clonedTable.primaryColumns
×
1681
                    .map((primaryColumn) => `"${primaryColumn.name}"`)
×
1682
                    .join(", ")
×
1683

×
1684
                upQueries.push(
×
1685
                    new Query(
×
1686
                        `ALTER TABLE ${this.escapePath(
×
1687
                            clonedTable,
×
1688
                        )} ADD CONSTRAINT "${pkName}" PRIMARY KEY (${columnNames})`,
×
1689
                    ),
×
1690
                )
×
1691
                downQueries.push(
×
1692
                    new Query(
×
1693
                        `ALTER TABLE ${this.escapePath(
×
1694
                            clonedTable,
×
1695
                        )} DROP CONSTRAINT "${pkName}"`,
×
1696
                    ),
×
1697
                )
×
1698
            }
×
1699
        }
14✔
1700

64✔
1701
        // drop column index
64✔
1702
        const columnIndex = clonedTable.indices.find(
64✔
1703
            (index) =>
64✔
1704
                index.columnNames.length === 1 &&
2✔
1705
                index.columnNames[0] === column.name,
64✔
1706
        )
64✔
1707
        if (columnIndex) {
68!
1708
            upQueries.push(this.dropIndexSql(columnIndex))
×
1709
            downQueries.push(this.createIndexSql(table, columnIndex))
×
1710
        }
×
1711

64✔
1712
        // drop column check
64✔
1713
        const columnCheck = clonedTable.checks.find(
64✔
1714
            (check) =>
64✔
1715
                !!check.columnNames &&
32✔
1716
                check.columnNames.length === 1 &&
32✔
1717
                check.columnNames[0] === column.name,
64✔
1718
        )
64✔
1719
        if (columnCheck) {
68✔
1720
            clonedTable.checks.splice(
4✔
1721
                clonedTable.checks.indexOf(columnCheck),
4✔
1722
                1,
4✔
1723
            )
4✔
1724
            upQueries.push(this.dropCheckConstraintSql(table, columnCheck))
4✔
1725
            downQueries.push(this.createCheckConstraintSql(table, columnCheck))
4✔
1726
        }
4✔
1727

64✔
1728
        // drop column unique
64✔
1729
        const columnUnique = clonedTable.uniques.find(
64✔
1730
            (unique) =>
64✔
1731
                unique.columnNames.length === 1 &&
54✔
1732
                unique.columnNames[0] === column.name,
64✔
1733
        )
64✔
1734
        if (columnUnique) {
68✔
1735
            clonedTable.uniques.splice(
6✔
1736
                clonedTable.uniques.indexOf(columnUnique),
6✔
1737
                1,
6✔
1738
            )
6✔
1739
            upQueries.push(this.dropUniqueConstraintSql(table, columnUnique))
6✔
1740
            downQueries.push(
6✔
1741
                this.createUniqueConstraintSql(table, columnUnique),
6✔
1742
            )
6✔
1743
        }
6✔
1744

64✔
1745
        upQueries.push(
64✔
1746
            new Query(
64✔
1747
                `ALTER TABLE ${this.escapePath(table)} DROP COLUMN "${
64✔
1748
                    column.name
64✔
1749
                }"`,
64✔
1750
            ),
64✔
1751
        )
64✔
1752
        downQueries.push(
64✔
1753
            new Query(
64✔
1754
                `ALTER TABLE ${this.escapePath(
64✔
1755
                    table,
64✔
1756
                )} ADD ${this.buildCreateColumnSql(column)}`,
64✔
1757
            ),
64✔
1758
        )
64✔
1759

64✔
1760
        if (column.generatedType && column.asExpression) {
68✔
1761
            const deleteQuery = this.deleteTypeormMetadataSql({
6✔
1762
                table: table.name,
6✔
1763
                type: MetadataTableType.GENERATED_COLUMN,
6✔
1764
                name: column.name,
6✔
1765
            })
6✔
1766
            const insertQuery = this.insertTypeormMetadataSql({
6✔
1767
                table: table.name,
6✔
1768
                type: MetadataTableType.GENERATED_COLUMN,
6✔
1769
                name: column.name,
6✔
1770
                value: column.asExpression,
6✔
1771
            })
6✔
1772

6✔
1773
            upQueries.push(deleteQuery)
6✔
1774
            downQueries.push(insertQuery)
6✔
1775
        }
6✔
1776

64✔
1777
        await this.executeQueries(upQueries, downQueries)
64✔
1778

64✔
1779
        clonedTable.removeColumn(column)
64✔
1780
        this.replaceCachedTable(table, clonedTable)
64✔
1781
    }
64✔
1782

23✔
1783
    /**
23✔
1784
     * Drops the columns in the table.
23✔
1785
     * @param tableOrName
23✔
1786
     * @param columns
23✔
1787
     * @param ifExists
23✔
1788
     */
23✔
1789
    async dropColumns(
23✔
1790
        tableOrName: Table | string,
10✔
1791
        columns: TableColumn[] | string[],
10✔
1792
        ifExists?: boolean,
10✔
1793
    ): Promise<void> {
10✔
1794
        for (const column of [...columns]) {
10✔
1795
            await this.dropColumn(tableOrName, column, ifExists)
26✔
1796
        }
26✔
1797
    }
10✔
1798

23✔
1799
    /**
23✔
1800
     * Creates a new primary key.
23✔
1801
     * @param tableOrName
23✔
1802
     * @param columnNames
23✔
1803
     * @param constraintName
23✔
1804
     */
23✔
1805
    async createPrimaryKey(
23✔
1806
        tableOrName: Table | string,
4✔
1807
        columnNames: string[],
4✔
1808
        constraintName?: string,
4✔
1809
    ): Promise<void> {
4✔
1810
        const table = InstanceChecker.isTable(tableOrName)
4✔
1811
            ? tableOrName
4!
1812
            : await this.getCachedTable(tableOrName)
4✔
1813
        const clonedTable = table.clone()
4✔
1814

4✔
1815
        const up = this.createPrimaryKeySql(table, columnNames, constraintName)
4✔
1816

4✔
1817
        // mark columns as primary, because dropPrimaryKeySql build constraint name from table primary column names.
4✔
1818
        clonedTable.columns.forEach((column) => {
4✔
1819
            if (columnNames.find((columnName) => columnName === column.name))
10✔
1820
                column.isPrimary = true
10✔
1821
        })
4✔
1822
        const down = this.dropPrimaryKeySql(clonedTable)
4✔
1823

4✔
1824
        await this.executeQueries(up, down)
4✔
1825
        this.replaceCachedTable(table, clonedTable)
4✔
1826
    }
4✔
1827

23✔
1828
    /**
23✔
1829
     * Updates composite primary keys.
23✔
1830
     * @param tableOrName
23✔
1831
     * @param columns
23✔
1832
     */
23✔
1833
    async updatePrimaryKeys(
23✔
1834
        tableOrName: Table | string,
4✔
1835
        columns: TableColumn[],
4✔
1836
    ): Promise<void> {
4✔
1837
        const table = InstanceChecker.isTable(tableOrName)
4✔
1838
            ? tableOrName
4✔
1839
            : await this.getCachedTable(tableOrName)
4!
1840
        const columnNames = columns.map((column) => column.name)
×
1841
        const clonedTable = table.clone()
×
1842
        const upQueries: Query[] = []
×
1843
        const downQueries: Query[] = []
×
1844

×
1845
        // if table already have primary columns, we must drop them.
×
1846
        const primaryColumns = clonedTable.primaryColumns
×
1847
        if (primaryColumns.length > 0) {
4✔
1848
            const pkName = primaryColumns[0].primaryKeyConstraintName
4✔
1849
                ? primaryColumns[0].primaryKeyConstraintName
4!
1850
                : this.connection.namingStrategy.primaryKeyName(
4✔
1851
                      clonedTable,
4✔
1852
                      primaryColumns.map((column) => column.name),
4✔
1853
                  )
4✔
1854

4✔
1855
            const columnNamesString = primaryColumns
4✔
1856
                .map((column) => `"${column.name}"`)
4✔
1857
                .join(", ")
4✔
1858

4✔
1859
            upQueries.push(
4✔
1860
                new Query(
4✔
1861
                    `ALTER TABLE ${this.escapePath(
4✔
1862
                        table,
4✔
1863
                    )} DROP CONSTRAINT "${pkName}"`,
4✔
1864
                ),
4✔
1865
            )
4✔
1866
            downQueries.push(
4✔
1867
                new Query(
4✔
1868
                    `ALTER TABLE ${this.escapePath(
4✔
1869
                        table,
4✔
1870
                    )} ADD CONSTRAINT "${pkName}" PRIMARY KEY (${columnNamesString})`,
4✔
1871
                ),
4✔
1872
            )
4✔
1873
        }
4✔
1874

4✔
1875
        // update columns in table.
4✔
1876
        clonedTable.columns
4✔
1877
            .filter((column) => columnNames.indexOf(column.name) !== -1)
4✔
1878
            .forEach((column) => {
4✔
1879
                column.isPrimary = true
8✔
1880
            })
4✔
1881

4✔
1882
        const pkName = primaryColumns[0].primaryKeyConstraintName
4✔
1883
            ? primaryColumns[0].primaryKeyConstraintName
4!
1884
            : this.connection.namingStrategy.primaryKeyName(
4✔
1885
                  clonedTable,
4✔
1886
                  columnNames,
4✔
1887
              )
4✔
1888

4✔
1889
        const columnNamesString = columnNames
4✔
1890
            .map((columnName) => `"${columnName}"`)
4✔
1891
            .join(", ")
4✔
1892
        upQueries.push(
4✔
1893
            new Query(
4✔
1894
                `ALTER TABLE ${this.escapePath(
4✔
1895
                    table,
4✔
1896
                )} ADD CONSTRAINT "${pkName}" PRIMARY KEY (${columnNamesString})`,
4✔
1897
            ),
4✔
1898
        )
4✔
1899
        downQueries.push(
4✔
1900
            new Query(
4✔
1901
                `ALTER TABLE ${this.escapePath(
4✔
1902
                    table,
4✔
1903
                )} DROP CONSTRAINT "${pkName}"`,
4✔
1904
            ),
4✔
1905
        )
4✔
1906

4✔
1907
        await this.executeQueries(upQueries, downQueries)
4✔
1908
        this.replaceCachedTable(table, clonedTable)
4✔
1909
    }
4✔
1910

23✔
1911
    /**
23✔
1912
     * Drops a primary key.
23✔
1913
     * @param tableOrName
23✔
1914
     * @param constraintName
23✔
1915
     * @param ifExists
23✔
1916
     */
23✔
1917
    async dropPrimaryKey(
23✔
1918
        tableOrName: Table | string,
8✔
1919
        constraintName?: string,
8✔
1920
        ifExists?: boolean,
8✔
1921
    ): Promise<void> {
8✔
1922
        const table = InstanceChecker.isTable(tableOrName)
8✔
1923
            ? tableOrName
8✔
1924
            : await this.getCachedTable(tableOrName)
8✔
1925
        if (ifExists && table.primaryColumns.length === 0) return
8!
1926

8✔
1927
        const up = this.dropPrimaryKeySql(table)
8✔
1928
        const down = this.createPrimaryKeySql(
8✔
1929
            table,
8✔
1930
            table.primaryColumns.map((column) => column.name),
8✔
1931
            constraintName,
8✔
1932
        )
8✔
1933
        await this.executeQueries(up, down)
8✔
1934
        table.primaryColumns.forEach((column) => {
8✔
1935
            column.isPrimary = false
8✔
1936
        })
8✔
1937
    }
8✔
1938

23✔
1939
    /**
23✔
1940
     * Creates a new unique constraint.
23✔
1941
     * @param tableOrName
23✔
1942
     * @param uniqueConstraint
23✔
1943
     */
23✔
1944
    async createUniqueConstraint(
23✔
1945
        tableOrName: Table | string,
16✔
1946
        uniqueConstraint: TableUnique,
16✔
1947
    ): Promise<void> {
16✔
1948
        const table = InstanceChecker.isTable(tableOrName)
16✔
1949
            ? tableOrName
16✔
1950
            : await this.getCachedTable(tableOrName)
16✔
1951

12✔
1952
        // new unique constraint may be passed without name. In this case we generate unique name manually.
12✔
1953
        if (!uniqueConstraint.name)
12✔
1954
            uniqueConstraint.name =
16✔
1955
                this.connection.namingStrategy.uniqueConstraintName(
4✔
1956
                    table,
4✔
1957
                    uniqueConstraint.columnNames,
4✔
1958
                )
4✔
1959

16✔
1960
        const up = this.createUniqueConstraintSql(table, uniqueConstraint)
16✔
1961
        const down = this.dropUniqueConstraintSql(table, uniqueConstraint)
16✔
1962
        await this.executeQueries(up, down)
16✔
1963
        table.addUniqueConstraint(uniqueConstraint)
16✔
1964
    }
16✔
1965

23✔
1966
    /**
23✔
1967
     * Creates a new unique constraints.
23✔
1968
     * @param tableOrName
23✔
1969
     * @param uniqueConstraints
23✔
1970
     */
23✔
1971
    async createUniqueConstraints(
23✔
1972
        tableOrName: Table | string,
6✔
1973
        uniqueConstraints: TableUnique[],
6✔
1974
    ): Promise<void> {
6✔
1975
        const promises = uniqueConstraints.map((uniqueConstraint) =>
6✔
1976
            this.createUniqueConstraint(tableOrName, uniqueConstraint),
6✔
1977
        )
6✔
1978
        await Promise.all(promises)
6✔
1979
    }
6✔
1980

23✔
1981
    /**
23✔
1982
     * Drops a unique constraint.
23✔
1983
     * @param tableOrName
23✔
1984
     * @param uniqueOrName
23✔
1985
     * @param ifExists
23✔
1986
     */
23✔
1987
    async dropUniqueConstraint(
23✔
1988
        tableOrName: Table | string,
18✔
1989
        uniqueOrName: TableUnique | string,
18✔
1990
        ifExists?: boolean,
18✔
1991
    ): Promise<void> {
18✔
1992
        const table = InstanceChecker.isTable(tableOrName)
18✔
1993
            ? tableOrName
18✔
1994
            : await this.getCachedTable(tableOrName)
18✔
1995
        const uniqueConstraint = InstanceChecker.isTableUnique(uniqueOrName)
10✔
1996
            ? uniqueOrName
18✔
1997
            : table.uniques.find((u) => u.name === uniqueOrName)
18✔
1998
        if (!uniqueConstraint) {
18✔
1999
            if (ifExists) return
2✔
2000
            throw new TypeORMError(
×
2001
                `Supplied unique constraint was not found in table ${table.name}`,
×
2002
            )
×
NEW
2003
        }
×
2004

16✔
2005
        const up = this.dropUniqueConstraintSql(table, uniqueConstraint)
16✔
2006
        const down = this.createUniqueConstraintSql(table, uniqueConstraint)
16✔
2007
        await this.executeQueries(up, down)
16✔
2008
        table.removeUniqueConstraint(uniqueConstraint)
16✔
2009
    }
16✔
2010

23✔
2011
    /**
23✔
2012
     * Drops unique constraints.
23✔
2013
     * @param tableOrName
23✔
2014
     * @param uniqueConstraints
23✔
2015
     * @param ifExists
23✔
2016
     */
23✔
2017
    async dropUniqueConstraints(
23✔
2018
        tableOrName: Table | string,
8✔
2019
        uniqueConstraints: TableUnique[],
8✔
2020
        ifExists?: boolean,
8✔
2021
    ): Promise<void> {
8✔
2022
        const promises = uniqueConstraints.map((uniqueConstraint) =>
8✔
2023
            this.dropUniqueConstraint(tableOrName, uniqueConstraint, ifExists),
8✔
2024
        )
8✔
2025
        await Promise.all(promises)
8✔
2026
    }
8✔
2027

23✔
2028
    /**
23✔
2029
     * Creates new check constraint.
23✔
2030
     * @param tableOrName
23✔
2031
     * @param checkConstraint
23✔
2032
     */
23✔
2033
    async createCheckConstraint(
23✔
2034
        tableOrName: Table | string,
10✔
2035
        checkConstraint: TableCheck,
10✔
2036
    ): Promise<void> {
10✔
2037
        const table = InstanceChecker.isTable(tableOrName)
10✔
2038
            ? tableOrName
10✔
2039
            : await this.getCachedTable(tableOrName)
10✔
2040

6✔
2041
        // new unique constraint may be passed without name. In this case we generate unique name manually.
6✔
2042
        if (!checkConstraint.name)
6✔
2043
            checkConstraint.name =
6✔
2044
                this.connection.namingStrategy.checkConstraintName(
6✔
2045
                    table,
6✔
2046
                    checkConstraint.expression!,
6✔
2047
                )
6✔
2048

10✔
2049
        const up = this.createCheckConstraintSql(table, checkConstraint)
10✔
2050
        const down = this.dropCheckConstraintSql(table, checkConstraint)
10✔
2051
        await this.executeQueries(up, down)
10✔
2052
        table.addCheckConstraint(checkConstraint)
10✔
2053
    }
10✔
2054

23✔
2055
    /**
23✔
2056
     * Creates new check constraints.
23✔
2057
     * @param tableOrName
23✔
2058
     * @param checkConstraints
23✔
2059
     */
23✔
2060
    async createCheckConstraints(
23✔
2061
        tableOrName: Table | string,
4✔
2062
        checkConstraints: TableCheck[],
4✔
2063
    ): Promise<void> {
4✔
2064
        const promises = checkConstraints.map((checkConstraint) =>
4✔
2065
            this.createCheckConstraint(tableOrName, checkConstraint),
4✔
2066
        )
4✔
2067
        await Promise.all(promises)
4✔
2068
    }
4✔
2069

23✔
2070
    /**
23✔
2071
     * Drops check constraint.
23✔
2072
     * @param tableOrName
23✔
2073
     * @param checkOrName
23✔
2074
     * @param ifExists
23✔
2075
     */
23✔
2076
    async dropCheckConstraint(
23✔
2077
        tableOrName: Table | string,
8✔
2078
        checkOrName: TableCheck | string,
8✔
2079
        ifExists?: boolean,
8✔
2080
    ): Promise<void> {
8✔
2081
        const table = InstanceChecker.isTable(tableOrName)
8✔
2082
            ? tableOrName
8✔
2083
            : await this.getCachedTable(tableOrName)
8✔
2084
        const checkConstraint = InstanceChecker.isTableCheck(checkOrName)
2✔
2085
            ? checkOrName
8✔
2086
            : table.checks.find((c) => c.name === checkOrName)
8✔
2087
        if (!checkConstraint) {
8✔
2088
            if (ifExists) return
2✔
2089
            throw new TypeORMError(
×
2090
                `Supplied check constraint was not found in table ${table.name}`,
×
2091
            )
×
NEW
2092
        }
×
2093

6✔
2094
        const up = this.dropCheckConstraintSql(table, checkConstraint)
6✔
2095
        const down = this.createCheckConstraintSql(table, checkConstraint)
6✔
2096
        await this.executeQueries(up, down)
6✔
2097
        table.removeCheckConstraint(checkConstraint)
6✔
2098
    }
6✔
2099

23✔
2100
    /**
23✔
2101
     * Drops check constraints.
23✔
2102
     * @param tableOrName
23✔
2103
     * @param checkConstraints
23✔
2104
     * @param ifExists
23✔
2105
     */
23✔
2106
    async dropCheckConstraints(
23✔
2107
        tableOrName: Table | string,
4✔
2108
        checkConstraints: TableCheck[],
4✔
2109
        ifExists?: boolean,
4✔
2110
    ): Promise<void> {
4✔
2111
        const promises = checkConstraints.map((checkConstraint) =>
4✔
2112
            this.dropCheckConstraint(tableOrName, checkConstraint, ifExists),
4✔
2113
        )
4✔
2114
        await Promise.all(promises)
4✔
2115
    }
4✔
2116

23✔
2117
    /**
23✔
2118
     * Creates a new exclusion constraint.
23✔
2119
     * @param tableOrName
23✔
2120
     * @param exclusionConstraint
23✔
2121
     */
23✔
2122
    async createExclusionConstraint(
23✔
2123
        tableOrName: Table | string,
×
2124
        exclusionConstraint: TableExclusion,
×
2125
    ): Promise<void> {
×
2126
        throw new TypeORMError(`Oracle does not support exclusion constraints.`)
×
2127
    }
×
2128

23✔
2129
    /**
23✔
2130
     * Creates a new exclusion constraints.
23✔
2131
     * @param tableOrName
23✔
2132
     * @param exclusionConstraints
23✔
2133
     */
23✔
2134
    async createExclusionConstraints(
23✔
2135
        tableOrName: Table | string,
×
2136
        exclusionConstraints: TableExclusion[],
×
2137
    ): Promise<void> {
×
2138
        throw new TypeORMError(`Oracle does not support exclusion constraints.`)
×
2139
    }
×
2140

23✔
2141
    /**
23✔
2142
     * Drops exclusion constraint.
23✔
2143
     * @param tableOrName
23✔
2144
     * @param exclusionOrName
23✔
2145
     * @param ifExists
23✔
2146
     */
23✔
2147
    async dropExclusionConstraint(
23✔
2148
        tableOrName: Table | string,
×
2149
        exclusionOrName: TableExclusion | string,
×
NEW
2150
        ifExists?: boolean,
×
2151
    ): Promise<void> {
×
2152
        throw new TypeORMError(`Oracle does not support exclusion constraints.`)
×
2153
    }
×
2154

23✔
2155
    /**
23✔
2156
     * Drops exclusion constraints.
23✔
2157
     * @param tableOrName
23✔
2158
     * @param exclusionConstraints
23✔
2159
     * @param ifExists
23✔
2160
     */
23✔
2161
    async dropExclusionConstraints(
23✔
2162
        tableOrName: Table | string,
×
2163
        exclusionConstraints: TableExclusion[],
×
NEW
2164
        ifExists?: boolean,
×
2165
    ): Promise<void> {
×
2166
        throw new TypeORMError(`Oracle does not support exclusion constraints.`)
×
2167
    }
×
2168

23✔
2169
    /**
23✔
2170
     * Creates a new foreign key.
23✔
2171
     * @param tableOrName
23✔
2172
     * @param foreignKey
23✔
2173
     */
23✔
2174
    async createForeignKey(
23✔
2175
        tableOrName: Table | string,
6,064✔
2176
        foreignKey: TableForeignKey,
6,064✔
2177
    ): Promise<void> {
6,064✔
2178
        const table = InstanceChecker.isTable(tableOrName)
6,064✔
2179
            ? tableOrName
6,064✔
2180
            : await this.getCachedTable(tableOrName)
6,064✔
2181

10✔
2182
        // new FK may be passed without name. In this case we generate FK name manually.
10✔
2183
        if (!foreignKey.name)
10✔
2184
            foreignKey.name = this.connection.namingStrategy.foreignKeyName(
6,064✔
2185
                table,
2✔
2186
                foreignKey.columnNames,
2✔
2187
                this.getTablePath(foreignKey),
2✔
2188
                foreignKey.referencedColumnNames,
2✔
2189
            )
2✔
2190

6,064✔
2191
        const up = this.createForeignKeySql(table, foreignKey)
6,064✔
2192
        const down = this.dropForeignKeySql(table, foreignKey)
6,064✔
2193
        await this.executeQueries(up, down)
6,064✔
2194
        table.addForeignKey(foreignKey)
6,064✔
2195
    }
6,064✔
2196

23✔
2197
    /**
23✔
2198
     * Creates a new foreign keys.
23✔
2199
     * @param tableOrName
23✔
2200
     * @param foreignKeys
23✔
2201
     */
23✔
2202
    async createForeignKeys(
23✔
2203
        tableOrName: Table | string,
3,596✔
2204
        foreignKeys: TableForeignKey[],
3,596✔
2205
    ): Promise<void> {
3,596✔
2206
        const promises = foreignKeys.map((foreignKey) =>
3,596✔
2207
            this.createForeignKey(tableOrName, foreignKey),
3,596✔
2208
        )
3,596✔
2209
        await Promise.all(promises)
3,596✔
2210
    }
3,596✔
2211

23✔
2212
    /**
23✔
2213
     * Drops a foreign key from the table.
23✔
2214
     * @param tableOrName
23✔
2215
     * @param foreignKeyOrName
23✔
2216
     * @param ifExists
23✔
2217
     */
23✔
2218
    async dropForeignKey(
23✔
2219
        tableOrName: Table | string,
22✔
2220
        foreignKeyOrName: TableForeignKey | string,
22✔
2221
        ifExists?: boolean,
22✔
2222
    ): Promise<void> {
22✔
2223
        const table = InstanceChecker.isTable(tableOrName)
22✔
2224
            ? tableOrName
22✔
2225
            : await this.getCachedTable(tableOrName)
22✔
2226
        const foreignKey = InstanceChecker.isTableForeignKey(foreignKeyOrName)
10✔
2227
            ? foreignKeyOrName
22✔
2228
            : table.foreignKeys.find((fk) => fk.name === foreignKeyOrName)
22✔
2229
        if (!foreignKey) {
22✔
2230
            if (ifExists) return
2✔
2231
            throw new TypeORMError(
×
2232
                `Supplied foreign key was not found in table ${table.name}`,
×
2233
            )
×
NEW
2234
        }
×
2235

20✔
2236
        if (!foreignKey.name) {
22!
2237
            foreignKey.name = this.connection.namingStrategy.foreignKeyName(
×
2238
                table,
×
2239
                foreignKey.columnNames,
×
2240
                this.getTablePath(foreignKey),
×
2241
                foreignKey.referencedColumnNames,
×
2242
            )
×
2243
        }
×
2244

20✔
2245
        const up = this.dropForeignKeySql(table, foreignKey)
20✔
2246
        const down = this.createForeignKeySql(table, foreignKey)
20✔
2247
        await this.executeQueries(up, down)
20✔
2248
        table.removeForeignKey(foreignKey)
20✔
2249
    }
20✔
2250

23✔
2251
    /**
23✔
2252
     * Drops a foreign keys from the table.
23✔
2253
     * @param tableOrName
23✔
2254
     * @param foreignKeys
23✔
2255
     * @param ifExists
23✔
2256
     */
23✔
2257
    async dropForeignKeys(
23✔
2258
        tableOrName: Table | string,
12✔
2259
        foreignKeys: TableForeignKey[],
12✔
2260
        ifExists?: boolean,
12✔
2261
    ): Promise<void> {
12✔
2262
        const promises = foreignKeys.map((foreignKey) =>
12✔
2263
            this.dropForeignKey(tableOrName, foreignKey, ifExists),
12✔
2264
        )
12✔
2265
        await Promise.all(promises)
12✔
2266
    }
12✔
2267

23✔
2268
    /**
23✔
2269
     * Creates a new index.
23✔
2270
     * @param tableOrName
23✔
2271
     * @param index
23✔
2272
     */
23✔
2273
    async createIndex(
23✔
2274
        tableOrName: Table | string,
28✔
2275
        index: TableIndex,
28✔
2276
    ): Promise<void> {
28✔
2277
        const table = InstanceChecker.isTable(tableOrName)
28✔
2278
            ? tableOrName
28✔
2279
            : await this.getCachedTable(tableOrName)
28✔
2280

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

28✔
2284
        const up = this.createIndexSql(table, index)
28✔
2285
        const down = this.dropIndexSql(index)
28✔
2286
        await this.executeQueries(up, down)
28✔
2287
        table.addIndex(index)
28✔
2288
    }
28✔
2289

23✔
2290
    /**
23✔
2291
     * Creates a new indices
23✔
2292
     * @param tableOrName
23✔
2293
     * @param indices
23✔
2294
     */
23✔
2295
    async createIndices(
23✔
2296
        tableOrName: Table | string,
14✔
2297
        indices: TableIndex[],
14✔
2298
    ): Promise<void> {
14✔
2299
        const promises = indices.map((index) =>
14✔
2300
            this.createIndex(tableOrName, index),
14✔
2301
        )
14✔
2302
        await Promise.all(promises)
14✔
2303
    }
14✔
2304

23✔
2305
    /**
23✔
2306
     * Drops an index from the table.
23✔
2307
     * @param tableOrName
23✔
2308
     * @param indexOrName
23✔
2309
     * @param ifExists
23✔
2310
     */
23✔
2311
    async dropIndex(
23✔
2312
        tableOrName: Table | string,
30✔
2313
        indexOrName: TableIndex | string,
30✔
2314
        ifExists?: boolean,
30✔
2315
    ): Promise<void> {
30✔
2316
        const table = InstanceChecker.isTable(tableOrName)
30✔
2317
            ? tableOrName
30✔
2318
            : await this.getCachedTable(tableOrName)
30✔
2319
        const index = InstanceChecker.isTableIndex(indexOrName)
12✔
2320
            ? indexOrName
30✔
2321
            : table.indices.find((i) => i.name === indexOrName)
30✔
2322
        if (!index) {
30✔
2323
            if (ifExists) return
2✔
2324
            throw new TypeORMError(
×
2325
                `Supplied index ${indexOrName} was not found in table ${table.name}`,
×
2326
            )
×
NEW
2327
        }
×
2328
        // old index may be passed without name. In this case we generate index name manually.
28✔
2329
        if (!index.name) index.name = this.generateIndexName(table, index)
30✔
2330

28✔
2331
        const up = this.dropIndexSql(index)
28✔
2332
        const down = this.createIndexSql(table, index)
28✔
2333
        await this.executeQueries(up, down)
28✔
2334
        table.removeIndex(index)
28✔
2335
    }
28✔
2336

23✔
2337
    /**
23✔
2338
     * Drops an indices from the table.
23✔
2339
     * @param tableOrName
23✔
2340
     * @param indices
23✔
2341
     * @param ifExists
23✔
2342
     */
23✔
2343
    async dropIndices(
23✔
2344
        tableOrName: Table | string,
2✔
2345
        indices: TableIndex[],
2✔
2346
        ifExists?: boolean,
2✔
2347
    ): Promise<void> {
2✔
2348
        const promises = indices.map((index) =>
2✔
2349
            this.dropIndex(tableOrName, index, ifExists),
2✔
2350
        )
2✔
2351
        await Promise.all(promises)
2✔
2352
    }
2✔
2353

23✔
2354
    /**
23✔
2355
     * Clears all table contents.
23✔
2356
     * Note: this operation uses SQL's TRUNCATE query which cannot be reverted in transactions.
23✔
2357
     * @param tableName
23✔
2358
     * @param options
23✔
2359
     * @param options.cascade
23✔
2360
     */
23✔
2361
    async clearTable(
23✔
2362
        tableName: string,
16✔
2363
        options?: { cascade?: boolean },
16✔
2364
    ): Promise<void> {
16✔
2365
        const cascade = options?.cascade ? " CASCADE" : ""
16✔
2366
        await this.query(
16✔
2367
            `TRUNCATE TABLE ${this.escapePath(tableName)}${cascade}`,
16✔
2368
        )
16✔
2369
    }
10✔
2370

23✔
2371
    /**
23✔
2372
     * Removes all tables from the currently connected database.
23✔
2373
     */
23✔
2374
    async clearDatabase(): Promise<void> {
23✔
2375
        const isAnotherTransactionActive = this.isTransactionActive
2,742✔
2376
        if (!isAnotherTransactionActive) await this.startTransaction()
2,742✔
2377
        try {
2,742✔
2378
            // drop views
2,742✔
2379
            const dropViewsQuery = `SELECT 'DROP VIEW "' || VIEW_NAME || '"' AS "query" FROM "USER_VIEWS"`
2,742✔
2380
            const dropViewQueries: ObjectLiteral[] =
2,742✔
2381
                await this.query(dropViewsQuery)
2,742✔
2382
            await Promise.all(
2,742✔
2383
                dropViewQueries.map((query) => this.query(query["query"])),
2,742✔
2384
            )
2,742✔
2385

2,742✔
2386
            // drop materialized views
2,742✔
2387
            const dropMatViewsQuery = `SELECT 'DROP MATERIALIZED VIEW "' || MVIEW_NAME || '"' AS "query" FROM "USER_MVIEWS"`
2,742✔
2388
            const dropMatViewQueries: ObjectLiteral[] =
2,742✔
2389
                await this.query(dropMatViewsQuery)
2,742✔
2390
            await Promise.all(
2,742✔
2391
                dropMatViewQueries.map((query) => this.query(query["query"])),
2,742✔
2392
            )
2,742✔
2393

2,742✔
2394
            // drop tables
2,742✔
2395
            const dropTablesQuery = `SELECT 'DROP TABLE "' || TABLE_NAME || '" CASCADE CONSTRAINTS' AS "query" FROM "USER_TABLES"`
2,742✔
2396
            const dropTableQueries: ObjectLiteral[] =
2,742✔
2397
                await this.query(dropTablesQuery)
2,742✔
2398
            await Promise.all(
2,742✔
2399
                dropTableQueries.map((query) => this.query(query["query"])),
2,742✔
2400
            )
2,742✔
2401
            if (!isAnotherTransactionActive) await this.commitTransaction()
2,742✔
2402
        } catch (error) {
2,742!
2403
            try {
×
2404
                // we throw original error even if rollback thrown an error
×
2405
                if (!isAnotherTransactionActive)
×
2406
                    await this.rollbackTransaction()
×
2407
            } catch (rollbackError) {}
×
2408
            throw error
×
2409
        }
×
2410
    }
2,742✔
2411

23✔
2412
    // -------------------------------------------------------------------------
23✔
2413
    // Protected Methods
23✔
2414
    // -------------------------------------------------------------------------
23✔
2415

23✔
2416
    protected async loadViews(viewNames?: string[]): Promise<View[]> {
23✔
2417
        const hasTable = await this.hasTable(this.getTypeormMetadataTableName())
2,870✔
2418
        if (!hasTable) {
2,870✔
2419
            return []
2,798✔
2420
        }
2,798✔
2421

72✔
2422
        if (!viewNames) {
2,870!
2423
            viewNames = []
×
2424
        }
×
2425

72✔
2426
        const currentDatabase = await this.getCurrentDatabase()
72✔
2427
        const currentSchema = await this.getCurrentSchema()
72✔
2428

72✔
2429
        const viewsCondition = viewNames
72✔
2430
            .map((viewName) => this.driver.parseTableName(viewName))
72✔
2431
            .map(({ schema, tableName }) => {
72✔
2432
                if (!schema) {
80!
2433
                    schema = this.driver.options.schema || currentSchema
×
2434
                }
×
2435

80✔
2436
                return `("T"."schema" = '${schema}' AND "T"."name" = '${tableName}')`
80✔
2437
            })
72✔
2438
            .join(" OR ")
72✔
2439

72✔
2440
        let query =
72✔
2441
            `SELECT "T".* FROM ${this.escapePath(
72✔
2442
                this.getTypeormMetadataTableName(),
72✔
2443
            )} "T" ` +
72✔
2444
            `INNER JOIN "USER_OBJECTS" "O" ON "O"."OBJECT_NAME" = "T"."name" AND "O"."OBJECT_TYPE" IN ( 'MATERIALIZED VIEW', 'VIEW' ) ` +
72✔
2445
            `WHERE "T"."type" IN ('${MetadataTableType.MATERIALIZED_VIEW}', '${MetadataTableType.VIEW}')`
72✔
2446
        if (viewsCondition.length > 0) query += ` AND ${viewsCondition}`
2,870✔
2447

72✔
2448
        const dbViews = await this.query(query)
72✔
2449
        return dbViews.map((dbView: any) => {
72✔
2450
            const parsedName = this.driver.parseTableName(dbView["name"])
20✔
2451

20✔
2452
            const view = new View()
20✔
2453
            view.database =
20✔
2454
                parsedName.database || dbView["database"] || currentDatabase
20!
2455
            view.schema = parsedName.schema || dbView["schema"] || currentSchema
20!
2456
            view.name = parsedName.tableName
20✔
2457
            view.expression = dbView["value"]
20✔
2458
            view.materialized =
20✔
2459
                dbView["type"] === MetadataTableType.MATERIALIZED_VIEW
20✔
2460
            return view
20✔
2461
        })
72✔
2462
    }
72✔
2463

23✔
2464
    /**
23✔
2465
     * Loads all tables (with given names) from the database and creates a Table from them.
23✔
2466
     * @param tableNames
23✔
2467
     */
23✔
2468
    protected async loadTables(tableNames?: string[]): Promise<Table[]> {
23✔
2469
        if (tableNames && tableNames.length === 0) {
3,392✔
2470
            return []
12✔
2471
        }
12✔
2472

3,380✔
2473
        const dbTables: { TABLE_NAME: string; OWNER: string }[] = []
3,380✔
2474

3,380✔
2475
        const currentSchema = await this.getCurrentSchema()
3,380✔
2476
        const currentDatabase = await this.getCurrentDatabase()
3,380✔
2477

3,380✔
2478
        if (!tableNames) {
3,392!
2479
            const tablesSql = `SELECT "TABLE_NAME", "OWNER" FROM "ALL_TABLES"`
×
2480
            dbTables.push(...(await this.query(tablesSql)))
×
2481
        } else {
3,392✔
2482
            const tablesCondition = tableNames
3,380✔
2483
                .map((tableName) => {
3,380✔
2484
                    const parts = tableName.split(".")
10,488✔
2485

10,488✔
2486
                    if (parts.length >= 3) {
10,488!
2487
                        const [, schema, name] = parts
×
2488
                        return `("OWNER" = '${schema}' AND "TABLE_NAME" = '${name}')`
×
2489
                    } else if (parts.length === 2) {
10,488✔
2490
                        const [schema, name] = parts
9,938✔
2491
                        return `("OWNER" = '${schema}' AND "TABLE_NAME" = '${name}')`
9,938✔
2492
                    } else if (parts.length === 1) {
10,488✔
2493
                        const [name] = parts
550✔
2494
                        return `("TABLE_NAME" = '${name}')`
550✔
2495
                    } else {
550!
2496
                        return `(1=0)`
×
2497
                    }
×
2498
                })
3,380✔
2499
                .join(" OR ")
3,380✔
2500
            const tablesSql = `SELECT "TABLE_NAME", "OWNER" FROM "ALL_TABLES" WHERE ${tablesCondition}`
3,380✔
2501
            dbTables.push(...(await this.query(tablesSql)))
3,380✔
2502
        }
3,380✔
2503

3,380✔
2504
        // if tables were not found in the db, no need to proceed
3,380✔
2505
        if (dbTables.length === 0) {
3,392✔
2506
            return []
2,764✔
2507
        }
2,764✔
2508

616✔
2509
        // load tables, columns, indices and foreign keys
616✔
2510
        const columnsCondition = dbTables
616✔
2511
            .map(({ TABLE_NAME, OWNER }) => {
616✔
2512
                return `("C"."OWNER" = '${OWNER}' AND "C"."TABLE_NAME" = '${TABLE_NAME}')`
936✔
2513
            })
616✔
2514
            .join(" OR ")
616✔
2515
        const columnsSql = `SELECT * FROM "ALL_TAB_COLS" "C" WHERE (${columnsCondition})`
616✔
2516

616✔
2517
        const indicesSql =
616✔
2518
            `SELECT "C"."INDEX_NAME", "C"."OWNER", "C"."TABLE_NAME", "C"."UNIQUENESS", ` +
616✔
2519
            `LISTAGG ("COL"."COLUMN_NAME", ',') WITHIN GROUP (ORDER BY "COL"."COLUMN_NAME") AS "COLUMN_NAMES" ` +
616✔
2520
            `FROM "ALL_INDEXES" "C" ` +
616✔
2521
            `INNER JOIN "ALL_IND_COLUMNS" "COL" ON "COL"."INDEX_OWNER" = "C"."OWNER" AND "COL"."INDEX_NAME" = "C"."INDEX_NAME" ` +
616✔
2522
            `LEFT JOIN "ALL_CONSTRAINTS" "CON" ON "CON"."OWNER" = "C"."OWNER" AND "CON"."CONSTRAINT_NAME" = "C"."INDEX_NAME" ` +
616✔
2523
            `WHERE (${columnsCondition}) AND "CON"."CONSTRAINT_NAME" IS NULL ` +
616✔
2524
            `GROUP BY "C"."INDEX_NAME", "C"."OWNER", "C"."TABLE_NAME", "C"."UNIQUENESS"`
616✔
2525

616✔
2526
        const foreignKeysSql =
616✔
2527
            `SELECT "C"."CONSTRAINT_NAME", "C"."OWNER", "C"."TABLE_NAME", "COL"."COLUMN_NAME", "REF_COL"."TABLE_NAME" AS "REFERENCED_TABLE_NAME", ` +
616✔
2528
            `"REF_COL"."COLUMN_NAME" AS "REFERENCED_COLUMN_NAME", "C"."DELETE_RULE" AS "ON_DELETE" ` +
616✔
2529
            `FROM "ALL_CONSTRAINTS" "C" ` +
616✔
2530
            `INNER JOIN "ALL_CONS_COLUMNS" "COL" ON "COL"."OWNER" = "C"."OWNER" AND "COL"."CONSTRAINT_NAME" = "C"."CONSTRAINT_NAME" ` +
616✔
2531
            `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" ` +
616✔
2532
            `WHERE (${columnsCondition}) AND "C"."CONSTRAINT_TYPE" = 'R'`
616✔
2533

616✔
2534
        const constraintsSql =
616✔
2535
            `SELECT "C"."CONSTRAINT_NAME", "C"."CONSTRAINT_TYPE", "C"."OWNER", "C"."TABLE_NAME", "COL"."COLUMN_NAME", "C"."SEARCH_CONDITION" ` +
616✔
2536
            `FROM "ALL_CONSTRAINTS" "C" ` +
616✔
2537
            `INNER JOIN "ALL_CONS_COLUMNS" "COL" ON "COL"."OWNER" = "C"."OWNER" AND "COL"."CONSTRAINT_NAME" = "C"."CONSTRAINT_NAME" ` +
616✔
2538
            `WHERE (${columnsCondition}) AND "C"."CONSTRAINT_TYPE" IN ('C', 'U', 'P') AND "C"."GENERATED" = 'USER NAME'`
616✔
2539

616✔
2540
        const [
616✔
2541
            dbColumns,
616✔
2542
            dbIndices,
616✔
2543
            dbForeignKeys,
616✔
2544
            dbConstraints,
616✔
2545
        ]: ObjectLiteral[][] = await Promise.all([
616✔
2546
            this.query(columnsSql),
616✔
2547
            this.query(indicesSql),
616✔
2548
            this.query(foreignKeysSql),
616✔
2549
            this.query(constraintsSql),
616✔
2550
        ])
616✔
2551

616✔
2552
        // create tables for loaded tables
616✔
2553
        return await Promise.all(
616✔
2554
            dbTables.map(async (dbTable) => {
616✔
2555
                const table = new Table()
936✔
2556
                const owner =
936✔
2557
                    dbTable["OWNER"] === currentSchema &&
936✔
2558
                    (!this.driver.options.schema ||
936!
2559
                        this.driver.options.schema === currentSchema)
936✔
2560
                        ? undefined
936✔
2561
                        : dbTable["OWNER"]
936!
2562
                table.database = currentDatabase
936✔
2563
                table.schema = dbTable["OWNER"]
936✔
2564
                table.name = this.driver.buildTableName(
936✔
2565
                    dbTable["TABLE_NAME"],
936✔
2566
                    owner,
936✔
2567
                )
936✔
2568

936✔
2569
                // create columns from the loaded columns
936✔
2570
                table.columns = await Promise.all(
936✔
2571
                    dbColumns
936✔
2572
                        .filter(
936✔
2573
                            (dbColumn) =>
936✔
2574
                                dbColumn["OWNER"] === dbTable["OWNER"] &&
10,506✔
2575
                                dbColumn["TABLE_NAME"] ===
10,506✔
2576
                                    dbTable["TABLE_NAME"] &&
10,506✔
2577
                                // Filter out auto-generated virtual columns,
3,398✔
2578
                                // since TypeORM will have no info about them.
3,398✔
2579
                                !(
3,398✔
2580
                                    dbColumn["VIRTUAL_COLUMN"] === "YES" &&
3,398✔
2581
                                    dbColumn["USER_GENERATED"] === "NO"
74✔
2582
                                ),
936✔
2583
                        )
936✔
2584
                        .map(async (dbColumn) => {
936✔
2585
                            const columnConstraints = dbConstraints.filter(
3,394✔
2586
                                (dbConstraint) =>
3,394✔
2587
                                    dbConstraint["OWNER"] ===
18,492✔
2588
                                        dbColumn["OWNER"] &&
18,492✔
2589
                                    dbConstraint["TABLE_NAME"] ===
18,492✔
2590
                                        dbColumn["TABLE_NAME"] &&
18,492✔
2591
                                    dbConstraint["COLUMN_NAME"] ===
7,736✔
2592
                                        dbColumn["COLUMN_NAME"],
3,394✔
2593
                            )
3,394✔
2594

3,394✔
2595
                            const uniqueConstraints = columnConstraints.filter(
3,394✔
2596
                                (constraint) =>
3,394✔
2597
                                    constraint["CONSTRAINT_TYPE"] === "U",
3,394✔
2598
                            )
3,394✔
2599
                            const isConstraintComposite =
3,394✔
2600
                                uniqueConstraints.every((uniqueConstraint) => {
3,394✔
2601
                                    return dbConstraints.some(
652✔
2602
                                        (dbConstraint) =>
652✔
2603
                                            dbConstraint["OWNER"] ===
3,090✔
2604
                                                dbColumn["OWNER"] &&
3,090✔
2605
                                            dbConstraint["TABLE_NAME"] ===
3,090✔
2606
                                                dbColumn["TABLE_NAME"] &&
3,090✔
2607
                                            dbConstraint["COLUMN_NAME"] !==
2,696✔
2608
                                                dbColumn["COLUMN_NAME"] &&
3,090✔
2609
                                            dbConstraint["CONSTRAINT_NAME"] ===
2,114✔
2610
                                                uniqueConstraint[
2,114✔
2611
                                                    "CONSTRAINT_NAME"
2,114✔
2612
                                                ] &&
3,090✔
2613
                                            dbConstraint["CONSTRAINT_TYPE"] ===
372✔
2614
                                                "U",
652✔
2615
                                    )
652✔
2616
                                })
3,394✔
2617

3,394✔
2618
                            const tableColumn = new TableColumn()
3,394✔
2619
                            tableColumn.name = dbColumn["COLUMN_NAME"]
3,394✔
2620
                            tableColumn.type =
3,394✔
2621
                                dbColumn["DATA_TYPE"].toLowerCase()
3,394✔
2622
                            if (tableColumn.type.indexOf("(") !== -1)
3,394✔
2623
                                tableColumn.type = tableColumn.type.replace(
3,394✔
2624
                                    /\([0-9]*\)/,
100✔
2625
                                    "",
100✔
2626
                                )
100✔
2627

3,394✔
2628
                            // check only columns that have length property
3,394✔
2629
                            if (
3,394✔
2630
                                this.driver.withLengthColumnTypes.indexOf(
3,394✔
2631
                                    tableColumn.type as ColumnType,
3,394✔
2632
                                ) !== -1
3,394✔
2633
                            ) {
3,394✔
2634
                                const length =
1,796✔
2635
                                    tableColumn.type === "raw"
1,796✔
2636
                                        ? dbColumn["DATA_LENGTH"]
1,796✔
2637
                                        : dbColumn["CHAR_COL_DECL_LENGTH"]
1,796✔
2638
                                tableColumn.length =
1,796✔
2639
                                    length &&
1,796✔
2640
                                    !this.isDefaultColumnLength(
1,796✔
2641
                                        table,
1,796✔
2642
                                        tableColumn,
1,796✔
2643
                                        length,
1,796✔
2644
                                    )
1,796✔
2645
                                        ? length.toString()
1,796✔
2646
                                        : ""
1,796✔
2647
                            }
1,796✔
2648

3,394✔
2649
                            if (
3,394✔
2650
                                tableColumn.type === "number" ||
3,394✔
2651
                                tableColumn.type === "float"
1,924✔
2652
                            ) {
3,394✔
2653
                                if (
1,478✔
2654
                                    dbColumn["DATA_PRECISION"] !== null &&
1,478✔
2655
                                    !this.isDefaultColumnPrecision(
18✔
2656
                                        table,
18✔
2657
                                        tableColumn,
18✔
2658
                                        dbColumn["DATA_PRECISION"],
18✔
2659
                                    )
1,478✔
2660
                                )
1,478✔
2661
                                    tableColumn.precision =
1,478✔
2662
                                        dbColumn["DATA_PRECISION"]
12✔
2663
                                if (
1,478✔
2664
                                    dbColumn["DATA_SCALE"] !== null &&
1,478✔
2665
                                    !this.isDefaultColumnScale(
222✔
2666
                                        table,
222✔
2667
                                        tableColumn,
222✔
2668
                                        dbColumn["DATA_SCALE"],
222✔
2669
                                    )
1,478✔
2670
                                )
1,478✔
2671
                                    tableColumn.scale = dbColumn["DATA_SCALE"]
1,478✔
2672
                            } else if (
3,394✔
2673
                                (tableColumn.type === "timestamp" ||
1,916✔
2674
                                    tableColumn.type ===
1,826✔
2675
                                        "timestamp with time zone" ||
1,916✔
2676
                                    tableColumn.type ===
1,820✔
2677
                                        "timestamp with local time zone") &&
1,916✔
2678
                                dbColumn["DATA_SCALE"] !== null
100✔
2679
                            ) {
1,916✔
2680
                                tableColumn.precision =
100✔
2681
                                    !this.isDefaultColumnPrecision(
100✔
2682
                                        table,
100✔
2683
                                        tableColumn,
100✔
2684
                                        dbColumn["DATA_SCALE"],
100✔
2685
                                    )
100✔
2686
                                        ? dbColumn["DATA_SCALE"]
100✔
2687
                                        : undefined
100✔
2688
                            }
100✔
2689

3,394✔
2690
                            tableColumn.default =
3,394✔
2691
                                dbColumn["DATA_DEFAULT"] !== null &&
3,394✔
2692
                                dbColumn["DATA_DEFAULT"] !== undefined &&
3,394✔
2693
                                dbColumn["VIRTUAL_COLUMN"] === "NO" &&
3,394✔
2694
                                dbColumn["DATA_DEFAULT"].trim() !== "NULL"
804✔
2695
                                    ? (tableColumn.default =
3,394✔
2696
                                          dbColumn["DATA_DEFAULT"].trim())
788✔
2697
                                    : undefined
3,394✔
2698

3,394✔
2699
                            const primaryConstraint = columnConstraints.find(
3,394✔
2700
                                (constraint) =>
3,394✔
2701
                                    constraint["CONSTRAINT_TYPE"] === "P",
3,394✔
2702
                            )
3,394✔
2703
                            if (primaryConstraint) {
3,394✔
2704
                                tableColumn.isPrimary = true
976✔
2705
                                // find another columns involved in primary key constraint
976✔
2706
                                const anotherPrimaryConstraints =
976✔
2707
                                    dbConstraints.filter(
976✔
2708
                                        (constraint) =>
976✔
2709
                                            constraint["OWNER"] ===
5,414✔
2710
                                                dbColumn["OWNER"] &&
5,414✔
2711
                                            constraint["TABLE_NAME"] ===
5,414✔
2712
                                                dbColumn["TABLE_NAME"] &&
5,414✔
2713
                                            constraint["COLUMN_NAME"] !==
1,926✔
2714
                                                dbColumn["COLUMN_NAME"] &&
5,414✔
2715
                                            constraint["CONSTRAINT_TYPE"] ===
932✔
2716
                                                "P",
976✔
2717
                                    )
976✔
2718

976✔
2719
                                // collect all column names
976✔
2720
                                const columnNames =
976✔
2721
                                    anotherPrimaryConstraints.map(
976✔
2722
                                        (constraint) =>
976✔
2723
                                            constraint["COLUMN_NAME"],
976✔
2724
                                    )
976✔
2725
                                columnNames.push(dbColumn["COLUMN_NAME"])
976✔
2726

976✔
2727
                                // build default primary key constraint name
976✔
2728
                                const pkName =
976✔
2729
                                    this.connection.namingStrategy.primaryKeyName(
976✔
2730
                                        table,
976✔
2731
                                        columnNames,
976✔
2732
                                    )
976✔
2733

976✔
2734
                                // if primary key has user-defined constraint name, write it in table column
976✔
2735
                                if (
976✔
2736
                                    primaryConstraint["CONSTRAINT_NAME"] !==
976✔
2737
                                    pkName
976✔
2738
                                ) {
976✔
2739
                                    tableColumn.primaryKeyConstraintName =
52✔
2740
                                        primaryConstraint["CONSTRAINT_NAME"]
52✔
2741
                                }
52✔
2742
                            }
976✔
2743

3,394✔
2744
                            tableColumn.isNullable =
3,394✔
2745
                                dbColumn["NULLABLE"] === "Y"
3,394✔
2746
                            tableColumn.isUnique =
3,394✔
2747
                                uniqueConstraints.length > 0 &&
3,394✔
2748
                                !isConstraintComposite
646✔
2749
                            tableColumn.isGenerated =
3,394✔
2750
                                dbColumn["IDENTITY_COLUMN"] === "YES"
3,394✔
2751
                            if (tableColumn.isGenerated) {
3,394✔
2752
                                tableColumn.generationStrategy = "increment"
520✔
2753
                                tableColumn.default = undefined
520✔
2754
                            }
520✔
2755
                            tableColumn.comment = "" // todo
3,394✔
2756

3,394✔
2757
                            if (dbColumn["VIRTUAL_COLUMN"] === "YES") {
3,394✔
2758
                                tableColumn.generatedType = "VIRTUAL"
70✔
2759

70✔
2760
                                const asExpressionQuery =
70✔
2761
                                    this.selectTypeormMetadataSql({
70✔
2762
                                        table: dbTable["TABLE_NAME"],
70✔
2763
                                        type: MetadataTableType.GENERATED_COLUMN,
70✔
2764
                                        name: tableColumn.name,
70✔
2765
                                    })
70✔
2766

70✔
2767
                                const results = await this.query(
70✔
2768
                                    asExpressionQuery.query,
70✔
2769
                                    asExpressionQuery.parameters,
70✔
2770
                                )
70✔
2771
                                if (results[0] && results[0].value) {
70✔
2772
                                    tableColumn.asExpression = results[0].value
70✔
2773
                                } else {
70!
2774
                                    tableColumn.asExpression = ""
×
2775
                                }
×
2776
                            }
70✔
2777

3,394✔
2778
                            return tableColumn
3,394✔
2779
                        }),
936✔
2780
                )
936✔
2781

936✔
2782
                // find unique constraints of table, group them by constraint name and build TableUnique.
936✔
2783
                const tableUniqueConstraints = OrmUtils.uniq(
936✔
2784
                    dbConstraints.filter((dbConstraint) => {
936✔
2785
                        return (
5,304✔
2786
                            dbConstraint["TABLE_NAME"] ===
5,304✔
2787
                                dbTable["TABLE_NAME"] &&
5,304✔
2788
                            dbConstraint["OWNER"] === dbTable["OWNER"] &&
5,304✔
2789
                            dbConstraint["CONSTRAINT_TYPE"] === "U"
1,820✔
2790
                        )
5,304✔
2791
                    }),
936✔
2792
                    (dbConstraint) => dbConstraint["CONSTRAINT_NAME"],
936✔
2793
                )
936✔
2794

936✔
2795
                table.uniques = tableUniqueConstraints.map((constraint) => {
936✔
2796
                    const uniques = dbConstraints.filter(
466✔
2797
                        (dbC) =>
466✔
2798
                            dbC["CONSTRAINT_NAME"] ===
2,784✔
2799
                            constraint["CONSTRAINT_NAME"],
466✔
2800
                    )
466✔
2801
                    return new TableUnique({
466✔
2802
                        name: constraint["CONSTRAINT_NAME"],
466✔
2803
                        columnNames: uniques.map((u) => u["COLUMN_NAME"]),
466✔
2804
                    })
466✔
2805
                })
936✔
2806

936✔
2807
                // find check constraints of table, group them by constraint name and build TableCheck.
936✔
2808
                const tableCheckConstraints = OrmUtils.uniq(
936✔
2809
                    dbConstraints.filter((dbConstraint) => {
936✔
2810
                        return (
5,304✔
2811
                            dbConstraint["TABLE_NAME"] ===
5,304✔
2812
                                dbTable["TABLE_NAME"] &&
5,304✔
2813
                            dbConstraint["OWNER"] === dbTable["OWNER"] &&
5,304✔
2814
                            dbConstraint["CONSTRAINT_TYPE"] === "C"
1,820✔
2815
                        )
5,304✔
2816
                    }),
936✔
2817
                    (dbConstraint) => dbConstraint["CONSTRAINT_NAME"],
936✔
2818
                )
936✔
2819

936✔
2820
                table.checks = tableCheckConstraints.map((constraint) => {
936✔
2821
                    const checks = dbConstraints.filter(
184✔
2822
                        (dbC) =>
184✔
2823
                            dbC["TABLE_NAME"] === constraint["TABLE_NAME"] &&
1,260✔
2824
                            dbC["OWNER"] === constraint["OWNER"] &&
1,260✔
2825
                            dbC["CONSTRAINT_NAME"] ===
906✔
2826
                                constraint["CONSTRAINT_NAME"],
184✔
2827
                    )
184✔
2828
                    return new TableCheck({
184✔
2829
                        name: constraint["CONSTRAINT_NAME"],
184✔
2830
                        columnNames: checks.map((c) => c["COLUMN_NAME"]),
184✔
2831
                        expression: constraint["SEARCH_CONDITION"],
184✔
2832
                    })
184✔
2833
                })
936✔
2834

936✔
2835
                // find foreign key constraints of table, group them by constraint name and build TableForeignKey.
936✔
2836
                const tableForeignKeyConstraints = OrmUtils.uniq(
936✔
2837
                    dbForeignKeys.filter(
936✔
2838
                        (dbForeignKey) =>
936✔
2839
                            dbForeignKey["OWNER"] === dbTable["OWNER"] &&
1,300✔
2840
                            dbForeignKey["TABLE_NAME"] ===
1,300✔
2841
                                dbTable["TABLE_NAME"],
936✔
2842
                    ),
936✔
2843
                    (dbForeignKey) => dbForeignKey["CONSTRAINT_NAME"],
936✔
2844
                )
936✔
2845

936✔
2846
                table.foreignKeys = tableForeignKeyConstraints.map(
936✔
2847
                    (dbForeignKey) => {
936✔
2848
                        const foreignKeys = dbForeignKeys.filter(
360✔
2849
                            (dbFk) =>
360✔
2850
                                dbFk["TABLE_NAME"] ===
964✔
2851
                                    dbForeignKey["TABLE_NAME"] &&
964✔
2852
                                dbFk["OWNER"] === dbForeignKey["OWNER"] &&
964✔
2853
                                dbFk["CONSTRAINT_NAME"] ===
760✔
2854
                                    dbForeignKey["CONSTRAINT_NAME"],
360✔
2855
                        )
360✔
2856
                        return new TableForeignKey({
360✔
2857
                            name: dbForeignKey["CONSTRAINT_NAME"],
360✔
2858
                            columnNames: foreignKeys.map(
360✔
2859
                                (dbFk) => dbFk["COLUMN_NAME"],
360✔
2860
                            ),
360✔
2861
                            referencedDatabase: table.database,
360✔
2862
                            referencedSchema: dbForeignKey["OWNER"],
360✔
2863
                            referencedTableName:
360✔
2864
                                dbForeignKey["REFERENCED_TABLE_NAME"],
360✔
2865
                            referencedColumnNames: foreignKeys.map(
360✔
2866
                                (dbFk) => dbFk["REFERENCED_COLUMN_NAME"],
360✔
2867
                            ),
360✔
2868
                            onDelete: dbForeignKey["ON_DELETE"],
360✔
2869
                            onUpdate: "NO ACTION", // Oracle does not have onUpdate option in FK's, but we need it for proper synchronization
360✔
2870
                        })
360✔
2871
                    },
936✔
2872
                )
936✔
2873

936✔
2874
                // Attempt to map auto-generated virtual columns to their
936✔
2875
                // referenced columns, through its 'DATA_DEFAULT' property.
936✔
2876
                //
936✔
2877
                // An example of this happening is when a column of type
936✔
2878
                // TIMESTAMP WITH TIME ZONE is indexed. Oracle will create a
936✔
2879
                // virtual column of type TIMESTAMP with a default value of
936✔
2880
                // SYS_EXTRACT_UTC(<column>).
936✔
2881
                const autoGenVirtualDbColumns = dbColumns
936✔
2882
                    .filter(
936✔
2883
                        (dbColumn) =>
936✔
2884
                            dbColumn["OWNER"] === dbTable["OWNER"] &&
10,506✔
2885
                            dbColumn["TABLE_NAME"] === dbTable["TABLE_NAME"] &&
10,506✔
2886
                            dbColumn["VIRTUAL_COLUMN"] === "YES" &&
10,506✔
2887
                            dbColumn["USER_GENERATED"] === "NO",
936✔
2888
                    )
936✔
2889
                    .reduce((acc, x) => {
936✔
2890
                        const referencedDbColumn = dbColumns.find((dbColumn) =>
4✔
2891
                            x["DATA_DEFAULT"].includes(dbColumn["COLUMN_NAME"]),
4✔
2892
                        )
4✔
2893

4✔
2894
                        if (!referencedDbColumn) return acc
4!
2895

4✔
2896
                        return {
4✔
2897
                            ...acc,
4✔
2898
                            [x["COLUMN_NAME"]]:
4✔
2899
                                referencedDbColumn["COLUMN_NAME"],
4✔
2900
                        }
4✔
2901
                    }, {})
936✔
2902

936✔
2903
                // create TableIndex objects from the loaded indices
936✔
2904
                table.indices = dbIndices
936✔
2905
                    .filter(
936✔
2906
                        (dbIndex) =>
936✔
2907
                            dbIndex["TABLE_NAME"] === dbTable["TABLE_NAME"] &&
632✔
2908
                            dbIndex["OWNER"] === dbTable["OWNER"],
936✔
2909
                    )
936✔
2910
                    .map((dbIndex) => {
936✔
2911
                        //
288✔
2912
                        const columnNames = dbIndex["COLUMN_NAMES"]
288✔
2913
                            .split(",")
288✔
2914
                            .map(
288✔
2915
                                (
288✔
2916
                                    columnName: keyof typeof autoGenVirtualDbColumns,
330✔
2917
                                ) =>
330✔
2918
                                    autoGenVirtualDbColumns[columnName] ??
330✔
2919
                                    columnName,
288✔
2920
                            )
288✔
2921

288✔
2922
                        return new TableIndex({
288✔
2923
                            name: dbIndex["INDEX_NAME"],
288✔
2924
                            columnNames,
288✔
2925
                            isUnique: dbIndex["UNIQUENESS"] === "UNIQUE",
288✔
2926
                        })
288✔
2927
                    })
936✔
2928

936✔
2929
                return table
936✔
2930
            }),
616✔
2931
        )
616✔
2932
    }
616✔
2933

23✔
2934
    /**
23✔
2935
     * Builds and returns SQL for create table.
23✔
2936
     * @param table
23✔
2937
     * @param createForeignKeys
23✔
2938
     */
23✔
2939
    protected createTableSql(table: Table, createForeignKeys?: boolean): Query {
23✔
2940
        const columnDefinitions = table.columns
9,648✔
2941
            .map((column) => this.buildCreateColumnSql(column))
9,648✔
2942
            .join(", ")
9,648✔
2943
        let sql = `CREATE TABLE ${this.escapePath(table)} (${columnDefinitions}`
9,648✔
2944

9,648✔
2945
        table.columns
9,648✔
2946
            .filter((column) => column.isUnique)
9,648✔
2947
            .forEach((column) => {
9,648✔
2948
                const isUniqueExist = table.uniques.some(
1,352✔
2949
                    (unique) =>
1,352✔
2950
                        unique.columnNames.length === 1 &&
1,802✔
2951
                        unique.columnNames[0] === column.name,
1,352✔
2952
                )
1,352✔
2953
                if (!isUniqueExist)
1,352✔
2954
                    table.uniques.push(
1,352✔
2955
                        new TableUnique({
10✔
2956
                            name: this.connection.namingStrategy.uniqueConstraintName(
10✔
2957
                                table,
10✔
2958
                                [column.name],
10✔
2959
                            ),
10✔
2960
                            columnNames: [column.name],
10✔
2961
                        }),
10✔
2962
                    )
10✔
2963
            })
9,648✔
2964

9,648✔
2965
        if (table.uniques.length > 0) {
9,648✔
2966
            const uniquesSql = table.uniques
1,200✔
2967
                .map((unique) => {
1,200✔
2968
                    const uniqueName = unique.name
1,760✔
2969
                        ? unique.name
1,760✔
2970
                        : this.connection.namingStrategy.uniqueConstraintName(
1,760✔
2971
                              table,
4✔
2972
                              unique.columnNames,
4✔
2973
                          )
1,760✔
2974
                    const columnNames = unique.columnNames
1,760✔
2975
                        .map((columnName) => `"${columnName}"`)
1,760✔
2976
                        .join(", ")
1,760✔
2977
                    return `CONSTRAINT "${uniqueName}" UNIQUE (${columnNames})`
1,760✔
2978
                })
1,200✔
2979
                .join(", ")
1,200✔
2980

1,200✔
2981
            sql += `, ${uniquesSql}`
1,200✔
2982
        }
1,200✔
2983

9,648✔
2984
        if (table.checks.length > 0) {
9,648✔
2985
            const checksSql = table.checks
152✔
2986
                .map((check) => {
152✔
2987
                    const checkName = check.name
154✔
2988
                        ? check.name
154✔
2989
                        : this.connection.namingStrategy.checkConstraintName(
154✔
2990
                              table,
2✔
2991
                              check.expression!,
2✔
2992
                          )
154✔
2993
                    return `CONSTRAINT "${checkName}" CHECK (${check.expression})`
154✔
2994
                })
152✔
2995
                .join(", ")
152✔
2996

152✔
2997
            sql += `, ${checksSql}`
152✔
2998
        }
152✔
2999

9,648✔
3000
        if (table.foreignKeys.length > 0 && createForeignKeys) {
9,648✔
3001
            const foreignKeysSql = table.foreignKeys
10✔
3002
                .map((fk) => {
10✔
3003
                    const columnNames = fk.columnNames
12✔
3004
                        .map((columnName) => `"${columnName}"`)
12✔
3005
                        .join(", ")
12✔
3006
                    if (!fk.name)
12✔
3007
                        fk.name = this.connection.namingStrategy.foreignKeyName(
12✔
3008
                            table,
8✔
3009
                            fk.columnNames,
8✔
3010
                            this.getTablePath(fk),
8✔
3011
                            fk.referencedColumnNames,
8✔
3012
                        )
8✔
3013
                    const referencedColumnNames = fk.referencedColumnNames
12✔
3014
                        .map((columnName) => `"${columnName}"`)
12✔
3015
                        .join(", ")
12✔
3016
                    let constraint = `CONSTRAINT "${
12✔
3017
                        fk.name
12✔
3018
                    }" FOREIGN KEY (${columnNames}) REFERENCES ${this.escapePath(
12✔
3019
                        this.getTablePath(fk),
12✔
3020
                    )} (${referencedColumnNames})`
12✔
3021
                    if (fk.onDelete && fk.onDelete !== "NO ACTION") {
12!
3022
                        // Oracle does not support NO ACTION, but we set NO ACTION by default in EntityMetadata
×
3023
                        constraint += ` ON DELETE ${fk.onDelete}`
×
3024
                    }
×
3025
                    return constraint
12✔
3026
                })
10✔
3027
                .join(", ")
10✔
3028

10✔
3029
            sql += `, ${foreignKeysSql}`
10✔
3030
        }
10✔
3031

9,648✔
3032
        const primaryColumns = table.columns.filter(
9,648✔
3033
            (column) => column.isPrimary,
9,648✔
3034
        )
9,648✔
3035
        if (primaryColumns.length > 0) {
9,648✔
3036
            const primaryKeyName = primaryColumns[0].primaryKeyConstraintName
9,604✔
3037
                ? primaryColumns[0].primaryKeyConstraintName
9,604✔
3038
                : this.connection.namingStrategy.primaryKeyName(
9,604✔
3039
                      table,
9,572✔
3040
                      primaryColumns.map((column) => column.name),
9,572✔
3041
                  )
9,604✔
3042

9,604✔
3043
            const columnNames = primaryColumns
9,604✔
3044
                .map((column) => `"${column.name}"`)
9,604✔
3045
                .join(", ")
9,604✔
3046
            sql += `, CONSTRAINT "${primaryKeyName}" PRIMARY KEY (${columnNames})`
9,604✔
3047
        }
9,604✔
3048

9,648✔
3049
        sql += `)`
9,648✔
3050

9,648✔
3051
        return new Query(sql)
9,648✔
3052
    }
9,648✔
3053

23✔
3054
    /**
23✔
3055
     * Builds drop table sql.
23✔
3056
     * @param tableOrName
23✔
3057
     * @param ifExists
23✔
3058
     */
23✔
3059
    protected dropTableSql(
23✔
3060
        tableOrName: Table | string,
9,648✔
3061
        ifExists?: boolean,
9,648✔
3062
    ): Query {
9,648✔
3063
        const query = ifExists
9,648✔
3064
            ? `DROP TABLE IF EXISTS ${this.escapePath(tableOrName)}`
9,648!
3065
            : `DROP TABLE ${this.escapePath(tableOrName)}`
9,648✔
3066
        return new Query(query)
9,648✔
3067
    }
9,648✔
3068

23✔
3069
    protected createViewSql(view: View): Query {
23✔
3070
        const materializedClause = view.materialized ? "MATERIALIZED " : ""
60✔
3071
        if (typeof view.expression === "string") {
60✔
3072
            return new Query(
44✔
3073
                `CREATE ${materializedClause}VIEW ${this.escapePath(view)} AS ${
44✔
3074
                    view.expression
44✔
3075
                }`,
44✔
3076
            )
44✔
3077
        } else {
60✔
3078
            return new Query(
16✔
3079
                `CREATE ${materializedClause}VIEW ${this.escapePath(
16✔
3080
                    view,
16✔
3081
                )} AS ${view.expression(this.connection).getQuery()}`,
16✔
3082
            )
16✔
3083
        }
16✔
3084
    }
60✔
3085

23✔
3086
    protected insertViewDefinitionSql(view: View): Query {
23✔
3087
        const expression =
60✔
3088
            typeof view.expression === "string"
60✔
3089
                ? view.expression.trim()
60✔
3090
                : view.expression(this.connection).getQuery()
60✔
3091
        const type = view.materialized
60✔
3092
            ? MetadataTableType.MATERIALIZED_VIEW
60✔
3093
            : MetadataTableType.VIEW
60✔
3094
        const { schema, tableName } = this.driver.parseTableName(view)
60✔
3095
        return this.insertTypeormMetadataSql({
60✔
3096
            type: type,
60✔
3097
            name: tableName,
60✔
3098
            schema: schema,
60✔
3099
            value: expression,
60✔
3100
        })
60✔
3101
    }
60✔
3102

23✔
3103
    /**
23✔
3104
     * Builds drop view sql.
23✔
3105
     * @param view
23✔
3106
     */
23✔
3107
    protected dropViewSql(view: View): Query {
23✔
3108
        const materializedClause = view.materialized ? "MATERIALIZED " : ""
60✔
3109
        return new Query(
60✔
3110
            `DROP ${materializedClause}VIEW ${this.escapePath(view)}`,
60✔
3111
        )
60✔
3112
    }
60✔
3113

23✔
3114
    /**
23✔
3115
     * Builds remove view sql.
23✔
3116
     * @param view
23✔
3117
     */
23✔
3118
    protected deleteViewDefinitionSql(view: View): Query {
23✔
3119
        const type = view.materialized
60✔
3120
            ? MetadataTableType.MATERIALIZED_VIEW
60✔
3121
            : MetadataTableType.VIEW
60✔
3122
        return this.deleteTypeormMetadataSql({ type, name: view.name })
60✔
3123
    }
60✔
3124

23✔
3125
    /**
23✔
3126
     * Builds create index sql.
23✔
3127
     * @param table
23✔
3128
     * @param index
23✔
3129
     */
23✔
3130
    protected createIndexSql(table: Table, index: TableIndex): Query {
23✔
3131
        const columns = index.columnNames
3,338✔
3132
            .map((columnName) => `"${columnName}"`)
3,338✔
3133
            .join(", ")
3,338✔
3134
        return new Query(
3,338✔
3135
            `CREATE ${index.isUnique ? "UNIQUE " : ""}INDEX "${
3,338✔
3136
                index.name
3,338✔
3137
            }" ON ${this.escapePath(table)} (${columns})`,
3,338✔
3138
        )
3,338✔
3139
    }
3,338✔
3140

23✔
3141
    /**
23✔
3142
     * Builds drop index sql.
23✔
3143
     * @param indexOrName
23✔
3144
     */
23✔
3145
    protected dropIndexSql(indexOrName: TableIndex | string): Query {
23✔
3146
        const indexName = InstanceChecker.isTableIndex(indexOrName)
3,338✔
3147
            ? indexOrName.name
3,338✔
3148
            : indexOrName
3,338!
3149
        return new Query(`DROP INDEX "${indexName}"`)
3,338✔
3150
    }
3,338✔
3151

23✔
3152
    /**
23✔
3153
     * Builds create primary key sql.
23✔
3154
     * @param table
23✔
3155
     * @param columnNames
23✔
3156
     * @param constraintName
23✔
3157
     */
23✔
3158
    protected createPrimaryKeySql(
23✔
3159
        table: Table,
12✔
3160
        columnNames: string[],
12✔
3161
        constraintName?: string,
12✔
3162
    ): Query {
12✔
3163
        const primaryKeyName = constraintName
12✔
3164
            ? constraintName
12✔
3165
            : this.connection.namingStrategy.primaryKeyName(table, columnNames)
12✔
3166

12✔
3167
        const columnNamesString = columnNames
12✔
3168
            .map((columnName) => `"${columnName}"`)
12✔
3169
            .join(", ")
12✔
3170

12✔
3171
        return new Query(
12✔
3172
            `ALTER TABLE ${this.escapePath(
12✔
3173
                table,
12✔
3174
            )} ADD CONSTRAINT "${primaryKeyName}" PRIMARY KEY (${columnNamesString})`,
12✔
3175
        )
12✔
3176
    }
12✔
3177

23✔
3178
    /**
23✔
3179
     * Builds drop primary key sql.
23✔
3180
     * @param table
23✔
3181
     */
23✔
3182
    protected dropPrimaryKeySql(table: Table): Query {
23✔
3183
        if (!table.primaryColumns.length)
12✔
3184
            throw new TypeORMError(`Table ${table} has no primary keys.`)
12!
3185

12✔
3186
        const columnNames = table.primaryColumns.map((column) => column.name)
12✔
3187
        const constraintName = table.primaryColumns[0].primaryKeyConstraintName
12✔
3188
        const primaryKeyName = constraintName
12✔
3189
            ? constraintName
12!
3190
            : this.connection.namingStrategy.primaryKeyName(table, columnNames)
12✔
3191

12✔
3192
        return new Query(
12✔
3193
            `ALTER TABLE ${this.escapePath(
12✔
3194
                table,
12✔
3195
            )} DROP CONSTRAINT "${primaryKeyName}"`,
12✔
3196
        )
12✔
3197
    }
12✔
3198

23✔
3199
    /**
23✔
3200
     * Builds create unique constraint sql.
23✔
3201
     * @param table
23✔
3202
     * @param uniqueConstraint
23✔
3203
     */
23✔
3204
    protected createUniqueConstraintSql(
23✔
3205
        table: Table,
38✔
3206
        uniqueConstraint: TableUnique,
38✔
3207
    ): Query {
38✔
3208
        const columnNames = uniqueConstraint.columnNames
38✔
3209
            .map((column) => `"` + column + `"`)
38✔
3210
            .join(", ")
38✔
3211
        return new Query(
38✔
3212
            `ALTER TABLE ${this.escapePath(table)} ADD CONSTRAINT "${
38✔
3213
                uniqueConstraint.name
38✔
3214
            }" UNIQUE (${columnNames})`,
38✔
3215
        )
38✔
3216
    }
38✔
3217

23✔
3218
    /**
23✔
3219
     * Builds drop unique constraint sql.
23✔
3220
     * @param table
23✔
3221
     * @param uniqueOrName
23✔
3222
     */
23✔
3223
    protected dropUniqueConstraintSql(
23✔
3224
        table: Table,
38✔
3225
        uniqueOrName: TableUnique | string,
38✔
3226
    ): Query {
38✔
3227
        const uniqueName = InstanceChecker.isTableUnique(uniqueOrName)
38✔
3228
            ? uniqueOrName.name
38✔
3229
            : uniqueOrName
38!
3230
        return new Query(
38✔
3231
            `ALTER TABLE ${this.escapePath(
38✔
3232
                table,
38✔
3233
            )} DROP CONSTRAINT "${uniqueName}"`,
38✔
3234
        )
38✔
3235
    }
38✔
3236

23✔
3237
    /**
23✔
3238
     * Builds create check constraint sql.
23✔
3239
     * @param table
23✔
3240
     * @param checkConstraint
23✔
3241
     */
23✔
3242
    protected createCheckConstraintSql(
23✔
3243
        table: Table,
20✔
3244
        checkConstraint: TableCheck,
20✔
3245
    ): Query {
20✔
3246
        return new Query(
20✔
3247
            `ALTER TABLE ${this.escapePath(table)} ADD CONSTRAINT "${
20✔
3248
                checkConstraint.name
20✔
3249
            }" CHECK (${checkConstraint.expression})`,
20✔
3250
        )
20✔
3251
    }
20✔
3252

23✔
3253
    /**
23✔
3254
     * Builds drop check constraint sql.
23✔
3255
     * @param table
23✔
3256
     * @param checkOrName
23✔
3257
     */
23✔
3258
    protected dropCheckConstraintSql(
23✔
3259
        table: Table,
20✔
3260
        checkOrName: TableCheck | string,
20✔
3261
    ): Query {
20✔
3262
        const checkName = InstanceChecker.isTableCheck(checkOrName)
20✔
3263
            ? checkOrName.name
20✔
3264
            : checkOrName
20!
3265
        return new Query(
20✔
3266
            `ALTER TABLE ${this.escapePath(
20✔
3267
                table,
20✔
3268
            )} DROP CONSTRAINT "${checkName}"`,
20✔
3269
        )
20✔
3270
    }
20✔
3271

23✔
3272
    /**
23✔
3273
     * Builds create foreign key sql.
23✔
3274
     * @param table
23✔
3275
     * @param foreignKey
23✔
3276
     */
23✔
3277
    protected createForeignKeySql(
23✔
3278
        table: Table,
6,084✔
3279
        foreignKey: TableForeignKey,
6,084✔
3280
    ): Query {
6,084✔
3281
        const columnNames = foreignKey.columnNames
6,084✔
3282
            .map((column) => `"` + column + `"`)
6,084✔
3283
            .join(", ")
6,084✔
3284
        const referencedColumnNames = foreignKey.referencedColumnNames
6,084✔
3285
            .map((column) => `"` + column + `"`)
6,084✔
3286
            .join(",")
6,084✔
3287
        let sql =
6,084✔
3288
            `ALTER TABLE ${this.escapePath(table)} ADD CONSTRAINT "${
6,084✔
3289
                foreignKey.name
6,084✔
3290
            }" FOREIGN KEY (${columnNames}) ` +
6,084✔
3291
            `REFERENCES ${this.escapePath(
6,084✔
3292
                this.getTablePath(foreignKey),
6,084✔
3293
            )} (${referencedColumnNames})`
6,084✔
3294
        // Oracle does not support NO ACTION, but we set NO ACTION by default in EntityMetadata
6,084✔
3295
        if (foreignKey.onDelete && foreignKey.onDelete !== "NO ACTION") {
6,084✔
3296
            sql += ` ON DELETE ${foreignKey.onDelete}`
2,080✔
3297
        }
2,080✔
3298
        return new Query(sql)
6,084✔
3299
    }
6,084✔
3300

23✔
3301
    /**
23✔
3302
     * Builds drop foreign key sql.
23✔
3303
     * @param table
23✔
3304
     * @param foreignKeyOrName
23✔
3305
     */
23✔
3306
    protected dropForeignKeySql(
23✔
3307
        table: Table,
6,096✔
3308
        foreignKeyOrName: TableForeignKey | string,
6,096✔
3309
    ): Query {
6,096✔
3310
        const foreignKeyName = InstanceChecker.isTableForeignKey(
6,096✔
3311
            foreignKeyOrName,
6,096✔
3312
        )
6,096✔
3313
            ? foreignKeyOrName.name
6,096✔
3314
            : foreignKeyOrName
6,096!
3315
        return new Query(
6,096✔
3316
            `ALTER TABLE ${this.escapePath(
6,096✔
3317
                table,
6,096✔
3318
            )} DROP CONSTRAINT "${foreignKeyName}"`,
6,096✔
3319
        )
6,096✔
3320
    }
6,096✔
3321

23✔
3322
    /**
23✔
3323
     * Builds a query for create column.
23✔
3324
     * @param column
23✔
3325
     */
23✔
3326
    protected buildCreateColumnSql(column: TableColumn) {
23✔
3327
        let c =
30,448✔
3328
            `"${column.name}" ` + this.connection.driver.createFullType(column)
30,448✔
3329
        if (column.charset) c += " CHARACTER SET " + column.charset
30,448!
3330
        if (column.collation) c += " COLLATE " + column.collation
30,448!
3331

30,448✔
3332
        if (column.asExpression) c += ` AS (${column.asExpression}) VIRTUAL`
30,448✔
3333

30,448✔
3334
        if (column.default !== undefined && column.default !== null)
30,448✔
3335
            // DEFAULT must be placed before NOT NULL
30,448✔
3336
            c += " DEFAULT " + column.default
30,448✔
3337
        if (column.isNullable !== true && !column.isGenerated)
30,448✔
3338
            // NOT NULL is not supported with GENERATED
30,448✔
3339
            c += " NOT NULL"
30,448✔
3340
        if (
30,448✔
3341
            column.isGenerated === true &&
30,448✔
3342
            column.generationStrategy === "increment"
5,976✔
3343
        )
30,448✔
3344
            c += " GENERATED BY DEFAULT AS IDENTITY"
30,448✔
3345

30,448✔
3346
        return c
30,448✔
3347
    }
30,448✔
3348

23✔
3349
    /**
23✔
3350
     * Escapes given table or view path.
23✔
3351
     * @param target
23✔
3352
     */
23✔
3353
    protected escapePath(target: Table | View | string): string {
23✔
3354
        // Ignore database when escaping paths
41,876✔
3355
        const { schema, tableName } = this.driver.parseTableName(target)
41,876✔
3356

41,876✔
3357
        if (schema && schema !== this.driver.schema) {
41,876!
3358
            return `"${schema}"."${tableName}"`
×
3359
        }
×
3360

41,876✔
3361
        return `"${tableName}"`
41,876✔
3362
    }
41,876✔
3363

23✔
3364
    /**
23✔
3365
     * Change table comment.
23✔
3366
     * @param tableOrName
23✔
3367
     * @param comment
23✔
3368
     */
23✔
3369
    changeTableComment(
23✔
3370
        tableOrName: Table | string,
×
3371
        comment?: string,
×
3372
    ): Promise<void> {
×
3373
        throw new TypeORMError(
×
3374
            `oracle driver does not support change table comment.`,
×
3375
        )
×
3376
    }
×
3377
}
23✔
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