Skip to content

Commit cde11ec

Browse files
author
Thomas Reggi
authored
fix: pass optional promise lib to maybePromise
passes `promiseLibrary` option from `MongoClient` to `maybePromise` function and removes `devDependency` `bluebird`. NODE-2490
1 parent 0c36a32 commit cde11ec

File tree

8 files changed

+114
-60
lines changed

8 files changed

+114
-60
lines changed

lib/cursor.js

+4-6
Original file line numberDiff line numberDiff line change
@@ -197,7 +197,7 @@ class Cursor extends CoreCursor {
197197
throw MongoError.create({ message: 'Cursor is closed', driver: true });
198198
}
199199

200-
return maybePromise(callback, cb => {
200+
return maybePromise(this, callback, cb => {
201201
const cursor = this;
202202
if (cursor.isNotified()) {
203203
return cb(null, false);
@@ -230,7 +230,7 @@ class Cursor extends CoreCursor {
230230
* @return {Promise} returns Promise if no callback passed
231231
*/
232232
next(callback) {
233-
return maybePromise(callback, cb => {
233+
return maybePromise(this, callback, cb => {
234234
const cursor = this;
235235
if (cursor.s.state === CursorState.CLOSED || (cursor.isDead && cursor.isDead())) {
236236
cb(MongoError.create({ message: 'Cursor is closed', driver: true }));
@@ -819,8 +819,7 @@ class Cursor extends CoreCursor {
819819
driver: true
820820
});
821821
}
822-
823-
return maybePromise(callback, cb => {
822+
return maybePromise(this, callback, cb => {
824823
const cursor = this;
825824
const items = [];
826825

@@ -1047,8 +1046,7 @@ class Cursor extends CoreCursor {
10471046
if (this.cmd.readConcern) {
10481047
delete this.cmd['readConcern'];
10491048
}
1050-
1051-
return maybePromise(callback, cb => {
1049+
return maybePromise(this, callback, cb => {
10521050
CoreCursor.prototype._next.apply(this, [cb]);
10531051
});
10541052
}

lib/mongo_client.js

+3-9
Original file line numberDiff line numberDiff line change
@@ -157,18 +157,12 @@ function MongoClient(url, options) {
157157
this.s = {
158158
url: url,
159159
options: options || {},
160-
promiseLibrary: null,
160+
promiseLibrary: (options && options.promiseLibrary) || Promise,
161161
dbCache: new Map(),
162162
sessions: new Set(),
163163
writeConcern: WriteConcern.fromOptions(options),
164164
namespace: new MongoDBNamespace('admin')
165165
};
166-
167-
// Get the promiseLibrary
168-
const promiseLibrary = this.s.options.promiseLibrary || Promise;
169-
170-
// Add the promise to the internal state
171-
this.s.promiseLibrary = promiseLibrary;
172166
}
173167

174168
/**
@@ -214,7 +208,7 @@ MongoClient.prototype.connect = function(callback) {
214208
}
215209

216210
const client = this;
217-
return maybePromise(callback, cb => {
211+
return maybePromise(this, callback, cb => {
218212
const err = validOptions(client.s.options);
219213
if (err) return cb(err);
220214

@@ -244,7 +238,7 @@ MongoClient.prototype.close = function(force, callback) {
244238
}
245239

246240
const client = this;
247-
return maybePromise(callback, cb => {
241+
return maybePromise(this, callback, cb => {
248242
const completeClose = err => {
249243
client.emit('close', client);
250244

lib/utils.js

+8-3
Original file line numberDiff line numberDiff line change
@@ -696,14 +696,19 @@ function* makeCounter(seed) {
696696
/**
697697
* Helper function for either accepting a callback, or returning a promise
698698
*
699-
* @param {Function} [callback] an optional callback.
699+
* @param {Object} parent an instance of parent with promiseLibrary.
700+
* @param {object} parent.s an object containing promiseLibrary.
701+
* @param {function} parent.s.promiseLibrary an object containing promiseLibrary.
702+
* @param {[Function]} callback an optional callback.
700703
* @param {Function} fn A function that takes a callback
701704
* @returns {Promise|void} Returns nothing if a callback is supplied, else returns a Promise.
702705
*/
703-
function maybePromise(callback, fn) {
706+
function maybePromise(parent, callback, fn) {
707+
const PromiseLibrary = (parent && parent.s && parent.s.promiseLibrary) || Promise;
708+
704709
let result;
705710
if (typeof callback !== 'function') {
706-
result = new Promise((resolve, reject) => {
711+
result = new PromiseLibrary((resolve, reject) => {
707712
callback = (err, res) => {
708713
if (err) return reject(err);
709714
resolve(res);

package.json

-1
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,6 @@
3131
"safe-buffer": "^5.1.2"
3232
},
3333
"devDependencies": {
34-
"bluebird": "3.5.0",
3534
"chai": "^4.1.1",
3635
"chai-subset": "^1.6.0",
3736
"chalk": "^2.4.2",

test/functional/byo_promises.test.js

+76-32
Original file line numberDiff line numberDiff line change
@@ -1,37 +1,81 @@
11
'use strict';
2+
3+
const maybePromise = require('./../../lib/utils').maybePromise;
24
var expect = require('chai').expect;
35

4-
describe('BYO Promises', function() {
5-
it('should Correctly Use Blurbird promises library', {
6-
metadata: {
7-
requires: {
8-
topology: ['single', 'ssl', 'wiredtiger']
9-
}
10-
},
11-
12-
// The actual test we wish to run
13-
test: function(done) {
14-
var self = this;
15-
const configuration = this.configuration;
16-
var Promise = require('bluebird');
17-
18-
const client = configuration.newClient(
19-
{},
20-
{
21-
promiseLibrary: Promise,
22-
sslValidate: false
23-
}
24-
);
25-
26-
client.connect().then(function(client) {
27-
var db = client.db(self.configuration.db);
28-
var promise = db.collection('test').insert({ a: 1 });
29-
expect(promise).to.be.an.instanceOf(Promise);
30-
31-
promise.then(function() {
32-
client.close(done);
33-
});
34-
});
35-
}
6+
class CustomPromise extends Promise {}
7+
CustomPromise.prototype.isCustomMongo = true;
8+
9+
const parent = { s: { promiseLibrary: CustomPromise } };
10+
11+
describe('Optional PromiseLibrary / maybePromise', function() {
12+
it('should correctly implement custom dependency-less promise', function(done) {
13+
const getCustomPromise = v => new CustomPromise(resolve => resolve(v));
14+
const getNativePromise = v => new Promise(resolve => resolve(v));
15+
expect(getNativePromise()).to.not.have.property('isCustomMongo');
16+
expect(getCustomPromise()).to.have.property('isCustomMongo');
17+
expect(getNativePromise()).to.have.property('then');
18+
expect(getCustomPromise()).to.have.property('then');
19+
done();
20+
});
21+
22+
it('should return a promise with extra property CustomMongo', function() {
23+
const prom = maybePromise(parent, undefined, () => 'example');
24+
expect(prom).to.have.property('isCustomMongo');
25+
expect(prom).to.have.property('then');
26+
});
27+
28+
it('should return a native promise with no parent', function(done) {
29+
const prom = maybePromise(undefined, undefined, () => 'example');
30+
expect(prom).to.not.have.property('isCustomMongo');
31+
expect(prom).to.have.property('then');
32+
done();
33+
});
34+
35+
it('should return a native promise with empty parent', function(done) {
36+
const prom = maybePromise({}, undefined, () => 'example');
37+
expect(prom).to.not.have.property('isCustomMongo');
38+
expect(prom).to.have.property('then');
39+
done();
40+
});
41+
42+
it('should return a native promise with emtpy "s"', function(done) {
43+
const prom = maybePromise({ s: {} }, undefined, () => 'example');
44+
expect(prom).to.not.have.property('isCustomMongo');
45+
expect(prom).to.have.property('then');
46+
done();
47+
});
48+
49+
it('should have cursor return native promise', function(done) {
50+
const configuration = this.configuration;
51+
const client = this.configuration.newClient({ w: 1 }, { poolSize: 1 });
52+
client.connect((err, client) => {
53+
expect(err).to.not.exist;
54+
const db = client.db(configuration.db);
55+
const collection = db.collection('test');
56+
const cursor = collection.find({});
57+
const isPromise = cursor.toArray();
58+
expect(isPromise).to.not.have.property('isCustomMongo');
59+
expect(isPromise).to.have.property('then');
60+
isPromise.then(() => client.close(done));
61+
});
62+
});
63+
64+
it('should have cursor return custom promise from new client options', function(done) {
65+
const configuration = this.configuration;
66+
const client = this.configuration.newClient(
67+
{ w: 1 },
68+
{ poolSize: 1, promiseLibrary: CustomPromise }
69+
);
70+
client.connect((err, client) => {
71+
const db = client.db(configuration.db);
72+
expect(err).to.be.null;
73+
const collection = db.collection('test');
74+
const cursor = collection.find({});
75+
const isPromise = cursor.toArray();
76+
expect(isPromise).to.have.property('isCustomMongo');
77+
expect(isPromise).to.have.property('then');
78+
isPromise.then(() => client.close(done));
79+
});
3680
});
3781
});

test/functional/promises_db.test.js

+5-3
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,9 @@ var test = require('./shared').assert;
33
var setupDatabase = require('./shared').setupDatabase;
44
var f = require('util').format;
55

6+
class CustomPromise extends Promise {}
7+
CustomPromise.prototype.isCustomMongo = true;
8+
69
describe('Promises (Db)', function() {
710
before(function() {
811
return setupDatabase(this.configuration);
@@ -373,7 +376,7 @@ describe('Promises (Db)', function() {
373376
}
374377
});
375378

376-
it('Should correctly execute createCollection using passed down bluebird Promise', {
379+
it('Should correctly execute createCollection using passed down CustomPromise Promise', {
377380
metadata: {
378381
requires: {
379382
topology: ['single']
@@ -384,9 +387,8 @@ describe('Promises (Db)', function() {
384387
test: function(done) {
385388
var configuration = this.configuration;
386389
var db = null;
387-
var BlueBird = require('bluebird');
388390

389-
const client = configuration.newClient({}, { promiseLibrary: BlueBird });
391+
const client = configuration.newClient({}, { promiseLibrary: CustomPromise });
390392
client
391393
.connect()
392394
.then(function() {

test/functional/spec-runner/index.js

+13-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
'use strict';
2-
const Promise = require('bluebird');
2+
33
const path = require('path');
44
const fs = require('fs');
55
const chai = require('chai');
@@ -14,6 +14,17 @@ chai.config.includeStack = true;
1414
chai.config.showDiff = true;
1515
chai.config.truncateThreshold = 0;
1616

17+
// Promise.try alternative https://stackoverflow.com/questions/60624081/promise-try-without-bluebird/60624164?noredirect=1#comment107255389_60624164
18+
function promiseTry(callback) {
19+
return new Promise((resolve, reject) => {
20+
try {
21+
resolve(callback());
22+
} catch (e) {
23+
reject(e);
24+
}
25+
});
26+
}
27+
1728
function escape(string) {
1829
return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
1930
}
@@ -571,7 +582,7 @@ function testOperation(operation, obj, context, options) {
571582
opPromise = cursor.toArray();
572583
} else {
573584
// wrap this in a `Promise.try` because some operations might throw
574-
opPromise = Promise.try(() => obj[operationName].apply(obj, args));
585+
opPromise = promiseTry(() => obj[operationName].apply(obj, args));
575586
}
576587

577588
if (operation.error) {

test/unit/cmap/connection_pool.test.js

+5-4
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
'use strict';
22

3-
const Promise = require('bluebird');
43
const loadSpecTests = require('../../spec').loadSpecTests;
54
const ConnectionPool = require('../../../lib/cmap/connection_pool').ConnectionPool;
65
const EventEmitter = require('events').EventEmitter;
76
const mock = require('mongodb-mock-server');
87
const BSON = require('bson');
8+
const util = require('util');
99
const cmapEvents = require('../../../lib/cmap/events');
1010

1111
const chai = require('chai');
@@ -26,8 +26,8 @@ const ALL_POOL_EVENTS = new Set([
2626
]);
2727

2828
const PROMISIFIED_POOL_FUNCTIONS = {
29-
checkOut: Promise.promisify(ConnectionPool.prototype.checkOut),
30-
close: Promise.promisify(ConnectionPool.prototype.close)
29+
checkOut: util.promisify(ConnectionPool.prototype.checkOut),
30+
close: util.promisify(ConnectionPool.prototype.close)
3131
};
3232

3333
function closePool(pool) {
@@ -379,14 +379,15 @@ describe('Connection Pool', function() {
379379
return p
380380
.then(() => {
381381
const connectionsToDestroy = Array.from(orphans).concat(Array.from(connections.values()));
382-
return Promise.each(connectionsToDestroy, conn => {
382+
const promises = connectionsToDestroy.map(conn => {
383383
return new Promise((resolve, reject) =>
384384
conn.destroy({ force: true }, err => {
385385
if (err) return reject(err);
386386
resolve();
387387
})
388388
);
389389
});
390+
return Promise.all(promises);
390391
})
391392
.then(() => {
392393
pool = undefined;

0 commit comments

Comments
 (0)