Merge pull request #341 from JamesMGreene/throw_real_errors

Throw real Errors instead of strings and plain objects
pull/2/head
Louis Chatriot 9 years ago
commit 82de35ee94
  1. 2
      lib/cursor.js
  2. 58
      lib/model.js
  3. 18
      lib/persistence.js

@ -77,7 +77,7 @@ Cursor.prototype.project = function (candidates) {
// Check for consistency // Check for consistency
keys = Object.keys(this._projection); keys = Object.keys(this._projection);
keys.forEach(function (k) { keys.forEach(function (k) {
if (action !== undefined && self._projection[k] !== action) { throw "Can't both keep and omit fields except for _id"; } if (action !== undefined && self._projection[k] !== action) { throw new Error("Can't both keep and omit fields except for _id"); }
action = self._projection[k]; action = self._projection[k];
}); });

@ -29,11 +29,11 @@ function checkKey (k, v) {
} }
if (k[0] === '$' && !(k === '$$date' && typeof v === 'number') && !(k === '$$deleted' && v === true) && !(k === '$$indexCreated') && !(k === '$$indexRemoved')) { if (k[0] === '$' && !(k === '$$date' && typeof v === 'number') && !(k === '$$deleted' && v === true) && !(k === '$$indexCreated') && !(k === '$$indexRemoved')) {
throw 'Field names cannot begin with the $ character'; throw new Error('Field names cannot begin with the $ character');
} }
if (k.indexOf('.') !== -1) { if (k.indexOf('.') !== -1) {
throw 'Field names cannot contain a .'; throw new Error('Field names cannot contain a .');
} }
} }
@ -266,11 +266,11 @@ lastStepModifierFunctions.$push = function (obj, field, value) {
// Create the array if it doesn't exist // Create the array if it doesn't exist
if (!obj.hasOwnProperty(field)) { obj[field] = []; } if (!obj.hasOwnProperty(field)) { obj[field] = []; }
if (!util.isArray(obj[field])) { throw "Can't $push an element on non-array values"; } if (!util.isArray(obj[field])) { throw new Error("Can't $push an element on non-array values"); }
if (value !== null && typeof value === 'object' && value.$each) { if (value !== null && typeof value === 'object' && value.$each) {
if (Object.keys(value).length > 1) { throw "Can't use another field in conjunction with $each"; } if (Object.keys(value).length > 1) { throw new Error("Can't use another field in conjunction with $each"); }
if (!util.isArray(value.$each)) { throw "$each requires an array value"; } if (!util.isArray(value.$each)) { throw new Error("$each requires an array value"); }
value.$each.forEach(function (v) { value.$each.forEach(function (v) {
obj[field].push(v); obj[field].push(v);
@ -292,11 +292,11 @@ lastStepModifierFunctions.$addToSet = function (obj, field, value) {
// Create the array if it doesn't exist // Create the array if it doesn't exist
if (!obj.hasOwnProperty(field)) { obj[field] = []; } if (!obj.hasOwnProperty(field)) { obj[field] = []; }
if (!util.isArray(obj[field])) { throw "Can't $addToSet an element on non-array values"; } if (!util.isArray(obj[field])) { throw new Error("Can't $addToSet an element on non-array values"); }
if (value !== null && typeof value === 'object' && value.$each) { if (value !== null && typeof value === 'object' && value.$each) {
if (Object.keys(value).length > 1) { throw "Can't use another field in conjunction with $each"; } if (Object.keys(value).length > 1) { throw new Error("Can't use another field in conjunction with $each"); }
if (!util.isArray(value.$each)) { throw "$each requires an array value"; } if (!util.isArray(value.$each)) { throw new Error("$each requires an array value"); }
value.$each.forEach(function (v) { value.$each.forEach(function (v) {
lastStepModifierFunctions.$addToSet(obj, field, v); lastStepModifierFunctions.$addToSet(obj, field, v);
@ -314,8 +314,8 @@ lastStepModifierFunctions.$addToSet = function (obj, field, value) {
* Remove the first or last element of an array * Remove the first or last element of an array
*/ */
lastStepModifierFunctions.$pop = function (obj, field, value) { lastStepModifierFunctions.$pop = function (obj, field, value) {
if (!util.isArray(obj[field])) { throw "Can't $pop an element from non-array values"; } if (!util.isArray(obj[field])) { throw new Error("Can't $pop an element from non-array values"); }
if (typeof value !== 'number') { throw value + " isn't an integer, can't use it with $pop"; } if (typeof value !== 'number') { throw new Error(value + " isn't an integer, can't use it with $pop"); }
if (value === 0) { return; } if (value === 0) { return; }
if (value > 0) { if (value > 0) {
@ -332,7 +332,7 @@ lastStepModifierFunctions.$pop = function (obj, field, value) {
lastStepModifierFunctions.$pull = function (obj, field, value) { lastStepModifierFunctions.$pull = function (obj, field, value) {
var arr, i; var arr, i;
if (!util.isArray(obj[field])) { throw "Can't $pull an element from non-array values"; } if (!util.isArray(obj[field])) { throw new Error("Can't $pull an element from non-array values"); }
arr = obj[field]; arr = obj[field];
for (i = arr.length - 1; i >= 0; i -= 1) { for (i = arr.length - 1; i >= 0; i -= 1) {
@ -347,13 +347,13 @@ lastStepModifierFunctions.$pull = function (obj, field, value) {
* Increment a numeric field's value * Increment a numeric field's value
*/ */
lastStepModifierFunctions.$inc = function (obj, field, value) { lastStepModifierFunctions.$inc = function (obj, field, value) {
if (typeof value !== 'number') { throw value + " must be a number"; } if (typeof value !== 'number') { throw new Error(value + " must be a number"); }
if (typeof obj[field] !== 'number') { if (typeof obj[field] !== 'number') {
if (!_.has(obj, field)) { if (!_.has(obj, field)) {
obj[field] = value; obj[field] = value;
} else { } else {
throw "Don't use the $inc modifier on non-number fields"; throw new Error("Don't use the $inc modifier on non-number fields");
} }
} else { } else {
obj[field] += value; obj[field] += value;
@ -390,10 +390,10 @@ function modify (obj, updateQuery) {
, newDoc, modifiers , newDoc, modifiers
; ;
if (keys.indexOf('_id') !== -1 && updateQuery._id !== obj._id) { throw "You cannot change a document's _id"; } if (keys.indexOf('_id') !== -1 && updateQuery._id !== obj._id) { throw new Error("You cannot change a document's _id"); }
if (dollarFirstChars.length !== 0 && dollarFirstChars.length !== firstChars.length) { if (dollarFirstChars.length !== 0 && dollarFirstChars.length !== firstChars.length) {
throw "You cannot mix modifiers and normal fields"; throw new Error("You cannot mix modifiers and normal fields");
} }
if (dollarFirstChars.length === 0) { if (dollarFirstChars.length === 0) {
@ -407,12 +407,12 @@ function modify (obj, updateQuery) {
modifiers.forEach(function (m) { modifiers.forEach(function (m) {
var keys; var keys;
if (!modifierFunctions[m]) { throw "Unknown modifier " + m; } if (!modifierFunctions[m]) { throw new Error("Unknown modifier " + m); }
// Can't rely on Object.keys throwing on non objects since ES6{ // Can't rely on Object.keys throwing on non objects since ES6{
// Not 100% satisfying as non objects can be interpreted as objects but no false negatives so we can live with it // Not 100% satisfying as non objects can be interpreted as objects but no false negatives so we can live with it
if (typeof updateQuery[m] !== 'object') { if (typeof updateQuery[m] !== 'object') {
throw "Modifier " + m + "'s argument must be an object"; throw new Error("Modifier " + m + "'s argument must be an object");
} }
keys = Object.keys(updateQuery[m]); keys = Object.keys(updateQuery[m]);
@ -425,7 +425,7 @@ function modify (obj, updateQuery) {
// Check result is valid and return it // Check result is valid and return it
checkObject(newDoc); checkObject(newDoc);
if (obj._id !== newDoc._id) { throw "You can't change a document's _id"; } if (obj._id !== newDoc._id) { throw new Error("You can't change a document's _id"); }
return newDoc; return newDoc;
}; };
@ -550,7 +550,7 @@ comparisonFunctions.$ne = function (a, b) {
comparisonFunctions.$in = function (a, b) { comparisonFunctions.$in = function (a, b) {
var i; var i;
if (!util.isArray(b)) { throw "$in operator called with a non-array"; } if (!util.isArray(b)) { throw new Error("$in operator called with a non-array"); }
for (i = 0; i < b.length; i += 1) { for (i = 0; i < b.length; i += 1) {
if (areThingsEqual(a, b[i])) { return true; } if (areThingsEqual(a, b[i])) { return true; }
@ -560,13 +560,13 @@ comparisonFunctions.$in = function (a, b) {
}; };
comparisonFunctions.$nin = function (a, b) { comparisonFunctions.$nin = function (a, b) {
if (!util.isArray(b)) { throw "$nin operator called with a non-array"; } if (!util.isArray(b)) { throw new Error("$nin operator called with a non-array"); }
return !comparisonFunctions.$in(a, b); return !comparisonFunctions.$in(a, b);
}; };
comparisonFunctions.$regex = function (a, b) { comparisonFunctions.$regex = function (a, b) {
if (!util.isRegExp(b)) { throw "$regex operator called with non regular expression"; } if (!util.isRegExp(b)) { throw new Error("$regex operator called with non regular expression"); }
if (typeof a !== 'string') { if (typeof a !== 'string') {
return false return false
@ -592,7 +592,7 @@ comparisonFunctions.$exists = function (value, exists) {
// Specific to arrays // Specific to arrays
comparisonFunctions.$size = function (obj, value) { comparisonFunctions.$size = function (obj, value) {
if (!util.isArray(obj)) { return false; } if (!util.isArray(obj)) { return false; }
if (value % 1 !== 0) { throw "$size operator called without an integer"; } if (value % 1 !== 0) { throw new Error("$size operator called without an integer"); }
return (obj.length == value); return (obj.length == value);
}; };
@ -607,7 +607,7 @@ arrayComparisonFunctions.$size = true;
logicalOperators.$or = function (obj, query) { logicalOperators.$or = function (obj, query) {
var i; var i;
if (!util.isArray(query)) { throw "$or operator used without an array"; } if (!util.isArray(query)) { throw new Error("$or operator used without an array"); }
for (i = 0; i < query.length; i += 1) { for (i = 0; i < query.length; i += 1) {
if (match(obj, query[i])) { return true; } if (match(obj, query[i])) { return true; }
@ -625,7 +625,7 @@ logicalOperators.$or = function (obj, query) {
logicalOperators.$and = function (obj, query) { logicalOperators.$and = function (obj, query) {
var i; var i;
if (!util.isArray(query)) { throw "$and operator used without an array"; } if (!util.isArray(query)) { throw new Error("$and operator used without an array"); }
for (i = 0; i < query.length; i += 1) { for (i = 0; i < query.length; i += 1) {
if (!match(obj, query[i])) { return false; } if (!match(obj, query[i])) { return false; }
@ -653,10 +653,10 @@ logicalOperators.$not = function (obj, query) {
logicalOperators.$where = function (obj, fn) { logicalOperators.$where = function (obj, fn) {
var result; var result;
if (!_.isFunction(fn)) { throw "$where operator used without a function"; } if (!_.isFunction(fn)) { throw new Error("$where operator used without a function"); }
result = fn.call(obj); result = fn.call(obj);
if (!_.isBoolean(result)) { throw "$where function must return boolean"; } if (!_.isBoolean(result)) { throw new Error("$where function must return boolean"); }
return result; return result;
}; };
@ -684,7 +684,7 @@ function match (obj, query) {
queryValue = query[queryKey]; queryValue = query[queryKey];
if (queryKey[0] === '$') { if (queryKey[0] === '$') {
if (!logicalOperators[queryKey]) { throw "Unknown logical operator " + queryKey; } if (!logicalOperators[queryKey]) { throw new Error("Unknown logical operator " + queryKey); }
if (!logicalOperators[queryKey](obj, queryValue)) { return false; } if (!logicalOperators[queryKey](obj, queryValue)) { return false; }
} else { } else {
if (!matchQueryPart(obj, queryKey, queryValue)) { return false; } if (!matchQueryPart(obj, queryKey, queryValue)) { return false; }
@ -728,13 +728,13 @@ function matchQueryPart (obj, queryKey, queryValue, treatObjAsValue) {
dollarFirstChars = _.filter(firstChars, function (c) { return c === '$'; }); dollarFirstChars = _.filter(firstChars, function (c) { return c === '$'; });
if (dollarFirstChars.length !== 0 && dollarFirstChars.length !== firstChars.length) { if (dollarFirstChars.length !== 0 && dollarFirstChars.length !== firstChars.length) {
throw "You cannot mix operators and normal fields"; throw new Error("You cannot mix operators and normal fields");
} }
// queryValue is an object of this form: { $comparisonOperator1: value1, ... } // queryValue is an object of this form: { $comparisonOperator1: value1, ... }
if (dollarFirstChars.length > 0) { if (dollarFirstChars.length > 0) {
for (i = 0; i < keys.length; i += 1) { for (i = 0; i < keys.length; i += 1) {
if (!comparisonFunctions[keys[i]]) { throw "Unknown comparison function " + keys[i]; } if (!comparisonFunctions[keys[i]]) { throw new Error("Unknown comparison function " + keys[i]); }
if (!comparisonFunctions[keys[i]](objValue, queryValue[keys[i]])) { return false; } if (!comparisonFunctions[keys[i]](objValue, queryValue[keys[i]])) { return false; }
} }

@ -29,15 +29,15 @@ function Persistence (options) {
this.corruptAlertThreshold = options.corruptAlertThreshold !== undefined ? options.corruptAlertThreshold : 0.1; this.corruptAlertThreshold = options.corruptAlertThreshold !== undefined ? options.corruptAlertThreshold : 0.1;
if (!this.inMemoryOnly && this.filename && this.filename.charAt(this.filename.length - 1) === '~') { if (!this.inMemoryOnly && this.filename && this.filename.charAt(this.filename.length - 1) === '~') {
throw "The datafile name can't end with a ~, which is reserved for crash safe backup files"; throw new Error("The datafile name can't end with a ~, which is reserved for crash safe backup files");
} }
// After serialization and before deserialization hooks with some basic sanity checks // After serialization and before deserialization hooks with some basic sanity checks
if (options.afterSerialization && !options.beforeDeserialization) { if (options.afterSerialization && !options.beforeDeserialization) {
throw "Serialization hook defined but deserialization hook undefined, cautiously refusing to start NeDB to prevent dataloss"; throw new Error("Serialization hook defined but deserialization hook undefined, cautiously refusing to start NeDB to prevent dataloss");
} }
if (!options.afterSerialization && options.beforeDeserialization) { if (!options.afterSerialization && options.beforeDeserialization) {
throw "Serialization hook undefined but deserialization hook defined, cautiously refusing to start NeDB to prevent dataloss"; throw new Error("Serialization hook undefined but deserialization hook defined, cautiously refusing to start NeDB to prevent dataloss");
} }
this.afterSerialization = options.afterSerialization || function (s) { return s; }; this.afterSerialization = options.afterSerialization || function (s) { return s; };
this.beforeDeserialization = options.beforeDeserialization || function (s) { return s; }; this.beforeDeserialization = options.beforeDeserialization || function (s) { return s; };
@ -45,7 +45,7 @@ function Persistence (options) {
for (j = 0; j < 10; j += 1) { for (j = 0; j < 10; j += 1) {
randomString = customUtils.uid(i); randomString = customUtils.uid(i);
if (this.beforeDeserialization(this.afterSerialization(randomString)) !== randomString) { if (this.beforeDeserialization(this.afterSerialization(randomString)) !== randomString) {
throw "beforeDeserialization is not the reverse of afterSerialization, cautiously refusing to start NeDB to prevent dataloss"; throw new Error("beforeDeserialization is not the reverse of afterSerialization, cautiously refusing to start NeDB to prevent dataloss");
} }
} }
} }
@ -89,21 +89,21 @@ Persistence.getNWAppFilename = function (appName, relativeFilename) {
case 'win32': case 'win32':
case 'win64': case 'win64':
home = process.env.LOCALAPPDATA || process.env.APPDATA; home = process.env.LOCALAPPDATA || process.env.APPDATA;
if (!home) { throw "Couldn't find the base application data folder"; } if (!home) { throw new Error("Couldn't find the base application data folder"); }
home = path.join(home, appName); home = path.join(home, appName);
break; break;
case 'darwin': case 'darwin':
home = process.env.HOME; home = process.env.HOME;
if (!home) { throw "Couldn't find the base application data directory"; } if (!home) { throw new Error("Couldn't find the base application data directory"); }
home = path.join(home, 'Library', 'Application Support', appName); home = path.join(home, 'Library', 'Application Support', appName);
break; break;
case 'linux': case 'linux':
home = process.env.HOME; home = process.env.HOME;
if (!home) { throw "Couldn't find the base application data directory"; } if (!home) { throw new Error("Couldn't find the base application data directory"); }
home = path.join(home, '.config', appName); home = path.join(home, '.config', appName);
break; break;
default: default:
throw "Can't use the Node Webkit relative path for platform " + process.platform; throw new Error("Can't use the Node Webkit relative path for platform " + process.platform);
break; break;
} }
@ -235,7 +235,7 @@ Persistence.prototype.treatRawData = function (rawData) {
// A bit lenient on corruption // A bit lenient on corruption
if (data.length > 0 && corruptItems / data.length > this.corruptAlertThreshold) { if (data.length > 0 && corruptItems / data.length > this.corruptAlertThreshold) {
throw "More than " + Math.floor(100 * this.corruptAlertThreshold) + "% of the data file is corrupt, the wrong beforeDeserialization hook may be used. Cautiously refusing to start NeDB to prevent dataloss" throw new Error("More than " + Math.floor(100 * this.corruptAlertThreshold) + "% of the data file is corrupt, the wrong beforeDeserialization hook may be used. Cautiously refusing to start NeDB to prevent dataloss");
} }
Object.keys(dataById).forEach(function (k) { Object.keys(dataById).forEach(function (k) {

Loading…
Cancel
Save