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

typeorm / typeorm / 21334389062

25 Jan 2026 02:44PM UTC coverage: 81.095% (-0.02%) from 81.117%
21334389062

push

github

web-flow
fix: handle relation ids in nested embedded entities (#11942)

26894 of 32681 branches covered (82.29%)

Branch coverage included in aggregate %.

93166 of 115367 relevant lines covered (80.76%)

70023.53 hits per line

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

18,954 ✔
146
        if (!this.isTransactionActive) throw new TransactionNotStartedError()
18,954 !
147

18,954 ✔
148
        await this.broadcaster.broadcast("BeforeTransactionCommit")
18,954 ✔
149

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

18,950 ✔
157
                    await this.broadcaster.broadcast("AfterTransactionCommit")
18,950 ✔
158

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

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

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

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

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

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

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

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

109,722 ✔
214
        const release = await this.lock.acquire()
109,722 ✔
215

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

109,722 ✔
219
        const broadcasterResult = new BroadcasterResult()
109,722 ✔
220

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

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

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

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

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

109,722 ✔
284
                    ok(raw)
109,722 ✔
285
                })
109,722 ✔
286
            })
109,722 ✔
287

109,706 ✔
288
            const result = new QueryResult()
109,706 ✔
289

109,706 ✔
290
            if (raw?.hasOwnProperty("recordset")) {
109,722 ✔
291
                result.records = raw.recordset
109,706 ✔
292
            }
109,706 ✔
293

109,706 ✔
294
            if (raw?.hasOwnProperty("rowsAffected")) {
109,722 ✔
295
                result.affected = raw.rowsAffected[0]
109,706 ✔
296
            }
109,706 ✔
297

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

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

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

109,722 ✔
334
            release()
109,722 ✔
335
        }
109,722 ✔
336
    }
109,722 ✔
337

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

50,900 ✔
4071
        return `"${tableName}"`
50,900 ✔
4072
    }
50,900 ✔
4073

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

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

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

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

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

33,670 ✔
4142
        if (column.collation) c += " COLLATE " + column.collation
33,670 ✔
4143

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

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

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

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

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

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

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

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

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

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

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

© 2026 Coveralls, Inc