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

typeorm / typeorm / 20153290793

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

push

github

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

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

26912 of 32666 branches covered (82.39%)

Branch coverage included in aggregate %.

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

694 existing lines in 23 files now uncovered.

91350 of 113685 relevant lines covered (80.35%)

68942.63 hits per line

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

91.44
/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()
24,700✔
60
        this.driver = driver
24,700✔
61
        this.connection = driver.connection
24,700✔
62
        this.broadcaster = new Broadcaster(this)
24,700✔
63
        this.mode = mode
24,700✔
64
    }
24,700✔
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
24,700✔
84
        return Promise.resolve()
24,700✔
85
    }
24,700✔
86

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

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

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

18,516✔
135
        await this.broadcaster.broadcast("AfterTransactionStart")
18,516✔
136
    }
18,516✔
137

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

18,468✔
145
        if (!this.isTransactionActive) throw new TransactionNotStartedError()
18,468!
146

18,468✔
147
        await this.broadcaster.broadcast("BeforeTransactionCommit")
18,468✔
148

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

18,464✔
156
                    await this.broadcaster.broadcast("AfterTransactionCommit")
18,464✔
157

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

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

48✔
174
        if (!this.isTransactionActive) throw new TransactionNotStartedError()
48!
175

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

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

40✔
190
                    await this.broadcaster.broadcast("AfterTransactionRollback")
40✔
191

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

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

106,910✔
210
        const release = await this.lock.acquire()
106,910✔
211

106,910✔
212
        this.driver.connection.logger.logQuery(query, parameters, this)
106,910✔
213
        await this.broadcaster.broadcast("BeforeQuery", query, parameters)
106,910✔
214

106,910✔
215
        const broadcasterResult = new BroadcasterResult()
106,910✔
216

106,910✔
217
        try {
106,910✔
218
            const pool = await (this.mode === "slave"
106,910✔
219
                ? this.driver.obtainSlaveConnection()
106,910✔
220
                : this.driver.obtainMasterConnection())
106,910✔
221
            const request = new this.driver.mssql.Request(
106,910✔
222
                this.isTransactionActive ? this.databaseConnection : pool,
106,910✔
223
            )
106,910✔
224
            if (parameters && parameters.length) {
106,910✔
225
                parameters.forEach((parameter, index) => {
29,964✔
226
                    const parameterName = index.toString()
70,554✔
227
                    if (InstanceChecker.isMssqlParameter(parameter)) {
70,554✔
228
                        const mssqlParameter =
52,892✔
229
                            this.mssqlParameterToNativeParameter(parameter)
52,892✔
230
                        if (mssqlParameter) {
52,892✔
231
                            request.input(
52,828✔
232
                                parameterName,
52,828✔
233
                                mssqlParameter,
52,828✔
234
                                parameter.value,
52,828✔
235
                            )
52,828✔
236
                        } else {
52,892✔
237
                            request.input(parameterName, parameter.value)
64✔
238
                        }
64✔
239
                    } else {
70,554✔
240
                        request.input(parameterName, parameter)
17,662✔
241
                    }
17,662✔
242
                })
29,964✔
243
            }
29,964✔
244
            const queryStartTime = Date.now()
106,910✔
245

106,910✔
246
            const raw = await new Promise<any>((ok, fail) => {
106,910✔
247
                request.query(query, (err: any, raw: any) => {
106,910✔
248
                    // log slow queries if maxQueryExecution time is set
106,910✔
249
                    const maxQueryExecutionTime =
106,910✔
250
                        this.driver.options.maxQueryExecutionTime
106,910✔
251
                    const queryEndTime = Date.now()
106,910✔
252
                    const queryExecutionTime = queryEndTime - queryStartTime
106,910✔
253

106,910✔
254
                    this.broadcaster.broadcastAfterQueryEvent(
106,910✔
255
                        broadcasterResult,
106,910✔
256
                        query,
106,910✔
257
                        parameters,
106,910✔
258
                        true,
106,910✔
259
                        queryExecutionTime,
106,910✔
260
                        raw,
106,910✔
261
                        undefined,
106,910✔
262
                    )
106,910✔
263

106,910✔
264
                    if (
106,910✔
265
                        maxQueryExecutionTime &&
106,910!
266
                        queryExecutionTime > maxQueryExecutionTime
×
267
                    ) {
106,910!
268
                        this.driver.connection.logger.logQuerySlow(
×
269
                            queryExecutionTime,
×
270
                            query,
×
271
                            parameters,
×
272
                            this,
×
273
                        )
×
274
                    }
×
275

106,910✔
276
                    if (err) {
106,910✔
277
                        fail(new QueryFailedError(query, parameters, err))
16✔
278
                    }
16✔
279

106,910✔
280
                    ok(raw)
106,910✔
281
                })
106,910✔
282
            })
106,910✔
283

106,894✔
284
            const result = new QueryResult()
106,894✔
285

106,894✔
286
            if (raw?.hasOwnProperty("recordset")) {
106,910✔
287
                result.records = raw.recordset
106,894✔
288
            }
106,894✔
289

106,894✔
290
            if (raw?.hasOwnProperty("rowsAffected")) {
106,910✔
291
                result.affected = raw.rowsAffected[0]
106,894✔
292
            }
106,894✔
293

106,894✔
294
            const queryType = query.slice(0, query.indexOf(" "))
106,894✔
295
            switch (queryType) {
106,894✔
296
                case "DELETE":
106,910✔
297
                    // for DELETE query additionally return number of affected rows
260✔
298
                    result.raw = [raw.recordset, raw.rowsAffected[0]]
260✔
299
                    break
260✔
300
                default:
106,910✔
301
                    result.raw = raw.recordset
106,634✔
302
            }
106,910✔
303

106,894✔
304
            if (useStructuredResult) {
106,910✔
305
                return result
30,964✔
306
            } else {
106,910✔
307
                return result.raw
75,930✔
308
            }
75,930✔
309
        } catch (err) {
106,910✔
310
            this.driver.connection.logger.logQueryError(
16✔
311
                err,
16✔
312
                query,
16✔
313
                parameters,
16✔
314
                this,
16✔
315
            )
16✔
316
            this.broadcaster.broadcastAfterQueryEvent(
16✔
317
                broadcasterResult,
16✔
318
                query,
16✔
319
                parameters,
16✔
320
                false,
16✔
321
                undefined,
16✔
322
                undefined,
16✔
323
                err,
16✔
324
            )
16✔
325

16✔
326
            throw err
16✔
327
        } finally {
106,910!
328
            await broadcasterResult.wait()
106,910✔
329

106,910✔
330
            release()
106,910✔
331
        }
106,910✔
332
    }
106,910✔
333

26✔
334
    /**
26✔
335
     * Returns raw data stream.
26✔
336
     */
26✔
337
    async stream(
26✔
338
        query: string,
2✔
339
        parameters?: any[],
2✔
340
        onEnd?: Function,
2✔
341
        onError?: Function,
2✔
342
    ): Promise<ReadStream> {
2✔
343
        if (this.isReleased) throw new QueryRunnerAlreadyReleasedError()
2!
344

2✔
345
        const release = await this.lock.acquire()
2✔
346

2✔
347
        this.driver.connection.logger.logQuery(query, parameters, this)
2✔
348
        const pool = await (this.mode === "slave"
2✔
349
            ? this.driver.obtainSlaveConnection()
2!
350
            : this.driver.obtainMasterConnection())
2✔
351
        const request = new this.driver.mssql.Request(
2✔
352
            this.isTransactionActive ? this.databaseConnection : pool,
2!
353
        )
2✔
354
        if (parameters && parameters.length) {
2!
355
            parameters.forEach((parameter, index) => {
×
356
                const parameterName = index.toString()
×
357
                if (InstanceChecker.isMssqlParameter(parameter)) {
×
358
                    request.input(
×
359
                        parameterName,
×
360
                        this.mssqlParameterToNativeParameter(parameter),
×
361
                        parameter.value,
×
362
                    )
×
363
                } else {
×
364
                    request.input(parameterName, parameter)
×
365
                }
×
366
            })
×
367
        }
×
368

2✔
369
        request.query(query)
2✔
370

2✔
371
        const streamRequest = request.toReadableStream()
2✔
372

2✔
373
        streamRequest.on("error", (err: any) => {
2✔
374
            release()
×
375
            this.driver.connection.logger.logQueryError(
×
376
                err,
×
377
                query,
×
378
                parameters,
×
379
                this,
×
380
            )
×
381
        })
2✔
382

2✔
383
        streamRequest.on("end", () => {
2✔
384
            release()
2✔
385
        })
2✔
386

2✔
387
        if (onEnd) {
2!
388
            streamRequest.on("end", onEnd)
×
389
        }
×
390

2✔
391
        if (onError) {
2!
392
            streamRequest.on("error", onError)
×
393
        }
×
394

2✔
395
        return streamRequest
2✔
396
    }
2✔
397

26✔
398
    /**
26✔
399
     * Returns all available database names including system databases.
26✔
400
     */
26✔
401
    async getDatabases(): Promise<string[]> {
26✔
402
        const results: ObjectLiteral[] = await this.query(`EXEC sp_databases`)
×
403
        return results.map((result) => result["DATABASE_NAME"])
×
404
    }
×
405

26✔
406
    /**
26✔
407
     * Returns all available schema names including system schemas.
26✔
408
     * If database parameter specified, returns schemas of that database.
26✔
409
     */
26✔
410
    async getSchemas(database?: string): Promise<string[]> {
26✔
411
        const query = database
×
412
            ? `SELECT * FROM "${database}"."sys"."schema"`
×
413
            : `SELECT * FROM "sys"."schemas"`
×
414
        const results: ObjectLiteral[] = await this.query(query)
×
415
        return results.map((result) => result["name"])
×
416
    }
×
417

26✔
418
    /**
26✔
419
     * Checks if database with the given name exist.
26✔
420
     */
26✔
421
    async hasDatabase(database: string): Promise<boolean> {
26✔
422
        const result = await this.query(
2,888✔
423
            `SELECT DB_ID('${database}') as "db_id"`,
2,888✔
424
        )
2,888✔
425
        const dbId = result[0]["db_id"]
2,888✔
426
        return !!dbId
2,888✔
427
    }
2,888✔
428

26✔
429
    /**
26✔
430
     * Loads currently using database
26✔
431
     */
26✔
432
    async getCurrentDatabase(): Promise<string> {
26✔
433
        const currentDBQuery = await this.query(`SELECT DB_NAME() AS "db_name"`)
3,660✔
434
        return currentDBQuery[0]["db_name"]
3,660✔
435
    }
3,660✔
436

26✔
437
    /**
26✔
438
     * Checks if schema with the given name exist.
26✔
439
     */
26✔
440
    async hasSchema(schema: string): Promise<boolean> {
26✔
441
        const result = await this.query(
6✔
442
            `SELECT SCHEMA_ID('${schema}') as "schema_id"`,
6✔
443
        )
6✔
444
        const schemaId = result[0]["schema_id"]
6✔
445
        return !!schemaId
6✔
446
    }
6✔
447

26✔
448
    /**
26✔
449
     * Loads currently using database schema
26✔
450
     */
26✔
451
    async getCurrentSchema(): Promise<string> {
26✔
452
        const currentSchemaQuery = await this.query(
4,560✔
453
            `SELECT SCHEMA_NAME() AS "schema_name"`,
4,560✔
454
        )
4,560✔
455
        return currentSchemaQuery[0]["schema_name"]
4,560✔
456
    }
4,560✔
457

26✔
458
    /**
26✔
459
     * Checks if table with the given name exist in the database.
26✔
460
     */
26✔
461
    async hasTable(tableOrName: Table | string): Promise<boolean> {
26✔
462
        const parsedTableName = this.driver.parseTableName(tableOrName)
3,114✔
463

3,114✔
464
        if (!parsedTableName.database) {
3,114!
465
            parsedTableName.database = await this.getCurrentDatabase()
×
466
        }
×
467

3,114✔
468
        if (!parsedTableName.schema) {
3,114!
469
            parsedTableName.schema = await this.getCurrentSchema()
×
470
        }
×
471

3,114✔
472
        const sql = `SELECT * FROM "${parsedTableName.database}"."INFORMATION_SCHEMA"."TABLES" WHERE "TABLE_NAME" = '${parsedTableName.tableName}' AND "TABLE_SCHEMA" = '${parsedTableName.schema}'`
3,114✔
473
        const result = await this.query(sql)
3,114✔
474
        return result.length ? true : false
3,114✔
475
    }
3,114✔
476

26✔
477
    /**
26✔
478
     * Checks if column exist in the table.
26✔
479
     */
26✔
480
    async hasColumn(
26✔
481
        tableOrName: Table | string,
8✔
482
        columnName: string,
8✔
483
    ): Promise<boolean> {
8✔
484
        const parsedTableName = this.driver.parseTableName(tableOrName)
8✔
485

8✔
486
        if (!parsedTableName.database) {
8!
487
            parsedTableName.database = await this.getCurrentDatabase()
×
488
        }
×
489

8✔
490
        if (!parsedTableName.schema) {
8!
491
            parsedTableName.schema = await this.getCurrentSchema()
×
492
        }
×
493

8✔
494
        const sql = `SELECT * FROM "${parsedTableName.database}"."INFORMATION_SCHEMA"."COLUMNS" WHERE "TABLE_NAME" = '${parsedTableName.tableName}' AND "TABLE_SCHEMA" = '${parsedTableName.schema}' AND "COLUMN_NAME" = '${columnName}'`
8✔
495
        const result = await this.query(sql)
8✔
496
        return result.length ? true : false
8✔
497
    }
8✔
498

26✔
499
    /**
26✔
500
     * Creates a new database.
26✔
501
     */
26✔
502
    async createDatabase(
26✔
503
        database: string,
18✔
504
        ifNotExist?: boolean,
18✔
505
    ): Promise<void> {
18✔
506
        const up = ifNotExist
18✔
507
            ? `IF DB_ID('${database}') IS NULL CREATE DATABASE "${database}"`
18✔
508
            : `CREATE DATABASE "${database}"`
18!
509
        const down = `DROP DATABASE "${database}"`
18✔
510
        await this.executeQueries(new Query(up), new Query(down))
18✔
511
    }
18✔
512

26✔
513
    /**
26✔
514
     * Drops database.
26✔
515
     */
26✔
516
    async dropDatabase(database: string, ifExist?: boolean): Promise<void> {
26✔
517
        const up = ifExist
4✔
518
            ? `IF DB_ID('${database}') IS NOT NULL DROP DATABASE "${database}"`
4✔
519
            : `DROP DATABASE "${database}"`
4✔
520
        const down = `CREATE DATABASE "${database}"`
4✔
521
        await this.executeQueries(new Query(up), new Query(down))
4✔
522
    }
4✔
523

26✔
524
    /**
26✔
525
     * Creates table schema.
26✔
526
     * If database name also specified (e.g. 'dbName.schemaName') schema will be created in specified database.
26✔
527
     */
26✔
528
    async createSchema(
26✔
529
        schemaPath: string,
28✔
530
        ifNotExist?: boolean,
28✔
531
    ): Promise<void> {
28✔
532
        const upQueries: Query[] = []
28✔
533
        const downQueries: Query[] = []
28✔
534

28✔
535
        if (schemaPath.indexOf(".") === -1) {
28✔
536
            const upQuery = ifNotExist
14✔
537
                ? `IF SCHEMA_ID('${schemaPath}') IS NULL BEGIN EXEC ('CREATE SCHEMA "${schemaPath}"') END`
14✔
538
                : `CREATE SCHEMA "${schemaPath}"`
14!
539
            upQueries.push(new Query(upQuery))
14✔
540
            downQueries.push(new Query(`DROP SCHEMA "${schemaPath}"`))
14✔
541
        } else {
14✔
542
            const dbName = schemaPath.split(".")[0]
14✔
543
            const schema = schemaPath.split(".")[1]
14✔
544
            const currentDB = await this.getCurrentDatabase()
14✔
545
            upQueries.push(new Query(`USE "${dbName}"`))
14✔
546
            downQueries.push(new Query(`USE "${currentDB}"`))
14✔
547

14✔
548
            const upQuery = ifNotExist
14✔
549
                ? `IF SCHEMA_ID('${schema}') IS NULL BEGIN EXEC ('CREATE SCHEMA "${schema}"') END`
14✔
550
                : `CREATE SCHEMA "${schema}"`
14!
551
            upQueries.push(new Query(upQuery))
14✔
552
            downQueries.push(new Query(`DROP SCHEMA "${schema}"`))
14✔
553

14✔
554
            upQueries.push(new Query(`USE "${currentDB}"`))
14✔
555
            downQueries.push(new Query(`USE "${dbName}"`))
14✔
556
        }
14✔
557

28✔
558
        await this.executeQueries(upQueries, downQueries)
28✔
559
    }
28✔
560

26✔
561
    /**
26✔
562
     * Drops table schema.
26✔
563
     * If database name also specified (e.g. 'dbName.schemaName') schema will be dropped in specified database.
26✔
564
     */
26✔
565
    async dropSchema(schemaPath: string, ifExist?: boolean): Promise<void> {
26✔
566
        const upQueries: Query[] = []
2✔
567
        const downQueries: Query[] = []
2✔
568

2✔
569
        if (schemaPath.indexOf(".") === -1) {
2✔
570
            const upQuery = ifExist
2✔
571
                ? `IF SCHEMA_ID('${schemaPath}') IS NULL BEGIN EXEC ('DROP SCHEMA "${schemaPath}"') END`
2!
572
                : `DROP SCHEMA "${schemaPath}"`
2✔
573
            upQueries.push(new Query(upQuery))
2✔
574
            downQueries.push(new Query(`CREATE SCHEMA "${schemaPath}"`))
2✔
575
        } else {
2!
576
            const dbName = schemaPath.split(".")[0]
×
577
            const schema = schemaPath.split(".")[1]
×
578
            const currentDB = await this.getCurrentDatabase()
×
579
            upQueries.push(new Query(`USE "${dbName}"`))
×
580
            downQueries.push(new Query(`USE "${currentDB}"`))
×
581

×
582
            const upQuery = ifExist
×
583
                ? `IF SCHEMA_ID('${schema}') IS NULL BEGIN EXEC ('DROP SCHEMA "${schema}"') END`
×
584
                : `DROP SCHEMA "${schema}"`
×
585
            upQueries.push(new Query(upQuery))
×
586
            downQueries.push(new Query(`CREATE SCHEMA "${schema}"`))
×
587

×
588
            upQueries.push(new Query(`USE "${currentDB}"`))
×
589
            downQueries.push(new Query(`USE "${dbName}"`))
×
590
        }
×
591

2✔
592
        await this.executeQueries(upQueries, downQueries)
2✔
593
    }
2✔
594

26✔
595
    /**
26✔
596
     * Creates a new table.
26✔
597
     */
26✔
598
    async createTable(
26✔
599
        table: Table,
9,992✔
600
        ifNotExist: boolean = false,
9,992✔
601
        createForeignKeys: boolean = true,
9,992✔
602
        createIndices: boolean = true,
9,992✔
603
    ): Promise<void> {
9,992✔
604
        if (ifNotExist) {
9,992✔
605
            const isTableExist = await this.hasTable(table)
66✔
606
            if (isTableExist) return Promise.resolve()
66✔
607
        }
66✔
608
        const upQueries: Query[] = []
9,988✔
609
        const downQueries: Query[] = []
9,988✔
610

9,988✔
611
        upQueries.push(this.createTableSql(table, createForeignKeys))
9,988✔
612
        downQueries.push(this.dropTableSql(table))
9,988✔
613

9,988✔
614
        // if createForeignKeys is true, we must drop created foreign keys in down query.
9,988✔
615
        // createTable does not need separate method to create foreign keys, because it create fk's in the same query with table creation.
9,988✔
616
        if (createForeignKeys)
9,988✔
617
            table.foreignKeys.forEach((foreignKey) =>
9,992✔
618
                downQueries.push(this.dropForeignKeySql(table, foreignKey)),
110✔
619
            )
110✔
620

9,988✔
621
        if (createIndices) {
9,988✔
622
            table.indices.forEach((index) => {
9,988✔
623
                // new index may be passed without name. In this case we generate index name manually.
4,292✔
624
                if (!index.name)
4,292✔
625
                    index.name = this.connection.namingStrategy.indexName(
4,292✔
626
                        table,
6✔
627
                        index.columnNames,
6✔
628
                        index.where,
6✔
629
                    )
6✔
630
                upQueries.push(this.createIndexSql(table, index))
4,292✔
631
                downQueries.push(this.dropIndexSql(table, index))
4,292✔
632
            })
9,988✔
633
        }
9,988✔
634

9,988✔
635
        // if table have column with generated type, we must add the expression to the metadata table
9,988✔
636
        const generatedColumns = table.columns.filter(
9,988✔
637
            (column) => column.generatedType && column.asExpression,
9,988✔
638
        )
9,988✔
639

9,988✔
640
        for (const column of generatedColumns) {
9,992✔
641
            const parsedTableName = this.driver.parseTableName(table)
56✔
642

56✔
643
            if (!parsedTableName.schema) {
56!
644
                parsedTableName.schema = await this.getCurrentSchema()
×
645
            }
×
646

56✔
647
            const insertQuery = this.insertTypeormMetadataSql({
56✔
648
                database: parsedTableName.database,
56✔
649
                schema: parsedTableName.schema,
56✔
650
                table: parsedTableName.tableName,
56✔
651
                type: MetadataTableType.GENERATED_COLUMN,
56✔
652
                name: column.name,
56✔
653
                value: column.asExpression,
56✔
654
            })
56✔
655

56✔
656
            const deleteQuery = this.deleteTypeormMetadataSql({
56✔
657
                database: parsedTableName.database,
56✔
658
                schema: parsedTableName.schema,
56✔
659
                table: parsedTableName.tableName,
56✔
660
                type: MetadataTableType.GENERATED_COLUMN,
56✔
661
                name: column.name,
56✔
662
            })
56✔
663

56✔
664
            upQueries.push(insertQuery)
56✔
665
            downQueries.push(deleteQuery)
56✔
666
        }
56✔
667

9,988✔
668
        await this.executeQueries(upQueries, downQueries)
9,988✔
669
    }
9,988✔
670

26✔
671
    /**
26✔
672
     * Drops the table.
26✔
673
     */
26✔
674
    async dropTable(
26✔
675
        tableOrName: Table | string,
24✔
676
        ifExist?: boolean,
24✔
677
        dropForeignKeys: boolean = true,
24✔
678
        dropIndices: boolean = true,
24✔
679
    ): Promise<void> {
24✔
680
        if (ifExist) {
24✔
681
            const isTableExist = await this.hasTable(tableOrName)
4✔
682
            if (!isTableExist) return Promise.resolve()
4!
683
        }
4✔
684

24✔
685
        // if dropTable called with dropForeignKeys = true, we must create foreign keys in down query.
24✔
686
        const createForeignKeys: boolean = dropForeignKeys
24✔
687
        const table = InstanceChecker.isTable(tableOrName)
24✔
688
            ? tableOrName
24✔
689
            : await this.getCachedTable(tableOrName)
24✔
690
        const upQueries: Query[] = []
16✔
691
        const downQueries: Query[] = []
16✔
692

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

16✔
696
        if (dropIndices) {
24✔
697
            table.indices.forEach((index) => {
24✔
698
                upQueries.push(this.dropIndexSql(table, index))
2✔
699
                downQueries.push(this.createIndexSql(table, index))
2✔
700
            })
24✔
701
        }
24✔
702

24✔
703
        // if dropForeignKeys is true, we just drop the table, otherwise we also drop table foreign keys.
24✔
704
        // createTable does not need separate method to create foreign keys, because it create fk's in the same query with table creation.
24✔
705
        if (dropForeignKeys)
24✔
706
            table.foreignKeys.forEach((foreignKey) =>
24✔
707
                upQueries.push(this.dropForeignKeySql(table, foreignKey)),
20✔
708
            )
20✔
709

24✔
710
        upQueries.push(this.dropTableSql(table))
24✔
711
        downQueries.push(this.createTableSql(table, createForeignKeys))
24✔
712

24✔
713
        // if table had columns with generated type, we must remove the expression from the metadata table
24✔
714
        const generatedColumns = table.columns.filter(
24✔
715
            (column) => column.generatedType && column.asExpression,
24✔
716
        )
24✔
717

24✔
718
        for (const column of generatedColumns) {
24✔
719
            const parsedTableName = this.driver.parseTableName(table)
8✔
720

8✔
721
            if (!parsedTableName.schema) {
8!
722
                parsedTableName.schema = await this.getCurrentSchema()
×
723
            }
×
724

8✔
725
            const deleteQuery = this.deleteTypeormMetadataSql({
8✔
726
                database: parsedTableName.database,
8✔
727
                schema: parsedTableName.schema,
8✔
728
                table: parsedTableName.tableName,
8✔
729
                type: MetadataTableType.GENERATED_COLUMN,
8✔
730
                name: column.name,
8✔
731
            })
8✔
732

8✔
733
            const insertQuery = this.insertTypeormMetadataSql({
8✔
734
                database: parsedTableName.database,
8✔
735
                schema: parsedTableName.schema,
8✔
736
                table: parsedTableName.tableName,
8✔
737
                type: MetadataTableType.GENERATED_COLUMN,
8✔
738
                name: column.name,
8✔
739
                value: column.asExpression,
8✔
740
            })
8✔
741

8✔
742
            upQueries.push(deleteQuery)
8✔
743
            downQueries.push(insertQuery)
8✔
744
        }
8✔
745

24✔
746
        await this.executeQueries(upQueries, downQueries)
24✔
747
    }
24✔
748

26✔
749
    /**
26✔
750
     * Creates a new view.
26✔
751
     */
26✔
752
    async createView(
26✔
753
        view: View,
16✔
754
        syncWithMetadata: boolean = false,
16✔
755
    ): Promise<void> {
16✔
756
        const upQueries: Query[] = []
16✔
757
        const downQueries: Query[] = []
16✔
758
        upQueries.push(this.createViewSql(view))
16✔
759
        if (syncWithMetadata)
16✔
760
            upQueries.push(await this.insertViewDefinitionSql(view))
16✔
761
        downQueries.push(this.dropViewSql(view))
16✔
762
        if (syncWithMetadata)
16✔
763
            downQueries.push(await this.deleteViewDefinitionSql(view))
16✔
764
        await this.executeQueries(upQueries, downQueries)
16✔
765
    }
16✔
766

26✔
767
    /**
26✔
768
     * Drops the view.
26✔
769
     */
26✔
770
    async dropView(target: View | string): Promise<void> {
26✔
771
        const viewName = InstanceChecker.isView(target) ? target.name : target
×
772
        const view = await this.getCachedView(viewName)
×
773

×
774
        const upQueries: Query[] = []
×
775
        const downQueries: Query[] = []
×
776
        upQueries.push(await this.deleteViewDefinitionSql(view))
×
777
        upQueries.push(this.dropViewSql(view))
×
778
        downQueries.push(await this.insertViewDefinitionSql(view))
×
779
        downQueries.push(this.createViewSql(view))
×
780
        await this.executeQueries(upQueries, downQueries)
×
781
    }
×
782

26✔
783
    /**
26✔
784
     * Renames a table.
26✔
785
     */
26✔
786
    async renameTable(
26✔
787
        oldTableOrName: Table | string,
34✔
788
        newTableName: string,
34✔
789
    ): Promise<void> {
34✔
790
        const upQueries: Query[] = []
34✔
791
        const downQueries: Query[] = []
34✔
792
        const oldTable = InstanceChecker.isTable(oldTableOrName)
34✔
793
            ? oldTableOrName
34✔
794
            : await this.getCachedTable(oldTableOrName)
34✔
795
        const newTable = oldTable.clone()
30✔
796

30✔
797
        // we need database name and schema name to rename FK constraints
30✔
798
        let dbName: string | undefined = undefined
30✔
799
        let schemaName: string | undefined = undefined
30✔
800
        let oldTableName: string = oldTable.name
30✔
801
        const splittedName = oldTable.name.split(".")
30✔
802
        if (splittedName.length === 3) {
34✔
803
            dbName = splittedName[0]
4✔
804
            oldTableName = splittedName[2]
4✔
805
            if (splittedName[1] !== "") schemaName = splittedName[1]
4✔
806
        } else if (splittedName.length === 2) {
34!
807
            schemaName = splittedName[0]
×
808
            oldTableName = splittedName[1]
×
809
        }
×
810

34✔
811
        newTable.name = this.driver.buildTableName(
34✔
812
            newTableName,
34✔
813
            schemaName,
34✔
814
            dbName,
34✔
815
        )
34✔
816

34✔
817
        // if we have tables with database which differs from database specified in config, we must change currently used database.
34✔
818
        // This need because we can not rename objects from another database.
34✔
819
        const currentDB = await this.getCurrentDatabase()
34✔
820
        if (dbName && dbName !== currentDB) {
34✔
821
            upQueries.push(new Query(`USE "${dbName}"`))
4✔
822
            downQueries.push(new Query(`USE "${currentDB}"`))
4✔
823
        }
4✔
824

34✔
825
        // rename table
34✔
826
        upQueries.push(
34✔
827
            new Query(
34✔
828
                `EXEC sp_rename "${this.getTablePath(
34✔
829
                    oldTable,
34✔
830
                )}", "${newTableName}"`,
34✔
831
            ),
34✔
832
        )
34✔
833
        downQueries.push(
34✔
834
            new Query(
34✔
835
                `EXEC sp_rename "${this.getTablePath(
34✔
836
                    newTable,
34✔
837
                )}", "${oldTableName}"`,
34✔
838
            ),
34✔
839
        )
34✔
840

34✔
841
        // rename primary key constraint
34✔
842
        if (
34✔
843
            newTable.primaryColumns.length > 0 &&
34✔
844
            !newTable.primaryColumns[0].primaryKeyConstraintName
34✔
845
        ) {
34✔
846
            const columnNames = newTable.primaryColumns.map(
26✔
847
                (column) => column.name,
26✔
848
            )
26✔
849

26✔
850
            const oldPkName = this.connection.namingStrategy.primaryKeyName(
26✔
851
                oldTable,
26✔
852
                columnNames,
26✔
853
            )
26✔
854
            const newPkName = this.connection.namingStrategy.primaryKeyName(
26✔
855
                newTable,
26✔
856
                columnNames,
26✔
857
            )
26✔
858

26✔
859
            // rename primary constraint
26✔
860
            upQueries.push(
26✔
861
                new Query(
26✔
862
                    `EXEC sp_rename "${this.getTablePath(
26✔
863
                        newTable,
26✔
864
                    )}.${oldPkName}", "${newPkName}"`,
26✔
865
                ),
26✔
866
            )
26✔
867
            downQueries.push(
26✔
868
                new Query(
26✔
869
                    `EXEC sp_rename "${this.getTablePath(
26✔
870
                        newTable,
26✔
871
                    )}.${newPkName}", "${oldPkName}"`,
26✔
872
                ),
26✔
873
            )
26✔
874
        }
26✔
875

34✔
876
        // rename unique constraints
34✔
877
        newTable.uniques.forEach((unique) => {
34✔
878
            const oldUniqueName =
10✔
879
                this.connection.namingStrategy.uniqueConstraintName(
10✔
880
                    oldTable,
10✔
881
                    unique.columnNames,
10✔
882
                )
10✔
883

10✔
884
            // Skip renaming if Unique has user defined constraint name
10✔
885
            if (unique.name !== oldUniqueName) return
10✔
886

6✔
887
            // build new constraint name
6✔
888
            const newUniqueName =
6✔
889
                this.connection.namingStrategy.uniqueConstraintName(
6✔
890
                    newTable,
6✔
891
                    unique.columnNames,
6✔
892
                )
6✔
893

6✔
894
            // build queries
6✔
895
            upQueries.push(
6✔
896
                new Query(
6✔
897
                    `EXEC sp_rename "${this.getTablePath(newTable)}.${
6✔
898
                        unique.name
6✔
899
                    }", "${newUniqueName}"`,
6✔
900
                ),
6✔
901
            )
6✔
902
            downQueries.push(
6✔
903
                new Query(
6✔
904
                    `EXEC sp_rename "${this.getTablePath(
6✔
905
                        newTable,
6✔
906
                    )}.${newUniqueName}", "${unique.name}"`,
6✔
907
                ),
6✔
908
            )
6✔
909

6✔
910
            // replace constraint name
6✔
911
            unique.name = newUniqueName
6✔
912
        })
34✔
913

34✔
914
        // rename index constraints
34✔
915
        newTable.indices.forEach((index) => {
34✔
916
            const oldIndexName = this.connection.namingStrategy.indexName(
22✔
917
                oldTable,
22✔
918
                index.columnNames,
22✔
919
                index.where,
22✔
920
            )
22✔
921

22✔
922
            // Skip renaming if Index has user defined constraint name
22✔
923
            if (index.name !== oldIndexName) return
22✔
924

10✔
925
            // build new constraint name
10✔
926
            const newIndexName = this.connection.namingStrategy.indexName(
10✔
927
                newTable,
10✔
928
                index.columnNames,
10✔
929
                index.where,
10✔
930
            )
10✔
931

10✔
932
            // build queries
10✔
933
            upQueries.push(
10✔
934
                new Query(
10✔
935
                    `EXEC sp_rename "${this.getTablePath(newTable)}.${
10✔
936
                        index.name
10✔
937
                    }", "${newIndexName}", "INDEX"`,
10✔
938
                ),
10✔
939
            )
10✔
940
            downQueries.push(
10✔
941
                new Query(
10✔
942
                    `EXEC sp_rename "${this.getTablePath(
10✔
943
                        newTable,
10✔
944
                    )}.${newIndexName}", "${index.name}", "INDEX"`,
10✔
945
                ),
10✔
946
            )
10✔
947

10✔
948
            // replace constraint name
10✔
949
            index.name = newIndexName
10✔
950
        })
34✔
951

34✔
952
        // rename foreign key constraints
34✔
953
        newTable.foreignKeys.forEach((foreignKey) => {
34✔
954
            const oldForeignKeyName =
18✔
955
                this.connection.namingStrategy.foreignKeyName(
18✔
956
                    oldTable,
18✔
957
                    foreignKey.columnNames,
18✔
958
                    this.getTablePath(foreignKey),
18✔
959
                    foreignKey.referencedColumnNames,
18✔
960
                )
18✔
961

18✔
962
            // Skip renaming if foreign key has user defined constraint name
18✔
963
            if (foreignKey.name !== oldForeignKeyName) return
18✔
964

2✔
965
            // build new constraint name
2✔
966
            const newForeignKeyName =
2✔
967
                this.connection.namingStrategy.foreignKeyName(
2✔
968
                    newTable,
2✔
969
                    foreignKey.columnNames,
2✔
970
                    this.getTablePath(foreignKey),
2✔
971
                    foreignKey.referencedColumnNames,
2✔
972
                )
2✔
973

2✔
974
            // build queries
2✔
975
            upQueries.push(
2✔
976
                new Query(
2✔
977
                    `EXEC sp_rename "${this.buildForeignKeyName(
2✔
978
                        foreignKey.name!,
2✔
979
                        schemaName,
2✔
980
                        dbName,
2✔
981
                    )}", "${newForeignKeyName}"`,
2✔
982
                ),
2✔
983
            )
2✔
984
            downQueries.push(
2✔
985
                new Query(
2✔
986
                    `EXEC sp_rename "${this.buildForeignKeyName(
2✔
987
                        newForeignKeyName,
2✔
988
                        schemaName,
2✔
989
                        dbName,
2✔
990
                    )}", "${foreignKey.name}"`,
2✔
991
                ),
2✔
992
            )
2✔
993

2✔
994
            // replace constraint name
2✔
995
            foreignKey.name = newForeignKeyName
2✔
996
        })
34✔
997

34✔
998
        // change currently used database back to default db.
34✔
999
        if (dbName && dbName !== currentDB) {
34✔
1000
            upQueries.push(new Query(`USE "${currentDB}"`))
4✔
1001
            downQueries.push(new Query(`USE "${dbName}"`))
4✔
1002
        }
4✔
1003

34✔
1004
        await this.executeQueries(upQueries, downQueries)
34✔
1005

34✔
1006
        // rename old table and replace it in cached tabled;
34✔
1007
        oldTable.name = newTable.name
34✔
1008
        this.replaceCachedTable(oldTable, newTable)
34✔
1009
    }
34✔
1010

26✔
1011
    /**
26✔
1012
     * Creates a new column from the column in the table.
26✔
1013
     */
26✔
1014
    async addColumn(
26✔
1015
        tableOrName: Table | string,
74✔
1016
        column: TableColumn,
74✔
1017
    ): Promise<void> {
74✔
1018
        const table = InstanceChecker.isTable(tableOrName)
74✔
1019
            ? tableOrName
74✔
1020
            : await this.getCachedTable(tableOrName)
74✔
1021
        const clonedTable = table.clone()
4✔
1022
        const upQueries: Query[] = []
4✔
1023
        const downQueries: Query[] = []
4✔
1024

4✔
1025
        upQueries.push(
4✔
1026
            new Query(
4✔
1027
                `ALTER TABLE ${this.escapePath(
4✔
1028
                    table,
4✔
1029
                )} ADD ${this.buildCreateColumnSql(
4✔
1030
                    table,
4✔
1031
                    column,
4✔
1032
                    false,
4✔
1033
                    true,
4✔
1034
                )}`,
4✔
1035
            ),
4✔
1036
        )
4✔
1037
        downQueries.push(
4✔
1038
            new Query(
4✔
1039
                `ALTER TABLE ${this.escapePath(table)} DROP COLUMN "${
4✔
1040
                    column.name
4✔
1041
                }"`,
4✔
1042
            ),
4✔
1043
        )
4✔
1044

4✔
1045
        // create or update primary key constraint
4✔
1046
        if (column.isPrimary) {
74✔
1047
            const primaryColumns = clonedTable.primaryColumns
14✔
1048
            // if table already have primary key, me must drop it and recreate again
14✔
1049
            if (primaryColumns.length > 0) {
14✔
1050
                const pkName = primaryColumns[0].primaryKeyConstraintName
4✔
1051
                    ? primaryColumns[0].primaryKeyConstraintName
4!
1052
                    : this.connection.namingStrategy.primaryKeyName(
4✔
1053
                          clonedTable,
4✔
1054
                          primaryColumns.map((column) => column.name),
4✔
1055
                      )
4✔
1056

4✔
1057
                const columnNames = primaryColumns
4✔
1058
                    .map((column) => `"${column.name}"`)
4✔
1059
                    .join(", ")
4✔
1060

4✔
1061
                upQueries.push(
4✔
1062
                    new Query(
4✔
1063
                        `ALTER TABLE ${this.escapePath(
4✔
1064
                            table,
4✔
1065
                        )} DROP CONSTRAINT "${pkName}"`,
4✔
1066
                    ),
4✔
1067
                )
4✔
1068
                downQueries.push(
4✔
1069
                    new Query(
4✔
1070
                        `ALTER TABLE ${this.escapePath(
4✔
1071
                            table,
4✔
1072
                        )} ADD CONSTRAINT "${pkName}" PRIMARY KEY (${columnNames})`,
4✔
1073
                    ),
4✔
1074
                )
4✔
1075
            }
4✔
1076

14✔
1077
            primaryColumns.push(column)
14✔
1078
            const pkName = primaryColumns[0].primaryKeyConstraintName
14✔
1079
                ? primaryColumns[0].primaryKeyConstraintName
14!
1080
                : this.connection.namingStrategy.primaryKeyName(
14✔
1081
                      clonedTable,
14✔
1082
                      primaryColumns.map((column) => column.name),
14✔
1083
                  )
14✔
1084

14✔
1085
            const columnNames = primaryColumns
14✔
1086
                .map((column) => `"${column.name}"`)
14✔
1087
                .join(", ")
14✔
1088
            upQueries.push(
14✔
1089
                new Query(
14✔
1090
                    `ALTER TABLE ${this.escapePath(
14✔
1091
                        table,
14✔
1092
                    )} ADD CONSTRAINT "${pkName}" PRIMARY KEY (${columnNames})`,
14✔
1093
                ),
14✔
1094
            )
14✔
1095
            downQueries.push(
14✔
1096
                new Query(
14✔
1097
                    `ALTER TABLE ${this.escapePath(
14✔
1098
                        table,
14✔
1099
                    )} DROP CONSTRAINT "${pkName}"`,
14✔
1100
                ),
14✔
1101
            )
14✔
1102
        }
14✔
1103

74✔
1104
        // create column index
74✔
1105
        const columnIndex = clonedTable.indices.find(
74✔
1106
            (index) =>
74✔
1107
                index.columnNames.length === 1 &&
2✔
1108
                index.columnNames[0] === column.name,
74✔
1109
        )
74✔
1110
        if (columnIndex) {
74!
1111
            upQueries.push(this.createIndexSql(table, columnIndex))
×
1112
            downQueries.push(this.dropIndexSql(table, columnIndex))
×
1113
        }
×
1114

74✔
1115
        // create unique constraint
74✔
1116
        if (column.isUnique) {
74✔
1117
            const uniqueConstraint = new TableUnique({
6✔
1118
                name: this.connection.namingStrategy.uniqueConstraintName(
6✔
1119
                    table,
6✔
1120
                    [column.name],
6✔
1121
                ),
6✔
1122
                columnNames: [column.name],
6✔
1123
            })
6✔
1124
            clonedTable.uniques.push(uniqueConstraint)
6✔
1125
            upQueries.push(
6✔
1126
                new Query(
6✔
1127
                    `ALTER TABLE ${this.escapePath(table)} ADD CONSTRAINT "${
6✔
1128
                        uniqueConstraint.name
6✔
1129
                    }" UNIQUE ("${column.name}")`,
6✔
1130
                ),
6✔
1131
            )
6✔
1132
            downQueries.push(
6✔
1133
                new Query(
6✔
1134
                    `ALTER TABLE ${this.escapePath(table)} DROP CONSTRAINT "${
6✔
1135
                        uniqueConstraint.name
6✔
1136
                    }"`,
6✔
1137
                ),
6✔
1138
            )
6✔
1139
        }
6✔
1140

74✔
1141
        // remove default constraint
74✔
1142
        if (column.default !== null && column.default !== undefined) {
74✔
1143
            const defaultName =
10✔
1144
                this.connection.namingStrategy.defaultConstraintName(
10✔
1145
                    table,
10✔
1146
                    column.name,
10✔
1147
                )
10✔
1148
            downQueries.push(
10✔
1149
                new Query(
10✔
1150
                    `ALTER TABLE ${this.escapePath(
10✔
1151
                        table,
10✔
1152
                    )} DROP CONSTRAINT "${defaultName}"`,
10✔
1153
                ),
10✔
1154
            )
10✔
1155
        }
10✔
1156

74✔
1157
        if (column.generatedType && column.asExpression) {
74✔
1158
            const parsedTableName = this.driver.parseTableName(table)
6✔
1159

6✔
1160
            if (!parsedTableName.schema) {
6!
1161
                parsedTableName.schema = await this.getCurrentSchema()
×
1162
            }
×
1163

6✔
1164
            const insertQuery = this.insertTypeormMetadataSql({
6✔
1165
                database: parsedTableName.database,
6✔
1166
                schema: parsedTableName.schema,
6✔
1167
                table: parsedTableName.tableName,
6✔
1168
                type: MetadataTableType.GENERATED_COLUMN,
6✔
1169
                name: column.name,
6✔
1170
                value: column.asExpression,
6✔
1171
            })
6✔
1172

6✔
1173
            const deleteQuery = this.deleteTypeormMetadataSql({
6✔
1174
                database: parsedTableName.database,
6✔
1175
                schema: parsedTableName.schema,
6✔
1176
                table: parsedTableName.tableName,
6✔
1177
                type: MetadataTableType.GENERATED_COLUMN,
6✔
1178
                name: column.name,
6✔
1179
            })
6✔
1180

6✔
1181
            upQueries.push(insertQuery)
6✔
1182
            downQueries.push(deleteQuery)
6✔
1183
        }
6✔
1184

74✔
1185
        await this.executeQueries(upQueries, downQueries)
74✔
1186

70✔
1187
        clonedTable.addColumn(column)
70✔
1188
        this.replaceCachedTable(table, clonedTable)
70✔
1189
    }
70✔
1190

26✔
1191
    /**
26✔
1192
     * Creates a new columns from the column in the table.
26✔
1193
     */
26✔
1194
    async addColumns(
26✔
1195
        tableOrName: Table | string,
12✔
1196
        columns: TableColumn[],
12✔
1197
    ): Promise<void> {
12✔
1198
        for (const column of columns) {
12✔
1199
            await this.addColumn(tableOrName, column)
14✔
1200
        }
12✔
1201
    }
10✔
1202

26✔
1203
    /**
26✔
1204
     * Renames column in the given table.
26✔
1205
     */
26✔
1206
    async renameColumn(
26✔
1207
        tableOrName: Table | string,
28✔
1208
        oldTableColumnOrName: TableColumn | string,
28✔
1209
        newTableColumnOrName: TableColumn | string,
28✔
1210
    ): Promise<void> {
28✔
1211
        const table = InstanceChecker.isTable(tableOrName)
28✔
1212
            ? tableOrName
28✔
1213
            : await this.getCachedTable(tableOrName)
28✔
1214
        const oldColumn = InstanceChecker.isTableColumn(oldTableColumnOrName)
4✔
1215
            ? oldTableColumnOrName
28✔
1216
            : table.columns.find((c) => c.name === oldTableColumnOrName)
28✔
1217
        if (!oldColumn)
28✔
1218
            throw new TypeORMError(
28!
1219
                `Column "${oldTableColumnOrName}" was not found in the "${table.name}" table.`,
×
1220
            )
×
1221

28✔
1222
        let newColumn: TableColumn | undefined = undefined
28✔
1223
        if (InstanceChecker.isTableColumn(newTableColumnOrName)) {
28✔
1224
            newColumn = newTableColumnOrName
18✔
1225
        } else {
28✔
1226
            newColumn = oldColumn.clone()
10✔
1227
            newColumn.name = newTableColumnOrName
10✔
1228
        }
10✔
1229

28✔
1230
        await this.changeColumn(table, oldColumn, newColumn)
28✔
1231
    }
28✔
1232

26✔
1233
    /**
26✔
1234
     * Changes a column in the table.
26✔
1235
     */
26✔
1236
    async changeColumn(
26✔
1237
        tableOrName: Table | string,
102✔
1238
        oldTableColumnOrName: TableColumn | string,
102✔
1239
        newColumn: TableColumn,
102✔
1240
    ): Promise<void> {
102✔
1241
        const table = InstanceChecker.isTable(tableOrName)
102✔
1242
            ? tableOrName
102✔
1243
            : await this.getCachedTable(tableOrName)
102!
1244
        let clonedTable = table.clone()
×
1245
        const upQueries: Query[] = []
×
1246
        const downQueries: Query[] = []
×
1247

×
1248
        const oldColumn = InstanceChecker.isTableColumn(oldTableColumnOrName)
×
1249
            ? oldTableColumnOrName
102✔
1250
            : table.columns.find(
102!
1251
                  (column) => column.name === oldTableColumnOrName,
×
1252
              )
102✔
1253
        if (!oldColumn)
102✔
1254
            throw new TypeORMError(
102!
1255
                `Column "${oldTableColumnOrName}" was not found in the "${table.name}" table.`,
×
1256
            )
×
1257

102✔
1258
        if (
102✔
1259
            (newColumn.isGenerated !== oldColumn.isGenerated &&
102✔
1260
                newColumn.generationStrategy !== "uuid") ||
102✔
1261
            newColumn.type !== oldColumn.type ||
102✔
1262
            newColumn.length !== oldColumn.length ||
102✔
1263
            newColumn.asExpression !== oldColumn.asExpression ||
102✔
1264
            newColumn.generatedType !== oldColumn.generatedType
52✔
1265
        ) {
102✔
1266
            // SQL Server does not support changing of IDENTITY column, so we must drop column and recreate it again.
50✔
1267
            // Also, we recreate column if column type changed
50✔
1268
            await this.dropColumn(table, oldColumn)
50✔
1269
            await this.addColumn(table, newColumn)
50✔
1270

50✔
1271
            // update cloned table
50✔
1272
            clonedTable = table.clone()
50✔
1273
        } else {
102✔
1274
            if (newColumn.name !== oldColumn.name) {
52✔
1275
                // we need database name and schema name to rename FK constraints
28✔
1276
                let dbName: string | undefined = undefined
28✔
1277
                let schemaName: string | undefined = undefined
28✔
1278
                const splittedName = table.name.split(".")
28✔
1279
                if (splittedName.length === 3) {
28✔
1280
                    dbName = splittedName[0]
4✔
1281
                    if (splittedName[1] !== "") schemaName = splittedName[1]
4✔
1282
                } else if (splittedName.length === 2) {
28!
1283
                    schemaName = splittedName[0]
×
1284
                }
×
1285

28✔
1286
                // if we have tables with database which differs from database specified in config, we must change currently used database.
28✔
1287
                // This need because we can not rename objects from another database.
28✔
1288
                const currentDB = await this.getCurrentDatabase()
28✔
1289
                if (dbName && dbName !== currentDB) {
28✔
1290
                    upQueries.push(new Query(`USE "${dbName}"`))
4✔
1291
                    downQueries.push(new Query(`USE "${currentDB}"`))
4✔
1292
                }
4✔
1293

28✔
1294
                // rename the column
28✔
1295
                upQueries.push(
28✔
1296
                    new Query(
28✔
1297
                        `EXEC sp_rename "${this.getTablePath(table)}.${
28✔
1298
                            oldColumn.name
28✔
1299
                        }", "${newColumn.name}"`,
28✔
1300
                    ),
28✔
1301
                )
28✔
1302
                downQueries.push(
28✔
1303
                    new Query(
28✔
1304
                        `EXEC sp_rename "${this.getTablePath(table)}.${
28✔
1305
                            newColumn.name
28✔
1306
                        }", "${oldColumn.name}"`,
28✔
1307
                    ),
28✔
1308
                )
28✔
1309

28✔
1310
                // rename column primary key constraint
28✔
1311
                if (
28✔
1312
                    oldColumn.isPrimary === true &&
28✔
1313
                    !oldColumn.primaryKeyConstraintName
6✔
1314
                ) {
28✔
1315
                    const primaryColumns = clonedTable.primaryColumns
2✔
1316

2✔
1317
                    // build old primary constraint name
2✔
1318
                    const columnNames = primaryColumns.map(
2✔
1319
                        (column) => column.name,
2✔
1320
                    )
2✔
1321
                    const oldPkName =
2✔
1322
                        this.connection.namingStrategy.primaryKeyName(
2✔
1323
                            clonedTable,
2✔
1324
                            columnNames,
2✔
1325
                        )
2✔
1326

2✔
1327
                    // replace old column name with new column name
2✔
1328
                    columnNames.splice(columnNames.indexOf(oldColumn.name), 1)
2✔
1329
                    columnNames.push(newColumn.name)
2✔
1330

2✔
1331
                    // build new primary constraint name
2✔
1332
                    const newPkName =
2✔
1333
                        this.connection.namingStrategy.primaryKeyName(
2✔
1334
                            clonedTable,
2✔
1335
                            columnNames,
2✔
1336
                        )
2✔
1337

2✔
1338
                    // rename primary constraint
2✔
1339
                    upQueries.push(
2✔
1340
                        new Query(
2✔
1341
                            `EXEC sp_rename "${this.getTablePath(
2✔
1342
                                clonedTable,
2✔
1343
                            )}.${oldPkName}", "${newPkName}"`,
2✔
1344
                        ),
2✔
1345
                    )
2✔
1346
                    downQueries.push(
2✔
1347
                        new Query(
2✔
1348
                            `EXEC sp_rename "${this.getTablePath(
2✔
1349
                                clonedTable,
2✔
1350
                            )}.${newPkName}", "${oldPkName}"`,
2✔
1351
                        ),
2✔
1352
                    )
2✔
1353
                }
2✔
1354

28✔
1355
                // rename index constraints
28✔
1356
                clonedTable.findColumnIndices(oldColumn).forEach((index) => {
28✔
1357
                    const oldIndexName =
6✔
1358
                        this.connection.namingStrategy.indexName(
6✔
1359
                            clonedTable,
6✔
1360
                            index.columnNames,
6✔
1361
                            index.where,
6✔
1362
                        )
6✔
1363

6✔
1364
                    // Skip renaming if Index has user defined constraint name
6✔
1365
                    if (index.name !== oldIndexName) return
6✔
1366

2✔
1367
                    // build new constraint name
2✔
1368
                    index.columnNames.splice(
2✔
1369
                        index.columnNames.indexOf(oldColumn.name),
2✔
1370
                        1,
2✔
1371
                    )
2✔
1372
                    index.columnNames.push(newColumn.name)
2✔
1373
                    const newIndexName =
2✔
1374
                        this.connection.namingStrategy.indexName(
2✔
1375
                            clonedTable,
2✔
1376
                            index.columnNames,
2✔
1377
                            index.where,
2✔
1378
                        )
2✔
1379

2✔
1380
                    // build queries
2✔
1381
                    upQueries.push(
2✔
1382
                        new Query(
2✔
1383
                            `EXEC sp_rename "${this.getTablePath(
2✔
1384
                                clonedTable,
2✔
1385
                            )}.${index.name}", "${newIndexName}", "INDEX"`,
2✔
1386
                        ),
2✔
1387
                    )
2✔
1388
                    downQueries.push(
2✔
1389
                        new Query(
2✔
1390
                            `EXEC sp_rename "${this.getTablePath(
2✔
1391
                                clonedTable,
2✔
1392
                            )}.${newIndexName}", "${index.name}", "INDEX"`,
2✔
1393
                        ),
2✔
1394
                    )
2✔
1395

2✔
1396
                    // replace constraint name
2✔
1397
                    index.name = newIndexName
2✔
1398
                })
28✔
1399

28✔
1400
                // rename foreign key constraints
28✔
1401
                clonedTable
28✔
1402
                    .findColumnForeignKeys(oldColumn)
28✔
1403
                    .forEach((foreignKey) => {
28✔
1404
                        const foreignKeyName =
2✔
1405
                            this.connection.namingStrategy.foreignKeyName(
2✔
1406
                                clonedTable,
2✔
1407
                                foreignKey.columnNames,
2✔
1408
                                this.getTablePath(foreignKey),
2✔
1409
                                foreignKey.referencedColumnNames,
2✔
1410
                            )
2✔
1411

2✔
1412
                        // Skip renaming if foreign key has user defined constraint name
2✔
1413
                        if (foreignKey.name !== foreignKeyName) return
2!
1414

2✔
1415
                        // build new constraint name
2✔
1416
                        foreignKey.columnNames.splice(
2✔
1417
                            foreignKey.columnNames.indexOf(oldColumn.name),
2✔
1418
                            1,
2✔
1419
                        )
2✔
1420
                        foreignKey.columnNames.push(newColumn.name)
2✔
1421
                        const newForeignKeyName =
2✔
1422
                            this.connection.namingStrategy.foreignKeyName(
2✔
1423
                                clonedTable,
2✔
1424
                                foreignKey.columnNames,
2✔
1425
                                this.getTablePath(foreignKey),
2✔
1426
                                foreignKey.referencedColumnNames,
2✔
1427
                            )
2✔
1428

2✔
1429
                        // build queries
2✔
1430
                        upQueries.push(
2✔
1431
                            new Query(
2✔
1432
                                `EXEC sp_rename "${this.buildForeignKeyName(
2✔
1433
                                    foreignKey.name!,
2✔
1434
                                    schemaName,
2✔
1435
                                    dbName,
2✔
1436
                                )}", "${newForeignKeyName}"`,
2✔
1437
                            ),
2✔
1438
                        )
2✔
1439
                        downQueries.push(
2✔
1440
                            new Query(
2✔
1441
                                `EXEC sp_rename "${this.buildForeignKeyName(
2✔
1442
                                    newForeignKeyName,
2✔
1443
                                    schemaName,
2✔
1444
                                    dbName,
2✔
1445
                                )}", "${foreignKey.name}"`,
2✔
1446
                            ),
2✔
1447
                        )
2✔
1448

2✔
1449
                        // replace constraint name
2✔
1450
                        foreignKey.name = newForeignKeyName
2✔
1451
                    })
28✔
1452

28✔
1453
                // rename check constraints
28✔
1454
                clonedTable.findColumnChecks(oldColumn).forEach((check) => {
28✔
1455
                    // build new constraint name
×
1456
                    check.columnNames!.splice(
×
1457
                        check.columnNames!.indexOf(oldColumn.name),
×
1458
                        1,
×
1459
                    )
×
1460
                    check.columnNames!.push(newColumn.name)
×
1461
                    const newCheckName =
×
1462
                        this.connection.namingStrategy.checkConstraintName(
×
1463
                            clonedTable,
×
1464
                            check.expression!,
×
1465
                        )
×
1466

×
1467
                    // build queries
×
1468
                    upQueries.push(
×
1469
                        new Query(
×
1470
                            `EXEC sp_rename "${this.getTablePath(
×
1471
                                clonedTable,
×
1472
                            )}.${check.name}", "${newCheckName}"`,
×
1473
                        ),
×
1474
                    )
×
1475
                    downQueries.push(
×
1476
                        new Query(
×
1477
                            `EXEC sp_rename "${this.getTablePath(
×
1478
                                clonedTable,
×
1479
                            )}.${newCheckName}", "${check.name}"`,
×
1480
                        ),
×
1481
                    )
×
1482

×
1483
                    // replace constraint name
×
1484
                    check.name = newCheckName
×
1485
                })
28✔
1486

28✔
1487
                // rename unique constraints
28✔
1488
                clonedTable.findColumnUniques(oldColumn).forEach((unique) => {
28✔
1489
                    const oldUniqueName =
12✔
1490
                        this.connection.namingStrategy.uniqueConstraintName(
12✔
1491
                            clonedTable,
12✔
1492
                            unique.columnNames,
12✔
1493
                        )
12✔
1494

12✔
1495
                    // Skip renaming if Unique has user defined constraint name
12✔
1496
                    if (unique.name !== oldUniqueName) return
12✔
1497

8✔
1498
                    // build new constraint name
8✔
1499
                    unique.columnNames.splice(
8✔
1500
                        unique.columnNames.indexOf(oldColumn.name),
8✔
1501
                        1,
8✔
1502
                    )
8✔
1503
                    unique.columnNames.push(newColumn.name)
8✔
1504
                    const newUniqueName =
8✔
1505
                        this.connection.namingStrategy.uniqueConstraintName(
8✔
1506
                            clonedTable,
8✔
1507
                            unique.columnNames,
8✔
1508
                        )
8✔
1509

8✔
1510
                    // build queries
8✔
1511
                    upQueries.push(
8✔
1512
                        new Query(
8✔
1513
                            `EXEC sp_rename "${this.getTablePath(
8✔
1514
                                clonedTable,
8✔
1515
                            )}.${unique.name}", "${newUniqueName}"`,
8✔
1516
                        ),
8✔
1517
                    )
8✔
1518
                    downQueries.push(
8✔
1519
                        new Query(
8✔
1520
                            `EXEC sp_rename "${this.getTablePath(
8✔
1521
                                clonedTable,
8✔
1522
                            )}.${newUniqueName}", "${unique.name}"`,
8✔
1523
                        ),
8✔
1524
                    )
8✔
1525

8✔
1526
                    // replace constraint name
8✔
1527
                    unique.name = newUniqueName
8✔
1528
                })
28✔
1529

28✔
1530
                // rename default constraints
28✔
1531
                if (
28✔
1532
                    oldColumn.default !== null &&
28✔
1533
                    oldColumn.default !== undefined
28✔
1534
                ) {
28✔
1535
                    const oldDefaultName =
4✔
1536
                        this.connection.namingStrategy.defaultConstraintName(
4✔
1537
                            table,
4✔
1538
                            oldColumn.name,
4✔
1539
                        )
4✔
1540
                    const newDefaultName =
4✔
1541
                        this.connection.namingStrategy.defaultConstraintName(
4✔
1542
                            table,
4✔
1543
                            newColumn.name,
4✔
1544
                        )
4✔
1545

4✔
1546
                    upQueries.push(
4✔
1547
                        new Query(
4✔
1548
                            `ALTER TABLE ${this.escapePath(
4✔
1549
                                table,
4✔
1550
                            )} DROP CONSTRAINT "${oldDefaultName}"`,
4✔
1551
                        ),
4✔
1552
                    )
4✔
1553
                    downQueries.push(
4✔
1554
                        new Query(
4✔
1555
                            `ALTER TABLE ${this.escapePath(
4✔
1556
                                table,
4✔
1557
                            )} ADD CONSTRAINT "${oldDefaultName}" DEFAULT ${
4✔
1558
                                oldColumn.default
4✔
1559
                            } FOR "${newColumn.name}"`,
4✔
1560
                        ),
4✔
1561
                    )
4✔
1562

4✔
1563
                    upQueries.push(
4✔
1564
                        new Query(
4✔
1565
                            `ALTER TABLE ${this.escapePath(
4✔
1566
                                table,
4✔
1567
                            )} ADD CONSTRAINT "${newDefaultName}" DEFAULT ${
4✔
1568
                                oldColumn.default
4✔
1569
                            } FOR "${newColumn.name}"`,
4✔
1570
                        ),
4✔
1571
                    )
4✔
1572
                    downQueries.push(
4✔
1573
                        new Query(
4✔
1574
                            `ALTER TABLE ${this.escapePath(
4✔
1575
                                table,
4✔
1576
                            )} DROP CONSTRAINT "${newDefaultName}"`,
4✔
1577
                        ),
4✔
1578
                    )
4✔
1579
                }
4✔
1580

28✔
1581
                // change currently used database back to default db.
28✔
1582
                if (dbName && dbName !== currentDB) {
28✔
1583
                    upQueries.push(new Query(`USE "${currentDB}"`))
4✔
1584
                    downQueries.push(new Query(`USE "${dbName}"`))
4✔
1585
                }
4✔
1586

28✔
1587
                // rename old column in the Table object
28✔
1588
                const oldTableColumn = clonedTable.columns.find(
28✔
1589
                    (column) => column.name === oldColumn.name,
28✔
1590
                )
28✔
1591
                clonedTable.columns[
28✔
1592
                    clonedTable.columns.indexOf(oldTableColumn!)
28✔
1593
                ].name = newColumn.name
28✔
1594
                oldColumn.name = newColumn.name
28✔
1595
            }
28✔
1596

52✔
1597
            if (
52✔
1598
                this.isColumnChanged(oldColumn, newColumn, false, false, false)
52✔
1599
            ) {
52!
1600
                upQueries.push(
×
1601
                    new Query(
×
1602
                        `ALTER TABLE ${this.escapePath(
×
1603
                            table,
×
1604
                        )} ALTER COLUMN ${this.buildCreateColumnSql(
×
1605
                            table,
×
1606
                            newColumn,
×
1607
                            true,
×
1608
                            false,
×
1609
                            true,
×
1610
                        )}`,
×
1611
                    ),
×
1612
                )
×
1613
                downQueries.push(
×
1614
                    new Query(
×
1615
                        `ALTER TABLE ${this.escapePath(
×
1616
                            table,
×
1617
                        )} ALTER COLUMN ${this.buildCreateColumnSql(
×
1618
                            table,
×
1619
                            oldColumn,
×
1620
                            true,
×
1621
                            false,
×
1622
                            true,
×
1623
                        )}`,
×
1624
                    ),
×
1625
                )
×
1626
            }
×
1627

52✔
1628
            if (this.isEnumChanged(oldColumn, newColumn)) {
52✔
1629
                const oldExpression = this.getEnumExpression(oldColumn)
2✔
1630
                const oldCheck = new TableCheck({
2✔
1631
                    name: this.connection.namingStrategy.checkConstraintName(
2✔
1632
                        table,
2✔
1633
                        oldExpression,
2✔
1634
                        true,
2✔
1635
                    ),
2✔
1636
                    expression: oldExpression,
2✔
1637
                })
2✔
1638

2✔
1639
                const newExpression = this.getEnumExpression(newColumn)
2✔
1640
                const newCheck = new TableCheck({
2✔
1641
                    name: this.connection.namingStrategy.checkConstraintName(
2✔
1642
                        table,
2✔
1643
                        newExpression,
2✔
1644
                        true,
2✔
1645
                    ),
2✔
1646
                    expression: newExpression,
2✔
1647
                })
2✔
1648

2✔
1649
                upQueries.push(this.dropCheckConstraintSql(table, oldCheck))
2✔
1650
                upQueries.push(this.createCheckConstraintSql(table, newCheck))
2✔
1651

2✔
1652
                downQueries.push(this.dropCheckConstraintSql(table, newCheck))
2✔
1653
                downQueries.push(this.createCheckConstraintSql(table, oldCheck))
2✔
1654
            }
2✔
1655

52✔
1656
            if (newColumn.isPrimary !== oldColumn.isPrimary) {
52✔
1657
                const primaryColumns = clonedTable.primaryColumns
6✔
1658

6✔
1659
                // if primary column state changed, we must always drop existed constraint.
6✔
1660
                if (primaryColumns.length > 0) {
6✔
1661
                    const pkName = primaryColumns[0].primaryKeyConstraintName
6✔
1662
                        ? primaryColumns[0].primaryKeyConstraintName
6!
1663
                        : this.connection.namingStrategy.primaryKeyName(
6✔
1664
                              clonedTable,
6✔
1665
                              primaryColumns.map((column) => column.name),
6✔
1666
                          )
6✔
1667

6✔
1668
                    const columnNames = primaryColumns
6✔
1669
                        .map((column) => `"${column.name}"`)
6✔
1670
                        .join(", ")
6✔
1671
                    upQueries.push(
6✔
1672
                        new Query(
6✔
1673
                            `ALTER TABLE ${this.escapePath(
6✔
1674
                                table,
6✔
1675
                            )} DROP CONSTRAINT "${pkName}"`,
6✔
1676
                        ),
6✔
1677
                    )
6✔
1678
                    downQueries.push(
6✔
1679
                        new Query(
6✔
1680
                            `ALTER TABLE ${this.escapePath(
6✔
1681
                                table,
6✔
1682
                            )} ADD CONSTRAINT "${pkName}" PRIMARY KEY (${columnNames})`,
6✔
1683
                        ),
6✔
1684
                    )
6✔
1685
                }
6✔
1686

6✔
1687
                if (newColumn.isPrimary === true) {
6✔
1688
                    primaryColumns.push(newColumn)
2✔
1689
                    // update column in table
2✔
1690
                    const column = clonedTable.columns.find(
2✔
1691
                        (column) => column.name === newColumn.name,
2✔
1692
                    )
2✔
1693
                    column!.isPrimary = true
2✔
1694
                    const pkName = primaryColumns[0].primaryKeyConstraintName
2✔
1695
                        ? primaryColumns[0].primaryKeyConstraintName
2!
1696
                        : this.connection.namingStrategy.primaryKeyName(
2✔
1697
                              clonedTable,
2✔
1698
                              primaryColumns.map((column) => column.name),
2✔
1699
                          )
2✔
1700

2✔
1701
                    const columnNames = primaryColumns
2✔
1702
                        .map((column) => `"${column.name}"`)
2✔
1703
                        .join(", ")
2✔
1704
                    upQueries.push(
2✔
1705
                        new Query(
2✔
1706
                            `ALTER TABLE ${this.escapePath(
2✔
1707
                                table,
2✔
1708
                            )} ADD CONSTRAINT "${pkName}" PRIMARY KEY (${columnNames})`,
2✔
1709
                        ),
2✔
1710
                    )
2✔
1711
                    downQueries.push(
2✔
1712
                        new Query(
2✔
1713
                            `ALTER TABLE ${this.escapePath(
2✔
1714
                                table,
2✔
1715
                            )} DROP CONSTRAINT "${pkName}"`,
2✔
1716
                        ),
2✔
1717
                    )
2✔
1718
                } else {
6✔
1719
                    const primaryColumn = primaryColumns.find(
4✔
1720
                        (c) => c.name === newColumn.name,
4✔
1721
                    )
4✔
1722
                    primaryColumns.splice(
4✔
1723
                        primaryColumns.indexOf(primaryColumn!),
4✔
1724
                        1,
4✔
1725
                    )
4✔
1726

4✔
1727
                    // update column in table
4✔
1728
                    const column = clonedTable.columns.find(
4✔
1729
                        (column) => column.name === newColumn.name,
4✔
1730
                    )
4✔
1731
                    column!.isPrimary = false
4✔
1732

4✔
1733
                    // if we have another primary keys, we must recreate constraint.
4✔
1734
                    if (primaryColumns.length > 0) {
4✔
1735
                        const pkName = primaryColumns[0]
2✔
1736
                            .primaryKeyConstraintName
2✔
1737
                            ? primaryColumns[0].primaryKeyConstraintName
2!
1738
                            : this.connection.namingStrategy.primaryKeyName(
2✔
1739
                                  clonedTable,
2✔
1740
                                  primaryColumns.map((column) => column.name),
2✔
1741
                              )
2✔
1742

2✔
1743
                        const columnNames = primaryColumns
2✔
1744
                            .map((column) => `"${column.name}"`)
2✔
1745
                            .join(", ")
2✔
1746
                        upQueries.push(
2✔
1747
                            new Query(
2✔
1748
                                `ALTER TABLE ${this.escapePath(
2✔
1749
                                    table,
2✔
1750
                                )} ADD CONSTRAINT "${pkName}" PRIMARY KEY (${columnNames})`,
2✔
1751
                            ),
2✔
1752
                        )
2✔
1753
                        downQueries.push(
2✔
1754
                            new Query(
2✔
1755
                                `ALTER TABLE ${this.escapePath(
2✔
1756
                                    table,
2✔
1757
                                )} DROP CONSTRAINT "${pkName}"`,
2✔
1758
                            ),
2✔
1759
                        )
2✔
1760
                    }
2✔
1761
                }
4✔
1762
            }
6✔
1763

52✔
1764
            if (newColumn.isUnique !== oldColumn.isUnique) {
52✔
1765
                if (newColumn.isUnique === true) {
2✔
1766
                    const uniqueConstraint = new TableUnique({
2✔
1767
                        name: this.connection.namingStrategy.uniqueConstraintName(
2✔
1768
                            table,
2✔
1769
                            [newColumn.name],
2✔
1770
                        ),
2✔
1771
                        columnNames: [newColumn.name],
2✔
1772
                    })
2✔
1773
                    clonedTable.uniques.push(uniqueConstraint)
2✔
1774
                    upQueries.push(
2✔
1775
                        new Query(
2✔
1776
                            `ALTER TABLE ${this.escapePath(
2✔
1777
                                table,
2✔
1778
                            )} ADD CONSTRAINT "${
2✔
1779
                                uniqueConstraint.name
2✔
1780
                            }" UNIQUE ("${newColumn.name}")`,
2✔
1781
                        ),
2✔
1782
                    )
2✔
1783
                    downQueries.push(
2✔
1784
                        new Query(
2✔
1785
                            `ALTER TABLE ${this.escapePath(
2✔
1786
                                table,
2✔
1787
                            )} DROP CONSTRAINT "${uniqueConstraint.name}"`,
2✔
1788
                        ),
2✔
1789
                    )
2✔
1790
                } else {
2!
1791
                    const uniqueConstraint = clonedTable.uniques.find(
×
1792
                        (unique) => {
×
1793
                            return (
×
1794
                                unique.columnNames.length === 1 &&
×
1795
                                !!unique.columnNames.find(
×
1796
                                    (columnName) =>
×
1797
                                        columnName === newColumn.name,
×
1798
                                )
×
1799
                            )
×
1800
                        },
×
1801
                    )
×
1802
                    clonedTable.uniques.splice(
×
1803
                        clonedTable.uniques.indexOf(uniqueConstraint!),
×
1804
                        1,
×
1805
                    )
×
1806
                    upQueries.push(
×
1807
                        new Query(
×
1808
                            `ALTER TABLE ${this.escapePath(
×
1809
                                table,
×
1810
                            )} DROP CONSTRAINT "${uniqueConstraint!.name}"`,
×
1811
                        ),
×
1812
                    )
×
1813
                    downQueries.push(
×
1814
                        new Query(
×
1815
                            `ALTER TABLE ${this.escapePath(
×
1816
                                table,
×
1817
                            )} ADD CONSTRAINT "${
×
1818
                                uniqueConstraint!.name
×
1819
                            }" UNIQUE ("${newColumn.name}")`,
×
1820
                        ),
×
1821
                    )
×
1822
                }
×
1823
            }
2✔
1824

52✔
1825
            if (newColumn.default !== oldColumn.default) {
52✔
1826
                // (note) if there is a previous default, we need to drop its constraint first
4✔
1827
                if (
4✔
1828
                    oldColumn.default !== null &&
4✔
1829
                    oldColumn.default !== undefined
4✔
1830
                ) {
4✔
1831
                    const defaultName =
2✔
1832
                        this.connection.namingStrategy.defaultConstraintName(
2✔
1833
                            table,
2✔
1834
                            oldColumn.name,
2✔
1835
                        )
2✔
1836
                    upQueries.push(
2✔
1837
                        new Query(
2✔
1838
                            `ALTER TABLE ${this.escapePath(
2✔
1839
                                table,
2✔
1840
                            )} DROP CONSTRAINT "${defaultName}"`,
2✔
1841
                        ),
2✔
1842
                    )
2✔
1843
                    downQueries.push(
2✔
1844
                        new Query(
2✔
1845
                            `ALTER TABLE ${this.escapePath(
2✔
1846
                                table,
2✔
1847
                            )} ADD CONSTRAINT "${defaultName}" DEFAULT ${
2✔
1848
                                oldColumn.default
2✔
1849
                            } FOR "${oldColumn.name}"`,
2✔
1850
                        ),
2✔
1851
                    )
2✔
1852
                }
2✔
1853

4✔
1854
                if (
4✔
1855
                    newColumn.default !== null &&
4✔
1856
                    newColumn.default !== undefined
4✔
1857
                ) {
4✔
1858
                    const defaultName =
4✔
1859
                        this.connection.namingStrategy.defaultConstraintName(
4✔
1860
                            table,
4✔
1861
                            newColumn.name,
4✔
1862
                        )
4✔
1863
                    upQueries.push(
4✔
1864
                        new Query(
4✔
1865
                            `ALTER TABLE ${this.escapePath(
4✔
1866
                                table,
4✔
1867
                            )} ADD CONSTRAINT "${defaultName}" DEFAULT ${
4✔
1868
                                newColumn.default
4✔
1869
                            } FOR "${newColumn.name}"`,
4✔
1870
                        ),
4✔
1871
                    )
4✔
1872
                    downQueries.push(
4✔
1873
                        new Query(
4✔
1874
                            `ALTER TABLE ${this.escapePath(
4✔
1875
                                table,
4✔
1876
                            )} DROP CONSTRAINT "${defaultName}"`,
4✔
1877
                        ),
4✔
1878
                    )
4✔
1879
                }
4✔
1880
            }
4✔
1881

52✔
1882
            await this.executeQueries(upQueries, downQueries)
52✔
1883
            this.replaceCachedTable(table, clonedTable)
52✔
1884
        }
52✔
1885
    }
102✔
1886

26✔
1887
    /**
26✔
1888
     * Changes a column in the table.
26✔
1889
     */
26✔
1890
    async changeColumns(
26✔
1891
        tableOrName: Table | string,
44✔
1892
        changedColumns: { newColumn: TableColumn; oldColumn: TableColumn }[],
44✔
1893
    ): Promise<void> {
44✔
1894
        for (const { oldColumn, newColumn } of changedColumns) {
44✔
1895
            await this.changeColumn(tableOrName, oldColumn, newColumn)
62✔
1896
        }
62✔
1897
    }
44✔
1898

26✔
1899
    /**
26✔
1900
     * Drops column in the table.
26✔
1901
     */
26✔
1902
    async dropColumn(
26✔
1903
        tableOrName: Table | string,
86✔
1904
        columnOrName: TableColumn | string,
86✔
1905
    ): Promise<void> {
86✔
1906
        const table = InstanceChecker.isTable(tableOrName)
86✔
1907
            ? tableOrName
86✔
1908
            : await this.getCachedTable(tableOrName)
86✔
1909
        const column = InstanceChecker.isTableColumn(columnOrName)
6✔
1910
            ? columnOrName
86✔
1911
            : table.findColumnByName(columnOrName)
86✔
1912
        if (!column)
86✔
1913
            throw new TypeORMError(
86✔
1914
                `Column "${columnOrName}" was not found in table "${table.name}"`,
2✔
1915
            )
2✔
1916

84✔
1917
        const clonedTable = table.clone()
84✔
1918
        const upQueries: Query[] = []
84✔
1919
        const downQueries: Query[] = []
84✔
1920

84✔
1921
        // drop primary key constraint
84✔
1922
        if (column.isPrimary) {
86✔
1923
            const pkName = column.primaryKeyConstraintName
14✔
1924
                ? column.primaryKeyConstraintName
14!
1925
                : this.connection.namingStrategy.primaryKeyName(
14✔
1926
                      clonedTable,
14✔
1927
                      clonedTable.primaryColumns.map((column) => column.name),
14✔
1928
                  )
14✔
1929

14✔
1930
            const columnNames = clonedTable.primaryColumns
14✔
1931
                .map((primaryColumn) => `"${primaryColumn.name}"`)
14✔
1932
                .join(", ")
14✔
1933

14✔
1934
            upQueries.push(
14✔
1935
                new Query(
14✔
1936
                    `ALTER TABLE ${this.escapePath(
14✔
1937
                        clonedTable,
14✔
1938
                    )} DROP CONSTRAINT "${pkName}"`,
14✔
1939
                ),
14✔
1940
            )
14✔
1941
            downQueries.push(
14✔
1942
                new Query(
14✔
1943
                    `ALTER TABLE ${this.escapePath(
14✔
1944
                        clonedTable,
14✔
1945
                    )} ADD CONSTRAINT "${pkName}" PRIMARY KEY (${columnNames})`,
14✔
1946
                ),
14✔
1947
            )
14✔
1948

14✔
1949
            // update column in table
14✔
1950
            const tableColumn = clonedTable.findColumnByName(column.name)
14✔
1951
            tableColumn!.isPrimary = false
14✔
1952

14✔
1953
            // if primary key have multiple columns, we must recreate it without dropped column
14✔
1954
            if (clonedTable.primaryColumns.length > 0) {
14✔
1955
                const pkName = clonedTable.primaryColumns[0]
2✔
1956
                    .primaryKeyConstraintName
2✔
1957
                    ? clonedTable.primaryColumns[0].primaryKeyConstraintName
2!
1958
                    : this.connection.namingStrategy.primaryKeyName(
2✔
1959
                          clonedTable,
2✔
1960
                          clonedTable.primaryColumns.map(
2✔
1961
                              (column) => column.name,
2✔
1962
                          ),
2✔
1963
                      )
2✔
1964

2✔
1965
                const columnNames = clonedTable.primaryColumns
2✔
1966
                    .map((primaryColumn) => `"${primaryColumn.name}"`)
2✔
1967
                    .join(", ")
2✔
1968
                upQueries.push(
2✔
1969
                    new Query(
2✔
1970
                        `ALTER TABLE ${this.escapePath(
2✔
1971
                            clonedTable,
2✔
1972
                        )} ADD CONSTRAINT "${pkName}" PRIMARY KEY (${columnNames})`,
2✔
1973
                    ),
2✔
1974
                )
2✔
1975
                downQueries.push(
2✔
1976
                    new Query(
2✔
1977
                        `ALTER TABLE ${this.escapePath(
2✔
1978
                            clonedTable,
2✔
1979
                        )} DROP CONSTRAINT "${pkName}"`,
2✔
1980
                    ),
2✔
1981
                )
2✔
1982
            }
2✔
1983
        }
14✔
1984

84✔
1985
        // drop column index
84✔
1986
        const columnIndex = clonedTable.indices.find(
84✔
1987
            (index) =>
84✔
1988
                index.columnNames.length === 1 &&
2✔
1989
                index.columnNames[0] === column.name,
84✔
1990
        )
84✔
1991
        if (columnIndex) {
86!
1992
            clonedTable.indices.splice(
×
1993
                clonedTable.indices.indexOf(columnIndex),
×
1994
                1,
×
1995
            )
×
1996
            upQueries.push(this.dropIndexSql(table, columnIndex))
×
1997
            downQueries.push(this.createIndexSql(table, columnIndex))
×
1998
        }
×
1999

84✔
2000
        // drop column check
84✔
2001
        const columnCheck = clonedTable.checks.find(
84✔
2002
            (check) =>
84✔
2003
                !!check.columnNames &&
32✔
2004
                check.columnNames.length === 1 &&
32✔
2005
                check.columnNames[0] === column.name,
84✔
2006
        )
84✔
2007
        if (columnCheck) {
86✔
2008
            clonedTable.checks.splice(
4✔
2009
                clonedTable.checks.indexOf(columnCheck),
4✔
2010
                1,
4✔
2011
            )
4✔
2012
            upQueries.push(this.dropCheckConstraintSql(table, columnCheck))
4✔
2013
            downQueries.push(this.createCheckConstraintSql(table, columnCheck))
4✔
2014
        }
4✔
2015

84✔
2016
        // drop column unique
84✔
2017
        const columnUnique = clonedTable.uniques.find(
84✔
2018
            (unique) =>
84✔
2019
                unique.columnNames.length === 1 &&
60✔
2020
                unique.columnNames[0] === column.name,
84✔
2021
        )
84✔
2022
        if (columnUnique) {
86✔
2023
            clonedTable.uniques.splice(
6✔
2024
                clonedTable.uniques.indexOf(columnUnique),
6✔
2025
                1,
6✔
2026
            )
6✔
2027
            upQueries.push(this.dropUniqueConstraintSql(table, columnUnique))
6✔
2028
            downQueries.push(
6✔
2029
                this.createUniqueConstraintSql(table, columnUnique),
6✔
2030
            )
6✔
2031
        }
6✔
2032

84✔
2033
        // drop default constraint
84✔
2034
        if (column.default !== null && column.default !== undefined) {
86✔
2035
            const defaultName =
12✔
2036
                this.connection.namingStrategy.defaultConstraintName(
12✔
2037
                    table,
12✔
2038
                    column.name,
12✔
2039
                )
12✔
2040
            upQueries.push(
12✔
2041
                new Query(
12✔
2042
                    `ALTER TABLE ${this.escapePath(
12✔
2043
                        table,
12✔
2044
                    )} DROP CONSTRAINT "${defaultName}"`,
12✔
2045
                ),
12✔
2046
            )
12✔
2047
            downQueries.push(
12✔
2048
                new Query(
12✔
2049
                    `ALTER TABLE ${this.escapePath(
12✔
2050
                        table,
12✔
2051
                    )} ADD CONSTRAINT "${defaultName}" DEFAULT ${
12✔
2052
                        column.default
12✔
2053
                    } FOR "${column.name}"`,
12✔
2054
                ),
12✔
2055
            )
12✔
2056
        }
12✔
2057

84✔
2058
        if (column.generatedType && column.asExpression) {
86✔
2059
            const parsedTableName = this.driver.parseTableName(table)
8✔
2060

8✔
2061
            if (!parsedTableName.schema) {
8!
2062
                parsedTableName.schema = await this.getCurrentSchema()
×
2063
            }
×
2064

8✔
2065
            const deleteQuery = this.deleteTypeormMetadataSql({
8✔
2066
                database: parsedTableName.database,
8✔
2067
                schema: parsedTableName.schema,
8✔
2068
                table: parsedTableName.tableName,
8✔
2069
                type: MetadataTableType.GENERATED_COLUMN,
8✔
2070
                name: column.name,
8✔
2071
            })
8✔
2072
            const insertQuery = this.insertTypeormMetadataSql({
8✔
2073
                database: parsedTableName.database,
8✔
2074
                schema: parsedTableName.schema,
8✔
2075
                table: parsedTableName.tableName,
8✔
2076
                type: MetadataTableType.GENERATED_COLUMN,
8✔
2077
                name: column.name,
8✔
2078
                value: column.asExpression,
8✔
2079
            })
8✔
2080

8✔
2081
            upQueries.push(deleteQuery)
8✔
2082
            downQueries.push(insertQuery)
8✔
2083
        }
8✔
2084

84✔
2085
        upQueries.push(
84✔
2086
            new Query(
84✔
2087
                `ALTER TABLE ${this.escapePath(table)} DROP COLUMN "${
84✔
2088
                    column.name
84✔
2089
                }"`,
84✔
2090
            ),
84✔
2091
        )
84✔
2092
        downQueries.push(
84✔
2093
            new Query(
84✔
2094
                `ALTER TABLE ${this.escapePath(
84✔
2095
                    table,
84✔
2096
                )} ADD ${this.buildCreateColumnSql(
84✔
2097
                    table,
84✔
2098
                    column,
84✔
2099
                    false,
84✔
2100
                    false,
84✔
2101
                )}`,
84✔
2102
            ),
84✔
2103
        )
84✔
2104

84✔
2105
        await this.executeQueries(upQueries, downQueries)
84✔
2106

84✔
2107
        clonedTable.removeColumn(column)
84✔
2108
        this.replaceCachedTable(table, clonedTable)
84✔
2109
    }
84✔
2110

26✔
2111
    /**
26✔
2112
     * Drops the columns in the table.
26✔
2113
     */
26✔
2114
    async dropColumns(
26✔
2115
        tableOrName: Table | string,
10✔
2116
        columns: TableColumn[] | string[],
10✔
2117
    ): Promise<void> {
10✔
2118
        for (const column of [...columns]) {
10✔
2119
            await this.dropColumn(tableOrName, column)
26✔
2120
        }
26✔
2121
    }
10✔
2122

26✔
2123
    /**
26✔
2124
     * Creates a new primary key.
26✔
2125
     */
26✔
2126
    async createPrimaryKey(
26✔
2127
        tableOrName: Table | string,
4✔
2128
        columnNames: string[],
4✔
2129
        constraintName?: string,
4✔
2130
    ): Promise<void> {
4✔
2131
        const table = InstanceChecker.isTable(tableOrName)
4✔
2132
            ? tableOrName
4!
2133
            : await this.getCachedTable(tableOrName)
4✔
2134
        const clonedTable = table.clone()
4✔
2135

4✔
2136
        const up = this.createPrimaryKeySql(table, columnNames, constraintName)
4✔
2137

4✔
2138
        // mark columns as primary, because dropPrimaryKeySql build constraint name from table primary column names.
4✔
2139
        clonedTable.columns.forEach((column) => {
4✔
2140
            if (columnNames.find((columnName) => columnName === column.name))
10✔
2141
                column.isPrimary = true
10✔
2142
        })
4✔
2143
        const down = this.dropPrimaryKeySql(clonedTable)
4✔
2144

4✔
2145
        await this.executeQueries(up, down)
4✔
2146
        this.replaceCachedTable(table, clonedTable)
4✔
2147
    }
4✔
2148

26✔
2149
    /**
26✔
2150
     * Updates composite primary keys.
26✔
2151
     */
26✔
2152
    async updatePrimaryKeys(
26✔
2153
        tableOrName: Table | string,
6✔
2154
        columns: TableColumn[],
6✔
2155
    ): Promise<void> {
6✔
2156
        const table = InstanceChecker.isTable(tableOrName)
6✔
2157
            ? tableOrName
6✔
2158
            : await this.getCachedTable(tableOrName)
6!
2159
        const clonedTable = table.clone()
×
2160
        const columnNames = columns.map((column) => column.name)
✔
2161
        const upQueries: Query[] = []
×
2162
        const downQueries: Query[] = []
×
2163

×
2164
        // if table already have primary columns, we must drop them.
×
2165
        const primaryColumns = clonedTable.primaryColumns
×
2166
        if (primaryColumns.length > 0) {
6✔
2167
            const pkName = primaryColumns[0].primaryKeyConstraintName
6✔
2168
                ? primaryColumns[0].primaryKeyConstraintName
6!
2169
                : this.connection.namingStrategy.primaryKeyName(
6✔
2170
                      clonedTable,
6✔
2171
                      primaryColumns.map((column) => column.name),
6✔
2172
                  )
6✔
2173

6✔
2174
            const columnNamesString = primaryColumns
6✔
2175
                .map((column) => `"${column.name}"`)
6✔
2176
                .join(", ")
6✔
2177

6✔
2178
            upQueries.push(
6✔
2179
                new Query(
6✔
2180
                    `ALTER TABLE ${this.escapePath(
6✔
2181
                        table,
6✔
2182
                    )} DROP CONSTRAINT "${pkName}"`,
6✔
2183
                ),
6✔
2184
            )
6✔
2185
            downQueries.push(
6✔
2186
                new Query(
6✔
2187
                    `ALTER TABLE ${this.escapePath(
6✔
2188
                        table,
6✔
2189
                    )} ADD CONSTRAINT "${pkName}" PRIMARY KEY (${columnNamesString})`,
6✔
2190
                ),
6✔
2191
            )
6✔
2192
        }
6✔
2193

6✔
2194
        // update columns in table.
6✔
2195
        clonedTable.columns
6✔
2196
            .filter((column) => columnNames.indexOf(column.name) !== -1)
6✔
2197
            .forEach((column) => (column.isPrimary = true))
6✔
2198

6✔
2199
        const pkName = primaryColumns[0].primaryKeyConstraintName
6✔
2200
            ? primaryColumns[0].primaryKeyConstraintName
6!
2201
            : this.connection.namingStrategy.primaryKeyName(
6✔
2202
                  clonedTable,
6✔
2203
                  columnNames,
6✔
2204
              )
6✔
2205

6✔
2206
        const columnNamesString = columnNames
6✔
2207
            .map((columnName) => `"${columnName}"`)
6✔
2208
            .join(", ")
6✔
2209

6✔
2210
        upQueries.push(
6✔
2211
            new Query(
6✔
2212
                `ALTER TABLE ${this.escapePath(
6✔
2213
                    table,
6✔
2214
                )} ADD CONSTRAINT "${pkName}" PRIMARY KEY (${columnNamesString})`,
6✔
2215
            ),
6✔
2216
        )
6✔
2217
        downQueries.push(
6✔
2218
            new Query(
6✔
2219
                `ALTER TABLE ${this.escapePath(
6✔
2220
                    table,
6✔
2221
                )} DROP CONSTRAINT "${pkName}"`,
6✔
2222
            ),
6✔
2223
        )
6✔
2224

6✔
2225
        await this.executeQueries(upQueries, downQueries)
6✔
2226
        this.replaceCachedTable(table, clonedTable)
6✔
2227
    }
6✔
2228

26✔
2229
    /**
26✔
2230
     * Drops a primary key.
26✔
2231
     */
26✔
2232
    async dropPrimaryKey(
26✔
2233
        tableOrName: Table | string,
6✔
2234
        constraintName?: string,
6✔
2235
    ): Promise<void> {
6✔
2236
        const table = InstanceChecker.isTable(tableOrName)
6✔
2237
            ? tableOrName
6✔
2238
            : await this.getCachedTable(tableOrName)
6!
2239
        const up = this.dropPrimaryKeySql(table)
×
2240
        const down = this.createPrimaryKeySql(
×
2241
            table,
×
2242
            table.primaryColumns.map((column) => column.name),
✔
2243
            constraintName,
×
2244
        )
×
2245
        await this.executeQueries(up, down)
×
2246
        table.primaryColumns.forEach((column) => {
6✔
2247
            column.isPrimary = false
6✔
2248
        })
6✔
2249
    }
6✔
2250

26✔
2251
    /**
26✔
2252
     * Creates a new unique constraint.
26✔
2253
     */
26✔
2254
    async createUniqueConstraint(
26✔
2255
        tableOrName: Table | string,
16✔
2256
        uniqueConstraint: TableUnique,
16✔
2257
    ): Promise<void> {
16✔
2258
        const table = InstanceChecker.isTable(tableOrName)
16✔
2259
            ? tableOrName
16✔
2260
            : await this.getCachedTable(tableOrName)
16✔
2261

12✔
2262
        // new unique constraint may be passed without name. In this case we generate unique name manually.
12✔
2263
        if (!uniqueConstraint.name)
12✔
2264
            uniqueConstraint.name =
16✔
2265
                this.connection.namingStrategy.uniqueConstraintName(
4✔
2266
                    table,
4✔
2267
                    uniqueConstraint.columnNames,
4✔
2268
                )
4✔
2269

16✔
2270
        const up = this.createUniqueConstraintSql(table, uniqueConstraint)
16✔
2271
        const down = this.dropUniqueConstraintSql(table, uniqueConstraint)
16✔
2272
        await this.executeQueries(up, down)
16✔
2273
        table.addUniqueConstraint(uniqueConstraint)
16✔
2274
    }
16✔
2275

26✔
2276
    /**
26✔
2277
     * Creates a new unique constraints.
26✔
2278
     */
26✔
2279
    async createUniqueConstraints(
26✔
2280
        tableOrName: Table | string,
6✔
2281
        uniqueConstraints: TableUnique[],
6✔
2282
    ): Promise<void> {
6✔
2283
        const promises = uniqueConstraints.map((uniqueConstraint) =>
6✔
2284
            this.createUniqueConstraint(tableOrName, uniqueConstraint),
6✔
2285
        )
6✔
2286
        await Promise.all(promises)
6✔
2287
    }
6✔
2288

26✔
2289
    /**
26✔
2290
     * Drops unique constraint.
26✔
2291
     */
26✔
2292
    async dropUniqueConstraint(
26✔
2293
        tableOrName: Table | string,
16✔
2294
        uniqueOrName: TableUnique | string,
16✔
2295
    ): Promise<void> {
16✔
2296
        const table = InstanceChecker.isTable(tableOrName)
16✔
2297
            ? tableOrName
16✔
2298
            : await this.getCachedTable(tableOrName)
16✔
2299
        const uniqueConstraint = InstanceChecker.isTableUnique(uniqueOrName)
8✔
2300
            ? uniqueOrName
16✔
2301
            : table.uniques.find((u) => u.name === uniqueOrName)
16!
2302
        if (!uniqueConstraint)
16✔
2303
            throw new TypeORMError(
16!
2304
                `Supplied unique constraint was not found in table ${table.name}`,
×
2305
            )
×
2306

16✔
2307
        const up = this.dropUniqueConstraintSql(table, uniqueConstraint)
16✔
2308
        const down = this.createUniqueConstraintSql(table, uniqueConstraint)
16✔
2309
        await this.executeQueries(up, down)
16✔
2310
        table.removeUniqueConstraint(uniqueConstraint)
16✔
2311
    }
16✔
2312

26✔
2313
    /**
26✔
2314
     * Drops unique constraints.
26✔
2315
     */
26✔
2316
    async dropUniqueConstraints(
26✔
2317
        tableOrName: Table | string,
8✔
2318
        uniqueConstraints: TableUnique[],
8✔
2319
    ): Promise<void> {
8✔
2320
        const promises = uniqueConstraints.map((uniqueConstraint) =>
8✔
2321
            this.dropUniqueConstraint(tableOrName, uniqueConstraint),
8✔
2322
        )
8✔
2323
        await Promise.all(promises)
8✔
2324
    }
8✔
2325

26✔
2326
    /**
26✔
2327
     * Creates a new check constraint.
26✔
2328
     */
26✔
2329
    async createCheckConstraint(
26✔
2330
        tableOrName: Table | string,
10✔
2331
        checkConstraint: TableCheck,
10✔
2332
    ): Promise<void> {
10✔
2333
        const table = InstanceChecker.isTable(tableOrName)
10✔
2334
            ? tableOrName
10✔
2335
            : await this.getCachedTable(tableOrName)
10✔
2336

6✔
2337
        // new unique constraint may be passed without name. In this case we generate unique name manually.
6✔
2338
        if (!checkConstraint.name)
6✔
2339
            checkConstraint.name =
6✔
2340
                this.connection.namingStrategy.checkConstraintName(
6✔
2341
                    table,
6✔
2342
                    checkConstraint.expression!,
6✔
2343
                )
6✔
2344

10✔
2345
        const up = this.createCheckConstraintSql(table, checkConstraint)
10✔
2346
        const down = this.dropCheckConstraintSql(table, checkConstraint)
10✔
2347
        await this.executeQueries(up, down)
10✔
2348
        table.addCheckConstraint(checkConstraint)
10✔
2349
    }
10✔
2350

26✔
2351
    /**
26✔
2352
     * Creates a new check constraints.
26✔
2353
     */
26✔
2354
    async createCheckConstraints(
26✔
2355
        tableOrName: Table | string,
4✔
2356
        checkConstraints: TableCheck[],
4✔
2357
    ): Promise<void> {
4✔
2358
        const promises = checkConstraints.map((checkConstraint) =>
4✔
2359
            this.createCheckConstraint(tableOrName, checkConstraint),
4✔
2360
        )
4✔
2361
        await Promise.all(promises)
4✔
2362
    }
4✔
2363

26✔
2364
    /**
26✔
2365
     * Drops check constraint.
26✔
2366
     */
26✔
2367
    async dropCheckConstraint(
26✔
2368
        tableOrName: Table | string,
6✔
2369
        checkOrName: TableCheck | string,
6✔
2370
    ): Promise<void> {
6✔
2371
        const table = InstanceChecker.isTable(tableOrName)
6✔
2372
            ? tableOrName
6✔
2373
            : await this.getCachedTable(tableOrName)
6!
2374
        const checkConstraint = InstanceChecker.isTableCheck(checkOrName)
×
2375
            ? checkOrName
6✔
2376
            : table.checks.find((c) => c.name === checkOrName)
6!
2377
        if (!checkConstraint)
6✔
2378
            throw new TypeORMError(
6!
2379
                `Supplied check constraint was not found in table ${table.name}`,
×
2380
            )
×
2381

6✔
2382
        const up = this.dropCheckConstraintSql(table, checkConstraint)
6✔
2383
        const down = this.createCheckConstraintSql(table, checkConstraint)
6✔
2384
        await this.executeQueries(up, down)
6✔
2385
        table.removeCheckConstraint(checkConstraint)
6✔
2386
    }
6✔
2387

26✔
2388
    /**
26✔
2389
     * Drops check constraints.
26✔
2390
     */
26✔
2391
    async dropCheckConstraints(
26✔
2392
        tableOrName: Table | string,
4✔
2393
        checkConstraints: TableCheck[],
4✔
2394
    ): Promise<void> {
4✔
2395
        const promises = checkConstraints.map((checkConstraint) =>
4✔
2396
            this.dropCheckConstraint(tableOrName, checkConstraint),
4✔
2397
        )
4✔
2398
        await Promise.all(promises)
4✔
2399
    }
4✔
2400

26✔
2401
    /**
26✔
2402
     * Creates a new exclusion constraint.
26✔
2403
     */
26✔
2404
    async createExclusionConstraint(
26✔
2405
        tableOrName: Table | string,
×
2406
        exclusionConstraint: TableExclusion,
×
2407
    ): Promise<void> {
×
2408
        throw new TypeORMError(
×
2409
            `SqlServer does not support exclusion constraints.`,
×
2410
        )
×
2411
    }
×
2412

26✔
2413
    /**
26✔
2414
     * Creates a new exclusion constraints.
26✔
2415
     */
26✔
2416
    async createExclusionConstraints(
26✔
2417
        tableOrName: Table | string,
×
2418
        exclusionConstraints: TableExclusion[],
×
2419
    ): Promise<void> {
×
2420
        throw new TypeORMError(
×
2421
            `SqlServer does not support exclusion constraints.`,
×
2422
        )
×
2423
    }
×
2424

26✔
2425
    /**
26✔
2426
     * Drops exclusion constraint.
26✔
2427
     */
26✔
2428
    async dropExclusionConstraint(
26✔
2429
        tableOrName: Table | string,
×
2430
        exclusionOrName: TableExclusion | string,
×
2431
    ): Promise<void> {
×
2432
        throw new TypeORMError(
×
2433
            `SqlServer does not support exclusion constraints.`,
×
2434
        )
×
2435
    }
×
2436

26✔
2437
    /**
26✔
2438
     * Drops exclusion constraints.
26✔
2439
     */
26✔
2440
    async dropExclusionConstraints(
26✔
2441
        tableOrName: Table | string,
×
2442
        exclusionConstraints: TableExclusion[],
×
2443
    ): Promise<void> {
×
2444
        throw new TypeORMError(
×
2445
            `SqlServer does not support exclusion constraints.`,
×
2446
        )
×
2447
    }
×
2448

26✔
2449
    /**
26✔
2450
     * Creates a new foreign key.
26✔
2451
     */
26✔
2452
    async createForeignKey(
26✔
2453
        tableOrName: Table | string,
6,602✔
2454
        foreignKey: TableForeignKey,
6,602✔
2455
    ): Promise<void> {
6,602✔
2456
        const table = InstanceChecker.isTable(tableOrName)
6,602✔
2457
            ? tableOrName
6,602✔
2458
            : await this.getCachedTable(tableOrName)
6,602✔
2459
        const metadata = this.connection.hasMetadata(table.name)
10✔
2460
            ? this.connection.getMetadata(table.name)
6,602✔
2461
            : undefined
6,602✔
2462

6,602✔
2463
        if (
6,602✔
2464
            metadata &&
6,602✔
2465
            metadata.treeParentRelation &&
6,602✔
2466
            metadata.treeParentRelation!.isTreeParent &&
6,602✔
2467
            metadata.foreignKeys.find(
776✔
2468
                (foreignKey) => foreignKey.onDelete !== "NO ACTION",
776✔
2469
            )
6,602✔
2470
        )
6,602✔
2471
            throw new TypeORMError(
6,602!
2472
                "SqlServer does not support options in TreeParent.",
×
2473
            )
×
2474

6,602✔
2475
        // new FK may be passed without name. In this case we generate FK name manually.
6,602✔
2476
        if (!foreignKey.name)
6,602✔
2477
            foreignKey.name = this.connection.namingStrategy.foreignKeyName(
6,602✔
2478
                table,
2✔
2479
                foreignKey.columnNames,
2✔
2480
                this.getTablePath(foreignKey),
2✔
2481
                foreignKey.referencedColumnNames,
2✔
2482
            )
2✔
2483

6,602✔
2484
        const up = this.createForeignKeySql(table, foreignKey)
6,602✔
2485
        const down = this.dropForeignKeySql(table, foreignKey)
6,602✔
2486
        await this.executeQueries(up, down)
6,602✔
2487
        table.addForeignKey(foreignKey)
6,602✔
2488
    }
6,602✔
2489

26✔
2490
    /**
26✔
2491
     * Creates a new foreign keys.
26✔
2492
     */
26✔
2493
    async createForeignKeys(
26✔
2494
        tableOrName: Table | string,
4,050✔
2495
        foreignKeys: TableForeignKey[],
4,050✔
2496
    ): Promise<void> {
4,050✔
2497
        const promises = foreignKeys.map((foreignKey) =>
4,050✔
2498
            this.createForeignKey(tableOrName, foreignKey),
4,050✔
2499
        )
4,050✔
2500
        await Promise.all(promises)
4,050✔
2501
    }
4,050✔
2502

26✔
2503
    /**
26✔
2504
     * Drops a foreign key from the table.
26✔
2505
     */
26✔
2506
    async dropForeignKey(
26✔
2507
        tableOrName: Table | string,
22✔
2508
        foreignKeyOrName: TableForeignKey | string,
22✔
2509
    ): Promise<void> {
22✔
2510
        const table = InstanceChecker.isTable(tableOrName)
22✔
2511
            ? tableOrName
22✔
2512
            : await this.getCachedTable(tableOrName)
22✔
2513
        const foreignKey = InstanceChecker.isTableForeignKey(foreignKeyOrName)
8✔
2514
            ? foreignKeyOrName
22✔
2515
            : table.foreignKeys.find((fk) => fk.name === foreignKeyOrName)
22!
2516
        if (!foreignKey)
22✔
2517
            throw new TypeORMError(
22!
2518
                `Supplied foreign key was not found in table ${table.name}`,
×
2519
            )
×
2520

22✔
2521
        const up = this.dropForeignKeySql(table, foreignKey)
22✔
2522
        const down = this.createForeignKeySql(table, foreignKey)
22✔
2523
        await this.executeQueries(up, down)
22✔
2524
        table.removeForeignKey(foreignKey)
22✔
2525
    }
22✔
2526

26✔
2527
    /**
26✔
2528
     * Drops a foreign keys from the table.
26✔
2529
     */
26✔
2530
    async dropForeignKeys(
26✔
2531
        tableOrName: Table | string,
14✔
2532
        foreignKeys: TableForeignKey[],
14✔
2533
    ): Promise<void> {
14✔
2534
        const promises = foreignKeys.map((foreignKey) =>
14✔
2535
            this.dropForeignKey(tableOrName, foreignKey),
14✔
2536
        )
14✔
2537
        await Promise.all(promises)
14✔
2538
    }
14✔
2539

26✔
2540
    /**
26✔
2541
     * Creates a new index.
26✔
2542
     */
26✔
2543
    async createIndex(
26✔
2544
        tableOrName: Table | string,
28✔
2545
        index: TableIndex,
28✔
2546
    ): Promise<void> {
28✔
2547
        const table = InstanceChecker.isTable(tableOrName)
28✔
2548
            ? tableOrName
28✔
2549
            : await this.getCachedTable(tableOrName)
28✔
2550

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

28✔
2554
        const up = this.createIndexSql(table, index)
28✔
2555
        const down = this.dropIndexSql(table, index)
28✔
2556
        await this.executeQueries(up, down)
28✔
2557
        table.addIndex(index)
28✔
2558
    }
28✔
2559

26✔
2560
    /**
26✔
2561
     * Creates a new indices
26✔
2562
     */
26✔
2563
    async createIndices(
26✔
2564
        tableOrName: Table | string,
14✔
2565
        indices: TableIndex[],
14✔
2566
    ): Promise<void> {
14✔
2567
        const promises = indices.map((index) =>
14✔
2568
            this.createIndex(tableOrName, index),
14✔
2569
        )
14✔
2570
        await Promise.all(promises)
14✔
2571
    }
14✔
2572

26✔
2573
    /**
26✔
2574
     * Drops an index.
26✔
2575
     */
26✔
2576
    async dropIndex(
26✔
2577
        tableOrName: Table | string,
32✔
2578
        indexOrName: TableIndex | string,
32✔
2579
    ): Promise<void> {
32✔
2580
        const table = InstanceChecker.isTable(tableOrName)
32✔
2581
            ? tableOrName
32✔
2582
            : await this.getCachedTable(tableOrName)
32✔
2583
        const index = InstanceChecker.isTableIndex(indexOrName)
10✔
2584
            ? indexOrName
32✔
2585
            : table.indices.find((i) => i.name === indexOrName)
32!
2586
        if (!index)
32✔
2587
            throw new TypeORMError(
32!
2588
                `Supplied index was not found in table ${table.name}`,
×
2589
            )
×
2590

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

32✔
2594
        const up = this.dropIndexSql(table, index)
32✔
2595
        const down = this.createIndexSql(table, index)
32✔
2596
        await this.executeQueries(up, down)
32✔
2597
        table.removeIndex(index)
32✔
2598
    }
32✔
2599

26✔
2600
    /**
26✔
2601
     * Drops an indices from the table.
26✔
2602
     */
26✔
2603
    async dropIndices(
26✔
2604
        tableOrName: Table | string,
4✔
2605
        indices: TableIndex[],
4✔
2606
    ): Promise<void> {
4✔
2607
        const promises = indices.map((index) =>
4✔
2608
            this.dropIndex(tableOrName, index),
4✔
2609
        )
4✔
2610
        await Promise.all(promises)
4✔
2611
    }
4✔
2612

26✔
2613
    /**
26✔
2614
     * Clears all table contents.
26✔
2615
     * Note: this operation uses SQL's TRUNCATE query which cannot be reverted in transactions.
26✔
2616
     */
26✔
2617
    async clearTable(tablePath: string): Promise<void> {
26✔
2618
        await this.query(`TRUNCATE TABLE ${this.escapePath(tablePath)}`)
4✔
2619
    }
4✔
2620

26✔
2621
    /**
26✔
2622
     * Removes all tables from the currently connected database.
26✔
2623
     */
26✔
2624
    async clearDatabase(database?: string): Promise<void> {
26✔
2625
        if (database) {
2,882✔
2626
            const isDatabaseExist = await this.hasDatabase(database)
2,882✔
2627
            if (!isDatabaseExist) return Promise.resolve()
2,882!
2628
        }
2,882✔
2629

2,882✔
2630
        const isAnotherTransactionActive = this.isTransactionActive
2,882✔
2631
        if (!isAnotherTransactionActive) await this.startTransaction()
2,882✔
2632
        try {
2,882✔
2633
            const allViewsSql = database
2,882✔
2634
                ? `SELECT * FROM "${database}"."INFORMATION_SCHEMA"."VIEWS"`
2,882✔
2635
                : `SELECT * FROM "INFORMATION_SCHEMA"."VIEWS"`
2,882!
2636
            const allViewsResults: ObjectLiteral[] =
2,882✔
2637
                await this.query(allViewsSql)
2,882✔
2638

2,882✔
2639
            await Promise.all(
2,882✔
2640
                allViewsResults.map((viewResult) => {
2,882✔
2641
                    // 'DROP VIEW' does not allow specifying the database name as a prefix to the object name.
16✔
2642
                    const dropTableSql = `DROP VIEW "${viewResult["TABLE_SCHEMA"]}"."${viewResult["TABLE_NAME"]}"`
16✔
2643
                    return this.query(dropTableSql)
16✔
2644
                }),
2,882✔
2645
            )
2,882✔
2646

2,882✔
2647
            const allTablesSql = database
2,882✔
2648
                ? `SELECT * FROM "${database}"."INFORMATION_SCHEMA"."TABLES" WHERE "TABLE_TYPE" = 'BASE TABLE'`
2,882✔
2649
                : `SELECT * FROM "INFORMATION_SCHEMA"."TABLES" WHERE "TABLE_TYPE" = 'BASE TABLE'`
2,882!
2650
            const allTablesResults: ObjectLiteral[] =
2,882✔
2651
                await this.query(allTablesSql)
2,882✔
2652

2,882✔
2653
            if (allTablesResults.length > 0) {
2,882✔
2654
                const tablesByCatalog: {
2,840✔
2655
                    [key: string]: {
2,840✔
2656
                        TABLE_NAME: string
2,840✔
2657
                        TABLE_SCHEMA: string
2,840✔
2658
                    }[]
2,840✔
2659
                } = allTablesResults.reduce(
2,840✔
2660
                    (c, { TABLE_CATALOG, TABLE_SCHEMA, TABLE_NAME }) => {
2,840✔
2661
                        c[TABLE_CATALOG] = c[TABLE_CATALOG] || []
9,920✔
2662
                        c[TABLE_CATALOG].push({ TABLE_SCHEMA, TABLE_NAME })
9,920✔
2663
                        return c
9,920✔
2664
                    },
2,840✔
2665
                    {},
2,840✔
2666
                )
2,840✔
2667

2,840✔
2668
                const foreignKeysSql = Object.entries(tablesByCatalog)
2,840✔
2669
                    .map(([TABLE_CATALOG, tables]) => {
2,840✔
2670
                        const conditions = tables
2,840✔
2671
                            .map(({ TABLE_SCHEMA, TABLE_NAME }) => {
2,840✔
2672
                                return `("fk"."referenced_object_id" = OBJECT_ID('"${TABLE_CATALOG}"."${TABLE_SCHEMA}"."${TABLE_NAME}"'))`
9,920✔
2673
                            })
2,840✔
2674
                            .join(" OR ")
2,840✔
2675

2,840✔
2676
                        return `
2,840✔
2677
                        SELECT DISTINCT '${TABLE_CATALOG}' AS                                              "TABLE_CATALOG",
2,840✔
2678
                                        OBJECT_SCHEMA_NAME("fk"."parent_object_id",
2,840✔
2679
                                                           DB_ID('${TABLE_CATALOG}')) AS                   "TABLE_SCHEMA",
2,840✔
2680
                                        OBJECT_NAME("fk"."parent_object_id", DB_ID('${TABLE_CATALOG}')) AS "TABLE_NAME",
2,840✔
2681
                                        "fk"."name" AS                                                     "CONSTRAINT_NAME"
2,840✔
2682
                        FROM "${TABLE_CATALOG}"."sys"."foreign_keys" AS "fk"
2,840✔
2683
                        WHERE (${conditions})
2,840✔
2684
                    `
2,840✔
2685
                    })
2,840✔
2686
                    .join(" UNION ALL ")
2,840✔
2687

2,840✔
2688
                const foreignKeys: {
2,840✔
2689
                    TABLE_CATALOG: string
2,840✔
2690
                    TABLE_SCHEMA: string
2,840✔
2691
                    TABLE_NAME: string
2,840✔
2692
                    CONSTRAINT_NAME: string
2,840✔
2693
                }[] = await this.query(foreignKeysSql)
2,840✔
2694

2,840✔
2695
                await Promise.all(
2,840✔
2696
                    foreignKeys.map(
2,840✔
2697
                        async ({
2,840✔
2698
                            TABLE_CATALOG,
6,568✔
2699
                            TABLE_SCHEMA,
6,568✔
2700
                            TABLE_NAME,
6,568✔
2701
                            CONSTRAINT_NAME,
6,568✔
2702
                        }) => {
6,568✔
2703
                            // Disable the constraint first.
6,568✔
2704
                            await this.query(
6,568✔
2705
                                `ALTER TABLE "${TABLE_CATALOG}"."${TABLE_SCHEMA}"."${TABLE_NAME}" ` +
6,568✔
2706
                                    `NOCHECK CONSTRAINT "${CONSTRAINT_NAME}"`,
6,568✔
2707
                            )
6,568✔
2708

6,568✔
2709
                            await this.query(
6,568✔
2710
                                `ALTER TABLE "${TABLE_CATALOG}"."${TABLE_SCHEMA}"."${TABLE_NAME}" ` +
6,568✔
2711
                                    `DROP CONSTRAINT "${CONSTRAINT_NAME}" -- FROM CLEAR`,
6,568✔
2712
                            )
6,568✔
2713
                        },
2,840✔
2714
                    ),
2,840✔
2715
                )
2,840✔
2716

2,840✔
2717
                await Promise.all(
2,840✔
2718
                    allTablesResults.map(async (tablesResult) => {
2,840✔
2719
                        if (tablesResult["TABLE_NAME"].startsWith("#")) {
9,920!
UNCOV
2720
                            // don't try to drop temporary tables
×
UNCOV
2721
                            return
×
2722
                        }
×
2723

9,920✔
2724
                        const dropTableSql = `DROP TABLE "${tablesResult["TABLE_CATALOG"]}"."${tablesResult["TABLE_SCHEMA"]}"."${tablesResult["TABLE_NAME"]}"`
9,920✔
2725
                        return this.query(dropTableSql)
9,920✔
2726
                    }),
2,840✔
2727
                )
2,840✔
2728
            }
2,840✔
2729

2,882✔
2730
            if (!isAnotherTransactionActive) await this.commitTransaction()
2,882✔
2731
        } catch (error) {
2,882!
UNCOV
2732
            try {
×
UNCOV
2733
                // we throw original error even if rollback thrown an error
×
2734
                if (!isAnotherTransactionActive)
×
2735
                    await this.rollbackTransaction()
×
2736
            } catch (rollbackError) {}
×
2737
            throw error
×
2738
        }
×
2739
    }
2,882✔
2740

26✔
2741
    // -------------------------------------------------------------------------
26✔
2742
    // Protected Methods
26✔
2743
    // -------------------------------------------------------------------------
26✔
2744

26✔
2745
    protected async loadViews(viewPaths?: string[]): Promise<View[]> {
26✔
2746
        const hasTable = await this.hasTable(this.getTypeormMetadataTableName())
2,994✔
2747
        if (!hasTable) {
2,994✔
2748
            return []
2,964✔
2749
        }
2,964✔
2750

30✔
2751
        if (!viewPaths) {
2,994!
UNCOV
2752
            viewPaths = []
×
UNCOV
2753
        }
×
2754

30✔
2755
        const currentSchema = await this.getCurrentSchema()
30✔
2756
        const currentDatabase = await this.getCurrentDatabase()
30✔
2757

30✔
2758
        const dbNames = viewPaths
30✔
2759
            .map((viewPath) => this.driver.parseTableName(viewPath).database)
30✔
2760
            .filter((database) => database)
30✔
2761

30✔
2762
        if (
30✔
2763
            this.driver.database &&
30✔
2764
            !dbNames.find((dbName) => dbName === this.driver.database)
30✔
2765
        )
2,994✔
2766
            dbNames.push(this.driver.database)
2,994✔
2767

30✔
2768
        const viewsCondition = viewPaths
30✔
2769
            .map((viewPath) => {
30✔
2770
                let { schema, tableName: name } =
22✔
2771
                    this.driver.parseTableName(viewPath)
22✔
2772

22✔
2773
                if (!schema) {
22!
UNCOV
2774
                    schema = currentSchema
×
UNCOV
2775
                }
×
2776
                return `("T"."SCHEMA" = '${schema}' AND "T"."NAME" = '${name}')`
22✔
2777
            })
30✔
2778
            .join(" OR ")
30✔
2779

30✔
2780
        const query = dbNames
30✔
2781
            .map((dbName) => {
30✔
2782
                return (
38✔
2783
                    `SELECT "T".*, "V"."CHECK_OPTION" FROM ${this.escapePath(
38✔
2784
                        this.getTypeormMetadataTableName(),
38✔
2785
                    )} "t" ` +
38✔
2786
                    `INNER JOIN "${dbName}"."INFORMATION_SCHEMA"."VIEWS" "V" ON "V"."TABLE_SCHEMA" = "T"."SCHEMA" AND "v"."TABLE_NAME" = "T"."NAME" WHERE "T"."TYPE" = '${
38✔
2787
                        MetadataTableType.VIEW
38✔
2788
                    }' ${viewsCondition ? `AND (${viewsCondition})` : ""}`
38✔
2789
                )
38✔
2790
            })
30✔
2791
            .join(" UNION ALL ")
30✔
2792

30✔
2793
        const dbViews = await this.query(query)
30✔
2794
        return dbViews.map((dbView: any) => {
30✔
2795
            const view = new View()
6✔
2796
            const db =
6✔
2797
                dbView["TABLE_CATALOG"] === currentDatabase
6✔
2798
                    ? undefined
6!
2799
                    : dbView["TABLE_CATALOG"]
6✔
2800
            const schema =
6✔
2801
                dbView["schema"] === currentSchema &&
6✔
2802
                !this.driver.options.schema
6✔
2803
                    ? undefined
6✔
2804
                    : dbView["schema"]
6!
2805
            view.database = dbView["TABLE_CATALOG"]
6✔
2806
            view.schema = dbView["schema"]
6✔
2807
            view.name = this.driver.buildTableName(dbView["name"], schema, db)
6✔
2808
            view.expression = dbView["value"]
6✔
2809
            return view
6✔
2810
        })
30✔
2811
    }
30✔
2812

26✔
2813
    /**
26✔
2814
     * Loads all tables (with given names) from the database and creates a Table from them.
26✔
2815
     */
26✔
2816
    protected async loadTables(tableNames?: string[]): Promise<Table[]> {
26✔
2817
        // if no tables given then no need to proceed
3,568✔
2818
        if (tableNames && tableNames.length === 0) {
3,568✔
2819
            return []
14✔
2820
        }
14✔
2821

3,554✔
2822
        const currentSchema = await this.getCurrentSchema()
3,554✔
2823
        const currentDatabase = await this.getCurrentDatabase()
3,554✔
2824

3,554✔
2825
        const dbTables: {
3,554✔
2826
            TABLE_CATALOG: string
3,554✔
2827
            TABLE_SCHEMA: string
3,554✔
2828
            TABLE_NAME: string
3,554✔
2829
        }[] = []
3,554✔
2830

3,554✔
2831
        if (!tableNames) {
3,568!
UNCOV
2832
            const databasesSql =
×
UNCOV
2833
                `SELECT DISTINCT "name" ` +
×
2834
                `FROM "master"."dbo"."sysdatabases" ` +
×
2835
                `WHERE "name" NOT IN ('master', 'model', 'msdb')`
×
2836
            const dbDatabases: { name: string }[] =
×
2837
                await this.query(databasesSql)
×
2838

×
2839
            const tablesSql = dbDatabases
×
2840
                .map(({ name }) => {
×
2841
                    return `
×
2842
                    SELECT DISTINCT
×
2843
                        "TABLE_CATALOG", "TABLE_SCHEMA", "TABLE_NAME"
×
2844
                    FROM "${name}"."INFORMATION_SCHEMA"."TABLES"
×
2845
                    WHERE
×
2846
                      "TABLE_TYPE" = 'BASE TABLE'
×
2847
                      AND
×
2848
                      "TABLE_CATALOG" = '${name}'
×
2849
                      AND
×
2850
                      ISNULL(Objectproperty(Object_id("TABLE_CATALOG" + '.' + "TABLE_SCHEMA" + '.' + "TABLE_NAME"), 'IsMSShipped'), 0) = 0
×
2851
                `
×
2852
                })
×
2853
                .join(" UNION ALL ")
×
2854

×
2855
            dbTables.push(...(await this.query(tablesSql)))
×
2856
        } else {
3,568✔
2857
            const tableNamesByCatalog = tableNames
3,554✔
2858
                .map((tableName) => this.driver.parseTableName(tableName))
3,554✔
2859
                .reduce(
3,554✔
2860
                    (c, { database, ...other }) => {
3,554✔
2861
                        database = database || currentDatabase
10,918!
2862
                        c[database] = c[database] || []
10,918✔
2863
                        c[database].push({
10,918✔
2864
                            schema: other.schema || currentSchema,
10,918!
2865
                            tableName: other.tableName,
10,918✔
2866
                        })
10,918✔
2867
                        return c
10,918✔
2868
                    },
3,554✔
2869
                    {} as {
3,554✔
2870
                        [key: string]: { schema: string; tableName: string }[]
3,554✔
2871
                    },
3,554✔
2872
                )
3,554✔
2873

3,554✔
2874
            const tablesSql = Object.entries(tableNamesByCatalog)
3,554✔
2875
                .map(([database, tables]) => {
3,554✔
2876
                    const tablesCondition = tables
3,562✔
2877
                        .map(({ schema, tableName }) => {
3,562✔
2878
                            return `("TABLE_SCHEMA" = '${schema}' AND "TABLE_NAME" = '${tableName}')`
10,918✔
2879
                        })
3,562✔
2880
                        .join(" OR ")
3,562✔
2881

3,562✔
2882
                    return `
3,562✔
2883
                    SELECT DISTINCT
3,562✔
2884
                        "TABLE_CATALOG", "TABLE_SCHEMA", "TABLE_NAME"
3,562✔
2885
                    FROM "${database}"."INFORMATION_SCHEMA"."TABLES"
3,562✔
2886
                    WHERE
3,562✔
2887
                          "TABLE_TYPE" = 'BASE TABLE' AND
3,562✔
2888
                          "TABLE_CATALOG" = '${database}' AND
3,562✔
2889
                          ${tablesCondition}
3,562✔
2890
                `
3,562✔
2891
                })
3,554✔
2892
                .join(" UNION ALL ")
3,554✔
2893

3,554✔
2894
            dbTables.push(...(await this.query(tablesSql)))
3,554✔
2895
        }
3,554✔
2896

3,554✔
2897
        // if tables were not found in the db, no need to proceed
3,554✔
2898
        if (dbTables.length === 0) {
3,568✔
2899
            return []
2,888✔
2900
        }
2,888✔
2901

666✔
2902
        const dbTablesByCatalog = dbTables.reduce(
666✔
2903
            (c, { TABLE_CATALOG, ...other }) => {
666✔
2904
                c[TABLE_CATALOG] = c[TABLE_CATALOG] || []
990✔
2905
                c[TABLE_CATALOG].push(other)
990✔
2906
                return c
990✔
2907
            },
666✔
2908
            {} as {
666✔
2909
                [key: string]: { TABLE_NAME: string; TABLE_SCHEMA: string }[]
666✔
2910
            },
666✔
2911
        )
666✔
2912

666✔
2913
        const columnsSql = Object.entries(dbTablesByCatalog)
666✔
2914
            .map(([TABLE_CATALOG, tables]) => {
666✔
2915
                const condition = tables
666✔
2916
                    .map(
666✔
2917
                        ({ TABLE_SCHEMA, TABLE_NAME }) =>
666✔
2918
                            `("TABLE_SCHEMA" = '${TABLE_SCHEMA}' AND "TABLE_NAME" = '${TABLE_NAME}')`,
666✔
2919
                    )
666✔
2920
                    .join("OR")
666✔
2921

666✔
2922
                return (
666✔
2923
                    `SELECT "COLUMNS".*, "cc"."is_persisted", "cc"."definition" ` +
666✔
2924
                    `FROM "${TABLE_CATALOG}"."INFORMATION_SCHEMA"."COLUMNS" ` +
666✔
2925
                    `LEFT JOIN "sys"."computed_columns" "cc" ON COL_NAME("cc"."object_id", "cc"."column_id") = "column_name" ` +
666✔
2926
                    `WHERE (${condition})`
666✔
2927
                )
666✔
2928
            })
666✔
2929
            .join(" UNION ALL ")
666✔
2930

666✔
2931
        const constraintsSql = Object.entries(dbTablesByCatalog)
666✔
2932
            .map(([TABLE_CATALOG, tables]) => {
666✔
2933
                const conditions = tables
666✔
2934
                    .map(
666✔
2935
                        ({ TABLE_NAME, TABLE_SCHEMA }) =>
666✔
2936
                            `("columnUsages"."TABLE_SCHEMA" = '${TABLE_SCHEMA}' AND "columnUsages"."TABLE_NAME" = '${TABLE_NAME}')`,
666✔
2937
                    )
666✔
2938
                    .join(" OR ")
666✔
2939

666✔
2940
                return (
666✔
2941
                    `SELECT "columnUsages".*, "tableConstraints"."CONSTRAINT_TYPE", "chk"."definition" ` +
666✔
2942
                    `FROM "${TABLE_CATALOG}"."INFORMATION_SCHEMA"."CONSTRAINT_COLUMN_USAGE" "columnUsages" ` +
666✔
2943
                    `INNER JOIN "${TABLE_CATALOG}"."INFORMATION_SCHEMA"."TABLE_CONSTRAINTS" "tableConstraints" ` +
666✔
2944
                    `ON ` +
666✔
2945
                    `"tableConstraints"."CONSTRAINT_NAME" = "columnUsages"."CONSTRAINT_NAME" AND ` +
666✔
2946
                    `"tableConstraints"."TABLE_SCHEMA" = "columnUsages"."TABLE_SCHEMA" AND ` +
666✔
2947
                    `"tableConstraints"."TABLE_NAME" = "columnUsages"."TABLE_NAME" ` +
666✔
2948
                    `LEFT JOIN "${TABLE_CATALOG}"."sys"."check_constraints" "chk" ` +
666✔
2949
                    `ON ` +
666✔
2950
                    `"chk"."object_id" = OBJECT_ID("columnUsages"."TABLE_CATALOG" + '.' + "columnUsages"."TABLE_SCHEMA" + '.' + "columnUsages"."CONSTRAINT_NAME") ` +
666✔
2951
                    `WHERE ` +
666✔
2952
                    `(${conditions}) AND ` +
666✔
2953
                    `"tableConstraints"."CONSTRAINT_TYPE" IN ('PRIMARY KEY', 'UNIQUE', 'CHECK')`
666✔
2954
                )
666✔
2955
            })
666✔
2956
            .join(" UNION ALL ")
666✔
2957

666✔
2958
        const foreignKeysSql = Object.entries(dbTablesByCatalog)
666✔
2959
            .map(([TABLE_CATALOG, tables]) => {
666✔
2960
                const conditions = tables
666✔
2961
                    .map(
666✔
2962
                        ({ TABLE_NAME, TABLE_SCHEMA }) =>
666✔
2963
                            `("s1"."name" = '${TABLE_SCHEMA}' AND "t1"."name" = '${TABLE_NAME}')`,
666✔
2964
                    )
666✔
2965
                    .join(" OR ")
666✔
2966

666✔
2967
                return (
666✔
2968
                    `SELECT "fk"."name" AS "FK_NAME", '${TABLE_CATALOG}' AS "TABLE_CATALOG", "s1"."name" AS "TABLE_SCHEMA", "t1"."name" AS "TABLE_NAME", ` +
666✔
2969
                    `"col1"."name" AS "COLUMN_NAME", "s2"."name" AS "REF_SCHEMA", "t2"."name" AS "REF_TABLE", "col2"."name" AS "REF_COLUMN", ` +
666✔
2970
                    `"fk"."delete_referential_action_desc" AS "ON_DELETE", "fk"."update_referential_action_desc" AS "ON_UPDATE" ` +
666✔
2971
                    `FROM "${TABLE_CATALOG}"."sys"."foreign_keys" "fk" ` +
666✔
2972
                    `INNER JOIN "${TABLE_CATALOG}"."sys"."foreign_key_columns" "fkc" ON "fkc"."constraint_object_id" = "fk"."object_id" ` +
666✔
2973
                    `INNER JOIN "${TABLE_CATALOG}"."sys"."tables" "t1" ON "t1"."object_id" = "fk"."parent_object_id" ` +
666✔
2974
                    `INNER JOIN "${TABLE_CATALOG}"."sys"."schemas" "s1" ON "s1"."schema_id" = "t1"."schema_id" ` +
666✔
2975
                    `INNER JOIN "${TABLE_CATALOG}"."sys"."tables" "t2" ON "t2"."object_id" = "fk"."referenced_object_id" ` +
666✔
2976
                    `INNER JOIN "${TABLE_CATALOG}"."sys"."schemas" "s2" ON "s2"."schema_id" = "t2"."schema_id" ` +
666✔
2977
                    `INNER JOIN "${TABLE_CATALOG}"."sys"."columns" "col1" ON "col1"."column_id" = "fkc"."parent_column_id" AND "col1"."object_id" = "fk"."parent_object_id" ` +
666✔
2978
                    `INNER JOIN "${TABLE_CATALOG}"."sys"."columns" "col2" ON "col2"."column_id" = "fkc"."referenced_column_id" AND "col2"."object_id" = "fk"."referenced_object_id" ` +
666✔
2979
                    `WHERE (${conditions})`
666✔
2980
                )
666✔
2981
            })
666✔
2982
            .join(" UNION ALL ")
666✔
2983

666✔
2984
        const identityColumnsSql = Object.entries(dbTablesByCatalog)
666✔
2985
            .map(([TABLE_CATALOG, tables]) => {
666✔
2986
                const conditions = tables
666✔
2987
                    .map(
666✔
2988
                        ({ TABLE_NAME, TABLE_SCHEMA }) =>
666✔
2989
                            `("TABLE_SCHEMA" = '${TABLE_SCHEMA}' AND "TABLE_NAME" = '${TABLE_NAME}')`,
666✔
2990
                    )
666✔
2991
                    .join(" OR ")
666✔
2992

666✔
2993
                return (
666✔
2994
                    `SELECT "TABLE_CATALOG", "TABLE_SCHEMA", "COLUMN_NAME", "TABLE_NAME" ` +
666✔
2995
                    `FROM "${TABLE_CATALOG}"."INFORMATION_SCHEMA"."COLUMNS" ` +
666✔
2996
                    `WHERE ` +
666✔
2997
                    `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✔
2998
                    `(${conditions})`
666✔
2999
                )
666✔
3000
            })
666✔
3001
            .join(" UNION ALL ")
666✔
3002

666✔
3003
        const dbCollationsSql = `SELECT "NAME", "COLLATION_NAME" FROM "sys"."databases"`
666✔
3004

666✔
3005
        const indicesSql = Object.entries(dbTablesByCatalog)
666✔
3006
            .map(([TABLE_CATALOG, tables]) => {
666✔
3007
                const conditions = tables
666✔
3008
                    .map(
666✔
3009
                        ({ TABLE_NAME, TABLE_SCHEMA }) =>
666✔
3010
                            `("s"."name" = '${TABLE_SCHEMA}' AND "t"."name" = '${TABLE_NAME}')`,
666✔
3011
                    )
666✔
3012
                    .join(" OR ")
666✔
3013

666✔
3014
                return (
666✔
3015
                    `SELECT '${TABLE_CATALOG}' AS "TABLE_CATALOG", "s"."name" AS "TABLE_SCHEMA", "t"."name" AS "TABLE_NAME", ` +
666✔
3016
                    `"ind"."name" AS "INDEX_NAME", "col"."name" AS "COLUMN_NAME", "ind"."is_unique" AS "IS_UNIQUE", "ind"."filter_definition" as "CONDITION" ` +
666✔
3017
                    `FROM "${TABLE_CATALOG}"."sys"."indexes" "ind" ` +
666✔
3018
                    `INNER JOIN "${TABLE_CATALOG}"."sys"."index_columns" "ic" ON "ic"."object_id" = "ind"."object_id" AND "ic"."index_id" = "ind"."index_id" ` +
666✔
3019
                    `INNER JOIN "${TABLE_CATALOG}"."sys"."columns" "col" ON "col"."object_id" = "ic"."object_id" AND "col"."column_id" = "ic"."column_id" ` +
666✔
3020
                    `INNER JOIN "${TABLE_CATALOG}"."sys"."tables" "t" ON "t"."object_id" = "ind"."object_id" ` +
666✔
3021
                    `INNER JOIN "${TABLE_CATALOG}"."sys"."schemas" "s" ON "s"."schema_id" = "t"."schema_id" ` +
666✔
3022
                    `WHERE ` +
666✔
3023
                    `"ind"."is_primary_key" = 0 AND "ind"."is_unique_constraint" = 0 AND "t"."is_ms_shipped" = 0 AND ` +
666✔
3024
                    `(${conditions})`
666✔
3025
                )
666✔
3026
            })
666✔
3027
            .join(" UNION ALL ")
666✔
3028

666✔
3029
        const [
666✔
3030
            dbColumns,
666✔
3031
            dbConstraints,
666✔
3032
            dbForeignKeys,
666✔
3033
            dbIdentityColumns,
666✔
3034
            dbCollations,
666✔
3035
            dbIndices,
666✔
3036
        ]: ObjectLiteral[][] = await Promise.all([
666✔
3037
            this.query(columnsSql),
666✔
3038
            this.query(constraintsSql),
666✔
3039
            this.query(foreignKeysSql),
666✔
3040
            this.query(identityColumnsSql),
666✔
3041
            this.query(dbCollationsSql),
666✔
3042
            this.query(indicesSql),
666✔
3043
        ])
666✔
3044

666✔
3045
        // create table schemas for loaded tables
666✔
3046
        return await Promise.all(
666✔
3047
            dbTables.map(async (dbTable) => {
666✔
3048
                const table = new Table()
990✔
3049

990✔
3050
                const getSchemaFromKey = (dbObject: any, key: string) => {
990✔
3051
                    return dbObject[key] === currentSchema &&
1,328✔
3052
                        (!this.driver.options.schema ||
1,238✔
3053
                            this.driver.options.schema === currentSchema)
1,238✔
3054
                        ? undefined
1,328✔
3055
                        : dbObject[key]
1,328✔
3056
                }
1,328✔
3057

990✔
3058
                // We do not need to join schema and database names, when db or schema is by default.
990✔
3059
                const db =
990✔
3060
                    dbTable["TABLE_CATALOG"] === currentDatabase
990✔
3061
                        ? undefined
990✔
3062
                        : dbTable["TABLE_CATALOG"]
990✔
3063
                const schema = getSchemaFromKey(dbTable, "TABLE_SCHEMA")
990✔
3064
                table.database = dbTable["TABLE_CATALOG"]
990✔
3065
                table.schema = dbTable["TABLE_SCHEMA"]
990✔
3066
                table.name = this.driver.buildTableName(
990✔
3067
                    dbTable["TABLE_NAME"],
990✔
3068
                    schema,
990✔
3069
                    db,
990✔
3070
                )
990✔
3071

990✔
3072
                const defaultCollation = dbCollations.find(
990✔
3073
                    (dbCollation) =>
990✔
3074
                        dbCollation["NAME"] === dbTable["TABLE_CATALOG"],
990✔
3075
                )!
990✔
3076

990✔
3077
                // create columns from the loaded columns
990✔
3078
                table.columns = await Promise.all(
990✔
3079
                    dbColumns
990✔
3080
                        .filter(
990✔
3081
                            (dbColumn) =>
990✔
3082
                                dbColumn["TABLE_NAME"] ===
10,700✔
3083
                                    dbTable["TABLE_NAME"] &&
10,700✔
3084
                                dbColumn["TABLE_SCHEMA"] ===
3,546✔
3085
                                    dbTable["TABLE_SCHEMA"] &&
10,700✔
3086
                                dbColumn["TABLE_CATALOG"] ===
3,546✔
3087
                                    dbTable["TABLE_CATALOG"],
990✔
3088
                        )
990✔
3089
                        .map(async (dbColumn) => {
990✔
3090
                            const columnConstraints = dbConstraints.filter(
3,546✔
3091
                                (dbConstraint) =>
3,546✔
3092
                                    dbConstraint["TABLE_NAME"] ===
18,730✔
3093
                                        dbColumn["TABLE_NAME"] &&
18,730✔
3094
                                    dbConstraint["TABLE_SCHEMA"] ===
7,836✔
3095
                                        dbColumn["TABLE_SCHEMA"] &&
18,730✔
3096
                                    dbConstraint["TABLE_CATALOG"] ===
7,836✔
3097
                                        dbColumn["TABLE_CATALOG"] &&
18,730✔
3098
                                    dbConstraint["COLUMN_NAME"] ===
7,836✔
3099
                                        dbColumn["COLUMN_NAME"],
3,546✔
3100
                            )
3,546✔
3101

3,546✔
3102
                            const uniqueConstraints = columnConstraints.filter(
3,546✔
3103
                                (constraint) =>
3,546✔
3104
                                    constraint["CONSTRAINT_TYPE"] === "UNIQUE",
3,546✔
3105
                            )
3,546✔
3106
                            const isConstraintComposite =
3,546✔
3107
                                uniqueConstraints.every((uniqueConstraint) => {
3,546✔
3108
                                    return dbConstraints.some(
590✔
3109
                                        (dbConstraint) =>
590✔
3110
                                            dbConstraint["CONSTRAINT_TYPE"] ===
2,604✔
3111
                                                "UNIQUE" &&
2,604✔
3112
                                            dbConstraint["CONSTRAINT_NAME"] ===
1,216✔
3113
                                                uniqueConstraint[
1,216✔
3114
                                                    "CONSTRAINT_NAME"
1,216✔
3115
                                                ] &&
2,604✔
3116
                                            dbConstraint["TABLE_SCHEMA"] ===
762✔
3117
                                                dbColumn["TABLE_SCHEMA"] &&
2,604✔
3118
                                            dbConstraint["TABLE_CATALOG"] ===
762✔
3119
                                                dbColumn["TABLE_CATALOG"] &&
2,604✔
3120
                                            dbConstraint["COLUMN_NAME"] !==
762✔
3121
                                                dbColumn["COLUMN_NAME"],
590✔
3122
                                    )
590✔
3123
                                })
3,546✔
3124

3,546✔
3125
                            const isGenerated = !!dbIdentityColumns.find(
3,546✔
3126
                                (column) =>
3,546✔
3127
                                    column["TABLE_NAME"] ===
5,696✔
3128
                                        dbColumn["TABLE_NAME"] &&
5,696✔
3129
                                    column["TABLE_SCHEMA"] ===
1,770✔
3130
                                        dbColumn["TABLE_SCHEMA"] &&
5,696✔
3131
                                    column["TABLE_CATALOG"] ===
1,770✔
3132
                                        dbColumn["TABLE_CATALOG"] &&
5,696✔
3133
                                    column["COLUMN_NAME"] ===
1,770✔
3134
                                        dbColumn["COLUMN_NAME"],
3,546✔
3135
                            )
3,546✔
3136

3,546✔
3137
                            const tableColumn = new TableColumn()
3,546✔
3138
                            tableColumn.name = dbColumn["COLUMN_NAME"]
3,546✔
3139
                            tableColumn.type =
3,546✔
3140
                                dbColumn["DATA_TYPE"].toLowerCase()
3,546✔
3141

3,546✔
3142
                            // check only columns that have length property
3,546✔
3143
                            if (
3,546✔
3144
                                this.driver.withLengthColumnTypes.indexOf(
3,546✔
3145
                                    tableColumn.type as ColumnType,
3,546✔
3146
                                ) !== -1 &&
3,546✔
3147
                                dbColumn["CHARACTER_MAXIMUM_LENGTH"]
1,928✔
3148
                            ) {
3,546✔
3149
                                const length =
1,928✔
3150
                                    dbColumn[
1,928✔
3151
                                        "CHARACTER_MAXIMUM_LENGTH"
1,928✔
3152
                                    ].toString()
1,928✔
3153
                                if (length === "-1") {
1,928✔
3154
                                    tableColumn.length = "MAX"
8✔
3155
                                } else {
1,928✔
3156
                                    if (tableColumn.type === "vector") {
1,920✔
3157
                                        const len = +length
2✔
3158
                                        // NOTE: real returned length is (N*4 + 8) where N is desired dimensions
2✔
3159
                                        if (!Number.isNaN(len)) {
2✔
3160
                                            tableColumn.length = String(
2✔
3161
                                                (len - 8) / 4,
2✔
3162
                                            )
2✔
3163
                                        }
2✔
3164
                                    } else {
1,920✔
3165
                                        tableColumn.length =
1,918✔
3166
                                            !this.isDefaultColumnLength(
1,918✔
3167
                                                table,
1,918✔
3168
                                                tableColumn,
1,918✔
3169
                                                length,
1,918✔
3170
                                            )
1,918✔
3171
                                                ? length
1,918✔
3172
                                                : ""
1,918✔
3173
                                    }
1,918✔
3174
                                }
1,920✔
3175
                            }
1,928✔
3176

3,546✔
3177
                            if (
3,546✔
3178
                                tableColumn.type === "decimal" ||
3,546✔
3179
                                tableColumn.type === "numeric"
3,536✔
3180
                            ) {
3,546✔
3181
                                if (
14✔
3182
                                    dbColumn["NUMERIC_PRECISION"] !== null &&
14✔
3183
                                    !this.isDefaultColumnPrecision(
14✔
3184
                                        table,
14✔
3185
                                        tableColumn,
14✔
3186
                                        dbColumn["NUMERIC_PRECISION"],
14✔
3187
                                    )
14✔
3188
                                )
14✔
3189
                                    tableColumn.precision =
14✔
3190
                                        dbColumn["NUMERIC_PRECISION"]
8✔
3191
                                if (
14✔
3192
                                    dbColumn["NUMERIC_SCALE"] !== null &&
14✔
3193
                                    !this.isDefaultColumnScale(
14✔
3194
                                        table,
14✔
3195
                                        tableColumn,
14✔
3196
                                        dbColumn["NUMERIC_SCALE"],
14✔
3197
                                    )
14✔
3198
                                )
14✔
3199
                                    tableColumn.scale =
14✔
3200
                                        dbColumn["NUMERIC_SCALE"]
8✔
3201
                            }
14✔
3202

3,546✔
3203
                            if (tableColumn.type === "nvarchar") {
3,546✔
3204
                                // Check if this is an enum
1,594✔
3205
                                const columnCheckConstraints =
1,594✔
3206
                                    columnConstraints.filter(
1,594✔
3207
                                        (constraint) =>
1,594✔
3208
                                            constraint["CONSTRAINT_TYPE"] ===
518✔
3209
                                            "CHECK",
1,594✔
3210
                                    )
1,594✔
3211
                                if (columnCheckConstraints.length) {
1,594✔
3212
                                    // const isEnumRegexp = new RegExp("^\\(\\[" + tableColumn.name + "\\]='[^']+'(?: OR \\[" + tableColumn.name + "\\]='[^']+')*\\)$");
22✔
3213
                                    for (const checkConstraint of columnCheckConstraints) {
22✔
3214
                                        if (
22✔
3215
                                            this.isEnumCheckConstraint(
22✔
3216
                                                checkConstraint[
22✔
3217
                                                    "CONSTRAINT_NAME"
22✔
3218
                                                ],
22✔
3219
                                            )
22✔
3220
                                        ) {
22✔
3221
                                            // This is an enum constraint, make column into an enum
10✔
3222
                                            tableColumn.enum = []
10✔
3223
                                            const enumValueRegexp = new RegExp(
10✔
3224
                                                "\\[" +
10✔
3225
                                                    tableColumn.name +
10✔
3226
                                                    "\\]='([^']+)'",
10✔
3227
                                                "g",
10✔
3228
                                            )
10✔
3229
                                            let result
10✔
3230
                                            while (
10✔
3231
                                                (result = enumValueRegexp.exec(
10✔
3232
                                                    checkConstraint[
10✔
3233
                                                        "definition"
10✔
3234
                                                    ],
10✔
3235
                                                )) !== null
10✔
3236
                                            ) {
10✔
3237
                                                tableColumn.enum.unshift(
26✔
3238
                                                    result[1],
26✔
3239
                                                )
26✔
3240
                                            }
26✔
3241
                                            // Skip other column constraints
10✔
3242
                                            break
10✔
3243
                                        }
10✔
3244
                                    }
22✔
3245
                                }
22✔
3246
                            }
1,594✔
3247

3,546✔
3248
                            const primaryConstraint = columnConstraints.find(
3,546✔
3249
                                (constraint) =>
3,546✔
3250
                                    constraint["CONSTRAINT_TYPE"] ===
1,796✔
3251
                                    "PRIMARY KEY",
3,546✔
3252
                            )
3,546✔
3253
                            if (primaryConstraint) {
3,546✔
3254
                                tableColumn.isPrimary = true
1,028✔
3255
                                // find another columns involved in primary key constraint
1,028✔
3256
                                const anotherPrimaryConstraints =
1,028✔
3257
                                    dbConstraints.filter(
1,028✔
3258
                                        (constraint) =>
1,028✔
3259
                                            constraint["TABLE_NAME"] ===
5,468✔
3260
                                                dbColumn["TABLE_NAME"] &&
5,468✔
3261
                                            constraint["TABLE_SCHEMA"] ===
1,930✔
3262
                                                dbColumn["TABLE_SCHEMA"] &&
5,468✔
3263
                                            constraint["TABLE_CATALOG"] ===
1,930✔
3264
                                                dbColumn["TABLE_CATALOG"] &&
5,468✔
3265
                                            constraint["COLUMN_NAME"] !==
1,930✔
3266
                                                dbColumn["COLUMN_NAME"] &&
5,468✔
3267
                                            constraint["CONSTRAINT_TYPE"] ===
882✔
3268
                                                "PRIMARY KEY",
1,028✔
3269
                                    )
1,028✔
3270

1,028✔
3271
                                // collect all column names
1,028✔
3272
                                const columnNames =
1,028✔
3273
                                    anotherPrimaryConstraints.map(
1,028✔
3274
                                        (constraint) =>
1,028✔
3275
                                            constraint["COLUMN_NAME"],
1,028✔
3276
                                    )
1,028✔
3277
                                columnNames.push(dbColumn["COLUMN_NAME"])
1,028✔
3278

1,028✔
3279
                                // build default primary key constraint name
1,028✔
3280
                                const pkName =
1,028✔
3281
                                    this.connection.namingStrategy.primaryKeyName(
1,028✔
3282
                                        table,
1,028✔
3283
                                        columnNames,
1,028✔
3284
                                    )
1,028✔
3285

1,028✔
3286
                                // if primary key has user-defined constraint name, write it in table column
1,028✔
3287
                                if (
1,028✔
3288
                                    primaryConstraint["CONSTRAINT_NAME"] !==
1,028✔
3289
                                    pkName
1,028✔
3290
                                ) {
1,028✔
3291
                                    tableColumn.primaryKeyConstraintName =
52✔
3292
                                        primaryConstraint["CONSTRAINT_NAME"]
52✔
3293
                                }
52✔
3294
                            }
1,028✔
3295

3,546✔
3296
                            tableColumn.default =
3,546✔
3297
                                dbColumn["COLUMN_DEFAULT"] !== null &&
3,546✔
3298
                                dbColumn["COLUMN_DEFAULT"] !== undefined
212✔
3299
                                    ? this.removeParenthesisFromDefault(
3,546✔
3300
                                          dbColumn["COLUMN_DEFAULT"],
212✔
3301
                                      )
3,546✔
3302
                                    : undefined
3,546✔
3303
                            tableColumn.isNullable =
3,546✔
3304
                                dbColumn["IS_NULLABLE"] === "YES"
3,546✔
3305
                            tableColumn.isUnique =
3,546✔
3306
                                uniqueConstraints.length > 0 &&
3,546✔
3307
                                !isConstraintComposite
590✔
3308
                            tableColumn.isGenerated = isGenerated
3,546✔
3309
                            if (isGenerated)
3,546✔
3310
                                tableColumn.generationStrategy = "increment"
3,546✔
3311
                            if (tableColumn.default === "newsequentialid()") {
3,546✔
3312
                                tableColumn.isGenerated = true
14✔
3313
                                tableColumn.generationStrategy = "uuid"
14✔
3314
                                tableColumn.default = undefined
14✔
3315
                            }
14✔
3316

3,546✔
3317
                            // todo: unable to get default charset
3,546✔
3318
                            // tableColumn.charset = dbColumn["CHARACTER_SET_NAME"];
3,546✔
3319
                            if (dbColumn["COLLATION_NAME"])
3,546✔
3320
                                tableColumn.collation =
3,546✔
3321
                                    dbColumn["COLLATION_NAME"] ===
1,880✔
3322
                                    defaultCollation["COLLATION_NAME"]
1,880✔
3323
                                        ? undefined
1,880✔
3324
                                        : dbColumn["COLLATION_NAME"]
1,880✔
3325

3,546✔
3326
                            if (
3,546✔
3327
                                tableColumn.type === "datetime2" ||
3,546✔
3328
                                tableColumn.type === "time" ||
3,546✔
3329
                                tableColumn.type === "datetimeoffset"
3,518✔
3330
                            ) {
3,546✔
3331
                                tableColumn.precision =
32✔
3332
                                    !this.isDefaultColumnPrecision(
32✔
3333
                                        table,
32✔
3334
                                        tableColumn,
32✔
3335
                                        dbColumn["DATETIME_PRECISION"],
32✔
3336
                                    )
32✔
3337
                                        ? dbColumn["DATETIME_PRECISION"]
32✔
3338
                                        : undefined
32✔
3339
                            }
32✔
3340

3,546✔
3341
                            if (
3,546✔
3342
                                dbColumn["is_persisted"] !== null &&
3,546✔
3343
                                dbColumn["is_persisted"] !== undefined &&
3,546✔
3344
                                dbColumn["definition"]
94✔
3345
                            ) {
3,546✔
3346
                                tableColumn.generatedType =
94✔
3347
                                    dbColumn["is_persisted"] === true
94✔
3348
                                        ? "STORED"
94✔
3349
                                        : "VIRTUAL"
94✔
3350
                                // We cannot relay on information_schema.columns.generation_expression, because it is formatted different.
94✔
3351
                                const asExpressionQuery =
94✔
3352
                                    this.selectTypeormMetadataSql({
94✔
3353
                                        database: dbTable["TABLE_CATALOG"],
94✔
3354
                                        schema: dbTable["TABLE_SCHEMA"],
94✔
3355
                                        table: dbTable["TABLE_NAME"],
94✔
3356
                                        type: MetadataTableType.GENERATED_COLUMN,
94✔
3357
                                        name: tableColumn.name,
94✔
3358
                                    })
94✔
3359

94✔
3360
                                const results = await this.query(
94✔
3361
                                    asExpressionQuery.query,
94✔
3362
                                    asExpressionQuery.parameters,
94✔
3363
                                )
94✔
3364
                                if (results[0] && results[0].value) {
94✔
3365
                                    tableColumn.asExpression = results[0].value
94✔
3366
                                } else {
94!
UNCOV
3367
                                    tableColumn.asExpression = ""
×
UNCOV
3368
                                }
×
3369
                            }
94✔
3370

3,546✔
3371
                            return tableColumn
3,546✔
3372
                        }),
990✔
3373
                )
990✔
3374

990✔
3375
                // find unique constraints of table, group them by constraint name and build TableUnique.
990✔
3376
                const tableUniqueConstraints = OrmUtils.uniq(
990✔
3377
                    dbConstraints.filter(
990✔
3378
                        (dbConstraint) =>
990✔
3379
                            dbConstraint["TABLE_NAME"] ===
5,330✔
3380
                                dbTable["TABLE_NAME"] &&
5,330✔
3381
                            dbConstraint["TABLE_SCHEMA"] ===
1,816✔
3382
                                dbTable["TABLE_SCHEMA"] &&
5,330✔
3383
                            dbConstraint["TABLE_CATALOG"] ===
1,816✔
3384
                                dbTable["TABLE_CATALOG"] &&
5,330✔
3385
                            dbConstraint["CONSTRAINT_TYPE"] === "UNIQUE",
990✔
3386
                    ),
990✔
3387
                    (dbConstraint) => dbConstraint["CONSTRAINT_NAME"],
990✔
3388
                )
990✔
3389

990✔
3390
                table.uniques = tableUniqueConstraints.map((constraint) => {
990✔
3391
                    const uniques = dbConstraints.filter(
414✔
3392
                        (dbC) =>
414✔
3393
                            dbC["CONSTRAINT_NAME"] ===
2,602✔
3394
                            constraint["CONSTRAINT_NAME"],
414✔
3395
                    )
414✔
3396
                    return new TableUnique({
414✔
3397
                        name: constraint["CONSTRAINT_NAME"],
414✔
3398
                        columnNames: uniques.map((u) => u["COLUMN_NAME"]),
414✔
3399
                    })
414✔
3400
                })
990✔
3401

990✔
3402
                // find check constraints of table, group them by constraint name and build TableCheck.
990✔
3403
                const tableCheckConstraints = OrmUtils.uniq(
990✔
3404
                    dbConstraints.filter(
990✔
3405
                        (dbConstraint) =>
990✔
3406
                            dbConstraint["TABLE_NAME"] ===
5,330✔
3407
                                dbTable["TABLE_NAME"] &&
5,330✔
3408
                            dbConstraint["TABLE_SCHEMA"] ===
1,816✔
3409
                                dbTable["TABLE_SCHEMA"] &&
5,330✔
3410
                            dbConstraint["TABLE_CATALOG"] ===
1,816✔
3411
                                dbTable["TABLE_CATALOG"] &&
5,330✔
3412
                            dbConstraint["CONSTRAINT_TYPE"] === "CHECK",
990✔
3413
                    ),
990✔
3414
                    (dbConstraint) => dbConstraint["CONSTRAINT_NAME"],
990✔
3415
                )
990✔
3416

990✔
3417
                table.checks = tableCheckConstraints
990✔
3418
                    .filter(
990✔
3419
                        (constraint) =>
990✔
3420
                            !this.isEnumCheckConstraint(
184✔
3421
                                constraint["CONSTRAINT_NAME"],
184✔
3422
                            ),
990✔
3423
                    )
990✔
3424
                    .map((constraint) => {
990✔
3425
                        const checks = dbConstraints.filter(
174✔
3426
                            (dbC) =>
174✔
3427
                                dbC["CONSTRAINT_NAME"] ===
1,220✔
3428
                                constraint["CONSTRAINT_NAME"],
174✔
3429
                        )
174✔
3430
                        return new TableCheck({
174✔
3431
                            name: constraint["CONSTRAINT_NAME"],
174✔
3432
                            columnNames: checks.map((c) => c["COLUMN_NAME"]),
174✔
3433
                            expression: constraint["definition"],
174✔
3434
                        })
174✔
3435
                    })
990✔
3436

990✔
3437
                // find foreign key constraints of table, group them by constraint name and build TableForeignKey.
990✔
3438
                const tableForeignKeyConstraints = OrmUtils.uniq(
990✔
3439
                    dbForeignKeys.filter(
990✔
3440
                        (dbForeignKey) =>
990✔
3441
                            dbForeignKey["TABLE_NAME"] ===
1,280✔
3442
                                dbTable["TABLE_NAME"] &&
1,280✔
3443
                            dbForeignKey["TABLE_SCHEMA"] ===
346✔
3444
                                dbTable["TABLE_SCHEMA"] &&
1,280✔
3445
                            dbForeignKey["TABLE_CATALOG"] ===
346✔
3446
                                dbTable["TABLE_CATALOG"],
990✔
3447
                    ),
990✔
3448
                    (dbForeignKey) => dbForeignKey["FK_NAME"],
990✔
3449
                )
990✔
3450

990✔
3451
                table.foreignKeys = tableForeignKeyConstraints.map(
990✔
3452
                    (dbForeignKey) => {
990✔
3453
                        const foreignKeys = dbForeignKeys.filter(
338✔
3454
                            (dbFk) =>
338✔
3455
                                dbFk["FK_NAME"] === dbForeignKey["FK_NAME"],
338✔
3456
                        )
338✔
3457

338✔
3458
                        // if referenced table located in currently used db and schema, we don't need to concat db and schema names to table name.
338✔
3459
                        const db =
338✔
3460
                            dbForeignKey["TABLE_CATALOG"] === currentDatabase
338✔
3461
                                ? undefined
338✔
3462
                                : dbForeignKey["TABLE_CATALOG"]
338✔
3463
                        const schema = getSchemaFromKey(
338✔
3464
                            dbForeignKey,
338✔
3465
                            "REF_SCHEMA",
338✔
3466
                        )
338✔
3467
                        const referencedTableName = this.driver.buildTableName(
338✔
3468
                            dbForeignKey["REF_TABLE"],
338✔
3469
                            schema,
338✔
3470
                            db,
338✔
3471
                        )
338✔
3472

338✔
3473
                        return new TableForeignKey({
338✔
3474
                            name: dbForeignKey["FK_NAME"],
338✔
3475
                            columnNames: foreignKeys.map(
338✔
3476
                                (dbFk) => dbFk["COLUMN_NAME"],
338✔
3477
                            ),
338✔
3478
                            referencedDatabase: dbForeignKey["TABLE_CATALOG"],
338✔
3479
                            referencedSchema: dbForeignKey["REF_SCHEMA"],
338✔
3480
                            referencedTableName: referencedTableName,
338✔
3481
                            referencedColumnNames: foreignKeys.map(
338✔
3482
                                (dbFk) => dbFk["REF_COLUMN"],
338✔
3483
                            ),
338✔
3484
                            onDelete: dbForeignKey["ON_DELETE"].replace(
338✔
3485
                                "_",
338✔
3486
                                " ",
338✔
3487
                            ), // SqlServer returns NO_ACTION, instead of NO ACTION
338✔
3488
                            onUpdate: dbForeignKey["ON_UPDATE"].replace(
338✔
3489
                                "_",
338✔
3490
                                " ",
338✔
3491
                            ), // SqlServer returns NO_ACTION, instead of NO ACTION
338✔
3492
                        })
338✔
3493
                    },
990✔
3494
                )
990✔
3495

990✔
3496
                // find index constraints of table, group them by constraint name and build TableIndex.
990✔
3497
                const tableIndexConstraints = OrmUtils.uniq(
990✔
3498
                    dbIndices.filter(
990✔
3499
                        (dbIndex) =>
990✔
3500
                            dbIndex["TABLE_NAME"] === dbTable["TABLE_NAME"] &&
722✔
3501
                            dbIndex["TABLE_SCHEMA"] ===
332✔
3502
                                dbTable["TABLE_SCHEMA"] &&
722✔
3503
                            dbIndex["TABLE_CATALOG"] ===
332✔
3504
                                dbTable["TABLE_CATALOG"],
990✔
3505
                    ),
990✔
3506
                    (dbIndex) => dbIndex["INDEX_NAME"],
990✔
3507
                )
990✔
3508

990✔
3509
                table.indices = tableIndexConstraints.map((constraint) => {
990✔
3510
                    const indices = dbIndices.filter((index) => {
288✔
3511
                        return (
964✔
3512
                            index["TABLE_CATALOG"] ===
964✔
3513
                                constraint["TABLE_CATALOG"] &&
964✔
3514
                            index["TABLE_SCHEMA"] ===
964✔
3515
                                constraint["TABLE_SCHEMA"] &&
964✔
3516
                            index["TABLE_NAME"] === constraint["TABLE_NAME"] &&
964✔
3517
                            index["INDEX_NAME"] === constraint["INDEX_NAME"]
694✔
3518
                        )
964✔
3519
                    })
288✔
3520
                    return new TableIndex(<TableIndexOptions>{
288✔
3521
                        table: table,
288✔
3522
                        name: constraint["INDEX_NAME"],
288✔
3523
                        columnNames: indices.map((i) => i["COLUMN_NAME"]),
288✔
3524
                        isUnique: constraint["IS_UNIQUE"],
288✔
3525
                        where: constraint["CONDITION"],
288✔
3526
                    })
288✔
3527
                })
990✔
3528

990✔
3529
                return table
990✔
3530
            }),
666✔
3531
        )
666✔
3532
    }
666✔
3533

26✔
3534
    /**
26✔
3535
     * Builds and returns SQL for create table.
26✔
3536
     */
26✔
3537
    protected createTableSql(table: Table, createForeignKeys?: boolean): Query {
26✔
3538
        const columnDefinitions = table.columns
10,012✔
3539
            .map((column) =>
10,012✔
3540
                this.buildCreateColumnSql(table, column, false, true),
10,012✔
3541
            )
10,012✔
3542
            .join(", ")
10,012✔
3543
        let sql = `CREATE TABLE ${this.escapePath(table)} (${columnDefinitions}`
10,012✔
3544

10,012✔
3545
        table.columns
10,012✔
3546
            .filter((column) => column.isUnique)
10,012✔
3547
            .forEach((column) => {
10,012✔
3548
                const isUniqueExist = table.uniques.some(
642✔
3549
                    (unique) =>
642✔
3550
                        unique.columnNames.length === 1 &&
776✔
3551
                        unique.columnNames[0] === column.name,
642✔
3552
                )
642✔
3553
                if (!isUniqueExist)
642✔
3554
                    table.uniques.push(
642✔
3555
                        new TableUnique({
8✔
3556
                            name: this.connection.namingStrategy.uniqueConstraintName(
8✔
3557
                                table,
8✔
3558
                                [column.name],
8✔
3559
                            ),
8✔
3560
                            columnNames: [column.name],
8✔
3561
                        }),
8✔
3562
                    )
8✔
3563
            })
10,012✔
3564

10,012✔
3565
        if (table.uniques.length > 0) {
10,012✔
3566
            const uniquesSql = table.uniques
596✔
3567
                .map((unique) => {
596✔
3568
                    const uniqueName = unique.name
868✔
3569
                        ? unique.name
868✔
3570
                        : this.connection.namingStrategy.uniqueConstraintName(
868✔
3571
                              table,
4✔
3572
                              unique.columnNames,
4✔
3573
                          )
868✔
3574
                    const columnNames = unique.columnNames
868✔
3575
                        .map((columnName) => `"${columnName}"`)
868✔
3576
                        .join(", ")
868✔
3577
                    return `CONSTRAINT "${uniqueName}" UNIQUE (${columnNames})`
868✔
3578
                })
596✔
3579
                .join(", ")
596✔
3580

596✔
3581
            sql += `, ${uniquesSql}`
596✔
3582
        }
596✔
3583

10,012✔
3584
        if (table.checks.length > 0) {
10,012✔
3585
            const checksSql = table.checks
146✔
3586
                .map((check) => {
146✔
3587
                    const checkName = check.name
148✔
3588
                        ? check.name
148✔
3589
                        : this.connection.namingStrategy.checkConstraintName(
148✔
3590
                              table,
2✔
3591
                              check.expression!,
2✔
3592
                          )
148✔
3593
                    return `CONSTRAINT "${checkName}" CHECK (${check.expression})`
148✔
3594
                })
146✔
3595
                .join(", ")
146✔
3596

146✔
3597
            sql += `, ${checksSql}`
146✔
3598
        }
146✔
3599

10,012✔
3600
        if (table.foreignKeys.length > 0 && createForeignKeys) {
10,012✔
3601
            const foreignKeysSql = table.foreignKeys
8✔
3602
                .map((fk) => {
8✔
3603
                    const columnNames = fk.columnNames
10✔
3604
                        .map((columnName) => `"${columnName}"`)
10✔
3605
                        .join(", ")
10✔
3606
                    if (!fk.name)
10✔
3607
                        fk.name = this.connection.namingStrategy.foreignKeyName(
10✔
3608
                            table,
6✔
3609
                            fk.columnNames,
6✔
3610
                            this.getTablePath(fk),
6✔
3611
                            fk.referencedColumnNames,
6✔
3612
                        )
6✔
3613
                    const referencedColumnNames = fk.referencedColumnNames
10✔
3614
                        .map((columnName) => `"${columnName}"`)
10✔
3615
                        .join(", ")
10✔
3616

10✔
3617
                    let constraint = `CONSTRAINT "${
10✔
3618
                        fk.name
10✔
3619
                    }" FOREIGN KEY (${columnNames}) REFERENCES ${this.escapePath(
10✔
3620
                        this.getTablePath(fk),
10✔
3621
                    )} (${referencedColumnNames})`
10✔
3622
                    if (fk.onDelete) constraint += ` ON DELETE ${fk.onDelete}`
10✔
3623
                    if (fk.onUpdate) constraint += ` ON UPDATE ${fk.onUpdate}`
10✔
3624

10✔
3625
                    return constraint
10✔
3626
                })
8✔
3627
                .join(", ")
8✔
3628

8✔
3629
            sql += `, ${foreignKeysSql}`
8✔
3630
        }
8✔
3631

10,012✔
3632
        const primaryColumns = table.columns.filter(
10,012✔
3633
            (column) => column.isPrimary,
10,012✔
3634
        )
10,012✔
3635
        if (primaryColumns.length > 0) {
10,012✔
3636
            const primaryKeyName = primaryColumns[0].primaryKeyConstraintName
9,986✔
3637
                ? primaryColumns[0].primaryKeyConstraintName
9,986✔
3638
                : this.connection.namingStrategy.primaryKeyName(
9,986✔
3639
                      table,
9,954✔
3640
                      primaryColumns.map((column) => column.name),
9,954✔
3641
                  )
9,986✔
3642

9,986✔
3643
            const columnNames = primaryColumns
9,986✔
3644
                .map((column) => `"${column.name}"`)
9,986✔
3645
                .join(", ")
9,986✔
3646
            sql += `, CONSTRAINT "${primaryKeyName}" PRIMARY KEY (${columnNames})`
9,986✔
3647
        }
9,986✔
3648

10,012✔
3649
        sql += `)`
10,012✔
3650

10,012✔
3651
        return new Query(sql)
10,012✔
3652
    }
10,012✔
3653

26✔
3654
    /**
26✔
3655
     * Builds drop table sql.
26✔
3656
     */
26✔
3657
    protected dropTableSql(
26✔
3658
        tableOrName: Table | string,
10,012✔
3659
        ifExist?: boolean,
10,012✔
3660
    ): Query {
10,012✔
3661
        const query = ifExist
10,012✔
3662
            ? `DROP TABLE IF EXISTS ${this.escapePath(tableOrName)}`
10,012!
3663
            : `DROP TABLE ${this.escapePath(tableOrName)}`
10,012✔
3664
        return new Query(query)
10,012✔
3665
    }
10,012✔
3666

26✔
3667
    protected createViewSql(view: View): Query {
26✔
3668
        const parsedName = this.driver.parseTableName(view)
16✔
3669

16✔
3670
        // Can't use `escapePath` here because `CREATE VIEW` does not accept database names.
16✔
3671
        const viewIdentifier = parsedName.schema
16✔
3672
            ? `"${parsedName.schema}"."${parsedName.tableName}"`
16✔
3673
            : `"${parsedName.tableName}"`
16!
3674

16✔
3675
        if (typeof view.expression === "string") {
16✔
3676
            return new Query(
4✔
3677
                `CREATE VIEW ${viewIdentifier} AS ${view.expression}`,
4✔
3678
            )
4✔
3679
        } else {
16✔
3680
            return new Query(
12✔
3681
                `CREATE VIEW ${viewIdentifier} AS ${view
12✔
3682
                    .expression(this.connection)
12✔
3683
                    .getQuery()}`,
12✔
3684
            )
12✔
3685
        }
12✔
3686
    }
16✔
3687

26✔
3688
    protected async insertViewDefinitionSql(view: View): Promise<Query> {
26✔
3689
        const parsedTableName = this.driver.parseTableName(view)
16✔
3690

16✔
3691
        if (!parsedTableName.schema) {
16!
UNCOV
3692
            parsedTableName.schema = await this.getCurrentSchema()
×
UNCOV
3693
        }
×
3694

16✔
3695
        const expression =
16✔
3696
            typeof view.expression === "string"
16✔
3697
                ? view.expression.trim()
16✔
3698
                : view.expression(this.connection).getQuery()
16✔
3699
        return this.insertTypeormMetadataSql({
16✔
3700
            type: MetadataTableType.VIEW,
16✔
3701
            database: parsedTableName.database,
16✔
3702
            schema: parsedTableName.schema,
16✔
3703
            name: parsedTableName.tableName,
16✔
3704
            value: expression,
16✔
3705
        })
16✔
3706
    }
16✔
3707

26✔
3708
    /**
26✔
3709
     * Builds drop view sql.
26✔
3710
     */
26✔
3711
    protected dropViewSql(viewOrPath: View | string): Query {
26✔
3712
        return new Query(`DROP VIEW ${this.escapePath(viewOrPath)}`)
16✔
3713
    }
16✔
3714

26✔
3715
    /**
26✔
3716
     * Builds remove view sql.
26✔
3717
     */
26✔
3718
    protected async deleteViewDefinitionSql(
26✔
3719
        viewOrPath: View | string,
16✔
3720
    ): Promise<Query> {
16✔
3721
        const parsedTableName = this.driver.parseTableName(viewOrPath)
16✔
3722

16✔
3723
        if (!parsedTableName.schema) {
16!
UNCOV
3724
            parsedTableName.schema = await this.getCurrentSchema()
×
UNCOV
3725
        }
×
3726

16✔
3727
        return this.deleteTypeormMetadataSql({
16✔
3728
            type: MetadataTableType.VIEW,
16✔
3729
            database: parsedTableName.database,
16✔
3730
            schema: parsedTableName.schema,
16✔
3731
            name: parsedTableName.tableName,
16✔
3732
        })
16✔
3733
    }
16✔
3734

26✔
3735
    /**
26✔
3736
     * Builds create index sql.
26✔
3737
     */
26✔
3738
    protected createIndexSql(table: Table, index: TableIndex): Query {
26✔
3739
        const columns = index.columnNames
4,354✔
3740
            .map((columnName) => `"${columnName}"`)
4,354✔
3741
            .join(", ")
4,354✔
3742
        return new Query(
4,354✔
3743
            `CREATE ${index.isUnique ? "UNIQUE " : ""}INDEX "${
4,354✔
3744
                index.name
4,354✔
3745
            }" ON ${this.escapePath(table)} (${columns}) ${
4,354✔
3746
                index.where ? "WHERE " + index.where : ""
4,354✔
3747
            }`,
4,354✔
3748
        )
4,354✔
3749
    }
4,354✔
3750

26✔
3751
    /**
26✔
3752
     * Builds drop index sql.
26✔
3753
     */
26✔
3754
    protected dropIndexSql(
26✔
3755
        table: Table,
4,354✔
3756
        indexOrName: TableIndex | string,
4,354✔
3757
    ): Query {
4,354✔
3758
        const indexName = InstanceChecker.isTableIndex(indexOrName)
4,354✔
3759
            ? indexOrName.name
4,354✔
3760
            : indexOrName
4,354!
3761
        return new Query(
4,354✔
3762
            `DROP INDEX "${indexName}" ON ${this.escapePath(table)}`,
4,354✔
3763
        )
4,354✔
3764
    }
4,354✔
3765

26✔
3766
    /**
26✔
3767
     * Builds create primary key sql.
26✔
3768
     */
26✔
3769
    protected createPrimaryKeySql(
26✔
3770
        table: Table,
10✔
3771
        columnNames: string[],
10✔
3772
        constraintName?: string,
10✔
3773
    ): Query {
10✔
3774
        const primaryKeyName = constraintName
10✔
3775
            ? constraintName
10!
3776
            : this.connection.namingStrategy.primaryKeyName(table, columnNames)
10✔
3777

10✔
3778
        const columnNamesString = columnNames
10✔
3779
            .map((columnName) => `"${columnName}"`)
10✔
3780
            .join(", ")
10✔
3781
        return new Query(
10✔
3782
            `ALTER TABLE ${this.escapePath(
10✔
3783
                table,
10✔
3784
            )} ADD CONSTRAINT "${primaryKeyName}" PRIMARY KEY (${columnNamesString})`,
10✔
3785
        )
10✔
3786
    }
10✔
3787

26✔
3788
    /**
26✔
3789
     * Builds drop primary key sql.
26✔
3790
     */
26✔
3791
    protected dropPrimaryKeySql(table: Table): Query {
26✔
3792
        const columnNames = table.primaryColumns.map((column) => column.name)
10✔
3793
        const constraintName = table.primaryColumns[0].primaryKeyConstraintName
10✔
3794
        const primaryKeyName = constraintName
10✔
3795
            ? constraintName
10!
3796
            : this.connection.namingStrategy.primaryKeyName(table, columnNames)
10✔
3797

10✔
3798
        return new Query(
10✔
3799
            `ALTER TABLE ${this.escapePath(
10✔
3800
                table,
10✔
3801
            )} DROP CONSTRAINT "${primaryKeyName}"`,
10✔
3802
        )
10✔
3803
    }
10✔
3804

26✔
3805
    /**
26✔
3806
     * Builds create unique constraint sql.
26✔
3807
     */
26✔
3808
    protected createUniqueConstraintSql(
26✔
3809
        table: Table,
38✔
3810
        uniqueConstraint: TableUnique,
38✔
3811
    ): Query {
38✔
3812
        const columnNames = uniqueConstraint.columnNames
38✔
3813
            .map((column) => `"` + column + `"`)
38✔
3814
            .join(", ")
38✔
3815
        return new Query(
38✔
3816
            `ALTER TABLE ${this.escapePath(table)} ADD CONSTRAINT "${
38✔
3817
                uniqueConstraint.name
38✔
3818
            }" UNIQUE (${columnNames})`,
38✔
3819
        )
38✔
3820
    }
38✔
3821

26✔
3822
    /**
26✔
3823
     * Builds drop unique constraint sql.
26✔
3824
     */
26✔
3825
    protected dropUniqueConstraintSql(
26✔
3826
        table: Table,
38✔
3827
        uniqueOrName: TableUnique | string,
38✔
3828
    ): Query {
38✔
3829
        const uniqueName = InstanceChecker.isTableUnique(uniqueOrName)
38✔
3830
            ? uniqueOrName.name
38✔
3831
            : uniqueOrName
38!
3832
        return new Query(
38✔
3833
            `ALTER TABLE ${this.escapePath(
38✔
3834
                table,
38✔
3835
            )} DROP CONSTRAINT "${uniqueName}"`,
38✔
3836
        )
38✔
3837
    }
38✔
3838

26✔
3839
    /**
26✔
3840
     * Builds create check constraint sql.
26✔
3841
     */
26✔
3842
    protected createCheckConstraintSql(
26✔
3843
        table: Table,
24✔
3844
        checkConstraint: TableCheck,
24✔
3845
    ): Query {
24✔
3846
        return new Query(
24✔
3847
            `ALTER TABLE ${this.escapePath(table)} ADD CONSTRAINT "${
24✔
3848
                checkConstraint.name
24✔
3849
            }" CHECK (${checkConstraint.expression})`,
24✔
3850
        )
24✔
3851
    }
24✔
3852

26✔
3853
    /**
26✔
3854
     * Builds drop check constraint sql.
26✔
3855
     */
26✔
3856
    protected dropCheckConstraintSql(
26✔
3857
        table: Table,
24✔
3858
        checkOrName: TableCheck | string,
24✔
3859
    ): Query {
24✔
3860
        const checkName = InstanceChecker.isTableCheck(checkOrName)
24✔
3861
            ? checkOrName.name
24✔
3862
            : checkOrName
24!
3863
        return new Query(
24✔
3864
            `ALTER TABLE ${this.escapePath(
24✔
3865
                table,
24✔
3866
            )} DROP CONSTRAINT "${checkName}"`,
24✔
3867
        )
24✔
3868
    }
24✔
3869

26✔
3870
    /**
26✔
3871
     * Builds create foreign key sql.
26✔
3872
     */
26✔
3873
    protected createForeignKeySql(
26✔
3874
        table: Table,
6,624✔
3875
        foreignKey: TableForeignKey,
6,624✔
3876
    ): Query {
6,624✔
3877
        const columnNames = foreignKey.columnNames
6,624✔
3878
            .map((column) => `"` + column + `"`)
6,624✔
3879
            .join(", ")
6,624✔
3880
        const referencedColumnNames = foreignKey.referencedColumnNames
6,624✔
3881
            .map((column) => `"` + column + `"`)
6,624✔
3882
            .join(",")
6,624✔
3883
        let sql =
6,624✔
3884
            `ALTER TABLE ${this.escapePath(table)} ADD CONSTRAINT "${
6,624✔
3885
                foreignKey.name
6,624✔
3886
            }" FOREIGN KEY (${columnNames}) ` +
6,624✔
3887
            `REFERENCES ${this.escapePath(
6,624✔
3888
                this.getTablePath(foreignKey),
6,624✔
3889
            )}(${referencedColumnNames})`
6,624✔
3890
        if (foreignKey.onDelete) sql += ` ON DELETE ${foreignKey.onDelete}`
6,624✔
3891
        if (foreignKey.onUpdate) sql += ` ON UPDATE ${foreignKey.onUpdate}`
6,624✔
3892

6,624✔
3893
        return new Query(sql)
6,624✔
3894
    }
6,624✔
3895

26✔
3896
    /**
26✔
3897
     * Builds drop foreign key sql.
26✔
3898
     */
26✔
3899
    protected dropForeignKeySql(
26✔
3900
        table: Table,
6,634✔
3901
        foreignKeyOrName: TableForeignKey | string,
6,634✔
3902
    ): Query {
6,634✔
3903
        const foreignKeyName = InstanceChecker.isTableForeignKey(
6,634✔
3904
            foreignKeyOrName,
6,634✔
3905
        )
6,634✔
3906
            ? foreignKeyOrName.name
6,634✔
3907
            : foreignKeyOrName
6,634!
3908
        return new Query(
6,634✔
3909
            `ALTER TABLE ${this.escapePath(
6,634✔
3910
                table,
6,634✔
3911
            )} DROP CONSTRAINT "${foreignKeyName}"`,
6,634✔
3912
        )
6,634✔
3913
    }
6,634✔
3914

26✔
3915
    /**
26✔
3916
     * Escapes given table or View path.
26✔
3917
     */
26✔
3918
    protected escapePath(target: Table | View | string): string {
26✔
3919
        const { database, schema, tableName } =
49,332✔
3920
            this.driver.parseTableName(target)
49,332✔
3921

49,332✔
3922
        if (database && database !== this.driver.database) {
49,332✔
3923
            if (schema && schema !== this.driver.searchSchema) {
96✔
3924
                return `"${database}"."${schema}"."${tableName}"`
84✔
3925
            }
84✔
3926

12✔
3927
            return `"${database}".."${tableName}"`
12✔
3928
        }
12✔
3929

49,236✔
3930
        if (schema && schema !== this.driver.searchSchema) {
49,332✔
3931
            return `"${schema}"."${tableName}"`
140✔
3932
        }
140✔
3933

49,096✔
3934
        return `"${tableName}"`
49,096✔
3935
    }
49,096✔
3936

26✔
3937
    /**
26✔
3938
     * Concat database name and schema name to the foreign key name.
26✔
3939
     * Needs because FK name is relevant to the schema and database.
26✔
3940
     */
26✔
3941
    protected buildForeignKeyName(
26✔
3942
        fkName: string,
8✔
3943
        schemaName: string | undefined,
8✔
3944
        dbName: string | undefined,
8✔
3945
    ): string {
8✔
3946
        let joinedFkName = fkName
8✔
3947
        if (schemaName && schemaName !== this.driver.searchSchema)
8✔
3948
            joinedFkName = schemaName + "." + joinedFkName
8✔
3949
        if (dbName && dbName !== this.driver.database)
8✔
3950
            joinedFkName = dbName + "." + joinedFkName
8✔
3951

8✔
3952
        return joinedFkName
8✔
3953
    }
8✔
3954

26✔
3955
    /**
26✔
3956
     * Removes parenthesis around default value.
26✔
3957
     * Sql server returns default value with parenthesis around, e.g.
26✔
3958
     *  ('My text') - for string
26✔
3959
     *  ((1)) - for number
26✔
3960
     *  (newsequentialId()) - for function
26✔
3961
     */
26✔
3962
    protected removeParenthesisFromDefault(defaultValue: string): any {
26✔
3963
        if (defaultValue.substr(0, 1) !== "(") return defaultValue
428✔
3964
        const normalizedDefault = defaultValue.substr(
216✔
3965
            1,
216✔
3966
            defaultValue.lastIndexOf(")") - 1,
216✔
3967
        )
216✔
3968
        return this.removeParenthesisFromDefault(normalizedDefault)
216✔
3969
    }
216✔
3970

26✔
3971
    /**
26✔
3972
     * Builds a query for create column.
26✔
3973
     */
26✔
3974
    protected buildCreateColumnSql(
26✔
3975
        table: Table,
32,430✔
3976
        column: TableColumn,
32,430✔
3977
        skipIdentity: boolean,
32,430✔
3978
        createDefault: boolean,
32,430✔
3979
        skipEnum?: boolean,
32,430✔
3980
    ) {
32,430✔
3981
        let c = `"${column.name}" ${this.connection.driver.createFullType(
32,430✔
3982
            column,
32,430✔
3983
        )}`
32,430✔
3984

32,430✔
3985
        if (!skipEnum && column.enum) {
32,430✔
3986
            const expression = this.getEnumExpression(column)
48✔
3987
            const checkName =
48✔
3988
                this.connection.namingStrategy.checkConstraintName(
48✔
3989
                    table,
48✔
3990
                    expression,
48✔
3991
                    true,
48✔
3992
                )
48✔
3993
            c += ` CONSTRAINT ${checkName} CHECK(${expression})`
48✔
3994
        }
48✔
3995

32,430✔
3996
        if (column.collation) c += " COLLATE " + column.collation
32,430✔
3997

32,430✔
3998
        if (column.asExpression) {
32,430✔
3999
            c += ` AS (${column.asExpression})`
78✔
4000
            if (column.generatedType === "STORED") {
78✔
4001
                c += ` PERSISTED`
42✔
4002

42✔
4003
                // NOT NULL can be specified for computed columns only if PERSISTED is also specified
42✔
4004
                if (column.isNullable !== true) c += " NOT NULL"
42✔
4005
            }
42✔
4006
        } else {
32,430✔
4007
            if (column.isNullable !== true) c += " NOT NULL"
32,352✔
4008
        }
32,352✔
4009

32,430✔
4010
        if (
32,430✔
4011
            column.isGenerated === true &&
32,430✔
4012
            column.generationStrategy === "increment" &&
32,430✔
4013
            !skipIdentity
5,944✔
4014
        )
32,430✔
4015
            // don't use skipPrimary here since updates can update already exist primary without auto inc.
32,430✔
4016
            c += " IDENTITY(1,1)"
32,430✔
4017

32,430✔
4018
        if (
32,430✔
4019
            column.default !== undefined &&
32,430✔
4020
            column.default !== null &&
32,430✔
4021
            createDefault
1,968✔
4022
        ) {
32,430✔
4023
            // we create named constraint to be able to delete this constraint when column been dropped
1,956✔
4024
            const defaultName =
1,956✔
4025
                this.connection.namingStrategy.defaultConstraintName(
1,956✔
4026
                    table,
1,956✔
4027
                    column.name,
1,956✔
4028
                )
1,956✔
4029
            c += ` CONSTRAINT "${defaultName}" DEFAULT ${column.default}`
1,956✔
4030
        }
1,956✔
4031

32,430✔
4032
        if (
32,430✔
4033
            column.isGenerated &&
32,430✔
4034
            column.generationStrategy === "uuid" &&
32,430✔
4035
            !column.default
256✔
4036
        ) {
32,430✔
4037
            // we create named constraint to be able to delete this constraint when column been dropped
256✔
4038
            const defaultName =
256✔
4039
                this.connection.namingStrategy.defaultConstraintName(
256✔
4040
                    table,
256✔
4041
                    column.name,
256✔
4042
                )
256✔
4043
            c += ` CONSTRAINT "${defaultName}" DEFAULT NEWSEQUENTIALID()`
256✔
4044
        }
256✔
4045
        return c
32,430✔
4046
    }
32,430✔
4047

26✔
4048
    private getEnumExpression(column: TableColumn) {
26✔
4049
        if (!column.enum) {
52!
UNCOV
4050
            throw new Error(`Enum is not defined in column ${column.name}`)
×
UNCOV
4051
        }
×
4052
        return (
52✔
4053
            column.name +
52✔
4054
            " IN (" +
52✔
4055
            column.enum.map((val) => "'" + val + "'").join(",") +
52✔
4056
            ")"
52✔
4057
        )
52✔
4058
    }
52✔
4059

26✔
4060
    protected isEnumCheckConstraint(name: string): boolean {
26✔
4061
        return name.indexOf("CHK_") !== -1 && name.indexOf("_ENUM") !== -1
206✔
4062
    }
206✔
4063

26✔
4064
    /**
26✔
4065
     * Converts MssqlParameter into real mssql parameter type.
26✔
4066
     */
26✔
4067
    protected mssqlParameterToNativeParameter(parameter: MssqlParameter): any {
26✔
4068
        switch (this.driver.normalizeType({ type: parameter.type as any })) {
52,892✔
4069
            case "bit":
52,892✔
4070
                return this.driver.mssql.Bit
4,042✔
4071
            case "bigint":
52,892✔
4072
                return this.driver.mssql.BigInt
64✔
4073
            case "decimal":
52,892✔
4074
                return this.driver.mssql.Decimal(...parameter.params)
8✔
4075
            case "float":
52,892✔
4076
                return this.driver.mssql.Float
60✔
4077
            case "int":
52,892✔
4078
                return this.driver.mssql.Int
23,936✔
4079
            case "money":
52,892✔
4080
                return this.driver.mssql.Money
2✔
4081
            case "numeric":
52,892✔
4082
                return this.driver.mssql.Numeric(...parameter.params)
4✔
4083
            case "smallint":
52,892✔
4084
                return this.driver.mssql.SmallInt
2✔
4085
            case "smallmoney":
52,892✔
4086
                return this.driver.mssql.SmallMoney
2✔
4087
            case "real":
52,892✔
4088
                return this.driver.mssql.Real
2✔
4089
            case "tinyint":
52,892✔
4090
                return this.driver.mssql.TinyInt
2✔
4091
            case "char":
52,892✔
4092
                if (
10✔
4093
                    this.driver.options.options
10✔
4094
                        ?.disableAsciiToUnicodeParamConversion
10✔
4095
                ) {
10✔
4096
                    return this.driver.mssql.Char(...parameter.params)
2✔
4097
                }
2✔
4098
                return this.driver.mssql.NChar(...parameter.params)
8✔
4099
            case "nchar":
52,892✔
4100
                return this.driver.mssql.NChar(...parameter.params)
4✔
4101
            case "text":
52,892✔
4102
                if (
10✔
4103
                    this.driver.options.options
10✔
4104
                        ?.disableAsciiToUnicodeParamConversion
10!
4105
                ) {
10!
UNCOV
4106
                    return this.driver.mssql.Text
×
UNCOV
4107
                }
×
4108
                return this.driver.mssql.Ntext
10✔
4109
            case "ntext":
52,892✔
4110
                return this.driver.mssql.Ntext
14✔
4111
            case "varchar":
52,892✔
4112
                if (
170✔
4113
                    this.driver.options.options
170✔
4114
                        ?.disableAsciiToUnicodeParamConversion
170✔
4115
                ) {
170✔
4116
                    return this.driver.mssql.VarChar(...parameter.params)
2✔
4117
                }
2✔
4118
                return this.driver.mssql.NVarChar(...parameter.params)
168✔
4119
            case "nvarchar":
52,892✔
4120
                return this.driver.mssql.NVarChar(...parameter.params)
23,886✔
4121
            case "xml":
52,892!
UNCOV
4122
                return this.driver.mssql.Xml
×
4123
            case "time":
52,892✔
4124
                return this.driver.mssql.Time(...parameter.params)
12✔
4125
            case "date":
52,892✔
4126
                return this.driver.mssql.Date
10✔
4127
            case "datetime":
52,892✔
4128
                return this.driver.mssql.DateTime
44✔
4129
            case "datetime2":
52,892✔
4130
                return this.driver.mssql.DateTime2(...parameter.params)
24✔
4131
            case "datetimeoffset":
52,892✔
4132
                return this.driver.mssql.DateTimeOffset(...parameter.params)
8✔
4133
            case "smalldatetime":
52,892✔
4134
                return this.driver.mssql.SmallDateTime
2✔
4135
            case "uniqueidentifier":
52,892✔
4136
                return this.driver.mssql.UniqueIdentifier
502✔
4137
            case "variant":
52,892!
UNCOV
4138
                return this.driver.mssql.Variant
×
4139
            case "binary":
52,892✔
4140
                return this.driver.mssql.Binary
26✔
4141
            case "varbinary":
52,892✔
4142
                return this.driver.mssql.VarBinary(...parameter.params)
4✔
4143
            case "image":
52,892✔
4144
                return this.driver.mssql.Image
2✔
4145
            case "udt":
52,892!
4146
                return this.driver.mssql.UDT
×
4147
            case "rowversion":
52,892!
UNCOV
4148
                return this.driver.mssql.RowVersion
×
4149
            case "vector":
52,892✔
4150
                return this.driver.mssql.Ntext
20✔
4151
        }
52,892✔
4152
    }
52,892✔
4153

26✔
4154
    /**
26✔
4155
     * Converts string literal of isolation level to enum.
26✔
4156
     * The underlying mssql driver requires an enum for the isolation level.
26✔
4157
     */
26✔
4158
    convertIsolationLevel(isolation: IsolationLevel) {
26✔
4159
        const ISOLATION_LEVEL = this.driver.mssql.ISOLATION_LEVEL
12✔
4160
        switch (isolation) {
12✔
4161
            case "READ UNCOMMITTED":
12✔
4162
                return ISOLATION_LEVEL.READ_UNCOMMITTED
4✔
4163
            case "REPEATABLE READ":
12✔
4164
                return ISOLATION_LEVEL.REPEATABLE_READ
2✔
4165
            case "SERIALIZABLE":
12✔
4166
                return ISOLATION_LEVEL.SERIALIZABLE
4✔
4167

12✔
4168
            case "READ COMMITTED":
12✔
4169
            default:
12✔
4170
                return ISOLATION_LEVEL.READ_COMMITTED
2✔
4171
        }
12✔
4172
    }
12✔
4173

26✔
4174
    /**
26✔
4175
     * Change table comment.
26✔
4176
     */
26✔
4177
    changeTableComment(
26✔
4178
        tableOrName: Table | string,
×
4179
        comment?: string,
×
4180
    ): Promise<void> {
×
4181
        throw new TypeORMError(
×
4182
            `sqlserver driver does not support change table comment.`,
×
UNCOV
4183
        )
×
UNCOV
4184
    }
×
4185
}
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