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

typeorm / typeorm / 19887336856

03 Dec 2025 08:29AM UTC coverage: 80.77% (-0.03%) from 80.796%
19887336856

push

github

web-flow
chore: release v0.3.28 (#11816)

26495 of 32180 branches covered (82.33%)

Branch coverage included in aggregate %.

91354 of 113726 relevant lines covered (80.33%)

67968.61 hits per line

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

105,852✔
210
        const release = await this.lock.acquire()
105,852✔
211

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

105,852✔
215
        const broadcasterResult = new BroadcasterResult()
105,852✔
216

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

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

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

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

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

105,852✔
280
                    ok(raw)
105,852✔
281
                })
105,852✔
282
            })
105,852✔
283

105,836✔
284
            const result = new QueryResult()
105,836✔
285

105,836✔
286
            if (raw?.hasOwnProperty("recordset")) {
105,852✔
287
                result.records = raw.recordset
105,836✔
288
            }
105,836✔
289

105,836✔
290
            if (raw?.hasOwnProperty("rowsAffected")) {
105,852✔
291
                result.affected = raw.rowsAffected[0]
105,836✔
292
            }
105,836✔
293

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

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

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

105,852✔
330
            release()
105,852✔
331
        }
105,852✔
332
    }
105,852✔
333

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

2,858✔
2732
            if (!isAnotherTransactionActive) await this.commitTransaction()
2,858✔
2733
        } catch (error) {
2,858!
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
    }
2,858✔
2742

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

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

30✔
2753
        if (!viewPaths) {
2,970!
2754
            viewPaths = []
×
2755
        }
×
2756

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

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

30✔
2764
        if (
30✔
2765
            this.driver.database &&
30✔
2766
            !dbNames.find((dbName) => dbName === this.driver.database)
30✔
2767
        )
2,970✔
2768
            dbNames.push(this.driver.database)
2,970✔
2769

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

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

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

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

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

3,530✔
2824
        const currentSchema = await this.getCurrentSchema()
3,530✔
2825
        const currentDatabase = await this.getCurrentDatabase()
3,530✔
2826

3,530✔
2827
        const dbTables: {
3,530✔
2828
            TABLE_CATALOG: string
3,530✔
2829
            TABLE_SCHEMA: string
3,530✔
2830
            TABLE_NAME: string
3,530✔
2831
        }[] = []
3,530✔
2832

3,530✔
2833
        if (!tableNames) {
3,544!
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 {
3,544✔
2860
            const tableNamesByCatalog = tableNames
3,530✔
2861
                .map((tableName) => this.driver.parseTableName(tableName))
3,530✔
2862
                .reduce((c, { database, ...other }) => {
3,530✔
2863
                    database = database || currentDatabase
10,712!
2864
                    c[database] = c[database] || []
10,712✔
2865
                    c[database].push({
10,712✔
2866
                        schema: other.schema || currentSchema,
10,712!
2867
                        tableName: other.tableName,
10,712✔
2868
                    })
10,712✔
2869
                    return c
10,712✔
2870
                }, {} as { [key: string]: { schema: string; tableName: string }[] })
3,530✔
2871

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

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

3,530✔
2892
            dbTables.push(...(await this.query(tablesSql)))
3,530✔
2893
        }
3,530✔
2894

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

3,536✔
3369
                            return tableColumn
3,536✔
3370
                        }),
986✔
3371
                )
986✔
3372

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

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

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

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

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

986✔
3449
                table.foreignKeys = tableForeignKeyConstraints.map(
986✔
3450
                    (dbForeignKey) => {
986✔
3451
                        const foreignKeys = dbForeignKeys.filter(
336✔
3452
                            (dbFk) =>
336✔
3453
                                dbFk["FK_NAME"] === dbForeignKey["FK_NAME"],
336✔
3454
                        )
336✔
3455

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

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

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

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

986✔
3527
                return table
986✔
3528
            }),
666✔
3529
        )
666✔
3530
    }
666✔
3531

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

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

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

596✔
3579
            sql += `, ${uniquesSql}`
596✔
3580
        }
596✔
3581

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

146✔
3595
            sql += `, ${checksSql}`
146✔
3596
        }
146✔
3597

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

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

10✔
3623
                    return constraint
10✔
3624
                })
8✔
3625
                .join(", ")
8✔
3626

8✔
3627
            sql += `, ${foreignKeysSql}`
8✔
3628
        }
8✔
3629

9,810✔
3630
        const primaryColumns = table.columns.filter(
9,810✔
3631
            (column) => column.isPrimary,
9,810✔
3632
        )
9,810✔
3633
        if (primaryColumns.length > 0) {
9,810✔
3634
            const primaryKeyName = primaryColumns[0].primaryKeyConstraintName
9,784✔
3635
                ? primaryColumns[0].primaryKeyConstraintName
9,784✔
3636
                : this.connection.namingStrategy.primaryKeyName(
9,784✔
3637
                      table,
9,752✔
3638
                      primaryColumns.map((column) => column.name),
9,752✔
3639
                  )
9,784✔
3640

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

9,810✔
3647
        sql += `)`
9,810✔
3648

9,810✔
3649
        return new Query(sql)
9,810✔
3650
    }
9,810✔
3651

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

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

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

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

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

16✔
3689
        if (!parsedTableName.schema) {
16!
3690
            parsedTableName.schema = await this.getCurrentSchema()
×
3691
        }
×
3692

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

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

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

16✔
3721
        if (!parsedTableName.schema) {
16!
3722
            parsedTableName.schema = await this.getCurrentSchema()
×
3723
        }
×
3724

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

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

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

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

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

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

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

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

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

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

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

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

6,508✔
3891
        return new Query(sql)
6,508✔
3892
    }
6,508✔
3893

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

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

48,560✔
3920
        if (database && database !== this.driver.database) {
48,560✔
3921
            if (schema && schema !== this.driver.searchSchema) {
96✔
3922
                return `"${database}"."${schema}"."${tableName}"`
84✔
3923
            }
84✔
3924

12✔
3925
            return `"${database}".."${tableName}"`
12✔
3926
        }
12✔
3927

48,464✔
3928
        if (schema && schema !== this.driver.searchSchema) {
48,560✔
3929
            return `"${schema}"."${tableName}"`
140✔
3930
        }
140✔
3931

48,324✔
3932
        return `"${tableName}"`
48,324✔
3933
    }
48,324✔
3934

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

8✔
3950
        return joinedFkName
8✔
3951
    }
8✔
3952

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

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

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

31,892✔
3994
        if (column.collation) c += " COLLATE " + column.collation
31,892✔
3995

31,892✔
3996
        if (column.asExpression) {
31,892✔
3997
            c += ` AS (${column.asExpression})`
78✔
3998
            if (column.generatedType === "STORED") {
78✔
3999
                c += ` PERSISTED`
42✔
4000

42✔
4001
                // NOT NULL can be specified for computed columns only if PERSISTED is also specified
42✔
4002
                if (column.isNullable !== true) c += " NOT NULL"
42✔
4003
            }
42✔
4004
        } else {
31,892✔
4005
            if (column.isNullable !== true) c += " NOT NULL"
31,814✔
4006
        }
31,814✔
4007

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

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

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

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

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

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

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

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

26✔
4172
    /**
26✔
4173
     * Change table comment.
26✔
4174
     */
26✔
4175
    changeTableComment(
26✔
4176
        tableOrName: Table | string,
×
4177
        comment?: string,
×
4178
    ): Promise<void> {
×
4179
        throw new TypeORMError(
×
4180
            `sqlserver driver does not support change table comment.`,
×
4181
        )
×
4182
    }
×
4183
}
26✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc