Skip to content

Commit

Permalink
Merge pull request #36 from synatic/develop
Browse files Browse the repository at this point in the history
2.0.0 - added support for version 5 of the mongodb nodejs sdk
  • Loading branch information
thiren authored Jun 25, 2023
2 parents cafb2e7 + 37fc1bd commit 92e8452
Show file tree
Hide file tree
Showing 9 changed files with 154 additions and 212 deletions.
2 changes: 1 addition & 1 deletion .eslintrc.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@
"es6": true,
"mocha": true
},
"parserOptions": { "ecmaVersion": 2018 },
"extends": ["eslint:recommended", "google", "prettier"],
"globals": {},
"parserOptions": {},
"rules": {
"indent": ["error", 4, {"SwitchCase": 1}],
"max-len": ["off"],
Expand Down
11 changes: 8 additions & 3 deletions .github/workflows/ci-build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,15 +19,20 @@ jobs:
runs-on: ubuntu-latest
services:
mongo:
image: mongo:5
image: mongo:6.0
options: >-
--health-cmd mongosh
--health-interval 10s
--health-timeout 5s
--health-retries 5
ports:
- 27017:27017

steps:
- uses: actions/checkout@v3
- uses: actions/setup-node@v3
with:
node-version: 14
node-version: 18
registry-url: https://registry.npmjs.org/
# Skip post-install scripts here, as a malicious
# script could steal NODE_AUTH_TOKEN.
Expand All @@ -49,7 +54,7 @@ jobs:
- uses: actions/checkout@v3
- uses: actions/setup-node@v3
with:
node-version: 14
node-version: 18
registry-url: https://registry.npmjs.org/
# Skip post-install scripts here, as a malicious
# script could steal NODE_AUTH_TOKEN.
Expand Down
11 changes: 8 additions & 3 deletions .github/workflows/ci-npm-publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,20 @@ jobs:
runs-on: ubuntu-latest
services:
mongo:
image: mongo:5
image: mongo:6.0
options: >-
--health-cmd mongosh
--health-interval 10s
--health-timeout 5s
--health-retries 5
ports:
- 27017:27017

steps:
- uses: actions/checkout@v3
- uses: actions/setup-node@v3
with:
node-version: 14
node-version: 18
registry-url: https://registry.npmjs.org/
# Skip post-install scripts here, as a malicious
# script could steal NODE_AUTH_TOKEN.
Expand All @@ -40,7 +45,7 @@ jobs:
- uses: actions/checkout@v3
- uses: actions/setup-node@v3
with:
node-version: 14
node-version: 18
registry-url: https://registry.npmjs.org/
# Skip post-install scripts here, as a malicious
# script could steal NODE_AUTH_TOKEN.
Expand Down
124 changes: 66 additions & 58 deletions lib/Collection.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,8 @@ const _defaultQueryTimeoutMS = 120000;
* @typedef {import('mongodb').EstimatedDocumentCountOptions} EstimatedDocumentCountOptions
* @typedef {import('mongodb').CountDocumentsOptions} CountDocumentsOptions
* @typedef {import('mongodb').CountOptions} CountOptions
* @typedef {import('mongodb').FindOptions} FindOptions
* @typedef {import('mongodb').FindCursor} FindCursor
* @typedef {import('mongodb').CursorStreamOptions} CursorStreamOptions
* @typedef {import('stream').Readable} Readable
* @typedef {import('mongodb').Collection} Collection
*/

/** A wrapper around the mongodb collection with some helper functions
Expand All @@ -24,7 +21,7 @@ const _defaultQueryTimeoutMS = 120000;
class Collection {
/** Creates an instance of Collection.
*
* @param {Collection} collection - the underlying mongo collection
* @param {import('mongodb').Collection} collection - the underlying mongo collection
* @param {object} [options] - the query options
* @param {number} [options.queryTimeout] - the query timeout defaults to 120000ms
* @param {boolean} [options.estimatedDocumentCount] - use estimated document count when calling count
Expand All @@ -36,13 +33,27 @@ class Collection {
this._collection = collection;
}

/** Counts the documents in the collection
// todo: remove once
/**
* Counts the documents in the collection
* @deprecated in favour of using countDocuments
* @param {Object} query
* @param {EstimatedDocumentCountOptions | CountDocumentsOptions} [options={}]
* @param {Function} callback
* @returns {*}
* @return {*}
*/
count(query, options = {}, callback) {
this.countDocuments(query, options, callback);
}

/**
* Counts the documents in the collection
* @param {Object} query
* @param {EstimatedDocumentCountOptions | CountDocumentsOptions} [options={}]
* @param {Function} callback
* @return {*}
*/
countDocuments(query, options = {}, callback) {
if ($check.function(options)) {
callback = options;
options = {};
Expand All @@ -51,68 +62,63 @@ class Collection {
}
if (!$check.instanceStrict(query, MongoQuery)) return callback('Invalid query object');

const countRetrieved = (err, count) => {
if (err) return callback(err);
if (!count) return callback(null, 0);
else return callback(null, count);
};

const filter = query.parsedQuery.query || {};
try {
if (this._options.estimatedDocumentCount && this._collection.estimatedDocumentCount) {
this._collection.estimatedDocumentCount(options, countRetrieved);
} else if (this._collection.countDocuments) {
this._collection.countDocuments(filter, options, countRetrieved);
} else {
// todo: remove this once we've completed the mongodb package updates across all systems
this._collection.count(filter, options, countRetrieved);
}
} catch (exp) {
return callback(exp);
}
this._collection
.countDocuments(filter, options)
.then((count) => {
if (!count) {
return callback(null, 0);
}

return callback(null, count);
})
.catch(callback);
}

/** Creates a cursor given the MongoQuery Object
/**
* Creates a cursor given the MongoQuery Object
* @param {Object} query - the MongoQuery Object
* @param {FindOptions} [options={}]
* @returns {FindCursor}
* @param {import('mongodb').FindOptions} [options={}]
* @return {import('mongodb').FindCursor}
*/
queryAsCursor(query, options = {}) {
if (!$check.instanceStrict(query, MongoQuery)) throw new Error('Invalid query object');

const cur = this._collection.find(query.parsedQuery.query, options);
const filter = query.parsedQuery.query || {};
const cursor = this._collection.find(filter, options);

// top and limit
cur.limit(query.parsedQuery.limit);
cursor.limit(query.parsedQuery.limit);

// select
if (query.parsedQuery.select) cur.project(query.parsedQuery.select);
if (query.parsedQuery.projection) cur.project(query.parsedQuery.projection);
if (query.parsedQuery.select) cursor.project(query.parsedQuery.select);
if (query.parsedQuery.projection) cursor.project(query.parsedQuery.projection);

// sort
if (query.parsedQuery.sort) cur.sort(query.parsedQuery.sort);
if (query.parsedQuery.sort) cursor.sort(query.parsedQuery.sort);

// orderby
if (query.parsedQuery.orderby) cur.sort(query.parsedQuery.orderby);
if (query.parsedQuery.orderby) cursor.sort(query.parsedQuery.orderby);

// skip
if (query.parsedQuery.skip) cur.skip(query.parsedQuery.skip);
else cur.skip(0);
if (query.parsedQuery.skip) cursor.skip(query.parsedQuery.skip);
else cursor.skip(0);

if ($check.assigned(options.maxTimeMS)) {
cur.maxTimeMS(options.maxTimeMS);
cursor.maxTimeMS(options.maxTimeMS);
} else {
cur.maxTimeMS(this._options.queryTimeout);
cursor.maxTimeMS(this._options.queryTimeout);
}

return cur;
return cursor;
}

/** Executes the MongoQuery as an Array
/**
* Executes the MongoQuery as an Array
* @param {Object} query - the MongoQuery Object
* @param {FindOptions} [options={}]
* @param {Function} callback
* @returns {*}
* @param {import('mongodb').FindOptions} [options={}]
* @param {function} callback
* @return {*}
*/
query(query, options = {}, callback) {
if ($check.function(options)) {
Expand All @@ -123,40 +129,40 @@ class Collection {
}
if (!$check.instanceStrict(query, MongoQuery)) return callback('Invalid query object');
try {
const cur = this.queryAsCursor(query, options);
const cursor = this.queryAsCursor(query, options);

cur.toArray(function (err, results) {
if (err) {
return callback(err);
}
cursor.toArray().then((results)=>{
if (!results) {
return callback(null, []);
}
return callback(null, results);
}).catch((err) => {
return callback(err);
});
} catch (exp) {
return callback(exp);
}
}

/** Executes the MongoQuery as a stream
/**
* Executes the MongoQuery as a stream
* @param {Object} query - the MongoQuery Object
* @param {FindOptions} [options={}]
* @param {import('mongodb').FindOptions} [options={}]
* @param {CursorStreamOptions} [streamOptions={}]
* @returns {Readable}
* @return {import('stream').Readable}
* @memberof Collection
*/
queryAsStream(query, options = {}, streamOptions = {}) {
if (!$check.instanceStrict(query, MongoQuery)) throw new Error('Invalid query object');
const cur = this.queryAsCursor(query, options);
const cursor = this.queryAsCursor(query, options);

return cur.stream(streamOptions);
return cursor.stream(streamOptions);
}

/**
* @param {Object} options
* @param {Function} callback
* @returns {void}
* @param {function} callback
* @return {function}
* @memberof Collection
*/
updateStats(options, callback) {
Expand Down Expand Up @@ -190,12 +196,14 @@ class Collection {
update.$inc[dayPath + '.' + increment.field] = increment.value;
update.$inc[hourPath + '.' + increment.field] = increment.value;
}
this._collection.updateOne(options.query, update, callback);
this._collection.updateOne(options.query, update).then((result) => {
return callback(null, result);
}).catch(callback);
}

/** Gets the underlying MongoDB collection
*
* @return {*}
/**
* Gets the underlying MongoDB collection
* @return {import('mongodb').Collection}
*/
get collection() {
return this._collection;
Expand Down
21 changes: 10 additions & 11 deletions lib/Utils.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
const ObjectID = require('mongodb').ObjectId;
const {ObjectId} = require('mongodb');
const $check = require('check-types');
const $json = require('@synatic/json-magic');

Expand All @@ -11,7 +11,6 @@ const _unsafeAggregateFunctions = [
{name: '$merge', aggregate: true},
{name: '$out', aggregate: true},
{name: '$planCacheStats', aggregate: true},

{name: '$explain', aggregate: false},
{name: '$hint', aggregate: false},
{name: '$showDiskLoc', aggregate: false},
Expand All @@ -27,7 +26,7 @@ class Utils {
* @return {ObjectId}
*/
static generateId() {
return new ObjectID();
return new ObjectId();
}

/** Checks whether a provided id is a valid mongo id
Expand All @@ -40,18 +39,18 @@ class Utils {
return false;
}

if ($check.object(id) && id._bsontype === 'ObjectID' && Buffer.isBuffer(id.id) && id.id.length === 12) {
return ObjectID.isValid(id.id);
if ($check.object(id) && id._bsontype === 'ObjectId' && Buffer.isBuffer(id.id) && id.id.length === 12) {
return ObjectId.isValid(id.id);
}

if (id.toString().length !== 24) {
return false;
}

return ObjectID.isValid(id.toString());
return ObjectId.isValid(id.toString());
}

/** Parses a id to a mongodb ObjectID
/** Parses an id to a mongodb ObjectId
*
* @param {string|object} id - the mongo id to validate
* @return {null|ObjectId|boolean}
Expand All @@ -61,16 +60,16 @@ class Utils {
return false;
}

if ($check.object(id) && id._bsontype === 'ObjectID' && Buffer.isBuffer(id.id) && id.id.length === 12) {
return new ObjectID(id.id);
if ($check.object(id) && id._bsontype === 'ObjectId' && Buffer.isBuffer(id.id) && id.id.length === 12) {
return new ObjectId(id.id);
}

if (id.toString().length !== 24) {
return null;
}

if (ObjectID.isValid(id.toString())) {
return new ObjectID(id.toString());
if (ObjectId.isValid(id.toString())) {
return new ObjectId(id.toString());
}
}

Expand Down
Loading

0 comments on commit 92e8452

Please sign in to comment.