summaryrefslogtreecommitdiff
path: root/jstests/aggregation/expressions/concat_arrays.js
diff options
context:
space:
mode:
Diffstat (limited to 'jstests/aggregation/expressions/concat_arrays.js')
-rw-r--r--jstests/aggregation/expressions/concat_arrays.js154
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
+]);
+}());