New Case Study:See how Anthropic automated 95% of dependency reviews with Socket.Learn More
Socket
Sign inDemoInstall
Socket

waterline

Package Overview
Dependencies
Maintainers
2
Versions
165
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

waterline - npm Package Compare versions

Comparing version 0.10.0-rc6 to 0.10.0-rc7

lib/waterline/error/WLUsageError.js

103

lib/waterline/adapter/dql.js

@@ -5,12 +5,12 @@ /**

var normalize = require('../utils/normalize'),
schema = require('../utils/schema'),
hasOwnProperty = require('../utils/helpers').object.hasOwnProperty;
var normalize = require('../utils/normalize');
var schema = require('../utils/schema');
var hasOwnProperty = require('../utils/helpers').object.hasOwnProperty;
/**
* DQL Adapter Normalization
*/
module.exports = {

@@ -22,2 +22,13 @@

/**
* join()
*
* If `join` is defined in the adapter, Waterline will use it to optimize
* the `.populate()` implementation when joining collections within the same
* database connection.
*
* @param {[type]} criteria
* @param {Function} cb
*/
join: function(criteria, cb) {

@@ -30,3 +41,3 @@

// Build Default Error Message
var err = "No join() method defined in adapter!";
var err = 'No join() method defined in adapter!';

@@ -48,4 +59,16 @@ // Find the connection to run this on

/**
* create()
*
* Create one or more models.
*
* @param {[type]} values [description]
* @param {Function} cb [description]
* @return {[type]} [description]
*/
create: function(values, cb) {
var globalId = this.query.globalId;
// Normalize Arguments

@@ -57,3 +80,3 @@ cb = normalize.callback(cb);

// Build Default Error Message
var err = "No create() method defined in adapter!";
var err = 'No create() method defined in adapter!';

@@ -67,6 +90,22 @@ // Find the connection to run this on

if(!hasOwnProperty(adapter, 'create')) return cb(new Error(err));
adapter.create(connName, this.collection, values, cb);
adapter.create(connName, this.collection, values, normalize.callback(function afterwards (err, createdRecord) {
if (err) {
if (typeof err === 'object') err.model = globalId;
return cb(err);
}
else return cb(null, createdRecord);
}));
},
// Find a set of models
/**
* find()
*
* Find a set of models.
*
* @param {[type]} criteria [description]
* @param {Function} cb [description]
* @return {[type]} [description]
*/
find: function(criteria, cb) {

@@ -79,3 +118,3 @@

// Build Default Error Message
var err = "No find() method defined in adapter!";
var err = 'No find() method defined in adapter!';

@@ -92,3 +131,12 @@ // Find the connection to run this on

// Find exactly one model
/**
* findOne()
*
* Find exactly one model.
*
* @param {[type]} criteria [description]
* @param {Function} cb [description]
* @return {[type]} [description]
*/
findOne: function(criteria, cb) {

@@ -116,2 +164,8 @@

/**
* [count description]
* @param {[type]} criteria [description]
* @param {Function} cb [description]
* @return {[type]} [description]
*/
count: function(criteria, cb) {

@@ -147,4 +201,14 @@ var connName;

/**
* [update description]
* @param {[type]} criteria [description]
* @param {[type]} values [description]
* @param {Function} cb [description]
* @return {[type]} [description]
*/
update: function (criteria, values, cb) {
var globalId = this.query.globalId;
// Normalize Arguments

@@ -165,5 +229,18 @@ cb = normalize.callback(cb);

adapter.update(connName, this.collection, criteria, values, cb);
adapter.update(connName, this.collection, criteria, values, normalize.callback(function afterwards (err, updatedRecords) {
if (err) {
if (typeof err === 'object') err.model = globalId;
return cb(err);
}
return cb(null, updatedRecords);
}));
},
/**
* [destroy description]
* @param {[type]} criteria [description]
* @param {Function} cb [description]
* @return {[type]} [description]
*/
destroy: function(criteria, cb) {

@@ -170,0 +247,0 @@

26

lib/waterline/core/validations.js

@@ -8,8 +8,12 @@ /**

var _ = require('lodash'),
anchor = require('anchor'),
async = require('async'),
utils = require('../utils/helpers'),
hasOwnProperty = utils.object.hasOwnProperty;
var _ = require('lodash');
var anchor = require('anchor');
var async = require('async');
var utils = require('../utils/helpers');
var hasOwnProperty = utils.object.hasOwnProperty;
var WLValidationError = require('../error/WLValidationError');
/**

@@ -65,6 +69,9 @@ * Build up validations using the Anchor module.

// Ignore null values
if(attrs[attr][prop] === null) return;
// If property is reserved don't do anything with it
if(['defaultsTo', 'primaryKey', 'autoIncrement', 'unique', 'index', 'collection', 'dominant',
'columnName', 'foreignKey', 'references', 'on', 'groupKey', 'model', 'via', 'size',
'example', 'validationMessage'].indexOf(prop) > -1) return;
'example', 'validationMessage', 'validations'].indexOf(prop) > -1) return;

@@ -172,8 +179,9 @@ // use the Anchor `in` method for enums

// Validate all validations in parallell
async.each(validations, validate, function() {
// Validate all validations in parallel
async.each(validations, validate, function allValidationsChecked () {
if(Object.keys(errors).length === 0) return cb();
cb({ 'ValidationError': errors });
cb(errors);
});
};

@@ -7,12 +7,30 @@ /**

_ = require('lodash'),
WLError = require('./WLError'),
WLValidationError = require('./WLValidationError'),
WLAdapterError = require('./WLAdapterError'),
_isValidationError = require('./isValidationError'),
_isConstraintViolation = require('./isConstraintViolation'),
_isAdapterError = require('./isAdapterError');
WLError = require('./WLError');
WLValidationError = require('./WLValidationError');
// Expose a closure which returns the appropriate class of WLError
module.exports = function(err) {
/**
* A classifier which normalizes a mystery error into a simple,
* consistent format. This ensures that our instance which is
* "new"-ed up belongs to one of a handful of distinct categories
* and has a predictable method signature and properties.
*
* The returned error instance will always be or extend from
* `WLError` (which extends from `Error`)
*
* NOTE:
* This method should eventually be deprecated in a
* future version of Waterline. It exists to help
* w/ error type negotiation. In general, Waterline
* should use WLError, or errors which extend from it
* to construct error objects of the appropriate type.
* In other words, no ** new ** errors should need to
* be wrapped in a call to `errorify` - instead, code
* necessary to handle any new error conditions should
* construct a `WLError` directly and return that.
*
* @param {???} err
* @return {WLError}
*/
module.exports = function errorify(err) {

@@ -22,3 +40,3 @@ // If specified `err` is already a WLError, just return it.

return negotiate(err);
return duckType(err);
};

@@ -30,31 +48,55 @@

* Determine which type of error we're working with.
* Err... using hacks.
*
* @return {[type]} [description]
*/
function negotiate(err) {
function duckType(err) {
// Validation or constraint violation error (`E_VALIDATION`)
//
//
// i.e. detected before talking to adapter, like `minLength`
// i.e. constraint violation reported by adapter, like `unique`
if (_isValidationError(err) || _isConstraintViolation(err)) {
if (/*_isValidationError(err) || */_isConstraintViolation(err)) {
// Dress `unique` rule violations to be consistent with other
// validation errors.
return new WLValidationError(err);
}
// Adapter error (`E_ADAPTER`)
//
// Miscellaneous physical-layer consistency violation
// i.e. reported by adapter via `waterline-errors`
else if (_isAdapterError(err)) {
return new WLAdapterError(err);
}
// Unexpected miscellaneous error (`E_UNKNOWN`)
//
//
// (i.e. helmet fire. The database crashed or something. Or there's an adapter
// bug. Or a bug in WL core.)
else {
return new WLError(err);
return new WLError({
originalError: err
});
}
/**
* @param {?} err
* @return {Boolean} whether this is an adapter-level constraint
* violation (e.g. `unique`)
*/
function _isConstraintViolation(err) {
// If a proper error code is specified, this error can be classified.
if (err && typeof err === 'object' && err.code === 'E_UNIQUE') {
return true;
}
// Otherwise, there is not enough information to call this a
// constraint violation error and provide proper explanation to
// the architect.
else return false;
}
// /**
// * @param {?} err
// * @return {Boolean} whether this is a validation error (e.g. minLength exceeded for attribute)
// */
// function _isValidationError(err) {
// return _.isObject(err) && err.ValidationError;
// }

@@ -6,67 +6,162 @@ /**

var util = require('util')
, http = require('http')
, _ = require('lodash');
module.exports = WLError;
/**
* WLError
*
* A classifier which normalizes a mystery error into a simple,
* consistent format. WLError ensures that the instance that is
* "new"-ed up belongs to one of a handful of distinct categories
* and has a predictable method signature and properties.
* All errors passed to a query callback in Waterline extend
* from this base error class.
*
* @param {?} err
* @param {Object} properties
* @constructor {WLError}
*/
function WLError(err) {
function WLError( properties ) {
// Save reference to original error.
this.originalError = err;
// Call super constructor (Error)
WLError.super_.call(this);
// Default properties
this.status = 'error';
this.code = 'E_UNKNOWN';
this.msg = 'Waterline: ORM encountered an unknown error.';
// Fold defined properties into the new WLError instance.
properties = properties||{};
_.extend(this, properties);
}
util.inherits(WLError, Error);
// Default properties
WLError.prototype.status =
500;
WLError.prototype.code =
'E_UNKNOWN';
WLError.prototype.reason =
'Encountered an unexpected error';
/**
* Override JSON serialization.
* (i.e. when this error is passed to `res.json()` or `JSON.stringify`)
*
* For example:
* ```json
* {
* status: 500,
* code: 'E_UNKNOWN'
* }
* ```
*
* @return {Object}
*/
WLError.prototype.toJSON = WLError.prototype.toPOJO =
function toPOJO() {
WLError.prototype.toJSON =
WLError.prototype.toPOJO =
function () {
var obj = {
error: this.code,
summary: this.reason,
status: this.status,
raw: this.explain()
};
// Worst case, try to dress up the original error as much as possible.
return {
status: this.status,
message: this.msg,
// TODO: make this better (i.e. not a hard-coded check-- use the inheritance approach discussed in TODO at top of this file and override the toJSON() function for the validation error case)
details: this.invalidAttributes || this.toString(),
code: this.code
};
// Only include `raw` if its truthy.
if (!obj.raw) delete obj.raw;
return obj;
};
/**
* Override output for `sails.log[.*]`
*
* @return {String}
*
* For example:
* ```sh
* Waterline: ORM encountered an unexpected error:
* { ValidationError: { name: [ [Object], [Object] ] } }
* ```
*/
WLError.prototype.toLog = function () {
return this.inspect();
};
/**
* Override output for `util.inspect`
* (also when this error is logged using `console.log`)
*
* @return {String}
*/
WLError.prototype.inspect = function () {
return util.format('Error (%s)', this.code) + ' :: ' + /*this.toString() +*/ '\n'+util.inspect(this.toPOJO());
};
/**
* @return {String}
*/
WLError.prototype.toString = function () {
var output = '';
var summary = this.summarize();
var explanation = this.explain();
// Try to dress up the original error as much as possible.
var stringifiedErr;
if (_.isString(this.originalError)) {
stringifiedErr = this.originalError;
}
// Run toString() on Errors
else if (_.isObject(this.originalError) && this.originalError instanceof Error && _.isFunction(this.originalError.toString) ) {
stringifiedErr = this.originalError.toString();
}
// But for other objects, use util.inspect()
else {
stringifiedErr = util.inspect(this.originalError);
}
return stringifiedErr;
output += summary;
output += (summary && explanation) ? ':' : '.';
if (explanation) {
output += '\n' + explanation;
}
return output;
};
/**
* @return {String}
*/
WLError.prototype.summarize = function () {
var output = '';
if (this.reason) {
output += this.reason;
}
else {
output += this.getCanonicalStatusMessage();
}
return output;
};
/**
* @return {String} a detailed explanation of this error
*/
WLError.prototype.explain = function () {
// Try to dress up the wrapped "original" error as much as possible.
if (!this.originalError) {
return '';
}
else if (typeof this.originalError === 'string') {
return this.originalError;
}
// Run toString() on Errors
else if ( util.isError(this.originalError) ) {
return this.originalError.toString();
}
// But for other objects, use util.inspect()
else {
return util.inspect(this.originalError);
}
};
/**
* @return {String} description of this error's status code, as defined by HTTP.
*/
WLError.prototype.getCanonicalStatusMessage = function () {
return http.STATUS_CODES[this.status];
};
module.exports = WLError;

@@ -6,10 +6,8 @@ /**

var WLError = require('./WLError');
var nodeutil = require('util');
var WLUsageError = require('./WLUsageError');
var util = require('util');
var _ = require('lodash');
module.exports = WLValidationError;
/**

@@ -20,15 +18,168 @@ * WLValidationError

*/
function WLValidationError (err) {
function WLValidationError (properties) {
// Call super
WLError.call(this, err);
// Call superclass
WLValidationError.super_.call(this, properties);
// Override default WLError properties
this.status = 'invalid';
// Ensure valid usage
if ( typeof this.invalidAttributes !== 'object' ) {
return new WLUsageError({
reason: 'An `invalidAttributes` object must be passed into the constructor for `WLValidationError`'
});
}
// if ( typeof this.model !== 'string' ) {
// return new WLUsageError({
// reason: 'A `model` string (the collection\'s `globalId`) must be passed into the constructor for `WLValidationError`'
// });
// }
// Customize the `reason` based on the # of invalid attributes
// (`reason` may not be overridden)
var isSingular = this.length === 1;
this.reason = util.format('%d attribute%s %s invalid',
this.length,
isSingular ? '' : 's',
isSingular ? 'is' : 'are');
// Always apply the 'E_VALIDATION' error code, even if it was overridden.
this.code = 'E_VALIDATION';
this.msg = 'Waterline: Could not complete operation - violates one or more of your model\'s validation rules.';
this.invalidAttributes = this.originalError.ValidationError;
// Status may be overridden.
this.status = properties.status || 400;
// Model should always be set.
// (this should be the globalId of model, or "collection")
this.model = properties.model;
// Ensure messages exist for each invalidAttribute
this.invalidAttributes = _.mapValues(this.invalidAttributes, function (rules, attrName) {
return _.map(rules, function (rule) {
if (!rule.message) {
rule.message = util.format('A record with that `%s` already exists (`%s`).', attrName, rule.value);
}
return rule;
});
});
}
nodeutil.inherits(WLValidationError, WLError);
util.inherits(WLValidationError, WLError);
/**
* `rules`
*
* @return {Object[Array[String]]} dictionary of validation rule ids, indexed by attribute
*/
WLValidationError.prototype.__defineGetter__('rules', function(){
return _.mapValues(this.invalidAttributes, function (rules, attrName) {
return _.pluck(rules, 'rule');
});
});
/**
* `messages` (aka `errors`)
*
* @return {Object[Array[String]]} dictionary of validation messages, indexed by attribute
*/
WLValidationError.prototype.__defineGetter__('messages', function(){
return _.mapValues(this.invalidAttributes, function (rules, attrName) {
return _.pluck(rules, 'message');
});
});
WLValidationError.prototype.__defineGetter__('errors', function(){
return this.messages;
});
/**
* `attributes` (aka `keys`)
*
* @return {Array[String]} of invalid attribute names
*/
WLValidationError.prototype.__defineGetter__('attributes', function(){
return _.keys(this.invalidAttributes);
});
WLValidationError.prototype.__defineGetter__('keys', function(){
return this.attributes;
});
/**
* `.length`
*
* @return {Integer} number of invalid attributes
*/
WLValidationError.prototype.__defineGetter__('length', function(){
return this.attributes.length;
});
/**
* `.ValidationError`
* (backwards-compatibility)
*
* @return {Object[Array[Object]]} number of invalid attributes
*/
WLValidationError.prototype.__defineGetter__('ValidationError', function(){
//
// TODO:
// Down the road- emit deprecation event here--
// (will log information about new error handling options)
//
return this.invalidAttributes;
});
/**
* [toJSON description]
* @type {[type]}
*/
WLValidationError.prototype.toJSON =
WLValidationError.prototype.toPOJO =
function () {
return {
error: this.code,
model: this.model,
summary: this.reason,
status: this.status,
invalidAttributes: this.invalidAttributes
};
};
/**
* @return {String} a detailed explanation of this error
*/
WLValidationError.prototype.explain = function () {
return _.reduce(this.messages, function (memo, messages, attrName) {
memo += attrName + ':\n';
memo += _.reduce(messages, function (memo, message) {
memo += ' ' + message + '\n';
return memo;
}, '');
return memo;
}, '');
};
/**
* Override output for `util.inspect`
* (also when this error is logged using `console.log`)
*
* @return {String}
*/
WLError.prototype.inspect = function () {
return util.format('Error (%s)', this.code) + ' :: ' + this.toString() + '\nDetails:\n'+util.inspect(this.toPOJO());
};
module.exports = WLValidationError;

@@ -68,2 +68,3 @@

values.forEach(function(record) {
if(record === null) return;
var item = Object.create(record.__proto__);

@@ -70,0 +71,0 @@ Object.keys(record).forEach(function(key) {

@@ -95,3 +95,5 @@ /**

self.adapter.create(values, function(err, values) {
if(err) return cb(err);
if(err) {
return cb(err);
}

@@ -98,0 +100,0 @@ // Unserialize values

@@ -15,3 +15,4 @@ /**

_ = require('lodash'),
async = require('async');
async = require('async'),
hasOwnProperty = utils.object.hasOwnProperty;

@@ -91,4 +92,17 @@ module.exports = {

// We need to run one last check on the results using the criteria. This allows a self
// association where we end up with two records in the cache both having each other as
// embedded objects and we only want one result. However we need to filter any join criteria
// out of the top level where query so that searchs by primary key still work.
var tmpCriteria = _.cloneDeep(criteria.where);
if(!tmpCriteria) tmpCriteria = {};
criteria.joins.forEach(function(join) {
if(!hasOwnProperty(join, 'alias')) return;
if(!hasOwnProperty(tmpCriteria, join.alias)) return;
delete tmpCriteria[join.alias];
});
// Pass results into Waterline-Criteria
var _criteria = { where: _.cloneDeep(criteria.where) };
var _criteria = { where: tmpCriteria };
results = waterlineCriteria('parent', { parent: results }, _criteria).results;

@@ -119,3 +133,3 @@

if(!results) return cb()
if(!results) return cb();

@@ -243,4 +257,17 @@ // Normalize results to an array

// We need to run one last check on the results using the criteria. This allows a self
// association where we end up with two records in the cache both having each other as
// embedded objects and we only want one result. However we need to filter any join criteria
// out of the top level where query so that searchs by primary key still work.
var tmpCriteria = _.cloneDeep(criteria.where);
if(!tmpCriteria) tmpCriteria = {};
criteria.joins.forEach(function(join) {
if(!hasOwnProperty(join, 'alias')) return;
if(!hasOwnProperty(tmpCriteria, join.alias)) return;
delete tmpCriteria[join.alias];
});
// Pass results into Waterline-Criteria
var _criteria = { where: _.cloneDeep(criteria.where) };
var _criteria = { where: tmpCriteria };
results = waterlineCriteria('parent', { parent: results }, _criteria).results;

@@ -271,2 +298,4 @@

if(!results) return cb(null, []);
// Normalize results to an array

@@ -273,0 +302,0 @@ if(!Array.isArray(results) && results) results = [results];

@@ -478,4 +478,4 @@

_tmpCriteria = _.cloneDeep(userCriteria);
_tmpCriteria = normalize.criteria(_tmpCriteria);
// Ensure `where` criteria is properly formatted

@@ -667,3 +667,3 @@ if(hasOwnProperty(userCriteria, 'where')) {

delete userCriteria.sort;
criteria = _.merge(userCriteria, criteria);
criteria = _.extend(criteria, userCriteria);
}

@@ -670,0 +670,0 @@

@@ -40,4 +40,11 @@ /**

function(cb) {
self._validator.validate(values, presentOnly === true, function(err) {
if(err) return cb(err);
self._validator.validate(values, presentOnly === true, function(invalidAttributes) {
// Create validation error here
// (pass in the invalid attributes as well as the collection's globalId)
if(invalidAttributes) return cb(new WLValidationError({
invalidAttributes: invalidAttributes,
model: self.globalId
}));
cb();

@@ -44,0 +51,0 @@ });

@@ -82,4 +82,8 @@

exports.matchMongoId = function matchMongoId(id) {
if(typeof id.toString === 'undefined') return false;
return id.toString().match(/^[a-fA-F0-9]{24}$/) ? true : false;
// id must be truthy- and either BE a string, or be an object
// with a toString method.
if( !id ||
! (_.isString(id) || (_.isObject(id) || _.isFunction(id.toString)))
) return false;
else return id.toString().match(/^[a-fA-F0-9]{24}$/) ? true : false;
};

@@ -58,3 +58,3 @@ /**

// Ensure type is lower case
if(typeof attributes[key].type !== 'undefined') {
if(attributes[key].type && typeof attributes[key].type !== 'undefined') {
attributes[key].type = attributes[key].type.toLowerCase();

@@ -61,0 +61,0 @@ }

{
"name": "waterline",
"description": "An ORM for Node.js and the Sails framework",
"version": "0.10.0-rc6",
"version": "0.10.0-rc7",
"homepage": "http://github.com/balderdashy/waterline",

@@ -25,3 +25,3 @@ "contributors": [

"q": "~0.9.7",
"waterline-schema": "~0.1.6",
"waterline-schema": "~0.1.7",
"node-switchback": "~0.0.4",

@@ -28,0 +28,0 @@ "waterline-criteria": "~0.10.3"

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