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

typeorm / typeorm / 19549987525

20 Nov 2025 08:11PM UTC coverage: 80.769% (+4.3%) from 76.433%
19549987525

push

github

web-flow
ci: run tests on commits to master and next (#11783)

Co-authored-by: Oleg "OSA413" Sokolov <OSA413@users.noreply.github.com>

26500 of 32174 branches covered (82.36%)

Branch coverage included in aggregate %.

91252 of 113615 relevant lines covered (80.32%)

88980.79 hits per line

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

94.34
/src/driver/sqlite-abstract/AbstractSqliteDriver.ts
1
import { Driver } from "../Driver"
26✔
2
import { ObjectLiteral } from "../../common/ObjectLiteral"
26✔
3
import { ColumnMetadata } from "../../metadata/ColumnMetadata"
26✔
4
import { DateUtils } from "../../util/DateUtils"
26✔
5
import { DataSource } from "../../data-source/DataSource"
26✔
6
import { RdbmsSchemaBuilder } from "../../schema-builder/RdbmsSchemaBuilder"
26✔
7
import { CteCapabilities } from "../types/CteCapabilities"
26✔
8
import { MappedColumnTypes } from "../types/MappedColumnTypes"
26✔
9
import { ColumnType } from "../types/ColumnTypes"
26✔
10
import { QueryRunner } from "../../query-runner/QueryRunner"
26✔
11
import { DataTypeDefaults } from "../types/DataTypeDefaults"
26✔
12
import { TableColumn } from "../../schema-builder/table/TableColumn"
26✔
13
import { BaseDataSourceOptions } from "../../data-source/BaseDataSourceOptions"
26✔
14
import { EntityMetadata } from "../../metadata/EntityMetadata"
26✔
15
import { OrmUtils } from "../../util/OrmUtils"
26✔
16
import { ApplyValueTransformers } from "../../util/ApplyValueTransformers"
26✔
17
import { ReplicationMode } from "../types/ReplicationMode"
26✔
18
import { DriverUtils } from "../DriverUtils"
26✔
19
import { TypeORMError } from "../../error"
26✔
20
import { Table } from "../../schema-builder/table/Table"
26✔
21
import { View } from "../../schema-builder/view/View"
26✔
22
import { TableForeignKey } from "../../schema-builder/table/TableForeignKey"
26✔
23
import { InstanceChecker } from "../../util/InstanceChecker"
26✔
24
import { UpsertType } from "../types/UpsertType"
26✔
25

26✔
26
type DatabasesMap = Record<
26✔
27
    string,
26✔
28
    {
26✔
29
        attachFilepathAbsolute: string
26✔
30
        attachFilepathRelative: string
26✔
31
        attachHandle: string
26✔
32
    }
26✔
33
>
26✔
34

26✔
35
/**
26✔
36
 * Organizes communication with sqlite DBMS.
26✔
37
 */
26✔
38
export abstract class AbstractSqliteDriver implements Driver {
26✔
39
    // -------------------------------------------------------------------------
26✔
40
    // Public Properties
26✔
41
    // -------------------------------------------------------------------------
26✔
42

26✔
43
    /**
26✔
44
     * Connection used by driver.
26✔
45
     */
26✔
46
    connection: DataSource
26✔
47

26✔
48
    /**
26✔
49
     * Sqlite has a single QueryRunner because it works on a single database connection.
26✔
50
     */
26✔
51
    queryRunner?: QueryRunner
26✔
52

26✔
53
    /**
26✔
54
     * Real database connection with sqlite database.
26✔
55
     */
26✔
56
    databaseConnection: any
26✔
57

26✔
58
    // -------------------------------------------------------------------------
26✔
59
    // Public Implemented Properties
26✔
60
    // -------------------------------------------------------------------------
26✔
61

26✔
62
    /**
26✔
63
     * Connection options.
26✔
64
     */
26✔
65
    options: BaseDataSourceOptions
26✔
66

26✔
67
    /**
26✔
68
     * Master database used to perform all write queries.
26✔
69
     */
26✔
70
    database?: string
26✔
71

26✔
72
    /**
26✔
73
     * Indicates if replication is enabled.
26✔
74
     */
26✔
75
    isReplicated: boolean = false
26✔
76

26✔
77
    /**
26✔
78
     * SQLite underlying library.
26✔
79
     */
26✔
80
    sqlite: any
26✔
81

26✔
82
    /**
26✔
83
     * Indicates if tree tables are supported by this driver.
26✔
84
     */
26✔
85
    treeSupport = true
26✔
86

26✔
87
    /**
26✔
88
     * Represent transaction support by this driver
26✔
89
     */
26✔
90
    transactionSupport: "simple" | "nested" | "none" = "nested"
26✔
91

26✔
92
    /**
26✔
93
     * Gets list of supported column data types by a driver.
26✔
94
     *
26✔
95
     * @see https://www.tutorialspoint.com/sqlite/sqlite_data_types.htm
26✔
96
     * @see https://sqlite.org/datatype3.html
26✔
97
     */
26✔
98
    supportedDataTypes: ColumnType[] = [
26✔
99
        "int",
26✔
100
        "integer",
26✔
101
        "tinyint",
26✔
102
        "smallint",
26✔
103
        "mediumint",
26✔
104
        "bigint",
26✔
105
        "unsigned big int",
26✔
106
        "int2",
26✔
107
        "int8",
26✔
108
        "integer",
26✔
109
        "character",
26✔
110
        "varchar",
26✔
111
        "varying character",
26✔
112
        "nchar",
26✔
113
        "native character",
26✔
114
        "nvarchar",
26✔
115
        "text",
26✔
116
        "clob",
26✔
117
        "text",
26✔
118
        "blob",
26✔
119
        "real",
26✔
120
        "double",
26✔
121
        "double precision",
26✔
122
        "float",
26✔
123
        "real",
26✔
124
        "numeric",
26✔
125
        "decimal",
26✔
126
        "boolean",
26✔
127
        "date",
26✔
128
        "time",
26✔
129
        "datetime",
26✔
130
        "json",
26✔
131
    ]
26✔
132

26✔
133
    /**
26✔
134
     * Returns type of upsert supported by driver if any
26✔
135
     */
26✔
136
    supportedUpsertTypes: UpsertType[] = ["on-conflict-do-update"]
26✔
137

26✔
138
    /**
26✔
139
     * Gets list of column data types that support length by a driver.
26✔
140
     */
26✔
141
    withLengthColumnTypes: ColumnType[] = [
26✔
142
        "character",
26✔
143
        "varchar",
26✔
144
        "varying character",
26✔
145
        "nchar",
26✔
146
        "native character",
26✔
147
        "nvarchar",
26✔
148
        "text",
26✔
149
        "blob",
26✔
150
        "clob",
26✔
151
    ]
26✔
152

26✔
153
    /**
26✔
154
     * Gets list of spatial column data types.
26✔
155
     */
26✔
156
    spatialTypes: ColumnType[] = []
26✔
157

26✔
158
    /**
26✔
159
     * Gets list of column data types that support precision by a driver.
26✔
160
     */
26✔
161
    withPrecisionColumnTypes: ColumnType[] = [
26✔
162
        "real",
26✔
163
        "double",
26✔
164
        "double precision",
26✔
165
        "float",
26✔
166
        "real",
26✔
167
        "numeric",
26✔
168
        "decimal",
26✔
169
        "date",
26✔
170
        "time",
26✔
171
        "datetime",
26✔
172
    ]
26✔
173

26✔
174
    /**
26✔
175
     * Gets list of column data types that support scale by a driver.
26✔
176
     */
26✔
177
    withScaleColumnTypes: ColumnType[] = [
26✔
178
        "real",
26✔
179
        "double",
26✔
180
        "double precision",
26✔
181
        "float",
26✔
182
        "real",
26✔
183
        "numeric",
26✔
184
        "decimal",
26✔
185
    ]
26✔
186

26✔
187
    /**
26✔
188
     * Orm has special columns and we need to know what database column types should be for those types.
26✔
189
     * Column types are driver dependant.
26✔
190
     */
26✔
191
    mappedDataTypes: MappedColumnTypes = {
26✔
192
        createDate: "datetime",
26✔
193
        createDateDefault: "datetime('now')",
26✔
194
        updateDate: "datetime",
26✔
195
        updateDateDefault: "datetime('now')",
26✔
196
        deleteDate: "datetime",
26✔
197
        deleteDateNullable: true,
26✔
198
        version: "integer",
26✔
199
        treeLevel: "integer",
26✔
200
        migrationId: "integer",
26✔
201
        migrationName: "varchar",
26✔
202
        migrationTimestamp: "bigint",
26✔
203
        cacheId: "int",
26✔
204
        cacheIdentifier: "varchar",
26✔
205
        cacheTime: "bigint",
26✔
206
        cacheDuration: "int",
26✔
207
        cacheQuery: "text",
26✔
208
        cacheResult: "text",
26✔
209
        metadataType: "varchar",
26✔
210
        metadataDatabase: "varchar",
26✔
211
        metadataSchema: "varchar",
26✔
212
        metadataTable: "varchar",
26✔
213
        metadataName: "varchar",
26✔
214
        metadataValue: "text",
26✔
215
    }
26✔
216

26✔
217
    /**
26✔
218
     * Default values of length, precision and scale depends on column data type.
26✔
219
     * Used in the cases when length/precision/scale is not specified by user.
26✔
220
     */
26✔
221
    dataTypeDefaults: DataTypeDefaults
26✔
222

26✔
223
    /**
26✔
224
     * No documentation specifying a maximum length for identifiers could be found
26✔
225
     * for SQLite.
26✔
226
     */
26✔
227
    maxAliasLength?: number
26✔
228

26✔
229
    cteCapabilities: CteCapabilities = {
26✔
230
        enabled: true,
26✔
231
        requiresRecursiveHint: true,
26✔
232
    }
26✔
233

26✔
234
    // -------------------------------------------------------------------------
26✔
235
    // Protected Properties
26✔
236
    // -------------------------------------------------------------------------
26✔
237

26✔
238
    /**
26✔
239
     * Any attached databases (excepting default 'main')
26✔
240
     */
26✔
241
    attachedDatabases: DatabasesMap = {}
26✔
242

26✔
243
    // -------------------------------------------------------------------------
26✔
244
    // Constructor
26✔
245
    // -------------------------------------------------------------------------
26✔
246

26✔
247
    constructor(connection: DataSource) {
26✔
248
        this.connection = connection
4,200✔
249
        this.options = connection.options as BaseDataSourceOptions
4,200✔
250

4,200✔
251
        this.database = DriverUtils.buildDriverOptions(this.options).database
4,200✔
252
    }
4,200✔
253

26✔
254
    // -------------------------------------------------------------------------
26✔
255
    // Public Abstract
26✔
256
    // -------------------------------------------------------------------------
26✔
257

26✔
258
    /**
26✔
259
     * Creates a query runner used to execute database queries.
26✔
260
     */
26✔
261
    abstract createQueryRunner(mode: ReplicationMode): QueryRunner
26✔
262

26✔
263
    // -------------------------------------------------------------------------
26✔
264
    // Public Methods
26✔
265
    // -------------------------------------------------------------------------
26✔
266

26✔
267
    /**
26✔
268
     * Performs connection to the database.
26✔
269
     */
26✔
270
    async connect(): Promise<void> {
26✔
271
        this.databaseConnection = await this.createDatabaseConnection()
2,910✔
272
    }
2,910✔
273

26✔
274
    /**
26✔
275
     * Makes any action after connection (e.g. create extensions in Postgres driver).
26✔
276
     */
26✔
277
    afterConnect(): Promise<void> {
26✔
278
        return Promise.resolve()
1,284✔
279
    }
1,284✔
280

26✔
281
    /**
26✔
282
     * Closes connection with database.
26✔
283
     */
26✔
284
    async disconnect(): Promise<void> {
26✔
285
        return new Promise<void>((ok, fail) => {
×
286
            this.queryRunner = undefined
×
287
            this.databaseConnection.close((err: any) =>
×
288
                err ? fail(err) : ok(),
×
289
            )
×
290
        })
×
291
    }
×
292

26✔
293
    hasAttachedDatabases(): boolean {
26✔
294
        return !!Object.keys(this.attachedDatabases).length
×
295
    }
×
296

26✔
297
    getAttachedDatabaseHandleByRelativePath(path: string): string | undefined {
26✔
298
        return this.attachedDatabases?.[path]?.attachHandle
1,869,711✔
299
    }
1,869,711✔
300

26✔
301
    getAttachedDatabasePathRelativeByHandle(
26✔
302
        handle: string,
981✔
303
    ): string | undefined {
981✔
304
        return Object.values(this.attachedDatabases).find(
981✔
305
            ({ attachHandle }) => handle === attachHandle,
981✔
306
        )?.attachFilepathRelative
981✔
307
    }
981✔
308

26✔
309
    /**
26✔
310
     * Creates a schema builder used to build and sync a schema.
26✔
311
     */
26✔
312
    createSchemaBuilder() {
26✔
313
        return new RdbmsSchemaBuilder(this.connection)
12,498✔
314
    }
12,498✔
315

26✔
316
    /**
26✔
317
     * Prepares given value to a value to be persisted, based on its column type and metadata.
26✔
318
     */
26✔
319
    preparePersistentValue(value: any, columnMetadata: ColumnMetadata): any {
26✔
320
        if (columnMetadata.transformer)
342,930✔
321
            value = ApplyValueTransformers.transformTo(
342,930✔
322
                columnMetadata.transformer,
417✔
323
                value,
417✔
324
            )
417✔
325

342,930✔
326
        if (value === null || value === undefined) return value
342,930✔
327

286,119✔
328
        if (
286,119✔
329
            columnMetadata.type === Boolean ||
286,119✔
330
            columnMetadata.type === "boolean"
268,056✔
331
        ) {
342,930✔
332
            return value === true ? 1 : 0
18,081✔
333
        } else if (columnMetadata.type === "date") {
342,930✔
334
            return DateUtils.mixedDateToDateString(value)
21✔
335
        } else if (columnMetadata.type === "time") {
268,038!
336
            return DateUtils.mixedDateToTimeString(value)
12✔
337
        } else if (
268,017✔
338
            columnMetadata.type === "datetime" ||
268,005✔
339
            columnMetadata.type === Date
267,921✔
340
        ) {
268,005✔
341
            // to string conversation needs because SQLite stores date as integer number, when date came as Object
282✔
342
            // TODO: think about `toUTC` conversion
282✔
343
            return DateUtils.mixedDateToUtcDatetimeString(value)
282✔
344
        } else if (
268,005✔
345
            columnMetadata.type === "json" ||
267,723✔
346
            columnMetadata.type === "simple-json"
267,717✔
347
        ) {
267,723✔
348
            return DateUtils.simpleJsonToString(value)
48✔
349
        } else if (columnMetadata.type === "simple-array") {
267,723!
350
            return DateUtils.simpleArrayToString(value)
6✔
351
        } else if (columnMetadata.type === "simple-enum") {
267,675!
352
            return DateUtils.simpleEnumToString(value)
66✔
353
        }
66✔
354

267,603✔
355
        return value
267,603✔
356
    }
267,603✔
357

26✔
358
    /**
26✔
359
     * Prepares given value to a value to be hydrated, based on its column type or metadata.
26✔
360
     */
26✔
361
    prepareHydratedValue(value: any, columnMetadata: ColumnMetadata): any {
26✔
362
        if (value === null || value === undefined)
597,018✔
363
            return columnMetadata.transformer
597,018✔
364
                ? ApplyValueTransformers.transformFrom(
46,563✔
365
                      columnMetadata.transformer,
108✔
366
                      value,
108✔
367
                  )
46,563✔
368
                : value
46,563✔
369

550,455✔
370
        if (
550,455✔
371
            columnMetadata.type === Boolean ||
550,455✔
372
            columnMetadata.type === "boolean"
544,062✔
373
        ) {
597,018✔
374
            value = value ? true : false
6,399✔
375
        } else if (
597,018✔
376
            columnMetadata.type === "datetime" ||
544,056✔
377
            columnMetadata.type === Date
540,006✔
378
        ) {
544,056✔
379
            /**
4,413✔
380
             * Fix date conversion issue
4,413✔
381
             *
4,413✔
382
             * If the format of the date string is "2018-03-14 02:33:33.906", Safari (and iOS WKWebView) will convert it to an invalid date object.
4,413✔
383
             * We need to modify the date string to "2018-03-14T02:33:33.906Z" and Safari will convert it correctly.
4,413✔
384
             *
4,413✔
385
             * ISO 8601
4,413✔
386
             * https://www.w3.org/TR/NOTE-datetime
4,413✔
387
             */
4,413✔
388
            if (value && typeof value === "string") {
4,413✔
389
                // There are various valid time string formats a sqlite time string might have:
2,919✔
390
                // https://www.sqlite.org/lang_datefunc.html
2,919✔
391
                // There are two separate fixes we may need to do:
2,919✔
392
                //   1) Add 'T' separator if space is used instead
2,919✔
393
                //   2) Add 'Z' UTC suffix if no timezone or offset specified
2,919✔
394

2,919✔
395
                if (/^\d\d\d\d-\d\d-\d\d \d\d:\d\d/.test(value)) {
2,919✔
396
                    value = value.replace(" ", "T")
2,910✔
397
                }
2,910✔
398
                if (
2,919✔
399
                    /^\d\d\d\d-\d\d-\d\dT\d\d:\d\d(:\d\d(\.\d\d\d)?)?$/.test(
2,919✔
400
                        value,
2,919✔
401
                    )
2,919✔
402
                ) {
2,919✔
403
                    value += "Z"
2,910✔
404
                }
2,910✔
405
            }
2,919✔
406

4,413✔
407
            value = DateUtils.normalizeHydratedDate(value)
4,413✔
408
        } else if (columnMetadata.type === "date") {
544,056✔
409
            value = DateUtils.mixedDateToDateString(value)
27✔
410
        } else if (columnMetadata.type === "time") {
539,643!
411
            value = DateUtils.mixedTimeToString(value)
12✔
412
        } else if (
539,616✔
413
            columnMetadata.type === "json" ||
539,604✔
414
            columnMetadata.type === "simple-json"
539,598✔
415
        ) {
539,604✔
416
            value = DateUtils.stringToSimpleJson(value)
60✔
417
        } else if (columnMetadata.type === "simple-array") {
539,604!
418
            value = DateUtils.stringToSimpleArray(value)
6✔
419
        } else if (columnMetadata.type === "simple-enum") {
539,544!
420
            value = DateUtils.stringToSimpleEnum(value, columnMetadata)
240✔
421
        } else if (columnMetadata.type === Number) {
539,538✔
422
            // convert to number if number
129,021✔
423
            value = !isNaN(+value) ? parseInt(value) : value
129,021!
424
        }
129,021✔
425

550,455✔
426
        if (columnMetadata.transformer)
550,455✔
427
            value = ApplyValueTransformers.transformFrom(
597,018✔
428
                columnMetadata.transformer,
555✔
429
                value,
555✔
430
            )
555✔
431

550,455✔
432
        return value
550,455✔
433
    }
550,455✔
434

26✔
435
    /**
26✔
436
     * Replaces parameters in the given sql with special escaping character
26✔
437
     * and an array of parameter names to be passed to a query.
26✔
438
     */
26✔
439
    escapeQueryWithParameters(
26✔
440
        sql: string,
153,141✔
441
        parameters: ObjectLiteral,
153,141✔
442
        nativeParameters: ObjectLiteral,
153,141✔
443
    ): [string, any[]] {
153,141✔
444
        const escapedParameters: any[] = Object.keys(nativeParameters).map(
153,141✔
445
            (key) => {
153,141✔
446
                // Mapping boolean values to their numeric representation
12✔
447
                if (typeof nativeParameters[key] === "boolean") {
12✔
448
                    return nativeParameters[key] === true ? 1 : 0
12✔
449
                }
12✔
450

×
451
                if (nativeParameters[key] instanceof Date) {
×
452
                    return DateUtils.mixedDateToUtcDatetimeString(
×
453
                        nativeParameters[key],
×
454
                    )
×
455
                }
×
456

×
457
                return nativeParameters[key]
×
458
            },
153,141✔
459
        )
153,141✔
460

153,141✔
461
        if (!parameters || !Object.keys(parameters).length)
153,141✔
462
            return [sql, escapedParameters]
153,141✔
463

146,994✔
464
        sql = sql.replace(
146,994✔
465
            /:(\.\.\.)?([A-Za-z0-9_.]+)/g,
146,994✔
466
            (full, isArray: string, key: string): string => {
146,994✔
467
                if (!parameters.hasOwnProperty(key)) {
399,348!
468
                    return full
×
469
                }
×
470

399,348✔
471
                const value: any = parameters[key]
399,348✔
472

399,348✔
473
                if (isArray) {
399,348✔
474
                    return value
1,044✔
475
                        .map((v: any) => {
1,044✔
476
                            escapedParameters.push(v)
1,467✔
477
                            return this.createParameter(
1,467✔
478
                                key,
1,467✔
479
                                escapedParameters.length - 1,
1,467✔
480
                            )
1,467✔
481
                        })
1,044✔
482
                        .join(", ")
1,044✔
483
                }
1,044✔
484

398,304✔
485
                if (typeof value === "function") {
399,348!
486
                    return value()
×
487
                } else if (typeof value === "number") {
399,348✔
488
                    return String(value)
241,818✔
489
                }
241,818✔
490

156,486✔
491
                // Sqlite does not have a boolean data type so we have to transform
156,486✔
492
                // it to 1 or 0
156,486✔
493
                if (typeof value === "boolean") {
399,348✔
494
                    escapedParameters.push(+value)
1,401✔
495
                    return this.createParameter(
1,401✔
496
                        key,
1,401✔
497
                        escapedParameters.length - 1,
1,401✔
498
                    )
1,401✔
499
                }
1,401✔
500

155,085✔
501
                if (value instanceof Date) {
399,348!
502
                    escapedParameters.push(
33✔
503
                        DateUtils.mixedDateToUtcDatetimeString(value),
33✔
504
                    )
33✔
505
                    return this.createParameter(
33✔
506
                        key,
33✔
507
                        escapedParameters.length - 1,
33✔
508
                    )
33✔
509
                }
33✔
510

155,052✔
511
                escapedParameters.push(value)
155,052✔
512
                return this.createParameter(key, escapedParameters.length - 1)
155,052✔
513
            },
146,994✔
514
        ) // todo: make replace only in value statements, otherwise problems
146,994✔
515
        return [sql, escapedParameters]
146,994✔
516
    }
146,994✔
517

26✔
518
    /**
26✔
519
     * Escapes a column name.
26✔
520
     */
26✔
521
    escape(columnName: string): string {
26✔
522
        return '"' + columnName + '"'
12,876,042✔
523
    }
12,876,042✔
524

26✔
525
    /**
26✔
526
     * Build full table name with database name, schema name and table name.
26✔
527
     * E.g. myDB.mySchema.myTable
26✔
528
     *
26✔
529
     * Returns only simple table name because all inherited drivers does not supports schema and database.
26✔
530
     */
26✔
531
    buildTableName(
26✔
532
        tableName: string,
903,015✔
533
        schema?: string,
903,015✔
534
        database?: string,
903,015✔
535
    ): string {
903,015✔
536
        return tableName
903,015✔
537
    }
903,015✔
538

26✔
539
    /**
26✔
540
     * Parse a target table name or other types and return a normalized table definition.
26✔
541
     */
26✔
542
    parseTableName(
26✔
543
        target: EntityMetadata | Table | View | TableForeignKey | string,
4,099,242✔
544
    ): { database?: string; schema?: string; tableName: string } {
4,099,242✔
545
        const driverDatabase = this.database
4,099,242✔
546
        const driverSchema = undefined
4,099,242✔
547

4,099,242✔
548
        if (InstanceChecker.isTable(target) || InstanceChecker.isView(target)) {
4,099,242✔
549
            const parsed = this.parseTableName(
1,364,355✔
550
                target.schema
1,364,355✔
551
                    ? `"${target.schema}"."${target.name}"`
1,364,355!
552
                    : target.name,
1,364,355✔
553
            )
1,364,355✔
554

1,364,355✔
555
            return {
1,364,355✔
556
                database: target.database || parsed.database || driverDatabase,
1,364,355!
557
                schema: target.schema || parsed.schema || driverSchema,
1,364,355✔
558
                tableName: parsed.tableName,
1,364,355✔
559
            }
1,364,355✔
560
        }
1,364,355✔
561

2,734,887✔
562
        if (InstanceChecker.isTableForeignKey(target)) {
4,099,242✔
563
            const parsed = this.parseTableName(target.referencedTableName)
1,947✔
564

1,947✔
565
            return {
1,947✔
566
                database:
1,947✔
567
                    target.referencedDatabase ||
1,947✔
568
                    parsed.database ||
1,947!
569
                    driverDatabase,
1,947✔
570
                schema:
1,947✔
571
                    target.referencedSchema || parsed.schema || driverSchema,
1,947✔
572
                tableName: parsed.tableName,
1,947✔
573
            }
1,947✔
574
        }
1,947✔
575

2,732,940✔
576
        if (InstanceChecker.isEntityMetadata(target)) {
4,099,242✔
577
            // EntityMetadata tableName is never a path
1,366,638✔
578

1,366,638✔
579
            return {
1,366,638✔
580
                database: target.database || driverDatabase,
1,366,638✔
581
                schema: target.schema || driverSchema,
1,366,638✔
582
                tableName: target.tableName,
1,366,638✔
583
            }
1,366,638✔
584
        }
1,366,638✔
585

1,366,302✔
586
        const parts = target.split(".")
1,366,302✔
587

1,366,302✔
588
        if (parts.length === 3) {
4,099,242!
589
            return {
×
590
                database: parts[0] || driverDatabase,
×
591
                schema: parts[1] || driverSchema,
×
592
                tableName: parts[2],
×
593
            }
×
594
        } else if (parts.length === 2) {
4,099,242!
595
            const database =
789✔
596
                this.getAttachedDatabasePathRelativeByHandle(parts[0]) ??
789!
597
                driverDatabase
×
598
            return {
789✔
599
                database: database,
789✔
600
                schema: parts[0],
789✔
601
                tableName: parts[1],
789✔
602
            }
789✔
603
        } else {
1,366,302✔
604
            return {
1,365,513✔
605
                database: driverDatabase,
1,365,513✔
606
                schema: driverSchema,
1,365,513✔
607
                tableName: target,
1,365,513✔
608
            }
1,365,513✔
609
        }
1,365,513✔
610
    }
4,099,242✔
611

26✔
612
    /**
26✔
613
     * Creates a database type from a given column metadata.
26✔
614
     */
26✔
615
    normalizeType(column: {
26✔
616
        type?: ColumnType
295,026✔
617
        length?: number | string
295,026✔
618
        precision?: number | null
295,026✔
619
        scale?: number
295,026✔
620
    }): string {
295,026✔
621
        if (column.type === Number || column.type === "int") {
295,026✔
622
            return "integer"
149,808✔
623
        } else if (column.type === String) {
295,026✔
624
            return "varchar"
113,421✔
625
        } else if (column.type === Date) {
145,218✔
626
            return "datetime"
1,134✔
627
        } else if (column.type === Boolean) {
31,797✔
628
            return "boolean"
7,911✔
629
        } else if (column.type === "uuid") {
30,663✔
630
            return "varchar"
4,572✔
631
        } else if (column.type === "simple-array") {
22,752!
632
            return "text"
30✔
633
        } else if (column.type === "simple-json") {
18,180✔
634
            return "text"
210✔
635
        } else if (column.type === "simple-enum") {
18,150!
636
            return "varchar"
396✔
637
        } else {
17,940✔
638
            return (column.type as string) || ""
17,544!
639
        }
17,544✔
640
    }
295,026✔
641

26✔
642
    /**
26✔
643
     * Normalizes "default" value of the column.
26✔
644
     */
26✔
645
    normalizeDefault(columnMetadata: ColumnMetadata): string | undefined {
26✔
646
        const defaultValue = columnMetadata.default
257,946✔
647

257,946✔
648
        if (typeof defaultValue === "number") {
257,946✔
649
            return "" + defaultValue
3,039✔
650
        }
3,039✔
651

254,907✔
652
        if (typeof defaultValue === "boolean") {
257,946✔
653
            return defaultValue ? "1" : "0"
198✔
654
        }
198✔
655

254,709✔
656
        if (typeof defaultValue === "function") {
257,946✔
657
            return defaultValue()
7,059✔
658
        }
7,059✔
659

247,650✔
660
        if (typeof defaultValue === "string") {
257,946✔
661
            return `'${defaultValue}'`
4,983✔
662
        }
4,983✔
663

242,667✔
664
        if (defaultValue === null || defaultValue === undefined) {
257,946✔
665
            return undefined
242,667✔
666
        }
242,667✔
667

×
668
        return `${defaultValue}`
×
669
    }
×
670

26✔
671
    /**
26✔
672
     * Normalizes "isUnique" value of the column.
26✔
673
     */
26✔
674
    normalizeIsUnique(column: ColumnMetadata): boolean {
26✔
675
        return column.entityMetadata.uniques.some(
260,145✔
676
            (uq) => uq.columns.length === 1 && uq.columns[0] === column,
260,145✔
677
        )
260,145✔
678
    }
260,145✔
679

26✔
680
    /**
26✔
681
     * Calculates column length taking into account the default length values.
26✔
682
     */
26✔
683
    getColumnLength(column: ColumnMetadata): string {
26✔
684
        return column.length ? column.length.toString() : ""
124,617✔
685
    }
124,617✔
686

26✔
687
    /**
26✔
688
     * Normalizes "default" value of the column.
26✔
689
     */
26✔
690
    createFullType(column: TableColumn): string {
26✔
691
        let type = column.type
237,105✔
692
        if (column.enum) {
237,105!
693
            return "varchar"
144✔
694
        }
144✔
695
        if (column.length) {
237,105✔
696
            type += "(" + column.length + ")"
8,235✔
697
        } else if (
237,105✔
698
            column.precision !== null &&
228,726✔
699
            column.precision !== undefined &&
228,726✔
700
            column.scale !== null &&
228,726✔
701
            column.scale !== undefined
78✔
702
        ) {
228,726✔
703
            type += "(" + column.precision + "," + column.scale + ")"
39✔
704
        } else if (
228,726✔
705
            column.precision !== null &&
228,687✔
706
            column.precision !== undefined
228,687✔
707
        ) {
228,687✔
708
            type += "(" + column.precision + ")"
39✔
709
        }
39✔
710

236,961✔
711
        if (column.isArray) type += " array"
237,105!
712

236,961✔
713
        return type
236,961✔
714
    }
236,961✔
715

26✔
716
    /**
26✔
717
     * Obtains a new database connection to a master server.
26✔
718
     * Used for replication.
26✔
719
     * If replication is not setup then returns default connection's database connection.
26✔
720
     */
26✔
721
    obtainMasterConnection(): Promise<any> {
26✔
722
        return Promise.resolve()
×
723
    }
×
724

26✔
725
    /**
26✔
726
     * Obtains a new database connection to a slave server.
26✔
727
     * Used for replication.
26✔
728
     * If replication is not setup then returns master (default) connection's database connection.
26✔
729
     */
26✔
730
    obtainSlaveConnection(): Promise<any> {
26✔
731
        return Promise.resolve()
×
732
    }
×
733

26✔
734
    /**
26✔
735
     * Creates generated map of values generated or returned by database after INSERT query.
26✔
736
     */
26✔
737
    createGeneratedMap(
26✔
738
        metadata: EntityMetadata,
92,715✔
739
        insertResult: any,
92,715✔
740
        entityIndex: number,
92,715✔
741
        entityNum: number,
92,715✔
742
    ) {
92,715✔
743
        const generatedMap = metadata.generatedColumns.reduce(
92,715✔
744
            (map, generatedColumn) => {
92,715✔
745
                let value: any
27,732✔
746
                if (
27,732✔
747
                    generatedColumn.generationStrategy === "increment" &&
27,732✔
748
                    insertResult
27,012✔
749
                ) {
27,732✔
750
                    // NOTE: When INSERT statement is successfully completed, the last inserted row ID is returned.
27,009✔
751
                    // see also: SqliteQueryRunner.query()
27,009✔
752
                    value = insertResult - entityNum + entityIndex + 1
27,009✔
753
                    // } else if (generatedColumn.generationStrategy === "uuid") {
27,009✔
754
                    //     value = insertValue[generatedColumn.databaseName];
27,009✔
755
                }
27,009✔
756

27,732✔
757
                if (!value) return map
27,732✔
758
                return OrmUtils.mergeDeep(
27,009✔
759
                    map,
27,009✔
760
                    generatedColumn.createValueMap(value),
27,009✔
761
                )
27,009✔
762
            },
92,715✔
763
            {} as ObjectLiteral,
92,715✔
764
        )
92,715✔
765

92,715✔
766
        return Object.keys(generatedMap).length > 0 ? generatedMap : undefined
92,715✔
767
    }
92,715✔
768

26✔
769
    /**
26✔
770
     * Differentiate columns of this table and columns from the given column metadatas columns
26✔
771
     * and returns only changed.
26✔
772
     */
26✔
773
    findChangedColumns(
26✔
774
        tableColumns: TableColumn[],
41,976✔
775
        columnMetadatas: ColumnMetadata[],
41,976✔
776
    ): ColumnMetadata[] {
41,976✔
777
        return columnMetadatas.filter((columnMetadata) => {
41,976✔
778
            const tableColumn = tableColumns.find(
130,110✔
779
                (c) => c.name === columnMetadata.databaseName,
130,110✔
780
            )
130,110✔
781
            if (!tableColumn) return false // we don't need new columns, we only need exist and changed
130,110✔
782

130,071✔
783
            const isColumnChanged =
130,071✔
784
                tableColumn.name !== columnMetadata.databaseName ||
130,071✔
785
                tableColumn.type !== this.normalizeType(columnMetadata) ||
130,110✔
786
                tableColumn.length !== columnMetadata.length ||
130,110✔
787
                tableColumn.precision !== columnMetadata.precision ||
130,110✔
788
                tableColumn.scale !== columnMetadata.scale ||
130,110✔
789
                this.normalizeDefault(columnMetadata) !== tableColumn.default ||
130,110✔
790
                tableColumn.isPrimary !== columnMetadata.isPrimary ||
130,110✔
791
                tableColumn.isNullable !== columnMetadata.isNullable ||
130,110✔
792
                tableColumn.generatedType !== columnMetadata.generatedType ||
130,110✔
793
                tableColumn.asExpression !== columnMetadata.asExpression ||
130,110✔
794
                tableColumn.isUnique !==
129,945✔
795
                    this.normalizeIsUnique(columnMetadata) ||
130,110✔
796
                (tableColumn.enum &&
129,936!
797
                    columnMetadata.enum &&
129,936!
798
                    !OrmUtils.isArraysEqual(
159✔
799
                        tableColumn.enum,
159✔
800
                        columnMetadata.enum.map((val) => val + ""),
159✔
801
                    )) ||
130,110✔
802
                (columnMetadata.generationStrategy !== "uuid" &&
129,933✔
803
                    tableColumn.isGenerated !== columnMetadata.isGenerated)
129,933✔
804

130,110✔
805
            // DEBUG SECTION
130,110✔
806
            // if (isColumnChanged) {
130,110✔
807
            //     console.log("table:", columnMetadata.entityMetadata.tableName)
130,110✔
808
            //     console.log(
130,110✔
809
            //         "name:",
130,110✔
810
            //         tableColumn.name,
130,110✔
811
            //         columnMetadata.databaseName,
130,110✔
812
            //     )
130,110✔
813
            //     console.log(
130,110✔
814
            //         "type:",
130,110✔
815
            //         tableColumn.type,
130,110✔
816
            //         this.normalizeType(columnMetadata),
130,110✔
817
            //     )
130,110✔
818
            //     console.log(
130,110✔
819
            //         "length:",
130,110✔
820
            //         tableColumn.length,
130,110✔
821
            //         columnMetadata.length,
130,110✔
822
            //     )
130,110✔
823
            //     console.log(
130,110✔
824
            //         "precision:",
130,110✔
825
            //         tableColumn.precision,
130,110✔
826
            //         columnMetadata.precision,
130,110✔
827
            //     )
130,110✔
828
            //     console.log("scale:", tableColumn.scale, columnMetadata.scale)
130,110✔
829
            //     console.log(
130,110✔
830
            //         "default:",
130,110✔
831
            //         this.normalizeDefault(columnMetadata),
130,110✔
832
            //         columnMetadata.default,
130,110✔
833
            //     )
130,110✔
834
            //     console.log(
130,110✔
835
            //         "isPrimary:",
130,110✔
836
            //         tableColumn.isPrimary,
130,110✔
837
            //         columnMetadata.isPrimary,
130,110✔
838
            //     )
130,110✔
839
            //     console.log(
130,110✔
840
            //         "isNullable:",
130,110✔
841
            //         tableColumn.isNullable,
130,110✔
842
            //         columnMetadata.isNullable,
130,110✔
843
            //     )
130,110✔
844
            //     console.log(
130,110✔
845
            //         "generatedType:",
130,110✔
846
            //         tableColumn.generatedType,
130,110✔
847
            //         columnMetadata.generatedType,
130,110✔
848
            //     )
130,110✔
849
            //     console.log(
130,110✔
850
            //         "asExpression:",
130,110✔
851
            //         tableColumn.asExpression,
130,110✔
852
            //         columnMetadata.asExpression,
130,110✔
853
            //     )
130,110✔
854
            //     console.log(
130,110✔
855
            //         "isUnique:",
130,110✔
856
            //         tableColumn.isUnique,
130,110✔
857
            //         this.normalizeIsUnique(columnMetadata),
130,110✔
858
            //     )
130,110✔
859
            //     console.log(
130,110✔
860
            //         "enum:",
130,110✔
861
            //         tableColumn.enum &&
130,110✔
862
            //             columnMetadata.enum &&
130,110✔
863
            //             !OrmUtils.isArraysEqual(
130,110✔
864
            //                 tableColumn.enum,
130,110✔
865
            //                 columnMetadata.enum.map((val) => val + ""),
130,110✔
866
            //             ),
130,110✔
867
            //     )
130,110✔
868
            //     console.log(
130,110✔
869
            //         "isGenerated:",
130,110✔
870
            //         tableColumn.isGenerated,
130,110✔
871
            //         columnMetadata.isGenerated,
130,110✔
872
            //     )
130,110✔
873
            // }
130,110✔
874

130,110✔
875
            return isColumnChanged
130,110✔
876
        })
41,976✔
877
    }
41,976✔
878

26✔
879
    /**
26✔
880
     * Returns true if driver supports RETURNING / OUTPUT statement.
26✔
881
     */
26✔
882
    isReturningSqlSupported(): boolean {
26✔
883
        return false
185,121✔
884
    }
185,121✔
885

26✔
886
    /**
26✔
887
     * Returns true if driver supports uuid values generation on its own.
26✔
888
     */
26✔
889
    isUUIDGenerationSupported(): boolean {
26✔
890
        return false
1,053✔
891
    }
1,053✔
892

26✔
893
    /**
26✔
894
     * Returns true if driver supports fulltext indices.
26✔
895
     */
26✔
896
    isFullTextColumnTypeSupported(): boolean {
26✔
897
        return false
216✔
898
    }
216✔
899

26✔
900
    /**
26✔
901
     * Creates an escaped parameter.
26✔
902
     */
26✔
903
    createParameter(parameterName: string, index: number): string {
26✔
904
        // return "$" + (index + 1);
159,567✔
905
        return "?"
159,567✔
906
        // return "$" + parameterName;
159,567✔
907
    }
159,567✔
908

26✔
909
    // -------------------------------------------------------------------------
26✔
910
    // Protected Methods
26✔
911
    // -------------------------------------------------------------------------
26✔
912

26✔
913
    /**
26✔
914
     * Creates connection with the database.
26✔
915
     */
26✔
916
    protected async createDatabaseConnection(): Promise<any> {
26✔
917
        throw new TypeORMError(
×
918
            "Do not use AbstractSqlite directly, it has to be used with one of the sqlite drivers",
×
919
        )
×
920
    }
×
921

26✔
922
    /**
26✔
923
     * If driver dependency is not given explicitly, then try to load it via "require".
26✔
924
     */
26✔
925
    protected loadDependencies(): void {
26✔
926
        // dependencies have to be loaded in the specific driver
×
927
    }
×
928
}
26✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc