diff --git a/lib/mongodb.js b/lib/mongodb.js index 31759e8ec..015571223 100644 --- a/lib/mongodb.js +++ b/lib/mongodb.js @@ -197,7 +197,8 @@ function MongoDB(settings, dataSource) { this.settings.enableOptimizedfindOrCreate === true || this.settings.enableOptimizedFindOrCreate === true ) { - debug('Optimized findOrCreate is enabled by default, and the enableOptimizedFindOrCreate setting is ignored since v7.0.0.') + debug('Optimized findOrCreate is enabled by default, and the enableOptimizedFindOrCreate setting ' + + 'is ignored since v7.0.0.'); } if (this.settings.enableGeoIndexing === true) { @@ -230,82 +231,189 @@ MongoDB.prototype.connect = function(callback) { }); }); } else { - // See https://github.com/mongodb/node-mongodb-native/blob/3.7/lib/mongo_client.js#L94 + // See https://www.mongodb.com/docs/manual/reference/connection-string const validOptionNames = [ - 'poolSize', - 'ssl', - 'sslValidate', - 'sslCA', - 'sslCert', - 'sslKey', - 'sslPass', - 'sslCRL', + 'replicaSet', + /** Enables or disables TLS/SSL for the connection. */ 'tls', + /** A boolean to enable or disables TLS/SSL for the connection. (The ssl option is equivalent to the tls option.) */ + 'ssl', + /** + * Specifies the location of a local TLS Certificate + * @deprecated Will be removed in the next major version. Please use tlsCertificateKeyFile instead. + */ + 'tlsCertificateFile', + /** Specifies the location of a local .pem file that contains either the client's TLS/SSL certificate and key or only the client's TLS/SSL key when tlsCertificateFile is used to provide the certificate. */ 'tlsCertificateKeyFile', + /** Specifies the password to de-crypt the tlsCertificateKeyFile. */ 'tlsCertificateKeyFilePassword', + /** Specifies the location of a local .pem file that contains the root certificate chain from the Certificate Authority. This file is used to validate the certificate presented by the mongod/mongos instance. */ + 'tlsCAFile', + /** Bypasses validation of the certificates presented by the mongod/mongos instance */ 'tlsAllowInvalidCertificates', + /** Disables hostname validation of the certificate presented by the mongod/mongos instance. */ 'tlsAllowInvalidHostnames', + /** Disables various certificate validations. */ 'tlsInsecure', - 'tlsCAFile', - 'autoReconnect', - 'noDelay', - 'keepAlive', - 'keepAliveInitialDelay', + /** The time in milliseconds to attempt a connection before timing out. */ 'connectTimeoutMS', - 'serverSelectionTimeoutMS', - 'family', + /** The time in milliseconds to attempt a send or receive on a socket before the attempt times out. */ 'socketTimeoutMS', - 'reconnectTries', - 'reconnectInterval', - 'ha', - 'haInterval', - 'replicaSet', - 'secondaryAcceptableLatencyMS', - 'acceptableLatencyMS', - 'connectWithNoPrimary', - 'authSource', - 'forceServerObjectId', - 'serializeFunctions', - 'ignoreUndefined', - 'raw', - 'bufferMaxEntries', - 'readPreference', - 'pkFactory', - 'promiseLibrary', + /** An array or comma-delimited string of compressors to enable network compression for communication between this client and a mongod/mongos instance. */ + 'compressors', + /** An integer that specifies the compression level if using zlib for network compression. */ + 'zlibCompressionLevel', + /** The maximum number of hosts to connect to when using an srv connection string, a setting of `0` means unlimited hosts */ + 'srvMaxHosts', + /** + * Modifies the srv URI to look like: + * + * `_{srvServiceName}._tcp.{hostname}.{domainname}` + * + * Querying this DNS URI is expected to respond with SRV records + */ + 'srvServiceName', + /** The maximum number of connections in the connection pool. */ + 'maxPoolSize', + /** The minimum number of connections in the connection pool. */ + 'minPoolSize', + /** The maximum number of connections that may be in the process of being established concurrently by the connection pool. */ + 'maxConnecting', + /** The maximum number of milliseconds that a connection can remain idle in the pool before being removed and closed. */ + 'maxIdleTimeMS', + /** The maximum time in milliseconds that a thread can wait for a connection to become available. */ + 'waitQueueTimeoutMS', + /** Specify a read concern for the collection (only MongoDB 3.2 or higher supported) */ 'readConcern', + /** The level of isolation */ + 'readConcernLevel', + /** Specifies the read preferences for this connection */ + 'readPreference', + /** Specifies, in seconds, how stale a secondary can be before the client stops using it for read operations. */ 'maxStalenessSeconds', - 'loggerLevel', - 'logger', - 'promoteValues', - 'promoteBuffers', - 'promoteLongs', - 'domainsEnabled', - 'checkServerIdentity', - 'validateOptions', - 'appname', + /** Specifies the tags document as a comma-separated list of colon-separated key-value pairs. */ + 'readPreferenceTags', + /** The auth settings for when connection to server. */ 'auth', + /** Specify the database name associated with the user’s credentials. */ + 'authSource', + /** Specify the authentication mechanism that MongoDB will use to authenticate the connection. */ 'authMechanism', - 'compression', - 'readPreferenceTags', - 'numberOfRetries', - 'auto_reconnect', - 'minSize', - 'useNewUrlParser', - 'useUnifiedTopology', - 'writeConcern', - // Ignored options - 'native_parser', - // Legacy options - 'server', - 'replset', - 'replSet', - 'mongos', - 'db', + /** Specify properties for the specified authMechanism as a comma-separated list of colon-separated key-value pairs. */ + 'authMechanismProperties', + /** The size (in milliseconds) of the latency window for selecting among multiple suitable MongoDB instances. */ + 'localThresholdMS', + /** Specifies how long (in milliseconds) to block for server selection before throwing an exception. */ + 'serverSelectionTimeoutMS', + /** heartbeatFrequencyMS controls when the driver checks the state of the MongoDB deployment. Specify the interval (in milliseconds) between checks, counted from the end of the previous check until the beginning of the next one. */ + 'heartbeatFrequencyMS', + /** Sets the minimum heartbeat frequency. In the event that the driver has to frequently re-check a server's availability, it will wait at least this long since the previous check to avoid wasted effort. */ + 'minHeartbeatFrequencyMS', + /** The name of the application that created this MongoClient instance. MongoDB 3.4 and newer will print this value in the server log upon establishing each connection. It is also recorded in the slow query log and profile collections */ + 'appName', + /** Enables retryable reads. */ + 'retryReads', + /** Enable retryable writes. */ + 'retryWrites', + /** Allow a driver to force a Single topology type with a connection string containing one host */ + 'directConnection', + /** Instruct the driver it is connecting to a load balancer fronting a mongos like service */ + 'loadBalanced', + /** + * The write concern w value + * @deprecated Please use the `writeConcern` option instead + */ 'w', - 'wtimeout', - 'j', + /** + * The write concern timeout + * @deprecated Please use the `writeConcern` option instead + */ + 'wtimeoutMS', + /** + * The journal write concern + * @deprecated Please use the `writeConcern` option instead + */ 'journal', - 'fsync', + /** + * A MongoDB WriteConcern, which describes the level of acknowledgement + * requested from MongoDB for write operations. + * + * @see https://www.mongodb.com/docs/manual/reference/write-concern/ + */ + 'writeConcern', + /** + * Validate mongod server certificate against Certificate Authority + * @deprecated Will be removed in the next major version. Please use tlsAllowInvalidCertificates instead. + */ + 'sslValidate', + /** + * SSL Certificate file path. + * @deprecated Will be removed in the next major version. Please use tlsCAFile instead. + */ + 'sslCA', + /** + * SSL Certificate file path. + * @deprecated Will be removed in the next major version. Please use tlsCertificateKeyFile instead. + */ + 'sslCert', + /** + * SSL Key file file path. + * @deprecated Will be removed in the next major version. Please use tlsCertificateKeyFile instead. + */ + 'sslKey', + /** + * SSL Certificate pass phrase. + * @deprecated Will be removed in the next major version. Please use tlsCertificateKeyFilePassword instead. + */ + 'sslPass', + /** + * SSL Certificate revocation list file path. + * @deprecated Will be removed in the next major version. Please use tlsCertificateKeyFile instead. + */ + 'sslCRL', + /** TCP Connection no delay */ + 'noDelay', + /** @deprecated TCP Connection keep alive enabled. Will not be able to turn off in the future. */ + 'keepAlive', + /** + * @deprecated The number of milliseconds to wait before initiating keepAlive on the TCP socket. + * Will not be configurable in the future. + */ + 'keepAliveInitialDelay', + /** Force server to assign `_id` values instead of driver */ + 'forceServerObjectId', + /** A primary key factory function for generation of custom `_id` keys */ + 'pkFactory', + /** Enable command monitoring for this client */ + 'monitorCommands', + /** Server API version */ + 'serverApi', + /** + * Optionally enable in-use auto encryption + * + * @remarks + * Automatic encryption is an enterprise only feature that only applies to operations on a collection. Automatic encryption is not supported for operations on a database or view, and operations that are not bypassed will result in error + * (see [libmongocrypt: Auto Encryption Allow-List](https://github.com/mongodb/specifications/blob/master/source/client-side-encryption/client-side-encryption.rst#libmongocrypt-auto-encryption-allow-list)). To bypass automatic encryption for all operations, set bypassAutoEncryption=true in AutoEncryptionOpts. + * + * Automatic encryption requires the authenticated user to have the [listCollections privilege action](https://www.mongodb.com/docs/manual/reference/command/listCollections/#dbcmd.listCollections). + * + * If a MongoClient with a limited connection pool size (i.e a non-zero maxPoolSize) is configured with AutoEncryptionOptions, a separate internal MongoClient is created if any of the following are true: + * - AutoEncryptionOptions.keyVaultClient is not passed. + * - AutoEncryptionOptions.bypassAutomaticEncryption is false. + * + * If an internal MongoClient is created, it is configured with the same options as the parent MongoClient except minPoolSize is set to 0 and AutoEncryptionOptions is omitted. + */ + 'autoEncryption', + /** Allows a wrapping driver to amend the client metadata generated by the driver to include information about the wrapping driver */ + 'driverInfo', + /** Configures a Socks5 proxy host used for creating TCP connections. */ + 'proxyHost', + /** Configures a Socks5 proxy port used for creating TCP connections. */ + 'proxyPort', + /** Configures a Socks5 proxy username when the proxy in proxyHost requires username/password authentication. */ + 'proxyUsername', + /** Configures a Socks5 proxy password when the proxy in proxyHost requires username/password authentication. */ + 'proxyPassword', ]; const lbOptions = Object.keys(self.settings); @@ -338,7 +446,10 @@ MongoDB.prototype.connect = function(callback) { self.settings.url = urlObj.toString(); } - new mongodb.MongoClient(self.settings.url, validOptions).connect(function( + const mongoClient = new mongodb.MongoClient(self.settings.url, validOptions); + const callbackConnect = util.callbackify(() => mongoClient.connect()); + + callbackConnect(function( err, client, ) { @@ -586,21 +697,23 @@ MongoDB.prototype.execute = function(modelName, command) { done(err, result); }; + // from mongoddb v5 command does not support callback + args.pop(); + debug('MongoDB: model=%s command=%s', modelName, command, args); + // args had callback removed - if (command === 'find') { - // find does not support callback, remove and use a toArray with this callback - args.pop(); - debug('MongoDB: model=%s command=%s', modelName, command, args); - try { - const cursor = collection[command].apply(collection, args); - return observerCallback(null, cursor); - } catch (err) { - return observerCallback(err, null); + try { + const execute = collection[command].apply(collection, args); + + if (command === 'find') { + return observerCallback(null, execute); + } else { + const callbackCommand = util.callbackify(() => execute); + + return callbackCommand(observerCallback); } - } else { - args[args.length - 1] = observerCallback; - debug('MongoDB: model=%s command=%s', modelName, command, args); - return collection[command].apply(collection, args); + } catch (err) { + return observerCallback(err, null); } }, callback, @@ -1487,7 +1600,9 @@ MongoDB.prototype.all = function all(modelName, filter, options, callback) { cursor.skip(filter.offset); } - cursor.toArray(function(err, data) { + const callbackCursor = util.callbackify(() => cursor.toArray()); + + callbackCursor(function(err, data) { if (self.debug) { debug('all', modelName, filter, err, data); } @@ -1557,10 +1672,13 @@ MongoDB.prototype.findOrCreate = function findOrCreate(modelName, filter, data, const projection = fieldsArrayToObj(filter.fields); - this.collection(modelName).findOneAndUpdate( + const callbackFindOneAndUpdate = util.callbackify(() => this.collection(modelName).findOneAndUpdate( query, {$setOnInsert: data}, {projection: projection, sort: sort, upsert: true}, + )); + + callbackFindOneAndUpdate( function(err, result) { if (self.debug) { debug('findOrCreate.callback', modelName, filter, err, result); @@ -1596,7 +1714,7 @@ MongoDB.prototype.findOrCreate = function findOrCreate(modelName, filter, data, } }, ); -} +}; /** * Transform db data to model entity @@ -2109,13 +2227,9 @@ MongoDB.prototype.autoupdate = function(models, cb) { if (self.debug) { debug('createIndex: ', index); } - self - .collection(modelName) - .createIndex( - index.fields || index.keys, - index.options, - indexCallback, - ); + const callbackCreateIndex = util.callbackify(() => self + .collection(modelName).createIndex(index.fields || index.keys)); + callbackCreateIndex(indexCallback); }, modelCallback, ); @@ -2161,7 +2275,9 @@ MongoDB.prototype.automigrate = function(models, cb) { debug('drop collection %s for model %s', collectionName, modelName); } - self.db.dropCollection(collectionName, function(err, collection) { + const callbackDropCollection = util.callbackify((collectionName) => self.db.dropCollection(collectionName)); + + callbackDropCollection(collectionName, function(err, collection) { if (err) { debug( 'Error dropping collection %s for model %s: ', @@ -2184,7 +2300,10 @@ MongoDB.prototype.automigrate = function(models, cb) { if (self.debug) { debug('create collection %s for model %s', collectionName, modelName); } - self.db.createCollection(collectionName, modelCallback); + + const callbackCreateCollection = util.callbackify((collectionName) => self.db + .createCollection(collectionName)); + callbackCreateCollection(collectionName, modelCallback); }); }, function(err) { @@ -2204,7 +2323,7 @@ MongoDB.prototype.automigrate = function(models, cb) { MongoDB.prototype.ping = function(cb) { const self = this; if (self.db) { - this.db.collection('dummy').findOne({_id: 1}, cb); + util.callbackify(() => this.db.collection('dummy').findOne({_id: 1}))(cb); } else { self.dataSource.once('connected', function() { self.ping(cb); diff --git a/package-lock.json b/package-lock.json index f87adf4be..95ee6c806 100644 --- a/package-lock.json +++ b/package-lock.json @@ -6,14 +6,14 @@ "packages": { "": { "name": "loopback-connector-mongodb", - "version": "6.2.0", + "version": "7.0.0-alpha.2", "license": "MIT", "dependencies": { "async": "^3.2.4", "bson": "^1.1.6", "debug": "^4.3.4", "loopback-connector": "^5.0.1", - "mongodb": "^4.6.0", + "mongodb": "^5.9.1", "strong-globalize": "^6.0.5" }, "devDependencies": { @@ -34,7 +34,7 @@ "sinon": "^12.0.1" }, "engines": { - "node": "14 || 16 || 18" + "node": "18 || 20" } }, "deps/juggler-v4": { @@ -857,6 +857,15 @@ "@jridgewell/sourcemap-codec": "^1.4.10" } }, + "node_modules/@mongodb-js/saslprep": { + "version": "1.1.9", + "resolved": "https://registry.npmjs.org/@mongodb-js/saslprep/-/saslprep-1.1.9.tgz", + "integrity": "sha512-tVkljjeEaAhCqTzajSdgbQ6gE6f3oneVwa3iXR6csiEwXXOFsiC6Uh9iAjAhXPtqa/XMDHWjjeNH/77m/Yq2dw==", + "optional": true, + "dependencies": { + "sparse-bitfield": "^3.0.3" + } + }, "node_modules/@nodelib/fs.scandir": { "version": "2.1.5", "dev": true, @@ -967,9 +976,9 @@ "dev": true }, "node_modules/@types/webidl-conversions": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/@types/webidl-conversions/-/webidl-conversions-7.0.0.tgz", - "integrity": "sha512-xTE1E+YF4aWPJJeUzaZI5DRntlkY3+BCVJi0axFptnjGmAoWxkyREIh/XMrfxVLejwQxMCfDXdICo0VLxThrog==" + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/@types/webidl-conversions/-/webidl-conversions-7.0.3.tgz", + "integrity": "sha512-CiJJvcRtIgzadHCYXw7dqEnMNRjhGZlYK05Mj9OyktqV8uVT8fD2BFOB7S1uwBE3Kj2Z+4UyPmFw/Ixgw/LAlA==" }, "node_modules/@types/whatwg-url": { "version": "8.2.2", @@ -1149,25 +1158,6 @@ "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" }, - "node_modules/base64-js": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", - "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, "node_modules/bcp47": { "version": "1.1.2", "license": "MIT", @@ -1258,29 +1248,6 @@ "node": ">=0.6.19" } }, - "node_modules/buffer": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", - "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "dependencies": { - "base64-js": "^1.3.1", - "ieee754": "^1.1.13" - } - }, "node_modules/caching-transform": { "version": "4.0.0", "dev": true, @@ -1705,14 +1672,6 @@ "node": ">=8" } }, - "node_modules/denque": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/denque/-/denque-2.1.0.tgz", - "integrity": "sha512-HVQE3AAb/pxF8fQAoiqpvg9i3evqug3hoiwakOyZAwJm+6vZehbkYXZ0l4JxS+I3QxM97v5aaRNhj8v5oBhekw==", - "engines": { - "node": ">=0.10" - } - }, "node_modules/depd": { "version": "2.0.0", "dev": true, @@ -2544,25 +2503,6 @@ "node": ">=10.17.0" } }, - "node_modules/ieee754": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", - "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, "node_modules/ignore": { "version": "5.2.0", "dev": true, @@ -2645,10 +2585,22 @@ "url": "https://github.com/sindresorhus/invert-kv?sponsor=1" } }, - "node_modules/ip": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ip/-/ip-2.0.0.tgz", - "integrity": "sha512-WKa+XuLG1A1R0UWhl2+1XQSi+fZWMsYKffMZTTYsiZaUD8k2yDAj5atimTUD2TZkyCkNEeYE5NhFZmupOGtjYQ==" + "node_modules/ip-address": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-9.0.5.tgz", + "integrity": "sha512-zHtQzGojZXTwZTHQqra+ETKd4Sn3vgi7uBmlPoXVWZqYvuKmtI0l/VZTjqGmJY9x88GGOaZ9+G9ES8hC4T4X8g==", + "dependencies": { + "jsbn": "1.1.0", + "sprintf-js": "^1.1.3" + }, + "engines": { + "node": ">= 12" + } + }, + "node_modules/ip-address/node_modules/sprintf-js": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.3.tgz", + "integrity": "sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA==" }, "node_modules/is-arrayish": { "version": "0.2.1", @@ -2914,6 +2866,11 @@ "js-yaml": "bin/js-yaml.js" } }, + "node_modules/jsbn": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-1.1.0.tgz", + "integrity": "sha512-4bYVV3aAMtDTTu4+xsDYa6sy9GyJ69/amsu9sYF2zqjiEoZA5xJi3BrfX3uY+/IekIu7MwdObdbDWpoZdBv3/A==" + }, "node_modules/jsesc": { "version": "2.5.2", "dev": true, @@ -3220,7 +3177,8 @@ }, "node_modules/memory-pager": { "version": "1.5.0", - "license": "MIT", + "resolved": "https://registry.npmjs.org/memory-pager/-/memory-pager-1.5.0.tgz", + "integrity": "sha512-ZS4Bp4r/Zoeq6+NLJpP+0Zzm0pR8whtGPf1XExKLJBAczGMnSi3It14OiNCStjQjM6NU1okjQGSxgEZN8eBYKg==", "optional": true }, "node_modules/meow": { @@ -3470,40 +3428,60 @@ } }, "node_modules/mongodb": { - "version": "4.9.1", - "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-4.9.1.tgz", - "integrity": "sha512-ZhgI/qBf84fD7sI4waZBoLBNJYPQN5IOC++SBCiPiyhzpNKOxN/fi0tBHvH2dEC42HXtNEbFB0zmNz4+oVtorQ==", + "version": "5.9.2", + "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-5.9.2.tgz", + "integrity": "sha512-H60HecKO4Bc+7dhOv4sJlgvenK4fQNqqUIlXxZYQNbfEWSALGAwGoyJd/0Qwk4TttFXUOHJ2ZJQe/52ScaUwtQ==", "dependencies": { - "bson": "^4.7.0", - "denque": "^2.1.0", - "mongodb-connection-string-url": "^2.5.3", - "socks": "^2.7.0" + "bson": "^5.5.0", + "mongodb-connection-string-url": "^2.6.0", + "socks": "^2.7.1" }, "engines": { - "node": ">=12.9.0" + "node": ">=14.20.1" }, "optionalDependencies": { - "saslprep": "^1.0.3" + "@mongodb-js/saslprep": "^1.1.0" + }, + "peerDependencies": { + "@aws-sdk/credential-providers": "^3.188.0", + "@mongodb-js/zstd": "^1.0.0", + "kerberos": "^1.0.0 || ^2.0.0", + "mongodb-client-encryption": ">=2.3.0 <3", + "snappy": "^7.2.2" + }, + "peerDependenciesMeta": { + "@aws-sdk/credential-providers": { + "optional": true + }, + "@mongodb-js/zstd": { + "optional": true + }, + "kerberos": { + "optional": true + }, + "mongodb-client-encryption": { + "optional": true + }, + "snappy": { + "optional": true + } } }, "node_modules/mongodb-connection-string-url": { - "version": "2.5.3", - "resolved": "https://registry.npmjs.org/mongodb-connection-string-url/-/mongodb-connection-string-url-2.5.3.tgz", - "integrity": "sha512-f+/WsED+xF4B74l3k9V/XkTVj5/fxFH2o5ToKXd8Iyi5UhM+sO9u0Ape17Mvl/GkZaFtM0HQnzAG5OTmhKw+tQ==", + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/mongodb-connection-string-url/-/mongodb-connection-string-url-2.6.0.tgz", + "integrity": "sha512-WvTZlI9ab0QYtTYnuMLgobULWhokRjtC7db9LtcVfJ+Hsnyr5eo6ZtNAt3Ly24XZScGMelOcGtm7lSn0332tPQ==", "dependencies": { "@types/whatwg-url": "^8.2.1", "whatwg-url": "^11.0.0" } }, "node_modules/mongodb/node_modules/bson": { - "version": "4.7.0", - "resolved": "https://registry.npmjs.org/bson/-/bson-4.7.0.tgz", - "integrity": "sha512-VrlEE4vuiO1WTpfof4VmaVolCVYkYTgB9iWgYNOrVlnifpME/06fhFRmONgBhClD5pFC1t9ZWqFUQEQAzY43bA==", - "dependencies": { - "buffer": "^5.6.0" - }, + "version": "5.5.1", + "resolved": "https://registry.npmjs.org/bson/-/bson-5.5.1.tgz", + "integrity": "sha512-ix0EwukN2EpC0SRWIj/7B5+A6uQMQy6KMREI9qQqvgpkV2frH63T0UDVd1SYedL6dNCmDBYB3QtXi4ISk9YT+g==", "engines": { - "node": ">=6.9.0" + "node": ">=14.20.1" } }, "node_modules/ms": { @@ -4535,17 +4513,6 @@ ], "license": "MIT" }, - "node_modules/saslprep": { - "version": "1.0.3", - "license": "MIT", - "optional": true, - "dependencies": { - "sparse-bitfield": "^3.0.3" - }, - "engines": { - "node": ">=6" - } - }, "node_modules/semver": { "version": "7.3.7", "dev": true, @@ -4719,15 +4686,15 @@ } }, "node_modules/socks": { - "version": "2.7.0", - "resolved": "https://registry.npmjs.org/socks/-/socks-2.7.0.tgz", - "integrity": "sha512-scnOe9y4VuiNUULJN72GrM26BNOjVsfPXI+j+98PkyEfsIXroa5ofyjT+FzGvn/xHs73U2JtoBYAVx9Hl4quSA==", + "version": "2.8.3", + "resolved": "https://registry.npmjs.org/socks/-/socks-2.8.3.tgz", + "integrity": "sha512-l5x7VUUWbjVFbafGLxPWkYsHIhEvmF85tbIeFZWc8ZPtoMyybuEhL7Jye/ooC4/d48FgOjSJXgsF/AJPYCW8Zw==", "dependencies": { - "ip": "^2.0.0", + "ip-address": "^9.0.5", "smart-buffer": "^4.2.0" }, "engines": { - "node": ">= 10.13.0", + "node": ">= 10.0.0", "npm": ">= 3.0.0" } }, @@ -4752,7 +4719,8 @@ }, "node_modules/sparse-bitfield": { "version": "3.0.3", - "license": "MIT", + "resolved": "https://registry.npmjs.org/sparse-bitfield/-/sparse-bitfield-3.0.3.tgz", + "integrity": "sha512-kvzhi7vqKTfkh0PZU+2D2PIllw2ymqJKujUcyPMd9Y75Nv4nPbGJZXNhxsgdQab2BmlDct1YnfQCguEvHr7VsQ==", "optional": true, "dependencies": { "memory-pager": "^1.0.2" @@ -5956,6 +5924,15 @@ "@jridgewell/sourcemap-codec": "^1.4.10" } }, + "@mongodb-js/saslprep": { + "version": "1.1.9", + "resolved": "https://registry.npmjs.org/@mongodb-js/saslprep/-/saslprep-1.1.9.tgz", + "integrity": "sha512-tVkljjeEaAhCqTzajSdgbQ6gE6f3oneVwa3iXR6csiEwXXOFsiC6Uh9iAjAhXPtqa/XMDHWjjeNH/77m/Yq2dw==", + "optional": true, + "requires": { + "sparse-bitfield": "^3.0.3" + } + }, "@nodelib/fs.scandir": { "version": "2.1.5", "dev": true, @@ -6045,9 +6022,9 @@ "dev": true }, "@types/webidl-conversions": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/@types/webidl-conversions/-/webidl-conversions-7.0.0.tgz", - "integrity": "sha512-xTE1E+YF4aWPJJeUzaZI5DRntlkY3+BCVJi0axFptnjGmAoWxkyREIh/XMrfxVLejwQxMCfDXdICo0VLxThrog==" + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/@types/webidl-conversions/-/webidl-conversions-7.0.3.tgz", + "integrity": "sha512-CiJJvcRtIgzadHCYXw7dqEnMNRjhGZlYK05Mj9OyktqV8uVT8fD2BFOB7S1uwBE3Kj2Z+4UyPmFw/Ixgw/LAlA==" }, "@types/whatwg-url": { "version": "8.2.2", @@ -6166,11 +6143,6 @@ "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" }, - "base64-js": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", - "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==" - }, "bcp47": { "version": "1.1.2" }, @@ -6230,15 +6202,6 @@ "resolved": "https://registry.npmjs.org/bson/-/bson-1.1.6.tgz", "integrity": "sha512-EvVNVeGo4tHxwi8L6bPj3y3itEvStdwvvlojVxxbyYfoaxJ6keLgrTuKdyfEAszFK+H3olzBuafE0yoh0D1gdg==" }, - "buffer": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", - "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", - "requires": { - "base64-js": "^1.3.1", - "ieee754": "^1.1.13" - } - }, "caching-transform": { "version": "4.0.0", "dev": true, @@ -6517,11 +6480,6 @@ "strip-bom": "^4.0.0" } }, - "denque": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/denque/-/denque-2.1.0.tgz", - "integrity": "sha512-HVQE3AAb/pxF8fQAoiqpvg9i3evqug3hoiwakOyZAwJm+6vZehbkYXZ0l4JxS+I3QxM97v5aaRNhj8v5oBhekw==" - }, "depd": { "version": "2.0.0", "dev": true @@ -7043,11 +7001,6 @@ "version": "2.1.0", "dev": true }, - "ieee754": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", - "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==" - }, "ignore": { "version": "5.2.0", "dev": true @@ -7095,10 +7048,21 @@ "invert-kv": { "version": "3.0.1" }, - "ip": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ip/-/ip-2.0.0.tgz", - "integrity": "sha512-WKa+XuLG1A1R0UWhl2+1XQSi+fZWMsYKffMZTTYsiZaUD8k2yDAj5atimTUD2TZkyCkNEeYE5NhFZmupOGtjYQ==" + "ip-address": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-9.0.5.tgz", + "integrity": "sha512-zHtQzGojZXTwZTHQqra+ETKd4Sn3vgi7uBmlPoXVWZqYvuKmtI0l/VZTjqGmJY9x88GGOaZ9+G9ES8hC4T4X8g==", + "requires": { + "jsbn": "1.1.0", + "sprintf-js": "^1.1.3" + }, + "dependencies": { + "sprintf-js": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.3.tgz", + "integrity": "sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA==" + } + } }, "is-arrayish": { "version": "0.2.1", @@ -7266,6 +7230,11 @@ "esprima": "^4.0.0" } }, + "jsbn": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-1.1.0.tgz", + "integrity": "sha512-4bYVV3aAMtDTTu4+xsDYa6sy9GyJ69/amsu9sYF2zqjiEoZA5xJi3BrfX3uY+/IekIu7MwdObdbDWpoZdBv3/A==" + }, "jsesc": { "version": "2.5.2", "dev": true @@ -7468,6 +7437,8 @@ }, "memory-pager": { "version": "1.5.0", + "resolved": "https://registry.npmjs.org/memory-pager/-/memory-pager-1.5.0.tgz", + "integrity": "sha512-ZS4Bp4r/Zoeq6+NLJpP+0Zzm0pR8whtGPf1XExKLJBAczGMnSi3It14OiNCStjQjM6NU1okjQGSxgEZN8eBYKg==", "optional": true }, "meow": { @@ -7627,31 +7598,27 @@ } }, "mongodb": { - "version": "4.9.1", - "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-4.9.1.tgz", - "integrity": "sha512-ZhgI/qBf84fD7sI4waZBoLBNJYPQN5IOC++SBCiPiyhzpNKOxN/fi0tBHvH2dEC42HXtNEbFB0zmNz4+oVtorQ==", + "version": "5.9.2", + "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-5.9.2.tgz", + "integrity": "sha512-H60HecKO4Bc+7dhOv4sJlgvenK4fQNqqUIlXxZYQNbfEWSALGAwGoyJd/0Qwk4TttFXUOHJ2ZJQe/52ScaUwtQ==", "requires": { - "bson": "^4.7.0", - "denque": "^2.1.0", - "mongodb-connection-string-url": "^2.5.3", - "saslprep": "^1.0.3", - "socks": "^2.7.0" + "@mongodb-js/saslprep": "^1.1.0", + "bson": "^5.5.0", + "mongodb-connection-string-url": "^2.6.0", + "socks": "^2.7.1" }, "dependencies": { "bson": { - "version": "4.7.0", - "resolved": "https://registry.npmjs.org/bson/-/bson-4.7.0.tgz", - "integrity": "sha512-VrlEE4vuiO1WTpfof4VmaVolCVYkYTgB9iWgYNOrVlnifpME/06fhFRmONgBhClD5pFC1t9ZWqFUQEQAzY43bA==", - "requires": { - "buffer": "^5.6.0" - } + "version": "5.5.1", + "resolved": "https://registry.npmjs.org/bson/-/bson-5.5.1.tgz", + "integrity": "sha512-ix0EwukN2EpC0SRWIj/7B5+A6uQMQy6KMREI9qQqvgpkV2frH63T0UDVd1SYedL6dNCmDBYB3QtXi4ISk9YT+g==" } } }, "mongodb-connection-string-url": { - "version": "2.5.3", - "resolved": "https://registry.npmjs.org/mongodb-connection-string-url/-/mongodb-connection-string-url-2.5.3.tgz", - "integrity": "sha512-f+/WsED+xF4B74l3k9V/XkTVj5/fxFH2o5ToKXd8Iyi5UhM+sO9u0Ape17Mvl/GkZaFtM0HQnzAG5OTmhKw+tQ==", + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/mongodb-connection-string-url/-/mongodb-connection-string-url-2.6.0.tgz", + "integrity": "sha512-WvTZlI9ab0QYtTYnuMLgobULWhokRjtC7db9LtcVfJ+Hsnyr5eo6ZtNAt3Ly24XZScGMelOcGtm7lSn0332tPQ==", "requires": { "@types/whatwg-url": "^8.2.1", "whatwg-url": "^11.0.0" @@ -8308,13 +8275,6 @@ "safe-buffer": { "version": "5.2.1" }, - "saslprep": { - "version": "1.0.3", - "optional": true, - "requires": { - "sparse-bitfield": "^3.0.3" - } - }, "semver": { "version": "7.3.7", "dev": true, @@ -8448,11 +8408,11 @@ } }, "socks": { - "version": "2.7.0", - "resolved": "https://registry.npmjs.org/socks/-/socks-2.7.0.tgz", - "integrity": "sha512-scnOe9y4VuiNUULJN72GrM26BNOjVsfPXI+j+98PkyEfsIXroa5ofyjT+FzGvn/xHs73U2JtoBYAVx9Hl4quSA==", + "version": "2.8.3", + "resolved": "https://registry.npmjs.org/socks/-/socks-2.8.3.tgz", + "integrity": "sha512-l5x7VUUWbjVFbafGLxPWkYsHIhEvmF85tbIeFZWc8ZPtoMyybuEhL7Jye/ooC4/d48FgOjSJXgsF/AJPYCW8Zw==", "requires": { - "ip": "^2.0.0", + "ip-address": "^9.0.5", "smart-buffer": "^4.2.0" } }, @@ -8464,6 +8424,8 @@ }, "sparse-bitfield": { "version": "3.0.3", + "resolved": "https://registry.npmjs.org/sparse-bitfield/-/sparse-bitfield-3.0.3.tgz", + "integrity": "sha512-kvzhi7vqKTfkh0PZU+2D2PIllw2ymqJKujUcyPMd9Y75Nv4nPbGJZXNhxsgdQab2BmlDct1YnfQCguEvHr7VsQ==", "optional": true, "requires": { "memory-pager": "^1.0.2" diff --git a/package.json b/package.json index ca3feab24..1c7c81346 100644 --- a/package.json +++ b/package.json @@ -37,7 +37,7 @@ "bson": "^1.1.6", "debug": "^4.3.4", "loopback-connector": "^5.0.1", - "mongodb": "^4.6.0", + "mongodb": "^5.9.1", "strong-globalize": "^6.0.5" }, "devDependencies": { diff --git a/test/mongodb.test.js b/test/mongodb.test.js index e4aa283ed..86a051a77 100644 --- a/test/mongodb.test.js +++ b/test/mongodb.test.js @@ -527,59 +527,52 @@ describe('mongodb connector', function() { }); }); - it('should create indexes', function(done) { - db.automigrate('User', function() { - db.connector.db + it('should create indexes', async function() { + db.automigrate('User', async function() { + const result = await db.connector.db .collection('User') - .indexInformation(function(err, result) { - /* eslint-disable camelcase */ - const indexes = { - _id_: [['_id', 1]], - name_age_index: [['name', 1], ['age', -1]], - age_index: [['age', -1]], - name_1: [['name', 1]], - email_1: [['email', 1]], - }; - /* eslint-enable camelcase */ - indexes.should.eql(result); - done(err, result); - }); + .indexInformation(); + /* eslint-disable camelcase */ + const indexes = { + _id_: [['_id', 1]], + name_age_index: [['name', 1], ['age', -1]], + age_index: [['age', -1]], + name_1: [['name', 1]], + email_1: [['email', 1]], + }; + /* eslint-enable camelcase */ + indexes.should.eql(result); }); }); - it('should create complex indexes', function(done) { - db.automigrate('Superhero', function() { - db.connector.db.collection('sh').indexInformation(function(err, result) { - /* eslint-disable camelcase */ - const indexes = { - _id_: [['_id', 1]], - geojson_location_geometry: [['location.geometry', '2dsphere']], - power_1: [['power', 1]], - name_1: [['name', 1]], - address_1: [['address', 1]], - }; + it('should create complex indexes', async function() { + db.automigrate('Superhero', async function() { + const result = await db.connector.db.collection('sh').indexInformation(); + /* eslint-disable camelcase */ + const indexes = { + _id_: [['_id', 1]], + geojson_location_geometry: [['location.geometry', '2dsphere']], + power_1: [['power', 1]], + name_1: [['name', 1]], + address_1: [['address', 1]], + }; /* eslint-enable camelcase */ - indexes.should.eql(result); - done(err, result); - }); + indexes.should.eql(result); }); }); - it('should create case insensitive indexes', function(done) { - db.automigrate('Category', function() { - db.connector.db.collection('Category').indexes(function(err, result) { - if (err) return done(err); - const indexes = [ - {name: '_id_', key: {_id: 1}}, - {name: 'title_1', key: {title: 1}}, - {name: 'title_case_insensitive', key: {title: 1}, collation: {locale: 'en', strength: 1}}, - {name: 'posts_1', key: {posts: 1}}, - ]; - - result.should.containDeep(indexes); - done(); - }); + it('should create case insensitive indexes', async function() { + db.automigrate('Category', async function() { + const result = await db.connector.db.collection('Category').indexes(); + const indexes = [ + {name: '_id_', key: {_id: 1}}, + {name: 'title_1', key: {title: 1}}, + {name: 'title_case_insensitive', key: {title: 1}, collation: {locale: 'en', strength: 1}}, + {name: 'posts_1', key: {posts: 1}}, + ]; + + result.should.containDeep(indexes); }); }); @@ -832,18 +825,15 @@ describe('mongodb connector', function() { }); }); - it('should allow custom collection name', function(done) { - Post.create({title: 'Post1', content: 'Post content'}, function( + it('should allow custom collection name', async function() { + Post.create({title: 'Post1', content: 'Post content'}, async function( err, post, ) { - Post.dataSource.connector.db + const p = await Post.dataSource.connector.db .collection('PostCollection') - .findOne({_id: post.id}, function(err, p) { - should.not.exist(err); - should.exist(p); - done(); - }); + .findOne({_id: post.id}); + should.exist(p); }); }); @@ -1325,10 +1315,7 @@ describe('mongodb connector', function() { function(err, updatedusers) { should.exist(err); err.name.should.equal('MongoServerError'); - err.errmsg.should.equal( - 'The dollar ($) prefixed ' + - "field '$rename' in '$rename' is not valid for storage.", - ); + err.errmsg.should.match(/The dollar \(\$\) prefixed field \'\$rename\' in \'\$rename\' is not allowed/); done(); }, ); @@ -1350,10 +1337,7 @@ describe('mongodb connector', function() { function(err, updatedusers) { should.exist(err); err.name.should.equal('MongoServerError'); - err.errmsg.should.equal( - 'The dollar ($) prefixed ' + - "field '$rename' in '$rename' is not valid for storage.", - ); + err.errmsg.should.match(/The dollar \(\$\) prefixed field \'\$rename\' in \'\$rename\' is not allowed/); done(); }, ); @@ -1407,10 +1391,7 @@ describe('mongodb connector', function() { function(err, updatedusers) { should.exist(err); err.name.should.equal('MongoServerError'); - err.errmsg.should.equal( - 'The dollar ($) prefixed ' + - "field '$rename' in '$rename' is not valid for storage.", - ); + err.errmsg.should.match(/The dollar \(\$\) prefixed field \'\$rename\' in \'\$rename\' is not allowed/); done(); }, );