Comparing version 0.8.2 to 0.8.3
@@ -34,2 +34,16 @@ ## [Unreleased] | ||
## [0.8.3] - 2018-01-23 | ||
### Added | ||
* Support for multiple join conditions with $lookup operator in the aggregate() method | ||
### Changed | ||
* Validation payload method on updated() action, now is used the same from the Model itself. | ||
### Fixed | ||
* Bug in aggregate() method for discriminated models | ||
## [0.8.2] - 2018-01-22 | ||
@@ -384,2 +398,3 @@ | ||
[0.8.3]: https://github.com/Yonirt/moltyjs/compare/v0.8.2...v0.8.3 | ||
[0.8.2]: https://github.com/Yonirt/moltyjs/compare/v0.8.1...v0.8.2 | ||
@@ -386,0 +401,0 @@ [0.8.1]: https://github.com/Yonirt/moltyjs/compare/v0.8.0...v0.8.1 |
'use strict'; | ||
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"); } }; }(); | ||
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; }; | ||
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"); }); }; } | ||
@@ -41,3 +41,3 @@ | ||
$match: [], | ||
$lookup: ['from', 'localField', 'foreignField', 'as'], | ||
$lookup: ['from', 'localField', 'foreignField', 'as', 'let', 'pipeline'], | ||
$project: [] | ||
@@ -219,3 +219,17 @@ }; | ||
/** | ||
* _validateAndIndexAggregateOperators(): Check if the aggregate operators | ||
* _validateUpdatePayload(): Validate update payload | ||
*/ | ||
_validateUpdatePayload(payload, model) { | ||
return _asyncToGenerator(function* () { | ||
let validations = []; | ||
Object.keys(payload).forEach(function (operator) { | ||
validations.push(model.validatePayloadFieldValues(payload[operator], model._schemaNormalized, payload[operator], operator)); | ||
}); | ||
validations = yield Promise.all(validations); | ||
})(); | ||
} | ||
/** | ||
* _validateAggregateOperators(): Check if the aggregate operators | ||
* are correct and supported | ||
@@ -225,5 +239,3 @@ * | ||
*/ | ||
_validateAndIndexAggregateOperators(pipeline) { | ||
let operatorIndexes = {}; | ||
let i = 0; | ||
_validateAggregateOperators(pipeline) { | ||
var _iteratorNormalCompletion = true; | ||
@@ -238,7 +250,2 @@ var _didIteratorError = false; | ||
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) { | ||
@@ -257,4 +264,7 @@ throw new Error('The aggregate operator is not allowed, got: ' + operator); | ||
} | ||
if (operator === '$lookup' && stage['$lookup']['pipeline']) { | ||
return this._validateAggregateOperators(stage['$lookup']['pipeline']); | ||
} | ||
}); | ||
i++; | ||
} | ||
@@ -275,64 +285,70 @@ } catch (err) { | ||
} | ||
return operatorIndexes; | ||
} | ||
/** | ||
* _validatePayload(): Check if the payload is valid based on the model schema | ||
* _normalizeAggregatePipeline(): Normalize $looup stages in the aggregate | ||
* pipeline in case of discriminated models | ||
* | ||
* @params {Object} payload | ||
* @params {Object} schema | ||
* @param {Object} pipeline | ||
* | ||
* @returns {Boolean} | ||
* @returns {Array} | ||
*/ | ||
_validatePayload(payload, schema) { | ||
Object.keys(payload).forEach(operator => { | ||
Object.keys(payload[operator]).forEach(key => { | ||
let value = payload[operator][key]; | ||
_normalizeAggregatePipeline(pipeline, parentDiscriminator) { | ||
var _iteratorNormalCompletion2 = true; | ||
var _didIteratorError2 = false; | ||
var _iteratorError2 = undefined; | ||
if (schema[key] === undefined) { | ||
throw new Error('Field name ' + key + ' does not correspond to any field name on the schema'); | ||
} | ||
try { | ||
for (var _iterator2 = pipeline[Symbol.iterator](), _step2; !(_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done); _iteratorNormalCompletion2 = true) { | ||
let stage = _step2.value; | ||
// Objects nested | ||
if (!schema[key].type && isObject(value)) { | ||
return this._validatePayload(value, schema[key]); | ||
} | ||
Object.keys(stage).forEach(operator => { | ||
if (operator === '$lookup') { | ||
// Check if there is a $lookup operator in the pipeline with | ||
// discriminated models pointing out | ||
// Validation type | ||
if (!isValidType(value, schema[key].type)) { | ||
throw new Error('Unsuported value (' + value + ') for type ' + schema[key].type); | ||
} | ||
let _discriminator = null; | ||
let lookupFrom = stage['$lookup'].from; | ||
if (this.models[lookupFrom]) { | ||
_discriminator = this.models[lookupFrom]._discriminator; | ||
if (_discriminator) { | ||
stage['$lookup'].from = this.models[lookupFrom]._modelName; | ||
} | ||
} | ||
// Reg exp validation | ||
if (schema[key].match && isString(value) && !schema[key].match.test(value)) { | ||
throw new Error('Value assigned to ' + key + ' does not match the regex/string ' + schema[key].match.toString() + '. Value was ' + value); | ||
if (stage['$lookup']['pipeline']) { | ||
return this._normalizeAggregatePipeline(stage['$lookup']['pipeline'], _discriminator); | ||
} | ||
} | ||
}); | ||
} | ||
} catch (err) { | ||
_didIteratorError2 = true; | ||
_iteratorError2 = err; | ||
} finally { | ||
try { | ||
if (!_iteratorNormalCompletion2 && _iterator2.return) { | ||
_iterator2.return(); | ||
} | ||
// Enum validation | ||
if (!isInEnum(schema[key].enum, value)) { | ||
throw new Error('Value assigned to ' + key + ' should be in enum [' + schema[key].enum.join(', ') + '], got ' + value); | ||
} finally { | ||
if (_didIteratorError2) { | ||
throw _iteratorError2; | ||
} | ||
} | ||
} | ||
// Min value validation | ||
if (isNumber(schema[key].min) && value < schema[key].min) { | ||
throw new Error('Value assigned to ' + key + ' is less than min, ' + schema[key].min + ', got ' + value); | ||
} | ||
if (parentDiscriminator) { | ||
const discriminatorKey = this.models[parentDiscriminator]._schemaOptions.inheritOptions.discriminatorKey; | ||
// Max value validation | ||
if (isNumber(schema[key].max) && value > schema[key].max) { | ||
throw new Error('Value assigned to ' + key + ' is less than max, ' + schema[key].max + ', got ' + value); | ||
} | ||
// Max lenght validation | ||
if (schema[key].maxlength && isString(value) && value.length > schema[key].maxlength) { | ||
throw new Error('Value assigned to ' + key + ' is bigger than ' + schema[key].maxlength.toString() + '. Value was ' + value.length); | ||
} | ||
if (pipeline[0]['$match'] && pipeline[0]['$match'].discriminatorKey) throw new Error('You can not include a specific value for the "discriminatorKey" on the query.'); | ||
// Custom validation | ||
if (typeof schema[key].validate === 'function' && !schema[key].validate(value)) { | ||
throw new Error('Value assigned to ' + key + ' failed custom validator. Value was ' + value); | ||
} | ||
const pipelineKeys = Object.keys(pipeline[0]); | ||
pipeline.unshift({ | ||
$match: { [discriminatorKey]: parentDiscriminator } | ||
}); | ||
}); | ||
} | ||
return pipeline; | ||
} | ||
@@ -756,3 +772,8 @@ | ||
// Validate the payload | ||
_this4._validatePayload(payload, model._schemaNormalized); | ||
yield _this4._validateUpdatePayload(payload, model); | ||
/*await model.validatePayloadFieldValues( | ||
payload, | ||
model._schemaNormalized, | ||
payload, | ||
);*/ | ||
@@ -823,14 +844,15 @@ // Ensure index are created | ||
// Check aggregate operators | ||
const operatorsIndexes = _this5._validateAndIndexAggregateOperators(pipeline); | ||
// Assign default options to perform the aggregate query | ||
const aggregateOptions = Object.assign({}, defaultAggregateOptions, options); | ||
_this5._validateAggregateOperators(pipeline); | ||
// 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 = {}; | ||
let model = {}, | ||
discriminator = null; | ||
if (_this5.models[collection]) { | ||
const _discriminator = _this5.models[collection]._discriminator; | ||
if (_discriminator) { | ||
@@ -840,8 +862,7 @@ 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.'); | ||
if (pipeline[0]['$match'] && 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 | ||
}); | ||
discriminator = collection; | ||
} | ||
model = _this5.models[collection]; | ||
@@ -853,17 +874,6 @@ collection = _this5.models[collection]._modelName; | ||
// 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; | ||
// Check all stages in the pipeline looking for any lookup stage | ||
// pointing out to a discriminated model | ||
pipeline = _this5._normalizeAggregatePipeline(pipeline, discriminator); | ||
if (_discriminator) { | ||
lookup.from = _this5.models[lookup.from]._modelName; | ||
} | ||
} | ||
} | ||
} | ||
// Ensure index are created | ||
@@ -870,0 +880,0 @@ if (_this5._indexes[collection] && _this5._indexes[collection].length > 0) { |
@@ -121,3 +121,3 @@ 'use strict'; | ||
// Validate all the values | ||
yield _this._validatePayloadFieldValues(data, _this._schemaNormalized, data); | ||
yield _this.validatePayloadFieldValues(data, _this._schemaNormalized, data); | ||
@@ -219,3 +219,3 @@ // Returning the new document created | ||
/** | ||
* _validatePayloadFieldValues : Check if the data type and format is | ||
* validatePayloadFieldValues : Check if the data type and format is | ||
* accepted by the schema assigned to this model and | ||
@@ -228,3 +228,3 @@ * also pass all the validation | ||
*/ | ||
_validatePayloadFieldValues(payload, schema, parentPayload) { | ||
validatePayloadFieldValues(payload, schema, parentPayload, operator = null) { | ||
var _this2 = this; | ||
@@ -242,3 +242,3 @@ | ||
// Array | ||
if (isArray(schema[key]) && payload[key]) { | ||
if (isArray(schema[key]) && payload[key] && !schema[key].type) { | ||
var _iteratorNormalCompletion2 = true; | ||
@@ -253,3 +253,3 @@ var _didIteratorError2 = false; | ||
try { | ||
yield _this2._validatePayloadFieldValues(arrayItem, schema[key][0], parentPayload); | ||
yield _this2.validatePayloadFieldValues(arrayItem, schema[key][0], parentPayload, operator); | ||
continue; | ||
@@ -277,5 +277,5 @@ } catch (error) { | ||
// Objects nested | ||
if (isObject(schema[key]) && !isArray(schema[key]) && payload[key]) { | ||
if (isObject(schema[key]) && !isArray(schema[key]) && payload[key] && !schema[key].type) { | ||
try { | ||
yield _this2._validatePayloadFieldValues(payload[key], schema[key], parentPayload); | ||
yield _this2.validatePayloadFieldValues(payload[key], schema[key], parentPayload, operator); | ||
continue; | ||
@@ -288,6 +288,6 @@ } catch (error) { | ||
// No required values | ||
if ((!payload || payload[key] === undefined) && !schema[key].required) continue; | ||
if ((!payload || payload[key] === undefined) && (!schema[key].requiredn || operator)) continue; | ||
// Is required validation | ||
if (schema[key].required && (!payload || isEmptyValue(payload[key]))) { | ||
if ((!operator || operator === '$unset') && schema[key].required && (!payload || isEmptyValue(payload[key]))) { | ||
throw new Error('Key ' + key + ' is required'); | ||
@@ -298,3 +298,3 @@ } | ||
if (!isValidType(payload[key], isArray(schema[key]) ? Array : schema[key].type)) { | ||
throw new Error('Unsuported value (' + JSON.stringify(payload[key]) + ') for type ' + schemaKeyTypeAux); | ||
throw new Error('Unsuported value (' + JSON.stringify(payload[key]) + ') for type ' + schema[key].type); | ||
} | ||
@@ -301,0 +301,0 @@ |
{ | ||
"name": "moltyjs", | ||
"version": "0.8.2", | ||
"version": "0.8.3", | ||
"description": "A tiny ODM for MongoDB with multy tenancy support.", | ||
@@ -5,0 +5,0 @@ "main": "lib/index.js", |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
117626
2148