mirror of https://github.com/mongodb/mongo
1122 lines
39 KiB
JavaScript
1122 lines
39 KiB
JavaScript
(function() {
|
|
"use strict";
|
|
|
|
load("jstests/aggregation/extras/utils.js"); // For arrayEq and orderedArrayEq.
|
|
load("jstests/libs/sbe_assert_error_override.js");
|
|
|
|
const coll = db.computed_projection;
|
|
coll.drop();
|
|
const documents = [
|
|
{_id: 0, a: 1, b: "x", c: 10, zero: 0},
|
|
{_id: 1, a: 2, b: "y", c: 11},
|
|
{_id: 2, a: 3, b: "z", c: 12},
|
|
{_id: 3, x: {y: 1}},
|
|
{_id: 4, x: {y: 2}},
|
|
{_id: 5, x: {y: [1, 2, 3]}, v: {w: [4, 5, 6]}},
|
|
{_id: 6, x: {y: 4}, v: {w: 4}},
|
|
{_id: 7, x: [{y: 1}], v: [{w: 1}]},
|
|
{_id: 8, x: [{y: 1}, {y: 2}], v: [{w: 5}, {w: 6}]},
|
|
{_id: 9, x: [{y: 1}, {y: [1, 2, 3]}], v: [{w: 4}, {w: [4, 5, 6]}]},
|
|
{_id: 10, z: 1},
|
|
{_id: 11, z: 2},
|
|
{_id: 12, z: [1, 2, 3]},
|
|
{_id: 13, z: 3},
|
|
{_id: 14, z: 4},
|
|
{_id: 15, a: 10, x: 1},
|
|
{_id: 16, a: 10, x: 10},
|
|
{_id: 17, x: {y: [{z: 1}, {z: 2}]}},
|
|
{_id: 18, x: [[{y: 1}, {y: 2}], {y: 3}, {y: 4}, [[[{y: 5}]]], {y: 6}]},
|
|
{_id: 19, i: {j: 5}, k: {l: 10}},
|
|
{_id: 20, x: [[{y: 1}, {y: 2}], {y: 3}, {y: 4}, [[[{y: 5}]]], {y: 6}]},
|
|
{_id: 21, x: [[{y: {z: 1}}, {y: 2}], {y: 3}, {y: {z: 2}}, [[[{y: 5}, {y: {z: 3}}]]], {y: 6}]},
|
|
{
|
|
_id: 22,
|
|
tf: [true, false],
|
|
ff: [false, false],
|
|
t: true,
|
|
f: false,
|
|
n: null,
|
|
a: 1,
|
|
b: 0,
|
|
zero: 0
|
|
},
|
|
{_id: 23, i1: NumberInt(1), i2: NumberInt(-1), i3: NumberInt(-2147483648)},
|
|
{_id: 24, l1: NumberLong("12345678900"), l2: NumberLong("-12345678900")},
|
|
{_id: 25, s: "string", l: NumberLong("-9223372036854775808"), n: null},
|
|
{_id: 26, d1: 4.6, d2: -4.6, dec1: NumberDecimal("4.6"), dec2: NumberDecimal("-4.6")},
|
|
{_id: 27, dec1: NumberDecimal("-1.0"), dec2: NumberDecimal("2.0"), dec3: NumberDecimal("3.0")}
|
|
];
|
|
assert.commandWorked(coll.insert(documents));
|
|
|
|
// A concise way to express an "expected" result that takes the form
|
|
// [{_id: 0, foo: <BOOL>}, {_id, 1, foo: <BOOL>}, ..., {_id: 26, foo: <BOOL>}] by passing an object
|
|
// of the form {foo: [INTEGER_LIST]}, where INTEGER_LIST is the list of '_id' values for documents
|
|
// where "foo" should be true.
|
|
function computedProjectionWithBoolValues(boolProj) {
|
|
return documents.map(doc => {
|
|
const projectedDoc = {_id: doc._id};
|
|
Object.keys(boolProj).forEach(key => {
|
|
projectedDoc[key] = boolProj[key].includes(doc._id);
|
|
});
|
|
return projectedDoc;
|
|
});
|
|
}
|
|
|
|
const testCases = [
|
|
{
|
|
desc: "Single-level path 1",
|
|
expected: [
|
|
{_id: 0, foo: 1}, {_id: 1, foo: 2}, {_id: 2, foo: 3}, {_id: 3}, {_id: 4},
|
|
{_id: 5}, {_id: 6}, {_id: 7}, {_id: 8}, {_id: 9},
|
|
{_id: 10}, {_id: 11}, {_id: 12}, {_id: 13}, {_id: 14},
|
|
{_id: 15, foo: 10}, {_id: 16, foo: 10}, {_id: 17}, {_id: 18}, {_id: 19},
|
|
{_id: 20}, {_id: 21}, {_id: 22, foo: 1}, {_id: 23}, {_id: 24},
|
|
{_id: 25}, {_id: 26}, {_id: 27}
|
|
],
|
|
query: {},
|
|
proj: {_id: 1, foo: "$a"}
|
|
},
|
|
{
|
|
desc: "Single-level path 2",
|
|
expected: [
|
|
{_id: 0, foo: 1}, {_id: 1, foo: 2}, {_id: 2, foo: 3}, {_id: 3}, {_id: 4},
|
|
{_id: 5}, {_id: 6}, {_id: 7}, {_id: 8}, {_id: 9},
|
|
{_id: 10}, {_id: 11}, {_id: 12}, {_id: 13}, {_id: 14},
|
|
{_id: 15, foo: 10}, {_id: 16, foo: 10}, {_id: 17}, {_id: 18}, {_id: 19},
|
|
{_id: 20}, {_id: 21}, {_id: 22, foo: 1}, {_id: 23}, {_id: 24},
|
|
{_id: 25}, {_id: 26}, {_id: 27}
|
|
],
|
|
query: {},
|
|
proj: {foo: "$a"}
|
|
},
|
|
{
|
|
desc: "Single-level path 3",
|
|
expected: [
|
|
{foo: 1}, {foo: 2}, {foo: 3}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {},
|
|
{}, {foo: 10}, {foo: 10}, {}, {}, {}, {}, {}, {foo: 1}, {}, {}, {}, {}, {}
|
|
],
|
|
query: {},
|
|
proj: {_id: 0, foo: "$a"}
|
|
},
|
|
{
|
|
desc: "Two single-level paths",
|
|
expected: [
|
|
{_id: 0, foo: 1, bar: "x"},
|
|
{_id: 1, foo: 2, bar: "y"},
|
|
{_id: 2, foo: 3, bar: "z"},
|
|
{_id: 3},
|
|
{_id: 4},
|
|
{_id: 5},
|
|
{_id: 6},
|
|
{_id: 7},
|
|
{_id: 8},
|
|
{_id: 9},
|
|
{_id: 10},
|
|
{_id: 11},
|
|
{_id: 12},
|
|
{_id: 13},
|
|
{_id: 14},
|
|
{_id: 15, foo: 10},
|
|
{_id: 16, foo: 10},
|
|
{_id: 17},
|
|
{_id: 18},
|
|
{_id: 19},
|
|
{_id: 20},
|
|
{_id: 21},
|
|
{_id: 22, foo: 1, bar: 0},
|
|
{_id: 23},
|
|
{_id: 24},
|
|
{_id: 25},
|
|
{_id: 26},
|
|
{_id: 27}
|
|
],
|
|
query: {},
|
|
proj: {_id: 1, foo: "$a", bar: "$b"}
|
|
},
|
|
{
|
|
desc: "Simple addition",
|
|
expected: [{_id: 0, foo: 11}, {_id: 1, foo: 13}, {_id: 2, foo: 15}],
|
|
query: {c: {$gt: 0}},
|
|
proj: {foo: {$add: ["$a", "$c"]}}
|
|
},
|
|
{
|
|
desc: "$add with arity 1 and 3",
|
|
expected: [{_id: 27, add1: NumberDecimal("-1.0"), add3: NumberDecimal("4.0")}],
|
|
query: {dec1: NumberDecimal("-1.0")},
|
|
proj: {add1: {$add: "$dec1"}, add3: {$add: ["$dec1", "$dec2", "$dec3"]}}
|
|
},
|
|
{
|
|
desc: "Single-level path 4",
|
|
expected: [
|
|
{_id: 0, a: 1, foo: "x"},
|
|
{_id: 1, a: 2, foo: "y"},
|
|
{_id: 2, a: 3, foo: "z"},
|
|
{_id: 3},
|
|
{_id: 4},
|
|
{_id: 5},
|
|
{_id: 6},
|
|
{_id: 7},
|
|
{_id: 8},
|
|
{_id: 9},
|
|
{_id: 10},
|
|
{_id: 11},
|
|
{_id: 12},
|
|
{_id: 13},
|
|
{_id: 14},
|
|
{_id: 15, a: 10},
|
|
{_id: 16, a: 10},
|
|
{_id: 17},
|
|
{_id: 18},
|
|
{_id: 19},
|
|
{_id: 20},
|
|
{_id: 21},
|
|
{_id: 22, a: 1, foo: 0},
|
|
{_id: 23},
|
|
{_id: 24},
|
|
{_id: 25},
|
|
{_id: 26},
|
|
{_id: 27}
|
|
],
|
|
query: {},
|
|
proj: {a: 1, foo: "$b"}
|
|
},
|
|
{
|
|
desc: "Two-level path 1",
|
|
expected: [
|
|
{_id: 0},
|
|
{_id: 1},
|
|
{_id: 2},
|
|
{_id: 3, foo: 1},
|
|
{_id: 4, foo: 2},
|
|
{_id: 5, foo: [1, 2, 3]},
|
|
{_id: 6, foo: 4},
|
|
{_id: 7, foo: [1]},
|
|
{_id: 8, foo: [1, 2]},
|
|
{_id: 9, foo: [1, [1, 2, 3]]},
|
|
{_id: 10},
|
|
{_id: 11},
|
|
{_id: 12},
|
|
{_id: 13},
|
|
{_id: 14},
|
|
{_id: 15},
|
|
{_id: 16},
|
|
{_id: 17, foo: [{z: 1}, {z: 2}]},
|
|
{_id: 18, foo: [3, 4, 6]},
|
|
{_id: 19},
|
|
{_id: 20, foo: [3, 4, 6]},
|
|
{_id: 21, foo: [3, {z: 2}, 6]},
|
|
{_id: 22},
|
|
{_id: 23},
|
|
{_id: 24},
|
|
{_id: 25},
|
|
{_id: 26},
|
|
{_id: 27}
|
|
],
|
|
query: {},
|
|
proj: {_id: 1, foo: "$x.y"}
|
|
},
|
|
{
|
|
desc: "Two-level path 2",
|
|
expected: [
|
|
{_id: 0},
|
|
{_id: 1},
|
|
{_id: 2},
|
|
{_id: 3, foo: 1},
|
|
{_id: 4, foo: 2},
|
|
{_id: 5, foo: [1, 2, 3]},
|
|
{_id: 6, foo: 4},
|
|
{_id: 7, foo: [1]},
|
|
{_id: 8, foo: [1, 2]},
|
|
{_id: 9, foo: [1, [1, 2, 3]]},
|
|
{_id: 10},
|
|
{_id: 11},
|
|
{_id: 12},
|
|
{_id: 13},
|
|
{_id: 14},
|
|
{_id: 15},
|
|
{_id: 16},
|
|
{_id: 17, foo: [{z: 1}, {z: 2}]},
|
|
{_id: 18, foo: [3, 4, 6]},
|
|
{_id: 19},
|
|
{_id: 20, foo: [3, 4, 6]},
|
|
{_id: 21, foo: [3, {z: 2}, 6]},
|
|
{_id: 22},
|
|
{_id: 23},
|
|
{_id: 24},
|
|
{_id: 25},
|
|
{_id: 26},
|
|
{_id: 27}
|
|
],
|
|
query: {},
|
|
proj: {foo: "$x.y"}
|
|
},
|
|
{
|
|
desc: "Two-level path 3",
|
|
expected: [
|
|
{},
|
|
{},
|
|
{},
|
|
{foo: 1},
|
|
{foo: 2},
|
|
{foo: [1, 2, 3]},
|
|
{foo: 4},
|
|
{foo: [1]},
|
|
{foo: [1, 2]},
|
|
{foo: [1, [1, 2, 3]]},
|
|
{},
|
|
{},
|
|
{},
|
|
{},
|
|
{},
|
|
{},
|
|
{},
|
|
{foo: [{z: 1}, {z: 2}]},
|
|
{foo: [3, 4, 6]},
|
|
{},
|
|
{foo: [3, 4, 6]},
|
|
{foo: [3, {z: 2}, 6]},
|
|
{},
|
|
{},
|
|
{},
|
|
{},
|
|
{},
|
|
{}
|
|
],
|
|
query: {},
|
|
proj: {_id: 0, foo: "$x.y"}
|
|
},
|
|
{
|
|
desc: "Two two-level paths",
|
|
expected: [
|
|
{_id: 0},
|
|
{_id: 1},
|
|
{_id: 2},
|
|
{_id: 3, foo: 1},
|
|
{_id: 4, foo: 2},
|
|
{_id: 5, foo: [1, 2, 3], bar: [4, 5, 6]},
|
|
{_id: 6, foo: 4, bar: 4},
|
|
{_id: 7, foo: [1], bar: [1]},
|
|
{_id: 8, foo: [1, 2], bar: [5, 6]},
|
|
{_id: 9, foo: [1, [1, 2, 3]], bar: [4, [4, 5, 6]]},
|
|
{_id: 10},
|
|
{_id: 11},
|
|
{_id: 12},
|
|
{_id: 13},
|
|
{_id: 14},
|
|
{_id: 15},
|
|
{_id: 16},
|
|
{_id: 17, foo: [{z: 1}, {z: 2}]},
|
|
{_id: 18, foo: [3, 4, 6]},
|
|
{_id: 19},
|
|
{_id: 20, foo: [3, 4, 6]},
|
|
{_id: 21, foo: [3, {z: 2}, 6]},
|
|
{_id: 22},
|
|
{_id: 23},
|
|
{_id: 24},
|
|
{_id: 25},
|
|
{_id: 26},
|
|
{_id: 27}
|
|
],
|
|
query: {},
|
|
proj: {foo: "$x.y", bar: "$v.w"}
|
|
},
|
|
{
|
|
desc: "Addition of two-level paths",
|
|
expected: [{_id: 19, foo: 15}],
|
|
query: {"i.j": {$gt: 0}},
|
|
proj: {foo: {$add: ["$i.j", "$k.l"]}}
|
|
},
|
|
{
|
|
desc: "Dotted-path projection and two-level path",
|
|
expected: [
|
|
{_id: 0},
|
|
{_id: 1},
|
|
{_id: 2},
|
|
{_id: 3, x: {y: 1}},
|
|
{_id: 4, x: {y: 2}},
|
|
{_id: 5, x: {y: [1, 2, 3]}, foo: [4, 5, 6]},
|
|
{_id: 6, x: {y: 4}, foo: 4},
|
|
{_id: 7, x: [{y: 1}], foo: [1]},
|
|
{_id: 8, x: [{y: 1}, {y: 2}], foo: [5, 6]},
|
|
{_id: 9, x: [{y: 1}, {y: [1, 2, 3]}], foo: [4, [4, 5, 6]]},
|
|
{_id: 10},
|
|
{_id: 11},
|
|
{_id: 12},
|
|
{_id: 13},
|
|
{_id: 14},
|
|
{_id: 15},
|
|
{_id: 16},
|
|
{_id: 17, x: {y: [{z: 1}, {z: 2}]}},
|
|
{_id: 18, x: [[{y: 1}, {y: 2}], {y: 3}, {y: 4}, [[[{y: 5}]]], {y: 6}]},
|
|
{_id: 19},
|
|
{_id: 20, x: [[{y: 1}, {y: 2}], {y: 3}, {y: 4}, [[[{y: 5}]]], {y: 6}]},
|
|
{
|
|
_id: 21,
|
|
x: [[{y: {z: 1}}, {y: 2}], {y: 3}, {y: {z: 2}}, [[[{y: 5}, {y: {z: 3}}]]], {y: 6}]
|
|
},
|
|
{_id: 22},
|
|
{_id: 23},
|
|
{_id: 24},
|
|
{_id: 25},
|
|
{_id: 26},
|
|
{_id: 27}
|
|
],
|
|
query: {},
|
|
proj: {"x.y": 1, foo: "$v.w"}
|
|
},
|
|
//
|
|
// Test simple expressions with the $abs operator.
|
|
//
|
|
{
|
|
desc: "$abs operator",
|
|
expected: [{_id: 23, abs_i1: 1, abs_i2: 1, abs_i3: NumberLong("2147483648")}],
|
|
query: {i1: 1},
|
|
proj: {abs_i1: {$abs: "$i1"}, abs_i2: {$abs: "$i2"}, abs_i3: {$abs: "$i3"}}
|
|
},
|
|
{
|
|
desc: "$abs with NumberLong input",
|
|
expected: [{_id: 24, abs_l1: NumberLong("12345678900"), abs_l2: NumberLong("12345678900")}],
|
|
query: {l1: NumberLong("12345678900")},
|
|
proj: {abs_l1: {$abs: "$l1"}, abs_l2: {$abs: "$l2"}}
|
|
},
|
|
{
|
|
desc: "$abs with NumberDecimal input",
|
|
expected: [{
|
|
_id: 26,
|
|
abs_d1: 4.6,
|
|
abs_d2: 4.6,
|
|
abs_dec1: NumberDecimal("4.6"),
|
|
abs_dec2: NumberDecimal("4.6")
|
|
}],
|
|
query: {d1: 4.6},
|
|
proj: {
|
|
abs_d1: {$abs: "$d1"},
|
|
abs_d2: {$abs: "$d2"},
|
|
abs_dec1: {$abs: "$dec1"},
|
|
abs_dec2: {$abs: "$dec2"}
|
|
}
|
|
},
|
|
{
|
|
desc: "$abs with string input",
|
|
expectedErrorCode: 28765,
|
|
query: {s: "string"},
|
|
proj: {abs_s: {$abs: "$s"}}
|
|
},
|
|
{
|
|
desc: "$abs with MIN_LONG_LONG input",
|
|
expectedErrorCode: 28680,
|
|
query: {s: "string"},
|
|
proj: {abs_l: {$abs: "$l"}}
|
|
},
|
|
{
|
|
desc: "$abs with missing input",
|
|
expected: [{_id: 25, abs_n: null, abs_ne: null}],
|
|
query: {s: "string"},
|
|
proj: {abs_n: {$abs: "$n"}, abs_ne: {$abs: "$non_existent"}}
|
|
},
|
|
//
|
|
// Test $and/$or.
|
|
//
|
|
{
|
|
desc: "Single-branch $and",
|
|
expected: [
|
|
{_id: 0, foo: true}, {_id: 1, foo: true}, {_id: 2, foo: true},
|
|
{_id: 3, foo: false}, {_id: 4, foo: false}, {_id: 5, foo: false},
|
|
{_id: 6, foo: false}, {_id: 7, foo: false}, {_id: 8, foo: false},
|
|
{_id: 9, foo: false}, {_id: 10, foo: false}, {_id: 11, foo: false},
|
|
{_id: 12, foo: false}, {_id: 13, foo: false}, {_id: 14, foo: false},
|
|
{_id: 15, foo: true}, {_id: 16, foo: true}, {_id: 17, foo: false},
|
|
{_id: 18, foo: false}, {_id: 19, foo: false}, {_id: 20, foo: false},
|
|
{_id: 21, foo: false}, {_id: 22, foo: true}, {_id: 23, foo: false},
|
|
{_id: 24, foo: false}, {_id: 25, foo: false}, {_id: 26, foo: false},
|
|
{_id: 27, foo: false}
|
|
],
|
|
query: {},
|
|
proj: {foo: {$and: ["$a"]}}
|
|
},
|
|
{
|
|
desc: "Single-branch $or",
|
|
expected: [
|
|
{_id: 0, foo: true}, {_id: 1, foo: true}, {_id: 2, foo: true},
|
|
{_id: 3, foo: false}, {_id: 4, foo: false}, {_id: 5, foo: false},
|
|
{_id: 6, foo: false}, {_id: 7, foo: false}, {_id: 8, foo: false},
|
|
{_id: 9, foo: false}, {_id: 10, foo: false}, {_id: 11, foo: false},
|
|
{_id: 12, foo: false}, {_id: 13, foo: false}, {_id: 14, foo: false},
|
|
{_id: 15, foo: true}, {_id: 16, foo: true}, {_id: 17, foo: false},
|
|
{_id: 18, foo: false}, {_id: 19, foo: false}, {_id: 20, foo: false},
|
|
{_id: 21, foo: false}, {_id: 22, foo: true}, {_id: 23, foo: false},
|
|
{_id: 24, foo: false}, {_id: 25, foo: false}, {_id: 26, foo: false},
|
|
{_id: 27, foo: false}
|
|
],
|
|
query: {},
|
|
proj: {foo: {$or: ["$a"]}}
|
|
},
|
|
{
|
|
desc: "$and with BSONNull branch",
|
|
expected: [{_id: 22, foo: false}],
|
|
query: {_id: 22, a: 1},
|
|
proj: {foo: {$and: ["$n"]}}
|
|
},
|
|
{
|
|
desc: "$or with BSONNull branch",
|
|
expected: [{_id: 22, foo: false}],
|
|
query: {_id: 22, a: 1},
|
|
proj: {foo: {$or: ["$n"]}}
|
|
},
|
|
{
|
|
desc: "$and with missing path in branch",
|
|
expected: [{_id: 22, foo: false}],
|
|
query: {_id: 22, a: 1},
|
|
proj: {foo: {$and: ["$nonexistent"]}}
|
|
},
|
|
{
|
|
desc: "$or with missing path in branch",
|
|
expected: [{_id: 22, foo: false}],
|
|
query: {_id: 22, a: 1},
|
|
proj: {foo: {$or: ["$nonexistent"]}}
|
|
},
|
|
{
|
|
desc: "$and with array branch",
|
|
expected: [{_id: 22, foo: true, bar: true}],
|
|
query: {_id: 22, a: 1},
|
|
proj: {foo: {$and: []}, bar: {$and: ["$tf", "$t", "$a"]}}
|
|
},
|
|
{
|
|
desc: "Three-branch $or",
|
|
expected: [{_id: 22, foo: false, bar: false}],
|
|
query: {_id: 22, a: 1},
|
|
proj: {foo: {$or: []}, bar: {$or: ["$f", "$n", "$nonexistent"]}}
|
|
},
|
|
{
|
|
desc: "Multiple computed $and projections 1",
|
|
expected: [{_id: 22, foo: false, bar: false, baz: false}],
|
|
query: {_id: 22, a: 1},
|
|
proj: {foo: {$and: ["$a", "$b"]}, bar: {$and: ["$a", "$f"]}, baz: {$and: ["$a", "$n"]}}
|
|
},
|
|
{
|
|
desc: "Multiple computed $or projections",
|
|
expected: [{_id: 22, foo: true, bar: true, baz: true}],
|
|
query: {_id: 22, a: 1},
|
|
proj: {foo: {$or: ["$a", "$b"]}, bar: {$or: ["$a", "$f"]}, baz: {$or: ["$a", "$n"]}}
|
|
},
|
|
{
|
|
desc: "Multiple computed $and projections 2",
|
|
expected: [{_id: 22, foo: true, bar: false}],
|
|
query: {_id: 22, a: 1},
|
|
proj: {foo: {$and: ["$ff", "$t"]}, bar: {$and: ["$nonexistent", "$t"]}}
|
|
},
|
|
//
|
|
// $switch and $cond tests.
|
|
//
|
|
{
|
|
desc: "Single-case $switch with default",
|
|
expected: [
|
|
{_id: 0, foo: "x"}, {_id: 1, foo: 11}, {_id: 2, foo: 12}, {_id: 3}, {_id: 4},
|
|
{_id: 5}, {_id: 6}, {_id: 7}, {_id: 8}, {_id: 9},
|
|
{_id: 10}, {_id: 11}, {_id: 12}, {_id: 13}, {_id: 14},
|
|
{_id: 15}, {_id: 16}, {_id: 17}, {_id: 18}, {_id: 19},
|
|
{_id: 20}, {_id: 21}, {_id: 22, foo: 0}, {_id: 23}, {_id: 24},
|
|
{_id: 25}, {_id: 26}, {_id: 27}
|
|
],
|
|
query: {},
|
|
proj: {foo: {$switch: {branches: [{case: {$eq: ["$a", 1]}, then: "$b"}], default: "$c"}}}
|
|
},
|
|
{
|
|
desc: "$cond",
|
|
expected: [
|
|
{_id: 0, foo: "x"}, {_id: 1, foo: 11}, {_id: 2, foo: 12}, {_id: 3}, {_id: 4},
|
|
{_id: 5}, {_id: 6}, {_id: 7}, {_id: 8}, {_id: 9},
|
|
{_id: 10}, {_id: 11}, {_id: 12}, {_id: 13}, {_id: 14},
|
|
{_id: 15}, {_id: 16}, {_id: 17}, {_id: 18}, {_id: 19},
|
|
{_id: 20}, {_id: 21}, {_id: 22, foo: 0}, {_id: 23}, {_id: 24},
|
|
{_id: 25}, {_id: 26}, {_id: 27}
|
|
],
|
|
query: {},
|
|
proj: {foo: {$cond: {if: {$eq: ["$a", 1]}, then: "$b", else: "$c"}}}
|
|
},
|
|
{
|
|
desc: "Two-case $switch with default",
|
|
expected: [
|
|
{_id: 0, foo: "x"}, {_id: 1, foo: 2}, {_id: 2, foo: 12}, {_id: 3}, {_id: 4},
|
|
{_id: 5}, {_id: 6}, {_id: 7}, {_id: 8}, {_id: 9},
|
|
{_id: 10}, {_id: 11}, {_id: 12}, {_id: 13}, {_id: 14},
|
|
{_id: 15}, {_id: 16}, {_id: 17}, {_id: 18}, {_id: 19},
|
|
{_id: 20}, {_id: 21}, {_id: 22, foo: 0}, {_id: 23}, {_id: 24},
|
|
{_id: 25}, {_id: 26}, {_id: 27}
|
|
],
|
|
query: {},
|
|
proj: {
|
|
foo: {
|
|
$switch: {
|
|
branches: [
|
|
{case: {$eq: ["$a", 1]}, then: "$b"},
|
|
{case: {$eq: ["$b", "y"]}, then: "$a"}
|
|
],
|
|
default: "$c"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
//
|
|
// Failing expressions
|
|
//
|
|
{
|
|
desc: "$abs with string input as $and branch",
|
|
expectedErrorCode: 28765,
|
|
query: {s: "string"},
|
|
proj: {foo: {$and: [{$abs: ["$s"]}, "$n"]}}
|
|
},
|
|
{
|
|
desc: "$abs with string input as $or branch",
|
|
expectedErrorCode: 28765,
|
|
query: {s: "string"},
|
|
proj: {foo: {$or: [{$abs: ["$s"]}, "$s"]}}
|
|
},
|
|
{
|
|
desc: "Switch fall-through with no default",
|
|
expectedErrorCode: 40066,
|
|
query: {},
|
|
proj: {
|
|
foo: {
|
|
$switch: {
|
|
branches: [
|
|
{case: {$eq: ["$a", 1]}, then: "$b"},
|
|
{case: {$eq: ["$b", "y"]}, then: "$a"}
|
|
]
|
|
// No default case.
|
|
}
|
|
}
|
|
}
|
|
},
|
|
{
|
|
desc: "$abs with string input as case condition",
|
|
expectedErrorCode: 28765,
|
|
query: {s: "string"},
|
|
proj: {foo: {$switch: {branches: [{case: {$gt: [{$abs: ["$s"]}, 0]}, then: "$n"}]}}}
|
|
},
|
|
{
|
|
desc: "$abs with string input as case result",
|
|
expectedErrorCode: 28765,
|
|
query: {s: "string"},
|
|
proj: {foo: {$switch: {branches: [{case: {$eq: ["$s", "string"]}, then: {$abs: ["$s"]}}]}}}
|
|
},
|
|
{
|
|
desc: "$abs with string input as $switch default",
|
|
expectedErrorCode: 28765,
|
|
query: {s: "string"},
|
|
proj: {
|
|
foo:
|
|
{$switch: {branches: [{case: {$eq: ["$s", 0]}, then: "$n"}], default: {$abs: "$s"}}}
|
|
}
|
|
},
|
|
{
|
|
desc: "$abs with string input as $cond condition",
|
|
expectedErrorCode: 28765,
|
|
query: {s: "string"},
|
|
proj: {foo: {$cond: {if: {$eq: [{$abs: "$s"}, "$n"]}, then: "$b", else: "$c"}}}
|
|
},
|
|
{
|
|
desc: "$abs with string input as $cond result (then)",
|
|
expectedErrorCode: 28765,
|
|
query: {s: "string"},
|
|
proj: {foo: {$cond: {if: {$eq: ["$s", "string"]}, then: {$abs: ["$s"]}, else: "$c"}}}
|
|
},
|
|
{
|
|
desc: "$abs with string input as $cond result (else)",
|
|
expectedErrorCode: 28765,
|
|
query: {s: "string"},
|
|
proj: {foo: {$cond: {if: {$eq: ["$s", "gnirts"]}, then: "$b", else: {$abs: ["$s"]}}}}
|
|
},
|
|
//
|
|
// Test short circuiting: these queries have expressions that would fail (because |$x| is
|
|
// invalid) but won't because they do not execute.
|
|
//
|
|
{
|
|
desc: "$abs with string input as short-circuited $and branch",
|
|
expected: [{_id: 25, foo: false}],
|
|
query: {s: "string"},
|
|
proj: {foo: {$and: ["$n", {$abs: ["$s"]}]}}
|
|
},
|
|
{
|
|
desc: "$abs with string input as short-circuited $or branch",
|
|
expected: [{_id: 25, foo: true}],
|
|
query: {s: "string"},
|
|
proj: {foo: {$or: ["$s", {$abs: ["$s"]}]}}
|
|
},
|
|
//
|
|
// Test that short-circuited branches do not do any work, such as traversing an array. The
|
|
// short-circuited branches cointain divide by zero operation which if it were to execute
|
|
// would result in an error from the query that would cause the test to fail.
|
|
//
|
|
{
|
|
desc: "$divide by zero in short-circuited $and/$or branches",
|
|
expected: [{_id: 22, foo: false, bar: true}],
|
|
query: {_id: 22, a: 1},
|
|
proj: {
|
|
foo: {$and: ["$f", {$divide: [1, "$zero"]}]},
|
|
bar: {$or: ["$t", {$divide: [1, "$zero"]}]}
|
|
}
|
|
},
|
|
{
|
|
desc: "$divide by zero in nested short-circuited $or branches",
|
|
expected: [{_id: 22, foo: false, bar: true}],
|
|
query: {_id: 22, a: 1},
|
|
proj: {
|
|
foo: {$and: ["$f", {$or: ["$f", {$divide: [1, "$zero"]}]}, {$eq: ["$a", 1]}]},
|
|
bar: {$and: ["$t", {$or: ["$t", {$divide: [1, "$zero"]}]}, {$eq: ["$a", 1]}]}
|
|
}
|
|
},
|
|
{
|
|
desc: "$divide by zero in untaken $switch cases",
|
|
expected: [{_id: 0, foo: "x"}, {_id: 22, foo: 0}],
|
|
query: {a: 1},
|
|
proj: {
|
|
foo: {
|
|
$switch: {
|
|
branches: [
|
|
{case: {$eq: ["$a", 2]}, then: {$divide: [1, "$zero"]}},
|
|
{case: {$eq: ["$a", 3]}, then: {$divide: [1, "$zero"]}}
|
|
],
|
|
default: "$b"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
{
|
|
desc: "$divide by zero in unevaluated case condition and untaken $switch default branch",
|
|
expected: [{_id: 0, foo: "x"}, {_id: 22, foo: 0}],
|
|
query: {a: 1},
|
|
proj: {
|
|
foo: {
|
|
$switch: {
|
|
branches: [
|
|
{case: {$eq: ["$a", 1]}, then: "$b"},
|
|
{case: {$divide: [1, "$zero"]}, then: {$divide: [1, "$zero"]}}
|
|
],
|
|
default: {$divide: [1, "$zero"]}
|
|
}
|
|
}
|
|
}
|
|
},
|
|
{
|
|
desc: "$divide by zero in untaken $cond branch (else)",
|
|
expected: [{_id: 0, foo: "x"}, {_id: 22, foo: 0}],
|
|
query: {a: 1},
|
|
proj: {foo: {$cond: {if: {$eq: ["$a", 1]}, then: "$b", else: {$divide: [1, "$zero"]}}}}
|
|
},
|
|
{
|
|
desc: "$divide by zero in untaken $cond branch (then)",
|
|
expected: [{_id: 0, foo: "x"}, {_id: 22, foo: 0}],
|
|
query: {a: 1},
|
|
proj: {foo: {$cond: {if: {$eq: ["$a", 2]}, then: {$divide: [1, "$zero"]}, else: "$b"}}}
|
|
},
|
|
//
|
|
// $let tests.
|
|
//
|
|
{
|
|
desc: "$let with single-path variable definitions 1",
|
|
expected: computedProjectionWithBoolValues({foo: [0, 1, 2, 15, 16, 22]}),
|
|
query: {},
|
|
proj: {foo: {$let: {vars: {va: "$a", vb: "$b"}, "in": {$and: "$$va"}}}}
|
|
},
|
|
{
|
|
desc: "$let with single-path variable definitions 2",
|
|
expected: computedProjectionWithBoolValues({foo: [0, 1, 2]}),
|
|
query: {},
|
|
proj: {foo: {$let: {vars: {va: "$a", vb: "$b"}, "in": {$and: "$$vb"}}}}
|
|
},
|
|
{
|
|
desc: "$let with single-path variable definitions 3",
|
|
expected: computedProjectionWithBoolValues({foo: [0, 1, 2]}),
|
|
query: {},
|
|
proj: {foo: {$let: {vars: {va: "$a", vb: "$b"}, "in": {$and: ["$$va", "$$vb"]}}}}
|
|
},
|
|
{
|
|
desc: "$let with $and variable definition",
|
|
expected: computedProjectionWithBoolValues({foo: [0, 1, 2]}),
|
|
query: {},
|
|
proj: {foo: {$let: {vars: {va: {$and: ["$a", "$b"]}}, "in": "$$va"}}}
|
|
},
|
|
{
|
|
desc: "Two-level path including $let variable",
|
|
expected: [
|
|
{_id: 0},
|
|
{_id: 1},
|
|
{_id: 2},
|
|
{_id: 3, foo: 1},
|
|
{_id: 4, foo: 2},
|
|
{_id: 5, foo: [1, 2, 3]},
|
|
{_id: 6, foo: 4},
|
|
{_id: 7, foo: [1]},
|
|
{_id: 8, foo: [1, 2]},
|
|
{_id: 9, foo: [1, [1, 2, 3]]},
|
|
{_id: 10},
|
|
{_id: 11},
|
|
{_id: 12},
|
|
{_id: 13},
|
|
{_id: 14},
|
|
{_id: 15},
|
|
{_id: 16},
|
|
{_id: 17, foo: [{z: 1}, {z: 2}]},
|
|
{_id: 18, foo: [3, 4, 6]},
|
|
{_id: 19},
|
|
{_id: 20, foo: [3, 4, 6]},
|
|
{_id: 21, foo: [3, {z: 2}, 6]},
|
|
{_id: 22},
|
|
{_id: 23},
|
|
{_id: 24},
|
|
{_id: 25},
|
|
{_id: 26},
|
|
{_id: 27}
|
|
],
|
|
query: {},
|
|
proj: {foo: {$let: {vars: {va: "$x"}, "in": "$$va.y"}}}
|
|
},
|
|
{
|
|
desc: "Nested $let expressions",
|
|
expected: computedProjectionWithBoolValues({foo: [22]}),
|
|
query: {},
|
|
proj: {
|
|
foo: {
|
|
$let: {
|
|
vars: {vt: "$t", vf: "$f"},
|
|
"in": {
|
|
$let: {vars: {vf: "$$vt", va: "$a"},
|
|
"in": {$and: ["$$vt", "$$vf", "$$va"]}}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
},
|
|
{
|
|
desc: "$let with variable definition including nested $let",
|
|
expected: [{_id: 22, foo: false}],
|
|
query: {_id: 22, a: 1},
|
|
proj: {
|
|
foo: {
|
|
$let: {
|
|
vars:
|
|
{va: {$let: {vars: {vt: "$t", va: "$va"}, "in": {$and: ["$$vt", "$$va"]}}}},
|
|
"in": "$$va"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
{
|
|
desc: "$let renaming $$CURRENT",
|
|
expected: [
|
|
{_id: 0, foo: 1}, {_id: 1, foo: 2}, {_id: 2, foo: 3}, {_id: 3}, {_id: 4},
|
|
{_id: 5}, {_id: 6}, {_id: 7}, {_id: 8}, {_id: 9},
|
|
{_id: 10}, {_id: 11}, {_id: 12}, {_id: 13}, {_id: 14},
|
|
{_id: 15, foo: 10}, {_id: 16, foo: 10}, {_id: 17}, {_id: 18}, {_id: 19},
|
|
{_id: 20}, {_id: 21}, {_id: 22, foo: 1}, {_id: 23}, {_id: 24},
|
|
{_id: 25}, {_id: 26}, {_id: 27}
|
|
],
|
|
query: {},
|
|
proj: {foo: {$let: {vars: {doc: "$$CURRENT"}, "in": "$$doc.a"}}}
|
|
},
|
|
{
|
|
desc: "$let shadowing $$CURRENT",
|
|
expected: [
|
|
{_id: 0, foo: 1}, {_id: 1, foo: 2}, {_id: 2, foo: 3}, {_id: 3}, {_id: 4},
|
|
{_id: 5}, {_id: 6}, {_id: 7}, {_id: 8}, {_id: 9},
|
|
{_id: 10}, {_id: 11}, {_id: 12}, {_id: 13}, {_id: 14},
|
|
{_id: 15, foo: 10}, {_id: 16, foo: 10}, {_id: 17}, {_id: 18}, {_id: 19},
|
|
{_id: 20}, {_id: 21}, {_id: 22, foo: 1}, {_id: 23}, {_id: 24},
|
|
{_id: 25}, {_id: 26}, {_id: 27}
|
|
],
|
|
query: {},
|
|
proj: {foo: {$let: {vars: {CURRENT: "$$CURRENT.a"}, "in": "$$CURRENT"}}}
|
|
},
|
|
{
|
|
desc: "$$REMOVE",
|
|
expected: documents.map(doc => ({_id: doc._id})),
|
|
query: {},
|
|
proj: {a: "$$REMOVE"}
|
|
},
|
|
{
|
|
desc: "$$REMOVE with additional path components",
|
|
expected: documents.map(doc => ({_id: doc._id})),
|
|
query: {},
|
|
proj: {a: "$$REMOVE.x.y"}
|
|
},
|
|
{
|
|
desc: "$lt",
|
|
expected: computedProjectionWithBoolValues(
|
|
{foo: [3, 4, 5, 6, 7, 8, 9, 17, 18, 20, 21], bar: [0, 1, 2], baz: [5, 8, 9], qux: []}),
|
|
query: {},
|
|
proj: {
|
|
foo: {$lt: ["$a", "$x"]},
|
|
bar: {$lt: ["$a", "$b"]},
|
|
baz: {$lt: ["$x.y", "$v.w"]},
|
|
qux: {$lt: ["$a", "$nonexistent"]}
|
|
}
|
|
},
|
|
{
|
|
desc: "$lte",
|
|
expected: computedProjectionWithBoolValues({
|
|
foo: [
|
|
3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
|
|
16, 17, 18, 19, 20, 21, 23, 24, 25, 26, 27
|
|
],
|
|
bar: [
|
|
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12,
|
|
13, 14, 17, 18, 19, 20, 21, 23, 24, 25, 26, 27
|
|
],
|
|
baz: [0, 1, 2, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 19, 22, 23, 24, 25, 26, 27],
|
|
qux:
|
|
[3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 17, 18, 19, 20, 21, 23, 24, 25, 26, 27]
|
|
}),
|
|
query: {},
|
|
proj: {
|
|
foo: {$lte: ["$a", "$x"]},
|
|
bar: {$lte: ["$a", "$b"]},
|
|
baz: {$lte: ["$x.y", "$v.w"]},
|
|
qux: {$lte: ["$a", "$nonexistent"]}
|
|
}
|
|
},
|
|
{
|
|
desc: "$gt",
|
|
expected: computedProjectionWithBoolValues({
|
|
foo: [0, 1, 2, 15, 22],
|
|
bar: [15, 16, 22],
|
|
baz: [3, 4, 17, 18, 20, 21],
|
|
qux: [0, 1, 2, 15, 16, 22]
|
|
}),
|
|
query: {},
|
|
proj: {
|
|
foo: {$gt: ["$a", "$x"]},
|
|
bar: {$gt: ["$a", "$b"]},
|
|
baz: {$gt: ["$x.y", "$v.w"]},
|
|
qux: {$gt: ["$a", "$nonexistent"]}
|
|
}
|
|
},
|
|
{
|
|
desc: "$gte",
|
|
expected: computedProjectionWithBoolValues({
|
|
foo: [0, 1, 2, 10, 11, 12, 13, 14, 15, 16, 19, 22, 23, 24, 25, 26, 27],
|
|
bar: [
|
|
3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
|
|
16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27
|
|
],
|
|
baz: [
|
|
0, 1, 2, 3, 4, 6, 7, 10, 11, 12, 13, 14, 15,
|
|
16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27
|
|
],
|
|
qux: [
|
|
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13,
|
|
14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27
|
|
]
|
|
}),
|
|
query: {},
|
|
proj: {
|
|
foo: {$gte: ["$a", "$x"]},
|
|
bar: {$gte: ["$a", "$b"]},
|
|
baz: {$gte: ["$x.y", "$v.w"]},
|
|
qux: {$gte: ["$a", "$nonexistent"]}
|
|
}
|
|
},
|
|
{
|
|
desc: "$eq",
|
|
expected: computedProjectionWithBoolValues({
|
|
foo: [10, 11, 12, 13, 14, 16, 19, 23, 24, 25, 26, 27],
|
|
bar: [3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 17, 18, 19, 20, 21, 23, 24, 25, 26, 27],
|
|
baz: [0, 1, 2, 6, 7, 10, 11, 12, 13, 14, 15, 16, 19, 22, 23, 24, 25, 26, 27],
|
|
qux:
|
|
[3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 17, 18, 19, 20, 21, 23, 24, 25, 26, 27]
|
|
}),
|
|
query: {},
|
|
proj: {
|
|
foo: {$eq: ["$a", "$x"]},
|
|
bar: {$eq: ["$a", "$b"]},
|
|
baz: {$eq: ["$x.y", "$v.w"]},
|
|
qux: {$eq: ["$a", "$nonexistent"]}
|
|
}
|
|
},
|
|
{
|
|
desc: "$ne",
|
|
expected: computedProjectionWithBoolValues({
|
|
foo: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 15, 17, 18, 20, 21, 22],
|
|
bar: [0, 1, 2, 15, 16, 22],
|
|
baz: [3, 4, 5, 8, 9, 17, 18, 20, 21],
|
|
qux: [0, 1, 2, 15, 16, 22]
|
|
}),
|
|
query: {},
|
|
proj: {
|
|
foo: {$ne: ["$a", "$x"]},
|
|
bar: {$ne: ["$a", "$b"]},
|
|
baz: {$ne: ["$x.y", "$v.w"]},
|
|
qux: {$ne: ["$a", "$nonexistent"]}
|
|
}
|
|
},
|
|
{
|
|
desc: "$cmp",
|
|
expected: [
|
|
{_id: 0, foo: 1, bar: -1, baz: 0, qux: 1}, {_id: 1, foo: 1, bar: -1, baz: 0, qux: 1},
|
|
{_id: 2, foo: 1, bar: -1, baz: 0, qux: 1}, {_id: 3, foo: -1, bar: 0, baz: 1, qux: 0},
|
|
{_id: 4, foo: -1, bar: 0, baz: 1, qux: 0}, {_id: 5, foo: -1, bar: 0, baz: -1, qux: 0},
|
|
{_id: 6, foo: -1, bar: 0, baz: 0, qux: 0}, {_id: 7, foo: -1, bar: 0, baz: 0, qux: 0},
|
|
{_id: 8, foo: -1, bar: 0, baz: -1, qux: 0}, {_id: 9, foo: -1, bar: 0, baz: -1, qux: 0},
|
|
{_id: 10, foo: 0, bar: 0, baz: 0, qux: 0}, {_id: 11, foo: 0, bar: 0, baz: 0, qux: 0},
|
|
{_id: 12, foo: 0, bar: 0, baz: 0, qux: 0}, {_id: 13, foo: 0, bar: 0, baz: 0, qux: 0},
|
|
{_id: 14, foo: 0, bar: 0, baz: 0, qux: 0}, {_id: 15, foo: 1, bar: 1, baz: 0, qux: 1},
|
|
{_id: 16, foo: 0, bar: 1, baz: 0, qux: 1}, {_id: 17, foo: -1, bar: 0, baz: 1, qux: 0},
|
|
{_id: 18, foo: -1, bar: 0, baz: 1, qux: 0}, {_id: 19, foo: 0, bar: 0, baz: 0, qux: 0},
|
|
{_id: 20, foo: -1, bar: 0, baz: 1, qux: 0}, {_id: 21, foo: -1, bar: 0, baz: 1, qux: 0},
|
|
{_id: 22, foo: 1, bar: 1, baz: 0, qux: 1}, {_id: 23, foo: 0, bar: 0, baz: 0, qux: 0},
|
|
{_id: 24, foo: 0, bar: 0, baz: 0, qux: 0}, {_id: 25, foo: 0, bar: 0, baz: 0, qux: 0},
|
|
{_id: 26, foo: 0, bar: 0, baz: 0, qux: 0}, {_id: 27, foo: 0, bar: 0, baz: 0, qux: 0}
|
|
],
|
|
query: {},
|
|
proj: {
|
|
foo: {$cmp: ["$a", "$x"]},
|
|
bar: {$cmp: ["$a", "$b"]},
|
|
baz: {$cmp: ["$x.y", "$v.w"]},
|
|
qux: {$cmp: ["$a", "$nonexistent"]}
|
|
}
|
|
},
|
|
//
|
|
// Nesting torture tests.
|
|
//
|
|
{
|
|
desc: "Nesting torture test 1",
|
|
expected: computedProjectionWithBoolValues({foo: [5, 6, 7, 8, 9]}),
|
|
query: {},
|
|
proj: {
|
|
foo: {
|
|
$let: {
|
|
vars: {v1: {$or: ["$x.y", "$v.w"]}, vx: "$x"},
|
|
"in": {$and: ["$$vx.y", "$v.w"]}
|
|
}
|
|
}
|
|
}
|
|
},
|
|
{
|
|
desc: "Nesting torture test 2",
|
|
expected: computedProjectionWithBoolValues({foo: [5, 6, 7, 8, 9]}),
|
|
query: {},
|
|
proj: {
|
|
foo: {
|
|
$let: {
|
|
vars: {v1: "$x.y"},
|
|
"in": {
|
|
$let: {
|
|
vars:
|
|
{v2: {$let: {vars: {v3: "$v.w"}, "in": {$and: ["$$v1", "$$v3"]}}}},
|
|
"in": "$$v2"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
},
|
|
{
|
|
desc: "Nesting torture test 3",
|
|
expected: computedProjectionWithBoolValues(
|
|
{foo: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 15, 16, 17, 18, 20, 21, 22]}),
|
|
query: {},
|
|
proj: {foo: {$or: ["$a", {$lt: [{$and: ["$a", "$c"]}, {$or: ["$c", "$x"]}]}, "$x"]}}
|
|
},
|
|
{
|
|
desc: "Ludicrous nesting torture test with multiple computed fields",
|
|
expected: [
|
|
{_id: 0, foo: false, baz: false},
|
|
{_id: 1, foo: false, baz: false},
|
|
{_id: 2, foo: false, baz: false},
|
|
{_id: 3, foo: 2, baz: false},
|
|
{_id: 4, bar: 2, baz: false},
|
|
{_id: 5, foo: true, bar: [1, 2, 3], baz: true},
|
|
{_id: 6, foo: true, bar: 4, baz: false},
|
|
{_id: 7, foo: true, bar: [1], baz: false},
|
|
{_id: 8, foo: true, bar: [1, 2], baz: true},
|
|
{_id: 9, foo: true, bar: [1, [1, 2, 3]], baz: true},
|
|
{_id: 10, foo: false, baz: false},
|
|
{_id: 11, foo: false, baz: false},
|
|
{_id: 12, foo: false, baz: false},
|
|
{_id: 13, foo: false, baz: false},
|
|
{_id: 14, foo: false, baz: false},
|
|
{_id: 15, foo: false, baz: false},
|
|
{_id: 16, foo: false, baz: false},
|
|
{_id: 17, foo: true, bar: [{z: 1}, {z: 2}], baz: false},
|
|
{_id: 18, foo: true, bar: [3, 4, 6], baz: false},
|
|
{_id: 19, foo: false, baz: false},
|
|
{_id: 20, foo: true, bar: [3, 4, 6], baz: false},
|
|
{_id: 21, foo: true, bar: [3, {z: 2}, 6], baz: false},
|
|
{_id: 22, foo: true, baz: false},
|
|
{_id: 23, foo: false, baz: false},
|
|
{_id: 24, foo: false, baz: false},
|
|
{_id: 25, foo: false, baz: false},
|
|
{_id: 26, foo: false, baz: false},
|
|
{_id: 27, foo: false, baz: false}
|
|
],
|
|
query: {},
|
|
proj: {
|
|
foo: {
|
|
$let: {
|
|
vars: {
|
|
v1: {$or: ["$x.y", "$v.w"]},
|
|
v2: {$switch: {branches: [{case: "$v.w", then: 1}], default: 2}},
|
|
v3: "$b"
|
|
},
|
|
"in": {
|
|
$switch: {
|
|
branches: [
|
|
{case: {$eq: ["$x.y", 1]}, then: "$$v2"},
|
|
{case: {$eq: ["$x.y", 2]}, then: "$v.w"},
|
|
{case: {$eq: ["$$v3", 2]}, then: "$c"}
|
|
],
|
|
default: {$or: ["$$v1", "$tf"]}
|
|
}
|
|
}
|
|
}
|
|
},
|
|
bar: {
|
|
$switch: {
|
|
branches: [
|
|
{case: {$gt: ["$x.y", 1]}, then: "$x.y"},
|
|
{case: {$let: {vars: {v4: "$v.w1"}, "in": "$$v4"}}, then: "$v.w2"}
|
|
],
|
|
default: "$x.y.z"
|
|
}
|
|
},
|
|
baz: {
|
|
$let: {
|
|
vars: {v5: "$x.y", v6: "$v.w"},
|
|
"in": {
|
|
$cond: {
|
|
if: {$lt: ["$$v5", "$$v6"]},
|
|
then: {
|
|
$switch: {
|
|
branches: [
|
|
{case: {$eq: ["$v.w", 5]}, then: "$v.w"},
|
|
{case: {$eq: ["$v.w", 4]}, then: "$x.y"}
|
|
],
|
|
default: {$or: ["$$v5", "$$v6"]}
|
|
}
|
|
},
|
|
else: false
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
];
|
|
|
|
testCases.forEach(function(test) {
|
|
if (test.expected) {
|
|
let actual;
|
|
assert.doesNotThrow(() => {
|
|
actual = coll.find(test.query, test.proj).toArray();
|
|
}, [], test);
|
|
assert(arrayEq(actual, test.expected), Object.assign({actual: actual}, test));
|
|
} else {
|
|
assert(test.expectedErrorCode, test);
|
|
const result =
|
|
db.runCommand({find: coll.getName(), filter: test.query, projection: test.proj});
|
|
assert.commandFailedWithCode(
|
|
result, test.expectedErrorCode, Object.assign({result: result}, test));
|
|
}
|
|
});
|
|
}());
|