Change MinimongoError to accept field in a new options parameter.

This allows the field name to be dynamically introduced into the error
message.

Follows-up on meteor/meteor#8529.
This commit is contained in:
Jesse Rosenberger
2017-04-07 17:06:13 +03:00
parent 9163643906
commit eedf8bddbf
4 changed files with 70 additions and 31 deletions

View File

@@ -40,7 +40,11 @@ Minimongo = {};
// Use it to export private functions to test in Tinytest.
MinimongoTest = {};
MinimongoError = function (message) {
MinimongoError = function (message, options={}) {
if (typeof message === "string" && options.field) {
message += ` for field '${options.field}'`;
}
var e = new Error(message);
e.name = "MinimongoError";
return e;

View File

@@ -163,6 +163,22 @@ Tinytest.add("minimongo - basics", function (test) {
});
Tinytest.add("minimongo - error - no options", function (test) {
try {
throw MinimongoError("Not fun to have errors");
} catch (e) {
test.equal(e.message, "Not fun to have errors");
}
});
Tinytest.add("minimongo - error - with field", function (test) {
try {
throw MinimongoError("Cats are no fun", { field: "mice" });
} catch (e) {
test.equal(e.message, "Cats are no fun for field 'mice'");
}
});
Tinytest.add("minimongo - cursors", function (test) {
var c = new LocalCollection();
var res;

View File

@@ -185,20 +185,24 @@ var MODIFIERS = {
$currentDate: function (target, field, arg) {
if (typeof arg === "object" && arg.hasOwnProperty("$type")) {
if (arg.$type !== "date") {
throw MinimongoError("Minimongo does currently only support the date type in $currentDate modifiers: " + field);
throw MinimongoError(
"Minimongo does currently only support the date type " +
"in $currentDate modifiers",
{ field });
}
} else if (arg !== true) {
throw MinimongoError("Invalid $currentDate modifier: " + field);
throw MinimongoError("Invalid $currentDate modifier", { field });
}
target[field] = new Date();
},
$min: function (target, field, arg) {
if (typeof arg !== "number") {
throw MinimongoError("Modifier $min allowed for numbers only: " + field);
throw MinimongoError("Modifier $min allowed for numbers only", { field });
}
if (field in target) {
if (typeof target[field] !== "number") {
throw MinimongoError("Cannot apply $min modifier to non-number: " + field);
throw MinimongoError(
"Cannot apply $min modifier to non-number", { field });
}
if (target[field] > arg) {
target[field] = arg;
@@ -209,11 +213,12 @@ var MODIFIERS = {
},
$max: function (target, field, arg) {
if (typeof arg !== "number") {
throw MinimongoError("Modifier $max allowed for numbers only: " + field);
throw MinimongoError("Modifier $max allowed for numbers only", { field });
}
if (field in target) {
if (typeof target[field] !== "number") {
throw MinimongoError("Cannot apply $max modifier to non-number: " + field);
throw MinimongoError(
"Cannot apply $max modifier to non-number", { field });
}
if (target[field] < arg) {
target[field] = arg;
@@ -224,10 +229,11 @@ var MODIFIERS = {
},
$inc: function (target, field, arg) {
if (typeof arg !== "number")
throw MinimongoError("Modifier $inc allowed for numbers only: " + field);
throw MinimongoError("Modifier $inc allowed for numbers only", { field });
if (field in target) {
if (typeof target[field] !== "number")
throw MinimongoError("Cannot apply $inc modifier to non-number: " + field);
throw MinimongoError(
"Cannot apply $inc modifier to non-number", { field });
target[field] += arg;
} else {
target[field] = arg;
@@ -235,12 +241,13 @@ var MODIFIERS = {
},
$set: function (target, field, arg) {
if (!_.isObject(target)) { // not an array or an object
var e = MinimongoError("Cannot set property on non-object field: " + field);
var e = MinimongoError(
"Cannot set property on non-object field", { field });
e.setPropertyError = true;
throw e;
}
if (target === null) {
var e = MinimongoError("Cannot set property on null: " + field);
var e = MinimongoError("Cannot set property on null", { field });
e.setPropertyError = true;
throw e;
}
@@ -267,7 +274,8 @@ var MODIFIERS = {
if (target[field] === undefined)
target[field] = [];
if (!(target[field] instanceof Array))
throw MinimongoError("Cannot apply $push modifier to non-array: " + field);
throw MinimongoError(
"Cannot apply $push modifier to non-array", { field });
if (!(arg && arg.$each)) {
// Simple mode: not $each
@@ -278,16 +286,17 @@ var MODIFIERS = {
// Fancy mode: $each (and maybe $slice and $sort and $position)
var toPush = arg.$each;
if (!(toPush instanceof Array))
throw MinimongoError("$each must be an array: " + field);
throw MinimongoError("$each must be an array", { field });
// Parse $position
var position = undefined;
if ('$position' in arg) {
if (typeof arg.$position !== "number")
throw MinimongoError("$position must be a numeric value: " + field);
throw MinimongoError("$position must be a numeric value", { field });
// XXX should check to make sure integer
if (arg.$position < 0)
throw MinimongoError("$position in $push must be zero or positive: " + field);
throw MinimongoError(
"$position in $push must be zero or positive", { field });
position = arg.$position;
}
@@ -295,10 +304,11 @@ var MODIFIERS = {
var slice = undefined;
if ('$slice' in arg) {
if (typeof arg.$slice !== "number")
throw MinimongoError("$slice must be a numeric value: " + field);
throw MinimongoError("$slice must be a numeric value", { field });
// XXX should check to make sure integer
if (arg.$slice > 0)
throw MinimongoError("$slice in $push must be zero or negative: " + field);
throw MinimongoError(
"$slice in $push must be zero or negative", { field });
slice = arg.$slice;
}
@@ -306,7 +316,7 @@ var MODIFIERS = {
var sortFunction = undefined;
if (arg.$sort) {
if (slice === undefined)
throw MinimongoError("$sort requires $slice to be present: " + field);
throw MinimongoError("$sort requires $slice to be present", { field });
// XXX this allows us to use a $sort whose value is an array, but that's
// actually an extension of the Node driver, so it won't work
// server-side. Could be confusing!
@@ -315,7 +325,7 @@ var MODIFIERS = {
for (var i = 0; i < toPush.length; i++) {
if (LocalCollection._f._type(toPush[i]) !== 3) {
throw MinimongoError("$push like modifiers using $sort " +
"require all elements to be objects: " + field);
"require all elements to be objects", { field });
}
}
}
@@ -350,7 +360,8 @@ var MODIFIERS = {
if (x === undefined)
target[field] = arg;
else if (!(x instanceof Array))
throw MinimongoError("Cannot apply $pushAll modifier to non-array: " + field);
throw MinimongoError(
"Cannot apply $pushAll modifier to non-array", { field });
else {
for (var i = 0; i < arg.length; i++)
x.push(arg[i]);
@@ -371,7 +382,8 @@ var MODIFIERS = {
if (x === undefined)
target[field] = values;
else if (!(x instanceof Array))
throw MinimongoError("Cannot apply $addToSet modifier to non-array: " + field);
throw MinimongoError(
"Cannot apply $addToSet modifier to non-array", { field });
else {
_.each(values, function (value) {
for (var i = 0; i < x.length; i++)
@@ -388,7 +400,8 @@ var MODIFIERS = {
if (x === undefined)
return;
else if (!(x instanceof Array))
throw MinimongoError("Cannot apply $pop modifier to non-array: " + field);
throw MinimongoError(
"Cannot apply $pop modifier to non-array", { field });
else {
if (typeof arg === 'number' && arg < 0)
x.splice(0, 1);
@@ -403,7 +416,8 @@ var MODIFIERS = {
if (x === undefined)
return;
else if (!(x instanceof Array))
throw MinimongoError("Cannot apply $pull/pullAll modifier to non-array: " + field);
throw MinimongoError(
"Cannot apply $pull/pullAll modifier to non-array", { field });
else {
var out = [];
if (arg != null && typeof arg === "object" && !(arg instanceof Array)) {
@@ -430,14 +444,16 @@ var MODIFIERS = {
},
$pullAll: function (target, field, arg) {
if (!(typeof arg === "object" && arg instanceof Array))
throw MinimongoError("Modifier $pushAll/pullAll allowed for arrays only: " + field);
throw MinimongoError(
"Modifier $pushAll/pullAll allowed for arrays only", { field });
if (target === undefined)
return;
var x = target[field];
if (x === undefined)
return;
else if (!(x instanceof Array))
throw MinimongoError("Cannot apply $pull/pullAll modifier to non-array: " + field);
throw MinimongoError(
"Cannot apply $pull/pullAll modifier to non-array", { field });
else {
var out = [];
for (var i = 0; i < x.length; i++) {
@@ -457,15 +473,17 @@ var MODIFIERS = {
$rename: function (target, field, arg, keypath, doc) {
if (keypath === arg)
// no idea why mongo has this restriction..
throw MinimongoError("$rename source must differ from target: " + field);
throw MinimongoError("$rename source must differ from target", { field });
if (target === null)
throw MinimongoError("$rename source field invalid: " + field);
throw MinimongoError("$rename source field invalid", { field });
if (typeof arg !== "string")
throw MinimongoError("$rename target must be a string: " + field);
throw MinimongoError("$rename target must be a string", { field });
if (arg.indexOf('\0') > -1) {
// Null bytes are not allowed in Mongo field names
// https://docs.mongodb.com/manual/reference/limits/#Restrictions-on-Field-Names
throw MinimongoError("The 'to' field for $rename cannot contain an embedded null byte: " + field);
throw MinimongoError(
"The 'to' field for $rename cannot contain an embedded null byte",
{ field });
}
if (target === undefined)
return;
@@ -475,13 +493,13 @@ var MODIFIERS = {
var keyparts = arg.split('.');
var target2 = findModTarget(doc, keyparts, {forbidArray: true});
if (target2 === null)
throw MinimongoError("$rename target field invalid: " + field);
throw MinimongoError("$rename target field invalid", { field });
var field2 = keyparts.pop();
target2[field2] = v;
},
$bit: function (target, field, arg) {
// XXX mongo only supports $bit on integers, and we only support
// native javascript numbers (doubles) so far, so we can't support $bit
throw MinimongoError("$bit is not supported: " + field);
throw MinimongoError("$bit is not supported", { field });
}
};

View File

@@ -7,6 +7,7 @@ Package.onUse(function (api) {
api.export('LocalCollection');
api.export('Minimongo');
api.export('MinimongoTest', { testOnly: true });
api.export('MinimongoError', { testOnly: true });
api.use([
'underscore',
'ejson',