Skip to content

Commit

Permalink
feat: upgrade mongodb driver to version 4.x
Browse files Browse the repository at this point in the history
Signed-off-by: Antonio Ramón Sánchez Morales <[email protected]>
  • Loading branch information
arsa-dev authored and achrinza committed Oct 23, 2022
1 parent 9f9f721 commit d0e815b
Show file tree
Hide file tree
Showing 4 changed files with 404 additions and 140 deletions.
131 changes: 86 additions & 45 deletions lib/mongodb.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,9 @@
/*!
* Module dependencies
*/
const bson = require('bson');
const g = require('strong-globalize')();
const mongodb = require('mongodb');
const urlParser = require('mongodb/lib/url_parser');
const urlParser = require('mongodb/lib/connection_string').parseOptions;
const util = require('util');
const async = require('async');
const Connector = require('loopback-connector').Connector;
Expand All @@ -29,7 +28,7 @@ exports.ObjectID = ObjectID;
* @returns {ObjectID}
*/
function ObjectID(id) {
if (id instanceof mongodb.ObjectID) {
if (id instanceof mongodb.ObjectId) {
return id;
}
if (typeof id !== 'string') {
Expand All @@ -40,7 +39,7 @@ function ObjectID(id) {
// hex string. For LoopBack, we only allow 24-byte hex string, but 12-byte
// string such as 'line-by-line' should be kept as string
if (ObjectIdValueRegex.test(id)) {
return new bson.ObjectID(id);
return new mongodb.ObjectId(id);
} else {
return id;
}
Expand Down Expand Up @@ -113,10 +112,9 @@ exports.initialize = function initializeDataSource(dataSource, callback) {
fsync: s.fsync || null,
};
s.url = s.url || generateMongoDBURL(s);
s.useNewUrlParser = s.useNewUrlParser !== false;
s.useUnifiedTopology = s.useUnifiedTopology !== false;
// useNewUrlParser and useUnifiedTopology are default now
dataSource.connector = new MongoDB(s, dataSource);
dataSource.ObjectID = mongodb.ObjectID;
dataSource.ObjectID = mongodb.ObjectId;

if (callback) {
if (s.lazyConnect) {
Expand Down Expand Up @@ -285,8 +283,6 @@ MongoDB.prototype.connect = function(callback) {
'validateOptions',
'appname',
'auth',
'user',
'password',
'authMechanism',
'compression',
'readPreferenceTags',
Expand Down Expand Up @@ -354,17 +350,45 @@ MongoDB.prototype.connect = function(callback) {
}
self.client = client;
// The database name might be in the url
return urlParser(self.settings.url, self.settings, function(err, url) {
if (err) {
onError(err);
return;
}
try {
const url = urlParser(self.settings.url, validOptions); // only supports the validURL options now
// See https://github.com/mongodb/mongodb/blob/6.0.1/lib/mongodb.d.ts#L3854
const validDbOptionNames = [
'authSource',
'forceServerObjectId',
'readPreference',
'pkFactory',
'readConcern',
'retryWrites',
'checkKeys',
'serializeFunctions',
'ignoreUndefined',
'promoteLongs',
'promoteBuffers',
'promoteValues',
'fieldsAsRaw',
'bsonRegExp',
'raw',
'writeConcern',
'logger',
'loggerLevel',
];
const dbOptions = url.db_options || self.settings;
const dbOptionKeys = Object.keys(dbOptions);
const validDbOptions = {};
dbOptionKeys.forEach(function(option) {
if (validDbOptionNames.indexOf(option) > -1) {
validDbOptions[option] = dbOptions[option];
}
});
self.db = client.db(
url.dbName || self.settings.database,
url.db_options || self.settings,
validDbOptions,
);
if (callback) callback(err, self.db);
});
} catch (e) {
onError(e);
}
});
}
};
Expand Down Expand Up @@ -498,7 +522,13 @@ MongoDB.prototype.execute = function(modelName, command) {

// Topology is destroyed when the server is disconnected
// Execute if DB is connected and functional otherwise connect/reconnect first
if (self.db && self.db.topology && !self.db.topology.isDestroyed()) {
if (
self.db && (
!self.db.topology || (self.db.topology && !self.db.topology.isDestroyed())
)
) {
doExecute();
} else if (self.db && !self.db.topology) {
doExecute();
} else {
if (self.db) {
Expand Down Expand Up @@ -545,7 +575,7 @@ MongoDB.prototype.execute = function(modelName, command) {
'execute',
context,
function(context, done) {
args[args.length - 1] = function(err, result) {
const observerCallback = function(err, result) {
if (err) {
debug('Error: ', err);
} else {
Expand All @@ -554,8 +584,23 @@ MongoDB.prototype.execute = function(modelName, command) {
}
done(err, result);
};
debug('MongoDB: model=%s command=%s', modelName, command, args);
return collection[command].apply(collection, 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);
}
} else {
args[args.length - 1] = observerCallback;
debug('MongoDB: model=%s command=%s', modelName, command, args);
return collection[command].apply(collection, args);
}
},
callback,
);
Expand Down Expand Up @@ -620,7 +665,7 @@ MongoDB.prototype.create = function(modelName, data, options, callback) {
if (err) {
return callback(err);
}
idValue = result.ops[0]._id;
idValue = result.insertedId;

try {
idValue = self.coerceId(modelName, idValue, options);
Expand Down Expand Up @@ -674,18 +719,13 @@ MongoDB.prototype.save = function(modelName, data, options, callback) {
}

const info = {};
if (result && result.result) {
// create result formats:
// { ok: 1, n: 1, upserted: [ [Object] ] }
// { ok: 1, nModified: 0, n: 1, upserted: [ [Object] ] }
//
// update result formats:
// { ok: 1, n: 1 }
// { ok: 1, nModified: 1, n: 1 }
if (result.result.ok === 1 && result.result.n === 1) {
info.isNewInstance = !!result.result.upserted;
if (result) {
// new 4.0 result formats:
// { acknowledged: true, modifiedCount: 1, upsertedCount: 1, : modifiedCount: 1}
if (result.acknowledged === true && (result.matchedCount === 1 || result.upsertedCount === 1)) {
info.isNewInstance = result.upsertedCount === 1;
} else {
debug('save result format not recognized: %j', result.result);
debug('save result format not recognized: %j', result);
}
}

Expand Down Expand Up @@ -854,7 +894,8 @@ MongoDB.prototype.updateOrCreate = function updateOrCreate(
data,
buildOptions({
upsert: true,
returnOriginal: false,
returnNewDocument: true,
returnDocument: 'after', // ensures new document gets returned
sort: [['_id', 'asc']],
}, options),
function(err, result) {
Expand Down Expand Up @@ -922,9 +963,9 @@ MongoDB.prototype.destroy = function destroy(modelName, id, options, callback) {
if (self.debug) {
debug('delete.callback', modelName, id, err, result);
}
let res = result && result.result;
let res = result;
if (res) {
res = {count: res.n};
res = {count: res.deletedCount};
}
if (callback) {
callback(err, res);
Expand Down Expand Up @@ -1523,7 +1564,7 @@ MongoDB.prototype.destroyAll = function destroyAll(

if (self.debug) debug('destroyAll.callback', modelName, where, err, info);

const affectedCount = info.result ? info.result.n : undefined;
const affectedCount = info ? info.deletedCount : undefined;

if (callback) {
callback(err, {count: affectedCount});
Expand Down Expand Up @@ -1614,7 +1655,7 @@ MongoDB.prototype.replaceWithOptions = function(modelName, id, data, options, cb
if (err) return cb && cb(err);
let result;
const cbInfo = {};
if (info.result && info.result.n == 1) {
if (info && (info.matchedCount === 1 || info.upsertedCount === 1)) {
result = self.fromDatabase(modelName, data);
delete result._id;
result[idName] = id;
Expand All @@ -1625,8 +1666,8 @@ MongoDB.prototype.replaceWithOptions = function(modelName, id, data, options, cb
// replace result formats:
// 2.4.x: { ok: 1, n: 1 }
// { ok: 1, nModified: 1, n: 1 }
if (info.result.nModified !== undefined) {
cbInfo.isNewInstance = info.result.nModified === 0;
if (info.modifiedCount !== undefined) {
cbInfo.isNewInstance = info.modifiedCount === 0;
}
} else {
result = undefined;
Expand Down Expand Up @@ -1754,7 +1795,7 @@ MongoDB.prototype.update = MongoDB.prototype.updateAll = function updateAll(
if (self.debug)
debug('updateAll.callback', modelName, where, updateData, err, info);

const affectedCount = info.result ? info.result.n : undefined;
const affectedCount = info ? info.matchedCount : undefined;

if (cb) {
cb(err, {count: affectedCount});
Expand Down Expand Up @@ -1805,7 +1846,8 @@ MongoDB.prototype.upsertWithWhere = function upsertWithWhere(
updateData,
buildOptions({
upsert: true,
returnOriginal: false,
returnNewDocument: true,
returnDocument: 'after', // ensures new documents get returned
sort: [['_id', 'asc']],
}, options),
function(err, result) {
Expand Down Expand Up @@ -2040,7 +2082,7 @@ MongoDB.prototype.automigrate = function(models, cb) {
);
if (
!(
err.name === 'MongoError' &&
err.name === 'MongoServerError' &&
err.ok === 0 &&
err.errmsg === 'ns not found'
)
Expand Down Expand Up @@ -2188,7 +2230,7 @@ function isObjectIDProperty(modelCtor, propDef, value, options) {
(Array.isArray(value) && value.every((v) => typeof v === 'string' && v.match(ObjectIdValueRegex)))) {
if (isStoredAsObjectID(propDef)) return true;
else return !isStrictObjectIDCoercionEnabled(modelCtor, options);
} else if (value instanceof mongodb.ObjectID) {
} else if (value instanceof mongodb.ObjectId) {
return true;
} else {
return false;
Expand Down Expand Up @@ -2285,7 +2327,7 @@ function optimizedFindOrCreate(modelName, filter, data, options, callback) {
let value = result.value;
const created = !!result.lastErrorObject.upserted;

if (created && (value == null || Object.keys(value).length == 0)) {
if (created && (value == null || Object.keys(value).length === 0)) {
value = data;
self.setIdValue(modelName, value, result.lastErrorObject.upserted);
} else {
Expand Down Expand Up @@ -2336,7 +2378,6 @@ function visitAllProperties(data, modelCtor, visitor) {
} else {
visitor(modelCtor, value, def, (newValue) => { data[p] = newValue; });
}
continue;
}
}

Expand Down
Loading

0 comments on commit d0e815b

Please sign in to comment.