228 lines
9.5 KiB
JavaScript
228 lines
9.5 KiB
JavaScript
//
|
|
// Upsert behavior tests for field extraction
|
|
//
|
|
|
|
var coll = db.upsert_field_gen;
|
|
coll.drop();
|
|
|
|
var upsertedResult = function(query, expr) {
|
|
coll.drop();
|
|
result = coll.update(query, expr, { upsert : true });
|
|
return result;
|
|
};
|
|
|
|
var upsertedField = function(query, expr, fieldName) {
|
|
assert.writeOK(upsertedResult(query, expr));
|
|
return coll.findOne()[fieldName];
|
|
};
|
|
|
|
var upsertedId = function(query, expr) {
|
|
return upsertedField(query, expr, "_id");
|
|
};
|
|
|
|
var upsertedXVal = function(query, expr) {
|
|
return upsertedField(query, expr, "x");
|
|
};
|
|
|
|
//
|
|
// _id field has special rules
|
|
//
|
|
|
|
// _id autogenerated
|
|
assert.neq(null, upsertedId({}, {}));
|
|
|
|
// _id autogenerated with add'l fields
|
|
assert.neq(null, upsertedId({}, { a : 1 }));
|
|
assert.eq(1, upsertedField({}, { a : 1 }, "a"));
|
|
assert.neq(null, upsertedId({}, { $set : { a : 1 } }, "a"));
|
|
assert.eq(1, upsertedField({}, { $set : { a : 1 } }, "a"));
|
|
assert.neq(null, upsertedId({}, { $setOnInsert : { a : 1 } }, "a"));
|
|
assert.eq(1, upsertedField({}, { $setOnInsert : { a : 1 } }, "a"));
|
|
|
|
// _id not autogenerated
|
|
assert.eq(1, upsertedId({}, { _id : 1 }));
|
|
assert.eq(1, upsertedId({}, { $set : { _id : 1 } }));
|
|
assert.eq(1, upsertedId({}, { $setOnInsert : { _id : 1 } }));
|
|
|
|
// _id type error
|
|
assert.writeError(upsertedResult({}, { _id : [1, 2] }));
|
|
assert.writeError(upsertedResult({}, { _id : undefined }));
|
|
assert.writeError(upsertedResult({}, { $set : { _id : [1, 2] } }));
|
|
// Fails in v2.6, no validation
|
|
assert.writeError(upsertedResult({}, { $setOnInsert : { _id : undefined } }));
|
|
|
|
// Check things that are pretty much the same for replacement and $op style upserts
|
|
for (var i = 0; i < 3; i++) {
|
|
|
|
// replacement style
|
|
var expr = {};
|
|
|
|
// $op style
|
|
if (i == 1)
|
|
expr = { $set : { a : 1 } };
|
|
if (i == 2)
|
|
expr = { $setOnInsert : { a : 1 } };
|
|
|
|
var isReplStyle = i == 0;
|
|
|
|
// _id extracted
|
|
assert.eq(1, upsertedId({ _id : 1 }, expr));
|
|
// All below fail in v2.6, no $ops for _id and $and/$or not explored
|
|
assert.eq(1, upsertedId({ _id : { $eq : 1 } }, expr));
|
|
assert.eq(1, upsertedId({ _id : { $all : [1] } }, expr));
|
|
assert.eq(1, upsertedId({ $and : [{ _id : 1 }] }, expr));
|
|
assert.eq(1, upsertedId({ $and : [{ _id : { $eq : 1 } }] }, expr));
|
|
assert.eq(1, upsertedId({ $or : [{ _id : 1 }] }, expr));
|
|
assert.eq(1, upsertedId({ $or : [{ _id : { $eq : 1 } }] }, expr));
|
|
|
|
// _id not extracted, autogenerated
|
|
assert.neq(1, upsertedId({ _id : { $gt : 1 } }, expr));
|
|
assert.neq(1, upsertedId({ _id : { $ne : 1 } }, expr));
|
|
assert.neq(1, upsertedId({ _id : { $in : [1] } }, expr));
|
|
assert.neq(1, upsertedId({ _id : { $in : [1, 2] } }, expr));
|
|
assert.neq(1, upsertedId({ _id : { $elemMatch : { $eq : 1 } } }, expr));
|
|
assert.neq(1, upsertedId({ _id : { $exists : true } }, expr));
|
|
assert.neq(1, upsertedId({ _id : { $not : { $eq : 1 } } }, expr));
|
|
assert.neq(1, upsertedId({ $or : [{ _id : 1 }, { _id : 1 }] }, expr));
|
|
assert.neq(1, upsertedId({ $or : [{ _id : { $eq : 1 } }, { _id : 2 }] }, expr));
|
|
assert.neq(1, upsertedId({ $nor : [{ _id : 1 }] }, expr));
|
|
assert.neq(1, upsertedId({ $nor : [{ _id : { $eq : 1 } }] }, expr));
|
|
assert.neq(1, upsertedId({ $nor : [{ _id : { $eq : 1 } }, { _id : 1 }] }, expr));
|
|
|
|
// _id extraction errors
|
|
assert.writeError(upsertedResult({ _id : [1, 2] }, expr));
|
|
assert.writeError(upsertedResult({ _id : undefined }, expr));
|
|
assert.writeError(upsertedResult({ _id : { $eq : [1, 2] } }, expr));
|
|
assert.writeError(upsertedResult({ _id : { $eq : undefined } }, expr));
|
|
assert.writeError(upsertedResult({ _id : { $all : [ 1, 2 ] } }, expr));
|
|
// All below fail in v2.6, non-_id fields completely ignored
|
|
assert.writeError(upsertedResult({ $and : [{ _id : 1 }, { _id : 1 }] }, expr));
|
|
assert.writeError(upsertedResult({ $and : [{ _id : { $eq : 1 } }, { _id : 2 }] }, expr));
|
|
assert.writeError(upsertedResult({ _id : 1, "_id.x" : 1 }, expr));
|
|
assert.writeError(upsertedResult({ _id : { x : 1 }, "_id.x" : 1 }, expr));
|
|
|
|
// Special case - nested _id fields only used on $op-style updates
|
|
if (isReplStyle) {
|
|
// Fails in v2.6
|
|
assert.writeError(upsertedResult({ "_id.x" : 1, "_id.y" : 2 }, expr));
|
|
}
|
|
else {
|
|
// Fails in v2.6
|
|
assert.docEq({ x : 1, y : 2 }, upsertedId({ "_id.x" : 1, "_id.y" : 2 }, expr));
|
|
}
|
|
}
|
|
|
|
// regex _id in expression is an error, no regex ids allowed
|
|
assert.writeError(upsertedResult({}, { _id : /abc/ }));
|
|
// Fails in v2.6, no validation
|
|
assert.writeError(upsertedResult({}, { $set : { _id : /abc/ } }));
|
|
|
|
// no regex _id extraction from query
|
|
assert.neq(/abc/, upsertedId({ _id : /abc/ }, {}));
|
|
|
|
//
|
|
// Regular field extraction
|
|
//
|
|
|
|
// Check things that are pretty much the same for replacement and $op style upserts
|
|
for (var i = 0; i < 3; i++) {
|
|
|
|
// replacement style
|
|
var expr = {};
|
|
|
|
// $op style
|
|
if (i == 1)
|
|
expr = { $set : { a : 1 } };
|
|
if (i == 2)
|
|
expr = { $setOnInsert : { a : 1 } };
|
|
|
|
var isReplStyle = i == 0;
|
|
|
|
// field extracted when replacement style
|
|
var value = isReplStyle ? undefined : 1;
|
|
assert.eq(value, upsertedXVal({ x : 1 }, expr));
|
|
assert.eq(value, upsertedXVal({ x : { $eq : 1 } }, expr));
|
|
assert.eq(value, upsertedXVal({ x : { $all : [1] } }, expr));
|
|
assert.eq(value, upsertedXVal({ $and : [{ x : 1 }] }, expr));
|
|
assert.eq(value, upsertedXVal({ $and : [{ x : { $eq : 1 } }] }, expr));
|
|
assert.eq(value, upsertedXVal({ $or : [{ x : 1 }] }, expr));
|
|
assert.eq(value, upsertedXVal({ $or : [{ x : { $eq : 1 } }] }, expr));
|
|
// Special types extracted
|
|
assert.eq(isReplStyle ? undefined : [1, 2], upsertedXVal({ x : [1, 2] }, expr));
|
|
|
|
// field not extracted
|
|
assert.eq(undefined, upsertedXVal({ x : { $gt : 1 } }, expr));
|
|
assert.eq(undefined, upsertedXVal({ x : { $ne : 1 } }, expr));
|
|
assert.eq(undefined, upsertedXVal({ x : { $in : [1] } }, expr));
|
|
assert.eq(undefined, upsertedXVal({ x : { $in : [1, 2] } }, expr));
|
|
assert.eq(undefined, upsertedXVal({ x : { $elemMatch : { $eq : 1 } } }, expr));
|
|
assert.eq(undefined, upsertedXVal({ x : { $exists : true } }, expr));
|
|
assert.eq(undefined, upsertedXVal({ x : { $not : { $eq : 1 } } }, expr));
|
|
assert.eq(undefined, upsertedXVal({ $or : [{ x : 1 }, { x : 1 }] }, expr));
|
|
assert.eq(undefined, upsertedXVal({ $or : [{ x : { $eq : 1 } }, { x : 2 }] }, expr));
|
|
assert.eq(undefined, upsertedXVal({ $nor : [{ x : 1 }] }, expr));
|
|
assert.eq(undefined, upsertedXVal({ $nor : [{ x : { $eq : 1 } }] }, expr));
|
|
assert.eq(undefined, upsertedXVal({ $nor : [{ x : { $eq : 1 } }, { x : 1 }] }, expr));
|
|
|
|
// field extraction errors
|
|
assert.writeError(upsertedResult({ x : undefined }, expr));
|
|
|
|
if (!isReplStyle) {
|
|
assert.writeError(upsertedResult({ x : { 'x.x' : 1 } }, expr));
|
|
assert.writeError(upsertedResult({ x : { $all : [ 1, 2 ] } }, expr));
|
|
assert.writeError(upsertedResult({ $and : [{ x : 1 }, { x : 1 }] }, expr));
|
|
assert.writeError(upsertedResult({ $and : [{ x : { $eq : 1 } }, { x : 2 }] }, expr));
|
|
}
|
|
else {
|
|
assert.eq(undefined, upsertedXVal({ x : { 'x.x' : 1 } }, expr));
|
|
assert.eq(undefined, upsertedXVal({ x : { $all : [ 1, 2 ] } }, expr));
|
|
assert.eq(undefined, upsertedXVal({ $and : [{ x : 1 }, { x : 1 }] }, expr));
|
|
assert.eq(undefined, upsertedXVal({ $and : [{ x : { $eq : 1 } }, { x : 2 }] }, expr));
|
|
}
|
|
|
|
// nested field extraction
|
|
var docValue = isReplStyle ? undefined : { x : 1 };
|
|
assert.docEq(docValue, upsertedXVal({ "x.x" : 1 }, expr));
|
|
assert.docEq(docValue, upsertedXVal({ "x.x" : { $eq : 1 } }, expr));
|
|
assert.docEq(docValue, upsertedXVal({ "x.x" : { $all : [1] } }, expr));
|
|
assert.docEq(docValue, upsertedXVal({ $and : [{ "x.x" : 1 }] }, expr));
|
|
assert.docEq(docValue, upsertedXVal({ $and : [{ "x.x" : { $eq : 1 } }] }, expr));
|
|
assert.docEq(docValue, upsertedXVal({ $or : [{ "x.x" : 1 }] }, expr));
|
|
assert.docEq(docValue, upsertedXVal({ $or : [{ "x.x" : { $eq : 1 } }] }, expr));
|
|
|
|
// nested field conflicts
|
|
if (!isReplStyle) {
|
|
assert.writeError(upsertedResult({ x : 1, "x.x" : 1 }, expr));
|
|
assert.writeError(upsertedResult({ x : {}, "x.x" : 1 }, expr));
|
|
assert.writeError(upsertedResult({ x : { x : 1 }, "x.x" : 1 }, expr));
|
|
assert.writeError(upsertedResult({ x : { x : 1 }, "x.y" : 1 }, expr));
|
|
assert.writeError(upsertedResult({ x : [1, { x : 1 }], "x.x" : 1 }, expr));
|
|
}
|
|
else {
|
|
assert.eq(undefined, upsertedXVal({ x : 1, "x.x" : 1 }, expr));
|
|
assert.eq(undefined, upsertedXVal({ x : {}, "x.x" : 1 }, expr));
|
|
assert.eq(undefined, upsertedXVal({ x : { x : 1 }, "x.x" : 1 }, expr));
|
|
assert.eq(undefined, upsertedXVal({ x : { x : 1 }, "x.y" : 1 }, expr));
|
|
assert.eq(undefined, upsertedXVal({ x : [1, { x : 1 }], "x.x" : 1 }, expr));
|
|
}
|
|
|
|
}
|
|
|
|
// regex field in expression is a value
|
|
assert.eq(/abc/, upsertedXVal({}, { x : /abc/ }));
|
|
assert.eq(/abc/, upsertedXVal({}, { $set : { x : /abc/ } }));
|
|
|
|
// no regex field extraction from query unless $eq'd
|
|
assert.eq(/abc/, upsertedXVal({ x : { $eq : /abc/ } }, { $set : { a : 1 } }));
|
|
assert.eq(undefined, upsertedXVal({ x : /abc/ }, { $set : { a : 1 } }));
|
|
|
|
// replacement-style updates ignore conflicts *except* on _id field
|
|
assert.eq(1, upsertedId({ _id : 1, x : [1, { x : 1 }], "x.x" : 1 }, {}));
|
|
|
|
// DBRef special cases
|
|
// make sure query doesn't error when creating doc for insert, since it's missing the rest of the
|
|
// dbref fields. SERVER-14024
|
|
// Fails in 2.6.1->3
|
|
assert.docEq(tojson(DBRef("a", 1)), upsertedXVal({ "x.$id" : 1 },
|
|
{ $set : { x : DBRef("a", 1) } }));
|