diff options
Diffstat (limited to 'jstests/aggregation/expressions/concat_arrays.js')
-rw-r--r-- | jstests/aggregation/expressions/concat_arrays.js | 154 |
1 files changed, 154 insertions, 0 deletions
diff --git a/jstests/aggregation/expressions/concat_arrays.js b/jstests/aggregation/expressions/concat_arrays.js new file mode 100644 index 00000000000..37f4b6c4a72 --- /dev/null +++ b/jstests/aggregation/expressions/concat_arrays.js @@ -0,0 +1,154 @@ +// Confirm correctness of $concatArrays expression evaluation. + +(function() { +"use strict"; + +load("jstests/aggregation/extras/utils.js"); // For assertArrayEq. +load("jstests/libs/sbe_assert_error_override.js"); // Override error-code-checking APIs. + +const coll = db.projection_expr_concat_arrays; +coll.drop(); + +assert.commandWorked(coll.insertOne({ + int_arr: [1, 2, 3, 4], + dbl_arr: [10.0, 20.1, 20.4, 50.5], + nested_arr: [["an", "array"], "arr", [[], [[], "a", "b"]]], + str_arr: ["a", "b", "c"], + obj_arr: [{a: 1, b: 2}, {c: 3}, {d: 4, e: 5}], + null_arr: [null, null, null], + one_null_arr: [null], + one_str_arr: ["one"], + empty_arr: [], + null_val: null, + str_val: "a string", + dbl_val: 2.0, + int_val: 1, + obj_val: {a: 1, b: "two"} +})); + +function runAndAssert(operands, expectedResult) { + assertArrayEq({ + actual: coll.aggregate([{$project: {f: {$concatArrays: operands}}}]).map(doc => doc.f), + expected: expectedResult + }); +} + +function runAndAssertNull(operands) { + runAndAssert(operands, [null]); +} + +function runAndAssertThrows(operands) { + const error = + assert.throws(() => coll.aggregate([{$project: {f: {$concatArrays: operands}}}]).toArray()); + assert.commandFailedWithCode(error, 28664); +} + +runAndAssert(["$int_arr"], [[1, 2, 3, 4]]); +runAndAssert([[0], "$int_arr", [5, 6, 7]], [[0, 1, 2, 3, 4, 5, 6, 7]]); +runAndAssert(["$int_arr", "$str_arr"], [[1, 2, 3, 4, "a", "b", "c"]]); +runAndAssert( + ["$obj_arr", "$obj_arr", "$null_arr"], + [[{a: 1, b: 2}, {c: 3}, {d: 4, e: 5}, {a: 1, b: 2}, {c: 3}, {d: 4, e: 5}, null, null, null]]); +runAndAssert(["$int_arr", "$str_arr", "$nested_arr"], + [[1, 2, 3, 4, "a", "b", "c", ["an", "array"], "arr", [[], [[], "a", "b"]]]]); +runAndAssert(["$int_arr", "$obj_arr"], [[1, 2, 3, 4, {a: 1, b: 2}, {c: 3}, {d: 4, e: 5}]]); +runAndAssert(["$obj_arr"], [[{a: 1, b: 2}, {c: 3}, {d: 4, e: 5}]]); +runAndAssert(["$obj_arr", [{o: 123, b: 1}, {y: "o", d: "a"}]], + [[{a: 1, b: 2}, {c: 3}, {d: 4, e: 5}, {o: 123, b: 1}, {y: "o", d: "a"}]]); + +// Confirm that arrays containing null can be concatenated. +runAndAssert(["$null_arr"], [[null, null, null]]); +runAndAssert([[null], "$null_arr"], [[null, null, null, null]]); +runAndAssert("$one_null_arr", [[null]]); +runAndAssert(["$null_arr", "$one_null_arr", "$int_arr", "$null_arr"], + [[null, null, null, null, 1, 2, 3, 4, null, null, null]]); + +// Test operands that form more complex expressions. +runAndAssert([{$concatArrays: "$int_arr"}], [[1, 2, 3, 4]]); +runAndAssert([{$concatArrays: "$int_arr"}, {$concatArrays: {$concatArrays: "$str_arr"}}], + [[1, 2, 3, 4, "a", "b", "c"]]); +runAndAssert(["$str_arr", {$filter: {input: "$int_arr", + as: "num", + cond: { $and: [ + { $gte: [ "$$num", 2 ] }, + { $lte: [ "$$num", 3 ] } + ] }}}, "$int_arr"], + [["a", "b", "c", 2, 3, 1, 2, 3, 4]]); + +// Confirm that having any combination of null or missing inputs and valid inputs produces null. +runAndAssertNull(["$int_arr", "$null_val"]); +runAndAssertNull(["$int_arr", null]); +runAndAssertNull([null, "$int_arr", "$str_arr"]); +runAndAssertNull(["$int_arr", null, "$str_arr"]); +runAndAssertNull(["$null_val", "$str_arr", "$int_arr"]); +runAndAssertNull(["$str_arr", "$null_val", "$int_arr"]); +runAndAssertNull(["$int_arr", "$not_a_field"]); +runAndAssertNull(["$not_a_field", "$str_arr", "$int_arr"]); +runAndAssertNull(["$not_a_field"]); +runAndAssertNull(["$null_val"]); +runAndAssertNull(["$not_a_field", "$null_val"]); +runAndAssertNull(["$null_val", "$not_a_field"]); +runAndAssertNull([ + {$concatArrays: "$int_arr"}, + null, + {$concatArrays: {$concatArrays: ["$obj_arr", "$str_arr"]}} +]); + +// Confirm edge case where if null precedes non-array input, null is returned. +runAndAssertNull(["$int_arr", "$null_val", "$int_val"]); + +// +// Confirm error cases. +// + +// Confirm concatenating non-array and non-values produces an error. +runAndAssertThrows(["$dbl_val"]); +runAndAssertThrows(["$str_val"]); +runAndAssertThrows(["$int_val"]); +runAndAssertThrows([123]); +runAndAssertThrows(["some_val", [1, 2, 3]]); +runAndAssertThrows(["$obj_val"]); +runAndAssertThrows(["$int_arr", "$int_val"]); +runAndAssertThrows(["$dbl_arr", "$dbl_val"]); + +// Confirm edge case where if invalid input precedes null or missing inputs, the command fails. +runAndAssertThrows(["$int_arr", "$dbl_val", "$null_val"]); +runAndAssertThrows(["$int_arr", "some_string_value", "$null_val"]); +runAndAssertThrows(["$int_arr", 32]); +runAndAssertThrows(["$dbl_val", "$null_val"]); +runAndAssertThrows(["$int_arr", "$int_val", "$not_a_field"]); +runAndAssertThrows(["$int_val", "$not_a_field"]); +runAndAssertThrows(["$int_val", "$not_a_field", "$null_val"]); + +// Clear collection. +assert(coll.drop()); + +// Test case where find returns multiple documents. +assert.commandWorked(coll.insertMany([ + {arr1: [42, 35.0, 197865432], arr2: ["albatross", "abbacus", "alien"]}, + {arr1: [1], arr2: ["albatross", "abbacus", "alien"]}, + {arr1: [1, 2, 3, 4, 5, 6, 11, 12, 23], arr2: []}, + {arr1: [], arr2: ["foo", "bar"]}, + {arr1: [], arr2: []}, + {arr1: [1, 2, 3, 4, 5, 6, 11, 12, 23], arr2: null}, + {some_field: "foo"}, +])); +runAndAssert(["$arr1", "$arr2"], [ + [42, 35.0, 197865432, "albatross", "abbacus", "alien"], + [1, "albatross", "abbacus", "alien"], + [1, 2, 3, 4, 5, 6, 11, 12, 23], + ["foo", "bar"], + [], + null, + null +]); +runAndAssert(["$arr1", [1, 2, 3], "$arr2"], [ + [42, 35.0, 197865432, 1, 2, 3, "albatross", "abbacus", "alien"], + [1, 1, 2, 3, "albatross", "abbacus", "alien"], + [1, 2, 3, 4, 5, 6, 11, 12, 23, 1, 2, 3], + ["foo", 1, 2, 3, "bar"], + [1, 2, 3], + null, + null +]); +}()); |