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

typeorm / typeorm / 22259741167

21 Feb 2026 03:55PM UTC coverage: 81.269% (-0.02%) from 81.291%
22259741167

push

github

web-flow
chore(deps): update dependencies to latest minor versions (#12017)

Co-authored-by: Michael Bromley <michaelbromley@users.noreply.github.com>

27410 of 33223 branches covered (82.5%)

Branch coverage included in aggregate %.

93917 of 116068 relevant lines covered (80.92%)

71235.6 hits per line

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

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

26✔
32
/**
26✔
33
 * Runs queries on a single SQL Server database connection.
26✔
34
 */
26✔
35
export class SqlServerQueryRunner
26✔
36
    extends BaseQueryRunner
26✔
37
    implements QueryRunner
26✔
38
{
26✔
39
    // -------------------------------------------------------------------------
26✔
40
    // Public Implemented Properties
26✔
41
    // -------------------------------------------------------------------------
26✔
42

26✔
43
    /**
26✔
44
     * Database driver used by connection.
26✔
45
     */
26✔
46
    driver: SqlServerDriver
26✔
47

26✔
48
    // -------------------------------------------------------------------------
26✔
49
    // Private Properties
26✔
50
    // -------------------------------------------------------------------------
26✔
51

26✔
52
    private lock: QueryLock = new QueryLock()
26✔
53

26✔
54
    // -------------------------------------------------------------------------
26✔
55
    // Constructor
26✔
56
    // -------------------------------------------------------------------------
26✔
57

26✔
58
    constructor(driver: SqlServerDriver, mode: ReplicationMode) {
26✔
59
        super()
25,444✔
60
        this.driver = driver
25,444✔
61
        this.connection = driver.connection
25,444✔
62
        this.broadcaster = new Broadcaster(this)
25,444✔
63
        this.mode = mode
25,444✔
64
    }
25,444✔
65

26✔
66
    // -------------------------------------------------------------------------
26✔
67
    // Public Methods
26✔
68
    // -------------------------------------------------------------------------
26✔
69

26✔
70
    /**
26✔
71
     * Creates/uses database connection from the connection pool to perform further operations.
26✔
72
     * Returns obtained database connection.
26✔
73
     */
26✔
74
    connect(): Promise<void> {
26✔
75
        return Promise.resolve()
8✔
76
    }
8✔
77

26✔
78
    /**
26✔
79
     * Releases used database connection.
26✔
80
     * You cannot use query runner methods once its released.
26✔
81
     */
26✔
82
    release(): Promise<void> {
26✔
83
        this.isReleased = true
25,444✔
84
        return Promise.resolve()
25,444✔
85
    }
25,444✔
86

26✔
87
    /**
26✔
88
     * Starts transaction.
26✔
89
     * @param isolationLevel
26✔
90
     */
26✔
91
    async startTransaction(isolationLevel?: IsolationLevel): Promise<void> {
26✔
92
        if (this.isReleased) throw new QueryRunnerAlreadyReleasedError()
19,112!
93

19,112✔
94
        this.isTransactionActive = true
19,112✔
95
        try {
19,112✔
96
            await this.broadcaster.broadcast("BeforeTransactionStart")
19,112✔
97
        } catch (err) {
19,112!
98
            this.isTransactionActive = false
×
99
            throw err
×
100
        }
×
101
        await new Promise<void>(async (ok, fail) => {
19,112✔
102
            const transactionCallback = (err: any) => {
19,112✔
103
                if (err) {
19,102!
104
                    this.isTransactionActive = false
×
105
                    return fail(err)
×
106
                }
×
107
                ok()
19,102✔
108
            }
19,102✔
109

19,112✔
110
            if (this.transactionDepth === 0) {
19,112✔
111
                const pool = await (this.mode === "slave"
19,102✔
112
                    ? this.driver.obtainSlaveConnection()
19,102!
113
                    : this.driver.obtainMasterConnection())
19,102✔
114
                this.databaseConnection = pool.transaction()
19,102✔
115
                this.connection.logger.logQuery("BEGIN TRANSACTION")
19,102✔
116
                if (isolationLevel) {
19,102✔
117
                    this.databaseConnection.begin(
12✔
118
                        this.convertIsolationLevel(isolationLevel),
12✔
119
                        transactionCallback,
12✔
120
                    )
12✔
121
                    this.connection.logger.logQuery(
12✔
122
                        "SET TRANSACTION ISOLATION LEVEL " + isolationLevel,
12✔
123
                    )
12✔
124
                } else {
19,102✔
125
                    this.databaseConnection.begin(transactionCallback)
19,090✔
126
                }
19,090✔
127
            } else {
19,112✔
128
                await this.query(
10✔
129
                    `SAVE TRANSACTION typeorm_${this.transactionDepth}`,
10✔
130
                )
10✔
131
                ok()
10✔
132
            }
10✔
133
            this.transactionDepth += 1
19,112✔
134
        })
19,112✔
135

19,112✔
136
        await this.broadcaster.broadcast("AfterTransactionStart")
19,112✔
137
    }
19,112✔
138

26✔
139
    /**
26✔
140
     * Commits transaction.
26✔
141
     * Error will be thrown if transaction was not started.
26✔
142
     */
26✔
143
    async commitTransaction(): Promise<void> {
26✔
144
        if (this.isReleased) throw new QueryRunnerAlreadyReleasedError()
19,062!
145

19,062✔
146
        if (!this.isTransactionActive) throw new TransactionNotStartedError()
19,062!
147

19,062✔
148
        await this.broadcaster.broadcast("BeforeTransactionCommit")
19,062✔
149

19,062✔
150
        if (this.transactionDepth === 1) {
19,062✔
151
            return new Promise<void>((ok, fail) => {
19,058✔
152
                this.databaseConnection.commit(async (err: any) => {
19,058✔
153
                    if (err) return fail(err)
19,058!
154
                    this.isTransactionActive = false
19,058✔
155
                    this.databaseConnection = null
19,058✔
156

19,058✔
157
                    await this.broadcaster.broadcast("AfterTransactionCommit")
19,058✔
158

19,058✔
159
                    ok()
19,058✔
160
                    this.connection.logger.logQuery("COMMIT")
19,058✔
161
                    this.transactionDepth -= 1
19,058✔
162
                })
19,058✔
163
            })
19,058✔
164
        }
19,058✔
165
        this.transactionDepth -= 1
4✔
166
    }
4✔
167

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

50✔
175
        if (!this.isTransactionActive) throw new TransactionNotStartedError()
50!
176

50✔
177
        await this.broadcaster.broadcast("BeforeTransactionRollback")
50✔
178

50✔
179
        if (this.transactionDepth > 1) {
50✔
180
            await this.query(
6✔
181
                `ROLLBACK TRANSACTION typeorm_${this.transactionDepth - 1}`,
6✔
182
            )
6✔
183
            this.transactionDepth -= 1
6✔
184
        } else {
50✔
185
            return new Promise<void>((ok, fail) => {
44✔
186
                this.databaseConnection.rollback(async (err: any) => {
44✔
187
                    if (err) return fail(err)
44✔
188
                    this.isTransactionActive = false
42✔
189
                    this.databaseConnection = null
42✔
190

42✔
191
                    await this.broadcaster.broadcast("AfterTransactionRollback")
42✔
192

42✔
193
                    ok()
42✔
194
                    this.connection.logger.logQuery("ROLLBACK")
42✔
195
                    this.transactionDepth -= 1
42✔
196
                })
44✔
197
            })
44✔
198
        }
44✔
199
    }
50✔
200

26✔
201
    /**
26✔
202
     * Executes a given SQL query.
26✔
203
     * @param query
26✔
204
     * @param parameters
26✔
205
     * @param useStructuredResult
26✔
206
     */
26✔
207
    async query(
26✔
208
        query: string,
110,672✔
209
        parameters?: any[],
110,672✔
210
        useStructuredResult = false,
110,672✔
211
    ): Promise<any> {
110,672✔
212
        if (this.isReleased) throw new QueryRunnerAlreadyReleasedError()
110,672!
213

110,672✔
214
        const release = await this.lock.acquire()
110,672✔
215

110,672✔
216
        this.driver.connection.logger.logQuery(query, parameters, this)
110,672✔
217
        await this.broadcaster.broadcast("BeforeQuery", query, parameters)
110,672✔
218

110,672✔
219
        const broadcasterResult = new BroadcasterResult()
110,672✔
220

110,672✔
221
        try {
110,672✔
222
            const pool = await (this.mode === "slave"
110,672✔
223
                ? this.driver.obtainSlaveConnection()
110,672✔
224
                : this.driver.obtainMasterConnection())
110,672✔
225
            const request = new this.driver.mssql.Request(
110,672✔
226
                this.isTransactionActive ? this.databaseConnection : pool,
110,672✔
227
            )
110,672✔
228
            if (parameters && parameters.length) {
110,672✔
229
                parameters.forEach((parameter, index) => {
30,488✔
230
                    const parameterName = index.toString()
71,888✔
231
                    if (InstanceChecker.isMssqlParameter(parameter)) {
71,888✔
232
                        const mssqlParameter =
54,090✔
233
                            this.mssqlParameterToNativeParameter(parameter)
54,090✔
234
                        if (mssqlParameter) {
54,090✔
235
                            request.input(
54,026✔
236
                                parameterName,
54,026✔
237
                                mssqlParameter,
54,026✔
238
                                parameter.value,
54,026✔
239
                            )
54,026✔
240
                        } else {
54,090✔
241
                            request.input(parameterName, parameter.value)
64✔
242
                        }
64✔
243
                    } else {
71,888✔
244
                        request.input(parameterName, parameter)
17,798✔
245
                    }
17,798✔
246
                })
30,488✔
247
            }
30,488✔
248
            const queryStartTime = Date.now()
110,672✔
249

110,672✔
250
            const raw = await new Promise<any>((ok, fail) => {
110,672✔
251
                request.query(query, (err: any, raw: any) => {
110,672✔
252
                    // log slow queries if maxQueryExecution time is set
110,672✔
253
                    const maxQueryExecutionTime =
110,672✔
254
                        this.driver.options.maxQueryExecutionTime
110,672✔
255
                    const queryEndTime = Date.now()
110,672✔
256
                    const queryExecutionTime = queryEndTime - queryStartTime
110,672✔
257

110,672✔
258
                    this.broadcaster.broadcastAfterQueryEvent(
110,672✔
259
                        broadcasterResult,
110,672✔
260
                        query,
110,672✔
261
                        parameters,
110,672✔
262
                        true,
110,672✔
263
                        queryExecutionTime,
110,672✔
264
                        raw,
110,672✔
265
                        undefined,
110,672✔
266
                    )
110,672✔
267

110,672✔
268
                    if (
110,672✔
269
                        maxQueryExecutionTime &&
110,672!
270
                        queryExecutionTime > maxQueryExecutionTime
×
271
                    ) {
110,672!
272
                        this.driver.connection.logger.logQuerySlow(
×
273
                            queryExecutionTime,
×
274
                            query,
×
275
                            parameters,
×
276
                            this,
×
277
                        )
×
278
                    }
×
279

110,672✔
280
                    if (err) {
110,672✔
281
                        fail(new QueryFailedError(query, parameters, err))
16✔
282
                    }
16✔
283

110,672✔
284
                    ok(raw)
110,672✔
285
                })
110,672✔
286
            })
110,672✔
287

110,656✔
288
            const result = new QueryResult()
110,656✔
289

110,656✔
290
            if (raw?.hasOwnProperty("recordset")) {
110,672✔
291
                result.records = raw.recordset
110,656✔
292
            }
110,656✔
293

110,656✔
294
            if (raw?.hasOwnProperty("rowsAffected")) {
110,672✔
295
                result.affected = raw.rowsAffected[0]
110,656✔
296
            }
110,656✔
297

110,656✔
298
            const queryType = query.slice(0, query.indexOf(" "))
110,656✔
299
            switch (queryType) {
110,656✔
300
                case "DELETE":
110,672✔
301
                    // for DELETE query additionally return number of affected rows
260✔
302
                    result.raw = [raw.recordset, raw.rowsAffected[0]]
260✔
303
                    break
260✔
304
                default:
110,672✔
305
                    result.raw = raw.recordset
110,396✔
306
            }
110,672✔
307

110,656✔
308
            if (useStructuredResult) {
110,672✔
309
                return result
31,562✔
310
            } else {
110,672✔
311
                return result.raw
79,094✔
312
            }
79,094✔
313
        } catch (err) {
110,672✔
314
            this.driver.connection.logger.logQueryError(
16✔
315
                err,
16✔
316
                query,
16✔
317
                parameters,
16✔
318
                this,
16✔
319
            )
16✔
320
            this.broadcaster.broadcastAfterQueryEvent(
16✔
321
                broadcasterResult,
16✔
322
                query,
16✔
323
                parameters,
16✔
324
                false,
16✔
325
                undefined,
16✔
326
                undefined,
16✔
327
                err,
16✔
328
            )
16✔
329

16✔
330
            throw err
16✔
331
        } finally {
110,672!
332
            await broadcasterResult.wait()
110,672✔
333

110,672✔
334
            release()
110,672✔
335
        }
110,672✔
336
    }
110,672✔
337

26✔
338
    /**
26✔
339
     * Returns raw data stream.
26✔
340
     * @param query
26✔
341
     * @param parameters
26✔
342
     * @param onEnd
26✔
343
     * @param onError
26✔
344
     */
26✔
345
    async stream(
26✔
346
        query: string,
2✔
347
        parameters?: any[],
2✔
348
        onEnd?: Function,
2✔
349
        onError?: Function,
2✔
350
    ): Promise<ReadStream> {
2✔
351
        if (this.isReleased) throw new QueryRunnerAlreadyReleasedError()
2!
352

2✔
353
        const release = await this.lock.acquire()
2✔
354

2✔
355
        this.driver.connection.logger.logQuery(query, parameters, this)
2✔
356
        const pool = await (this.mode === "slave"
2✔
357
            ? this.driver.obtainSlaveConnection()
2!
358
            : this.driver.obtainMasterConnection())
2✔
359
        const request = new this.driver.mssql.Request(
2✔
360
            this.isTransactionActive ? this.databaseConnection : pool,
2!
361
        )
2✔
362
        if (parameters && parameters.length) {
2!
363
            parameters.forEach((parameter, index) => {
×
364
                const parameterName = index.toString()
×
365
                if (InstanceChecker.isMssqlParameter(parameter)) {
×
366
                    request.input(
×
367
                        parameterName,
×
368
                        this.mssqlParameterToNativeParameter(parameter),
×
369
                        parameter.value,
×
370
                    )
×
371
                } else {
×
372
                    request.input(parameterName, parameter)
×
373
                }
×
374
            })
×
375
        }
×
376

2✔
377
        request.query(query)
2✔
378

2✔
379
        const streamRequest = request.toReadableStream()
2✔
380

2✔
381
        streamRequest.on("error", (err: any) => {
2✔
382
            release()
×
383
            this.driver.connection.logger.logQueryError(
×
384
                err,
×
385
                query,
×
386
                parameters,
×
387
                this,
×
388
            )
×
389
        })
2✔
390

2✔
391
        streamRequest.on("end", () => {
2✔
392
            release()
2✔
393
        })
2✔
394

2✔
395
        if (onEnd) {
2!
396
            streamRequest.on("end", onEnd)
×
397
        }
×
398

2✔
399
        if (onError) {
2!
400
            streamRequest.on("error", onError)
×
401
        }
×
402

2✔
403
        return streamRequest
2✔
404
    }
2✔
405

26✔
406
    /**
26✔
407
     * Returns all available database names including system databases.
26✔
408
     */
26✔
409
    async getDatabases(): Promise<string[]> {
26✔
410
        const results: ObjectLiteral[] = await this.query(`EXEC sp_databases`)
×
411
        return results.map((result) => result["DATABASE_NAME"])
×
412
    }
×
413

26✔
414
    /**
26✔
415
     * Returns all available schema names including system schemas.
26✔
416
     * If database parameter specified, returns schemas of that database.
26✔
417
     * @param database
26✔
418
     */
26✔
419
    async getSchemas(database?: string): Promise<string[]> {
26✔
420
        const query = database
×
421
            ? `SELECT * FROM "${database}"."sys"."schema"`
×
422
            : `SELECT * FROM "sys"."schemas"`
×
423
        const results: ObjectLiteral[] = await this.query(query)
×
424
        return results.map((result) => result["name"])
×
425
    }
×
426

26✔
427
    /**
26✔
428
     * Checks if database with the given name exist.
26✔
429
     * @param database
26✔
430
     */
26✔
431
    async hasDatabase(database: string): Promise<boolean> {
26✔
432
        const result = await this.query(
2,988✔
433
            `SELECT DB_ID('${database}') as "db_id"`,
2,988✔
434
        )
2,988✔
435
        const dbId = result[0]["db_id"]
2,988✔
436
        return !!dbId
2,988✔
437
    }
2,988✔
438

26✔
439
    /**
26✔
440
     * Loads currently using database
26✔
441
     */
26✔
442
    async getCurrentDatabase(): Promise<string> {
26✔
443
        const currentDBQuery = await this.query(`SELECT DB_NAME() AS "db_name"`)
3,760✔
444
        return currentDBQuery[0]["db_name"]
3,760✔
445
    }
3,760✔
446

26✔
447
    /**
26✔
448
     * Checks if schema with the given name exist.
26✔
449
     * @param schema
26✔
450
     */
26✔
451
    async hasSchema(schema: string): Promise<boolean> {
26✔
452
        const result = await this.query(
6✔
453
            `SELECT SCHEMA_ID('${schema}') as "schema_id"`,
6✔
454
        )
6✔
455
        const schemaId = result[0]["schema_id"]
6✔
456
        return !!schemaId
6✔
457
    }
6✔
458

26✔
459
    /**
26✔
460
     * Loads currently using database schema
26✔
461
     */
26✔
462
    async getCurrentSchema(): Promise<string> {
26✔
463
        const currentSchemaQuery = await this.query(
4,672✔
464
            `SELECT SCHEMA_NAME() AS "schema_name"`,
4,672✔
465
        )
4,672✔
466
        return currentSchemaQuery[0]["schema_name"]
4,672✔
467
    }
4,672✔
468

26✔
469
    /**
26✔
470
     * Checks if table with the given name exist in the database.
26✔
471
     * @param tableOrName
26✔
472
     */
26✔
473
    async hasTable(tableOrName: Table | string): Promise<boolean> {
26✔
474
        const parsedTableName = this.driver.parseTableName(tableOrName)
3,214✔
475

3,214✔
476
        if (!parsedTableName.database) {
3,214!
477
            parsedTableName.database = await this.getCurrentDatabase()
×
478
        }
×
479

3,214✔
480
        if (!parsedTableName.schema) {
3,214!
481
            parsedTableName.schema = await this.getCurrentSchema()
×
482
        }
×
483

3,214✔
484
        const sql = `SELECT * FROM "${parsedTableName.database}"."INFORMATION_SCHEMA"."TABLES" WHERE "TABLE_NAME" = '${parsedTableName.tableName}' AND "TABLE_SCHEMA" = '${parsedTableName.schema}'`
3,214✔
485
        const result = await this.query(sql)
3,214✔
486
        return result.length ? true : false
3,214✔
487
    }
3,214✔
488

26✔
489
    /**
26✔
490
     * Checks if column exist in the table.
26✔
491
     * @param tableOrName
26✔
492
     * @param columnName
26✔
493
     */
26✔
494
    async hasColumn(
26✔
495
        tableOrName: Table | string,
8✔
496
        columnName: string,
8✔
497
    ): Promise<boolean> {
8✔
498
        const parsedTableName = this.driver.parseTableName(tableOrName)
8✔
499

8✔
500
        if (!parsedTableName.database) {
8!
501
            parsedTableName.database = await this.getCurrentDatabase()
×
502
        }
×
503

8✔
504
        if (!parsedTableName.schema) {
8!
505
            parsedTableName.schema = await this.getCurrentSchema()
×
506
        }
×
507

8✔
508
        const sql = `SELECT * FROM "${parsedTableName.database}"."INFORMATION_SCHEMA"."COLUMNS" WHERE "TABLE_NAME" = '${parsedTableName.tableName}' AND "TABLE_SCHEMA" = '${parsedTableName.schema}' AND "COLUMN_NAME" = '${columnName}'`
8✔
509
        const result = await this.query(sql)
8✔
510
        return result.length ? true : false
8✔
511
    }
8✔
512

26✔
513
    /**
26✔
514
     * Creates a new database.
26✔
515
     * @param database
26✔
516
     * @param ifNotExist
26✔
517
     */
26✔
518
    async createDatabase(
26✔
519
        database: string,
18✔
520
        ifNotExist?: boolean,
18✔
521
    ): Promise<void> {
18✔
522
        const up = ifNotExist
18✔
523
            ? `IF DB_ID('${database}') IS NULL CREATE DATABASE "${database}"`
18✔
524
            : `CREATE DATABASE "${database}"`
18!
525
        const down = `DROP DATABASE "${database}"`
18✔
526
        await this.executeQueries(new Query(up), new Query(down))
18✔
527
    }
18✔
528

26✔
529
    /**
26✔
530
     * Drops database.
26✔
531
     * @param database
26✔
532
     * @param ifExist
26✔
533
     */
26✔
534
    async dropDatabase(database: string, ifExist?: boolean): Promise<void> {
26✔
535
        const up = ifExist
4✔
536
            ? `IF DB_ID('${database}') IS NOT NULL DROP DATABASE "${database}"`
4✔
537
            : `DROP DATABASE "${database}"`
4✔
538
        const down = `CREATE DATABASE "${database}"`
4✔
539
        await this.executeQueries(new Query(up), new Query(down))
4✔
540
    }
4✔
541

26✔
542
    /**
26✔
543
     * Creates table schema.
26✔
544
     * If database name also specified (e.g. 'dbName.schemaName') schema will be created in specified database.
26✔
545
     * @param schemaPath
26✔
546
     * @param ifNotExist
26✔
547
     */
26✔
548
    async createSchema(
26✔
549
        schemaPath: string,
30✔
550
        ifNotExist?: boolean,
30✔
551
    ): Promise<void> {
30✔
552
        const upQueries: Query[] = []
30✔
553
        const downQueries: Query[] = []
30✔
554

30✔
555
        if (schemaPath.indexOf(".") === -1) {
30✔
556
            const upQuery = ifNotExist
16✔
557
                ? `IF SCHEMA_ID('${schemaPath}') IS NULL BEGIN EXEC ('CREATE SCHEMA "${schemaPath}"') END`
16✔
558
                : `CREATE SCHEMA "${schemaPath}"`
16!
559
            upQueries.push(new Query(upQuery))
16✔
560
            downQueries.push(new Query(`DROP SCHEMA "${schemaPath}"`))
16✔
561
        } else {
30✔
562
            const dbName = schemaPath.split(".")[0]
14✔
563
            const schema = schemaPath.split(".")[1]
14✔
564
            const currentDB = await this.getCurrentDatabase()
14✔
565
            upQueries.push(new Query(`USE "${dbName}"`))
14✔
566
            downQueries.push(new Query(`USE "${currentDB}"`))
14✔
567

14✔
568
            const upQuery = ifNotExist
14✔
569
                ? `IF SCHEMA_ID('${schema}') IS NULL BEGIN EXEC ('CREATE SCHEMA "${schema}"') END`
14✔
570
                : `CREATE SCHEMA "${schema}"`
14!
571
            upQueries.push(new Query(upQuery))
14✔
572
            downQueries.push(new Query(`DROP SCHEMA "${schema}"`))
14✔
573

14✔
574
            upQueries.push(new Query(`USE "${currentDB}"`))
14✔
575
            downQueries.push(new Query(`USE "${dbName}"`))
14✔
576
        }
14✔
577

30✔
578
        await this.executeQueries(upQueries, downQueries)
30✔
579
    }
30✔
580

26✔
581
    /**
26✔
582
     * Drops table schema.
26✔
583
     * If database name also specified (e.g. 'dbName.schemaName') schema will be dropped in specified database.
26✔
584
     * @param schemaPath
26✔
585
     * @param ifExist
26✔
586
     */
26✔
587
    async dropSchema(schemaPath: string, ifExist?: boolean): Promise<void> {
26✔
588
        const upQueries: Query[] = []
2✔
589
        const downQueries: Query[] = []
2✔
590

2✔
591
        if (schemaPath.indexOf(".") === -1) {
2✔
592
            const upQuery = ifExist
2✔
593
                ? `IF SCHEMA_ID('${schemaPath}') IS NULL BEGIN EXEC ('DROP SCHEMA "${schemaPath}"') END`
2!
594
                : `DROP SCHEMA "${schemaPath}"`
2✔
595
            upQueries.push(new Query(upQuery))
2✔
596
            downQueries.push(new Query(`CREATE SCHEMA "${schemaPath}"`))
2✔
597
        } else {
2!
598
            const dbName = schemaPath.split(".")[0]
×
599
            const schema = schemaPath.split(".")[1]
×
600
            const currentDB = await this.getCurrentDatabase()
×
601
            upQueries.push(new Query(`USE "${dbName}"`))
×
602
            downQueries.push(new Query(`USE "${currentDB}"`))
×
603

×
604
            const upQuery = ifExist
×
605
                ? `IF SCHEMA_ID('${schema}') IS NULL BEGIN EXEC ('DROP SCHEMA "${schema}"') END`
×
606
                : `DROP SCHEMA "${schema}"`
×
607
            upQueries.push(new Query(upQuery))
×
608
            downQueries.push(new Query(`CREATE SCHEMA "${schema}"`))
×
609

×
610
            upQueries.push(new Query(`USE "${currentDB}"`))
×
611
            downQueries.push(new Query(`USE "${dbName}"`))
×
612
        }
×
613

2✔
614
        await this.executeQueries(upQueries, downQueries)
2✔
615
    }
2✔
616

26✔
617
    /**
26✔
618
     * Creates a new table.
26✔
619
     * @param table
26✔
620
     * @param ifNotExist
26✔
621
     * @param createForeignKeys
26✔
622
     * @param createIndices
26✔
623
     */
26✔
624
    async createTable(
26✔
625
        table: Table,
10,528✔
626
        ifNotExist: boolean = false,
10,528✔
627
        createForeignKeys: boolean = true,
10,528✔
628
        createIndices: boolean = true,
10,528✔
629
    ): Promise<void> {
10,528✔
630
        if (ifNotExist) {
10,528✔
631
            const isTableExist = await this.hasTable(table)
66✔
632
            if (isTableExist) return Promise.resolve()
66✔
633
        }
66✔
634
        const upQueries: Query[] = []
10,524✔
635
        const downQueries: Query[] = []
10,524✔
636

10,524✔
637
        upQueries.push(this.createTableSql(table, createForeignKeys))
10,524✔
638
        downQueries.push(this.dropTableSql(table))
10,524✔
639

10,524✔
640
        // if createForeignKeys is true, we must drop created foreign keys in down query.
10,524✔
641
        // createTable does not need separate method to create foreign keys, because it create fk's in the same query with table creation.
10,524✔
642
        if (createForeignKeys)
10,524✔
643
            table.foreignKeys.forEach((foreignKey) =>
10,528✔
644
                downQueries.push(this.dropForeignKeySql(table, foreignKey)),
110✔
645
            )
110✔
646

10,524✔
647
        if (createIndices) {
10,524✔
648
            table.indices.forEach((index) => {
10,524✔
649
                // new index may be passed without name. In this case we generate index name manually.
4,524✔
650
                if (!index.name)
4,524✔
651
                    index.name = this.connection.namingStrategy.indexName(
4,524✔
652
                        table,
6✔
653
                        index.columnNames,
6✔
654
                        index.where,
6✔
655
                    )
6✔
656
                upQueries.push(this.createIndexSql(table, index))
4,524✔
657
                downQueries.push(this.dropIndexSql(table, index))
4,524✔
658
            })
10,524✔
659
        }
10,524✔
660

10,524✔
661
        // if table have column with generated type, we must add the expression to the metadata table
10,524✔
662
        const generatedColumns = table.columns.filter(
10,524✔
663
            (column) => column.generatedType && column.asExpression,
10,524✔
664
        )
10,524✔
665

10,524✔
666
        for (const column of generatedColumns) {
10,528✔
667
            const parsedTableName = this.driver.parseTableName(table)
56✔
668

56✔
669
            if (!parsedTableName.schema) {
56!
670
                parsedTableName.schema = await this.getCurrentSchema()
×
671
            }
×
672

56✔
673
            const insertQuery = this.insertTypeormMetadataSql({
56✔
674
                database: parsedTableName.database,
56✔
675
                schema: parsedTableName.schema,
56✔
676
                table: parsedTableName.tableName,
56✔
677
                type: MetadataTableType.GENERATED_COLUMN,
56✔
678
                name: column.name,
56✔
679
                value: column.asExpression,
56✔
680
            })
56✔
681

56✔
682
            const deleteQuery = this.deleteTypeormMetadataSql({
56✔
683
                database: parsedTableName.database,
56✔
684
                schema: parsedTableName.schema,
56✔
685
                table: parsedTableName.tableName,
56✔
686
                type: MetadataTableType.GENERATED_COLUMN,
56✔
687
                name: column.name,
56✔
688
            })
56✔
689

56✔
690
            upQueries.push(insertQuery)
56✔
691
            downQueries.push(deleteQuery)
56✔
692
        }
56✔
693

10,524✔
694
        await this.executeQueries(upQueries, downQueries)
10,524✔
695
    }
10,524✔
696

26✔
697
    /**
26✔
698
     * Drops the table.
26✔
699
     * @param tableOrName
26✔
700
     * @param ifExist
26✔
701
     * @param dropForeignKeys
26✔
702
     * @param dropIndices
26✔
703
     */
26✔
704
    async dropTable(
26✔
705
        tableOrName: Table | string,
24✔
706
        ifExist?: boolean,
24✔
707
        dropForeignKeys: boolean = true,
24✔
708
        dropIndices: boolean = true,
24✔
709
    ): Promise<void> {
24✔
710
        if (ifExist) {
24✔
711
            const isTableExist = await this.hasTable(tableOrName)
4✔
712
            if (!isTableExist) return Promise.resolve()
4!
713
        }
4✔
714

24✔
715
        // if dropTable called with dropForeignKeys = true, we must create foreign keys in down query.
24✔
716
        const createForeignKeys: boolean = dropForeignKeys
24✔
717
        const table = InstanceChecker.isTable(tableOrName)
24✔
718
            ? tableOrName
24✔
719
            : await this.getCachedTable(tableOrName)
24✔
720
        const upQueries: Query[] = []
16✔
721
        const downQueries: Query[] = []
16✔
722

16✔
723
        // It needs because if table does not exist and dropForeignKeys or dropIndices is true, we don't need
16✔
724
        // to perform drop queries for foreign keys and indices.
16✔
725

16✔
726
        if (dropIndices) {
24✔
727
            table.indices.forEach((index) => {
24✔
728
                upQueries.push(this.dropIndexSql(table, index))
2✔
729
                downQueries.push(this.createIndexSql(table, index))
2✔
730
            })
24✔
731
        }
24✔
732

24✔
733
        // if dropForeignKeys is true, we just drop the table, otherwise we also drop table foreign keys.
24✔
734
        // createTable does not need separate method to create foreign keys, because it create fk's in the same query with table creation.
24✔
735
        if (dropForeignKeys)
24✔
736
            table.foreignKeys.forEach((foreignKey) =>
24✔
737
                upQueries.push(this.dropForeignKeySql(table, foreignKey)),
20✔
738
            )
20✔
739

24✔
740
        upQueries.push(this.dropTableSql(table))
24✔
741
        downQueries.push(this.createTableSql(table, createForeignKeys))
24✔
742

24✔
743
        // if table had columns with generated type, we must remove the expression from the metadata table
24✔
744
        const generatedColumns = table.columns.filter(
24✔
745
            (column) => column.generatedType && column.asExpression,
24✔
746
        )
24✔
747

24✔
748
        for (const column of generatedColumns) {
24✔
749
            const parsedTableName = this.driver.parseTableName(table)
8✔
750

8✔
751
            if (!parsedTableName.schema) {
8!
752
                parsedTableName.schema = await this.getCurrentSchema()
×
753
            }
×
754

8✔
755
            const deleteQuery = this.deleteTypeormMetadataSql({
8✔
756
                database: parsedTableName.database,
8✔
757
                schema: parsedTableName.schema,
8✔
758
                table: parsedTableName.tableName,
8✔
759
                type: MetadataTableType.GENERATED_COLUMN,
8✔
760
                name: column.name,
8✔
761
            })
8✔
762

8✔
763
            const insertQuery = this.insertTypeormMetadataSql({
8✔
764
                database: parsedTableName.database,
8✔
765
                schema: parsedTableName.schema,
8✔
766
                table: parsedTableName.tableName,
8✔
767
                type: MetadataTableType.GENERATED_COLUMN,
8✔
768
                name: column.name,
8✔
769
                value: column.asExpression,
8✔
770
            })
8✔
771

8✔
772
            upQueries.push(deleteQuery)
8✔
773
            downQueries.push(insertQuery)
8✔
774
        }
8✔
775

24✔
776
        await this.executeQueries(upQueries, downQueries)
24✔
777
    }
24✔
778

26✔
779
    /**
26✔
780
     * Creates a new view.
26✔
781
     * @param view
26✔
782
     * @param syncWithMetadata
26✔
783
     */
26✔
784
    async createView(
26✔
785
        view: View,
16✔
786
        syncWithMetadata: boolean = false,
16✔
787
    ): Promise<void> {
16✔
788
        const upQueries: Query[] = []
16✔
789
        const downQueries: Query[] = []
16✔
790
        upQueries.push(this.createViewSql(view))
16✔
791
        if (syncWithMetadata)
16✔
792
            upQueries.push(await this.insertViewDefinitionSql(view))
16✔
793
        downQueries.push(this.dropViewSql(view))
16✔
794
        if (syncWithMetadata)
16✔
795
            downQueries.push(await this.deleteViewDefinitionSql(view))
16✔
796
        await this.executeQueries(upQueries, downQueries)
16✔
797
    }
16✔
798

26✔
799
    /**
26✔
800
     * Drops the view.
26✔
801
     * @param target
26✔
802
     */
26✔
803
    async dropView(target: View | string): Promise<void> {
26✔
804
        const viewName = InstanceChecker.isView(target) ? target.name : target
×
805
        const view = await this.getCachedView(viewName)
×
806

×
807
        const upQueries: Query[] = []
×
808
        const downQueries: Query[] = []
×
809
        upQueries.push(await this.deleteViewDefinitionSql(view))
×
810
        upQueries.push(this.dropViewSql(view))
×
811
        downQueries.push(await this.insertViewDefinitionSql(view))
×
812
        downQueries.push(this.createViewSql(view))
×
813
        await this.executeQueries(upQueries, downQueries)
×
814
    }
×
815

26✔
816
    /**
26✔
817
     * Renames a table.
26✔
818
     * @param oldTableOrName
26✔
819
     * @param newTableName
26✔
820
     */
26✔
821
    async renameTable(
26✔
822
        oldTableOrName: Table | string,
34✔
823
        newTableName: string,
34✔
824
    ): Promise<void> {
34✔
825
        const upQueries: Query[] = []
34✔
826
        const downQueries: Query[] = []
34✔
827
        const oldTable = InstanceChecker.isTable(oldTableOrName)
34✔
828
            ? oldTableOrName
34✔
829
            : await this.getCachedTable(oldTableOrName)
34✔
830
        const newTable = oldTable.clone()
30✔
831

30✔
832
        // we need database name and schema name to rename FK constraints
30✔
833
        let dbName: string | undefined = undefined
30✔
834
        let schemaName: string | undefined = undefined
30✔
835
        let oldTableName: string = oldTable.name
30✔
836
        const splittedName = oldTable.name.split(".")
30✔
837
        if (splittedName.length === 3) {
34✔
838
            dbName = splittedName[0]
4✔
839
            oldTableName = splittedName[2]
4✔
840
            if (splittedName[1] !== "") schemaName = splittedName[1]
4✔
841
        } else if (splittedName.length === 2) {
34!
842
            schemaName = splittedName[0]
×
843
            oldTableName = splittedName[1]
×
844
        }
×
845

34✔
846
        newTable.name = this.driver.buildTableName(
34✔
847
            newTableName,
34✔
848
            schemaName,
34✔
849
            dbName,
34✔
850
        )
34✔
851

34✔
852
        // if we have tables with database which differs from database specified in config, we must change currently used database.
34✔
853
        // This need because we can not rename objects from another database.
34✔
854
        const currentDB = await this.getCurrentDatabase()
34✔
855
        if (dbName && dbName !== currentDB) {
34✔
856
            upQueries.push(new Query(`USE "${dbName}"`))
4✔
857
            downQueries.push(new Query(`USE "${currentDB}"`))
4✔
858
        }
4✔
859

34✔
860
        // rename table
34✔
861
        upQueries.push(
34✔
862
            new Query(
34✔
863
                `EXEC sp_rename "${this.getTablePath(
34✔
864
                    oldTable,
34✔
865
                )}", "${newTableName}"`,
34✔
866
            ),
34✔
867
        )
34✔
868
        downQueries.push(
34✔
869
            new Query(
34✔
870
                `EXEC sp_rename "${this.getTablePath(
34✔
871
                    newTable,
34✔
872
                )}", "${oldTableName}"`,
34✔
873
            ),
34✔
874
        )
34✔
875

34✔
876
        // rename primary key constraint
34✔
877
        if (
34✔
878
            newTable.primaryColumns.length > 0 &&
34✔
879
            !newTable.primaryColumns[0].primaryKeyConstraintName
34✔
880
        ) {
34✔
881
            const columnNames = newTable.primaryColumns.map(
26✔
882
                (column) => column.name,
26✔
883
            )
26✔
884

26✔
885
            const oldPkName = this.connection.namingStrategy.primaryKeyName(
26✔
886
                oldTable,
26✔
887
                columnNames,
26✔
888
            )
26✔
889
            const newPkName = this.connection.namingStrategy.primaryKeyName(
26✔
890
                newTable,
26✔
891
                columnNames,
26✔
892
            )
26✔
893

26✔
894
            // rename primary constraint
26✔
895
            upQueries.push(
26✔
896
                new Query(
26✔
897
                    `EXEC sp_rename "${this.getTablePath(
26✔
898
                        newTable,
26✔
899
                    )}.${oldPkName}", "${newPkName}"`,
26✔
900
                ),
26✔
901
            )
26✔
902
            downQueries.push(
26✔
903
                new Query(
26✔
904
                    `EXEC sp_rename "${this.getTablePath(
26✔
905
                        newTable,
26✔
906
                    )}.${newPkName}", "${oldPkName}"`,
26✔
907
                ),
26✔
908
            )
26✔
909
        }
26✔
910

34✔
911
        // rename unique constraints
34✔
912
        newTable.uniques.forEach((unique) => {
34✔
913
            const oldUniqueName =
10✔
914
                this.connection.namingStrategy.uniqueConstraintName(
10✔
915
                    oldTable,
10✔
916
                    unique.columnNames,
10✔
917
                )
10✔
918

10✔
919
            // Skip renaming if Unique has user defined constraint name
10✔
920
            if (unique.name !== oldUniqueName) return
10✔
921

6✔
922
            // build new constraint name
6✔
923
            const newUniqueName =
6✔
924
                this.connection.namingStrategy.uniqueConstraintName(
6✔
925
                    newTable,
6✔
926
                    unique.columnNames,
6✔
927
                )
6✔
928

6✔
929
            // build queries
6✔
930
            upQueries.push(
6✔
931
                new Query(
6✔
932
                    `EXEC sp_rename "${this.getTablePath(newTable)}.${
6✔
933
                        unique.name
6✔
934
                    }", "${newUniqueName}"`,
6✔
935
                ),
6✔
936
            )
6✔
937
            downQueries.push(
6✔
938
                new Query(
6✔
939
                    `EXEC sp_rename "${this.getTablePath(
6✔
940
                        newTable,
6✔
941
                    )}.${newUniqueName}", "${unique.name}"`,
6✔
942
                ),
6✔
943
            )
6✔
944

6✔
945
            // replace constraint name
6✔
946
            unique.name = newUniqueName
6✔
947
        })
34✔
948

34✔
949
        // rename index constraints
34✔
950
        newTable.indices.forEach((index) => {
34✔
951
            const oldIndexName = this.connection.namingStrategy.indexName(
22✔
952
                oldTable,
22✔
953
                index.columnNames,
22✔
954
                index.where,
22✔
955
            )
22✔
956

22✔
957
            // Skip renaming if Index has user defined constraint name
22✔
958
            if (index.name !== oldIndexName) return
22✔
959

10✔
960
            // build new constraint name
10✔
961
            const newIndexName = this.connection.namingStrategy.indexName(
10✔
962
                newTable,
10✔
963
                index.columnNames,
10✔
964
                index.where,
10✔
965
            )
10✔
966

10✔
967
            // build queries
10✔
968
            upQueries.push(
10✔
969
                new Query(
10✔
970
                    `EXEC sp_rename "${this.getTablePath(newTable)}.${
10✔
971
                        index.name
10✔
972
                    }", "${newIndexName}", "INDEX"`,
10✔
973
                ),
10✔
974
            )
10✔
975
            downQueries.push(
10✔
976
                new Query(
10✔
977
                    `EXEC sp_rename "${this.getTablePath(
10✔
978
                        newTable,
10✔
979
                    )}.${newIndexName}", "${index.name}", "INDEX"`,
10✔
980
                ),
10✔
981
            )
10✔
982

10✔
983
            // replace constraint name
10✔
984
            index.name = newIndexName
10✔
985
        })
34✔
986

34✔
987
        // rename foreign key constraints
34✔
988
        newTable.foreignKeys.forEach((foreignKey) => {
34✔
989
            const oldForeignKeyName =
18✔
990
                this.connection.namingStrategy.foreignKeyName(
18✔
991
                    oldTable,
18✔
992
                    foreignKey.columnNames,
18✔
993
                    this.getTablePath(foreignKey),
18✔
994
                    foreignKey.referencedColumnNames,
18✔
995
                )
18✔
996

18✔
997
            // Skip renaming if foreign key has user defined constraint name
18✔
998
            if (foreignKey.name !== oldForeignKeyName) return
18✔
999

2✔
1000
            // build new constraint name
2✔
1001
            const newForeignKeyName =
2✔
1002
                this.connection.namingStrategy.foreignKeyName(
2✔
1003
                    newTable,
2✔
1004
                    foreignKey.columnNames,
2✔
1005
                    this.getTablePath(foreignKey),
2✔
1006
                    foreignKey.referencedColumnNames,
2✔
1007
                )
2✔
1008

2✔
1009
            // build queries
2✔
1010
            upQueries.push(
2✔
1011
                new Query(
2✔
1012
                    `EXEC sp_rename "${this.buildForeignKeyName(
2✔
1013
                        foreignKey.name!,
2✔
1014
                        schemaName,
2✔
1015
                        dbName,
2✔
1016
                    )}", "${newForeignKeyName}"`,
2✔
1017
                ),
2✔
1018
            )
2✔
1019
            downQueries.push(
2✔
1020
                new Query(
2✔
1021
                    `EXEC sp_rename "${this.buildForeignKeyName(
2✔
1022
                        newForeignKeyName,
2✔
1023
                        schemaName,
2✔
1024
                        dbName,
2✔
1025
                    )}", "${foreignKey.name}"`,
2✔
1026
                ),
2✔
1027
            )
2✔
1028

2✔
1029
            // replace constraint name
2✔
1030
            foreignKey.name = newForeignKeyName
2✔
1031
        })
34✔
1032

34✔
1033
        // change currently used database back to default db.
34✔
1034
        if (dbName && dbName !== currentDB) {
34✔
1035
            upQueries.push(new Query(`USE "${currentDB}"`))
4✔
1036
            downQueries.push(new Query(`USE "${dbName}"`))
4✔
1037
        }
4✔
1038

34✔
1039
        await this.executeQueries(upQueries, downQueries)
34✔
1040

34✔
1041
        // rename old table and replace it in cached tabled;
34✔
1042
        oldTable.name = newTable.name
34✔
1043
        this.replaceCachedTable(oldTable, newTable)
34✔
1044
    }
34✔
1045

26✔
1046
    /**
26✔
1047
     * Creates a new column from the column in the table.
26✔
1048
     * @param tableOrName
26✔
1049
     * @param column
26✔
1050
     */
26✔
1051
    async addColumn(
26✔
1052
        tableOrName: Table | string,
74✔
1053
        column: TableColumn,
74✔
1054
    ): Promise<void> {
74✔
1055
        const table = InstanceChecker.isTable(tableOrName)
74✔
1056
            ? tableOrName
74✔
1057
            : await this.getCachedTable(tableOrName)
74✔
1058
        const clonedTable = table.clone()
4✔
1059
        const upQueries: Query[] = []
4✔
1060
        const downQueries: Query[] = []
4✔
1061

4✔
1062
        upQueries.push(
4✔
1063
            new Query(
4✔
1064
                `ALTER TABLE ${this.escapePath(
4✔
1065
                    table,
4✔
1066
                )} ADD ${this.buildCreateColumnSql(
4✔
1067
                    table,
4✔
1068
                    column,
4✔
1069
                    false,
4✔
1070
                    true,
4✔
1071
                )}`,
4✔
1072
            ),
4✔
1073
        )
4✔
1074
        downQueries.push(
4✔
1075
            new Query(
4✔
1076
                `ALTER TABLE ${this.escapePath(table)} DROP COLUMN "${
4✔
1077
                    column.name
4✔
1078
                }"`,
4✔
1079
            ),
4✔
1080
        )
4✔
1081

4✔
1082
        // create or update primary key constraint
4✔
1083
        if (column.isPrimary) {
74✔
1084
            const primaryColumns = clonedTable.primaryColumns
14✔
1085
            // if table already have primary key, me must drop it and recreate again
14✔
1086
            if (primaryColumns.length > 0) {
14✔
1087
                const pkName = primaryColumns[0].primaryKeyConstraintName
4✔
1088
                    ? primaryColumns[0].primaryKeyConstraintName
4!
1089
                    : this.connection.namingStrategy.primaryKeyName(
4✔
1090
                          clonedTable,
4✔
1091
                          primaryColumns.map((column) => column.name),
4✔
1092
                      )
4✔
1093

4✔
1094
                const columnNames = primaryColumns
4✔
1095
                    .map((column) => `"${column.name}"`)
4✔
1096
                    .join(", ")
4✔
1097

4✔
1098
                upQueries.push(
4✔
1099
                    new Query(
4✔
1100
                        `ALTER TABLE ${this.escapePath(
4✔
1101
                            table,
4✔
1102
                        )} DROP CONSTRAINT "${pkName}"`,
4✔
1103
                    ),
4✔
1104
                )
4✔
1105
                downQueries.push(
4✔
1106
                    new Query(
4✔
1107
                        `ALTER TABLE ${this.escapePath(
4✔
1108
                            table,
4✔
1109
                        )} ADD CONSTRAINT "${pkName}" PRIMARY KEY (${columnNames})`,
4✔
1110
                    ),
4✔
1111
                )
4✔
1112
            }
4✔
1113

14✔
1114
            primaryColumns.push(column)
14✔
1115
            const pkName = primaryColumns[0].primaryKeyConstraintName
14✔
1116
                ? primaryColumns[0].primaryKeyConstraintName
14!
1117
                : this.connection.namingStrategy.primaryKeyName(
14✔
1118
                      clonedTable,
14✔
1119
                      primaryColumns.map((column) => column.name),
14✔
1120
                  )
14✔
1121

14✔
1122
            const columnNames = primaryColumns
14✔
1123
                .map((column) => `"${column.name}"`)
14✔
1124
                .join(", ")
14✔
1125
            upQueries.push(
14✔
1126
                new Query(
14✔
1127
                    `ALTER TABLE ${this.escapePath(
14✔
1128
                        table,
14✔
1129
                    )} ADD CONSTRAINT "${pkName}" PRIMARY KEY (${columnNames})`,
14✔
1130
                ),
14✔
1131
            )
14✔
1132
            downQueries.push(
14✔
1133
                new Query(
14✔
1134
                    `ALTER TABLE ${this.escapePath(
14✔
1135
                        table,
14✔
1136
                    )} DROP CONSTRAINT "${pkName}"`,
14✔
1137
                ),
14✔
1138
            )
14✔
1139
        }
14✔
1140

74✔
1141
        // create column index
74✔
1142
        const columnIndex = clonedTable.indices.find(
74✔
1143
            (index) =>
74✔
1144
                index.columnNames.length === 1 &&
2✔
1145
                index.columnNames[0] === column.name,
74✔
1146
        )
74✔
1147
        if (columnIndex) {
74!
1148
            upQueries.push(this.createIndexSql(table, columnIndex))
×
1149
            downQueries.push(this.dropIndexSql(table, columnIndex))
×
1150
        }
×
1151

74✔
1152
        // create unique constraint
74✔
1153
        if (column.isUnique) {
74✔
1154
            const uniqueConstraint = new TableUnique({
6✔
1155
                name: this.connection.namingStrategy.uniqueConstraintName(
6✔
1156
                    table,
6✔
1157
                    [column.name],
6✔
1158
                ),
6✔
1159
                columnNames: [column.name],
6✔
1160
            })
6✔
1161
            clonedTable.uniques.push(uniqueConstraint)
6✔
1162
            upQueries.push(
6✔
1163
                new Query(
6✔
1164
                    `ALTER TABLE ${this.escapePath(table)} ADD CONSTRAINT "${
6✔
1165
                        uniqueConstraint.name
6✔
1166
                    }" UNIQUE ("${column.name}")`,
6✔
1167
                ),
6✔
1168
            )
6✔
1169
            downQueries.push(
6✔
1170
                new Query(
6✔
1171
                    `ALTER TABLE ${this.escapePath(table)} DROP CONSTRAINT "${
6✔
1172
                        uniqueConstraint.name
6✔
1173
                    }"`,
6✔
1174
                ),
6✔
1175
            )
6✔
1176
        }
6✔
1177

74✔
1178
        // remove default constraint
74✔
1179
        if (column.default !== null && column.default !== undefined) {
74✔
1180
            const defaultName =
10✔
1181
                this.connection.namingStrategy.defaultConstraintName(
10✔
1182
                    table,
10✔
1183
                    column.name,
10✔
1184
                )
10✔
1185
            downQueries.push(
10✔
1186
                new Query(
10✔
1187
                    `ALTER TABLE ${this.escapePath(
10✔
1188
                        table,
10✔
1189
                    )} DROP CONSTRAINT "${defaultName}"`,
10✔
1190
                ),
10✔
1191
            )
10✔
1192
        }
10✔
1193

74✔
1194
        if (column.generatedType && column.asExpression) {
74✔
1195
            const parsedTableName = this.driver.parseTableName(table)
6✔
1196

6✔
1197
            if (!parsedTableName.schema) {
6!
1198
                parsedTableName.schema = await this.getCurrentSchema()
×
1199
            }
×
1200

6✔
1201
            const insertQuery = this.insertTypeormMetadataSql({
6✔
1202
                database: parsedTableName.database,
6✔
1203
                schema: parsedTableName.schema,
6✔
1204
                table: parsedTableName.tableName,
6✔
1205
                type: MetadataTableType.GENERATED_COLUMN,
6✔
1206
                name: column.name,
6✔
1207
                value: column.asExpression,
6✔
1208
            })
6✔
1209

6✔
1210
            const deleteQuery = this.deleteTypeormMetadataSql({
6✔
1211
                database: parsedTableName.database,
6✔
1212
                schema: parsedTableName.schema,
6✔
1213
                table: parsedTableName.tableName,
6✔
1214
                type: MetadataTableType.GENERATED_COLUMN,
6✔
1215
                name: column.name,
6✔
1216
            })
6✔
1217

6✔
1218
            upQueries.push(insertQuery)
6✔
1219
            downQueries.push(deleteQuery)
6✔
1220
        }
6✔
1221

74✔
1222
        await this.executeQueries(upQueries, downQueries)
74✔
1223

70✔
1224
        clonedTable.addColumn(column)
70✔
1225
        this.replaceCachedTable(table, clonedTable)
70✔
1226
    }
70✔
1227

26✔
1228
    /**
26✔
1229
     * Creates a new columns from the column in the table.
26✔
1230
     * @param tableOrName
26✔
1231
     * @param columns
26✔
1232
     */
26✔
1233
    async addColumns(
26✔
1234
        tableOrName: Table | string,
12✔
1235
        columns: TableColumn[],
12✔
1236
    ): Promise<void> {
12✔
1237
        for (const column of columns) {
12✔
1238
            await this.addColumn(tableOrName, column)
14✔
1239
        }
12✔
1240
    }
10✔
1241

26✔
1242
    /**
26✔
1243
     * Renames column in the given table.
26✔
1244
     * @param tableOrName
26✔
1245
     * @param oldTableColumnOrName
26✔
1246
     * @param newTableColumnOrName
26✔
1247
     */
26✔
1248
    async renameColumn(
26✔
1249
        tableOrName: Table | string,
28✔
1250
        oldTableColumnOrName: TableColumn | string,
28✔
1251
        newTableColumnOrName: TableColumn | string,
28✔
1252
    ): Promise<void> {
28✔
1253
        const table = InstanceChecker.isTable(tableOrName)
28✔
1254
            ? tableOrName
28✔
1255
            : await this.getCachedTable(tableOrName)
28✔
1256
        const oldColumn = InstanceChecker.isTableColumn(oldTableColumnOrName)
4✔
1257
            ? oldTableColumnOrName
28✔
1258
            : table.columns.find((c) => c.name === oldTableColumnOrName)
28✔
1259
        if (!oldColumn)
28✔
1260
            throw new TypeORMError(
28!
1261
                `Column "${oldTableColumnOrName}" was not found in the "${table.name}" table.`,
×
1262
            )
×
1263

28✔
1264
        let newColumn: TableColumn | undefined = undefined
28✔
1265
        if (InstanceChecker.isTableColumn(newTableColumnOrName)) {
28✔
1266
            newColumn = newTableColumnOrName
18✔
1267
        } else {
28✔
1268
            newColumn = oldColumn.clone()
10✔
1269
            newColumn.name = newTableColumnOrName
10✔
1270
        }
10✔
1271

28✔
1272
        await this.changeColumn(table, oldColumn, newColumn)
28✔
1273
    }
28✔
1274

26✔
1275
    /**
26✔
1276
     * Changes a column in the table.
26✔
1277
     * @param tableOrName
26✔
1278
     * @param oldTableColumnOrName
26✔
1279
     * @param newColumn
26✔
1280
     */
26✔
1281
    async changeColumn(
26✔
1282
        tableOrName: Table | string,
102✔
1283
        oldTableColumnOrName: TableColumn | string,
102✔
1284
        newColumn: TableColumn,
102✔
1285
    ): Promise<void> {
102✔
1286
        const table = InstanceChecker.isTable(tableOrName)
102✔
1287
            ? tableOrName
102✔
1288
            : await this.getCachedTable(tableOrName)
102!
1289
        let clonedTable = table.clone()
×
1290
        const upQueries: Query[] = []
×
1291
        const downQueries: Query[] = []
×
1292

×
1293
        const oldColumn = InstanceChecker.isTableColumn(oldTableColumnOrName)
×
1294
            ? oldTableColumnOrName
102✔
1295
            : table.columns.find(
102!
1296
                  (column) => column.name === oldTableColumnOrName,
×
1297
              )
102✔
1298
        if (!oldColumn)
102✔
1299
            throw new TypeORMError(
102!
1300
                `Column "${oldTableColumnOrName}" was not found in the "${table.name}" table.`,
×
1301
            )
×
1302

102✔
1303
        if (
102✔
1304
            (newColumn.isGenerated !== oldColumn.isGenerated &&
102✔
1305
                newColumn.generationStrategy !== "uuid") ||
102✔
1306
            newColumn.type !== oldColumn.type ||
102✔
1307
            newColumn.length !== oldColumn.length ||
102✔
1308
            newColumn.asExpression !== oldColumn.asExpression ||
102✔
1309
            newColumn.generatedType !== oldColumn.generatedType
52✔
1310
        ) {
102✔
1311
            // SQL Server does not support changing of IDENTITY column, so we must drop column and recreate it again.
50✔
1312
            // Also, we recreate column if column type changed
50✔
1313
            await this.dropColumn(table, oldColumn)
50✔
1314
            await this.addColumn(table, newColumn)
50✔
1315

50✔
1316
            // update cloned table
50✔
1317
            clonedTable = table.clone()
50✔
1318
        } else {
102✔
1319
            if (newColumn.name !== oldColumn.name) {
52✔
1320
                // we need database name and schema name to rename FK constraints
28✔
1321
                let dbName: string | undefined = undefined
28✔
1322
                let schemaName: string | undefined = undefined
28✔
1323
                const splittedName = table.name.split(".")
28✔
1324
                if (splittedName.length === 3) {
28✔
1325
                    dbName = splittedName[0]
4✔
1326
                    if (splittedName[1] !== "") schemaName = splittedName[1]
4✔
1327
                } else if (splittedName.length === 2) {
28!
1328
                    schemaName = splittedName[0]
×
1329
                }
×
1330

28✔
1331
                // if we have tables with database which differs from database specified in config, we must change currently used database.
28✔
1332
                // This need because we can not rename objects from another database.
28✔
1333
                const currentDB = await this.getCurrentDatabase()
28✔
1334
                if (dbName && dbName !== currentDB) {
28✔
1335
                    upQueries.push(new Query(`USE "${dbName}"`))
4✔
1336
                    downQueries.push(new Query(`USE "${currentDB}"`))
4✔
1337
                }
4✔
1338

28✔
1339
                // rename the column
28✔
1340
                upQueries.push(
28✔
1341
                    new Query(
28✔
1342
                        `EXEC sp_rename "${this.getTablePath(table)}.${
28✔
1343
                            oldColumn.name
28✔
1344
                        }", "${newColumn.name}"`,
28✔
1345
                    ),
28✔
1346
                )
28✔
1347
                downQueries.push(
28✔
1348
                    new Query(
28✔
1349
                        `EXEC sp_rename "${this.getTablePath(table)}.${
28✔
1350
                            newColumn.name
28✔
1351
                        }", "${oldColumn.name}"`,
28✔
1352
                    ),
28✔
1353
                )
28✔
1354

28✔
1355
                // rename column primary key constraint
28✔
1356
                if (
28✔
1357
                    oldColumn.isPrimary === true &&
28✔
1358
                    !oldColumn.primaryKeyConstraintName
6✔
1359
                ) {
28✔
1360
                    const primaryColumns = clonedTable.primaryColumns
2✔
1361

2✔
1362
                    // build old primary constraint name
2✔
1363
                    const columnNames = primaryColumns.map(
2✔
1364
                        (column) => column.name,
2✔
1365
                    )
2✔
1366
                    const oldPkName =
2✔
1367
                        this.connection.namingStrategy.primaryKeyName(
2✔
1368
                            clonedTable,
2✔
1369
                            columnNames,
2✔
1370
                        )
2✔
1371

2✔
1372
                    // replace old column name with new column name
2✔
1373
                    columnNames.splice(columnNames.indexOf(oldColumn.name), 1)
2✔
1374
                    columnNames.push(newColumn.name)
2✔
1375

2✔
1376
                    // build new primary constraint name
2✔
1377
                    const newPkName =
2✔
1378
                        this.connection.namingStrategy.primaryKeyName(
2✔
1379
                            clonedTable,
2✔
1380
                            columnNames,
2✔
1381
                        )
2✔
1382

2✔
1383
                    // rename primary constraint
2✔
1384
                    upQueries.push(
2✔
1385
                        new Query(
2✔
1386
                            `EXEC sp_rename "${this.getTablePath(
2✔
1387
                                clonedTable,
2✔
1388
                            )}.${oldPkName}", "${newPkName}"`,
2✔
1389
                        ),
2✔
1390
                    )
2✔
1391
                    downQueries.push(
2✔
1392
                        new Query(
2✔
1393
                            `EXEC sp_rename "${this.getTablePath(
2✔
1394
                                clonedTable,
2✔
1395
                            )}.${newPkName}", "${oldPkName}"`,
2✔
1396
                        ),
2✔
1397
                    )
2✔
1398
                }
2✔
1399

28✔
1400
                // rename index constraints
28✔
1401
                clonedTable.findColumnIndices(oldColumn).forEach((index) => {
28✔
1402
                    const oldIndexName =
6✔
1403
                        this.connection.namingStrategy.indexName(
6✔
1404
                            clonedTable,
6✔
1405
                            index.columnNames,
6✔
1406
                            index.where,
6✔
1407
                        )
6✔
1408

6✔
1409
                    // Skip renaming if Index has user defined constraint name
6✔
1410
                    if (index.name !== oldIndexName) return
6✔
1411

2✔
1412
                    // build new constraint name
2✔
1413
                    index.columnNames.splice(
2✔
1414
                        index.columnNames.indexOf(oldColumn.name),
2✔
1415
                        1,
2✔
1416
                    )
2✔
1417
                    index.columnNames.push(newColumn.name)
2✔
1418
                    const newIndexName =
2✔
1419
                        this.connection.namingStrategy.indexName(
2✔
1420
                            clonedTable,
2✔
1421
                            index.columnNames,
2✔
1422
                            index.where,
2✔
1423
                        )
2✔
1424

2✔
1425
                    // build queries
2✔
1426
                    upQueries.push(
2✔
1427
                        new Query(
2✔
1428
                            `EXEC sp_rename "${this.getTablePath(
2✔
1429
                                clonedTable,
2✔
1430
                            )}.${index.name}", "${newIndexName}", "INDEX"`,
2✔
1431
                        ),
2✔
1432
                    )
2✔
1433
                    downQueries.push(
2✔
1434
                        new Query(
2✔
1435
                            `EXEC sp_rename "${this.getTablePath(
2✔
1436
                                clonedTable,
2✔
1437
                            )}.${newIndexName}", "${index.name}", "INDEX"`,
2✔
1438
                        ),
2✔
1439
                    )
2✔
1440

2✔
1441
                    // replace constraint name
2✔
1442
                    index.name = newIndexName
2✔
1443
                })
28✔
1444

28✔
1445
                // rename foreign key constraints
28✔
1446
                clonedTable
28✔
1447
                    .findColumnForeignKeys(oldColumn)
28✔
1448
                    .forEach((foreignKey) => {
28✔
1449
                        const foreignKeyName =
2✔
1450
                            this.connection.namingStrategy.foreignKeyName(
2✔
1451
                                clonedTable,
2✔
1452
                                foreignKey.columnNames,
2✔
1453
                                this.getTablePath(foreignKey),
2✔
1454
                                foreignKey.referencedColumnNames,
2✔
1455
                            )
2✔
1456

2✔
1457
                        // Skip renaming if foreign key has user defined constraint name
2✔
1458
                        if (foreignKey.name !== foreignKeyName) return
2!
1459

2✔
1460
                        // build new constraint name
2✔
1461
                        foreignKey.columnNames.splice(
2✔
1462
                            foreignKey.columnNames.indexOf(oldColumn.name),
2✔
1463
                            1,
2✔
1464
                        )
2✔
1465
                        foreignKey.columnNames.push(newColumn.name)
2✔
1466
                        const newForeignKeyName =
2✔
1467
                            this.connection.namingStrategy.foreignKeyName(
2✔
1468
                                clonedTable,
2✔
1469
                                foreignKey.columnNames,
2✔
1470
                                this.getTablePath(foreignKey),
2✔
1471
                                foreignKey.referencedColumnNames,
2✔
1472
                            )
2✔
1473

2✔
1474
                        // build queries
2✔
1475
                        upQueries.push(
2✔
1476
                            new Query(
2✔
1477
                                `EXEC sp_rename "${this.buildForeignKeyName(
2✔
1478
                                    foreignKey.name!,
2✔
1479
                                    schemaName,
2✔
1480
                                    dbName,
2✔
1481
                                )}", "${newForeignKeyName}"`,
2✔
1482
                            ),
2✔
1483
                        )
2✔
1484
                        downQueries.push(
2✔
1485
                            new Query(
2✔
1486
                                `EXEC sp_rename "${this.buildForeignKeyName(
2✔
1487
                                    newForeignKeyName,
2✔
1488
                                    schemaName,
2✔
1489
                                    dbName,
2✔
1490
                                )}", "${foreignKey.name}"`,
2✔
1491
                            ),
2✔
1492
                        )
2✔
1493

2✔
1494
                        // replace constraint name
2✔
1495
                        foreignKey.name = newForeignKeyName
2✔
1496
                    })
28✔
1497

28✔
1498
                // rename check constraints
28✔
1499
                clonedTable.findColumnChecks(oldColumn).forEach((check) => {
28✔
1500
                    // build new constraint name
×
1501
                    check.columnNames!.splice(
×
1502
                        check.columnNames!.indexOf(oldColumn.name),
×
1503
                        1,
×
1504
                    )
×
1505
                    check.columnNames!.push(newColumn.name)
×
1506
                    const newCheckName =
×
1507
                        this.connection.namingStrategy.checkConstraintName(
×
1508
                            clonedTable,
×
1509
                            check.expression!,
×
1510
                        )
×
1511

×
1512
                    // build queries
×
1513
                    upQueries.push(
×
1514
                        new Query(
×
1515
                            `EXEC sp_rename "${this.getTablePath(
×
1516
                                clonedTable,
×
1517
                            )}.${check.name}", "${newCheckName}"`,
×
1518
                        ),
×
1519
                    )
×
1520
                    downQueries.push(
×
1521
                        new Query(
×
1522
                            `EXEC sp_rename "${this.getTablePath(
×
1523
                                clonedTable,
×
1524
                            )}.${newCheckName}", "${check.name}"`,
×
1525
                        ),
×
1526
                    )
×
1527

×
1528
                    // replace constraint name
×
1529
                    check.name = newCheckName
×
1530
                })
28✔
1531

28✔
1532
                // rename unique constraints
28✔
1533
                clonedTable.findColumnUniques(oldColumn).forEach((unique) => {
28✔
1534
                    const oldUniqueName =
12✔
1535
                        this.connection.namingStrategy.uniqueConstraintName(
12✔
1536
                            clonedTable,
12✔
1537
                            unique.columnNames,
12✔
1538
                        )
12✔
1539

12✔
1540
                    // Skip renaming if Unique has user defined constraint name
12✔
1541
                    if (unique.name !== oldUniqueName) return
12✔
1542

8✔
1543
                    // build new constraint name
8✔
1544
                    unique.columnNames.splice(
8✔
1545
                        unique.columnNames.indexOf(oldColumn.name),
8✔
1546
                        1,
8✔
1547
                    )
8✔
1548
                    unique.columnNames.push(newColumn.name)
8✔
1549
                    const newUniqueName =
8✔
1550
                        this.connection.namingStrategy.uniqueConstraintName(
8✔
1551
                            clonedTable,
8✔
1552
                            unique.columnNames,
8✔
1553
                        )
8✔
1554

8✔
1555
                    // build queries
8✔
1556
                    upQueries.push(
8✔
1557
                        new Query(
8✔
1558
                            `EXEC sp_rename "${this.getTablePath(
8✔
1559
                                clonedTable,
8✔
1560
                            )}.${unique.name}", "${newUniqueName}"`,
8✔
1561
                        ),
8✔
1562
                    )
8✔
1563
                    downQueries.push(
8✔
1564
                        new Query(
8✔
1565
                            `EXEC sp_rename "${this.getTablePath(
8✔
1566
                                clonedTable,
8✔
1567
                            )}.${newUniqueName}", "${unique.name}"`,
8✔
1568
                        ),
8✔
1569
                    )
8✔
1570

8✔
1571
                    // replace constraint name
8✔
1572
                    unique.name = newUniqueName
8✔
1573
                })
28✔
1574

28✔
1575
                // rename default constraints
28✔
1576
                if (
28✔
1577
                    oldColumn.default !== null &&
28✔
1578
                    oldColumn.default !== undefined
28✔
1579
                ) {
28✔
1580
                    const oldDefaultName =
4✔
1581
                        this.connection.namingStrategy.defaultConstraintName(
4✔
1582
                            table,
4✔
1583
                            oldColumn.name,
4✔
1584
                        )
4✔
1585
                    const newDefaultName =
4✔
1586
                        this.connection.namingStrategy.defaultConstraintName(
4✔
1587
                            table,
4✔
1588
                            newColumn.name,
4✔
1589
                        )
4✔
1590

4✔
1591
                    upQueries.push(
4✔
1592
                        new Query(
4✔
1593
                            `ALTER TABLE ${this.escapePath(
4✔
1594
                                table,
4✔
1595
                            )} DROP CONSTRAINT "${oldDefaultName}"`,
4✔
1596
                        ),
4✔
1597
                    )
4✔
1598
                    downQueries.push(
4✔
1599
                        new Query(
4✔
1600
                            `ALTER TABLE ${this.escapePath(
4✔
1601
                                table,
4✔
1602
                            )} ADD CONSTRAINT "${oldDefaultName}" DEFAULT ${
4✔
1603
                                oldColumn.default
4✔
1604
                            } FOR "${newColumn.name}"`,
4✔
1605
                        ),
4✔
1606
                    )
4✔
1607

4✔
1608
                    upQueries.push(
4✔
1609
                        new Query(
4✔
1610
                            `ALTER TABLE ${this.escapePath(
4✔
1611
                                table,
4✔
1612
                            )} ADD CONSTRAINT "${newDefaultName}" DEFAULT ${
4✔
1613
                                oldColumn.default
4✔
1614
                            } FOR "${newColumn.name}"`,
4✔
1615
                        ),
4✔
1616
                    )
4✔
1617
                    downQueries.push(
4✔
1618
                        new Query(
4✔
1619
                            `ALTER TABLE ${this.escapePath(
4✔
1620
                                table,
4✔
1621
                            )} DROP CONSTRAINT "${newDefaultName}"`,
4✔
1622
                        ),
4✔
1623
                    )
4✔
1624
                }
4✔
1625

28✔
1626
                // change currently used database back to default db.
28✔
1627
                if (dbName && dbName !== currentDB) {
28✔
1628
                    upQueries.push(new Query(`USE "${currentDB}"`))
4✔
1629
                    downQueries.push(new Query(`USE "${dbName}"`))
4✔
1630
                }
4✔
1631

28✔
1632
                // rename old column in the Table object
28✔
1633
                const oldTableColumn = clonedTable.columns.find(
28✔
1634
                    (column) => column.name === oldColumn.name,
28✔
1635
                )
28✔
1636
                clonedTable.columns[
28✔
1637
                    clonedTable.columns.indexOf(oldTableColumn!)
28✔
1638
                ].name = newColumn.name
28✔
1639
                oldColumn.name = newColumn.name
28✔
1640
            }
28✔
1641

52✔
1642
            if (
52✔
1643
                this.isColumnChanged(oldColumn, newColumn, false, false, false)
52✔
1644
            ) {
52!
1645
                upQueries.push(
×
1646
                    new Query(
×
1647
                        `ALTER TABLE ${this.escapePath(
×
1648
                            table,
×
1649
                        )} ALTER COLUMN ${this.buildCreateColumnSql(
×
1650
                            table,
×
1651
                            newColumn,
×
1652
                            true,
×
1653
                            false,
×
1654
                            true,
×
1655
                        )}`,
×
1656
                    ),
×
1657
                )
×
1658
                downQueries.push(
×
1659
                    new Query(
×
1660
                        `ALTER TABLE ${this.escapePath(
×
1661
                            table,
×
1662
                        )} ALTER COLUMN ${this.buildCreateColumnSql(
×
1663
                            table,
×
1664
                            oldColumn,
×
1665
                            true,
×
1666
                            false,
×
1667
                            true,
×
1668
                        )}`,
×
1669
                    ),
×
1670
                )
×
1671
            }
×
1672

52✔
1673
            if (this.isEnumChanged(oldColumn, newColumn)) {
52✔
1674
                const oldExpression = this.getEnumExpression(oldColumn)
2✔
1675
                const oldCheck = new TableCheck({
2✔
1676
                    name: this.connection.namingStrategy.checkConstraintName(
2✔
1677
                        table,
2✔
1678
                        oldExpression,
2✔
1679
                        true,
2✔
1680
                    ),
2✔
1681
                    expression: oldExpression,
2✔
1682
                })
2✔
1683

2✔
1684
                const newExpression = this.getEnumExpression(newColumn)
2✔
1685
                const newCheck = new TableCheck({
2✔
1686
                    name: this.connection.namingStrategy.checkConstraintName(
2✔
1687
                        table,
2✔
1688
                        newExpression,
2✔
1689
                        true,
2✔
1690
                    ),
2✔
1691
                    expression: newExpression,
2✔
1692
                })
2✔
1693

2✔
1694
                upQueries.push(this.dropCheckConstraintSql(table, oldCheck))
2✔
1695
                upQueries.push(this.createCheckConstraintSql(table, newCheck))
2✔
1696

2✔
1697
                downQueries.push(this.dropCheckConstraintSql(table, newCheck))
2✔
1698
                downQueries.push(this.createCheckConstraintSql(table, oldCheck))
2✔
1699
            }
2✔
1700

52✔
1701
            if (newColumn.isPrimary !== oldColumn.isPrimary) {
52✔
1702
                const primaryColumns = clonedTable.primaryColumns
6✔
1703

6✔
1704
                // if primary column state changed, we must always drop existed constraint.
6✔
1705
                if (primaryColumns.length > 0) {
6✔
1706
                    const pkName = primaryColumns[0].primaryKeyConstraintName
6✔
1707
                        ? primaryColumns[0].primaryKeyConstraintName
6!
1708
                        : this.connection.namingStrategy.primaryKeyName(
6✔
1709
                              clonedTable,
6✔
1710
                              primaryColumns.map((column) => column.name),
6✔
1711
                          )
6✔
1712

6✔
1713
                    const columnNames = primaryColumns
6✔
1714
                        .map((column) => `"${column.name}"`)
6✔
1715
                        .join(", ")
6✔
1716
                    upQueries.push(
6✔
1717
                        new Query(
6✔
1718
                            `ALTER TABLE ${this.escapePath(
6✔
1719
                                table,
6✔
1720
                            )} DROP CONSTRAINT "${pkName}"`,
6✔
1721
                        ),
6✔
1722
                    )
6✔
1723
                    downQueries.push(
6✔
1724
                        new Query(
6✔
1725
                            `ALTER TABLE ${this.escapePath(
6✔
1726
                                table,
6✔
1727
                            )} ADD CONSTRAINT "${pkName}" PRIMARY KEY (${columnNames})`,
6✔
1728
                        ),
6✔
1729
                    )
6✔
1730
                }
6✔
1731

6✔
1732
                if (newColumn.isPrimary === true) {
6✔
1733
                    primaryColumns.push(newColumn)
2✔
1734
                    // update column in table
2✔
1735
                    const column = clonedTable.columns.find(
2✔
1736
                        (column) => column.name === newColumn.name,
2✔
1737
                    )
2✔
1738
                    column!.isPrimary = true
2✔
1739
                    const pkName = primaryColumns[0].primaryKeyConstraintName
2✔
1740
                        ? primaryColumns[0].primaryKeyConstraintName
2!
1741
                        : this.connection.namingStrategy.primaryKeyName(
2✔
1742
                              clonedTable,
2✔
1743
                              primaryColumns.map((column) => column.name),
2✔
1744
                          )
2✔
1745

2✔
1746
                    const columnNames = primaryColumns
2✔
1747
                        .map((column) => `"${column.name}"`)
2✔
1748
                        .join(", ")
2✔
1749
                    upQueries.push(
2✔
1750
                        new Query(
2✔
1751
                            `ALTER TABLE ${this.escapePath(
2✔
1752
                                table,
2✔
1753
                            )} ADD CONSTRAINT "${pkName}" PRIMARY KEY (${columnNames})`,
2✔
1754
                        ),
2✔
1755
                    )
2✔
1756
                    downQueries.push(
2✔
1757
                        new Query(
2✔
1758
                            `ALTER TABLE ${this.escapePath(
2✔
1759
                                table,
2✔
1760
                            )} DROP CONSTRAINT "${pkName}"`,
2✔
1761
                        ),
2✔
1762
                    )
2✔
1763
                } else {
6✔
1764
                    const primaryColumn = primaryColumns.find(
4✔
1765
                        (c) => c.name === newColumn.name,
4✔
1766
                    )
4✔
1767
                    primaryColumns.splice(
4✔
1768
                        primaryColumns.indexOf(primaryColumn!),
4✔
1769
                        1,
4✔
1770
                    )
4✔
1771

4✔
1772
                    // update column in table
4✔
1773
                    const column = clonedTable.columns.find(
4✔
1774
                        (column) => column.name === newColumn.name,
4✔
1775
                    )
4✔
1776
                    column!.isPrimary = false
4✔
1777

4✔
1778
                    // if we have another primary keys, we must recreate constraint.
4✔
1779
                    if (primaryColumns.length > 0) {
4✔
1780
                        const pkName = primaryColumns[0]
2✔
1781
                            .primaryKeyConstraintName
2✔
1782
                            ? primaryColumns[0].primaryKeyConstraintName
2!
1783
                            : this.connection.namingStrategy.primaryKeyName(
2✔
1784
                                  clonedTable,
2✔
1785
                                  primaryColumns.map((column) => column.name),
2✔
1786
                              )
2✔
1787

2✔
1788
                        const columnNames = primaryColumns
2✔
1789
                            .map((column) => `"${column.name}"`)
2✔
1790
                            .join(", ")
2✔
1791
                        upQueries.push(
2✔
1792
                            new Query(
2✔
1793
                                `ALTER TABLE ${this.escapePath(
2✔
1794
                                    table,
2✔
1795
                                )} ADD CONSTRAINT "${pkName}" PRIMARY KEY (${columnNames})`,
2✔
1796
                            ),
2✔
1797
                        )
2✔
1798
                        downQueries.push(
2✔
1799
                            new Query(
2✔
1800
                                `ALTER TABLE ${this.escapePath(
2✔
1801
                                    table,
2✔
1802
                                )} DROP CONSTRAINT "${pkName}"`,
2✔
1803
                            ),
2✔
1804
                        )
2✔
1805
                    }
2✔
1806
                }
4✔
1807
            }
6✔
1808

52✔
1809
            if (newColumn.isUnique !== oldColumn.isUnique) {
52✔
1810
                if (newColumn.isUnique === true) {
2✔
1811
                    const uniqueConstraint = new TableUnique({
2✔
1812
                        name: this.connection.namingStrategy.uniqueConstraintName(
2✔
1813
                            table,
2✔
1814
                            [newColumn.name],
2✔
1815
                        ),
2✔
1816
                        columnNames: [newColumn.name],
2✔
1817
                    })
2✔
1818
                    clonedTable.uniques.push(uniqueConstraint)
2✔
1819
                    upQueries.push(
2✔
1820
                        new Query(
2✔
1821
                            `ALTER TABLE ${this.escapePath(
2✔
1822
                                table,
2✔
1823
                            )} ADD CONSTRAINT "${
2✔
1824
                                uniqueConstraint.name
2✔
1825
                            }" UNIQUE ("${newColumn.name}")`,
2✔
1826
                        ),
2✔
1827
                    )
2✔
1828
                    downQueries.push(
2✔
1829
                        new Query(
2✔
1830
                            `ALTER TABLE ${this.escapePath(
2✔
1831
                                table,
2✔
1832
                            )} DROP CONSTRAINT "${uniqueConstraint.name}"`,
2✔
1833
                        ),
2✔
1834
                    )
2✔
1835
                } else {
2!
1836
                    const uniqueConstraint = clonedTable.uniques.find(
×
1837
                        (unique) => {
×
1838
                            return (
×
1839
                                unique.columnNames.length === 1 &&
×
1840
                                !!unique.columnNames.find(
×
1841
                                    (columnName) =>
×
1842
                                        columnName === newColumn.name,
×
1843
                                )
×
1844
                            )
×
1845
                        },
×
1846
                    )
×
1847
                    clonedTable.uniques.splice(
×
1848
                        clonedTable.uniques.indexOf(uniqueConstraint!),
×
1849
                        1,
×
1850
                    )
×
1851
                    upQueries.push(
×
1852
                        new Query(
×
1853
                            `ALTER TABLE ${this.escapePath(
×
1854
                                table,
×
1855
                            )} DROP CONSTRAINT "${uniqueConstraint!.name}"`,
×
1856
                        ),
×
1857
                    )
×
1858
                    downQueries.push(
×
1859
                        new Query(
×
1860
                            `ALTER TABLE ${this.escapePath(
×
1861
                                table,
×
1862
                            )} ADD CONSTRAINT "${
×
1863
                                uniqueConstraint!.name
×
1864
                            }" UNIQUE ("${newColumn.name}")`,
×
1865
                        ),
×
1866
                    )
×
1867
                }
×
1868
            }
2✔
1869

52✔
1870
            if (newColumn.default !== oldColumn.default) {
52✔
1871
                // (note) if there is a previous default, we need to drop its constraint first
4✔
1872
                if (
4✔
1873
                    oldColumn.default !== null &&
4✔
1874
                    oldColumn.default !== undefined
4✔
1875
                ) {
4✔
1876
                    const defaultName =
2✔
1877
                        this.connection.namingStrategy.defaultConstraintName(
2✔
1878
                            table,
2✔
1879
                            oldColumn.name,
2✔
1880
                        )
2✔
1881
                    upQueries.push(
2✔
1882
                        new Query(
2✔
1883
                            `ALTER TABLE ${this.escapePath(
2✔
1884
                                table,
2✔
1885
                            )} DROP CONSTRAINT "${defaultName}"`,
2✔
1886
                        ),
2✔
1887
                    )
2✔
1888
                    downQueries.push(
2✔
1889
                        new Query(
2✔
1890
                            `ALTER TABLE ${this.escapePath(
2✔
1891
                                table,
2✔
1892
                            )} ADD CONSTRAINT "${defaultName}" DEFAULT ${
2✔
1893
                                oldColumn.default
2✔
1894
                            } FOR "${oldColumn.name}"`,
2✔
1895
                        ),
2✔
1896
                    )
2✔
1897
                }
2✔
1898

4✔
1899
                if (
4✔
1900
                    newColumn.default !== null &&
4✔
1901
                    newColumn.default !== undefined
4✔
1902
                ) {
4✔
1903
                    const defaultName =
4✔
1904
                        this.connection.namingStrategy.defaultConstraintName(
4✔
1905
                            table,
4✔
1906
                            newColumn.name,
4✔
1907
                        )
4✔
1908
                    upQueries.push(
4✔
1909
                        new Query(
4✔
1910
                            `ALTER TABLE ${this.escapePath(
4✔
1911
                                table,
4✔
1912
                            )} ADD CONSTRAINT "${defaultName}" DEFAULT ${
4✔
1913
                                newColumn.default
4✔
1914
                            } FOR "${newColumn.name}"`,
4✔
1915
                        ),
4✔
1916
                    )
4✔
1917
                    downQueries.push(
4✔
1918
                        new Query(
4✔
1919
                            `ALTER TABLE ${this.escapePath(
4✔
1920
                                table,
4✔
1921
                            )} DROP CONSTRAINT "${defaultName}"`,
4✔
1922
                        ),
4✔
1923
                    )
4✔
1924
                }
4✔
1925
            }
4✔
1926

52✔
1927
            await this.executeQueries(upQueries, downQueries)
52✔
1928
            this.replaceCachedTable(table, clonedTable)
52✔
1929
        }
52✔
1930
    }
102✔
1931

26✔
1932
    /**
26✔
1933
     * Changes a column in the table.
26✔
1934
     * @param tableOrName
26✔
1935
     * @param changedColumns
26✔
1936
     */
26✔
1937
    async changeColumns(
26✔
1938
        tableOrName: Table | string,
44✔
1939
        changedColumns: { newColumn: TableColumn; oldColumn: TableColumn }[],
44✔
1940
    ): Promise<void> {
44✔
1941
        for (const { oldColumn, newColumn } of changedColumns) {
44✔
1942
            await this.changeColumn(tableOrName, oldColumn, newColumn)
62✔
1943
        }
62✔
1944
    }
44✔
1945

26✔
1946
    /**
26✔
1947
     * Drops column in the table.
26✔
1948
     * @param tableOrName
26✔
1949
     * @param columnOrName
26✔
1950
     */
26✔
1951
    async dropColumn(
26✔
1952
        tableOrName: Table | string,
86✔
1953
        columnOrName: TableColumn | string,
86✔
1954
    ): Promise<void> {
86✔
1955
        const table = InstanceChecker.isTable(tableOrName)
86✔
1956
            ? tableOrName
86✔
1957
            : await this.getCachedTable(tableOrName)
86✔
1958
        const column = InstanceChecker.isTableColumn(columnOrName)
6✔
1959
            ? columnOrName
86✔
1960
            : table.findColumnByName(columnOrName)
86✔
1961
        if (!column)
86✔
1962
            throw new TypeORMError(
86✔
1963
                `Column "${columnOrName}" was not found in table "${table.name}"`,
2✔
1964
            )
2✔
1965

84✔
1966
        const clonedTable = table.clone()
84✔
1967
        const upQueries: Query[] = []
84✔
1968
        const downQueries: Query[] = []
84✔
1969

84✔
1970
        // drop primary key constraint
84✔
1971
        if (column.isPrimary) {
86✔
1972
            const pkName = column.primaryKeyConstraintName
14✔
1973
                ? column.primaryKeyConstraintName
14!
1974
                : this.connection.namingStrategy.primaryKeyName(
14✔
1975
                      clonedTable,
14✔
1976
                      clonedTable.primaryColumns.map((column) => column.name),
14✔
1977
                  )
14✔
1978

14✔
1979
            const columnNames = clonedTable.primaryColumns
14✔
1980
                .map((primaryColumn) => `"${primaryColumn.name}"`)
14✔
1981
                .join(", ")
14✔
1982

14✔
1983
            upQueries.push(
14✔
1984
                new Query(
14✔
1985
                    `ALTER TABLE ${this.escapePath(
14✔
1986
                        clonedTable,
14✔
1987
                    )} DROP CONSTRAINT "${pkName}"`,
14✔
1988
                ),
14✔
1989
            )
14✔
1990
            downQueries.push(
14✔
1991
                new Query(
14✔
1992
                    `ALTER TABLE ${this.escapePath(
14✔
1993
                        clonedTable,
14✔
1994
                    )} ADD CONSTRAINT "${pkName}" PRIMARY KEY (${columnNames})`,
14✔
1995
                ),
14✔
1996
            )
14✔
1997

14✔
1998
            // update column in table
14✔
1999
            const tableColumn = clonedTable.findColumnByName(column.name)
14✔
2000
            tableColumn!.isPrimary = false
14✔
2001

14✔
2002
            // if primary key have multiple columns, we must recreate it without dropped column
14✔
2003
            if (clonedTable.primaryColumns.length > 0) {
14✔
2004
                const pkName = clonedTable.primaryColumns[0]
2✔
2005
                    .primaryKeyConstraintName
2✔
2006
                    ? clonedTable.primaryColumns[0].primaryKeyConstraintName
2!
2007
                    : this.connection.namingStrategy.primaryKeyName(
2✔
2008
                          clonedTable,
2✔
2009
                          clonedTable.primaryColumns.map(
2✔
2010
                              (column) => column.name,
2✔
2011
                          ),
2✔
2012
                      )
2✔
2013

2✔
2014
                const columnNames = clonedTable.primaryColumns
2✔
2015
                    .map((primaryColumn) => `"${primaryColumn.name}"`)
2✔
2016
                    .join(", ")
2✔
2017
                upQueries.push(
2✔
2018
                    new Query(
2✔
2019
                        `ALTER TABLE ${this.escapePath(
2✔
2020
                            clonedTable,
2✔
2021
                        )} ADD CONSTRAINT "${pkName}" PRIMARY KEY (${columnNames})`,
2✔
2022
                    ),
2✔
2023
                )
2✔
2024
                downQueries.push(
2✔
2025
                    new Query(
2✔
2026
                        `ALTER TABLE ${this.escapePath(
2✔
2027
                            clonedTable,
2✔
2028
                        )} DROP CONSTRAINT "${pkName}"`,
2✔
2029
                    ),
2✔
2030
                )
2✔
2031
            }
2✔
2032
        }
14✔
2033

84✔
2034
        // drop column index
84✔
2035
        const columnIndex = clonedTable.indices.find(
84✔
2036
            (index) =>
84✔
2037
                index.columnNames.length === 1 &&
2✔
2038
                index.columnNames[0] === column.name,
84✔
2039
        )
84✔
2040
        if (columnIndex) {
86!
2041
            clonedTable.indices.splice(
×
2042
                clonedTable.indices.indexOf(columnIndex),
×
2043
                1,
×
2044
            )
×
2045
            upQueries.push(this.dropIndexSql(table, columnIndex))
×
2046
            downQueries.push(this.createIndexSql(table, columnIndex))
×
2047
        }
×
2048

84✔
2049
        // drop column check
84✔
2050
        const columnCheck = clonedTable.checks.find(
84✔
2051
            (check) =>
84✔
2052
                !!check.columnNames &&
32✔
2053
                check.columnNames.length === 1 &&
32✔
2054
                check.columnNames[0] === column.name,
84✔
2055
        )
84✔
2056
        if (columnCheck) {
86✔
2057
            clonedTable.checks.splice(
4✔
2058
                clonedTable.checks.indexOf(columnCheck),
4✔
2059
                1,
4✔
2060
            )
4✔
2061
            upQueries.push(this.dropCheckConstraintSql(table, columnCheck))
4✔
2062
            downQueries.push(this.createCheckConstraintSql(table, columnCheck))
4✔
2063
        }
4✔
2064

84✔
2065
        // drop column unique
84✔
2066
        const columnUnique = clonedTable.uniques.find(
84✔
2067
            (unique) =>
84✔
2068
                unique.columnNames.length === 1 &&
60✔
2069
                unique.columnNames[0] === column.name,
84✔
2070
        )
84✔
2071
        if (columnUnique) {
86✔
2072
            clonedTable.uniques.splice(
6✔
2073
                clonedTable.uniques.indexOf(columnUnique),
6✔
2074
                1,
6✔
2075
            )
6✔
2076
            upQueries.push(this.dropUniqueConstraintSql(table, columnUnique))
6✔
2077
            downQueries.push(
6✔
2078
                this.createUniqueConstraintSql(table, columnUnique),
6✔
2079
            )
6✔
2080
        }
6✔
2081

84✔
2082
        // drop default constraint
84✔
2083
        if (column.default !== null && column.default !== undefined) {
86✔
2084
            const defaultName =
12✔
2085
                this.connection.namingStrategy.defaultConstraintName(
12✔
2086
                    table,
12✔
2087
                    column.name,
12✔
2088
                )
12✔
2089
            upQueries.push(
12✔
2090
                new Query(
12✔
2091
                    `ALTER TABLE ${this.escapePath(
12✔
2092
                        table,
12✔
2093
                    )} DROP CONSTRAINT "${defaultName}"`,
12✔
2094
                ),
12✔
2095
            )
12✔
2096
            downQueries.push(
12✔
2097
                new Query(
12✔
2098
                    `ALTER TABLE ${this.escapePath(
12✔
2099
                        table,
12✔
2100
                    )} ADD CONSTRAINT "${defaultName}" DEFAULT ${
12✔
2101
                        column.default
12✔
2102
                    } FOR "${column.name}"`,
12✔
2103
                ),
12✔
2104
            )
12✔
2105
        }
12✔
2106

84✔
2107
        if (column.generatedType && column.asExpression) {
86✔
2108
            const parsedTableName = this.driver.parseTableName(table)
8✔
2109

8✔
2110
            if (!parsedTableName.schema) {
8!
2111
                parsedTableName.schema = await this.getCurrentSchema()
×
2112
            }
×
2113

8✔
2114
            const deleteQuery = this.deleteTypeormMetadataSql({
8✔
2115
                database: parsedTableName.database,
8✔
2116
                schema: parsedTableName.schema,
8✔
2117
                table: parsedTableName.tableName,
8✔
2118
                type: MetadataTableType.GENERATED_COLUMN,
8✔
2119
                name: column.name,
8✔
2120
            })
8✔
2121
            const insertQuery = this.insertTypeormMetadataSql({
8✔
2122
                database: parsedTableName.database,
8✔
2123
                schema: parsedTableName.schema,
8✔
2124
                table: parsedTableName.tableName,
8✔
2125
                type: MetadataTableType.GENERATED_COLUMN,
8✔
2126
                name: column.name,
8✔
2127
                value: column.asExpression,
8✔
2128
            })
8✔
2129

8✔
2130
            upQueries.push(deleteQuery)
8✔
2131
            downQueries.push(insertQuery)
8✔
2132
        }
8✔
2133

84✔
2134
        upQueries.push(
84✔
2135
            new Query(
84✔
2136
                `ALTER TABLE ${this.escapePath(table)} DROP COLUMN "${
84✔
2137
                    column.name
84✔
2138
                }"`,
84✔
2139
            ),
84✔
2140
        )
84✔
2141
        downQueries.push(
84✔
2142
            new Query(
84✔
2143
                `ALTER TABLE ${this.escapePath(
84✔
2144
                    table,
84✔
2145
                )} ADD ${this.buildCreateColumnSql(
84✔
2146
                    table,
84✔
2147
                    column,
84✔
2148
                    false,
84✔
2149
                    false,
84✔
2150
                )}`,
84✔
2151
            ),
84✔
2152
        )
84✔
2153

84✔
2154
        await this.executeQueries(upQueries, downQueries)
84✔
2155

84✔
2156
        clonedTable.removeColumn(column)
84✔
2157
        this.replaceCachedTable(table, clonedTable)
84✔
2158
    }
84✔
2159

26✔
2160
    /**
26✔
2161
     * Drops the columns in the table.
26✔
2162
     * @param tableOrName
26✔
2163
     * @param columns
26✔
2164
     */
26✔
2165
    async dropColumns(
26✔
2166
        tableOrName: Table | string,
10✔
2167
        columns: TableColumn[] | string[],
10✔
2168
    ): Promise<void> {
10✔
2169
        for (const column of [...columns]) {
10✔
2170
            await this.dropColumn(tableOrName, column)
26✔
2171
        }
26✔
2172
    }
10✔
2173

26✔
2174
    /**
26✔
2175
     * Creates a new primary key.
26✔
2176
     * @param tableOrName
26✔
2177
     * @param columnNames
26✔
2178
     * @param constraintName
26✔
2179
     */
26✔
2180
    async createPrimaryKey(
26✔
2181
        tableOrName: Table | string,
4✔
2182
        columnNames: string[],
4✔
2183
        constraintName?: string,
4✔
2184
    ): Promise<void> {
4✔
2185
        const table = InstanceChecker.isTable(tableOrName)
4✔
2186
            ? tableOrName
4!
2187
            : await this.getCachedTable(tableOrName)
4✔
2188
        const clonedTable = table.clone()
4✔
2189

4✔
2190
        const up = this.createPrimaryKeySql(table, columnNames, constraintName)
4✔
2191

4✔
2192
        // mark columns as primary, because dropPrimaryKeySql build constraint name from table primary column names.
4✔
2193
        clonedTable.columns.forEach((column) => {
4✔
2194
            if (columnNames.find((columnName) => columnName === column.name))
10✔
2195
                column.isPrimary = true
10✔
2196
        })
4✔
2197
        const down = this.dropPrimaryKeySql(clonedTable)
4✔
2198

4✔
2199
        await this.executeQueries(up, down)
4✔
2200
        this.replaceCachedTable(table, clonedTable)
4✔
2201
    }
4✔
2202

26✔
2203
    /**
26✔
2204
     * Updates composite primary keys.
26✔
2205
     * @param tableOrName
26✔
2206
     * @param columns
26✔
2207
     */
26✔
2208
    async updatePrimaryKeys(
26✔
2209
        tableOrName: Table | string,
6✔
2210
        columns: TableColumn[],
6✔
2211
    ): Promise<void> {
6✔
2212
        const table = InstanceChecker.isTable(tableOrName)
6✔
2213
            ? tableOrName
6✔
2214
            : await this.getCachedTable(tableOrName)
6!
2215
        const clonedTable = table.clone()
×
2216
        const columnNames = columns.map((column) => column.name)
✔
2217
        const upQueries: Query[] = []
×
2218
        const downQueries: Query[] = []
×
2219

×
2220
        // if table already have primary columns, we must drop them.
×
2221
        const primaryColumns = clonedTable.primaryColumns
×
2222
        if (primaryColumns.length > 0) {
6✔
2223
            const pkName = primaryColumns[0].primaryKeyConstraintName
6✔
2224
                ? primaryColumns[0].primaryKeyConstraintName
6!
2225
                : this.connection.namingStrategy.primaryKeyName(
6✔
2226
                      clonedTable,
6✔
2227
                      primaryColumns.map((column) => column.name),
6✔
2228
                  )
6✔
2229

6✔
2230
            const columnNamesString = primaryColumns
6✔
2231
                .map((column) => `"${column.name}"`)
6✔
2232
                .join(", ")
6✔
2233

6✔
2234
            upQueries.push(
6✔
2235
                new Query(
6✔
2236
                    `ALTER TABLE ${this.escapePath(
6✔
2237
                        table,
6✔
2238
                    )} DROP CONSTRAINT "${pkName}"`,
6✔
2239
                ),
6✔
2240
            )
6✔
2241
            downQueries.push(
6✔
2242
                new Query(
6✔
2243
                    `ALTER TABLE ${this.escapePath(
6✔
2244
                        table,
6✔
2245
                    )} ADD CONSTRAINT "${pkName}" PRIMARY KEY (${columnNamesString})`,
6✔
2246
                ),
6✔
2247
            )
6✔
2248
        }
6✔
2249

6✔
2250
        // update columns in table.
6✔
2251
        clonedTable.columns
6✔
2252
            .filter((column) => columnNames.indexOf(column.name) !== -1)
6✔
2253
            .forEach((column) => (column.isPrimary = true))
6✔
2254

6✔
2255
        const pkName = primaryColumns[0].primaryKeyConstraintName
6✔
2256
            ? primaryColumns[0].primaryKeyConstraintName
6!
2257
            : this.connection.namingStrategy.primaryKeyName(
6✔
2258
                  clonedTable,
6✔
2259
                  columnNames,
6✔
2260
              )
6✔
2261

6✔
2262
        const columnNamesString = columnNames
6✔
2263
            .map((columnName) => `"${columnName}"`)
6✔
2264
            .join(", ")
6✔
2265

6✔
2266
        upQueries.push(
6✔
2267
            new Query(
6✔
2268
                `ALTER TABLE ${this.escapePath(
6✔
2269
                    table,
6✔
2270
                )} ADD CONSTRAINT "${pkName}" PRIMARY KEY (${columnNamesString})`,
6✔
2271
            ),
6✔
2272
        )
6✔
2273
        downQueries.push(
6✔
2274
            new Query(
6✔
2275
                `ALTER TABLE ${this.escapePath(
6✔
2276
                    table,
6✔
2277
                )} DROP CONSTRAINT "${pkName}"`,
6✔
2278
            ),
6✔
2279
        )
6✔
2280

6✔
2281
        await this.executeQueries(upQueries, downQueries)
6✔
2282
        this.replaceCachedTable(table, clonedTable)
6✔
2283
    }
6✔
2284

26✔
2285
    /**
26✔
2286
     * Drops a primary key.
26✔
2287
     * @param tableOrName
26✔
2288
     * @param constraintName
26✔
2289
     */
26✔
2290
    async dropPrimaryKey(
26✔
2291
        tableOrName: Table | string,
6✔
2292
        constraintName?: string,
6✔
2293
    ): Promise<void> {
6✔
2294
        const table = InstanceChecker.isTable(tableOrName)
6✔
2295
            ? tableOrName
6✔
2296
            : await this.getCachedTable(tableOrName)
6!
2297
        const up = this.dropPrimaryKeySql(table)
×
2298
        const down = this.createPrimaryKeySql(
×
2299
            table,
×
2300
            table.primaryColumns.map((column) => column.name),
✔
2301
            constraintName,
×
2302
        )
×
2303
        await this.executeQueries(up, down)
×
2304
        table.primaryColumns.forEach((column) => {
6✔
2305
            column.isPrimary = false
6✔
2306
        })
6✔
2307
    }
6✔
2308

26✔
2309
    /**
26✔
2310
     * Creates a new unique constraint.
26✔
2311
     * @param tableOrName
26✔
2312
     * @param uniqueConstraint
26✔
2313
     */
26✔
2314
    async createUniqueConstraint(
26✔
2315
        tableOrName: Table | string,
16✔
2316
        uniqueConstraint: TableUnique,
16✔
2317
    ): Promise<void> {
16✔
2318
        const table = InstanceChecker.isTable(tableOrName)
16✔
2319
            ? tableOrName
16✔
2320
            : await this.getCachedTable(tableOrName)
16✔
2321

12✔
2322
        // new unique constraint may be passed without name. In this case we generate unique name manually.
12✔
2323
        if (!uniqueConstraint.name)
12✔
2324
            uniqueConstraint.name =
16✔
2325
                this.connection.namingStrategy.uniqueConstraintName(
4✔
2326
                    table,
4✔
2327
                    uniqueConstraint.columnNames,
4✔
2328
                )
4✔
2329

16✔
2330
        const up = this.createUniqueConstraintSql(table, uniqueConstraint)
16✔
2331
        const down = this.dropUniqueConstraintSql(table, uniqueConstraint)
16✔
2332
        await this.executeQueries(up, down)
16✔
2333
        table.addUniqueConstraint(uniqueConstraint)
16✔
2334
    }
16✔
2335

26✔
2336
    /**
26✔
2337
     * Creates a new unique constraints.
26✔
2338
     * @param tableOrName
26✔
2339
     * @param uniqueConstraints
26✔
2340
     */
26✔
2341
    async createUniqueConstraints(
26✔
2342
        tableOrName: Table | string,
6✔
2343
        uniqueConstraints: TableUnique[],
6✔
2344
    ): Promise<void> {
6✔
2345
        const promises = uniqueConstraints.map((uniqueConstraint) =>
6✔
2346
            this.createUniqueConstraint(tableOrName, uniqueConstraint),
6✔
2347
        )
6✔
2348
        await Promise.all(promises)
6✔
2349
    }
6✔
2350

26✔
2351
    /**
26✔
2352
     * Drops unique constraint.
26✔
2353
     * @param tableOrName
26✔
2354
     * @param uniqueOrName
26✔
2355
     */
26✔
2356
    async dropUniqueConstraint(
26✔
2357
        tableOrName: Table | string,
16✔
2358
        uniqueOrName: TableUnique | string,
16✔
2359
    ): Promise<void> {
16✔
2360
        const table = InstanceChecker.isTable(tableOrName)
16✔
2361
            ? tableOrName
16✔
2362
            : await this.getCachedTable(tableOrName)
16✔
2363
        const uniqueConstraint = InstanceChecker.isTableUnique(uniqueOrName)
8✔
2364
            ? uniqueOrName
16✔
2365
            : table.uniques.find((u) => u.name === uniqueOrName)
16!
2366
        if (!uniqueConstraint)
16✔
2367
            throw new TypeORMError(
16!
2368
                `Supplied unique constraint was not found in table ${table.name}`,
×
2369
            )
×
2370

16✔
2371
        const up = this.dropUniqueConstraintSql(table, uniqueConstraint)
16✔
2372
        const down = this.createUniqueConstraintSql(table, uniqueConstraint)
16✔
2373
        await this.executeQueries(up, down)
16✔
2374
        table.removeUniqueConstraint(uniqueConstraint)
16✔
2375
    }
16✔
2376

26✔
2377
    /**
26✔
2378
     * Drops unique constraints.
26✔
2379
     * @param tableOrName
26✔
2380
     * @param uniqueConstraints
26✔
2381
     */
26✔
2382
    async dropUniqueConstraints(
26✔
2383
        tableOrName: Table | string,
8✔
2384
        uniqueConstraints: TableUnique[],
8✔
2385
    ): Promise<void> {
8✔
2386
        const promises = uniqueConstraints.map((uniqueConstraint) =>
8✔
2387
            this.dropUniqueConstraint(tableOrName, uniqueConstraint),
8✔
2388
        )
8✔
2389
        await Promise.all(promises)
8✔
2390
    }
8✔
2391

26✔
2392
    /**
26✔
2393
     * Creates a new check constraint.
26✔
2394
     * @param tableOrName
26✔
2395
     * @param checkConstraint
26✔
2396
     */
26✔
2397
    async createCheckConstraint(
26✔
2398
        tableOrName: Table | string,
10✔
2399
        checkConstraint: TableCheck,
10✔
2400
    ): Promise<void> {
10✔
2401
        const table = InstanceChecker.isTable(tableOrName)
10✔
2402
            ? tableOrName
10✔
2403
            : await this.getCachedTable(tableOrName)
10✔
2404

6✔
2405
        // new unique constraint may be passed without name. In this case we generate unique name manually.
6✔
2406
        if (!checkConstraint.name)
6✔
2407
            checkConstraint.name =
6✔
2408
                this.connection.namingStrategy.checkConstraintName(
6✔
2409
                    table,
6✔
2410
                    checkConstraint.expression!,
6✔
2411
                )
6✔
2412

10✔
2413
        const up = this.createCheckConstraintSql(table, checkConstraint)
10✔
2414
        const down = this.dropCheckConstraintSql(table, checkConstraint)
10✔
2415
        await this.executeQueries(up, down)
10✔
2416
        table.addCheckConstraint(checkConstraint)
10✔
2417
    }
10✔
2418

26✔
2419
    /**
26✔
2420
     * Creates a new check constraints.
26✔
2421
     * @param tableOrName
26✔
2422
     * @param checkConstraints
26✔
2423
     */
26✔
2424
    async createCheckConstraints(
26✔
2425
        tableOrName: Table | string,
4✔
2426
        checkConstraints: TableCheck[],
4✔
2427
    ): Promise<void> {
4✔
2428
        const promises = checkConstraints.map((checkConstraint) =>
4✔
2429
            this.createCheckConstraint(tableOrName, checkConstraint),
4✔
2430
        )
4✔
2431
        await Promise.all(promises)
4✔
2432
    }
4✔
2433

26✔
2434
    /**
26✔
2435
     * Drops check constraint.
26✔
2436
     * @param tableOrName
26✔
2437
     * @param checkOrName
26✔
2438
     */
26✔
2439
    async dropCheckConstraint(
26✔
2440
        tableOrName: Table | string,
6✔
2441
        checkOrName: TableCheck | string,
6✔
2442
    ): Promise<void> {
6✔
2443
        const table = InstanceChecker.isTable(tableOrName)
6✔
2444
            ? tableOrName
6✔
2445
            : await this.getCachedTable(tableOrName)
6!
2446
        const checkConstraint = InstanceChecker.isTableCheck(checkOrName)
×
2447
            ? checkOrName
6✔
2448
            : table.checks.find((c) => c.name === checkOrName)
6!
2449
        if (!checkConstraint)
6✔
2450
            throw new TypeORMError(
6!
2451
                `Supplied check constraint was not found in table ${table.name}`,
×
2452
            )
×
2453

6✔
2454
        const up = this.dropCheckConstraintSql(table, checkConstraint)
6✔
2455
        const down = this.createCheckConstraintSql(table, checkConstraint)
6✔
2456
        await this.executeQueries(up, down)
6✔
2457
        table.removeCheckConstraint(checkConstraint)
6✔
2458
    }
6✔
2459

26✔
2460
    /**
26✔
2461
     * Drops check constraints.
26✔
2462
     * @param tableOrName
26✔
2463
     * @param checkConstraints
26✔
2464
     */
26✔
2465
    async dropCheckConstraints(
26✔
2466
        tableOrName: Table | string,
4✔
2467
        checkConstraints: TableCheck[],
4✔
2468
    ): Promise<void> {
4✔
2469
        const promises = checkConstraints.map((checkConstraint) =>
4✔
2470
            this.dropCheckConstraint(tableOrName, checkConstraint),
4✔
2471
        )
4✔
2472
        await Promise.all(promises)
4✔
2473
    }
4✔
2474

26✔
2475
    /**
26✔
2476
     * Creates a new exclusion constraint.
26✔
2477
     * @param tableOrName
26✔
2478
     * @param exclusionConstraint
26✔
2479
     */
26✔
2480
    async createExclusionConstraint(
26✔
2481
        tableOrName: Table | string,
×
2482
        exclusionConstraint: TableExclusion,
×
2483
    ): Promise<void> {
×
2484
        throw new TypeORMError(
×
2485
            `SqlServer does not support exclusion constraints.`,
×
2486
        )
×
2487
    }
×
2488

26✔
2489
    /**
26✔
2490
     * Creates a new exclusion constraints.
26✔
2491
     * @param tableOrName
26✔
2492
     * @param exclusionConstraints
26✔
2493
     */
26✔
2494
    async createExclusionConstraints(
26✔
2495
        tableOrName: Table | string,
×
2496
        exclusionConstraints: TableExclusion[],
×
2497
    ): Promise<void> {
×
2498
        throw new TypeORMError(
×
2499
            `SqlServer does not support exclusion constraints.`,
×
2500
        )
×
2501
    }
×
2502

26✔
2503
    /**
26✔
2504
     * Drops exclusion constraint.
26✔
2505
     * @param tableOrName
26✔
2506
     * @param exclusionOrName
26✔
2507
     */
26✔
2508
    async dropExclusionConstraint(
26✔
2509
        tableOrName: Table | string,
×
2510
        exclusionOrName: TableExclusion | string,
×
2511
    ): Promise<void> {
×
2512
        throw new TypeORMError(
×
2513
            `SqlServer does not support exclusion constraints.`,
×
2514
        )
×
2515
    }
×
2516

26✔
2517
    /**
26✔
2518
     * Drops exclusion constraints.
26✔
2519
     * @param tableOrName
26✔
2520
     * @param exclusionConstraints
26✔
2521
     */
26✔
2522
    async dropExclusionConstraints(
26✔
2523
        tableOrName: Table | string,
×
2524
        exclusionConstraints: TableExclusion[],
×
2525
    ): Promise<void> {
×
2526
        throw new TypeORMError(
×
2527
            `SqlServer does not support exclusion constraints.`,
×
2528
        )
×
2529
    }
×
2530

26✔
2531
    /**
26✔
2532
     * Creates a new foreign key.
26✔
2533
     * @param tableOrName
26✔
2534
     * @param foreignKey
26✔
2535
     */
26✔
2536
    async createForeignKey(
26✔
2537
        tableOrName: Table | string,
6,950✔
2538
        foreignKey: TableForeignKey,
6,950✔
2539
    ): Promise<void> {
6,950✔
2540
        const table = InstanceChecker.isTable(tableOrName)
6,950✔
2541
            ? tableOrName
6,950✔
2542
            : await this.getCachedTable(tableOrName)
6,950✔
2543
        const metadata = this.connection.hasMetadata(table.name)
10✔
2544
            ? this.connection.getMetadata(table.name)
6,950✔
2545
            : undefined
6,950✔
2546

6,950✔
2547
        if (
6,950✔
2548
            metadata &&
6,950✔
2549
            metadata.treeParentRelation &&
6,950✔
2550
            metadata.treeParentRelation!.isTreeParent &&
6,950✔
2551
            metadata.foreignKeys.find(
778✔
2552
                (foreignKey) => foreignKey.onDelete !== "NO ACTION",
778✔
2553
            )
6,950✔
2554
        )
6,950✔
2555
            throw new TypeORMError(
6,950!
2556
                "SqlServer does not support options in TreeParent.",
×
2557
            )
×
2558

6,950✔
2559
        // new FK may be passed without name. In this case we generate FK name manually.
6,950✔
2560
        if (!foreignKey.name)
6,950✔
2561
            foreignKey.name = this.connection.namingStrategy.foreignKeyName(
6,950✔
2562
                table,
2✔
2563
                foreignKey.columnNames,
2✔
2564
                this.getTablePath(foreignKey),
2✔
2565
                foreignKey.referencedColumnNames,
2✔
2566
            )
2✔
2567

6,950✔
2568
        const up = this.createForeignKeySql(table, foreignKey)
6,950✔
2569
        const down = this.dropForeignKeySql(table, foreignKey)
6,950✔
2570
        await this.executeQueries(up, down)
6,950✔
2571
        table.addForeignKey(foreignKey)
6,950✔
2572
    }
6,950✔
2573

26✔
2574
    /**
26✔
2575
     * Creates a new foreign keys.
26✔
2576
     * @param tableOrName
26✔
2577
     * @param foreignKeys
26✔
2578
     */
26✔
2579
    async createForeignKeys(
26✔
2580
        tableOrName: Table | string,
4,276✔
2581
        foreignKeys: TableForeignKey[],
4,276✔
2582
    ): Promise<void> {
4,276✔
2583
        const promises = foreignKeys.map((foreignKey) =>
4,276✔
2584
            this.createForeignKey(tableOrName, foreignKey),
4,276✔
2585
        )
4,276✔
2586
        await Promise.all(promises)
4,276✔
2587
    }
4,276✔
2588

26✔
2589
    /**
26✔
2590
     * Drops a foreign key from the table.
26✔
2591
     * @param tableOrName
26✔
2592
     * @param foreignKeyOrName
26✔
2593
     */
26✔
2594
    async dropForeignKey(
26✔
2595
        tableOrName: Table | string,
22✔
2596
        foreignKeyOrName: TableForeignKey | string,
22✔
2597
    ): Promise<void> {
22✔
2598
        const table = InstanceChecker.isTable(tableOrName)
22✔
2599
            ? tableOrName
22✔
2600
            : await this.getCachedTable(tableOrName)
22✔
2601
        const foreignKey = InstanceChecker.isTableForeignKey(foreignKeyOrName)
8✔
2602
            ? foreignKeyOrName
22✔
2603
            : table.foreignKeys.find((fk) => fk.name === foreignKeyOrName)
22!
2604
        if (!foreignKey)
22✔
2605
            throw new TypeORMError(
22!
2606
                `Supplied foreign key was not found in table ${table.name}`,
×
2607
            )
×
2608

22✔
2609
        if (!foreignKey.name) {
22!
2610
            foreignKey.name = this.connection.namingStrategy.foreignKeyName(
×
2611
                table,
×
2612
                foreignKey.columnNames,
×
2613
                this.getTablePath(foreignKey),
×
2614
                foreignKey.referencedColumnNames,
×
2615
            )
×
2616
        }
×
2617

22✔
2618
        const up = this.dropForeignKeySql(table, foreignKey)
22✔
2619
        const down = this.createForeignKeySql(table, foreignKey)
22✔
2620
        await this.executeQueries(up, down)
22✔
2621
        table.removeForeignKey(foreignKey)
22✔
2622
    }
22✔
2623

26✔
2624
    /**
26✔
2625
     * Drops a foreign keys from the table.
26✔
2626
     * @param tableOrName
26✔
2627
     * @param foreignKeys
26✔
2628
     */
26✔
2629
    async dropForeignKeys(
26✔
2630
        tableOrName: Table | string,
14✔
2631
        foreignKeys: TableForeignKey[],
14✔
2632
    ): Promise<void> {
14✔
2633
        const promises = foreignKeys.map((foreignKey) =>
14✔
2634
            this.dropForeignKey(tableOrName, foreignKey),
14✔
2635
        )
14✔
2636
        await Promise.all(promises)
14✔
2637
    }
14✔
2638

26✔
2639
    /**
26✔
2640
     * Creates a new index.
26✔
2641
     * @param tableOrName
26✔
2642
     * @param index
26✔
2643
     */
26✔
2644
    async createIndex(
26✔
2645
        tableOrName: Table | string,
28✔
2646
        index: TableIndex,
28✔
2647
    ): Promise<void> {
28✔
2648
        const table = InstanceChecker.isTable(tableOrName)
28✔
2649
            ? tableOrName
28✔
2650
            : await this.getCachedTable(tableOrName)
28✔
2651

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

28✔
2655
        const up = this.createIndexSql(table, index)
28✔
2656
        const down = this.dropIndexSql(table, index)
28✔
2657
        await this.executeQueries(up, down)
28✔
2658
        table.addIndex(index)
28✔
2659
    }
28✔
2660

26✔
2661
    /**
26✔
2662
     * Creates a new indices
26✔
2663
     * @param tableOrName
26✔
2664
     * @param indices
26✔
2665
     */
26✔
2666
    async createIndices(
26✔
2667
        tableOrName: Table | string,
14✔
2668
        indices: TableIndex[],
14✔
2669
    ): Promise<void> {
14✔
2670
        const promises = indices.map((index) =>
14✔
2671
            this.createIndex(tableOrName, index),
14✔
2672
        )
14✔
2673
        await Promise.all(promises)
14✔
2674
    }
14✔
2675

26✔
2676
    /**
26✔
2677
     * Drops an index.
26✔
2678
     * @param tableOrName
26✔
2679
     * @param indexOrName
26✔
2680
     */
26✔
2681
    async dropIndex(
26✔
2682
        tableOrName: Table | string,
32✔
2683
        indexOrName: TableIndex | string,
32✔
2684
    ): Promise<void> {
32✔
2685
        const table = InstanceChecker.isTable(tableOrName)
32✔
2686
            ? tableOrName
32✔
2687
            : await this.getCachedTable(tableOrName)
32✔
2688
        const index = InstanceChecker.isTableIndex(indexOrName)
10✔
2689
            ? indexOrName
32✔
2690
            : table.indices.find((i) => i.name === indexOrName)
32!
2691
        if (!index)
32✔
2692
            throw new TypeORMError(
32!
2693
                `Supplied index was not found in table ${table.name}`,
×
2694
            )
×
2695

32✔
2696
        // old index may be passed without name. In this case we generate index name manually.
32✔
2697
        if (!index.name) index.name = this.generateIndexName(table, index)
32✔
2698

32✔
2699
        const up = this.dropIndexSql(table, index)
32✔
2700
        const down = this.createIndexSql(table, index)
32✔
2701
        await this.executeQueries(up, down)
32✔
2702
        table.removeIndex(index)
32✔
2703
    }
32✔
2704

26✔
2705
    /**
26✔
2706
     * Drops an indices from the table.
26✔
2707
     * @param tableOrName
26✔
2708
     * @param indices
26✔
2709
     */
26✔
2710
    async dropIndices(
26✔
2711
        tableOrName: Table | string,
4✔
2712
        indices: TableIndex[],
4✔
2713
    ): Promise<void> {
4✔
2714
        const promises = indices.map((index) =>
4✔
2715
            this.dropIndex(tableOrName, index),
4✔
2716
        )
4✔
2717
        await Promise.all(promises)
4✔
2718
    }
4✔
2719

26✔
2720
    /**
26✔
2721
     * Clears all table contents.
26✔
2722
     * Note: this operation uses SQL's TRUNCATE query which cannot be reverted in transactions.
26✔
2723
     * @param tablePath
26✔
2724
     */
26✔
2725
    async clearTable(tablePath: string): Promise<void> {
26✔
2726
        await this.query(`TRUNCATE TABLE ${this.escapePath(tablePath)}`)
4✔
2727
    }
4✔
2728

26✔
2729
    /**
26✔
2730
     * Removes all tables from the currently connected database.
26✔
2731
     * @param database
26✔
2732
     */
26✔
2733
    async clearDatabase(database?: string): Promise<void> {
26✔
2734
        if (database) {
2,982✔
2735
            const isDatabaseExist = await this.hasDatabase(database)
2,982✔
2736
            if (!isDatabaseExist) return Promise.resolve()
2,982!
2737
        }
2,982✔
2738

2,982✔
2739
        const isAnotherTransactionActive = this.isTransactionActive
2,982✔
2740
        if (!isAnotherTransactionActive) await this.startTransaction()
2,982✔
2741
        try {
2,982✔
2742
            const allViewsSql = database
2,982✔
2743
                ? `SELECT * FROM "${database}"."INFORMATION_SCHEMA"."VIEWS"`
2,982✔
2744
                : `SELECT * FROM "INFORMATION_SCHEMA"."VIEWS"`
2,982!
2745
            const allViewsResults: ObjectLiteral[] =
2,982✔
2746
                await this.query(allViewsSql)
2,982✔
2747

2,982✔
2748
            await Promise.all(
2,982✔
2749
                allViewsResults.map((viewResult) => {
2,982✔
2750
                    // 'DROP VIEW' does not allow specifying the database name as a prefix to the object name.
16✔
2751
                    const dropTableSql = `DROP VIEW "${viewResult["TABLE_SCHEMA"]}"."${viewResult["TABLE_NAME"]}"`
16✔
2752
                    return this.query(dropTableSql)
16✔
2753
                }),
2,982✔
2754
            )
2,982✔
2755

2,982✔
2756
            const allTablesSql = database
2,982✔
2757
                ? `SELECT * FROM "${database}"."INFORMATION_SCHEMA"."TABLES" WHERE "TABLE_TYPE" = 'BASE TABLE'`
2,982✔
2758
                : `SELECT * FROM "INFORMATION_SCHEMA"."TABLES" WHERE "TABLE_TYPE" = 'BASE TABLE'`
2,982!
2759
            const allTablesResults: ObjectLiteral[] =
2,982✔
2760
                await this.query(allTablesSql)
2,982✔
2761

2,982✔
2762
            if (allTablesResults.length > 0) {
2,982✔
2763
                const tablesByCatalog: {
2,940✔
2764
                    [key: string]: {
2,940✔
2765
                        TABLE_NAME: string
2,940✔
2766
                        TABLE_SCHEMA: string
2,940✔
2767
                    }[]
2,940✔
2768
                } = allTablesResults.reduce(
2,940✔
2769
                    (c, { TABLE_CATALOG, TABLE_SCHEMA, TABLE_NAME }) => {
2,940✔
2770
                        c[TABLE_CATALOG] = c[TABLE_CATALOG] || []
10,456✔
2771
                        c[TABLE_CATALOG].push({ TABLE_SCHEMA, TABLE_NAME })
10,456✔
2772
                        return c
10,456✔
2773
                    },
2,940✔
2774
                    {},
2,940✔
2775
                )
2,940✔
2776

2,940✔
2777
                const foreignKeysSql = Object.entries(tablesByCatalog)
2,940✔
2778
                    .map(([TABLE_CATALOG, tables]) => {
2,940✔
2779
                        const conditions = tables
2,940✔
2780
                            .map(({ TABLE_SCHEMA, TABLE_NAME }) => {
2,940✔
2781
                                return `("fk"."referenced_object_id" = OBJECT_ID('"${TABLE_CATALOG}"."${TABLE_SCHEMA}"."${TABLE_NAME}"'))`
10,456✔
2782
                            })
2,940✔
2783
                            .join(" OR ")
2,940✔
2784

2,940✔
2785
                        return `
2,940✔
2786
                        SELECT DISTINCT '${TABLE_CATALOG}' AS                                              "TABLE_CATALOG",
2,940✔
2787
                                        OBJECT_SCHEMA_NAME("fk"."parent_object_id",
2,940✔
2788
                                                           DB_ID('${TABLE_CATALOG}')) AS                   "TABLE_SCHEMA",
2,940✔
2789
                                        OBJECT_NAME("fk"."parent_object_id", DB_ID('${TABLE_CATALOG}')) AS "TABLE_NAME",
2,940✔
2790
                                        "fk"."name" AS                                                     "CONSTRAINT_NAME"
2,940✔
2791
                        FROM "${TABLE_CATALOG}"."sys"."foreign_keys" AS "fk"
2,940✔
2792
                        WHERE (${conditions})
2,940✔
2793
                    `
2,940✔
2794
                    })
2,940✔
2795
                    .join(" UNION ALL ")
2,940✔
2796

2,940✔
2797
                const foreignKeys: {
2,940✔
2798
                    TABLE_CATALOG: string
2,940✔
2799
                    TABLE_SCHEMA: string
2,940✔
2800
                    TABLE_NAME: string
2,940✔
2801
                    CONSTRAINT_NAME: string
2,940✔
2802
                }[] = await this.query(foreignKeysSql)
2,940✔
2803

2,940✔
2804
                await Promise.all(
2,940✔
2805
                    foreignKeys.map(
2,940✔
2806
                        async ({
2,940✔
2807
                            TABLE_CATALOG,
6,916✔
2808
                            TABLE_SCHEMA,
6,916✔
2809
                            TABLE_NAME,
6,916✔
2810
                            CONSTRAINT_NAME,
6,916✔
2811
                        }) => {
6,916✔
2812
                            // Disable the constraint first.
6,916✔
2813
                            await this.query(
6,916✔
2814
                                `ALTER TABLE "${TABLE_CATALOG}"."${TABLE_SCHEMA}"."${TABLE_NAME}" ` +
6,916✔
2815
                                    `NOCHECK CONSTRAINT "${CONSTRAINT_NAME}"`,
6,916✔
2816
                            )
6,916✔
2817

6,916✔
2818
                            await this.query(
6,916✔
2819
                                `ALTER TABLE "${TABLE_CATALOG}"."${TABLE_SCHEMA}"."${TABLE_NAME}" ` +
6,916✔
2820
                                    `DROP CONSTRAINT "${CONSTRAINT_NAME}" -- FROM CLEAR`,
6,916✔
2821
                            )
6,916✔
2822
                        },
2,940✔
2823
                    ),
2,940✔
2824
                )
2,940✔
2825

2,940✔
2826
                await Promise.all(
2,940✔
2827
                    allTablesResults.map(async (tablesResult) => {
2,940✔
2828
                        if (tablesResult["TABLE_NAME"].startsWith("#")) {
10,456!
2829
                            // don't try to drop temporary tables
×
2830
                            return
×
2831
                        }
×
2832

10,456✔
2833
                        const dropTableSql = `DROP TABLE "${tablesResult["TABLE_CATALOG"]}"."${tablesResult["TABLE_SCHEMA"]}"."${tablesResult["TABLE_NAME"]}"`
10,456✔
2834
                        return this.query(dropTableSql)
10,456✔
2835
                    }),
2,940✔
2836
                )
2,940✔
2837
            }
2,940✔
2838

2,982✔
2839
            if (!isAnotherTransactionActive) await this.commitTransaction()
2,982✔
2840
        } catch (error) {
2,982!
2841
            try {
×
2842
                // we throw original error even if rollback thrown an error
×
2843
                if (!isAnotherTransactionActive)
×
2844
                    await this.rollbackTransaction()
×
2845
            } catch (rollbackError) {}
×
2846
            throw error
×
2847
        }
×
2848
    }
2,982✔
2849

26✔
2850
    // -------------------------------------------------------------------------
26✔
2851
    // Protected Methods
26✔
2852
    // -------------------------------------------------------------------------
26✔
2853

26✔
2854
    protected async loadViews(viewPaths?: string[]): Promise<View[]> {
26✔
2855
        const hasTable = await this.hasTable(this.getTypeormMetadataTableName())
3,094✔
2856
        if (!hasTable) {
3,094✔
2857
            return []
3,064✔
2858
        }
3,064✔
2859

30✔
2860
        if (!viewPaths) {
3,094!
2861
            viewPaths = []
×
2862
        }
×
2863

30✔
2864
        const currentSchema = await this.getCurrentSchema()
30✔
2865
        const currentDatabase = await this.getCurrentDatabase()
30✔
2866

30✔
2867
        const dbNames = viewPaths
30✔
2868
            .map((viewPath) => this.driver.parseTableName(viewPath).database)
30✔
2869
            .filter((database) => database)
30✔
2870

30✔
2871
        if (
30✔
2872
            this.driver.database &&
30✔
2873
            !dbNames.find((dbName) => dbName === this.driver.database)
30✔
2874
        )
3,094✔
2875
            dbNames.push(this.driver.database)
3,094✔
2876

30✔
2877
        const viewsCondition = viewPaths
30✔
2878
            .map((viewPath) => {
30✔
2879
                let { schema, tableName: name } =
22✔
2880
                    this.driver.parseTableName(viewPath)
22✔
2881

22✔
2882
                if (!schema) {
22!
2883
                    schema = currentSchema
×
2884
                }
×
2885
                return `("T"."SCHEMA" = '${schema}' AND "T"."NAME" = '${name}')`
22✔
2886
            })
30✔
2887
            .join(" OR ")
30✔
2888

30✔
2889
        const query = dbNames
30✔
2890
            .map((dbName) => {
30✔
2891
                return (
38✔
2892
                    `SELECT "T".*, "V"."CHECK_OPTION" FROM ${this.escapePath(
38✔
2893
                        this.getTypeormMetadataTableName(),
38✔
2894
                    )} "t" ` +
38✔
2895
                    `INNER JOIN "${dbName}"."INFORMATION_SCHEMA"."VIEWS" "V" ON "V"."TABLE_SCHEMA" = "T"."SCHEMA" AND "v"."TABLE_NAME" = "T"."NAME" WHERE "T"."TYPE" = '${
38✔
2896
                        MetadataTableType.VIEW
38✔
2897
                    }' ${viewsCondition ? `AND (${viewsCondition})` : ""}`
38✔
2898
                )
38✔
2899
            })
30✔
2900
            .join(" UNION ALL ")
30✔
2901

30✔
2902
        const dbViews = await this.query(query)
30✔
2903
        return dbViews.map((dbView: any) => {
30✔
2904
            const view = new View()
6✔
2905
            const db =
6✔
2906
                dbView["TABLE_CATALOG"] === currentDatabase
6✔
2907
                    ? undefined
6!
2908
                    : dbView["TABLE_CATALOG"]
6✔
2909
            const schema =
6✔
2910
                dbView["schema"] === currentSchema &&
6✔
2911
                !this.driver.options.schema
6✔
2912
                    ? undefined
6✔
2913
                    : dbView["schema"]
6!
2914
            view.database = dbView["TABLE_CATALOG"]
6✔
2915
            view.schema = dbView["schema"]
6✔
2916
            view.name = this.driver.buildTableName(dbView["name"], schema, db)
6✔
2917
            view.expression = dbView["value"]
6✔
2918
            return view
6✔
2919
        })
30✔
2920
    }
30✔
2921

26✔
2922
    /**
26✔
2923
     * Loads all tables (with given names) from the database and creates a Table from them.
26✔
2924
     * @param tableNames
26✔
2925
     */
26✔
2926
    protected async loadTables(tableNames?: string[]): Promise<Table[]> {
26✔
2927
        // if no tables given then no need to proceed
3,668✔
2928
        if (tableNames && tableNames.length === 0) {
3,668✔
2929
            return []
14✔
2930
        }
14✔
2931

3,654✔
2932
        const currentSchema = await this.getCurrentSchema()
3,654✔
2933
        const currentDatabase = await this.getCurrentDatabase()
3,654✔
2934

3,654✔
2935
        const dbTables: {
3,654✔
2936
            TABLE_CATALOG: string
3,654✔
2937
            TABLE_SCHEMA: string
3,654✔
2938
            TABLE_NAME: string
3,654✔
2939
        }[] = []
3,654✔
2940

3,654✔
2941
        if (!tableNames) {
3,668!
2942
            const databasesSql =
×
2943
                `SELECT DISTINCT "name" ` +
×
2944
                `FROM "master"."dbo"."sysdatabases" ` +
×
2945
                `WHERE "name" NOT IN ('master', 'model', 'msdb')`
×
2946
            const dbDatabases: { name: string }[] =
×
2947
                await this.query(databasesSql)
×
2948

×
2949
            const tablesSql = dbDatabases
×
2950
                .map(({ name }) => {
×
2951
                    return `
×
2952
                    SELECT DISTINCT
×
2953
                        "TABLE_CATALOG", "TABLE_SCHEMA", "TABLE_NAME"
×
2954
                    FROM "${name}"."INFORMATION_SCHEMA"."TABLES"
×
2955
                    WHERE
×
2956
                      "TABLE_TYPE" = 'BASE TABLE'
×
2957
                      AND
×
2958
                      "TABLE_CATALOG" = '${name}'
×
2959
                      AND
×
2960
                      ISNULL(Objectproperty(Object_id("TABLE_CATALOG" + '.' + "TABLE_SCHEMA" + '.' + "TABLE_NAME"), 'IsMSShipped'), 0) = 0
×
2961
                `
×
2962
                })
×
2963
                .join(" UNION ALL ")
×
2964

×
2965
            dbTables.push(...(await this.query(tablesSql)))
×
2966
        } else {
3,668✔
2967
            const tableNamesByCatalog = tableNames
3,654✔
2968
                .map((tableName) => this.driver.parseTableName(tableName))
3,654✔
2969
                .reduce(
3,654✔
2970
                    (c, { database, ...other }) => {
3,654✔
2971
                        database = database || currentDatabase
11,454!
2972
                        c[database] = c[database] || []
11,454✔
2973
                        c[database].push({
11,454✔
2974
                            schema: other.schema || currentSchema,
11,454!
2975
                            tableName: other.tableName,
11,454✔
2976
                        })
11,454✔
2977
                        return c
11,454✔
2978
                    },
3,654✔
2979
                    {} as {
3,654✔
2980
                        [key: string]: { schema: string; tableName: string }[]
3,654✔
2981
                    },
3,654✔
2982
                )
3,654✔
2983

3,654✔
2984
            const tablesSql = Object.entries(tableNamesByCatalog)
3,654✔
2985
                .map(([database, tables]) => {
3,654✔
2986
                    const tablesCondition = tables
3,662✔
2987
                        .map(({ schema, tableName }) => {
3,662✔
2988
                            return `("TABLE_SCHEMA" = '${schema}' AND "TABLE_NAME" = '${tableName}')`
11,454✔
2989
                        })
3,662✔
2990
                        .join(" OR ")
3,662✔
2991

3,662✔
2992
                    return `
3,662✔
2993
                    SELECT DISTINCT
3,662✔
2994
                        "TABLE_CATALOG", "TABLE_SCHEMA", "TABLE_NAME"
3,662✔
2995
                    FROM "${database}"."INFORMATION_SCHEMA"."TABLES"
3,662✔
2996
                    WHERE
3,662✔
2997
                          "TABLE_TYPE" = 'BASE TABLE' AND
3,662✔
2998
                          "TABLE_CATALOG" = '${database}' AND
3,662✔
2999
                          ${tablesCondition}
3,662✔
3000
                `
3,662✔
3001
                })
3,654✔
3002
                .join(" UNION ALL ")
3,654✔
3003

3,654✔
3004
            dbTables.push(...(await this.query(tablesSql)))
3,654✔
3005
        }
3,654✔
3006

3,654✔
3007
        // if tables were not found in the db, no need to proceed
3,654✔
3008
        if (dbTables.length === 0) {
3,668✔
3009
            return []
2,988✔
3010
        }
2,988✔
3011

666✔
3012
        const dbTablesByCatalog = dbTables.reduce(
666✔
3013
            (c, { TABLE_CATALOG, ...other }) => {
666✔
3014
                c[TABLE_CATALOG] = c[TABLE_CATALOG] || []
990✔
3015
                c[TABLE_CATALOG].push(other)
990✔
3016
                return c
990✔
3017
            },
666✔
3018
            {} as {
666✔
3019
                [key: string]: { TABLE_NAME: string; TABLE_SCHEMA: string }[]
666✔
3020
            },
666✔
3021
        )
666✔
3022

666✔
3023
        const columnsSql = Object.entries(dbTablesByCatalog)
666✔
3024
            .map(([TABLE_CATALOG, tables]) => {
666✔
3025
                const condition = tables
666✔
3026
                    .map(
666✔
3027
                        ({ TABLE_SCHEMA, TABLE_NAME }) =>
666✔
3028
                            `("TABLE_SCHEMA" = '${TABLE_SCHEMA}' AND "TABLE_NAME" = '${TABLE_NAME}')`,
666✔
3029
                    )
666✔
3030
                    .join("OR")
666✔
3031

666✔
3032
                return (
666✔
3033
                    `SELECT "COLUMNS".*, "cc"."is_persisted", "cc"."definition" ` +
666✔
3034
                    `FROM "${TABLE_CATALOG}"."INFORMATION_SCHEMA"."COLUMNS" ` +
666✔
3035
                    `LEFT JOIN "sys"."computed_columns" "cc" ON COL_NAME("cc"."object_id", "cc"."column_id") = "column_name" ` +
666✔
3036
                    `WHERE (${condition})`
666✔
3037
                )
666✔
3038
            })
666✔
3039
            .join(" UNION ALL ")
666✔
3040

666✔
3041
        const constraintsSql = Object.entries(dbTablesByCatalog)
666✔
3042
            .map(([TABLE_CATALOG, tables]) => {
666✔
3043
                const conditions = tables
666✔
3044
                    .map(
666✔
3045
                        ({ TABLE_NAME, TABLE_SCHEMA }) =>
666✔
3046
                            `("columnUsages"."TABLE_SCHEMA" = '${TABLE_SCHEMA}' AND "columnUsages"."TABLE_NAME" = '${TABLE_NAME}')`,
666✔
3047
                    )
666✔
3048
                    .join(" OR ")
666✔
3049

666✔
3050
                return (
666✔
3051
                    `SELECT "columnUsages".*, "tableConstraints"."CONSTRAINT_TYPE", "chk"."definition" ` +
666✔
3052
                    `FROM "${TABLE_CATALOG}"."INFORMATION_SCHEMA"."CONSTRAINT_COLUMN_USAGE" "columnUsages" ` +
666✔
3053
                    `INNER JOIN "${TABLE_CATALOG}"."INFORMATION_SCHEMA"."TABLE_CONSTRAINTS" "tableConstraints" ` +
666✔
3054
                    `ON ` +
666✔
3055
                    `"tableConstraints"."CONSTRAINT_NAME" = "columnUsages"."CONSTRAINT_NAME" AND ` +
666✔
3056
                    `"tableConstraints"."TABLE_SCHEMA" = "columnUsages"."TABLE_SCHEMA" AND ` +
666✔
3057
                    `"tableConstraints"."TABLE_NAME" = "columnUsages"."TABLE_NAME" ` +
666✔
3058
                    `LEFT JOIN "${TABLE_CATALOG}"."sys"."check_constraints" "chk" ` +
666✔
3059
                    `ON ` +
666✔
3060
                    `"chk"."object_id" = OBJECT_ID("columnUsages"."TABLE_CATALOG" + '.' + "columnUsages"."TABLE_SCHEMA" + '.' + "columnUsages"."CONSTRAINT_NAME") ` +
666✔
3061
                    `WHERE ` +
666✔
3062
                    `(${conditions}) AND ` +
666✔
3063
                    `"tableConstraints"."CONSTRAINT_TYPE" IN ('PRIMARY KEY', 'UNIQUE', 'CHECK')`
666✔
3064
                )
666✔
3065
            })
666✔
3066
            .join(" UNION ALL ")
666✔
3067

666✔
3068
        const foreignKeysSql = Object.entries(dbTablesByCatalog)
666✔
3069
            .map(([TABLE_CATALOG, tables]) => {
666✔
3070
                const conditions = tables
666✔
3071
                    .map(
666✔
3072
                        ({ TABLE_NAME, TABLE_SCHEMA }) =>
666✔
3073
                            `("s1"."name" = '${TABLE_SCHEMA}' AND "t1"."name" = '${TABLE_NAME}')`,
666✔
3074
                    )
666✔
3075
                    .join(" OR ")
666✔
3076

666✔
3077
                return (
666✔
3078
                    `SELECT "fk"."name" AS "FK_NAME", '${TABLE_CATALOG}' AS "TABLE_CATALOG", "s1"."name" AS "TABLE_SCHEMA", "t1"."name" AS "TABLE_NAME", ` +
666✔
3079
                    `"col1"."name" AS "COLUMN_NAME", "s2"."name" AS "REF_SCHEMA", "t2"."name" AS "REF_TABLE", "col2"."name" AS "REF_COLUMN", ` +
666✔
3080
                    `"fk"."delete_referential_action_desc" AS "ON_DELETE", "fk"."update_referential_action_desc" AS "ON_UPDATE" ` +
666✔
3081
                    `FROM "${TABLE_CATALOG}"."sys"."foreign_keys" "fk" ` +
666✔
3082
                    `INNER JOIN "${TABLE_CATALOG}"."sys"."foreign_key_columns" "fkc" ON "fkc"."constraint_object_id" = "fk"."object_id" ` +
666✔
3083
                    `INNER JOIN "${TABLE_CATALOG}"."sys"."tables" "t1" ON "t1"."object_id" = "fk"."parent_object_id" ` +
666✔
3084
                    `INNER JOIN "${TABLE_CATALOG}"."sys"."schemas" "s1" ON "s1"."schema_id" = "t1"."schema_id" ` +
666✔
3085
                    `INNER JOIN "${TABLE_CATALOG}"."sys"."tables" "t2" ON "t2"."object_id" = "fk"."referenced_object_id" ` +
666✔
3086
                    `INNER JOIN "${TABLE_CATALOG}"."sys"."schemas" "s2" ON "s2"."schema_id" = "t2"."schema_id" ` +
666✔
3087
                    `INNER JOIN "${TABLE_CATALOG}"."sys"."columns" "col1" ON "col1"."column_id" = "fkc"."parent_column_id" AND "col1"."object_id" = "fk"."parent_object_id" ` +
666✔
3088
                    `INNER JOIN "${TABLE_CATALOG}"."sys"."columns" "col2" ON "col2"."column_id" = "fkc"."referenced_column_id" AND "col2"."object_id" = "fk"."referenced_object_id" ` +
666✔
3089
                    `WHERE (${conditions})`
666✔
3090
                )
666✔
3091
            })
666✔
3092
            .join(" UNION ALL ")
666✔
3093

666✔
3094
        const identityColumnsSql = Object.entries(dbTablesByCatalog)
666✔
3095
            .map(([TABLE_CATALOG, tables]) => {
666✔
3096
                const conditions = tables
666✔
3097
                    .map(
666✔
3098
                        ({ TABLE_NAME, TABLE_SCHEMA }) =>
666✔
3099
                            `("TABLE_SCHEMA" = '${TABLE_SCHEMA}' AND "TABLE_NAME" = '${TABLE_NAME}')`,
666✔
3100
                    )
666✔
3101
                    .join(" OR ")
666✔
3102

666✔
3103
                return (
666✔
3104
                    `SELECT "TABLE_CATALOG", "TABLE_SCHEMA", "COLUMN_NAME", "TABLE_NAME" ` +
666✔
3105
                    `FROM "${TABLE_CATALOG}"."INFORMATION_SCHEMA"."COLUMNS" ` +
666✔
3106
                    `WHERE ` +
666✔
3107
                    `EXISTS(SELECT 1 FROM "${TABLE_CATALOG}"."sys"."columns" "S" WHERE OBJECT_ID("TABLE_CATALOG" + '.' + "TABLE_SCHEMA" + '.' + "TABLE_NAME") = "S"."OBJECT_ID" AND "COLUMN_NAME" = "S"."NAME" AND "S"."is_identity" = 1) AND ` +
666✔
3108
                    `(${conditions})`
666✔
3109
                )
666✔
3110
            })
666✔
3111
            .join(" UNION ALL ")
666✔
3112

666✔
3113
        const dbCollationsSql = `SELECT "NAME", "COLLATION_NAME" FROM "sys"."databases"`
666✔
3114

666✔
3115
        const indicesSql = Object.entries(dbTablesByCatalog)
666✔
3116
            .map(([TABLE_CATALOG, tables]) => {
666✔
3117
                const conditions = tables
666✔
3118
                    .map(
666✔
3119
                        ({ TABLE_NAME, TABLE_SCHEMA }) =>
666✔
3120
                            `("s"."name" = '${TABLE_SCHEMA}' AND "t"."name" = '${TABLE_NAME}')`,
666✔
3121
                    )
666✔
3122
                    .join(" OR ")
666✔
3123

666✔
3124
                return (
666✔
3125
                    `SELECT '${TABLE_CATALOG}' AS "TABLE_CATALOG", "s"."name" AS "TABLE_SCHEMA", "t"."name" AS "TABLE_NAME", ` +
666✔
3126
                    `"ind"."name" AS "INDEX_NAME", "col"."name" AS "COLUMN_NAME", "ind"."is_unique" AS "IS_UNIQUE", "ind"."filter_definition" as "CONDITION" ` +
666✔
3127
                    `FROM "${TABLE_CATALOG}"."sys"."indexes" "ind" ` +
666✔
3128
                    `INNER JOIN "${TABLE_CATALOG}"."sys"."index_columns" "ic" ON "ic"."object_id" = "ind"."object_id" AND "ic"."index_id" = "ind"."index_id" ` +
666✔
3129
                    `INNER JOIN "${TABLE_CATALOG}"."sys"."columns" "col" ON "col"."object_id" = "ic"."object_id" AND "col"."column_id" = "ic"."column_id" ` +
666✔
3130
                    `INNER JOIN "${TABLE_CATALOG}"."sys"."tables" "t" ON "t"."object_id" = "ind"."object_id" ` +
666✔
3131
                    `INNER JOIN "${TABLE_CATALOG}"."sys"."schemas" "s" ON "s"."schema_id" = "t"."schema_id" ` +
666✔
3132
                    `WHERE ` +
666✔
3133
                    `"ind"."is_primary_key" = 0 AND "ind"."is_unique_constraint" = 0 AND "t"."is_ms_shipped" = 0 AND ` +
666✔
3134
                    `(${conditions})`
666✔
3135
                )
666✔
3136
            })
666✔
3137
            .join(" UNION ALL ")
666✔
3138

666✔
3139
        const [
666✔
3140
            dbColumns,
666✔
3141
            dbConstraints,
666✔
3142
            dbForeignKeys,
666✔
3143
            dbIdentityColumns,
666✔
3144
            dbCollations,
666✔
3145
            dbIndices,
666✔
3146
        ]: ObjectLiteral[][] = await Promise.all([
666✔
3147
            this.query(columnsSql),
666✔
3148
            this.query(constraintsSql),
666✔
3149
            this.query(foreignKeysSql),
666✔
3150
            this.query(identityColumnsSql),
666✔
3151
            this.query(dbCollationsSql),
666✔
3152
            this.query(indicesSql),
666✔
3153
        ])
666✔
3154

666✔
3155
        // create table schemas for loaded tables
666✔
3156
        return await Promise.all(
666✔
3157
            dbTables.map(async (dbTable) => {
666✔
3158
                const table = new Table()
990✔
3159

990✔
3160
                const getSchemaFromKey = (dbObject: any, key: string) => {
990✔
3161
                    return dbObject[key] === currentSchema &&
1,328✔
3162
                        (!this.driver.options.schema ||
1,238✔
3163
                            this.driver.options.schema === currentSchema)
1,238✔
3164
                        ? undefined
1,328✔
3165
                        : dbObject[key]
1,328✔
3166
                }
1,328✔
3167

990✔
3168
                // We do not need to join schema and database names, when db or schema is by default.
990✔
3169
                const db =
990✔
3170
                    dbTable["TABLE_CATALOG"] === currentDatabase
990✔
3171
                        ? undefined
990✔
3172
                        : dbTable["TABLE_CATALOG"]
990✔
3173
                const schema = getSchemaFromKey(dbTable, "TABLE_SCHEMA")
990✔
3174
                table.database = dbTable["TABLE_CATALOG"]
990✔
3175
                table.schema = dbTable["TABLE_SCHEMA"]
990✔
3176
                table.name = this.driver.buildTableName(
990✔
3177
                    dbTable["TABLE_NAME"],
990✔
3178
                    schema,
990✔
3179
                    db,
990✔
3180
                )
990✔
3181

990✔
3182
                const defaultCollation = dbCollations.find(
990✔
3183
                    (dbCollation) =>
990✔
3184
                        dbCollation["NAME"] === dbTable["TABLE_CATALOG"],
990✔
3185
                )!
990✔
3186

990✔
3187
                // create columns from the loaded columns
990✔
3188
                table.columns = await Promise.all(
990✔
3189
                    dbColumns
990✔
3190
                        .filter(
990✔
3191
                            (dbColumn) =>
990✔
3192
                                dbColumn["TABLE_NAME"] ===
10,700✔
3193
                                    dbTable["TABLE_NAME"] &&
10,700✔
3194
                                dbColumn["TABLE_SCHEMA"] ===
3,546✔
3195
                                    dbTable["TABLE_SCHEMA"] &&
10,700✔
3196
                                dbColumn["TABLE_CATALOG"] ===
3,546✔
3197
                                    dbTable["TABLE_CATALOG"],
990✔
3198
                        )
990✔
3199
                        .map(async (dbColumn) => {
990✔
3200
                            const columnConstraints = dbConstraints.filter(
3,546✔
3201
                                (dbConstraint) =>
3,546✔
3202
                                    dbConstraint["TABLE_NAME"] ===
18,730✔
3203
                                        dbColumn["TABLE_NAME"] &&
18,730✔
3204
                                    dbConstraint["TABLE_SCHEMA"] ===
7,836✔
3205
                                        dbColumn["TABLE_SCHEMA"] &&
18,730✔
3206
                                    dbConstraint["TABLE_CATALOG"] ===
7,836✔
3207
                                        dbColumn["TABLE_CATALOG"] &&
18,730✔
3208
                                    dbConstraint["COLUMN_NAME"] ===
7,836✔
3209
                                        dbColumn["COLUMN_NAME"],
3,546✔
3210
                            )
3,546✔
3211

3,546✔
3212
                            const uniqueConstraints = columnConstraints.filter(
3,546✔
3213
                                (constraint) =>
3,546✔
3214
                                    constraint["CONSTRAINT_TYPE"] === "UNIQUE",
3,546✔
3215
                            )
3,546✔
3216
                            const isConstraintComposite =
3,546✔
3217
                                uniqueConstraints.every((uniqueConstraint) => {
3,546✔
3218
                                    return dbConstraints.some(
590✔
3219
                                        (dbConstraint) =>
590✔
3220
                                            dbConstraint["CONSTRAINT_TYPE"] ===
2,632✔
3221
                                                "UNIQUE" &&
2,632✔
3222
                                            dbConstraint["CONSTRAINT_NAME"] ===
1,216✔
3223
                                                uniqueConstraint[
1,216✔
3224
                                                    "CONSTRAINT_NAME"
1,216✔
3225
                                                ] &&
2,632✔
3226
                                            dbConstraint["TABLE_SCHEMA"] ===
762✔
3227
                                                dbColumn["TABLE_SCHEMA"] &&
2,632✔
3228
                                            dbConstraint["TABLE_CATALOG"] ===
762✔
3229
                                                dbColumn["TABLE_CATALOG"] &&
2,632✔
3230
                                            dbConstraint["COLUMN_NAME"] !==
762✔
3231
                                                dbColumn["COLUMN_NAME"],
590✔
3232
                                    )
590✔
3233
                                })
3,546✔
3234

3,546✔
3235
                            const isGenerated = !!dbIdentityColumns.find(
3,546✔
3236
                                (column) =>
3,546✔
3237
                                    column["TABLE_NAME"] ===
5,696✔
3238
                                        dbColumn["TABLE_NAME"] &&
5,696✔
3239
                                    column["TABLE_SCHEMA"] ===
1,770✔
3240
                                        dbColumn["TABLE_SCHEMA"] &&
5,696✔
3241
                                    column["TABLE_CATALOG"] ===
1,770✔
3242
                                        dbColumn["TABLE_CATALOG"] &&
5,696✔
3243
                                    column["COLUMN_NAME"] ===
1,770✔
3244
                                        dbColumn["COLUMN_NAME"],
3,546✔
3245
                            )
3,546✔
3246

3,546✔
3247
                            const tableColumn = new TableColumn()
3,546✔
3248
                            tableColumn.name = dbColumn["COLUMN_NAME"]
3,546✔
3249
                            tableColumn.type =
3,546✔
3250
                                dbColumn["DATA_TYPE"].toLowerCase()
3,546✔
3251

3,546✔
3252
                            // check only columns that have length property
3,546✔
3253
                            if (
3,546✔
3254
                                this.driver.withLengthColumnTypes.indexOf(
3,546✔
3255
                                    tableColumn.type as ColumnType,
3,546✔
3256
                                ) !== -1 &&
3,546✔
3257
                                dbColumn["CHARACTER_MAXIMUM_LENGTH"]
1,928✔
3258
                            ) {
3,546✔
3259
                                const length =
1,928✔
3260
                                    dbColumn[
1,928✔
3261
                                        "CHARACTER_MAXIMUM_LENGTH"
1,928✔
3262
                                    ].toString()
1,928✔
3263
                                if (length === "-1") {
1,928✔
3264
                                    tableColumn.length = "MAX"
8✔
3265
                                } else {
1,928✔
3266
                                    if (tableColumn.type === "vector") {
1,920✔
3267
                                        const len = +length
2✔
3268
                                        // NOTE: real returned length is (N*4 + 8) where N is desired dimensions
2✔
3269
                                        if (!Number.isNaN(len)) {
2✔
3270
                                            tableColumn.length = String(
2✔
3271
                                                (len - 8) / 4,
2✔
3272
                                            )
2✔
3273
                                        }
2✔
3274
                                    } else {
1,920✔
3275
                                        tableColumn.length =
1,918✔
3276
                                            !this.isDefaultColumnLength(
1,918✔
3277
                                                table,
1,918✔
3278
                                                tableColumn,
1,918✔
3279
                                                length,
1,918✔
3280
                                            )
1,918✔
3281
                                                ? length
1,918✔
3282
                                                : ""
1,918✔
3283
                                    }
1,918✔
3284
                                }
1,920✔
3285
                            }
1,928✔
3286

3,546✔
3287
                            if (
3,546✔
3288
                                tableColumn.type === "decimal" ||
3,546✔
3289
                                tableColumn.type === "numeric"
3,536✔
3290
                            ) {
3,546✔
3291
                                if (
14✔
3292
                                    dbColumn["NUMERIC_PRECISION"] !== null &&
14✔
3293
                                    !this.isDefaultColumnPrecision(
14✔
3294
                                        table,
14✔
3295
                                        tableColumn,
14✔
3296
                                        dbColumn["NUMERIC_PRECISION"],
14✔
3297
                                    )
14✔
3298
                                )
14✔
3299
                                    tableColumn.precision =
14✔
3300
                                        dbColumn["NUMERIC_PRECISION"]
8✔
3301
                                if (
14✔
3302
                                    dbColumn["NUMERIC_SCALE"] !== null &&
14✔
3303
                                    !this.isDefaultColumnScale(
14✔
3304
                                        table,
14✔
3305
                                        tableColumn,
14✔
3306
                                        dbColumn["NUMERIC_SCALE"],
14✔
3307
                                    )
14✔
3308
                                )
14✔
3309
                                    tableColumn.scale =
14✔
3310
                                        dbColumn["NUMERIC_SCALE"]
8✔
3311
                            }
14✔
3312

3,546✔
3313
                            if (tableColumn.type === "nvarchar") {
3,546✔
3314
                                // Check if this is an enum
1,594✔
3315
                                const columnCheckConstraints =
1,594✔
3316
                                    columnConstraints.filter(
1,594✔
3317
                                        (constraint) =>
1,594✔
3318
                                            constraint["CONSTRAINT_TYPE"] ===
518✔
3319
                                            "CHECK",
1,594✔
3320
                                    )
1,594✔
3321
                                if (columnCheckConstraints.length) {
1,594✔
3322
                                    // const isEnumRegexp = new RegExp("^\\(\\[" + tableColumn.name + "\\]='[^']+'(?: OR \\[" + tableColumn.name + "\\]='[^']+')*\\)$");
22✔
3323
                                    for (const checkConstraint of columnCheckConstraints) {
22✔
3324
                                        if (
22✔
3325
                                            this.isEnumCheckConstraint(
22✔
3326
                                                checkConstraint[
22✔
3327
                                                    "CONSTRAINT_NAME"
22✔
3328
                                                ],
22✔
3329
                                            )
22✔
3330
                                        ) {
22✔
3331
                                            // This is an enum constraint, make column into an enum
10✔
3332
                                            tableColumn.enum = []
10✔
3333
                                            const enumValueRegexp = new RegExp(
10✔
3334
                                                "\\[" +
10✔
3335
                                                    tableColumn.name +
10✔
3336
                                                    "\\]='([^']+)'",
10✔
3337
                                                "g",
10✔
3338
                                            )
10✔
3339
                                            let result
10✔
3340
                                            while (
10✔
3341
                                                (result = enumValueRegexp.exec(
10✔
3342
                                                    checkConstraint[
10✔
3343
                                                        "definition"
10✔
3344
                                                    ],
10✔
3345
                                                )) !== null
10✔
3346
                                            ) {
10✔
3347
                                                tableColumn.enum.unshift(
26✔
3348
                                                    result[1],
26✔
3349
                                                )
26✔
3350
                                            }
26✔
3351
                                            // Skip other column constraints
10✔
3352
                                            break
10✔
3353
                                        }
10✔
3354
                                    }
22✔
3355
                                }
22✔
3356
                            }
1,594✔
3357

3,546✔
3358
                            const primaryConstraint = columnConstraints.find(
3,546✔
3359
                                (constraint) =>
3,546✔
3360
                                    constraint["CONSTRAINT_TYPE"] ===
1,796✔
3361
                                    "PRIMARY KEY",
3,546✔
3362
                            )
3,546✔
3363
                            if (primaryConstraint) {
3,546✔
3364
                                tableColumn.isPrimary = true
1,028✔
3365
                                // find another columns involved in primary key constraint
1,028✔
3366
                                const anotherPrimaryConstraints =
1,028✔
3367
                                    dbConstraints.filter(
1,028✔
3368
                                        (constraint) =>
1,028✔
3369
                                            constraint["TABLE_NAME"] ===
5,468✔
3370
                                                dbColumn["TABLE_NAME"] &&
5,468✔
3371
                                            constraint["TABLE_SCHEMA"] ===
1,930✔
3372
                                                dbColumn["TABLE_SCHEMA"] &&
5,468✔
3373
                                            constraint["TABLE_CATALOG"] ===
1,930✔
3374
                                                dbColumn["TABLE_CATALOG"] &&
5,468✔
3375
                                            constraint["COLUMN_NAME"] !==
1,930✔
3376
                                                dbColumn["COLUMN_NAME"] &&
5,468✔
3377
                                            constraint["CONSTRAINT_TYPE"] ===
882✔
3378
                                                "PRIMARY KEY",
1,028✔
3379
                                    )
1,028✔
3380

1,028✔
3381
                                // collect all column names
1,028✔
3382
                                const columnNames =
1,028✔
3383
                                    anotherPrimaryConstraints.map(
1,028✔
3384
                                        (constraint) =>
1,028✔
3385
                                            constraint["COLUMN_NAME"],
1,028✔
3386
                                    )
1,028✔
3387
                                columnNames.push(dbColumn["COLUMN_NAME"])
1,028✔
3388

1,028✔
3389
                                // build default primary key constraint name
1,028✔
3390
                                const pkName =
1,028✔
3391
                                    this.connection.namingStrategy.primaryKeyName(
1,028✔
3392
                                        table,
1,028✔
3393
                                        columnNames,
1,028✔
3394
                                    )
1,028✔
3395

1,028✔
3396
                                // if primary key has user-defined constraint name, write it in table column
1,028✔
3397
                                if (
1,028✔
3398
                                    primaryConstraint["CONSTRAINT_NAME"] !==
1,028✔
3399
                                    pkName
1,028✔
3400
                                ) {
1,028✔
3401
                                    tableColumn.primaryKeyConstraintName =
52✔
3402
                                        primaryConstraint["CONSTRAINT_NAME"]
52✔
3403
                                }
52✔
3404
                            }
1,028✔
3405

3,546✔
3406
                            tableColumn.default =
3,546✔
3407
                                dbColumn["COLUMN_DEFAULT"] !== null &&
3,546✔
3408
                                dbColumn["COLUMN_DEFAULT"] !== undefined
212✔
3409
                                    ? this.removeParenthesisFromDefault(
3,546✔
3410
                                          dbColumn["COLUMN_DEFAULT"],
212✔
3411
                                      )
3,546✔
3412
                                    : undefined
3,546✔
3413
                            tableColumn.isNullable =
3,546✔
3414
                                dbColumn["IS_NULLABLE"] === "YES"
3,546✔
3415
                            tableColumn.isUnique =
3,546✔
3416
                                uniqueConstraints.length > 0 &&
3,546✔
3417
                                !isConstraintComposite
590✔
3418
                            tableColumn.isGenerated = isGenerated
3,546✔
3419
                            if (isGenerated)
3,546✔
3420
                                tableColumn.generationStrategy = "increment"
3,546✔
3421
                            if (tableColumn.default === "newsequentialid()") {
3,546✔
3422
                                tableColumn.isGenerated = true
14✔
3423
                                tableColumn.generationStrategy = "uuid"
14✔
3424
                                tableColumn.default = undefined
14✔
3425
                            }
14✔
3426

3,546✔
3427
                            // todo: unable to get default charset
3,546✔
3428
                            // tableColumn.charset = dbColumn["CHARACTER_SET_NAME"];
3,546✔
3429
                            if (dbColumn["COLLATION_NAME"])
3,546✔
3430
                                tableColumn.collation =
3,546✔
3431
                                    dbColumn["COLLATION_NAME"] ===
1,880✔
3432
                                    defaultCollation["COLLATION_NAME"]
1,880✔
3433
                                        ? undefined
1,880✔
3434
                                        : dbColumn["COLLATION_NAME"]
1,880✔
3435

3,546✔
3436
                            if (
3,546✔
3437
                                tableColumn.type === "datetime2" ||
3,546✔
3438
                                tableColumn.type === "time" ||
3,546✔
3439
                                tableColumn.type === "datetimeoffset"
3,518✔
3440
                            ) {
3,546✔
3441
                                tableColumn.precision =
32✔
3442
                                    !this.isDefaultColumnPrecision(
32✔
3443
                                        table,
32✔
3444
                                        tableColumn,
32✔
3445
                                        dbColumn["DATETIME_PRECISION"],
32✔
3446
                                    )
32✔
3447
                                        ? dbColumn["DATETIME_PRECISION"]
32✔
3448
                                        : undefined
32✔
3449
                            }
32✔
3450

3,546✔
3451
                            if (
3,546✔
3452
                                dbColumn["is_persisted"] !== null &&
3,546✔
3453
                                dbColumn["is_persisted"] !== undefined &&
3,546✔
3454
                                dbColumn["definition"]
94✔
3455
                            ) {
3,546✔
3456
                                tableColumn.generatedType =
94✔
3457
                                    dbColumn["is_persisted"] === true
94✔
3458
                                        ? "STORED"
94✔
3459
                                        : "VIRTUAL"
94✔
3460
                                // We cannot relay on information_schema.columns.generation_expression, because it is formatted different.
94✔
3461
                                const asExpressionQuery =
94✔
3462
                                    this.selectTypeormMetadataSql({
94✔
3463
                                        database: dbTable["TABLE_CATALOG"],
94✔
3464
                                        schema: dbTable["TABLE_SCHEMA"],
94✔
3465
                                        table: dbTable["TABLE_NAME"],
94✔
3466
                                        type: MetadataTableType.GENERATED_COLUMN,
94✔
3467
                                        name: tableColumn.name,
94✔
3468
                                    })
94✔
3469

94✔
3470
                                const results = await this.query(
94✔
3471
                                    asExpressionQuery.query,
94✔
3472
                                    asExpressionQuery.parameters,
94✔
3473
                                )
94✔
3474
                                if (results[0] && results[0].value) {
94✔
3475
                                    tableColumn.asExpression = results[0].value
94✔
3476
                                } else {
94!
3477
                                    tableColumn.asExpression = ""
×
3478
                                }
×
3479
                            }
94✔
3480

3,546✔
3481
                            return tableColumn
3,546✔
3482
                        }),
990✔
3483
                )
990✔
3484

990✔
3485
                // find unique constraints of table, group them by constraint name and build TableUnique.
990✔
3486
                const tableUniqueConstraints = OrmUtils.uniq(
990✔
3487
                    dbConstraints.filter(
990✔
3488
                        (dbConstraint) =>
990✔
3489
                            dbConstraint["TABLE_NAME"] ===
5,330✔
3490
                                dbTable["TABLE_NAME"] &&
5,330✔
3491
                            dbConstraint["TABLE_SCHEMA"] ===
1,816✔
3492
                                dbTable["TABLE_SCHEMA"] &&
5,330✔
3493
                            dbConstraint["TABLE_CATALOG"] ===
1,816✔
3494
                                dbTable["TABLE_CATALOG"] &&
5,330✔
3495
                            dbConstraint["CONSTRAINT_TYPE"] === "UNIQUE",
990✔
3496
                    ),
990✔
3497
                    (dbConstraint) => dbConstraint["CONSTRAINT_NAME"],
990✔
3498
                )
990✔
3499

990✔
3500
                table.uniques = tableUniqueConstraints.map((constraint) => {
990✔
3501
                    const uniques = dbConstraints.filter(
414✔
3502
                        (dbC) =>
414✔
3503
                            dbC["CONSTRAINT_NAME"] ===
2,602✔
3504
                            constraint["CONSTRAINT_NAME"],
414✔
3505
                    )
414✔
3506
                    return new TableUnique({
414✔
3507
                        name: constraint["CONSTRAINT_NAME"],
414✔
3508
                        columnNames: uniques.map((u) => u["COLUMN_NAME"]),
414✔
3509
                    })
414✔
3510
                })
990✔
3511

990✔
3512
                // find check constraints of table, group them by constraint name and build TableCheck.
990✔
3513
                const tableCheckConstraints = OrmUtils.uniq(
990✔
3514
                    dbConstraints.filter(
990✔
3515
                        (dbConstraint) =>
990✔
3516
                            dbConstraint["TABLE_NAME"] ===
5,330✔
3517
                                dbTable["TABLE_NAME"] &&
5,330✔
3518
                            dbConstraint["TABLE_SCHEMA"] ===
1,816✔
3519
                                dbTable["TABLE_SCHEMA"] &&
5,330✔
3520
                            dbConstraint["TABLE_CATALOG"] ===
1,816✔
3521
                                dbTable["TABLE_CATALOG"] &&
5,330✔
3522
                            dbConstraint["CONSTRAINT_TYPE"] === "CHECK",
990✔
3523
                    ),
990✔
3524
                    (dbConstraint) => dbConstraint["CONSTRAINT_NAME"],
990✔
3525
                )
990✔
3526

990✔
3527
                table.checks = tableCheckConstraints
990✔
3528
                    .filter(
990✔
3529
                        (constraint) =>
990✔
3530
                            !this.isEnumCheckConstraint(
184✔
3531
                                constraint["CONSTRAINT_NAME"],
184✔
3532
                            ),
990✔
3533
                    )
990✔
3534
                    .map((constraint) => {
990✔
3535
                        const checks = dbConstraints.filter(
174✔
3536
                            (dbC) =>
174✔
3537
                                dbC["CONSTRAINT_NAME"] ===
1,220✔
3538
                                constraint["CONSTRAINT_NAME"],
174✔
3539
                        )
174✔
3540
                        return new TableCheck({
174✔
3541
                            name: constraint["CONSTRAINT_NAME"],
174✔
3542
                            columnNames: checks.map((c) => c["COLUMN_NAME"]),
174✔
3543
                            expression: constraint["definition"],
174✔
3544
                        })
174✔
3545
                    })
990✔
3546

990✔
3547
                // find foreign key constraints of table, group them by constraint name and build TableForeignKey.
990✔
3548
                const tableForeignKeyConstraints = OrmUtils.uniq(
990✔
3549
                    dbForeignKeys.filter(
990✔
3550
                        (dbForeignKey) =>
990✔
3551
                            dbForeignKey["TABLE_NAME"] ===
1,280✔
3552
                                dbTable["TABLE_NAME"] &&
1,280✔
3553
                            dbForeignKey["TABLE_SCHEMA"] ===
346✔
3554
                                dbTable["TABLE_SCHEMA"] &&
1,280✔
3555
                            dbForeignKey["TABLE_CATALOG"] ===
346✔
3556
                                dbTable["TABLE_CATALOG"],
990✔
3557
                    ),
990✔
3558
                    (dbForeignKey) => dbForeignKey["FK_NAME"],
990✔
3559
                )
990✔
3560

990✔
3561
                table.foreignKeys = tableForeignKeyConstraints.map(
990✔
3562
                    (dbForeignKey) => {
990✔
3563
                        const foreignKeys = dbForeignKeys.filter(
338✔
3564
                            (dbFk) =>
338✔
3565
                                dbFk["FK_NAME"] === dbForeignKey["FK_NAME"],
338✔
3566
                        )
338✔
3567

338✔
3568
                        // if referenced table located in currently used db and schema, we don't need to concat db and schema names to table name.
338✔
3569
                        const db =
338✔
3570
                            dbForeignKey["TABLE_CATALOG"] === currentDatabase
338✔
3571
                                ? undefined
338✔
3572
                                : dbForeignKey["TABLE_CATALOG"]
338✔
3573
                        const schema = getSchemaFromKey(
338✔
3574
                            dbForeignKey,
338✔
3575
                            "REF_SCHEMA",
338✔
3576
                        )
338✔
3577
                        const referencedTableName = this.driver.buildTableName(
338✔
3578
                            dbForeignKey["REF_TABLE"],
338✔
3579
                            schema,
338✔
3580
                            db,
338✔
3581
                        )
338✔
3582

338✔
3583
                        return new TableForeignKey({
338✔
3584
                            name: dbForeignKey["FK_NAME"],
338✔
3585
                            columnNames: foreignKeys.map(
338✔
3586
                                (dbFk) => dbFk["COLUMN_NAME"],
338✔
3587
                            ),
338✔
3588
                            referencedDatabase: dbForeignKey["TABLE_CATALOG"],
338✔
3589
                            referencedSchema: dbForeignKey["REF_SCHEMA"],
338✔
3590
                            referencedTableName: referencedTableName,
338✔
3591
                            referencedColumnNames: foreignKeys.map(
338✔
3592
                                (dbFk) => dbFk["REF_COLUMN"],
338✔
3593
                            ),
338✔
3594
                            onDelete: dbForeignKey["ON_DELETE"].replace(
338✔
3595
                                "_",
338✔
3596
                                " ",
338✔
3597
                            ), // SqlServer returns NO_ACTION, instead of NO ACTION
338✔
3598
                            onUpdate: dbForeignKey["ON_UPDATE"].replace(
338✔
3599
                                "_",
338✔
3600
                                " ",
338✔
3601
                            ), // SqlServer returns NO_ACTION, instead of NO ACTION
338✔
3602
                        })
338✔
3603
                    },
990✔
3604
                )
990✔
3605

990✔
3606
                // find index constraints of table, group them by constraint name and build TableIndex.
990✔
3607
                const tableIndexConstraints = OrmUtils.uniq(
990✔
3608
                    dbIndices.filter(
990✔
3609
                        (dbIndex) =>
990✔
3610
                            dbIndex["TABLE_NAME"] === dbTable["TABLE_NAME"] &&
722✔
3611
                            dbIndex["TABLE_SCHEMA"] ===
332✔
3612
                                dbTable["TABLE_SCHEMA"] &&
722✔
3613
                            dbIndex["TABLE_CATALOG"] ===
332✔
3614
                                dbTable["TABLE_CATALOG"],
990✔
3615
                    ),
990✔
3616
                    (dbIndex) => dbIndex["INDEX_NAME"],
990✔
3617
                )
990✔
3618

990✔
3619
                table.indices = tableIndexConstraints.map((constraint) => {
990✔
3620
                    const indices = dbIndices.filter((index) => {
288✔
3621
                        return (
964✔
3622
                            index["TABLE_CATALOG"] ===
964✔
3623
                                constraint["TABLE_CATALOG"] &&
964✔
3624
                            index["TABLE_SCHEMA"] ===
964✔
3625
                                constraint["TABLE_SCHEMA"] &&
964✔
3626
                            index["TABLE_NAME"] === constraint["TABLE_NAME"] &&
964✔
3627
                            index["INDEX_NAME"] === constraint["INDEX_NAME"]
694✔
3628
                        )
964✔
3629
                    })
288✔
3630
                    return new TableIndex(<TableIndexOptions>{
288✔
3631
                        table: table,
288✔
3632
                        name: constraint["INDEX_NAME"],
288✔
3633
                        columnNames: indices.map((i) => i["COLUMN_NAME"]),
288✔
3634
                        isUnique: constraint["IS_UNIQUE"],
288✔
3635
                        where: constraint["CONDITION"],
288✔
3636
                    })
288✔
3637
                })
990✔
3638

990✔
3639
                return table
990✔
3640
            }),
666✔
3641
        )
666✔
3642
    }
666✔
3643

26✔
3644
    /**
26✔
3645
     * Builds and returns SQL for create table.
26✔
3646
     * @param table
26✔
3647
     * @param createForeignKeys
26✔
3648
     */
26✔
3649
    protected createTableSql(table: Table, createForeignKeys?: boolean): Query {
26✔
3650
        const columnDefinitions = table.columns
10,548✔
3651
            .map((column) =>
10,548✔
3652
                this.buildCreateColumnSql(table, column, false, true),
10,548✔
3653
            )
10,548✔
3654
            .join(", ")
10,548✔
3655
        let sql = `CREATE TABLE ${this.escapePath(table)} (${columnDefinitions}`
10,548✔
3656

10,548✔
3657
        table.columns
10,548✔
3658
            .filter((column) => column.isUnique)
10,548✔
3659
            .forEach((column) => {
10,548✔
3660
                const isUniqueExist = table.uniques.some(
666✔
3661
                    (unique) =>
666✔
3662
                        unique.columnNames.length === 1 &&
800✔
3663
                        unique.columnNames[0] === column.name,
666✔
3664
                )
666✔
3665
                if (!isUniqueExist)
666✔
3666
                    table.uniques.push(
666✔
3667
                        new TableUnique({
8✔
3668
                            name: this.connection.namingStrategy.uniqueConstraintName(
8✔
3669
                                table,
8✔
3670
                                [column.name],
8✔
3671
                            ),
8✔
3672
                            columnNames: [column.name],
8✔
3673
                        }),
8✔
3674
                    )
8✔
3675
            })
10,548✔
3676

10,548✔
3677
        if (table.uniques.length > 0) {
10,548✔
3678
            const uniquesSql = table.uniques
620✔
3679
                .map((unique) => {
620✔
3680
                    const uniqueName = unique.name
892✔
3681
                        ? unique.name
892✔
3682
                        : this.connection.namingStrategy.uniqueConstraintName(
892✔
3683
                              table,
4✔
3684
                              unique.columnNames,
4✔
3685
                          )
892✔
3686
                    const columnNames = unique.columnNames
892✔
3687
                        .map((columnName) => `"${columnName}"`)
892✔
3688
                        .join(", ")
892✔
3689
                    return `CONSTRAINT "${uniqueName}" UNIQUE (${columnNames})`
892✔
3690
                })
620✔
3691
                .join(", ")
620✔
3692

620✔
3693
            sql += `, ${uniquesSql}`
620✔
3694
        }
620✔
3695

10,548✔
3696
        if (table.checks.length > 0) {
10,548✔
3697
            const checksSql = table.checks
146✔
3698
                .map((check) => {
146✔
3699
                    const checkName = check.name
148✔
3700
                        ? check.name
148✔
3701
                        : this.connection.namingStrategy.checkConstraintName(
148✔
3702
                              table,
2✔
3703
                              check.expression!,
2✔
3704
                          )
148✔
3705
                    return `CONSTRAINT "${checkName}" CHECK (${check.expression})`
148✔
3706
                })
146✔
3707
                .join(", ")
146✔
3708

146✔
3709
            sql += `, ${checksSql}`
146✔
3710
        }
146✔
3711

10,548✔
3712
        if (table.foreignKeys.length > 0 && createForeignKeys) {
10,548✔
3713
            const foreignKeysSql = table.foreignKeys
8✔
3714
                .map((fk) => {
8✔
3715
                    const columnNames = fk.columnNames
10✔
3716
                        .map((columnName) => `"${columnName}"`)
10✔
3717
                        .join(", ")
10✔
3718
                    if (!fk.name)
10✔
3719
                        fk.name = this.connection.namingStrategy.foreignKeyName(
10✔
3720
                            table,
6✔
3721
                            fk.columnNames,
6✔
3722
                            this.getTablePath(fk),
6✔
3723
                            fk.referencedColumnNames,
6✔
3724
                        )
6✔
3725
                    const referencedColumnNames = fk.referencedColumnNames
10✔
3726
                        .map((columnName) => `"${columnName}"`)
10✔
3727
                        .join(", ")
10✔
3728

10✔
3729
                    let constraint = `CONSTRAINT "${
10✔
3730
                        fk.name
10✔
3731
                    }" FOREIGN KEY (${columnNames}) REFERENCES ${this.escapePath(
10✔
3732
                        this.getTablePath(fk),
10✔
3733
                    )} (${referencedColumnNames})`
10✔
3734
                    if (fk.onDelete) constraint += ` ON DELETE ${fk.onDelete}`
10✔
3735
                    if (fk.onUpdate) constraint += ` ON UPDATE ${fk.onUpdate}`
10✔
3736

10✔
3737
                    return constraint
10✔
3738
                })
8✔
3739
                .join(", ")
8✔
3740

8✔
3741
            sql += `, ${foreignKeysSql}`
8✔
3742
        }
8✔
3743

10,548✔
3744
        const primaryColumns = table.columns.filter(
10,548✔
3745
            (column) => column.isPrimary,
10,548✔
3746
        )
10,548✔
3747
        if (primaryColumns.length > 0) {
10,548✔
3748
            const primaryKeyName = primaryColumns[0].primaryKeyConstraintName
10,522✔
3749
                ? primaryColumns[0].primaryKeyConstraintName
10,522✔
3750
                : this.connection.namingStrategy.primaryKeyName(
10,522✔
3751
                      table,
10,490✔
3752
                      primaryColumns.map((column) => column.name),
10,490✔
3753
                  )
10,522✔
3754

10,522✔
3755
            const columnNames = primaryColumns
10,522✔
3756
                .map((column) => `"${column.name}"`)
10,522✔
3757
                .join(", ")
10,522✔
3758
            sql += `, CONSTRAINT "${primaryKeyName}" PRIMARY KEY (${columnNames})`
10,522✔
3759
        }
10,522✔
3760

10,548✔
3761
        sql += `)`
10,548✔
3762

10,548✔
3763
        return new Query(sql)
10,548✔
3764
    }
10,548✔
3765

26✔
3766
    /**
26✔
3767
     * Builds drop table sql.
26✔
3768
     * @param tableOrName
26✔
3769
     * @param ifExist
26✔
3770
     */
26✔
3771
    protected dropTableSql(
26✔
3772
        tableOrName: Table | string,
10,548✔
3773
        ifExist?: boolean,
10,548✔
3774
    ): Query {
10,548✔
3775
        const query = ifExist
10,548✔
3776
            ? `DROP TABLE IF EXISTS ${this.escapePath(tableOrName)}`
10,548!
3777
            : `DROP TABLE ${this.escapePath(tableOrName)}`
10,548✔
3778
        return new Query(query)
10,548✔
3779
    }
10,548✔
3780

26✔
3781
    protected createViewSql(view: View): Query {
26✔
3782
        const parsedName = this.driver.parseTableName(view)
16✔
3783

16✔
3784
        // Can't use `escapePath` here because `CREATE VIEW` does not accept database names.
16✔
3785
        const viewIdentifier = parsedName.schema
16✔
3786
            ? `"${parsedName.schema}"."${parsedName.tableName}"`
16✔
3787
            : `"${parsedName.tableName}"`
16!
3788

16✔
3789
        if (typeof view.expression === "string") {
16✔
3790
            return new Query(
4✔
3791
                `CREATE VIEW ${viewIdentifier} AS ${view.expression}`,
4✔
3792
            )
4✔
3793
        } else {
16✔
3794
            return new Query(
12✔
3795
                `CREATE VIEW ${viewIdentifier} AS ${view
12✔
3796
                    .expression(this.connection)
12✔
3797
                    .getQuery()}`,
12✔
3798
            )
12✔
3799
        }
12✔
3800
    }
16✔
3801

26✔
3802
    protected async insertViewDefinitionSql(view: View): Promise<Query> {
26✔
3803
        const parsedTableName = this.driver.parseTableName(view)
16✔
3804

16✔
3805
        if (!parsedTableName.schema) {
16!
3806
            parsedTableName.schema = await this.getCurrentSchema()
×
3807
        }
×
3808

16✔
3809
        const expression =
16✔
3810
            typeof view.expression === "string"
16✔
3811
                ? view.expression.trim()
16✔
3812
                : view.expression(this.connection).getQuery()
16✔
3813
        return this.insertTypeormMetadataSql({
16✔
3814
            type: MetadataTableType.VIEW,
16✔
3815
            database: parsedTableName.database,
16✔
3816
            schema: parsedTableName.schema,
16✔
3817
            name: parsedTableName.tableName,
16✔
3818
            value: expression,
16✔
3819
        })
16✔
3820
    }
16✔
3821

26✔
3822
    /**
26✔
3823
     * Builds drop view sql.
26✔
3824
     * @param viewOrPath
26✔
3825
     */
26✔
3826
    protected dropViewSql(viewOrPath: View | string): Query {
26✔
3827
        return new Query(`DROP VIEW ${this.escapePath(viewOrPath)}`)
16✔
3828
    }
16✔
3829

26✔
3830
    /**
26✔
3831
     * Builds remove view sql.
26✔
3832
     * @param viewOrPath
26✔
3833
     */
26✔
3834
    protected async deleteViewDefinitionSql(
26✔
3835
        viewOrPath: View | string,
16✔
3836
    ): Promise<Query> {
16✔
3837
        const parsedTableName = this.driver.parseTableName(viewOrPath)
16✔
3838

16✔
3839
        if (!parsedTableName.schema) {
16!
3840
            parsedTableName.schema = await this.getCurrentSchema()
×
3841
        }
×
3842

16✔
3843
        return this.deleteTypeormMetadataSql({
16✔
3844
            type: MetadataTableType.VIEW,
16✔
3845
            database: parsedTableName.database,
16✔
3846
            schema: parsedTableName.schema,
16✔
3847
            name: parsedTableName.tableName,
16✔
3848
        })
16✔
3849
    }
16✔
3850

26✔
3851
    /**
26✔
3852
     * Builds create index sql.
26✔
3853
     * @param table
26✔
3854
     * @param index
26✔
3855
     */
26✔
3856
    protected createIndexSql(table: Table, index: TableIndex): Query {
26✔
3857
        const columns = index.columnNames
4,586✔
3858
            .map((columnName) => `"${columnName}"`)
4,586✔
3859
            .join(", ")
4,586✔
3860
        return new Query(
4,586✔
3861
            `CREATE ${index.isUnique ? "UNIQUE " : ""}INDEX "${
4,586✔
3862
                index.name
4,586✔
3863
            }" ON ${this.escapePath(table)} (${columns}) ${
4,586✔
3864
                index.where ? "WHERE " + index.where : ""
4,586✔
3865
            }`,
4,586✔
3866
        )
4,586✔
3867
    }
4,586✔
3868

26✔
3869
    /**
26✔
3870
     * Builds drop index sql.
26✔
3871
     * @param table
26✔
3872
     * @param indexOrName
26✔
3873
     */
26✔
3874
    protected dropIndexSql(
26✔
3875
        table: Table,
4,586✔
3876
        indexOrName: TableIndex | string,
4,586✔
3877
    ): Query {
4,586✔
3878
        const indexName = InstanceChecker.isTableIndex(indexOrName)
4,586✔
3879
            ? indexOrName.name
4,586✔
3880
            : indexOrName
4,586!
3881
        return new Query(
4,586✔
3882
            `DROP INDEX "${indexName}" ON ${this.escapePath(table)}`,
4,586✔
3883
        )
4,586✔
3884
    }
4,586✔
3885

26✔
3886
    /**
26✔
3887
     * Builds create primary key sql.
26✔
3888
     * @param table
26✔
3889
     * @param columnNames
26✔
3890
     * @param constraintName
26✔
3891
     */
26✔
3892
    protected createPrimaryKeySql(
26✔
3893
        table: Table,
10✔
3894
        columnNames: string[],
10✔
3895
        constraintName?: string,
10✔
3896
    ): Query {
10✔
3897
        const primaryKeyName = constraintName
10✔
3898
            ? constraintName
10!
3899
            : this.connection.namingStrategy.primaryKeyName(table, columnNames)
10✔
3900

10✔
3901
        const columnNamesString = columnNames
10✔
3902
            .map((columnName) => `"${columnName}"`)
10✔
3903
            .join(", ")
10✔
3904
        return new Query(
10✔
3905
            `ALTER TABLE ${this.escapePath(
10✔
3906
                table,
10✔
3907
            )} ADD CONSTRAINT "${primaryKeyName}" PRIMARY KEY (${columnNamesString})`,
10✔
3908
        )
10✔
3909
    }
10✔
3910

26✔
3911
    /**
26✔
3912
     * Builds drop primary key sql.
26✔
3913
     * @param table
26✔
3914
     */
26✔
3915
    protected dropPrimaryKeySql(table: Table): Query {
26✔
3916
        const columnNames = table.primaryColumns.map((column) => column.name)
10✔
3917
        const constraintName = table.primaryColumns[0].primaryKeyConstraintName
10✔
3918
        const primaryKeyName = constraintName
10✔
3919
            ? constraintName
10!
3920
            : this.connection.namingStrategy.primaryKeyName(table, columnNames)
10✔
3921

10✔
3922
        return new Query(
10✔
3923
            `ALTER TABLE ${this.escapePath(
10✔
3924
                table,
10✔
3925
            )} DROP CONSTRAINT "${primaryKeyName}"`,
10✔
3926
        )
10✔
3927
    }
10✔
3928

26✔
3929
    /**
26✔
3930
     * Builds create unique constraint sql.
26✔
3931
     * @param table
26✔
3932
     * @param uniqueConstraint
26✔
3933
     */
26✔
3934
    protected createUniqueConstraintSql(
26✔
3935
        table: Table,
38✔
3936
        uniqueConstraint: TableUnique,
38✔
3937
    ): Query {
38✔
3938
        const columnNames = uniqueConstraint.columnNames
38✔
3939
            .map((column) => `"` + column + `"`)
38✔
3940
            .join(", ")
38✔
3941
        return new Query(
38✔
3942
            `ALTER TABLE ${this.escapePath(table)} ADD CONSTRAINT "${
38✔
3943
                uniqueConstraint.name
38✔
3944
            }" UNIQUE (${columnNames})`,
38✔
3945
        )
38✔
3946
    }
38✔
3947

26✔
3948
    /**
26✔
3949
     * Builds drop unique constraint sql.
26✔
3950
     * @param table
26✔
3951
     * @param uniqueOrName
26✔
3952
     */
26✔
3953
    protected dropUniqueConstraintSql(
26✔
3954
        table: Table,
38✔
3955
        uniqueOrName: TableUnique | string,
38✔
3956
    ): Query {
38✔
3957
        const uniqueName = InstanceChecker.isTableUnique(uniqueOrName)
38✔
3958
            ? uniqueOrName.name
38✔
3959
            : uniqueOrName
38!
3960
        return new Query(
38✔
3961
            `ALTER TABLE ${this.escapePath(
38✔
3962
                table,
38✔
3963
            )} DROP CONSTRAINT "${uniqueName}"`,
38✔
3964
        )
38✔
3965
    }
38✔
3966

26✔
3967
    /**
26✔
3968
     * Builds create check constraint sql.
26✔
3969
     * @param table
26✔
3970
     * @param checkConstraint
26✔
3971
     */
26✔
3972
    protected createCheckConstraintSql(
26✔
3973
        table: Table,
24✔
3974
        checkConstraint: TableCheck,
24✔
3975
    ): Query {
24✔
3976
        return new Query(
24✔
3977
            `ALTER TABLE ${this.escapePath(table)} ADD CONSTRAINT "${
24✔
3978
                checkConstraint.name
24✔
3979
            }" CHECK (${checkConstraint.expression})`,
24✔
3980
        )
24✔
3981
    }
24✔
3982

26✔
3983
    /**
26✔
3984
     * Builds drop check constraint sql.
26✔
3985
     * @param table
26✔
3986
     * @param checkOrName
26✔
3987
     */
26✔
3988
    protected dropCheckConstraintSql(
26✔
3989
        table: Table,
24✔
3990
        checkOrName: TableCheck | string,
24✔
3991
    ): Query {
24✔
3992
        const checkName = InstanceChecker.isTableCheck(checkOrName)
24✔
3993
            ? checkOrName.name
24✔
3994
            : checkOrName
24!
3995
        return new Query(
24✔
3996
            `ALTER TABLE ${this.escapePath(
24✔
3997
                table,
24✔
3998
            )} DROP CONSTRAINT "${checkName}"`,
24✔
3999
        )
24✔
4000
    }
24✔
4001

26✔
4002
    /**
26✔
4003
     * Builds create foreign key sql.
26✔
4004
     * @param table
26✔
4005
     * @param foreignKey
26✔
4006
     */
26✔
4007
    protected createForeignKeySql(
26✔
4008
        table: Table,
6,972✔
4009
        foreignKey: TableForeignKey,
6,972✔
4010
    ): Query {
6,972✔
4011
        const columnNames = foreignKey.columnNames
6,972✔
4012
            .map((column) => `"` + column + `"`)
6,972✔
4013
            .join(", ")
6,972✔
4014
        const referencedColumnNames = foreignKey.referencedColumnNames
6,972✔
4015
            .map((column) => `"` + column + `"`)
6,972✔
4016
            .join(",")
6,972✔
4017
        let sql =
6,972✔
4018
            `ALTER TABLE ${this.escapePath(table)} ADD CONSTRAINT "${
6,972✔
4019
                foreignKey.name
6,972✔
4020
            }" FOREIGN KEY (${columnNames}) ` +
6,972✔
4021
            `REFERENCES ${this.escapePath(
6,972✔
4022
                this.getTablePath(foreignKey),
6,972✔
4023
            )}(${referencedColumnNames})`
6,972✔
4024
        if (foreignKey.onDelete) sql += ` ON DELETE ${foreignKey.onDelete}`
6,972✔
4025
        if (foreignKey.onUpdate) sql += ` ON UPDATE ${foreignKey.onUpdate}`
6,972✔
4026

6,972✔
4027
        return new Query(sql)
6,972✔
4028
    }
6,972✔
4029

26✔
4030
    /**
26✔
4031
     * Builds drop foreign key sql.
26✔
4032
     * @param table
26✔
4033
     * @param foreignKeyOrName
26✔
4034
     */
26✔
4035
    protected dropForeignKeySql(
26✔
4036
        table: Table,
6,982✔
4037
        foreignKeyOrName: TableForeignKey | string,
6,982✔
4038
    ): Query {
6,982✔
4039
        const foreignKeyName = InstanceChecker.isTableForeignKey(
6,982✔
4040
            foreignKeyOrName,
6,982✔
4041
        )
6,982✔
4042
            ? foreignKeyOrName.name
6,982✔
4043
            : foreignKeyOrName
6,982!
4044
        return new Query(
6,982✔
4045
            `ALTER TABLE ${this.escapePath(
6,982✔
4046
                table,
6,982✔
4047
            )} DROP CONSTRAINT "${foreignKeyName}"`,
6,982✔
4048
        )
6,982✔
4049
    }
6,982✔
4050

26✔
4051
    /**
26✔
4052
     * Escapes given table or View path.
26✔
4053
     * @param target
26✔
4054
     */
26✔
4055
    protected escapePath(target: Table | View | string): string {
26✔
4056
        const { database, schema, tableName } =
51,912✔
4057
            this.driver.parseTableName(target)
51,912✔
4058

51,912✔
4059
        if (database && database !== this.driver.database) {
51,912✔
4060
            if (schema && schema !== this.driver.searchSchema) {
96✔
4061
                return `"${database}"."${schema}"."${tableName}"`
84✔
4062
            }
84✔
4063

12✔
4064
            return `"${database}".."${tableName}"`
12✔
4065
        }
12✔
4066

51,816✔
4067
        if (schema && schema !== this.driver.searchSchema) {
51,912✔
4068
            return `"${schema}"."${tableName}"`
148✔
4069
        }
148✔
4070

51,668✔
4071
        return `"${tableName}"`
51,668✔
4072
    }
51,668✔
4073

26✔
4074
    /**
26✔
4075
     * Concat database name and schema name to the foreign key name.
26✔
4076
     * Needs because FK name is relevant to the schema and database.
26✔
4077
     * @param fkName
26✔
4078
     * @param schemaName
26✔
4079
     * @param dbName
26✔
4080
     */
26✔
4081
    protected buildForeignKeyName(
26✔
4082
        fkName: string,
8✔
4083
        schemaName: string | undefined,
8✔
4084
        dbName: string | undefined,
8✔
4085
    ): string {
8✔
4086
        let joinedFkName = fkName
8✔
4087
        if (schemaName && schemaName !== this.driver.searchSchema)
8✔
4088
            joinedFkName = schemaName + "." + joinedFkName
8✔
4089
        if (dbName && dbName !== this.driver.database)
8✔
4090
            joinedFkName = dbName + "." + joinedFkName
8✔
4091

8✔
4092
        return joinedFkName
8✔
4093
    }
8✔
4094

26✔
4095
    /**
26✔
4096
     * Removes parenthesis around default value.
26✔
4097
     * Sql server returns default value with parenthesis around, e.g.
26✔
4098
     *  ('My text') - for string
26✔
4099
     *  ((1)) - for number
26✔
4100
     *  (newsequentialId()) - for function
26✔
4101
     * @param defaultValue
26✔
4102
     */
26✔
4103
    protected removeParenthesisFromDefault(defaultValue: string): any {
26✔
4104
        if (defaultValue.substr(0, 1) !== "(") return defaultValue
428✔
4105
        const normalizedDefault = defaultValue.substr(
216✔
4106
            1,
216✔
4107
            defaultValue.lastIndexOf(")") - 1,
216✔
4108
        )
216✔
4109
        return this.removeParenthesisFromDefault(normalizedDefault)
216✔
4110
    }
216✔
4111

26✔
4112
    /**
26✔
4113
     * Builds a query for create column.
26✔
4114
     * @param table
26✔
4115
     * @param column
26✔
4116
     * @param skipIdentity
26✔
4117
     * @param createDefault
26✔
4118
     * @param skipEnum
26✔
4119
     */
26✔
4120
    protected buildCreateColumnSql(
26✔
4121
        table: Table,
34,076✔
4122
        column: TableColumn,
34,076✔
4123
        skipIdentity: boolean,
34,076✔
4124
        createDefault: boolean,
34,076✔
4125
        skipEnum?: boolean,
34,076✔
4126
    ) {
34,076✔
4127
        let c = `"${column.name}" ${this.connection.driver.createFullType(
34,076✔
4128
            column,
34,076✔
4129
        )}`
34,076✔
4130

34,076✔
4131
        if (!skipEnum && column.enum) {
34,076✔
4132
            const expression = this.getEnumExpression(column)
48✔
4133
            const checkName =
48✔
4134
                this.connection.namingStrategy.checkConstraintName(
48✔
4135
                    table,
48✔
4136
                    expression,
48✔
4137
                    true,
48✔
4138
                )
48✔
4139
            c += ` CONSTRAINT ${checkName} CHECK(${expression})`
48✔
4140
        }
48✔
4141

34,076✔
4142
        if (column.collation) c += " COLLATE " + column.collation
34,076✔
4143

34,076✔
4144
        if (column.asExpression) {
34,076✔
4145
            c += ` AS (${column.asExpression})`
78✔
4146
            if (column.generatedType === "STORED") {
78✔
4147
                c += ` PERSISTED`
42✔
4148

42✔
4149
                // NOT NULL can be specified for computed columns only if PERSISTED is also specified
42✔
4150
                if (column.isNullable !== true) c += " NOT NULL"
42✔
4151
            }
42✔
4152
        } else {
34,076✔
4153
            if (column.isNullable !== true) c += " NOT NULL"
33,998✔
4154
        }
33,998✔
4155

34,076✔
4156
        if (
34,076✔
4157
            column.isGenerated === true &&
34,076✔
4158
            column.generationStrategy === "increment" &&
34,076✔
4159
            !skipIdentity
6,286✔
4160
        )
34,076✔
4161
            // don't use skipPrimary here since updates can update already exist primary without auto inc.
34,076✔
4162
            c += " IDENTITY(1,1)"
34,076✔
4163

34,076✔
4164
        if (
34,076✔
4165
            column.default !== undefined &&
34,076✔
4166
            column.default !== null &&
34,076✔
4167
            createDefault
2,018✔
4168
        ) {
34,076✔
4169
            // we create named constraint to be able to delete this constraint when column been dropped
2,006✔
4170
            const defaultName =
2,006✔
4171
                this.connection.namingStrategy.defaultConstraintName(
2,006✔
4172
                    table,
2,006✔
4173
                    column.name,
2,006✔
4174
                )
2,006✔
4175
            c += ` CONSTRAINT "${defaultName}" DEFAULT ${column.default}`
2,006✔
4176
        }
2,006✔
4177

34,076✔
4178
        if (
34,076✔
4179
            column.isGenerated &&
34,076✔
4180
            column.generationStrategy === "uuid" &&
34,076✔
4181
            !column.default
272✔
4182
        ) {
34,076✔
4183
            // we create named constraint to be able to delete this constraint when column been dropped
272✔
4184
            const defaultName =
272✔
4185
                this.connection.namingStrategy.defaultConstraintName(
272✔
4186
                    table,
272✔
4187
                    column.name,
272✔
4188
                )
272✔
4189
            c += ` CONSTRAINT "${defaultName}" DEFAULT NEWSEQUENTIALID()`
272✔
4190
        }
272✔
4191
        return c
34,076✔
4192
    }
34,076✔
4193

26✔
4194
    private getEnumExpression(column: TableColumn) {
26✔
4195
        if (!column.enum) {
52!
4196
            throw new Error(`Enum is not defined in column ${column.name}`)
×
4197
        }
×
4198
        return (
52✔
4199
            column.name +
52✔
4200
            " IN (" +
52✔
4201
            column.enum.map((val) => "'" + val + "'").join(",") +
52✔
4202
            ")"
52✔
4203
        )
52✔
4204
    }
52✔
4205

26✔
4206
    protected isEnumCheckConstraint(name: string): boolean {
26✔
4207
        return name.indexOf("CHK_") !== -1 && name.indexOf("_ENUM") !== -1
206✔
4208
    }
206✔
4209

26✔
4210
    /**
26✔
4211
     * Converts MssqlParameter into real mssql parameter type.
26✔
4212
     * @param parameter
26✔
4213
     */
26✔
4214
    protected mssqlParameterToNativeParameter(parameter: MssqlParameter): any {
26✔
4215
        switch (this.driver.normalizeType({ type: parameter.type as any })) {
54,090✔
4216
            case "bit":
54,090✔
4217
                return this.driver.mssql.Bit
4,104✔
4218
            case "bigint":
54,090✔
4219
                return this.driver.mssql.BigInt
64✔
4220
            case "decimal":
54,090✔
4221
                return this.driver.mssql.Decimal(...parameter.params)
8✔
4222
            case "float":
54,090✔
4223
                return this.driver.mssql.Float
60✔
4224
            case "int":
54,090✔
4225
                return this.driver.mssql.Int
24,578✔
4226
            case "money":
54,090✔
4227
                return this.driver.mssql.Money
2✔
4228
            case "numeric":
54,090✔
4229
                return this.driver.mssql.Numeric(...parameter.params)
4✔
4230
            case "smallint":
54,090✔
4231
                return this.driver.mssql.SmallInt
2✔
4232
            case "smallmoney":
54,090✔
4233
                return this.driver.mssql.SmallMoney
2✔
4234
            case "real":
54,090✔
4235
                return this.driver.mssql.Real
2✔
4236
            case "tinyint":
54,090✔
4237
                return this.driver.mssql.TinyInt
2✔
4238
            case "char":
54,090✔
4239
                if (
10✔
4240
                    this.driver.options.options
10✔
4241
                        ?.disableAsciiToUnicodeParamConversion
10✔
4242
                ) {
10✔
4243
                    return this.driver.mssql.Char(...parameter.params)
2✔
4244
                }
2✔
4245
                return this.driver.mssql.NChar(...parameter.params)
8✔
4246
            case "nchar":
54,090✔
4247
                return this.driver.mssql.NChar(...parameter.params)
4✔
4248
            case "text":
54,090✔
4249
                if (
10✔
4250
                    this.driver.options.options
10✔
4251
                        ?.disableAsciiToUnicodeParamConversion
10!
4252
                ) {
10!
4253
                    return this.driver.mssql.Text
×
4254
                }
×
4255
                return this.driver.mssql.Ntext
10✔
4256
            case "ntext":
54,090✔
4257
                return this.driver.mssql.Ntext
14✔
4258
            case "varchar":
54,090✔
4259
                if (
172✔
4260
                    this.driver.options.options
172✔
4261
                        ?.disableAsciiToUnicodeParamConversion
172✔
4262
                ) {
172✔
4263
                    return this.driver.mssql.VarChar(...parameter.params)
2✔
4264
                }
2✔
4265
                return this.driver.mssql.NVarChar(...parameter.params)
170✔
4266
            case "nvarchar":
54,090✔
4267
                return this.driver.mssql.NVarChar(...parameter.params)
24,370✔
4268
            case "xml":
54,090!
4269
                return this.driver.mssql.Xml
×
4270
            case "time":
54,090✔
4271
                return this.driver.mssql.Time(...parameter.params)
12✔
4272
            case "date":
54,090✔
4273
                return this.driver.mssql.Date
10✔
4274
            case "datetime":
54,090✔
4275
                return this.driver.mssql.DateTime
50✔
4276
            case "datetime2":
54,090✔
4277
                return this.driver.mssql.DateTime2(...parameter.params)
24✔
4278
            case "datetimeoffset":
54,090✔
4279
                return this.driver.mssql.DateTimeOffset(...parameter.params)
8✔
4280
            case "smalldatetime":
54,090✔
4281
                return this.driver.mssql.SmallDateTime
2✔
4282
            case "uniqueidentifier":
54,090✔
4283
                return this.driver.mssql.UniqueIdentifier
504✔
4284
            case "variant":
54,090!
4285
                return this.driver.mssql.Variant
×
4286
            case "binary":
54,090✔
4287
                return this.driver.mssql.Binary
26✔
4288
            case "varbinary":
54,090✔
4289
                return this.driver.mssql.VarBinary(...parameter.params)
4✔
4290
            case "image":
54,090✔
4291
                return this.driver.mssql.Image
2✔
4292
            case "udt":
54,090!
4293
                return this.driver.mssql.UDT
×
4294
            case "rowversion":
54,090!
4295
                return this.driver.mssql.RowVersion
×
4296
            case "vector":
54,090✔
4297
                return this.driver.mssql.Ntext
20✔
4298
        }
54,090✔
4299
    }
54,090✔
4300

26✔
4301
    /**
26✔
4302
     * Converts string literal of isolation level to enum.
26✔
4303
     * The underlying mssql driver requires an enum for the isolation level.
26✔
4304
     * @param isolation
26✔
4305
     */
26✔
4306
    convertIsolationLevel(isolation: IsolationLevel) {
26✔
4307
        const ISOLATION_LEVEL = this.driver.mssql.ISOLATION_LEVEL
12✔
4308
        switch (isolation) {
12✔
4309
            case "READ UNCOMMITTED":
12✔
4310
                return ISOLATION_LEVEL.READ_UNCOMMITTED
4✔
4311
            case "REPEATABLE READ":
12✔
4312
                return ISOLATION_LEVEL.REPEATABLE_READ
2✔
4313
            case "SERIALIZABLE":
12✔
4314
                return ISOLATION_LEVEL.SERIALIZABLE
4✔
4315

12✔
4316
            case "READ COMMITTED":
12✔
4317
            default:
12✔
4318
                return ISOLATION_LEVEL.READ_COMMITTED
2✔
4319
        }
12✔
4320
    }
12✔
4321

26✔
4322
    /**
26✔
4323
     * Change table comment.
26✔
4324
     * @param tableOrName
26✔
4325
     * @param comment
26✔
4326
     */
26✔
4327
    changeTableComment(
26✔
4328
        tableOrName: Table | string,
×
4329
        comment?: string,
×
4330
    ): Promise<void> {
×
4331
        throw new TypeORMError(
×
4332
            `sqlserver driver does not support change table comment.`,
×
4333
        )
×
4334
    }
×
4335
}
26✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc