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

typeorm / typeorm / 14796576772

02 May 2025 01:52PM UTC coverage: 45.367% (-30.9%) from 76.309%
14796576772

Pull #11434

github

web-flow
Merge ec4ce2d00 into fadad1a74
Pull Request #11434: feat: release PR releases using pkg.pr.new

5216 of 12761 branches covered (40.87%)

Branch coverage included in aggregate %.

11439 of 23951 relevant lines covered (47.76%)

15712.55 hits per line

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

54.7
/src/driver/mongodb/MongoDriver.ts
1
import { Driver } from "../Driver"
2
import { ConnectionIsNotSetError } from "../../error/ConnectionIsNotSetError"
4✔
3
import { DriverPackageNotInstalledError } from "../../error/DriverPackageNotInstalledError"
4✔
4
import { CteCapabilities } from "../types/CteCapabilities"
5
import { MongoQueryRunner } from "./MongoQueryRunner"
4✔
6
import { ObjectLiteral } from "../../common/ObjectLiteral"
7
import { ColumnMetadata } from "../../metadata/ColumnMetadata"
8
import { PlatformTools } from "../../platform/PlatformTools"
4✔
9
import { DataSource } from "../../data-source/DataSource"
10
import { MongoConnectionOptions } from "./MongoConnectionOptions"
11
import { MappedColumnTypes } from "../types/MappedColumnTypes"
12
import { ColumnType } from "../types/ColumnTypes"
13
import { MongoSchemaBuilder } from "../../schema-builder/MongoSchemaBuilder"
4✔
14
import { DataTypeDefaults } from "../types/DataTypeDefaults"
15
import { TableColumn } from "../../schema-builder/table/TableColumn"
16
import { DataSourceOptions } from "../../data-source/DataSourceOptions"
17
import { EntityMetadata } from "../../metadata/EntityMetadata"
18
import { ObjectUtils } from "../../util/ObjectUtils"
4✔
19
import { ApplyValueTransformers } from "../../util/ApplyValueTransformers"
4✔
20
import { ReplicationMode } from "../types/ReplicationMode"
21
import { DriverUtils } from "../DriverUtils"
4✔
22
import { TypeORMError } from "../../error"
4✔
23
import { Table } from "../../schema-builder/table/Table"
24
import { View } from "../../schema-builder/view/View"
25
import { TableForeignKey } from "../../schema-builder/table/TableForeignKey"
26
import { InstanceChecker } from "../../util/InstanceChecker"
4✔
27
import { UpsertType } from "../types/UpsertType"
28

29
/**
30
 * Organizes communication with MongoDB.
31
 */
32
export class MongoDriver implements Driver {
4✔
33
    // -------------------------------------------------------------------------
34
    // Public Properties
35
    // -------------------------------------------------------------------------
36

37
    /**
38
     * Underlying mongodb library.
39
     */
40
    mongodb: any
41

42
    /**
43
     * Mongodb does not require to dynamically create query runner each time,
44
     * because it does not have a regular connection pool as RDBMS systems have.
45
     */
46
    queryRunner?: MongoQueryRunner
47

48
    // -------------------------------------------------------------------------
49
    // Public Implemented Properties
50
    // -------------------------------------------------------------------------
51

52
    /**
53
     * Connection options.
54
     */
55
    options: MongoConnectionOptions
56

57
    /**
58
     * Master database used to perform all write queries.
59
     */
60
    database?: string
61

62
    /**
63
     * Indicates if replication is enabled.
64
     */
65
    isReplicated: boolean = false
8✔
66

67
    /**
68
     * Indicates if tree tables are supported by this driver.
69
     */
70
    treeSupport = false
8✔
71

72
    /**
73
     * Represent transaction support by this driver
74
     */
75
    transactionSupport = "none" as const
8✔
76

77
    /**
78
     * Mongodb does not need to have column types because they are not used in schema sync.
79
     */
80
    supportedDataTypes: ColumnType[] = []
8✔
81

82
    /**
83
     * Returns type of upsert supported by driver if any
84
     */
85
    supportedUpsertTypes: UpsertType[]
86

87
    /**
88
     * Gets list of spatial column data types.
89
     */
90
    spatialTypes: ColumnType[] = []
8✔
91

92
    /**
93
     * Gets list of column data types that support length by a driver.
94
     */
95
    withLengthColumnTypes: ColumnType[] = []
8✔
96

97
    /**
98
     * Gets list of column data types that support precision by a driver.
99
     */
100
    withPrecisionColumnTypes: ColumnType[] = []
8✔
101

102
    /**
103
     * Gets list of column data types that support scale by a driver.
104
     */
105
    withScaleColumnTypes: ColumnType[] = []
8✔
106

107
    /**
108
     * Mongodb does not need to have a strong defined mapped column types because they are not used in schema sync.
109
     */
110
    mappedDataTypes: MappedColumnTypes = {
8✔
111
        createDate: "int",
112
        createDateDefault: "",
113
        updateDate: "int",
114
        updateDateDefault: "",
115
        deleteDate: "int",
116
        deleteDateNullable: true,
117
        version: "int",
118
        treeLevel: "int",
119
        migrationId: "int",
120
        migrationName: "int",
121
        migrationTimestamp: "int",
122
        cacheId: "int",
123
        cacheIdentifier: "int",
124
        cacheTime: "int",
125
        cacheDuration: "int",
126
        cacheQuery: "int",
127
        cacheResult: "int",
128
        metadataType: "int",
129
        metadataDatabase: "int",
130
        metadataSchema: "int",
131
        metadataTable: "int",
132
        metadataName: "int",
133
        metadataValue: "int",
134
    }
135

136
    /**
137
     * Default values of length, precision and scale depends on column data type.
138
     * Used in the cases when length/precision/scale is not specified by user.
139
     */
140
    dataTypeDefaults: DataTypeDefaults
141

142
    /**
143
     * No documentation specifying a maximum length for identifiers could be found
144
     * for MongoDB.
145
     */
146
    maxAliasLength?: number
147

148
    cteCapabilities: CteCapabilities = {
8✔
149
        enabled: false,
150
    }
151

152
    // -------------------------------------------------------------------------
153
    // Protected Properties
154
    // -------------------------------------------------------------------------
155

156
    /**
157
     * Valid mongo connection options
158
     * NOTE: Keep in sync with MongoConnectionOptions
159
     */
160
    protected validOptionNames: string[] = [
8✔
161
        "appName",
162
        "authMechanism",
163
        "authSource",
164
        "autoEncryption",
165
        "checkServerIdentity",
166
        "compressors",
167
        "connectTimeoutMS",
168
        "directConnection",
169
        "family",
170
        "forceServerObjectId",
171
        "ignoreUndefined",
172
        "keepAlive",
173
        "keepAliveInitialDelay",
174
        "localThresholdMS",
175
        "maxStalenessSeconds",
176
        "minPoolSize",
177
        "monitorCommands",
178
        "noDelay",
179
        "pkFactory",
180
        "promoteBuffers",
181
        "promoteLongs",
182
        "promoteValues",
183
        "raw",
184
        "readConcern",
185
        "readPreference",
186
        "readPreferenceTags",
187
        "replicaSet",
188
        "retryWrites",
189
        "serializeFunctions",
190
        "socketTimeoutMS",
191
        "ssl",
192
        "sslCA",
193
        "sslCRL",
194
        "sslCert",
195
        "sslKey",
196
        "sslPass",
197
        "sslValidate",
198
        "tls",
199
        "tlsAllowInvalidCertificates",
200
        "tlsCAFile",
201
        "tlsCertificateKeyFile",
202
        "tlsCertificateKeyFilePassword",
203
        "w",
204
        "writeConcern",
205
        "wtimeoutMS",
206
        // Undocumented deprecated options
207
        // todo: remove next major version
208
        "appname",
209
        "fsync",
210
        "j",
211
        "useNewUrlParser",
212
        "useUnifiedTopology",
213
        "wtimeout",
214
    ]
215

216
    // -------------------------------------------------------------------------
217
    // Constructor
218
    // -------------------------------------------------------------------------
219

220
    constructor(protected connection: DataSource) {
8✔
221
        this.options = connection.options as MongoConnectionOptions
8✔
222

223
        // validate options to make sure everything is correct and driver will be able to establish connection
224
        this.validateOptions(connection.options)
8✔
225

226
        // load mongodb package
227
        this.loadDependencies()
8✔
228

229
        this.database = DriverUtils.buildMongoDBDriverOptions(
8✔
230
            this.options,
231
        ).database
232
    }
233

234
    // -------------------------------------------------------------------------
235
    // Public Methods
236
    // -------------------------------------------------------------------------
237

238
    /**
239
     * Performs connection to the database.
240
     */
241
    async connect(): Promise<void> {
242
        const options = DriverUtils.buildMongoDBDriverOptions(this.options)
8✔
243

244
        const client = await this.mongodb.MongoClient.connect(
8✔
245
            this.buildConnectionUrl(options),
246
            this.buildConnectionOptions(options),
247
        )
248

249
        this.queryRunner = new MongoQueryRunner(this.connection, client)
8✔
250
        ObjectUtils.assign(this.queryRunner, {
8✔
251
            manager: this.connection.manager,
252
        })
253
    }
254

255
    afterConnect(): Promise<void> {
256
        return Promise.resolve()
×
257
    }
258

259
    /**
260
     * Closes connection with the database.
261
     */
262
    async disconnect(): Promise<void> {
263
        if (!this.queryRunner) throw new ConnectionIsNotSetError("mongodb")
×
264
        // const handler = (err: any) => (err ? fail(err) : ok())
265
        this.queryRunner.databaseConnection.close()
×
266
        this.queryRunner = undefined
×
267
        // return ok()
268
    }
269

270
    /**
271
     * Creates a schema builder used to build and sync a schema.
272
     */
273
    createSchemaBuilder() {
274
        return new MongoSchemaBuilder(this.connection)
×
275
    }
276

277
    /**
278
     * Creates a query runner used to execute database queries.
279
     */
280
    createQueryRunner(mode: ReplicationMode) {
281
        return this.queryRunner!
×
282
    }
283

284
    /**
285
     * Replaces parameters in the given sql with special escaping character
286
     * and an array of parameter names to be passed to a query.
287
     */
288
    escapeQueryWithParameters(
289
        sql: string,
290
        parameters: ObjectLiteral,
291
        nativeParameters: ObjectLiteral,
292
    ): [string, any[]] {
293
        throw new TypeORMError(
×
294
            `This operation is not supported by Mongodb driver.`,
295
        )
296
    }
297

298
    /**
299
     * Escapes a column name.
300
     */
301
    escape(columnName: string): string {
302
        return columnName
×
303
    }
304

305
    /**
306
     * Build full table name with database name, schema name and table name.
307
     * E.g. myDB.mySchema.myTable
308
     */
309
    buildTableName(
310
        tableName: string,
311
        schema?: string,
312
        database?: string,
313
    ): string {
314
        return tableName
×
315
    }
316

317
    /**
318
     * Parse a target table name or other types and return a normalized table definition.
319
     */
320
    parseTableName(
321
        target: EntityMetadata | Table | View | TableForeignKey | string,
322
    ): { tableName: string; schema?: string; database?: string } {
323
        if (InstanceChecker.isEntityMetadata(target)) {
×
324
            return {
×
325
                tableName: target.tableName,
326
            }
327
        }
328

329
        if (InstanceChecker.isTable(target) || InstanceChecker.isView(target)) {
×
330
            return {
×
331
                tableName: target.name,
332
            }
333
        }
334

335
        if (InstanceChecker.isTableForeignKey(target)) {
×
336
            return {
×
337
                tableName: target.referencedTableName,
338
            }
339
        }
340

341
        return {
×
342
            tableName: target,
343
        }
344
    }
345

346
    /**
347
     * Prepares given value to a value to be persisted, based on its column type and metadata.
348
     */
349
    preparePersistentValue(value: any, columnMetadata: ColumnMetadata): any {
350
        if (columnMetadata.transformer)
×
351
            value = ApplyValueTransformers.transformTo(
×
352
                columnMetadata.transformer,
353
                value,
354
            )
355
        return value
×
356
    }
357

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

370
    /**
371
     * Creates a database type from a given column metadata.
372
     */
373
    normalizeType(column: {
374
        type?: ColumnType
375
        length?: number | string
376
        precision?: number | null
377
        scale?: number
378
    }): string {
379
        throw new TypeORMError(
×
380
            `MongoDB is schema-less, not supported by this driver.`,
381
        )
382
    }
383

384
    /**
385
     * Normalizes "default" value of the column.
386
     */
387
    normalizeDefault(columnMetadata: ColumnMetadata): string | undefined {
388
        throw new TypeORMError(
×
389
            `MongoDB is schema-less, not supported by this driver.`,
390
        )
391
    }
392

393
    /**
394
     * Normalizes "isUnique" value of the column.
395
     */
396
    normalizeIsUnique(column: ColumnMetadata): boolean {
397
        throw new TypeORMError(
×
398
            `MongoDB is schema-less, not supported by this driver.`,
399
        )
400
    }
401

402
    /**
403
     * Calculates column length taking into account the default length values.
404
     */
405
    getColumnLength(column: ColumnMetadata): string {
406
        throw new TypeORMError(
×
407
            `MongoDB is schema-less, not supported by this driver.`,
408
        )
409
    }
410

411
    /**
412
     * Normalizes "default" value of the column.
413
     */
414
    createFullType(column: TableColumn): string {
415
        throw new TypeORMError(
×
416
            `MongoDB is schema-less, not supported by this driver.`,
417
        )
418
    }
419

420
    /**
421
     * Obtains a new database connection to a master server.
422
     * Used for replication.
423
     * If replication is not setup then returns default connection's database connection.
424
     */
425
    obtainMasterConnection(): Promise<any> {
426
        return Promise.resolve()
×
427
    }
428

429
    /**
430
     * Obtains a new database connection to a slave server.
431
     * Used for replication.
432
     * If replication is not setup then returns master (default) connection's database connection.
433
     */
434
    obtainSlaveConnection(): Promise<any> {
435
        return Promise.resolve()
×
436
    }
437

438
    /**
439
     * Creates generated map of values generated or returned by database after INSERT query.
440
     */
441
    createGeneratedMap(metadata: EntityMetadata, insertedId: any) {
442
        return metadata.objectIdColumn!.createValueMap(insertedId)
×
443
    }
444

445
    /**
446
     * Differentiate columns of this table and columns from the given column metadatas columns
447
     * and returns only changed.
448
     */
449
    findChangedColumns(
450
        tableColumns: TableColumn[],
451
        columnMetadatas: ColumnMetadata[],
452
    ): ColumnMetadata[] {
453
        throw new TypeORMError(
×
454
            `MongoDB is schema-less, not supported by this driver.`,
455
        )
456
    }
457

458
    /**
459
     * Returns true if driver supports RETURNING / OUTPUT statement.
460
     */
461
    isReturningSqlSupported(): boolean {
462
        return false
×
463
    }
464

465
    /**
466
     * Returns true if driver supports uuid values generation on its own.
467
     */
468
    isUUIDGenerationSupported(): boolean {
469
        return false
×
470
    }
471

472
    /**
473
     * Returns true if driver supports fulltext indices.
474
     */
475
    isFullTextColumnTypeSupported(): boolean {
476
        return false
×
477
    }
478

479
    /**
480
     * Creates an escaped parameter.
481
     */
482
    createParameter(parameterName: string, index: number): string {
483
        return ""
×
484
    }
485

486
    // -------------------------------------------------------------------------
487
    // Protected Methods
488
    // -------------------------------------------------------------------------
489

490
    /**
491
     * Validate driver options to make sure everything is correct and driver will be able to establish connection.
492
     */
493
    protected validateOptions(options: DataSourceOptions) {
494
        // todo: fix
495
        // if (!options.url) {
496
        //     if (!options.database)
497
        //         throw new DriverOptionNotSetError("database");
498
        // }
499
    }
500

501
    /**
502
     * Loads all driver dependencies.
503
     */
504
    protected loadDependencies(): any {
505
        try {
8✔
506
            const mongodb = this.options.driver || PlatformTools.load("mongodb")
8✔
507
            this.mongodb = mongodb
8✔
508
        } catch (e) {
509
            throw new DriverPackageNotInstalledError("MongoDB", "mongodb")
×
510
        }
511
    }
512

513
    /**
514
     * Builds connection url that is passed to underlying driver to perform connection to the mongodb database.
515
     */
516
    protected buildConnectionUrl(options: { [key: string]: any }): string {
517
        const schemaUrlPart = options.type.toLowerCase()
8✔
518
        const credentialsUrlPart =
519
            options.username && options.password
8!
520
                ? `${encodeURIComponent(options.username)}:${encodeURIComponent(
521
                      options.password,
522
                  )}@`
523
                : ""
524

525
        const portUrlPart =
526
            schemaUrlPart === "mongodb+srv" ? "" : `:${options.port || "27017"}`
8!
527

528
        let connectionString: string
529
        if (options.replicaSet) {
8✔
530
            connectionString = `${schemaUrlPart}://${credentialsUrlPart}${
4✔
531
                options.hostReplicaSet ||
4!
532
                options.host + portUrlPart ||
533
                "127.0.0.1" + portUrlPart
534
            }/${options.database || ""}`
4!
535
        } else {
536
            connectionString = `${schemaUrlPart}://${credentialsUrlPart}${
4✔
537
                options.host || "127.0.0.1"
4!
538
            }${portUrlPart}/${options.database || ""}`
4!
539
        }
540

541
        return connectionString
8✔
542
    }
543

544
    /**
545
     * Build connection options from MongoConnectionOptions
546
     */
547
    protected buildConnectionOptions(options: { [key: string]: any }): any {
548
        const mongoOptions: any = {}
8✔
549

550
        for (const optionName of this.validOptionNames) {
8✔
551
            if (optionName in options) {
408✔
552
                mongoOptions[optionName] = options[optionName]
12✔
553
            }
554
        }
555

556
        mongoOptions.driverInfo = {
8✔
557
            name: "TypeORM",
558
        }
559

560
        if ("poolSize" in options) {
8!
561
            mongoOptions["maxPoolSize"] = options["poolSize"]
×
562
        }
563

564
        Object.assign(mongoOptions, options.extra)
8✔
565

566
        return mongoOptions
8✔
567
    }
568
}
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