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

typeorm / typeorm / 15219332477

23 May 2025 09:13PM UTC coverage: 17.216% (-59.1%) from 76.346%
15219332477

Pull #11332

github

naorpeled
cr comments - move if block
Pull Request #11332: feat: add new undefined and null behavior flags

1603 of 12759 branches covered (12.56%)

Branch coverage included in aggregate %.

0 of 31 new or added lines in 3 files covered. (0.0%)

14132 existing lines in 166 files now uncovered.

4731 of 24033 relevant lines covered (19.69%)

60.22 hits per line

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

UNCOV
229
    cteCapabilities: CteCapabilities = {
×
230
        enabled: true,
231
        requiresRecursiveHint: true,
232
    }
233

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

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

243
    // -------------------------------------------------------------------------
244
    // Constructor
245
    // -------------------------------------------------------------------------
246

247
    constructor(connection: DataSource) {
UNCOV
248
        this.connection = connection
×
UNCOV
249
        this.options = connection.options as BaseDataSourceOptions
×
250

UNCOV
251
        this.database = DriverUtils.buildDriverOptions(this.options).database
×
252
    }
253

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

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

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

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

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

281
    /**
282
     * Closes connection with database.
283
     */
284
    async disconnect(): Promise<void> {
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

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

297
    getAttachedDatabaseHandleByRelativePath(path: string): string | undefined {
UNCOV
298
        return this.attachedDatabases?.[path]?.attachHandle
×
299
    }
300

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

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

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

UNCOV
326
        if (value === null || value === undefined) return value
×
327

UNCOV
328
        if (
×
329
            columnMetadata.type === Boolean ||
×
330
            columnMetadata.type === "boolean"
331
        ) {
UNCOV
332
            return value === true ? 1 : 0
×
UNCOV
333
        } else if (columnMetadata.type === "date") {
×
UNCOV
334
            return DateUtils.mixedDateToDateString(value)
×
UNCOV
335
        } else if (columnMetadata.type === "time") {
×
UNCOV
336
            return DateUtils.mixedDateToTimeString(value)
×
UNCOV
337
        } else if (
×
338
            columnMetadata.type === "datetime" ||
×
339
            columnMetadata.type === Date
340
        ) {
341
            // to string conversation needs because SQLite stores date as integer number, when date came as Object
342
            // TODO: think about `toUTC` conversion
UNCOV
343
            return DateUtils.mixedDateToUtcDatetimeString(value)
×
UNCOV
344
        } else if (
×
345
            columnMetadata.type === "json" ||
×
346
            columnMetadata.type === "simple-json"
347
        ) {
UNCOV
348
            return DateUtils.simpleJsonToString(value)
×
UNCOV
349
        } else if (columnMetadata.type === "simple-array") {
×
UNCOV
350
            return DateUtils.simpleArrayToString(value)
×
UNCOV
351
        } else if (columnMetadata.type === "simple-enum") {
×
UNCOV
352
            return DateUtils.simpleEnumToString(value)
×
353
        }
354

UNCOV
355
        return value
×
356
    }
357

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

UNCOV
370
        if (
×
371
            columnMetadata.type === Boolean ||
×
372
            columnMetadata.type === "boolean"
373
        ) {
UNCOV
374
            value = value ? true : false
×
UNCOV
375
        } else if (
×
376
            columnMetadata.type === "datetime" ||
×
377
            columnMetadata.type === Date
378
        ) {
379
            /**
380
             * Fix date conversion issue
381
             *
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.
383
             * We need to modify the date string to "2018-03-14T02:33:33.906Z" and Safari will convert it correctly.
384
             *
385
             * ISO 8601
386
             * https://www.w3.org/TR/NOTE-datetime
387
             */
UNCOV
388
            if (value && typeof value === "string") {
×
389
                // There are various valid time string formats a sqlite time string might have:
390
                // https://www.sqlite.org/lang_datefunc.html
391
                // There are two separate fixes we may need to do:
392
                //   1) Add 'T' separator if space is used instead
393
                //   2) Add 'Z' UTC suffix if no timezone or offset specified
394

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

UNCOV
407
            value = DateUtils.normalizeHydratedDate(value)
×
UNCOV
408
        } else if (columnMetadata.type === "date") {
×
UNCOV
409
            value = DateUtils.mixedDateToDateString(value)
×
UNCOV
410
        } else if (columnMetadata.type === "time") {
×
UNCOV
411
            value = DateUtils.mixedTimeToString(value)
×
UNCOV
412
        } else if (
×
413
            columnMetadata.type === "json" ||
×
414
            columnMetadata.type === "simple-json"
415
        ) {
UNCOV
416
            value = DateUtils.stringToSimpleJson(value)
×
UNCOV
417
        } else if (columnMetadata.type === "simple-array") {
×
UNCOV
418
            value = DateUtils.stringToSimpleArray(value)
×
UNCOV
419
        } else if (columnMetadata.type === "simple-enum") {
×
UNCOV
420
            value = DateUtils.stringToSimpleEnum(value, columnMetadata)
×
UNCOV
421
        } else if (columnMetadata.type === Number) {
×
422
            // convert to number if number
UNCOV
423
            value = !isNaN(+value) ? parseInt(value) : value
×
424
        }
425

UNCOV
426
        if (columnMetadata.transformer)
×
UNCOV
427
            value = ApplyValueTransformers.transformFrom(
×
428
                columnMetadata.transformer,
429
                value,
430
            )
431

UNCOV
432
        return value
×
433
    }
434

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

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

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

UNCOV
461
        if (!parameters || !Object.keys(parameters).length)
×
UNCOV
462
            return [sql, escapedParameters]
×
463

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

UNCOV
471
                const value: any = parameters[key]
×
472

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

UNCOV
485
                if (typeof value === "function") {
×
486
                    return value()
×
UNCOV
487
                } else if (typeof value === "number") {
×
UNCOV
488
                    return String(value)
×
489
                }
490

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

UNCOV
501
                if (value instanceof Date) {
×
UNCOV
502
                    escapedParameters.push(
×
503
                        DateUtils.mixedDateToUtcDatetimeString(value),
504
                    )
UNCOV
505
                    return this.createParameter(
×
506
                        key,
507
                        escapedParameters.length - 1,
508
                    )
509
                }
510

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

518
    /**
519
     * Escapes a column name.
520
     */
521
    escape(columnName: string): string {
UNCOV
522
        return '"' + columnName + '"'
×
523
    }
524

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

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

UNCOV
548
        if (InstanceChecker.isTable(target) || InstanceChecker.isView(target)) {
×
UNCOV
549
            const parsed = this.parseTableName(
×
550
                target.schema
×
551
                    ? `"${target.schema}"."${target.name}"`
552
                    : target.name,
553
            )
554

UNCOV
555
            return {
×
556
                database: target.database || parsed.database || driverDatabase,
×
557
                schema: target.schema || parsed.schema || driverSchema,
×
558
                tableName: parsed.tableName,
559
            }
560
        }
561

UNCOV
562
        if (InstanceChecker.isTableForeignKey(target)) {
×
UNCOV
563
            const parsed = this.parseTableName(target.referencedTableName)
×
564

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

UNCOV
576
        if (InstanceChecker.isEntityMetadata(target)) {
×
577
            // EntityMetadata tableName is never a path
578

UNCOV
579
            return {
×
580
                database: target.database || driverDatabase,
×
581
                schema: target.schema || driverSchema,
×
582
                tableName: target.tableName,
583
            }
584
        }
585

UNCOV
586
        const parts = target.split(".")
×
587

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

612
    /**
613
     * Creates a database type from a given column metadata.
614
     */
615
    normalizeType(column: {
616
        type?: ColumnType
617
        length?: number | string
618
        precision?: number | null
619
        scale?: number
620
    }): string {
UNCOV
621
        if (column.type === Number || column.type === "int") {
×
UNCOV
622
            return "integer"
×
UNCOV
623
        } else if (column.type === String) {
×
UNCOV
624
            return "varchar"
×
UNCOV
625
        } else if (column.type === Date) {
×
UNCOV
626
            return "datetime"
×
UNCOV
627
        } else if (column.type === Boolean) {
×
UNCOV
628
            return "boolean"
×
UNCOV
629
        } else if (column.type === "uuid") {
×
UNCOV
630
            return "varchar"
×
UNCOV
631
        } else if (column.type === "simple-array") {
×
UNCOV
632
            return "text"
×
UNCOV
633
        } else if (column.type === "simple-json") {
×
UNCOV
634
            return "text"
×
UNCOV
635
        } else if (column.type === "simple-enum") {
×
UNCOV
636
            return "varchar"
×
637
        } else {
UNCOV
638
            return (column.type as string) || ""
×
639
        }
640
    }
641

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

UNCOV
648
        if (typeof defaultValue === "number") {
×
UNCOV
649
            return "" + defaultValue
×
650
        }
651

UNCOV
652
        if (typeof defaultValue === "boolean") {
×
UNCOV
653
            return defaultValue ? "1" : "0"
×
654
        }
655

UNCOV
656
        if (typeof defaultValue === "function") {
×
UNCOV
657
            return defaultValue()
×
658
        }
659

UNCOV
660
        if (typeof defaultValue === "string") {
×
UNCOV
661
            return `'${defaultValue}'`
×
662
        }
663

UNCOV
664
        if (defaultValue === null || defaultValue === undefined) {
×
UNCOV
665
            return undefined
×
666
        }
667

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

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

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

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

UNCOV
711
        if (column.isArray) type += " array"
×
712

UNCOV
713
        return type
×
714
    }
715

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

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

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

UNCOV
757
                if (!value) return map
×
UNCOV
758
                return OrmUtils.mergeDeep(
×
759
                    map,
760
                    generatedColumn.createValueMap(value),
761
                )
762
            },
763
            {} as ObjectLiteral,
764
        )
765

UNCOV
766
        return Object.keys(generatedMap).length > 0 ? generatedMap : undefined
×
767
    }
768

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

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

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

UNCOV
875
            return isColumnChanged
×
876
        })
877
    }
878

879
    /**
880
     * Returns true if driver supports RETURNING / OUTPUT statement.
881
     */
882
    isReturningSqlSupported(): boolean {
UNCOV
883
        return false
×
884
    }
885

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

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

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

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

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

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

© 2025 Coveralls, Inc