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

typeorm / typeorm / 14796576772

02 May 2025 01:52PM UTC coverage: 45.367% (-30.9%) from 76.309%
14796576772

Pull #11434

github

web-flow
Merge ec4ce2d00 into fadad1a74
Pull Request #11434: feat: release PR releases using pkg.pr.new

5216 of 12761 branches covered (40.87%)

Branch coverage included in aggregate %.

11439 of 23951 relevant lines covered (47.76%)

15712.55 hits per line

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

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

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

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

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

52
    private lock: QueryLock = new QueryLock()
×
53

54
    // -------------------------------------------------------------------------
55
    // Constructor
56
    // -------------------------------------------------------------------------
57

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

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

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

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

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

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

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

135
        await this.broadcaster.broadcast("AfterTransactionStart")
×
136
    }
137

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

145
        if (!this.isTransactionActive) throw new TransactionNotStartedError()
×
146

147
        await this.broadcaster.broadcast("BeforeTransactionCommit")
×
148

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

156
                    await this.broadcaster.broadcast("AfterTransactionCommit")
×
157

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

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

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

176
        await this.broadcaster.broadcast("BeforeTransactionRollback")
×
177

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

190
                    await this.broadcaster.broadcast("AfterTransactionRollback")
×
191

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

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

210
        const release = await this.lock.acquire()
×
211

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

215
        const broadcasterResult = new BroadcasterResult()
×
216

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

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

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

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

276
                    if (err) {
×
277
                        fail(new QueryFailedError(query, parameters, err))
×
278
                    }
279

280
                    ok(raw)
×
281
                })
282
            })
283

284
            const result = new QueryResult()
×
285

286
            if (raw?.hasOwnProperty("recordset")) {
×
287
                result.records = raw.recordset
×
288
            }
289

290
            if (raw?.hasOwnProperty("rowsAffected")) {
×
291
                result.affected = raw.rowsAffected[0]
×
292
            }
293

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

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

326
            throw err
×
327
        } finally {
328
            await broadcasterResult.wait()
×
329

330
            release()
×
331
        }
332
    }
333

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

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

347
        this.driver.connection.logger.logQuery(query, parameters, this)
×
348
        const pool = await (this.mode === "slave"
×
349
            ? this.driver.obtainSlaveConnection()
350
            : this.driver.obtainMasterConnection())
351
        const request = new this.driver.mssql.Request(
×
352
            this.isTransactionActive ? this.databaseConnection : pool,
×
353
        )
354
        if (parameters && parameters.length) {
×
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

369
        request.query(query)
×
370

371
        const streamRequest = request.toReadableStream()
×
372

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

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

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

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

395
        return streamRequest
×
396
    }
397

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

406
    /**
407
     * Returns all available schema names including system schemas.
408
     * If database parameter specified, returns schemas of that database.
409
     */
410
    async getSchemas(database?: string): Promise<string[]> {
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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

569
        if (schemaPath.indexOf(".") === -1) {
×
570
            const upQuery = ifExist
×
571
                ? `IF SCHEMA_ID('${schemaPath}') IS NULL BEGIN EXEC ('DROP SCHEMA "${schemaPath}"') END`
572
                : `DROP SCHEMA "${schemaPath}"`
573
            upQueries.push(new Query(upQuery))
×
574
            downQueries.push(new Query(`CREATE SCHEMA "${schemaPath}"`))
×
575
        } else {
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

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

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

611
        upQueries.push(this.createTableSql(table, createForeignKeys))
×
612
        downQueries.push(this.dropTableSql(table))
×
613

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

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

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

640
        for (const column of generatedColumns) {
×
641
            const parsedTableName = this.driver.parseTableName(table)
×
642

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

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

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

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

668
        await this.executeQueries(upQueries, downQueries)
×
669
    }
670

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

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

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

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

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

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

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

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

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

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

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

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

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

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

767
    /**
768
     * Drops the view.
769
     */
770
    async dropView(target: View | string): Promise<void> {
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

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

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

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

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

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

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

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

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

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

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

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

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

910
            // replace constraint name
911
            unique.name = newUniqueName
×
912
        })
913

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

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

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

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

948
            // replace constraint name
949
            index.name = newIndexName
×
950
        })
951

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

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

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

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

994
            // replace constraint name
995
            foreignKey.name = newForeignKeyName
×
996
        })
997

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

1004
        await this.executeQueries(upQueries, downQueries)
×
1005

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

1185
        await this.executeQueries(upQueries, downQueries)
×
1186

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

1396
                    // replace constraint name
1397
                    index.name = newIndexName
×
1398
                })
1399

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

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

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

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

1449
                        // replace constraint name
1450
                        foreignKey.name = newForeignKeyName
×
1451
                    })
1452

1453
                // rename check constraints
1454
                clonedTable.findColumnChecks(oldColumn).forEach((check) => {
×
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
                })
1486

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

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

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

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

1526
                    // replace constraint name
1527
                    unique.name = newUniqueName
×
1528
                })
1529

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

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

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

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

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

1597
            if (
×
1598
                this.isColumnChanged(oldColumn, newColumn, false, false, false)
1599
            ) {
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

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

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

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

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

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

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

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

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

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

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

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

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

1764
            if (newColumn.isUnique !== oldColumn.isUnique) {
×
1765
                if (newColumn.isUnique === true) {
×
1766
                    const uniqueConstraint = new TableUnique({
×
1767
                        name: this.connection.namingStrategy.uniqueConstraintName(
1768
                            table,
1769
                            [newColumn.name],
1770
                        ),
1771
                        columnNames: [newColumn.name],
1772
                    })
1773
                    clonedTable.uniques.push(uniqueConstraint)
×
1774
                    upQueries.push(
×
1775
                        new Query(
1776
                            `ALTER TABLE ${this.escapePath(
1777
                                table,
1778
                            )} ADD CONSTRAINT "${
1779
                                uniqueConstraint.name
1780
                            }" UNIQUE ("${newColumn.name}")`,
1781
                        ),
1782
                    )
1783
                    downQueries.push(
×
1784
                        new Query(
1785
                            `ALTER TABLE ${this.escapePath(
1786
                                table,
1787
                            )} DROP CONSTRAINT "${uniqueConstraint.name}"`,
1788
                        ),
1789
                    )
1790
                } else {
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
            }
1824

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

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

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

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

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

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

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

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

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

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

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

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

1985
        // drop column index
1986
        const columnIndex = clonedTable.indices.find(
×
1987
            (index) =>
1988
                index.columnNames.length === 1 &&
×
1989
                index.columnNames[0] === column.name,
1990
        )
1991
        if (columnIndex) {
×
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

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

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

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

2058
        if (column.generatedType && column.asExpression) {
×
2059
            const parsedTableName = this.driver.parseTableName(table)
×
2060

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

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

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

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

2105
        await this.executeQueries(upQueries, downQueries)
×
2106

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

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

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

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

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

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

2149
    /**
2150
     * Updates composite primary keys.
2151
     */
2152
    async updatePrimaryKeys(
2153
        tableOrName: Table | string,
2154
        columns: TableColumn[],
2155
    ): Promise<void> {
2156
        const table = InstanceChecker.isTable(tableOrName)
×
2157
            ? tableOrName
2158
            : await this.getCachedTable(tableOrName)
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) {
×
2167
            const pkName = primaryColumns[0].primaryKeyConstraintName
×
2168
                ? primaryColumns[0].primaryKeyConstraintName
2169
                : this.connection.namingStrategy.primaryKeyName(
2170
                      clonedTable,
2171
                      primaryColumns.map((column) => column.name),
×
2172
                  )
2173

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

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

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

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

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

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

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

2229
    /**
2230
     * Drops a primary key.
2231
     */
2232
    async dropPrimaryKey(
2233
        tableOrName: Table | string,
2234
        constraintName?: string,
2235
    ): Promise<void> {
2236
        const table = InstanceChecker.isTable(tableOrName)
×
2237
            ? tableOrName
2238
            : await this.getCachedTable(tableOrName)
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) => {
×
2247
            column.isPrimary = false
×
2248
        })
2249
    }
2250

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

2425
    /**
2426
     * Drops exclusion constraint.
2427
     */
2428
    async dropExclusionConstraint(
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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

2655
            if (allTablesResults.length > 0) {
×
2656
                const tablesByCatalog: {
2657
                    [key: string]: {
2658
                        TABLE_NAME: string
2659
                        TABLE_SCHEMA: string
2660
                    }[]
2661
                } = allTablesResults.reduce(
×
2662
                    (c, { TABLE_CATALOG, TABLE_SCHEMA, TABLE_NAME }) => {
2663
                        c[TABLE_CATALOG] = c[TABLE_CATALOG] || []
×
2664
                        c[TABLE_CATALOG].push({ TABLE_SCHEMA, TABLE_NAME })
×
2665
                        return c
×
2666
                    },
2667
                    {},
2668
                )
2669

2670
                const foreignKeysSql = Object.entries(tablesByCatalog)
×
2671
                    .map(([TABLE_CATALOG, tables]) => {
2672
                        const conditions = tables
×
2673
                            .map(({ TABLE_SCHEMA, TABLE_NAME }) => {
2674
                                return `("fk"."referenced_object_id" = OBJECT_ID('"${TABLE_CATALOG}"."${TABLE_SCHEMA}"."${TABLE_NAME}"'))`
×
2675
                            })
2676
                            .join(" OR ")
2677

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

2690
                const foreignKeys: {
2691
                    TABLE_CATALOG: string
2692
                    TABLE_SCHEMA: string
2693
                    TABLE_NAME: string
2694
                    CONSTRAINT_NAME: string
2695
                }[] = await this.query(foreignKeysSql)
×
2696

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

2711
                            await this.query(
×
2712
                                `ALTER TABLE "${TABLE_CATALOG}"."${TABLE_SCHEMA}"."${TABLE_NAME}" ` +
2713
                                    `DROP CONSTRAINT "${CONSTRAINT_NAME}" -- FROM CLEAR`,
2714
                            )
2715
                        },
2716
                    ),
2717
                )
2718

2719
                await Promise.all(
×
2720
                    allTablesResults.map((tablesResult) => {
2721
                        if (tablesResult["TABLE_NAME"].startsWith("#")) {
×
2722
                            // don't try to drop temporary tables
2723
                            return
×
2724
                        }
2725

2726
                        const dropTableSql = `DROP TABLE "${tablesResult["TABLE_CATALOG"]}"."${tablesResult["TABLE_SCHEMA"]}"."${tablesResult["TABLE_NAME"]}"`
×
2727
                        return this.query(dropTableSql)
×
2728
                    }),
2729
                )
2730
            }
2731

2732
            if (!isAnotherTransactionActive) await this.commitTransaction()
×
2733
        } catch (error) {
2734
            try {
×
2735
                // we throw original error even if rollback thrown an error
2736
                if (!isAnotherTransactionActive)
×
2737
                    await this.rollbackTransaction()
×
2738
            } catch (rollbackError) {}
2739
            throw error
×
2740
        }
2741
    }
2742

2743
    // -------------------------------------------------------------------------
2744
    // Protected Methods
2745
    // -------------------------------------------------------------------------
2746

2747
    protected async loadViews(viewPaths?: string[]): Promise<View[]> {
2748
        const hasTable = await this.hasTable(this.getTypeormMetadataTableName())
×
2749
        if (!hasTable) {
×
2750
            return []
×
2751
        }
2752

2753
        if (!viewPaths) {
×
2754
            viewPaths = []
×
2755
        }
2756

2757
        const currentSchema = await this.getCurrentSchema()
×
2758
        const currentDatabase = await this.getCurrentDatabase()
×
2759

2760
        const dbNames = viewPaths
×
2761
            .map((viewPath) => this.driver.parseTableName(viewPath).database)
×
2762
            .filter((database) => database)
×
2763

2764
        if (
×
2765
            this.driver.database &&
×
2766
            !dbNames.find((dbName) => dbName === this.driver.database)
×
2767
        )
2768
            dbNames.push(this.driver.database)
×
2769

2770
        const viewsCondition = viewPaths
×
2771
            .map((viewPath) => {
2772
                let { schema, tableName: name } =
2773
                    this.driver.parseTableName(viewPath)
×
2774

2775
                if (!schema) {
×
2776
                    schema = currentSchema
×
2777
                }
2778
                return `("T"."SCHEMA" = '${schema}' AND "T"."NAME" = '${name}')`
×
2779
            })
2780
            .join(" OR ")
2781

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

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

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

2824
        const currentSchema = await this.getCurrentSchema()
×
2825
        const currentDatabase = await this.getCurrentDatabase()
×
2826

2827
        const dbTables: {
2828
            TABLE_CATALOG: string
2829
            TABLE_SCHEMA: string
2830
            TABLE_NAME: string
2831
        }[] = []
×
2832

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

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

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

2872
            const tablesSql = Object.entries(tableNamesByCatalog)
×
2873
                .map(([database, tables]) => {
2874
                    const tablesCondition = tables
×
2875
                        .map(({ schema, tableName }) => {
2876
                            return `("TABLE_SCHEMA" = '${schema}' AND "TABLE_NAME" = '${tableName}')`
×
2877
                        })
2878
                        .join(" OR ")
2879

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

2892
            dbTables.push(...(await this.query(tablesSql)))
×
2893
        }
2894

2895
        // if tables were not found in the db, no need to proceed
2896
        if (dbTables.length === 0) {
×
2897
            return []
×
2898
        }
2899

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

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

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

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

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

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

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

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

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

3001
        const dbCollationsSql = `SELECT "NAME", "COLLATION_NAME" FROM "sys"."databases"`
×
3002

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

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

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

3043
        // create table schemas for loaded tables
3044
        return await Promise.all(
×
3045
            dbTables.map(async (dbTable) => {
3046
                const table = new Table()
×
3047

3048
                const getSchemaFromKey = (dbObject: any, key: string) => {
×
3049
                    return dbObject[key] === currentSchema &&
×
3050
                        (!this.driver.options.schema ||
3051
                            this.driver.options.schema === currentSchema)
3052
                        ? undefined
3053
                        : dbObject[key]
3054
                }
3055

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

3070
                const defaultCollation = dbCollations.find(
×
3071
                    (dbCollation) =>
3072
                        dbCollation["NAME"] === dbTable["TABLE_CATALOG"],
×
3073
                )!
3074

3075
                // create columns from the loaded columns
3076
                table.columns = await Promise.all(
×
3077
                    dbColumns
3078
                        .filter(
3079
                            (dbColumn) =>
3080
                                dbColumn["TABLE_NAME"] ===
×
3081
                                    dbTable["TABLE_NAME"] &&
3082
                                dbColumn["TABLE_SCHEMA"] ===
3083
                                    dbTable["TABLE_SCHEMA"] &&
3084
                                dbColumn["TABLE_CATALOG"] ===
3085
                                    dbTable["TABLE_CATALOG"],
3086
                        )
3087
                        .map(async (dbColumn) => {
3088
                            const columnConstraints = dbConstraints.filter(
×
3089
                                (dbConstraint) =>
3090
                                    dbConstraint["TABLE_NAME"] ===
×
3091
                                        dbColumn["TABLE_NAME"] &&
3092
                                    dbConstraint["TABLE_SCHEMA"] ===
3093
                                        dbColumn["TABLE_SCHEMA"] &&
3094
                                    dbConstraint["TABLE_CATALOG"] ===
3095
                                        dbColumn["TABLE_CATALOG"] &&
3096
                                    dbConstraint["COLUMN_NAME"] ===
3097
                                        dbColumn["COLUMN_NAME"],
3098
                            )
3099

3100
                            const uniqueConstraints = columnConstraints.filter(
×
3101
                                (constraint) =>
3102
                                    constraint["CONSTRAINT_TYPE"] === "UNIQUE",
×
3103
                            )
3104
                            const isConstraintComposite =
3105
                                uniqueConstraints.every((uniqueConstraint) => {
×
3106
                                    return dbConstraints.some(
×
3107
                                        (dbConstraint) =>
3108
                                            dbConstraint["CONSTRAINT_TYPE"] ===
×
3109
                                                "UNIQUE" &&
3110
                                            dbConstraint["CONSTRAINT_NAME"] ===
3111
                                                uniqueConstraint[
3112
                                                    "CONSTRAINT_NAME"
3113
                                                ] &&
3114
                                            dbConstraint["TABLE_SCHEMA"] ===
3115
                                                dbColumn["TABLE_SCHEMA"] &&
3116
                                            dbConstraint["TABLE_CATALOG"] ===
3117
                                                dbColumn["TABLE_CATALOG"] &&
3118
                                            dbConstraint["COLUMN_NAME"] !==
3119
                                                dbColumn["COLUMN_NAME"],
3120
                                    )
3121
                                })
3122

3123
                            const isGenerated = !!dbIdentityColumns.find(
×
3124
                                (column) =>
3125
                                    column["TABLE_NAME"] ===
×
3126
                                        dbColumn["TABLE_NAME"] &&
3127
                                    column["TABLE_SCHEMA"] ===
3128
                                        dbColumn["TABLE_SCHEMA"] &&
3129
                                    column["TABLE_CATALOG"] ===
3130
                                        dbColumn["TABLE_CATALOG"] &&
3131
                                    column["COLUMN_NAME"] ===
3132
                                        dbColumn["COLUMN_NAME"],
3133
                            )
3134

3135
                            const tableColumn = new TableColumn()
×
3136
                            tableColumn.name = dbColumn["COLUMN_NAME"]
×
3137
                            tableColumn.type =
×
3138
                                dbColumn["DATA_TYPE"].toLowerCase()
3139

3140
                            // check only columns that have length property
3141
                            if (
×
3142
                                this.driver.withLengthColumnTypes.indexOf(
×
3143
                                    tableColumn.type as ColumnType,
3144
                                ) !== -1 &&
3145
                                dbColumn["CHARACTER_MAXIMUM_LENGTH"]
3146
                            ) {
3147
                                const length =
3148
                                    dbColumn[
×
3149
                                        "CHARACTER_MAXIMUM_LENGTH"
3150
                                    ].toString()
3151
                                if (length === "-1") {
×
3152
                                    tableColumn.length = "MAX"
×
3153
                                } else {
3154
                                    tableColumn.length =
×
3155
                                        !this.isDefaultColumnLength(
×
3156
                                            table,
3157
                                            tableColumn,
3158
                                            length,
3159
                                        )
3160
                                            ? length
3161
                                            : ""
3162
                                }
3163
                            }
3164

3165
                            if (
×
3166
                                tableColumn.type === "decimal" ||
×
3167
                                tableColumn.type === "numeric"
3168
                            ) {
3169
                                if (
×
3170
                                    dbColumn["NUMERIC_PRECISION"] !== null &&
×
3171
                                    !this.isDefaultColumnPrecision(
3172
                                        table,
3173
                                        tableColumn,
3174
                                        dbColumn["NUMERIC_PRECISION"],
3175
                                    )
3176
                                )
3177
                                    tableColumn.precision =
×
3178
                                        dbColumn["NUMERIC_PRECISION"]
3179
                                if (
×
3180
                                    dbColumn["NUMERIC_SCALE"] !== null &&
×
3181
                                    !this.isDefaultColumnScale(
3182
                                        table,
3183
                                        tableColumn,
3184
                                        dbColumn["NUMERIC_SCALE"],
3185
                                    )
3186
                                )
3187
                                    tableColumn.scale =
×
3188
                                        dbColumn["NUMERIC_SCALE"]
3189
                            }
3190

3191
                            if (tableColumn.type === "nvarchar") {
×
3192
                                // Check if this is an enum
3193
                                const columnCheckConstraints =
3194
                                    columnConstraints.filter(
×
3195
                                        (constraint) =>
3196
                                            constraint["CONSTRAINT_TYPE"] ===
×
3197
                                            "CHECK",
3198
                                    )
3199
                                if (columnCheckConstraints.length) {
×
3200
                                    // const isEnumRegexp = new RegExp("^\\(\\[" + tableColumn.name + "\\]='[^']+'(?: OR \\[" + tableColumn.name + "\\]='[^']+')*\\)$");
3201
                                    for (const checkConstraint of columnCheckConstraints) {
×
3202
                                        if (
×
3203
                                            this.isEnumCheckConstraint(
3204
                                                checkConstraint[
3205
                                                    "CONSTRAINT_NAME"
3206
                                                ],
3207
                                            )
3208
                                        ) {
3209
                                            // This is an enum constraint, make column into an enum
3210
                                            tableColumn.enum = []
×
3211
                                            const enumValueRegexp = new RegExp(
×
3212
                                                "\\[" +
3213
                                                    tableColumn.name +
3214
                                                    "\\]='([^']+)'",
3215
                                                "g",
3216
                                            )
3217
                                            let result
3218
                                            while (
×
3219
                                                (result = enumValueRegexp.exec(
3220
                                                    checkConstraint[
3221
                                                        "definition"
3222
                                                    ],
3223
                                                )) !== null
3224
                                            ) {
3225
                                                tableColumn.enum.unshift(
×
3226
                                                    result[1],
3227
                                                )
3228
                                            }
3229
                                            // Skip other column constraints
3230
                                            break
×
3231
                                        }
3232
                                    }
3233
                                }
3234
                            }
3235

3236
                            const primaryConstraint = columnConstraints.find(
×
3237
                                (constraint) =>
3238
                                    constraint["CONSTRAINT_TYPE"] ===
×
3239
                                    "PRIMARY KEY",
3240
                            )
3241
                            if (primaryConstraint) {
×
3242
                                tableColumn.isPrimary = true
×
3243
                                // find another columns involved in primary key constraint
3244
                                const anotherPrimaryConstraints =
3245
                                    dbConstraints.filter(
×
3246
                                        (constraint) =>
3247
                                            constraint["TABLE_NAME"] ===
×
3248
                                                dbColumn["TABLE_NAME"] &&
3249
                                            constraint["TABLE_SCHEMA"] ===
3250
                                                dbColumn["TABLE_SCHEMA"] &&
3251
                                            constraint["TABLE_CATALOG"] ===
3252
                                                dbColumn["TABLE_CATALOG"] &&
3253
                                            constraint["COLUMN_NAME"] !==
3254
                                                dbColumn["COLUMN_NAME"] &&
3255
                                            constraint["CONSTRAINT_TYPE"] ===
3256
                                                "PRIMARY KEY",
3257
                                    )
3258

3259
                                // collect all column names
3260
                                const columnNames =
3261
                                    anotherPrimaryConstraints.map(
×
3262
                                        (constraint) =>
3263
                                            constraint["COLUMN_NAME"],
×
3264
                                    )
3265
                                columnNames.push(dbColumn["COLUMN_NAME"])
×
3266

3267
                                // build default primary key constraint name
3268
                                const pkName =
3269
                                    this.connection.namingStrategy.primaryKeyName(
×
3270
                                        table,
3271
                                        columnNames,
3272
                                    )
3273

3274
                                // if primary key has user-defined constraint name, write it in table column
3275
                                if (
×
3276
                                    primaryConstraint["CONSTRAINT_NAME"] !==
3277
                                    pkName
3278
                                ) {
3279
                                    tableColumn.primaryKeyConstraintName =
×
3280
                                        primaryConstraint["CONSTRAINT_NAME"]
3281
                                }
3282
                            }
3283

3284
                            tableColumn.default =
×
3285
                                dbColumn["COLUMN_DEFAULT"] !== null &&
×
3286
                                dbColumn["COLUMN_DEFAULT"] !== undefined
3287
                                    ? this.removeParenthesisFromDefault(
3288
                                          dbColumn["COLUMN_DEFAULT"],
3289
                                      )
3290
                                    : undefined
3291
                            tableColumn.isNullable =
×
3292
                                dbColumn["IS_NULLABLE"] === "YES"
3293
                            tableColumn.isUnique =
×
3294
                                uniqueConstraints.length > 0 &&
×
3295
                                !isConstraintComposite
3296
                            tableColumn.isGenerated = isGenerated
×
3297
                            if (isGenerated)
×
3298
                                tableColumn.generationStrategy = "increment"
×
3299
                            if (tableColumn.default === "newsequentialid()") {
×
3300
                                tableColumn.isGenerated = true
×
3301
                                tableColumn.generationStrategy = "uuid"
×
3302
                                tableColumn.default = undefined
×
3303
                            }
3304

3305
                            // todo: unable to get default charset
3306
                            // tableColumn.charset = dbColumn["CHARACTER_SET_NAME"];
3307
                            if (dbColumn["COLLATION_NAME"])
×
3308
                                tableColumn.collation =
×
3309
                                    dbColumn["COLLATION_NAME"] ===
×
3310
                                    defaultCollation["COLLATION_NAME"]
3311
                                        ? undefined
3312
                                        : dbColumn["COLLATION_NAME"]
3313

3314
                            if (
×
3315
                                tableColumn.type === "datetime2" ||
×
3316
                                tableColumn.type === "time" ||
3317
                                tableColumn.type === "datetimeoffset"
3318
                            ) {
3319
                                tableColumn.precision =
×
3320
                                    !this.isDefaultColumnPrecision(
×
3321
                                        table,
3322
                                        tableColumn,
3323
                                        dbColumn["DATETIME_PRECISION"],
3324
                                    )
3325
                                        ? dbColumn["DATETIME_PRECISION"]
3326
                                        : undefined
3327
                            }
3328

3329
                            if (
×
3330
                                dbColumn["is_persisted"] !== null &&
×
3331
                                dbColumn["is_persisted"] !== undefined &&
3332
                                dbColumn["definition"]
3333
                            ) {
3334
                                tableColumn.generatedType =
×
3335
                                    dbColumn["is_persisted"] === true
×
3336
                                        ? "STORED"
3337
                                        : "VIRTUAL"
3338
                                // We cannot relay on information_schema.columns.generation_expression, because it is formatted different.
3339
                                const asExpressionQuery =
3340
                                    this.selectTypeormMetadataSql({
×
3341
                                        database: dbTable["TABLE_CATALOG"],
3342
                                        schema: dbTable["TABLE_SCHEMA"],
3343
                                        table: dbTable["TABLE_NAME"],
3344
                                        type: MetadataTableType.GENERATED_COLUMN,
3345
                                        name: tableColumn.name,
3346
                                    })
3347

3348
                                const results = await this.query(
×
3349
                                    asExpressionQuery.query,
3350
                                    asExpressionQuery.parameters,
3351
                                )
3352
                                if (results[0] && results[0].value) {
×
3353
                                    tableColumn.asExpression = results[0].value
×
3354
                                } else {
3355
                                    tableColumn.asExpression = ""
×
3356
                                }
3357
                            }
3358

3359
                            return tableColumn
×
3360
                        }),
3361
                )
3362

3363
                // find unique constraints of table, group them by constraint name and build TableUnique.
3364
                const tableUniqueConstraints = OrmUtils.uniq(
×
3365
                    dbConstraints.filter(
3366
                        (dbConstraint) =>
3367
                            dbConstraint["TABLE_NAME"] ===
×
3368
                                dbTable["TABLE_NAME"] &&
3369
                            dbConstraint["TABLE_SCHEMA"] ===
3370
                                dbTable["TABLE_SCHEMA"] &&
3371
                            dbConstraint["TABLE_CATALOG"] ===
3372
                                dbTable["TABLE_CATALOG"] &&
3373
                            dbConstraint["CONSTRAINT_TYPE"] === "UNIQUE",
3374
                    ),
3375
                    (dbConstraint) => dbConstraint["CONSTRAINT_NAME"],
×
3376
                )
3377

3378
                table.uniques = tableUniqueConstraints.map((constraint) => {
×
3379
                    const uniques = dbConstraints.filter(
×
3380
                        (dbC) =>
3381
                            dbC["CONSTRAINT_NAME"] ===
×
3382
                            constraint["CONSTRAINT_NAME"],
3383
                    )
3384
                    return new TableUnique({
×
3385
                        name: constraint["CONSTRAINT_NAME"],
3386
                        columnNames: uniques.map((u) => u["COLUMN_NAME"]),
×
3387
                    })
3388
                })
3389

3390
                // find check constraints of table, group them by constraint name and build TableCheck.
3391
                const tableCheckConstraints = OrmUtils.uniq(
×
3392
                    dbConstraints.filter(
3393
                        (dbConstraint) =>
3394
                            dbConstraint["TABLE_NAME"] ===
×
3395
                                dbTable["TABLE_NAME"] &&
3396
                            dbConstraint["TABLE_SCHEMA"] ===
3397
                                dbTable["TABLE_SCHEMA"] &&
3398
                            dbConstraint["TABLE_CATALOG"] ===
3399
                                dbTable["TABLE_CATALOG"] &&
3400
                            dbConstraint["CONSTRAINT_TYPE"] === "CHECK",
3401
                    ),
3402
                    (dbConstraint) => dbConstraint["CONSTRAINT_NAME"],
×
3403
                )
3404

3405
                table.checks = tableCheckConstraints
×
3406
                    .filter(
3407
                        (constraint) =>
3408
                            !this.isEnumCheckConstraint(
×
3409
                                constraint["CONSTRAINT_NAME"],
3410
                            ),
3411
                    )
3412
                    .map((constraint) => {
3413
                        const checks = dbConstraints.filter(
×
3414
                            (dbC) =>
3415
                                dbC["CONSTRAINT_NAME"] ===
×
3416
                                constraint["CONSTRAINT_NAME"],
3417
                        )
3418
                        return new TableCheck({
×
3419
                            name: constraint["CONSTRAINT_NAME"],
3420
                            columnNames: checks.map((c) => c["COLUMN_NAME"]),
×
3421
                            expression: constraint["definition"],
3422
                        })
3423
                    })
3424

3425
                // find foreign key constraints of table, group them by constraint name and build TableForeignKey.
3426
                const tableForeignKeyConstraints = OrmUtils.uniq(
×
3427
                    dbForeignKeys.filter(
3428
                        (dbForeignKey) =>
3429
                            dbForeignKey["TABLE_NAME"] ===
×
3430
                                dbTable["TABLE_NAME"] &&
3431
                            dbForeignKey["TABLE_SCHEMA"] ===
3432
                                dbTable["TABLE_SCHEMA"] &&
3433
                            dbForeignKey["TABLE_CATALOG"] ===
3434
                                dbTable["TABLE_CATALOG"],
3435
                    ),
3436
                    (dbForeignKey) => dbForeignKey["FK_NAME"],
×
3437
                )
3438

3439
                table.foreignKeys = tableForeignKeyConstraints.map(
×
3440
                    (dbForeignKey) => {
3441
                        const foreignKeys = dbForeignKeys.filter(
×
3442
                            (dbFk) =>
3443
                                dbFk["FK_NAME"] === dbForeignKey["FK_NAME"],
×
3444
                        )
3445

3446
                        // if referenced table located in currently used db and schema, we don't need to concat db and schema names to table name.
3447
                        const db =
3448
                            dbForeignKey["TABLE_CATALOG"] === currentDatabase
×
3449
                                ? undefined
3450
                                : dbForeignKey["TABLE_CATALOG"]
3451
                        const schema = getSchemaFromKey(
×
3452
                            dbForeignKey,
3453
                            "REF_SCHEMA",
3454
                        )
3455
                        const referencedTableName = this.driver.buildTableName(
×
3456
                            dbForeignKey["REF_TABLE"],
3457
                            schema,
3458
                            db,
3459
                        )
3460

3461
                        return new TableForeignKey({
×
3462
                            name: dbForeignKey["FK_NAME"],
3463
                            columnNames: foreignKeys.map(
3464
                                (dbFk) => dbFk["COLUMN_NAME"],
×
3465
                            ),
3466
                            referencedDatabase: dbForeignKey["TABLE_CATALOG"],
3467
                            referencedSchema: dbForeignKey["REF_SCHEMA"],
3468
                            referencedTableName: referencedTableName,
3469
                            referencedColumnNames: foreignKeys.map(
3470
                                (dbFk) => dbFk["REF_COLUMN"],
×
3471
                            ),
3472
                            onDelete: dbForeignKey["ON_DELETE"].replace(
3473
                                "_",
3474
                                " ",
3475
                            ), // SqlServer returns NO_ACTION, instead of NO ACTION
3476
                            onUpdate: dbForeignKey["ON_UPDATE"].replace(
3477
                                "_",
3478
                                " ",
3479
                            ), // SqlServer returns NO_ACTION, instead of NO ACTION
3480
                        })
3481
                    },
3482
                )
3483

3484
                // find index constraints of table, group them by constraint name and build TableIndex.
3485
                const tableIndexConstraints = OrmUtils.uniq(
×
3486
                    dbIndices.filter(
3487
                        (dbIndex) =>
3488
                            dbIndex["TABLE_NAME"] === dbTable["TABLE_NAME"] &&
×
3489
                            dbIndex["TABLE_SCHEMA"] ===
3490
                                dbTable["TABLE_SCHEMA"] &&
3491
                            dbIndex["TABLE_CATALOG"] ===
3492
                                dbTable["TABLE_CATALOG"],
3493
                    ),
3494
                    (dbIndex) => dbIndex["INDEX_NAME"],
×
3495
                )
3496

3497
                table.indices = tableIndexConstraints.map((constraint) => {
×
3498
                    const indices = dbIndices.filter((index) => {
×
3499
                        return (
×
3500
                            index["TABLE_CATALOG"] ===
×
3501
                                constraint["TABLE_CATALOG"] &&
3502
                            index["TABLE_SCHEMA"] ===
3503
                                constraint["TABLE_SCHEMA"] &&
3504
                            index["TABLE_NAME"] === constraint["TABLE_NAME"] &&
3505
                            index["INDEX_NAME"] === constraint["INDEX_NAME"]
3506
                        )
3507
                    })
3508
                    return new TableIndex(<TableIndexOptions>{
×
3509
                        table: table,
3510
                        name: constraint["INDEX_NAME"],
3511
                        columnNames: indices.map((i) => i["COLUMN_NAME"]),
×
3512
                        isUnique: constraint["IS_UNIQUE"],
3513
                        where: constraint["CONDITION"],
3514
                    })
3515
                })
3516

3517
                return table
×
3518
            }),
3519
        )
3520
    }
3521

3522
    /**
3523
     * Builds and returns SQL for create table.
3524
     */
3525
    protected createTableSql(table: Table, createForeignKeys?: boolean): Query {
3526
        const columnDefinitions = table.columns
×
3527
            .map((column) =>
3528
                this.buildCreateColumnSql(table, column, false, true),
×
3529
            )
3530
            .join(", ")
3531
        let sql = `CREATE TABLE ${this.escapePath(table)} (${columnDefinitions}`
×
3532

3533
        table.columns
×
3534
            .filter((column) => column.isUnique)
×
3535
            .forEach((column) => {
3536
                const isUniqueExist = table.uniques.some(
×
3537
                    (unique) =>
3538
                        unique.columnNames.length === 1 &&
×
3539
                        unique.columnNames[0] === column.name,
3540
                )
3541
                if (!isUniqueExist)
×
3542
                    table.uniques.push(
×
3543
                        new TableUnique({
3544
                            name: this.connection.namingStrategy.uniqueConstraintName(
3545
                                table,
3546
                                [column.name],
3547
                            ),
3548
                            columnNames: [column.name],
3549
                        }),
3550
                    )
3551
            })
3552

3553
        if (table.uniques.length > 0) {
×
3554
            const uniquesSql = table.uniques
×
3555
                .map((unique) => {
3556
                    const uniqueName = unique.name
×
3557
                        ? unique.name
3558
                        : this.connection.namingStrategy.uniqueConstraintName(
3559
                              table,
3560
                              unique.columnNames,
3561
                          )
3562
                    const columnNames = unique.columnNames
×
3563
                        .map((columnName) => `"${columnName}"`)
×
3564
                        .join(", ")
3565
                    return `CONSTRAINT "${uniqueName}" UNIQUE (${columnNames})`
×
3566
                })
3567
                .join(", ")
3568

3569
            sql += `, ${uniquesSql}`
×
3570
        }
3571

3572
        if (table.checks.length > 0) {
×
3573
            const checksSql = table.checks
×
3574
                .map((check) => {
3575
                    const checkName = check.name
×
3576
                        ? check.name
3577
                        : this.connection.namingStrategy.checkConstraintName(
3578
                              table,
3579
                              check.expression!,
3580
                          )
3581
                    return `CONSTRAINT "${checkName}" CHECK (${check.expression})`
×
3582
                })
3583
                .join(", ")
3584

3585
            sql += `, ${checksSql}`
×
3586
        }
3587

3588
        if (table.foreignKeys.length > 0 && createForeignKeys) {
×
3589
            const foreignKeysSql = table.foreignKeys
×
3590
                .map((fk) => {
3591
                    const columnNames = fk.columnNames
×
3592
                        .map((columnName) => `"${columnName}"`)
×
3593
                        .join(", ")
3594
                    if (!fk.name)
×
3595
                        fk.name = this.connection.namingStrategy.foreignKeyName(
×
3596
                            table,
3597
                            fk.columnNames,
3598
                            this.getTablePath(fk),
3599
                            fk.referencedColumnNames,
3600
                        )
3601
                    const referencedColumnNames = fk.referencedColumnNames
×
3602
                        .map((columnName) => `"${columnName}"`)
×
3603
                        .join(", ")
3604

3605
                    let constraint = `CONSTRAINT "${
×
3606
                        fk.name
3607
                    }" FOREIGN KEY (${columnNames}) REFERENCES ${this.escapePath(
3608
                        this.getTablePath(fk),
3609
                    )} (${referencedColumnNames})`
3610
                    if (fk.onDelete) constraint += ` ON DELETE ${fk.onDelete}`
×
3611
                    if (fk.onUpdate) constraint += ` ON UPDATE ${fk.onUpdate}`
×
3612

3613
                    return constraint
×
3614
                })
3615
                .join(", ")
3616

3617
            sql += `, ${foreignKeysSql}`
×
3618
        }
3619

3620
        const primaryColumns = table.columns.filter(
×
3621
            (column) => column.isPrimary,
×
3622
        )
3623
        if (primaryColumns.length > 0) {
×
3624
            const primaryKeyName = primaryColumns[0].primaryKeyConstraintName
×
3625
                ? primaryColumns[0].primaryKeyConstraintName
3626
                : this.connection.namingStrategy.primaryKeyName(
3627
                      table,
3628
                      primaryColumns.map((column) => column.name),
×
3629
                  )
3630

3631
            const columnNames = primaryColumns
×
3632
                .map((column) => `"${column.name}"`)
×
3633
                .join(", ")
3634
            sql += `, CONSTRAINT "${primaryKeyName}" PRIMARY KEY (${columnNames})`
×
3635
        }
3636

3637
        sql += `)`
×
3638

3639
        return new Query(sql)
×
3640
    }
3641

3642
    /**
3643
     * Builds drop table sql.
3644
     */
3645
    protected dropTableSql(
3646
        tableOrName: Table | string,
3647
        ifExist?: boolean,
3648
    ): Query {
3649
        const query = ifExist
×
3650
            ? `DROP TABLE IF EXISTS ${this.escapePath(tableOrName)}`
3651
            : `DROP TABLE ${this.escapePath(tableOrName)}`
3652
        return new Query(query)
×
3653
    }
3654

3655
    protected createViewSql(view: View): Query {
3656
        const parsedName = this.driver.parseTableName(view)
×
3657

3658
        // Can't use `escapePath` here because `CREATE VIEW` does not accept database names.
3659
        const viewIdentifier = parsedName.schema
×
3660
            ? `"${parsedName.schema}"."${parsedName.tableName}"`
3661
            : `"${parsedName.tableName}"`
3662

3663
        if (typeof view.expression === "string") {
×
3664
            return new Query(
×
3665
                `CREATE VIEW ${viewIdentifier} AS ${view.expression}`,
3666
            )
3667
        } else {
3668
            return new Query(
×
3669
                `CREATE VIEW ${viewIdentifier} AS ${view
3670
                    .expression(this.connection)
3671
                    .getQuery()}`,
3672
            )
3673
        }
3674
    }
3675

3676
    protected async insertViewDefinitionSql(view: View): Promise<Query> {
3677
        const parsedTableName = this.driver.parseTableName(view)
×
3678

3679
        if (!parsedTableName.schema) {
×
3680
            parsedTableName.schema = await this.getCurrentSchema()
×
3681
        }
3682

3683
        const expression =
3684
            typeof view.expression === "string"
×
3685
                ? view.expression.trim()
3686
                : view.expression(this.connection).getQuery()
3687
        return this.insertTypeormMetadataSql({
×
3688
            type: MetadataTableType.VIEW,
3689
            database: parsedTableName.database,
3690
            schema: parsedTableName.schema,
3691
            name: parsedTableName.tableName,
3692
            value: expression,
3693
        })
3694
    }
3695

3696
    /**
3697
     * Builds drop view sql.
3698
     */
3699
    protected dropViewSql(viewOrPath: View | string): Query {
3700
        return new Query(`DROP VIEW ${this.escapePath(viewOrPath)}`)
×
3701
    }
3702

3703
    /**
3704
     * Builds remove view sql.
3705
     */
3706
    protected async deleteViewDefinitionSql(
3707
        viewOrPath: View | string,
3708
    ): Promise<Query> {
3709
        const parsedTableName = this.driver.parseTableName(viewOrPath)
×
3710

3711
        if (!parsedTableName.schema) {
×
3712
            parsedTableName.schema = await this.getCurrentSchema()
×
3713
        }
3714

3715
        return this.deleteTypeormMetadataSql({
×
3716
            type: MetadataTableType.VIEW,
3717
            database: parsedTableName.database,
3718
            schema: parsedTableName.schema,
3719
            name: parsedTableName.tableName,
3720
        })
3721
    }
3722

3723
    /**
3724
     * Builds create index sql.
3725
     */
3726
    protected createIndexSql(table: Table, index: TableIndex): Query {
3727
        const columns = index.columnNames
×
3728
            .map((columnName) => `"${columnName}"`)
×
3729
            .join(", ")
3730
        return new Query(
×
3731
            `CREATE ${index.isUnique ? "UNIQUE " : ""}INDEX "${
×
3732
                index.name
3733
            }" ON ${this.escapePath(table)} (${columns}) ${
3734
                index.where ? "WHERE " + index.where : ""
×
3735
            }`,
3736
        )
3737
    }
3738

3739
    /**
3740
     * Builds drop index sql.
3741
     */
3742
    protected dropIndexSql(
3743
        table: Table,
3744
        indexOrName: TableIndex | string,
3745
    ): Query {
3746
        const indexName = InstanceChecker.isTableIndex(indexOrName)
×
3747
            ? indexOrName.name
3748
            : indexOrName
3749
        return new Query(
×
3750
            `DROP INDEX "${indexName}" ON ${this.escapePath(table)}`,
3751
        )
3752
    }
3753

3754
    /**
3755
     * Builds create primary key sql.
3756
     */
3757
    protected createPrimaryKeySql(
3758
        table: Table,
3759
        columnNames: string[],
3760
        constraintName?: string,
3761
    ): Query {
3762
        const primaryKeyName = constraintName
×
3763
            ? constraintName
3764
            : this.connection.namingStrategy.primaryKeyName(table, columnNames)
3765

3766
        const columnNamesString = columnNames
×
3767
            .map((columnName) => `"${columnName}"`)
×
3768
            .join(", ")
3769
        return new Query(
×
3770
            `ALTER TABLE ${this.escapePath(
3771
                table,
3772
            )} ADD CONSTRAINT "${primaryKeyName}" PRIMARY KEY (${columnNamesString})`,
3773
        )
3774
    }
3775

3776
    /**
3777
     * Builds drop primary key sql.
3778
     */
3779
    protected dropPrimaryKeySql(table: Table): Query {
3780
        const columnNames = table.primaryColumns.map((column) => column.name)
×
3781
        const constraintName = table.primaryColumns[0].primaryKeyConstraintName
×
3782
        const primaryKeyName = constraintName
×
3783
            ? constraintName
3784
            : this.connection.namingStrategy.primaryKeyName(table, columnNames)
3785

3786
        return new Query(
×
3787
            `ALTER TABLE ${this.escapePath(
3788
                table,
3789
            )} DROP CONSTRAINT "${primaryKeyName}"`,
3790
        )
3791
    }
3792

3793
    /**
3794
     * Builds create unique constraint sql.
3795
     */
3796
    protected createUniqueConstraintSql(
3797
        table: Table,
3798
        uniqueConstraint: TableUnique,
3799
    ): Query {
3800
        const columnNames = uniqueConstraint.columnNames
×
3801
            .map((column) => `"` + column + `"`)
×
3802
            .join(", ")
3803
        return new Query(
×
3804
            `ALTER TABLE ${this.escapePath(table)} ADD CONSTRAINT "${
3805
                uniqueConstraint.name
3806
            }" UNIQUE (${columnNames})`,
3807
        )
3808
    }
3809

3810
    /**
3811
     * Builds drop unique constraint sql.
3812
     */
3813
    protected dropUniqueConstraintSql(
3814
        table: Table,
3815
        uniqueOrName: TableUnique | string,
3816
    ): Query {
3817
        const uniqueName = InstanceChecker.isTableUnique(uniqueOrName)
×
3818
            ? uniqueOrName.name
3819
            : uniqueOrName
3820
        return new Query(
×
3821
            `ALTER TABLE ${this.escapePath(
3822
                table,
3823
            )} DROP CONSTRAINT "${uniqueName}"`,
3824
        )
3825
    }
3826

3827
    /**
3828
     * Builds create check constraint sql.
3829
     */
3830
    protected createCheckConstraintSql(
3831
        table: Table,
3832
        checkConstraint: TableCheck,
3833
    ): Query {
3834
        return new Query(
×
3835
            `ALTER TABLE ${this.escapePath(table)} ADD CONSTRAINT "${
3836
                checkConstraint.name
3837
            }" CHECK (${checkConstraint.expression})`,
3838
        )
3839
    }
3840

3841
    /**
3842
     * Builds drop check constraint sql.
3843
     */
3844
    protected dropCheckConstraintSql(
3845
        table: Table,
3846
        checkOrName: TableCheck | string,
3847
    ): Query {
3848
        const checkName = InstanceChecker.isTableCheck(checkOrName)
×
3849
            ? checkOrName.name
3850
            : checkOrName
3851
        return new Query(
×
3852
            `ALTER TABLE ${this.escapePath(
3853
                table,
3854
            )} DROP CONSTRAINT "${checkName}"`,
3855
        )
3856
    }
3857

3858
    /**
3859
     * Builds create foreign key sql.
3860
     */
3861
    protected createForeignKeySql(
3862
        table: Table,
3863
        foreignKey: TableForeignKey,
3864
    ): Query {
3865
        const columnNames = foreignKey.columnNames
×
3866
            .map((column) => `"` + column + `"`)
×
3867
            .join(", ")
3868
        const referencedColumnNames = foreignKey.referencedColumnNames
×
3869
            .map((column) => `"` + column + `"`)
×
3870
            .join(",")
3871
        let sql =
3872
            `ALTER TABLE ${this.escapePath(table)} ADD CONSTRAINT "${
×
3873
                foreignKey.name
3874
            }" FOREIGN KEY (${columnNames}) ` +
3875
            `REFERENCES ${this.escapePath(
3876
                this.getTablePath(foreignKey),
3877
            )}(${referencedColumnNames})`
3878
        if (foreignKey.onDelete) sql += ` ON DELETE ${foreignKey.onDelete}`
×
3879
        if (foreignKey.onUpdate) sql += ` ON UPDATE ${foreignKey.onUpdate}`
×
3880

3881
        return new Query(sql)
×
3882
    }
3883

3884
    /**
3885
     * Builds drop foreign key sql.
3886
     */
3887
    protected dropForeignKeySql(
3888
        table: Table,
3889
        foreignKeyOrName: TableForeignKey | string,
3890
    ): Query {
3891
        const foreignKeyName = InstanceChecker.isTableForeignKey(
×
3892
            foreignKeyOrName,
3893
        )
3894
            ? foreignKeyOrName.name
3895
            : foreignKeyOrName
3896
        return new Query(
×
3897
            `ALTER TABLE ${this.escapePath(
3898
                table,
3899
            )} DROP CONSTRAINT "${foreignKeyName}"`,
3900
        )
3901
    }
3902

3903
    /**
3904
     * Escapes given table or View path.
3905
     */
3906
    protected escapePath(target: Table | View | string): string {
3907
        const { database, schema, tableName } =
3908
            this.driver.parseTableName(target)
×
3909

3910
        if (database && database !== this.driver.database) {
×
3911
            if (schema && schema !== this.driver.searchSchema) {
×
3912
                return `"${database}"."${schema}"."${tableName}"`
×
3913
            }
3914

3915
            return `"${database}".."${tableName}"`
×
3916
        }
3917

3918
        if (schema && schema !== this.driver.searchSchema) {
×
3919
            return `"${schema}"."${tableName}"`
×
3920
        }
3921

3922
        return `"${tableName}"`
×
3923
    }
3924

3925
    /**
3926
     * Concat database name and schema name to the foreign key name.
3927
     * Needs because FK name is relevant to the schema and database.
3928
     */
3929
    protected buildForeignKeyName(
3930
        fkName: string,
3931
        schemaName: string | undefined,
3932
        dbName: string | undefined,
3933
    ): string {
3934
        let joinedFkName = fkName
×
3935
        if (schemaName && schemaName !== this.driver.searchSchema)
×
3936
            joinedFkName = schemaName + "." + joinedFkName
×
3937
        if (dbName && dbName !== this.driver.database)
×
3938
            joinedFkName = dbName + "." + joinedFkName
×
3939

3940
        return joinedFkName
×
3941
    }
3942

3943
    /**
3944
     * Removes parenthesis around default value.
3945
     * Sql server returns default value with parenthesis around, e.g.
3946
     *  ('My text') - for string
3947
     *  ((1)) - for number
3948
     *  (newsequentialId()) - for function
3949
     */
3950
    protected removeParenthesisFromDefault(defaultValue: string): any {
3951
        if (defaultValue.substr(0, 1) !== "(") return defaultValue
×
3952
        const normalizedDefault = defaultValue.substr(
×
3953
            1,
3954
            defaultValue.lastIndexOf(")") - 1,
3955
        )
3956
        return this.removeParenthesisFromDefault(normalizedDefault)
×
3957
    }
3958

3959
    /**
3960
     * Builds a query for create column.
3961
     */
3962
    protected buildCreateColumnSql(
3963
        table: Table,
3964
        column: TableColumn,
3965
        skipIdentity: boolean,
3966
        createDefault: boolean,
3967
        skipEnum?: boolean,
3968
    ) {
3969
        let c = `"${column.name}" ${this.connection.driver.createFullType(
×
3970
            column,
3971
        )}`
3972

3973
        if (!skipEnum && column.enum) {
×
3974
            const expression = this.getEnumExpression(column)
×
3975
            const checkName =
3976
                this.connection.namingStrategy.checkConstraintName(
×
3977
                    table,
3978
                    expression,
3979
                    true,
3980
                )
3981
            c += ` CONSTRAINT ${checkName} CHECK(${expression})`
×
3982
        }
3983

3984
        if (column.collation) c += " COLLATE " + column.collation
×
3985

3986
        if (column.asExpression) {
×
3987
            c += ` AS (${column.asExpression})`
×
3988
            if (column.generatedType === "STORED") {
×
3989
                c += ` PERSISTED`
×
3990

3991
                // NOT NULL can be specified for computed columns only if PERSISTED is also specified
3992
                if (column.isNullable !== true) c += " NOT NULL"
×
3993
            }
3994
        } else {
3995
            if (column.isNullable !== true) c += " NOT NULL"
×
3996
        }
3997

3998
        if (
×
3999
            column.isGenerated === true &&
×
4000
            column.generationStrategy === "increment" &&
4001
            !skipIdentity
4002
        )
4003
            // don't use skipPrimary here since updates can update already exist primary without auto inc.
4004
            c += " IDENTITY(1,1)"
×
4005

4006
        if (
×
4007
            column.default !== undefined &&
×
4008
            column.default !== null &&
4009
            createDefault
4010
        ) {
4011
            // we create named constraint to be able to delete this constraint when column been dropped
4012
            const defaultName =
4013
                this.connection.namingStrategy.defaultConstraintName(
×
4014
                    table,
4015
                    column.name,
4016
                )
4017
            c += ` CONSTRAINT "${defaultName}" DEFAULT ${column.default}`
×
4018
        }
4019

4020
        if (
×
4021
            column.isGenerated &&
×
4022
            column.generationStrategy === "uuid" &&
4023
            !column.default
4024
        ) {
4025
            // we create named constraint to be able to delete this constraint when column been dropped
4026
            const defaultName =
4027
                this.connection.namingStrategy.defaultConstraintName(
×
4028
                    table,
4029
                    column.name,
4030
                )
4031
            c += ` CONSTRAINT "${defaultName}" DEFAULT NEWSEQUENTIALID()`
×
4032
        }
4033
        return c
×
4034
    }
4035

4036
    private getEnumExpression(column: TableColumn) {
4037
        if (!column.enum) {
×
4038
            throw new Error(`Enum is not defined in column ${column.name}`)
×
4039
        }
4040
        return (
×
4041
            column.name +
4042
            " IN (" +
4043
            column.enum.map((val) => "'" + val + "'").join(",") +
×
4044
            ")"
4045
        )
4046
    }
4047

4048
    protected isEnumCheckConstraint(name: string): boolean {
4049
        return name.indexOf("CHK_") !== -1 && name.indexOf("_ENUM") !== -1
×
4050
    }
4051

4052
    /**
4053
     * Converts MssqlParameter into real mssql parameter type.
4054
     */
4055
    protected mssqlParameterToNativeParameter(parameter: MssqlParameter): any {
4056
        switch (this.driver.normalizeType({ type: parameter.type as any })) {
×
4057
            case "bit":
4058
                return this.driver.mssql.Bit
×
4059
            case "bigint":
4060
                return this.driver.mssql.BigInt
×
4061
            case "decimal":
4062
                return this.driver.mssql.Decimal(...parameter.params)
×
4063
            case "float":
4064
                return this.driver.mssql.Float
×
4065
            case "int":
4066
                return this.driver.mssql.Int
×
4067
            case "money":
4068
                return this.driver.mssql.Money
×
4069
            case "numeric":
4070
                return this.driver.mssql.Numeric(...parameter.params)
×
4071
            case "smallint":
4072
                return this.driver.mssql.SmallInt
×
4073
            case "smallmoney":
4074
                return this.driver.mssql.SmallMoney
×
4075
            case "real":
4076
                return this.driver.mssql.Real
×
4077
            case "tinyint":
4078
                return this.driver.mssql.TinyInt
×
4079
            case "char":
4080
                if (
×
4081
                    this.driver.options.options
4082
                        ?.disableAsciiToUnicodeParamConversion
4083
                ) {
4084
                    return this.driver.mssql.Char(...parameter.params)
×
4085
                }
4086
                return this.driver.mssql.NChar(...parameter.params)
×
4087
            case "nchar":
4088
                return this.driver.mssql.NChar(...parameter.params)
×
4089
            case "text":
4090
                if (
×
4091
                    this.driver.options.options
4092
                        ?.disableAsciiToUnicodeParamConversion
4093
                ) {
4094
                    return this.driver.mssql.Text
×
4095
                }
4096
                return this.driver.mssql.Ntext
×
4097
            case "ntext":
4098
                return this.driver.mssql.Ntext
×
4099
            case "varchar":
4100
                if (
×
4101
                    this.driver.options.options
4102
                        ?.disableAsciiToUnicodeParamConversion
4103
                ) {
4104
                    return this.driver.mssql.VarChar(...parameter.params)
×
4105
                }
4106
                return this.driver.mssql.NVarChar(...parameter.params)
×
4107
            case "nvarchar":
4108
                return this.driver.mssql.NVarChar(...parameter.params)
×
4109
            case "xml":
4110
                return this.driver.mssql.Xml
×
4111
            case "time":
4112
                return this.driver.mssql.Time(...parameter.params)
×
4113
            case "date":
4114
                return this.driver.mssql.Date
×
4115
            case "datetime":
4116
                return this.driver.mssql.DateTime
×
4117
            case "datetime2":
4118
                return this.driver.mssql.DateTime2(...parameter.params)
×
4119
            case "datetimeoffset":
4120
                return this.driver.mssql.DateTimeOffset(...parameter.params)
×
4121
            case "smalldatetime":
4122
                return this.driver.mssql.SmallDateTime
×
4123
            case "uniqueidentifier":
4124
                return this.driver.mssql.UniqueIdentifier
×
4125
            case "variant":
4126
                return this.driver.mssql.Variant
×
4127
            case "binary":
4128
                return this.driver.mssql.Binary
×
4129
            case "varbinary":
4130
                return this.driver.mssql.VarBinary(...parameter.params)
×
4131
            case "image":
4132
                return this.driver.mssql.Image
×
4133
            case "udt":
4134
                return this.driver.mssql.UDT
×
4135
            case "rowversion":
4136
                return this.driver.mssql.RowVersion
×
4137
        }
4138
    }
4139

4140
    /**
4141
     * Converts string literal of isolation level to enum.
4142
     * The underlying mssql driver requires an enum for the isolation level.
4143
     */
4144
    convertIsolationLevel(isolation: IsolationLevel) {
4145
        const ISOLATION_LEVEL = this.driver.mssql.ISOLATION_LEVEL
×
4146
        switch (isolation) {
×
4147
            case "READ UNCOMMITTED":
4148
                return ISOLATION_LEVEL.READ_UNCOMMITTED
×
4149
            case "REPEATABLE READ":
4150
                return ISOLATION_LEVEL.REPEATABLE_READ
×
4151
            case "SERIALIZABLE":
4152
                return ISOLATION_LEVEL.SERIALIZABLE
×
4153

4154
            case "READ COMMITTED":
4155
            default:
4156
                return ISOLATION_LEVEL.READ_COMMITTED
×
4157
        }
4158
    }
4159

4160
    /**
4161
     * Change table comment.
4162
     */
4163
    changeTableComment(
4164
        tableOrName: Table | string,
4165
        comment?: string,
4166
    ): Promise<void> {
4167
        throw new TypeORMError(
×
4168
            `sqlserver driver does not support change table comment.`,
4169
        )
4170
    }
4171
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc