Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

moltyjs

Package Overview
Dependencies
Maintainers
1
Versions
71
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

moltyjs - npm Package Compare versions

Comparing version 0.5.1 to 0.6.0

.nyc_output/12941ba9999e40b98b709b4c5dec9699.json

14

CHANGELOG.md
## [Unreleased]
* Wrap results docs in moltyClass but not remove the metadata provided by MongoDB
* Add support to more pipeline stages in the aggregate function
* Fix english misspelling in the documentation.
* Populate documents with references to other documments.
* Add deleteOne() document

@@ -35,2 +35,13 @@ * Add embedded documents features

## [0.6.0] - 2018-01-02
### Added
* aggregate() function with support for $match, $project, and $lookup (without recursivity) stages pipeline
* Documentation about new aggreagte() function
### Fixed
* Error that cause wrong merging og prehooks, posthooks and methods of discriminated models.
## [0.5.1] - 2017-12-28

@@ -265,2 +276,3 @@

[0.6.0]: https://github.com/Yonirt/moltyjs/compare/v0.5.1...v0.6.0
[0.5.1]: https://github.com/Yonirt/moltyjs/compare/v0.5.0...v0.5.1

@@ -267,0 +279,0 @@ [0.5.0]: https://github.com/Yonirt/moltyjs/compare/v0.4.3...v0.5.0

'use strict';
var _slicedToArray = function () { function sliceIterator(arr, i) { var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i["return"]) _i["return"](); } finally { if (_d) throw _e; } } return _arr; } return function (arr, i) { if (Array.isArray(arr)) { return arr; } else if (Symbol.iterator in Object(arr)) { return sliceIterator(arr, i); } else { throw new TypeError("Invalid attempt to destructure non-iterable instance"); } }; }();
var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
var _slicedToArray = function () { function sliceIterator(arr, i) { var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i["return"]) _i["return"](); } finally { if (_d) throw _e; } } return _arr; } return function (arr, i) { if (Array.isArray(arr)) { return arr; } else if (Symbol.iterator in Object(arr)) { return sliceIterator(arr, i); } else { throw new TypeError("Invalid attempt to destructure non-iterable instance"); } }; }();
function _asyncToGenerator(fn) { return function () { var gen = fn.apply(this, arguments); return new Promise(function (resolve, reject) { function step(key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { return Promise.resolve(value).then(function (value) { step("next", value); }, function (err) { step("throw", err); }); } } return step("next"); }); }; }

@@ -26,3 +26,21 @@

// https://docs.mongodb.com/v3.4/reference/operator/update/
const validUpdateOperators = [
// Fields
'$currentDate', '$inc', '$min', '$max', '$mul', '$rename', '$set', '$setOnInsert', '$unset',
// Array
'$', '$addToSet', '$pop', '$pull', '$pushAll', '$push', '$pullAll',
// Modifiers
'$each', '$position', '$slice', '$sort',
// Bitwise
'$bit', '$isolated'];
// https://docs.mongodb.com/manual/reference/operator/aggregation-pipeline/
const validAggregateOperators = {
$match: [],
$lookup: ['from', 'localField', 'foreignField', 'as'],
$project: []
};
const defaultTenantsOptions = {

@@ -50,2 +68,4 @@ noListener: false,

const defaultAggregateOptions = {};
class MongoClient {

@@ -154,22 +174,23 @@ constructor() {

hooksList.forEach(key => {
switch (key.hook) {
case 'insertOne':
insertHooks.use(key.fn.bind(objectBinded, this, tenant));
break;
case 'insertMany':
insertManyHooks.use(key.fn.bind(objectBinded, this, tenant));
break;
case 'update':
updateHooks.use(key.fn.bind(objectBinded, this, tenant));
break;
case 'delete':
deleteHooks.use(key.fn.bind(objectBinded, this, tenant));
break;
default:
throw new Error('Hook "' + key.hook + '" is not allowed.');
break;
}
});
if (hooksList.length > 0) {
hooksList.forEach(key => {
switch (key.hook) {
case 'insertOne':
insertHooks.use(key.fn.bind(objectBinded, this, tenant));
break;
case 'insertMany':
insertManyHooks.use(key.fn.bind(objectBinded, this, tenant));
break;
case 'update':
updateHooks.use(key.fn.bind(objectBinded, this, tenant));
break;
case 'delete':
deleteHooks.use(key.fn.bind(objectBinded, this, tenant));
break;
default:
throw new Error('Hook "' + key.hook + '" is not allowed.');
break;
}
});
}
return {

@@ -189,12 +210,2 @@ insertOne: insertHooks,

_validateUpdateOperators(payload) {
// https://docs.mongodb.com/v3.4/reference/operator/update/
const validUpdateOperators = [
// Fields
'$currentDate', '$inc', '$min', '$max', '$mul', '$rename', '$set', '$setOnInsert', '$unset',
// Array
'$', '$addToSet', '$pop', '$pull', '$pushAll', '$push', '$pullAll',
// Modifiers
'$each', '$position', '$slice', '$sort',
// Bitwise
'$bit', '$isolated'];
Object.keys(payload).forEach(operator => {

@@ -204,3 +215,2 @@ if (validUpdateOperators.indexOf(operator) < 0) {

}
return;
});

@@ -210,2 +220,59 @@ }

/**
* _validateAndIndexAggregateOperators(): Check if the aggregate operators
* are correct and supported
*
* @param {Object} pipeline
*/
_validateAndIndexAggregateOperators(pipeline) {
let operatorIndexes = {};
let i = 0;
var _iteratorNormalCompletion = true;
var _didIteratorError = false;
var _iteratorError = undefined;
try {
for (var _iterator = pipeline[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
let stage = _step.value;
Object.keys(stage).forEach(operator => {
// Save the position of all
if (!operatorIndexes[operator]) operatorIndexes = _extends({}, operatorIndexes, { [operator]: [i] });else operatorIndexes = _extends({}, operatorIndexes, {
[operator]: [operator].push(i)
});
if (Object.keys(validAggregateOperators).indexOf(operator) < 0) {
throw new Error('The aggregate operator is not allowed, got: ' + operator);
}
// If the aggregate operator has additional parameters let's check
// which we support
if (validAggregateOperators[operator].length > 0) {
Object.keys(stage[operator]).forEach(suboperator => {
if (validAggregateOperators[operator].indexOf(suboperator) < 0) {
throw new Error('The paramater ' + suboperator + ' in ' + operator + ' aggreagate operator is not allowed');
}
});
}
});
i++;
}
} catch (err) {
_didIteratorError = true;
_iteratorError = err;
} finally {
try {
if (!_iteratorNormalCompletion && _iterator.return) {
_iterator.return();
}
} finally {
if (_didIteratorError) {
throw _iteratorError;
}
}
}
return operatorIndexes;
}
/**
* _validatePayload(): Check if the payload is valid based on the model schema

@@ -593,8 +660,7 @@ *

try {
// Get the Cursor
const cursor = conn.db(tenant, _this3._tenantsOptions).collection(collection).find(query);
// Run the cursor
var _ref8 = yield to(cursor.limit(findOptions.limit).project(findOptions.projection).toArray()),
// Get and run the Cursor
var _ref8 = yield to(conn.db(tenant, _this3._tenantsOptions).collection(collection).find(query, {
limit: findOptions.limit,
projection: findOptions.projection
}).toArray()),
_ref9 = _slicedToArray(_ref8, 2);

@@ -605,2 +671,10 @@

// Run the cursor
// http://mongodb.github.io/node-mongodb-native/3.0/api/Cursor.html
/*const [error, result] = await to(
cursor
.limit(findOptions.limit)
.project(findOptions.projection)
.toArray(),
);*/

@@ -659,2 +733,5 @@ if (error) {

// Check update operators
_this4._validateUpdateOperators(payload);
// If we are updating a resources in a discriminator model

@@ -682,5 +759,2 @@ // we have to set the proper filter and addres to the parent collection

// Check update operators
_this4._validateUpdateOperators(payload);
// Validate the payload

@@ -737,11 +811,12 @@ _this4._validatePayload(payload, model._schemaNormalized);

/**
* createIndexes(): Creates indexes on the db and collection collection
* aggregate(): Execute an aggregation framework pipeline against the collection.
*
* @param {String} tenant
* @param {String} collection
* @param [{String}] fields
* @param {Object[]} pipeline Array containing all the aggregation framework commands for the execution
* @param {Object} options Optional settings.
*
* @returns {Promise}
*/
createIndexes(tenant, collection, fields) {
aggregate(tenant, collection, pipeline = [], options = {}) {
var _this5 = this;

@@ -752,7 +827,52 @@

if (!collection && typeof collection != 'string') throw new Error('Should specify the collection name (String), got: ' + collection);
if (!fields && typeof fields != 'object') throw new Error('Should specify the field name (Array), got: ' + fields);
// Checking if indexes are already set for this tenant and this collection
if (_this5.tenants[tenant] && _this5.tenants[tenant][collection]) return;
// Check aggregate operators
const operatorsIndexes = _this5._validateAndIndexAggregateOperators(pipeline);
// Assign default options to perform the aggregate query
const aggregateOptions = Object.assign({}, defaultAggregateOptions, options);
// If we are looking for resources in a discriminator model
// we have to set the proper filter and address to the parent collection
let model = {};
if (_this5.models[collection]) {
const _discriminator = _this5.models[collection]._discriminator;
if (_discriminator) {
const discriminatorKey = _this5.models[collection]._schemaOptions.inheritOptions.discriminatorKey;
if (pipeline[0]['$match'].discriminatorKey) throw new Error('You can not include a specific value for the "discriminatorKey" on the query.');
pipeline[0]['$match'] = _extends({}, pipeline[0]['$match'], {
[discriminatorKey]: collection
});
}
model = _this5.models[collection];
collection = _this5.models[collection]._modelName;
} else {
throw new Error('The collection ' + collection + 'does not exist and is not registered.');
}
// Check if there is a $lookup operator in the pipeline with
// discriminated models pointing out
if (operatorsIndexes['$lookup']) {
for (let i = 0; i < operatorsIndexes['$lookup'].length; i++) {
let lookup = pipeline[operatorsIndexes['$lookup'][i]].$lookup;
if (_this5.models[lookup.from]) {
const _discriminator = _this5.models[lookup.from]._discriminator;
if (_discriminator) {
lookup.from = _this5.models[lookup.from]._modelName;
}
}
}
}
// Ensure index are created
if (_this5._indexes[collection] && _this5._indexes[collection].length > 0) {
yield _this5.createIndexes(tenant, collection, _this5._indexes[collection]);
}
// Acquiring db instance

@@ -764,6 +884,5 @@ const conn = yield _this5._connectionManager.acquire();

try {
// Ensure there are no indexes yet
yield to(conn.db(tenant, _this5._tenantsOptions).collection(collection).dropIndexes());
var _ref14 = yield to(conn.db(tenant, _this5._tenantsOptions).collection(collection).createIndexes(fields)),
// Get and run the Cursor
var _ref14 = yield to(conn.db(tenant, _this5._tenantsOptions).collection(collection).aggregate(pipeline, {}) //{} = aggregateOptions
.toArray()),
_ref15 = _slicedToArray(_ref14, 2);

@@ -774,2 +893,10 @@

// Run the cursor
// http://mongodb.github.io/node-mongodb-native/3.0/api/Cursor.html
/*const [error, result] = await to(
cursor
.limit(findOptions.limit)
.project(findOptions.projection)
.toArray(),
);*/

@@ -779,8 +906,27 @@ if (error) {

} else {
// Set Indexes for this tenant and this collection are already set
_this5.tenants[tenant] = _extends({}, _this5.tenants[tenant], {
[collection]: true
});
resolve(result);
if (result) {
if (aggregateOptions.moltyClass) {
/* const Document = require('../document');
let docs = [];
result.forEach(doc => {
docs.push(
new Document(
doc,
model._preHooks,
model._postHooks,
model._methods,
model._schemaOptions,
model._modelName,
model._discriminator,
),
);
});
resolve(docs);*/
resolve(result);
} else {
resolve(result);
}
} else {
resolve(result);
}
}

@@ -802,3 +948,3 @@ } catch (error) {

/**
* dropDatabase(): Drop a database, removing it permanently from the server.
* createIndexes(): Creates indexes on the db and collection collection
*

@@ -811,3 +957,3 @@ * @param {String} tenant

*/
dropDatabase(tenant) {
createIndexes(tenant, collection, fields) {
var _this6 = this;

@@ -817,3 +963,8 @@

if (!tenant && typeof tenant != 'string') throw new Error('Should specify the tenant name (String), got: ' + tenant);
if (!collection && typeof collection != 'string') throw new Error('Should specify the collection name (String), got: ' + collection);
if (!fields && typeof fields != 'object') throw new Error('Should specify the field name (Array), got: ' + fields);
// Checking if indexes are already set for this tenant and this collection
if (_this6.tenants[tenant] && _this6.tenants[tenant][collection]) return;
// Acquiring db instance

@@ -825,3 +976,6 @@ const conn = yield _this6._connectionManager.acquire();

try {
var _ref17 = yield to(conn.db(tenant, _this6._tenantsOptions).dropDatabase()),
// Ensure there are no indexes yet
yield to(conn.db(tenant, _this6._tenantsOptions).collection(collection).dropIndexes());
var _ref17 = yield to(conn.db(tenant, _this6._tenantsOptions).collection(collection).createIndexes(fields)),
_ref18 = _slicedToArray(_ref17, 2);

@@ -836,2 +990,7 @@

} else {
// Set Indexes for this tenant and this collection are already set
_this6.tenants[tenant] = _extends({}, _this6.tenants[tenant], {
[collection]: true
});
resolve(result);

@@ -852,4 +1011,51 @@ }

}
/**
* dropDatabase(): Drop a database, removing it permanently from the server.
*
* @param {String} tenant
* @param {String} collection
* @param [{String}] fields
*
* @returns {Promise}
*/
dropDatabase(tenant) {
var _this7 = this;
return _asyncToGenerator(function* () {
if (!tenant && typeof tenant != 'string') throw new Error('Should specify the tenant name (String), got: ' + tenant);
// Acquiring db instance
const conn = yield _this7._connectionManager.acquire();
return new Promise((() => {
var _ref19 = _asyncToGenerator(function* (resolve, reject) {
try {
var _ref20 = yield to(conn.db(tenant, _this7._tenantsOptions).dropDatabase()),
_ref21 = _slicedToArray(_ref20, 2);
const error = _ref21[0],
result = _ref21[1];
if (error) {
reject(error);
} else {
resolve(result);
}
} catch (error) {
reject(error);
} finally {
return yield _this7._connectionManager.release(conn);
}
});
return function (_x13, _x14) {
return _ref19.apply(this, arguments);
};
})());
})();
}
}
module.exports = new MongoClient();

23

lib/model.js

@@ -156,12 +156,2 @@ 'use strict';

let schema = {
methods: {},
_preHooks: {},
_postHooks: {},
_schema: {},
_options: {}
};
schema._options = schemaDiscriminator._options;
if (merge && merge.indexOf('methods') >= 0) {

@@ -172,17 +162,18 @@ Object.keys(schemaDiscriminator.methods).forEach(key => {

schema.methods = Object.assign({}, this._methods, schemaDiscriminator.methods);
Object.assign(schemaDiscriminator.methods, this._methods);
}
if (merge && merge.indexOf('preHooks') >= 0) {
schema._preHooks = this._preHooks.concat(schemaDiscriminator._preHooks);
schemaDiscriminator._preHooks = this._preHooks.concat(schemaDiscriminator._preHooks);
}
if (merge && merge.indexOf('postHooks') >= 0) {
schema._postHooks = this._postHooks.concat(schemaDiscriminator._postHooks);
schemaDiscriminator._postHooks = this._postHooks.concat(schemaDiscriminator._postHooks);
}
schema._schema = Object.assign({}, this._schemaNormalized, schemaDiscriminator._schema);
Object.assign(schemaDiscriminator._schema, this._schemaNormalized);
this._validateDiscriminatorName(childDiscriminatorKey, schema._schema);
this._validateDiscriminatorName(childDiscriminatorKey, schemaDiscriminator._schema);
const discriminatorModel = new Model(schema, this._modelName, discriminatorModelName);
const discriminatorModel = new Model(schemaDiscriminator, this._modelName, discriminatorModelName);

@@ -189,0 +180,0 @@ if (this._childsModels[discriminatorModelName]) throw new Error('There is already model discriminator with the same name: ' + discriminatorModelName);

{
"name": "moltyjs",
"version": "0.5.1",
"version": "0.6.0",
"description": "A tiny ODM for MongoDB with multy tenancy support.",

@@ -9,2 +9,3 @@ "main": "lib/index.js",

"build": "babel src -d lib",
"test:coverage": "\"nyc --reporter=html --reporter=text npm run test\"",
"test:watch": "\"npm run test -- --watch\"",

@@ -42,3 +43,3 @@ "test": "mocha \"./{,!(node_modules)/**/}*.test.js\" --require babel-core/register --require babel-polyfill --recursive --reporter spec --timeout 5000 --exit",

"np": "^2.18.2",
"npm": "^5.6.0",
"nyc": "^11.4.1",
"watch": "^1.0.2"

@@ -45,0 +46,0 @@ },

@@ -94,2 +94,6 @@ [![npm version](https://badge.fury.io/js/moltyjs.svg)](https://badge.fury.io/js/moltyjs)

},
tests: {
type: [Schema.types().ObjectId],
ref: 'ReferenceSchema',
},
},

@@ -441,2 +445,11 @@ {

* {String} `tanant` Tenant name
* {String} `collection` Collection name
* {Object} `query` Query object
* {Object} `options` Optional settings
* {Boolean} `moltyClass` (true by default) True if you want the results as MoltyJs Document class
instead of MongoDB Document
* {Number} `limit` (0 by default: no limit) Limit the results to the amount specified
* {Object} `projection` (null by default) Create a projection of a field, the projection document limits the fields to return for all matching documents
```javascript

@@ -456,2 +469,45 @@ const resUpdate = await connection.updateOne(

## Aggregate
Aggregation operations group values from multiple documents together, and can perform a variety of operations on the grouped data to return a single result.
### `aggregate(tenant, collection, pipeline = [], options = {}) {Promise}`
* {String} `tanant` Tenant name
* {String} `collection` Collection name
* {Object[]} `pipeline` Array containing all the aggregation framework commands for the execution.
* Pipeline stages supported [(use the same syntax as MongoDB Native Driver)](https://docs.mongodb.com/manual/reference/operator/aggregation-pipeline/):
* $match
* $lookup
* $project
* {Object} `options` Optional settings
* "There is no options supported yet"
```javascript
const pipeline = [
{
$match: {
_id: newDoc._data._id,
},
},
{
$lookup: {
from: 'ReferenceSchema',
localField: 'tests',
foreignField: '_id',
as: 'models',
},
},
{
$project: {
_id: 0,
tests: 1,
},
},
];
const aggregate = await connection.aggregate('tenant_test', 'TestModel', pipeline, {});
// {Result} || Error
```
Updating a document support all the [update operators](https://docs.mongodb.com/v3.4/reference/operator/update/) from MongoDB
SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc