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

typeorm / typeorm / 20030970342

08 Dec 2025 02:10PM UTC coverage: 80.764% (-0.007%) from 80.771%
20030970342

push

github

web-flow
chore: disable eslint errors for chai assertions (#11833)

26554 of 32253 branches covered (82.33%)

Branch coverage included in aggregate %.

26 of 61 new or added lines in 5 files covered. (42.62%)

1 existing line in 1 file now uncovered.

91386 of 113778 relevant lines covered (80.32%)

68140.32 hits per line

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

93.27
/src/driver/oracle/OracleDriver.ts
1
import { Driver } from "../Driver"
26✔
2
import { ConnectionIsNotSetError } from "../../error/ConnectionIsNotSetError"
26✔
3
import { DriverPackageNotInstalledError } from "../../error/DriverPackageNotInstalledError"
26✔
4
import { CteCapabilities } from "../types/CteCapabilities"
26✔
5
import { OracleQueryRunner } from "./OracleQueryRunner"
26✔
6
import { ObjectLiteral } from "../../common/ObjectLiteral"
26✔
7
import { ColumnMetadata } from "../../metadata/ColumnMetadata"
26✔
8
import { DateUtils } from "../../util/DateUtils"
26✔
9
import { PlatformTools } from "../../platform/PlatformTools"
26✔
10
import { DataSource } from "../../data-source/DataSource"
26✔
11
import { RdbmsSchemaBuilder } from "../../schema-builder/RdbmsSchemaBuilder"
26✔
12
import { OracleConnectionOptions } from "./OracleConnectionOptions"
26✔
13
import { MappedColumnTypes } from "../types/MappedColumnTypes"
26✔
14
import { ColumnType } from "../types/ColumnTypes"
26✔
15
import { DataTypeDefaults } from "../types/DataTypeDefaults"
26✔
16
import { TableColumn } from "../../schema-builder/table/TableColumn"
26✔
17
import { OracleConnectionCredentialsOptions } from "./OracleConnectionCredentialsOptions"
26✔
18
import { DriverUtils } from "../DriverUtils"
26✔
19
import { EntityMetadata } from "../../metadata/EntityMetadata"
26✔
20
import { OrmUtils } from "../../util/OrmUtils"
26✔
21
import { ApplyValueTransformers } from "../../util/ApplyValueTransformers"
26✔
22
import { ReplicationMode } from "../types/ReplicationMode"
26✔
23
import { Table } from "../../schema-builder/table/Table"
26✔
24
import { View } from "../../schema-builder/view/View"
26✔
25
import { TableForeignKey } from "../../schema-builder/table/TableForeignKey"
26✔
26
import { TypeORMError } from "../../error"
26✔
27
import { InstanceChecker } from "../../util/InstanceChecker"
26✔
28
import { UpsertType } from "../types/UpsertType"
26✔
29
import { OnDeleteType } from "../../metadata/types/OnDeleteType"
26✔
30
import { OnUpdateType } from "../../metadata/types/OnUpdateType"
26✔
31

26✔
32
/**
26✔
33
 * Organizes communication with Oracle RDBMS.
26✔
34
 */
26✔
35
export class OracleDriver implements Driver {
26✔
36
    // -------------------------------------------------------------------------
26✔
37
    // Public Properties
26✔
38
    // -------------------------------------------------------------------------
26✔
39

26✔
40
    /**
26✔
41
     * Connection used by driver.
26✔
42
     */
26✔
43
    connection: DataSource
26✔
44

26✔
45
    /**
26✔
46
     * Underlying oracle library.
26✔
47
     */
26✔
48
    oracle: any
26✔
49

26✔
50
    /**
26✔
51
     * Pool for master database.
26✔
52
     */
26✔
53
    master: any
26✔
54

26✔
55
    /**
26✔
56
     * Pool for slave databases.
26✔
57
     * Used in replication.
26✔
58
     */
26✔
59
    slaves: any[] = []
26✔
60

26✔
61
    // -------------------------------------------------------------------------
26✔
62
    // Public Implemented Properties
26✔
63
    // -------------------------------------------------------------------------
26✔
64

26✔
65
    /**
26✔
66
     * Connection options.
26✔
67
     */
26✔
68
    options: OracleConnectionOptions
26✔
69

26✔
70
    /**
26✔
71
     * Database name used to perform all write queries.
26✔
72
     */
26✔
73
    database?: string
26✔
74

26✔
75
    /**
26✔
76
     * Schema name used to perform all write queries.
26✔
77
     */
26✔
78
    schema?: string
26✔
79

26✔
80
    /**
26✔
81
     * Indicates if replication is enabled.
26✔
82
     */
26✔
83
    isReplicated: boolean = false
26✔
84

26✔
85
    /**
26✔
86
     * Indicates if tree tables are supported by this driver.
26✔
87
     */
26✔
88
    treeSupport = true
26✔
89

26✔
90
    /**
26✔
91
     * Represent transaction support by this driver
26✔
92
     */
26✔
93
    transactionSupport = "nested" as const
26✔
94

26✔
95
    /**
26✔
96
     * Gets list of supported column data types by a driver.
26✔
97
     *
26✔
98
     * @see https://www.techonthenet.com/oracle/datatypes.php
26✔
99
     * @see https://docs.oracle.com/cd/B28359_01/server.111/b28318/datatype.htm#CNCPT012
26✔
100
     */
26✔
101
    supportedDataTypes: ColumnType[] = [
26✔
102
        "char",
26✔
103
        "nchar",
26✔
104
        "nvarchar2",
26✔
105
        "varchar2",
26✔
106
        "long",
26✔
107
        "raw",
26✔
108
        "long raw",
26✔
109
        "number",
26✔
110
        "numeric",
26✔
111
        "float",
26✔
112
        "dec",
26✔
113
        "decimal",
26✔
114
        "integer",
26✔
115
        "int",
26✔
116
        "smallint",
26✔
117
        "real",
26✔
118
        "double precision",
26✔
119
        "date",
26✔
120
        "timestamp",
26✔
121
        "timestamp with time zone",
26✔
122
        "timestamp with local time zone",
26✔
123
        "interval year to month",
26✔
124
        "interval day to second",
26✔
125
        "bfile",
26✔
126
        "blob",
26✔
127
        "clob",
26✔
128
        "nclob",
26✔
129
        "rowid",
26✔
130
        "urowid",
26✔
131
        "simple-json",
26✔
132
        "json",
26✔
133
    ]
26✔
134

26✔
135
    /**
26✔
136
     * Returns type of upsert supported by driver if any
26✔
137
     */
26✔
138
    supportedUpsertTypes: UpsertType[] = ["merge-into"]
26✔
139

26✔
140
    /**
26✔
141
     * Returns list of supported onDelete types by driver.
26✔
142
     * https://docs.oracle.com/en/database/oracle/oracle-database/21/sqlrf/sql-language-reference.pdf
26✔
143
     * Oracle does not support NO ACTION, but NO ACTION is set by default in EntityMetadata
26✔
144
     */
26✔
145
    supportedOnDeleteTypes: OnDeleteType[] = [
26✔
146
        "CASCADE",
26✔
147
        "SET NULL",
26✔
148
        "NO ACTION",
26✔
149
    ]
26✔
150

26✔
151
    /**
26✔
152
     * Returns list of supported onUpdate types by driver.
26✔
153
     * Oracle does not have onUpdate option, but we allow NO ACTION since it is set by default in EntityMetadata
26✔
154
     */
26✔
155
    supportedOnUpdateTypes: OnUpdateType[] = ["NO ACTION"]
26✔
156

26✔
157
    /**
26✔
158
     * Gets list of spatial column data types.
26✔
159
     */
26✔
160
    spatialTypes: ColumnType[] = []
26✔
161

26✔
162
    /**
26✔
163
     * Gets list of column data types that support length by a driver.
26✔
164
     */
26✔
165
    withLengthColumnTypes: ColumnType[] = [
26✔
166
        "char",
26✔
167
        "nchar",
26✔
168
        "nvarchar2",
26✔
169
        "varchar2",
26✔
170
        "varchar",
26✔
171
        "raw",
26✔
172
    ]
26✔
173

26✔
174
    /**
26✔
175
     * Gets list of column data types that support precision by a driver.
26✔
176
     */
26✔
177
    withPrecisionColumnTypes: ColumnType[] = [
26✔
178
        "number",
26✔
179
        "float",
26✔
180
        "timestamp",
26✔
181
        "timestamp with time zone",
26✔
182
        "timestamp with local time zone",
26✔
183
    ]
26✔
184

26✔
185
    /**
26✔
186
     * Gets list of column data types that support scale by a driver.
26✔
187
     */
26✔
188
    withScaleColumnTypes: ColumnType[] = ["number"]
26✔
189

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

26✔
220
    /**
26✔
221
     * The prefix used for the parameters
26✔
222
     */
26✔
223
    parametersPrefix: string = ":"
26✔
224

26✔
225
    /**
26✔
226
     * Default values of length, precision and scale depends on column data type.
26✔
227
     * Used in the cases when length/precision/scale is not specified by user.
26✔
228
     */
26✔
229
    dataTypeDefaults: DataTypeDefaults = {
26✔
230
        char: { length: 1 },
26✔
231
        nchar: { length: 1 },
26✔
232
        varchar: { length: 255 },
26✔
233
        varchar2: { length: 255 },
26✔
234
        nvarchar2: { length: 255 },
26✔
235
        raw: { length: 2000 },
26✔
236
        float: { precision: 126 },
26✔
237
        timestamp: { precision: 6 },
26✔
238
        "timestamp with time zone": { precision: 6 },
26✔
239
        "timestamp with local time zone": { precision: 6 },
26✔
240
    }
26✔
241

26✔
242
    /**
26✔
243
     * Max length allowed by Oracle for aliases.
26✔
244
     * @see https://docs.oracle.com/database/121/SQLRF/sql_elements008.htm#SQLRF51129
26✔
245
     * > The following list of rules applies to both quoted and nonquoted identifiers unless otherwise indicated
26✔
246
     * > Names must be from 1 to 30 bytes long with these exceptions:
26✔
247
     * > [...]
26✔
248
     *
26✔
249
     * Since Oracle 12.2 (with a compatible driver/client), the limit has been set to 128.
26✔
250
     * @see https://docs.oracle.com/en/database/oracle/oracle-database/12.2/sqlrf/Database-Object-Names-and-Qualifiers.html
26✔
251
     *
26✔
252
     * > If COMPATIBLE is set to a value of 12.2 or higher, then names must be from 1 to 128 bytes long with these exceptions
26✔
253
     */
26✔
254
    maxAliasLength = 29
26✔
255

26✔
256
    cteCapabilities: CteCapabilities = {
26✔
257
        enabled: true,
26✔
258
    }
26✔
259

26✔
260
    dummyTableName = "DUAL"
26✔
261

26✔
262
    // -------------------------------------------------------------------------
26✔
263
    // Constructor
26✔
264
    // -------------------------------------------------------------------------
26✔
265

26✔
266
    constructor(connection: DataSource) {
26✔
267
        this.connection = connection
908✔
268
        this.options = connection.options as OracleConnectionOptions
908✔
269

908✔
270
        if (this.options.useUTC === true) {
908!
271
            process.env.ORA_SDTZ = "UTC"
×
272
        }
×
273
        // load oracle package
908✔
274
        this.loadDependencies()
908✔
275

908✔
276
        this.database = DriverUtils.buildDriverOptions(
908✔
277
            this.options.replication
908✔
278
                ? this.options.replication.master
908!
279
                : this.options,
908✔
280
        ).database
908✔
281
        this.schema = DriverUtils.buildDriverOptions(this.options).schema
908✔
282

908✔
283
        // Object.assign(connection.options, DriverUtils.buildDriverOptions(connection.options)); // todo: do it better way
908✔
284
        // validate options to make sure everything is set
908✔
285
        // if (!this.options.host)
908✔
286
        //     throw new DriverOptionNotSetError("host");
908✔
287
        // if (!this.options.username)
908✔
288
        //     throw new DriverOptionNotSetError("username");
908✔
289
        // if (!this.options.sid)
908✔
290
        //     throw new DriverOptionNotSetError("sid");
908✔
291
        //
908✔
292
    }
908✔
293

26✔
294
    // -------------------------------------------------------------------------
26✔
295
    // Public Methods
26✔
296
    // -------------------------------------------------------------------------
26✔
297

26✔
298
    /**
26✔
299
     * Performs connection to the database.
26✔
300
     * Based on pooling options, it can either create connection immediately,
26✔
301
     * either create a pool and create connection when needed.
26✔
302
     */
26✔
303
    async connect(): Promise<void> {
26✔
304
        this.oracle.fetchAsString = [this.oracle.DB_TYPE_CLOB]
908✔
305
        this.oracle.fetchAsBuffer = [this.oracle.DB_TYPE_BLOB]
908✔
306
        if (this.options.replication) {
908!
307
            this.slaves = await Promise.all(
×
308
                this.options.replication.slaves.map((slave) => {
×
309
                    return this.createPool(this.options, slave)
×
310
                }),
×
311
            )
×
312
            this.master = await this.createPool(
×
313
                this.options,
×
314
                this.options.replication.master,
×
315
            )
×
316
        } else {
908✔
317
            this.master = await this.createPool(this.options, this.options)
908✔
318
        }
908✔
319

908✔
320
        if (!this.database || !this.schema) {
908!
321
            const queryRunner = this.createQueryRunner("master")
908✔
322

908✔
323
            if (!this.database) {
908✔
324
                this.database = await queryRunner.getCurrentDatabase()
908✔
325
            }
908✔
326

908✔
327
            if (!this.schema) {
908✔
328
                this.schema = await queryRunner.getCurrentSchema()
908✔
329
            }
908✔
330

908✔
331
            await queryRunner.release()
908✔
332
        }
908✔
333
    }
908✔
334

26✔
335
    /**
26✔
336
     * Makes any action after connection (e.g. create extensions in Postgres driver).
26✔
337
     */
26✔
338
    afterConnect(): Promise<void> {
26✔
339
        return Promise.resolve()
902✔
340
    }
902✔
341

26✔
342
    /**
26✔
343
     * Closes connection with the database.
26✔
344
     */
26✔
345
    async disconnect(): Promise<void> {
26✔
346
        if (!this.master) {
908!
347
            throw new ConnectionIsNotSetError("oracle")
×
348
        }
×
349

908✔
350
        await this.closePool(this.master)
908✔
351
        await Promise.all(this.slaves.map((slave) => this.closePool(slave)))
908✔
352
        this.master = undefined
908✔
353
        this.slaves = []
908✔
354
    }
908✔
355

26✔
356
    /**
26✔
357
     * Creates a schema builder used to build and sync a schema.
26✔
358
     */
26✔
359
    createSchemaBuilder() {
26✔
360
        return new RdbmsSchemaBuilder(this.connection)
2,730✔
361
    }
2,730✔
362

26✔
363
    /**
26✔
364
     * Creates a query runner used to execute database queries.
26✔
365
     */
26✔
366
    createQueryRunner(mode: ReplicationMode) {
26✔
367
        return new OracleQueryRunner(this, mode)
23,188✔
368
    }
23,188✔
369

26✔
370
    /**
26✔
371
     * Replaces parameters in the given sql with special escaping character
26✔
372
     * and an array of parameter names to be passed to a query.
26✔
373
     */
26✔
374
    escapeQueryWithParameters(
26✔
375
        sql: string,
34,030✔
376
        parameters: ObjectLiteral,
34,030✔
377
        nativeParameters: ObjectLiteral,
34,030✔
378
    ): [string, any[]] {
34,030✔
379
        const escapedParameters: any[] = Object.keys(nativeParameters).map(
34,030✔
380
            (key) => {
34,030✔
381
                if (typeof nativeParameters[key] === "boolean")
×
382
                    return nativeParameters[key] ? 1 : 0
×
383
                return nativeParameters[key]
×
384
            },
34,030✔
385
        )
34,030✔
386
        if (!parameters || !Object.keys(parameters).length)
34,030✔
387
            return [sql, escapedParameters]
34,030✔
388

32,758✔
389
        sql = sql.replace(
32,758✔
390
            /:(\.\.\.)?([A-Za-z0-9_.]+)/g,
32,758✔
391
            (full, isArray: string, key: string): string => {
32,758✔
392
                if (!parameters.hasOwnProperty(key)) {
74,880!
393
                    return full
×
394
                }
×
395

74,880✔
396
                const value: any = parameters[key]
74,880✔
397

74,880✔
398
                if (isArray) {
74,880✔
399
                    return value
216✔
400
                        .map((v: any) => {
216✔
401
                            escapedParameters.push(v)
310✔
402
                            return this.createParameter(
310✔
403
                                key,
310✔
404
                                escapedParameters.length - 1,
310✔
405
                            )
310✔
406
                        })
216✔
407
                        .join(", ")
216✔
408
                }
216✔
409

74,664✔
410
                if (typeof value === "function") {
74,880!
411
                    return value()
×
412
                }
×
413

74,664✔
414
                if (typeof value === "boolean") {
74,880✔
415
                    return value ? "1" : "0"
304✔
416
                }
304✔
417

74,360✔
418
                escapedParameters.push(value)
74,360✔
419

74,360✔
420
                return this.createParameter(key, escapedParameters.length - 1)
74,360✔
421
            },
32,758✔
422
        ) // todo: make replace only in value statements, otherwise problems
32,758✔
423
        return [sql, escapedParameters]
32,758✔
424
    }
32,758✔
425

26✔
426
    /**
26✔
427
     * Escapes a column name.
26✔
428
     */
26✔
429
    escape(columnName: string): string {
26✔
430
        return `"${columnName}"`
303,468✔
431
    }
303,468✔
432

26✔
433
    /**
26✔
434
     * Build full table name with database name, schema name and table name.
26✔
435
     * Oracle does not support table schemas. One user can have only one schema.
26✔
436
     */
26✔
437
    buildTableName(
26✔
438
        tableName: string,
608,184✔
439
        schema?: string,
608,184✔
440
        database?: string,
608,184✔
441
    ): string {
608,184✔
442
        const tablePath = [tableName]
608,184✔
443

608,184✔
444
        if (schema) {
608,184✔
445
            tablePath.unshift(schema)
592,894✔
446
        }
592,894✔
447

608,184✔
448
        return tablePath.join(".")
608,184✔
449
    }
608,184✔
450

26✔
451
    /**
26✔
452
     * Parse a target table name or other types and return a normalized table definition.
26✔
453
     */
26✔
454
    parseTableName(
26✔
455
        target: EntityMetadata | Table | View | TableForeignKey | string,
959,286✔
456
    ): { database?: string; schema?: string; tableName: string } {
959,286✔
457
        const driverDatabase = this.database
959,286✔
458
        const driverSchema = this.schema
959,286✔
459

959,286✔
460
        if (InstanceChecker.isTable(target) || InstanceChecker.isView(target)) {
959,286✔
461
            const parsed = this.parseTableName(target.name)
318,166✔
462

318,166✔
463
            return {
318,166✔
464
                database: target.database || parsed.database || driverDatabase,
318,166!
465
                schema: target.schema || parsed.schema || driverSchema,
318,166!
466
                tableName: parsed.tableName,
318,166✔
467
            }
318,166✔
468
        }
318,166✔
469

641,120✔
470
        if (InstanceChecker.isTableForeignKey(target)) {
959,286✔
471
            const parsed = this.parseTableName(target.referencedTableName)
6,156✔
472

6,156✔
473
            return {
6,156✔
474
                database:
6,156✔
475
                    target.referencedDatabase ||
6,156✔
476
                    parsed.database ||
6,156!
477
                    driverDatabase,
6,156✔
478
                schema:
6,156✔
479
                    target.referencedSchema || parsed.schema || driverSchema,
6,156!
480
                tableName: parsed.tableName,
6,156✔
481
            }
6,156✔
482
        }
6,156✔
483

634,964✔
484
        if (InstanceChecker.isEntityMetadata(target)) {
959,286✔
485
            // EntityMetadata tableName is never a path
301,992✔
486

301,992✔
487
            return {
301,992✔
488
                database: target.database || driverDatabase,
301,992✔
489
                schema: target.schema || driverSchema,
301,992✔
490
                tableName: target.tableName,
301,992✔
491
            }
301,992✔
492
        }
301,992✔
493

332,972✔
494
        const parts = target.split(".")
332,972✔
495

332,972✔
496
        if (parts.length === 3) {
959,286!
497
            return {
×
498
                database: parts[0] || driverDatabase,
×
499
                schema: parts[1] || driverSchema,
×
500
                tableName: parts[2],
×
501
            }
×
502
        } else if (parts.length === 2) {
959,286✔
503
            return {
6,086✔
504
                database: driverDatabase,
6,086✔
505
                schema: parts[0] || driverSchema,
6,086!
506
                tableName: parts[1],
6,086✔
507
            }
6,086✔
508
        } else {
332,972✔
509
            return {
326,886✔
510
                database: driverDatabase,
326,886✔
511
                schema: driverSchema,
326,886✔
512
                tableName: target,
326,886✔
513
            }
326,886✔
514
        }
326,886✔
515
    }
959,286✔
516

26✔
517
    /**
26✔
518
     * Prepares given value to a value to be persisted, based on its column type and metadata.
26✔
519
     */
26✔
520
    preparePersistentValue(value: any, columnMetadata: ColumnMetadata): any {
26✔
521
        if (columnMetadata.transformer)
59,810✔
522
            value = ApplyValueTransformers.transformTo(
59,810✔
523
                columnMetadata.transformer,
80✔
524
                value,
80✔
525
            )
80✔
526

59,810✔
527
        if (value === null || value === undefined) return value
59,810✔
528

48,818✔
529
        if (columnMetadata.type === Boolean) {
59,810✔
530
            return value ? 1 : 0
4,018✔
531
        } else if (columnMetadata.type === "date") {
59,810✔
532
            if (typeof value === "string") value = value.replace(/[^0-9-]/g, "")
10✔
533
            return () =>
10✔
534
                `TO_DATE('${DateUtils.mixedDateToDateString(value, {
10✔
535
                    utc: columnMetadata.utc,
10✔
536
                })}', 'YYYY-MM-DD')`
10✔
537
        } else if (
44,800✔
538
            columnMetadata.type === Date ||
44,790✔
539
            columnMetadata.type === "timestamp" ||
44,790✔
540
            columnMetadata.type === "timestamp with time zone" ||
44,790✔
541
            columnMetadata.type === "timestamp with local time zone"
44,724✔
542
        ) {
44,790✔
543
            return DateUtils.mixedDateToDate(value)
70✔
544
        } else if (columnMetadata.type === "simple-array") {
44,790✔
545
            return DateUtils.simpleArrayToString(value)
2✔
546
        } else if (columnMetadata.type === "simple-json") {
44,720✔
547
            return DateUtils.simpleJsonToString(value)
10✔
548
        } else if (columnMetadata.type === "json") {
44,718✔
549
            return DateUtils.simpleJsonToString(value)
2✔
550
        }
2✔
551

44,706✔
552
        return value
44,706✔
553
    }
44,706✔
554

26✔
555
    /**
26✔
556
     * Prepares given value to a value to be persisted, based on its column type or metadata.
26✔
557
     */
26✔
558
    prepareHydratedValue(value: any, columnMetadata: ColumnMetadata): any {
26✔
559
        if (value === null || value === undefined)
49,394✔
560
            return columnMetadata.transformer
49,394✔
561
                ? ApplyValueTransformers.transformFrom(
2,646✔
562
                      columnMetadata.transformer,
24✔
563
                      value,
24✔
564
                  )
2,646✔
565
                : value
2,646✔
566

46,748✔
567
        if (columnMetadata.type === Boolean) {
49,394✔
568
            value = !!value
1,424✔
569
        } else if (columnMetadata.type === "date") {
49,394✔
570
            value = DateUtils.mixedDateToDateString(value, {
10✔
571
                utc: columnMetadata.utc,
10✔
572
            })
10✔
573
        } else if (columnMetadata.type === "time") {
45,324!
574
            value = DateUtils.mixedTimeToString(value)
×
575
        } else if (
45,314✔
576
            columnMetadata.type === Date ||
45,314✔
577
            columnMetadata.type === "timestamp" ||
45,314✔
578
            columnMetadata.type === "timestamp with time zone" ||
45,314✔
579
            columnMetadata.type === "timestamp with local time zone"
44,428✔
580
        ) {
45,314✔
581
            value = DateUtils.normalizeHydratedDate(value)
890✔
582
        } else if (columnMetadata.type === "simple-array") {
45,314✔
583
            value = DateUtils.stringToSimpleArray(value)
2✔
584
        } else if (columnMetadata.type === "simple-json") {
44,424✔
585
            value = DateUtils.stringToSimpleJson(value)
10✔
586
        } else if (columnMetadata.type === Number) {
44,422✔
587
            // convert to number if number
32,376✔
588
            value = !isNaN(+value) ? parseInt(value) : value
32,376!
589
        }
32,376✔
590

46,748✔
591
        if (columnMetadata.transformer)
46,748✔
592
            value = ApplyValueTransformers.transformFrom(
49,394✔
593
                columnMetadata.transformer,
138✔
594
                value,
138✔
595
            )
138✔
596

46,748✔
597
        return value
46,748✔
598
    }
46,748✔
599

26✔
600
    /**
26✔
601
     * Creates a database type from a given column metadata.
26✔
602
     */
26✔
603
    normalizeType(column: {
26✔
604
        type?: ColumnType
74,362✔
605
        length?: number | string
74,362✔
606
        precision?: number | null
74,362✔
607
        scale?: number
74,362✔
608
        isArray?: boolean
74,362✔
609
    }): string {
74,362✔
610
        if (
74,362✔
611
            column.type === Number ||
74,362✔
612
            column.type === Boolean ||
74,362✔
613
            column.type === "numeric" ||
74,362✔
614
            column.type === "dec" ||
74,362✔
615
            column.type === "decimal" ||
74,362✔
616
            column.type === "int" ||
74,362✔
617
            column.type === "integer" ||
74,362✔
618
            column.type === "smallint"
32,090✔
619
        ) {
74,362✔
620
            return "number"
42,286✔
621
        } else if (
74,362✔
622
            column.type === "real" ||
32,076✔
623
            column.type === "double precision"
32,062✔
624
        ) {
32,076✔
625
            return "float"
28✔
626
        } else if (column.type === String || column.type === "varchar") {
32,076✔
627
            return "varchar2"
26,184✔
628
        } else if (column.type === Date) {
32,048✔
629
            return "timestamp"
410✔
630
        } else if ((column.type as any) === Buffer) {
5,864✔
631
            return "blob"
14✔
632
        } else if (column.type === "uuid") {
5,454✔
633
            return "varchar2"
1,214✔
634
        } else if (column.type === "simple-array") {
5,440✔
635
            return "clob"
14✔
636
        } else if (column.type === "simple-json") {
4,226✔
637
            return "clob"
50✔
638
        } else if (column.type === "json") {
4,212✔
639
            return "json"
14✔
640
        } else {
4,162✔
641
            return (column.type as string) || ""
4,148!
642
        }
4,148✔
643
    }
74,362✔
644

26✔
645
    /**
26✔
646
     * Normalizes "default" value of the column.
26✔
647
     */
26✔
648
    normalizeDefault(columnMetadata: ColumnMetadata): string | undefined {
26✔
649
        const defaultValue = columnMetadata.default
56,614✔
650

56,614✔
651
        if (typeof defaultValue === "number") {
56,614✔
652
            return "" + defaultValue
544✔
653
        }
544✔
654

56,070✔
655
        if (typeof defaultValue === "boolean") {
56,614✔
656
            return defaultValue ? "1" : "0"
36✔
657
        }
36✔
658

56,034✔
659
        if (typeof defaultValue === "function") {
56,614✔
660
            return defaultValue()
1,646✔
661
        }
1,646✔
662

54,388✔
663
        if (typeof defaultValue === "string") {
56,614✔
664
            return `'${defaultValue}'`
752✔
665
        }
752✔
666

53,636✔
667
        if (defaultValue === null || defaultValue === undefined) {
56,614✔
668
            return undefined
53,636✔
669
        }
53,636✔
670

×
671
        return `${defaultValue}`
×
672
    }
×
673

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

26✔
683
    /**
26✔
684
     * Calculates column length taking into account the default length values.
26✔
685
     */
26✔
686
    getColumnLength(column: ColumnMetadata | TableColumn): string {
26✔
687
        if (column.length) return column.length.toString()
98,010✔
688

73,634✔
689
        switch (column.type) {
73,634✔
690
            case String:
98,010✔
691
            case "varchar":
98,010✔
692
            case "varchar2":
98,010✔
693
            case "nvarchar2":
98,010✔
694
                return "255"
22,422✔
695
            case "raw":
98,010✔
696
                return "2000"
14✔
697
            case "uuid":
98,010✔
698
                return "36"
932✔
699
            default:
98,010✔
700
                return ""
50,266✔
701
        }
98,010✔
702
    }
98,010✔
703

26✔
704
    createFullType(column: TableColumn): string {
26✔
705
        let type = column.type
28,346✔
706

28,346✔
707
        // used 'getColumnLength()' method, because in Oracle column length is required for some data types.
28,346✔
708
        if (this.getColumnLength(column)) {
28,346✔
709
            type += `(${this.getColumnLength(column)})`
11,578✔
710
        } else if (
28,346✔
711
            column.precision !== null &&
16,768✔
712
            column.precision !== undefined &&
16,768✔
713
            column.scale !== null &&
16,768✔
714
            column.scale !== undefined
52✔
715
        ) {
16,768✔
716
            type += "(" + column.precision + "," + column.scale + ")"
28✔
717
        } else if (
16,768✔
718
            column.precision !== null &&
16,740✔
719
            column.precision !== undefined
16,740✔
720
        ) {
16,740✔
721
            type += "(" + column.precision + ")"
24✔
722
        }
24✔
723

28,346✔
724
        if (column.type === "timestamp with time zone") {
28,346✔
725
            type =
16✔
726
                "TIMESTAMP" +
16✔
727
                (column.precision !== null && column.precision !== undefined
16✔
728
                    ? "(" + column.precision + ")"
16✔
729
                    : "") +
16✔
730
                " WITH TIME ZONE"
16✔
731
        } else if (column.type === "timestamp with local time zone") {
28,346✔
732
            type =
12✔
733
                "TIMESTAMP" +
12✔
734
                (column.precision !== null && column.precision !== undefined
12✔
735
                    ? "(" + column.precision + ")"
12✔
736
                    : "") +
12✔
737
                " WITH LOCAL TIME ZONE"
12✔
738
        }
12✔
739

28,346✔
740
        if (column.isArray) type += " array"
28,346!
741

28,346✔
742
        return type
28,346✔
743
    }
28,346✔
744

26✔
745
    /**
26✔
746
     * Obtains a new database connection to a master server.
26✔
747
     * Used for replication.
26✔
748
     * If replication is not setup then returns default connection's database connection.
26✔
749
     */
26✔
750
    obtainMasterConnection(): Promise<any> {
26✔
751
        return new Promise<any>((ok, fail) => {
22,252✔
752
            if (!this.master) {
22,252!
753
                return fail(new TypeORMError("Driver not Connected"))
×
754
            }
×
755

22,252✔
756
            this.master.getConnection(
22,252✔
757
                (err: any, connection: any, release: Function) => {
22,252✔
758
                    if (err) return fail(err)
22,252!
759
                    ok(connection)
22,252✔
760
                },
22,252✔
761
            )
22,252✔
762
        })
22,252✔
763
    }
22,252✔
764

26✔
765
    /**
26✔
766
     * Obtains a new database connection to a slave server.
26✔
767
     * Used for replication.
26✔
768
     * If replication is not setup then returns master (default) connection's database connection.
26✔
769
     */
26✔
770
    obtainSlaveConnection(): Promise<any> {
26✔
771
        if (!this.slaves.length) return this.obtainMasterConnection()
×
772

×
773
        return new Promise<any>((ok, fail) => {
×
774
            const random = Math.floor(Math.random() * this.slaves.length)
×
775

×
776
            this.slaves[random].getConnection((err: any, connection: any) => {
×
777
                if (err) return fail(err)
×
778
                ok(connection)
×
779
            })
×
780
        })
×
781
    }
×
782

26✔
783
    /**
26✔
784
     * Creates generated map of values generated or returned by database after INSERT query.
26✔
785
     */
26✔
786
    createGeneratedMap(metadata: EntityMetadata, insertResult: ObjectLiteral) {
26✔
787
        if (!insertResult) return undefined
18,998✔
788

18,830✔
789
        return Object.keys(insertResult).reduce((map, key) => {
18,830✔
790
            const column = metadata.findColumnWithDatabaseName(key)
8,448✔
791
            if (column) {
8,448✔
792
                OrmUtils.mergeDeep(
8,448✔
793
                    map,
8,448✔
794
                    column.createValueMap(
8,448✔
795
                        this.prepareHydratedValue(insertResult[key], column),
8,448✔
796
                    ),
8,448✔
797
                )
8,448✔
798
            }
8,448✔
799
            return map
8,448✔
800
        }, {} as ObjectLiteral)
18,830✔
801
    }
18,830✔
802

26✔
803
    /**
26✔
804
     * Differentiate columns of this table and columns from the given column metadatas columns
26✔
805
     * and returns only changed.
26✔
806
     */
26✔
807
    findChangedColumns(
26✔
808
        tableColumns: TableColumn[],
9,238✔
809
        columnMetadatas: ColumnMetadata[],
9,238✔
810
    ): ColumnMetadata[] {
9,238✔
811
        return columnMetadatas.filter((columnMetadata) => {
9,238✔
812
            const tableColumn = tableColumns.find(
28,996✔
813
                (c) => c.name === columnMetadata.databaseName,
28,996✔
814
            )
28,996✔
815
            if (!tableColumn) return false // we don't need new columns, we only need exist and changed
28,996✔
816

28,988✔
817
            const isColumnChanged =
28,988✔
818
                tableColumn.name !== columnMetadata.databaseName ||
28,988✔
819
                tableColumn.type !== this.normalizeType(columnMetadata) ||
28,996✔
820
                tableColumn.length !== this.getColumnLength(columnMetadata) ||
28,996✔
821
                tableColumn.precision !== columnMetadata.precision ||
28,996✔
822
                tableColumn.scale !== columnMetadata.scale ||
28,996✔
823
                // || tableColumn.comment !== columnMetadata.comment
28,970✔
824
                tableColumn.default !== this.normalizeDefault(columnMetadata) ||
28,996✔
825
                tableColumn.isPrimary !== columnMetadata.isPrimary ||
28,996✔
826
                tableColumn.isNullable !== columnMetadata.isNullable ||
28,996✔
827
                tableColumn.asExpression !== columnMetadata.asExpression ||
28,996✔
828
                tableColumn.generatedType !== columnMetadata.generatedType ||
28,996✔
829
                tableColumn.isUnique !==
28,968✔
830
                    this.normalizeIsUnique(columnMetadata) ||
28,996✔
831
                (columnMetadata.generationStrategy !== "uuid" &&
28,966✔
832
                    tableColumn.isGenerated !== columnMetadata.isGenerated)
28,966✔
833

28,996✔
834
            // DEBUG SECTION
28,996✔
835
            // if (isColumnChanged) {
28,996✔
836
            //     console.log("table:", columnMetadata.entityMetadata.tableName)
28,996✔
837
            //     console.log(
28,996✔
838
            //         "name:",
28,996✔
839
            //         tableColumn.name,
28,996✔
840
            //         columnMetadata.databaseName,
28,996✔
841
            //     )
28,996✔
842
            //     console.log(
28,996✔
843
            //         "type:",
28,996✔
844
            //         tableColumn.type,
28,996✔
845
            //         this.normalizeType(columnMetadata),
28,996✔
846
            //     )
28,996✔
847
            //     console.log(
28,996✔
848
            //         "length:",
28,996✔
849
            //         tableColumn.length,
28,996✔
850
            //         columnMetadata.length,
28,996✔
851
            //     )
28,996✔
852
            //     console.log(
28,996✔
853
            //         "precision:",
28,996✔
854
            //         tableColumn.precision,
28,996✔
855
            //         columnMetadata.precision,
28,996✔
856
            //     )
28,996✔
857
            //     console.log("scale:", tableColumn.scale, columnMetadata.scale)
28,996✔
858
            //     console.log(
28,996✔
859
            //         "comment:",
28,996✔
860
            //         tableColumn.comment,
28,996✔
861
            //         columnMetadata.comment,
28,996✔
862
            //     )
28,996✔
863
            //     console.log(
28,996✔
864
            //         "default:",
28,996✔
865
            //         tableColumn.default,
28,996✔
866
            //         this.normalizeDefault(columnMetadata),
28,996✔
867
            //     )
28,996✔
868
            //     console.log(
28,996✔
869
            //         "enum:",
28,996✔
870
            //         tableColumn.enum &&
28,996✔
871
            //             columnMetadata.enum &&
28,996✔
872
            //             !OrmUtils.isArraysEqual(
28,996✔
873
            //                 tableColumn.enum,
28,996✔
874
            //                 columnMetadata.enum.map((val) => val + ""),
28,996✔
875
            //             ),
28,996✔
876
            //     )
28,996✔
877
            //     console.log(
28,996✔
878
            //         "onUpdate:",
28,996✔
879
            //         tableColumn.onUpdate,
28,996✔
880
            //         columnMetadata.onUpdate,
28,996✔
881
            //     )
28,996✔
882
            //     console.log(
28,996✔
883
            //         "isPrimary:",
28,996✔
884
            //         tableColumn.isPrimary,
28,996✔
885
            //         columnMetadata.isPrimary,
28,996✔
886
            //     )
28,996✔
887
            //     console.log(
28,996✔
888
            //         "isNullable:",
28,996✔
889
            //         tableColumn.isNullable,
28,996✔
890
            //         columnMetadata.isNullable,
28,996✔
891
            //     )
28,996✔
892
            //     console.log(
28,996✔
893
            //         "asExpression:",
28,996✔
894
            //         tableColumn.asExpression,
28,996✔
895
            //         columnMetadata.asExpression,
28,996✔
896
            //     )
28,996✔
897
            //     console.log(
28,996✔
898
            //         "generatedType:",
28,996✔
899
            //         tableColumn.generatedType,
28,996✔
900
            //         columnMetadata.generatedType,
28,996✔
901
            //     )
28,996✔
902
            //     console.log(
28,996✔
903
            //         "isUnique:",
28,996✔
904
            //         tableColumn.isUnique,
28,996✔
905
            //         this.normalizeIsUnique(columnMetadata),
28,996✔
906
            //     )
28,996✔
907
            //     console.log(
28,996✔
908
            //         "isGenerated:",
28,996✔
909
            //         tableColumn.isGenerated,
28,996✔
910
            //         columnMetadata.isGenerated,
28,996✔
911
            //     )
28,996✔
912
            //     console.log("==========================================")
28,996✔
913
            // }
28,996✔
914

28,996✔
915
            return isColumnChanged
28,996✔
916
        })
9,238✔
917
    }
9,238✔
918

26✔
919
    /**
26✔
920
     * Returns true if driver supports RETURNING / OUTPUT statement.
26✔
921
     */
26✔
922
    isReturningSqlSupported(): boolean {
26✔
923
        return true
45,530✔
924
    }
45,530✔
925

26✔
926
    /**
26✔
927
     * Returns true if driver supports uuid values generation on its own.
26✔
928
     */
26✔
929
    isUUIDGenerationSupported(): boolean {
26✔
930
        return false
204✔
931
    }
204✔
932

26✔
933
    /**
26✔
934
     * Returns true if driver supports fulltext indices.
26✔
935
     */
26✔
936
    isFullTextColumnTypeSupported(): boolean {
26✔
937
        return false
56✔
938
    }
56✔
939

26✔
940
    /**
26✔
941
     * Creates an escaped parameter.
26✔
942
     */
26✔
943
    createParameter(parameterName: string, index: number): string {
26✔
944
        return this.parametersPrefix + (index + 1)
75,004✔
945
    }
75,004✔
946

26✔
947
    /**
26✔
948
     * Converts column type in to native oracle type.
26✔
949
     */
26✔
950
    columnTypeToNativeParameter(type: ColumnType): any {
26✔
951
        switch (this.normalizeType({ type: type as any })) {
8,452✔
952
            case "number":
8,452✔
953
            case "numeric":
8,452✔
954
            case "int":
8,452✔
955
            case "integer":
8,452✔
956
            case "smallint":
8,452✔
957
            case "dec":
8,452✔
958
            case "decimal":
8,452✔
959
                return this.oracle.DB_TYPE_NUMBER
7,416✔
960
            case "char":
8,452!
961
            case "nchar":
8,452!
962
            case "nvarchar2":
8,452!
963
            case "varchar2":
8,452✔
964
                return this.oracle.DB_TYPE_VARCHAR
560✔
965
            case "blob":
8,452!
966
                return this.oracle.DB_TYPE_BLOB
×
967
            case "simple-json":
8,452!
968
            case "clob":
8,452!
969
                return this.oracle.DB_TYPE_CLOB
×
970
            case "date":
8,452!
971
            case "timestamp":
8,452✔
972
            case "timestamp with time zone":
8,452✔
973
            case "timestamp with local time zone":
8,452✔
974
                return this.oracle.DB_TYPE_TIMESTAMP
476✔
975
            case "json":
8,452!
976
                return this.oracle.DB_TYPE_JSON
×
977
        }
8,452✔
978
    }
8,452✔
979

26✔
980
    // -------------------------------------------------------------------------
26✔
981
    // Protected Methods
26✔
982
    // -------------------------------------------------------------------------
26✔
983

26✔
984
    /**
26✔
985
     * Loads all driver dependencies.
26✔
986
     */
26✔
987
    protected loadDependencies(): void {
26✔
988
        try {
908✔
989
            const oracle = this.options.driver || PlatformTools.load("oracledb")
908✔
990
            this.oracle = oracle
908✔
991
        } catch {
908!
992
            throw new DriverPackageNotInstalledError("Oracle", "oracledb")
×
993
        }
×
994
        const thickMode = this.options.thickMode
908✔
995
        if (thickMode) {
908!
NEW
996
            if (typeof thickMode === "object") {
×
NEW
997
                this.oracle.initOracleClient(thickMode)
×
NEW
998
            } else {
×
NEW
999
                this.oracle.initOracleClient()
×
NEW
1000
            }
×
UNCOV
1001
        }
×
1002
    }
908✔
1003

26✔
1004
    /**
26✔
1005
     * Creates a new connection pool for a given database credentials.
26✔
1006
     */
26✔
1007
    protected async createPool(
26✔
1008
        options: OracleConnectionOptions,
908✔
1009
        credentials: OracleConnectionCredentialsOptions,
908✔
1010
    ): Promise<any> {
908✔
1011
        credentials = Object.assign(
908✔
1012
            {},
908✔
1013
            credentials,
908✔
1014
            DriverUtils.buildDriverOptions(credentials),
908✔
1015
        ) // todo: do it better way
908✔
1016

908✔
1017
        if (!credentials.connectString) {
908✔
1018
            let address = `(PROTOCOL=TCP)`
908✔
1019

908✔
1020
            if (credentials.host) {
908✔
1021
                address += `(HOST=${credentials.host})`
908✔
1022
            }
908✔
1023

908✔
1024
            if (credentials.port) {
908✔
1025
                address += `(PORT=${credentials.port})`
908✔
1026
            }
908✔
1027

908✔
1028
            let connectData = `(SERVER=DEDICATED)`
908✔
1029

908✔
1030
            if (credentials.sid) {
908!
1031
                connectData += `(SID=${credentials.sid})`
×
1032
            }
×
1033

908✔
1034
            if (credentials.serviceName) {
908✔
1035
                connectData += `(SERVICE_NAME=${credentials.serviceName})`
908✔
1036
            }
908✔
1037

908✔
1038
            const connectString = `(DESCRIPTION=(ADDRESS=${address})(CONNECT_DATA=${connectData}))`
908✔
1039
            Object.assign(credentials, { connectString })
908✔
1040
        }
908✔
1041

908✔
1042
        // build connection options for the driver
908✔
1043
        const connectionOptions = Object.assign(
908✔
1044
            {},
908✔
1045
            {
908✔
1046
                user: credentials.username,
908✔
1047
                password: credentials.password,
908✔
1048
                connectString: credentials.connectString,
908✔
1049
            },
908✔
1050
            {
908✔
1051
                poolMax: options.poolSize,
908✔
1052
            },
908✔
1053
            options.extra || {},
908✔
1054
        )
908✔
1055

908✔
1056
        // pooling is enabled either when its set explicitly to true,
908✔
1057
        // either when its not defined at all (e.g. enabled by default)
908✔
1058
        return new Promise<void>((ok, fail) => {
908✔
1059
            this.oracle.createPool(connectionOptions, (err: any, pool: any) => {
908✔
1060
                if (err) return fail(err)
908!
1061
                ok(pool)
908✔
1062
            })
908✔
1063
        })
908✔
1064
    }
908✔
1065

26✔
1066
    /**
26✔
1067
     * Closes connection pool.
26✔
1068
     */
26✔
1069
    protected async closePool(pool: any): Promise<void> {
26✔
1070
        return new Promise<void>((ok, fail) => {
908✔
1071
            pool.close((err: any) => (err ? fail(err) : ok()))
908!
1072
            pool = undefined
908✔
1073
        })
908✔
1074
    }
908✔
1075
}
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