From d96cd5aec68118af35ba81a5218e8d107a1e204b Mon Sep 17 00:00:00 2001 From: Maxim Katcharov Date: Thu, 3 Nov 2022 14:40:41 -0600 Subject: [PATCH 1/5] Implement array expressions --- .../model/expressions/ArrayExpression.java | 27 +++ .../client/model/expressions/Expressions.java | 88 +++++++-- .../model/expressions/MqlExpression.java | 74 ++++++- .../AbstractExpressionsFunctionalTest.java | 7 + .../ArrayExpressionsFunctionalTest.java | 185 +++++++++++++++++- .../ComparisonExpressionsFunctionalTest.java | 7 - 6 files changed, 359 insertions(+), 29 deletions(-) diff --git a/driver-core/src/main/com/mongodb/client/model/expressions/ArrayExpression.java b/driver-core/src/main/com/mongodb/client/model/expressions/ArrayExpression.java index 77266e17bd7..5ef7d00799a 100644 --- a/driver-core/src/main/com/mongodb/client/model/expressions/ArrayExpression.java +++ b/driver-core/src/main/com/mongodb/client/model/expressions/ArrayExpression.java @@ -19,6 +19,8 @@ import java.util.function.BinaryOperator; import java.util.function.Function; +import static com.mongodb.client.model.expressions.Expressions.of; + /** * Expresses an array value. An array value is a finite, ordered collection of * elements of a certain type. @@ -61,4 +63,29 @@ public interface ArrayExpression extends Expression { */ T reduce(T initialValue, BinaryOperator in); + IntegerExpression size(); + + T arrayElemAt(IntegerExpression i); + + default T arrayElemAt(final int i) { + return this.arrayElemAt(of(i)); + } + + T first(); + + T last(); + + BooleanExpression contains(T contains); + + ArrayExpression concatArrays(ArrayExpression array); + + ArrayExpression slice(IntegerExpression start, IntegerExpression length); + + default ArrayExpression slice(final int start, final int length) { + return this.slice(of(start), of(length)); + } + + ArrayExpression setUnion(ArrayExpression set); + + ArrayExpression distinct(); } diff --git a/driver-core/src/main/com/mongodb/client/model/expressions/Expressions.java b/driver-core/src/main/com/mongodb/client/model/expressions/Expressions.java index a11cef3dfa4..bc127a4a1ef 100644 --- a/driver-core/src/main/com/mongodb/client/model/expressions/Expressions.java +++ b/driver-core/src/main/com/mongodb/client/model/expressions/Expressions.java @@ -58,6 +58,21 @@ public static BooleanExpression of(final boolean of) { return new MqlExpression<>((codecRegistry) -> new AstPlaceholder(new BsonBoolean(of))); } + /** + * Returns an array expression containing the same boolean values as the + * provided array of booleans. + * + * @param array the array of booleans + * @return the boolean array expression + */ + public static ArrayExpression ofBooleanArray(final boolean... array) { + List result = new ArrayList<>(); + for (boolean b : array) { + result.add(new BsonBoolean(b)); + } + return new MqlExpression<>((cr) -> new AstPlaceholder(new BsonArray(result))); + } + /** * Returns an expression having the same integer value as the provided * int primitive. @@ -68,21 +83,64 @@ public static BooleanExpression of(final boolean of) { public static IntegerExpression of(final int of) { return new MqlExpression<>((codecRegistry) -> new AstPlaceholder(new BsonInt32(of))); } + + public static ArrayExpression ofIntegerArray(final int... array) { + List list = Arrays.stream(array) + .mapToObj(BsonInt32::new) + .collect(Collectors.toList()); + return new MqlExpression<>((cr) -> new AstPlaceholder(new BsonArray(list))); + } + public static IntegerExpression of(final long of) { return new MqlExpression<>((codecRegistry) -> new AstPlaceholder(new BsonInt64(of))); } + + public static ArrayExpression ofIntegerArray(final long... array) { + List list = Arrays.stream(array) + .mapToObj(BsonInt64::new) + .collect(Collectors.toList()); + return new MqlExpression<>((cr) -> new AstPlaceholder(new BsonArray(list))); + } + public static NumberExpression of(final double of) { return new MqlExpression<>((codecRegistry) -> new AstPlaceholder(new BsonDouble(of))); } + + public static ArrayExpression ofNumberArray(final double... array) { + List list = Arrays.stream(array) + .mapToObj(BsonDouble::new) + .collect(Collectors.toList()); + return new MqlExpression<>((cr) -> new AstPlaceholder(new BsonArray(list))); + } + public static NumberExpression of(final Decimal128 of) { Assertions.notNull("Decimal128", of); return new MqlExpression<>((codecRegistry) -> new AstPlaceholder(new BsonDecimal128(of))); } + + public static ArrayExpression ofNumberArray(final Decimal128... array) { + List result = new ArrayList<>(); + for (Decimal128 e : array) { + Assertions.notNull("elements of array", e); + result.add(new BsonDecimal128(e)); + } + return new MqlExpression<>((cr) -> new AstPlaceholder(new BsonArray(result))); + } + public static DateExpression of(final Instant of) { Assertions.notNull("Instant", of); return new MqlExpression<>((codecRegistry) -> new AstPlaceholder(new BsonDateTime(of.toEpochMilli()))); } + public static ArrayExpression ofDateArray(final Instant... array) { + List result = new ArrayList<>(); + for (Instant e : array) { + Assertions.notNull("elements of array", e); + result.add(new BsonDateTime(e.toEpochMilli())); + } + return new MqlExpression<>((cr) -> new AstPlaceholder(new BsonArray(result))); + } + /** * Returns an expression having the same string value as the provided * string. @@ -95,27 +153,25 @@ public static StringExpression of(final String of) { return new MqlExpression<>((codecRegistry) -> new AstPlaceholder(new BsonString(of))); } - /** - * Returns an array expression containing the same boolean values as the - * provided array of booleans. - * - * @param array the array of booleans - * @return the boolean array expression - */ - public static ArrayExpression ofBooleanArray(final boolean... array) { + + public static ArrayExpression ofStringArray(final String... array) { List result = new ArrayList<>(); - for (boolean b : array) { - result.add(new BsonBoolean(b)); + for (String e : array) { + Assertions.notNull("elements of array", e); + result.add(new BsonString(e)); } return new MqlExpression<>((cr) -> new AstPlaceholder(new BsonArray(result))); } - - public static ArrayExpression ofIntegerArray(final int... ofIntegerArray) { - List array = Arrays.stream(ofIntegerArray) - .mapToObj(BsonInt32::new) - .collect(Collectors.toList()); - return new MqlExpression<>((cr) -> new AstPlaceholder(new BsonArray(array))); + @SafeVarargs // nothing is stored in the array + public static ArrayExpression ofArray(final T... array) { + Assertions.notNull("array", array); + return new MqlExpression<>((cr) -> { + List array2 = Arrays.stream(array) + .map(v -> ((MqlExpression) v).toBsonValue(cr)) + .collect(Collectors.toList()); + return new AstPlaceholder(new BsonArray(array2)); + }); } public static DocumentExpression ofDocument(final Bson document) { diff --git a/driver-core/src/main/com/mongodb/client/model/expressions/MqlExpression.java b/driver-core/src/main/com/mongodb/client/model/expressions/MqlExpression.java index 302dd7e0610..0d5c412c28b 100644 --- a/driver-core/src/main/com/mongodb/client/model/expressions/MqlExpression.java +++ b/driver-core/src/main/com/mongodb/client/model/expressions/MqlExpression.java @@ -22,6 +22,7 @@ import org.bson.BsonValue; import org.bson.codecs.configuration.CodecRegistry; +import java.util.Collections; import java.util.function.BinaryOperator; import java.util.function.Function; @@ -173,7 +174,7 @@ public ArrayExpression map(final Function filter(final Function cond) { T varThis = variable("$$this"); - return new MqlExpression((cr) -> astDoc("$filter", new BsonDocument() + return new MqlExpression<>((cr) -> astDoc("$filter", new BsonDocument() .append("input", this.toBsonValue(cr)) .append("cond", extractBsonValue(cr, cond.apply(varThis))))); } @@ -185,7 +186,76 @@ public T reduce(final T initialValue, final BinaryOperator in) { return newMqlExpression((cr) -> astDoc("$reduce", new BsonDocument() .append("input", this.toBsonValue(cr)) .append("initialValue", extractBsonValue(cr, initialValue)) - .append("in", extractBsonValue(cr, in.apply(varThis, varValue))))); + .append("in", extractBsonValue(cr, in.apply(varValue, varThis))))); + } + + @Override + public IntegerExpression size() { + return new MqlExpression<>( + (cr) -> new AstPlaceholder(new BsonDocument("$size", + // must wrap the first argument in a list + new BsonArray(Collections.singletonList(this.toBsonValue(cr)))))); + } + + @Override + public T arrayElemAt(final IntegerExpression at) { + return new MqlExpression<>(ast("$arrayElemAt", at)) + .assertImplementsAllExpressions(); + } + + @Override + public T first() { + return new MqlExpression<>( + (cr) -> new AstPlaceholder(new BsonDocument("$first", + // must wrap the first argument in a list + new BsonArray(Collections.singletonList(this.toBsonValue(cr)))))) + .assertImplementsAllExpressions(); + } + + @Override + public T last() { + return new MqlExpression<>( + (cr) -> new AstPlaceholder(new BsonDocument("$last", + // must wrap the first argument in a list + new BsonArray(Collections.singletonList(this.toBsonValue(cr)))))) + .assertImplementsAllExpressions(); + } + + @Override + public BooleanExpression contains(final T item) { + String name = "$in"; + return new MqlExpression<>((cr) -> { + BsonArray value = new BsonArray(); + value.add(extractBsonValue(cr, item)); + value.add(this.toBsonValue(cr)); + return new AstPlaceholder(new BsonDocument(name, value)); + }).assertImplementsAllExpressions(); + } + + @Override + public ArrayExpression concatArrays(final ArrayExpression array) { + return new MqlExpression<>(ast("$concatArrays", array)) + .assertImplementsAllExpressions(); + } + + @Override + public ArrayExpression slice(final IntegerExpression start, final IntegerExpression length) { + return new MqlExpression<>(ast("$slice", start, length)) + .assertImplementsAllExpressions(); + } + + @Override + public ArrayExpression setUnion(final ArrayExpression set) { + return new MqlExpression<>(ast("$setUnion", set)) + .assertImplementsAllExpressions(); + } + + @Override + public ArrayExpression distinct() { + return new MqlExpression<>( + (cr) -> new AstPlaceholder(new BsonDocument("$setUnion", + // must wrap the first argument in a list + new BsonArray(Collections.singletonList(this.toBsonValue(cr)))))); } diff --git a/driver-core/src/test/functional/com/mongodb/client/model/expressions/AbstractExpressionsFunctionalTest.java b/driver-core/src/test/functional/com/mongodb/client/model/expressions/AbstractExpressionsFunctionalTest.java index fc35aed7c3e..4b966294027 100644 --- a/driver-core/src/test/functional/com/mongodb/client/model/expressions/AbstractExpressionsFunctionalTest.java +++ b/driver-core/src/test/functional/com/mongodb/client/model/expressions/AbstractExpressionsFunctionalTest.java @@ -113,5 +113,12 @@ public BsonValue readValue(final BsonReader reader, final DecoderContext decoder return super.readValue(reader, decoderContext); } } + + + static R ofRem() { + // $$REMOVE is intentionally not exposed to users + return new MqlExpression<>((cr) -> new MqlExpression.AstPlaceholder(new BsonString("$$REMOVE"))) + .assertImplementsAllExpressions(); + } } diff --git a/driver-core/src/test/functional/com/mongodb/client/model/expressions/ArrayExpressionsFunctionalTest.java b/driver-core/src/test/functional/com/mongodb/client/model/expressions/ArrayExpressionsFunctionalTest.java index b056a9fb8d0..2f1f3728acc 100644 --- a/driver-core/src/test/functional/com/mongodb/client/model/expressions/ArrayExpressionsFunctionalTest.java +++ b/driver-core/src/test/functional/com/mongodb/client/model/expressions/ArrayExpressionsFunctionalTest.java @@ -18,23 +18,79 @@ import org.junit.jupiter.api.Test; +import java.math.BigDecimal; +import java.time.Instant; import java.util.Arrays; +import java.util.Collections; import java.util.stream.Collectors; import java.util.stream.Stream; import static com.mongodb.client.model.expressions.Expressions.of; +import static com.mongodb.client.model.expressions.Expressions.ofArray; import static com.mongodb.client.model.expressions.Expressions.ofBooleanArray; +import static com.mongodb.client.model.expressions.Expressions.ofDateArray; +import static com.mongodb.client.model.expressions.Expressions.ofIntegerArray; +import static com.mongodb.client.model.expressions.Expressions.ofNumberArray; +import static com.mongodb.client.model.expressions.Expressions.ofStringArray; @SuppressWarnings({"ConstantConditions", "Convert2MethodRef"}) class ArrayExpressionsFunctionalTest extends AbstractExpressionsFunctionalTest { // https://www.mongodb.com/docs/manual/reference/operator/aggregation/#array-expression-operators // (Incomplete) + private final ArrayExpression array123 = ofIntegerArray(1, 2, 3); private final ArrayExpression arrayTTF = ofBooleanArray(true, true, false); @Test public void literalsTest() { - assertExpression(Arrays.asList(true, true, false), arrayTTF, "[true, true, false]"); + // Boolean + assertExpression( + Arrays.asList(true, true, false), + arrayTTF, + "[true, true, false]"); + // Integer + assertExpression( + Arrays.asList(1, 2, 3), + array123, + "[1, 2, 3]"); + assertExpression( + Arrays.asList(1L, 2L, 3L), + ofIntegerArray(1L, 2L, 3L), + "[{'$numberLong': '1'}, {'$numberLong': '2'}, {'$numberLong': '3'}]"); + // Number + assertExpression( + Arrays.asList(1.0, 2.0, 3.0), + ofNumberArray(1.0, 2.0, 3.0), + "[1.0, 2.0, 3.0]"); + assertExpression( + Arrays.asList(BigDecimal.valueOf(1.0)), + ofNumberArray(BigDecimal.valueOf(1.0)), + "[{'$numberDecimal': '1.0'}]"); + // String + assertExpression( + Arrays.asList("a", "b", "c"), + ofStringArray("a", "b", "c"), + "['a', 'b', 'c']"); + // Date + assertExpression( + Arrays.asList(Instant.parse("2007-12-03T10:15:30.00Z")), + ofDateArray(Instant.parse("2007-12-03T10:15:30.00Z")), + "[{'$date': '2007-12-03T10:15:30.00Z'}]"); + // Document + // ... + + // Array + ArrayExpression> arrays = ofArray(ofArray(), ofArray()); + assertExpression( + Arrays.asList(Collections.emptyList(), Collections.emptyList()), arrays, + "[[], []]"); + + // Mixed + ArrayExpression expression = ofArray(of(1), of(true), ofArray(of(1.0), of(1))); + assertExpression( + Arrays.asList(1, true, Arrays.asList(1.0, 1)), + expression, + "[1, true, [1.0, 1]]"); } @Test @@ -67,19 +123,19 @@ public void reduceTest() { .reduce(false, (a, b) -> a || b), arrayTTF.reduce(of(false), (a, b) -> a.or(b)), // MQL: - "{'$reduce': {'input': [true, true, false], 'initialValue': false, 'in': {'$or': ['$$this', '$$value']}}}"); + "{'$reduce': {'input': [true, true, false], 'initialValue': false, 'in': {'$or': ['$$value', '$$this']}}}"); assertExpression( Stream.of(true, true, false) .reduce(true, (a, b) -> a && b), arrayTTF.reduce(of(true), (a, b) -> a.and(b)), // MQL: - "{'$reduce': {'input': [true, true, false], 'initialValue': true, 'in': {'$and': ['$$this', '$$value']}}}"); + "{'$reduce': {'input': [true, true, false], 'initialValue': true, 'in': {'$and': ['$$value', '$$this']}}}"); // empty array assertExpression( Stream.empty().reduce(true, (a, b) -> a && b), ofBooleanArray().reduce(of(true), (a, b) -> a.and(b)), // MQL: - "{'$reduce': {'input': [], 'initialValue': true, 'in': {'$and': ['$$this', '$$value']}}}"); + "{'$reduce': {'input': [], 'initialValue': true, 'in': {'$and': ['$$value', '$$this']}}}"); // constant result assertExpression( Stream.of(true, true, false) @@ -87,5 +143,126 @@ public void reduceTest() { arrayTTF.reduce(of(true), (a, b) -> of(true)), // MQL: "{'$reduce': {'input': [true, true, false], 'initialValue': true, 'in': true}}"); + // non-commutative + assertExpression( + "abc", + ofStringArray("a", "b", "c").reduce(of(""), (a, b) -> a.concat(b)), + // MQL: + "{'$reduce': {'input': ['a', 'b', 'c'], 'initialValue': '', 'in': {'$concat': ['$$value', '$$this']}}}"); + + } + + @Test + public void sizeTest() { + // https://www.mongodb.com/docs/manual/reference/operator/aggregation/size/ + assertExpression( + Arrays.asList(1, 2, 3).size(), + array123.size(), + // MQL: + "{'$size': [[1, 2, 3]]}"); + } + + @Test + public void arrayElemAtTest() { + // https://www.mongodb.com/docs/manual/reference/operator/aggregation/arrayElemAt/ + assertExpression( + Arrays.asList(1, 2, 3).get(0), + array123.arrayElemAt((IntegerExpression) of(0.0)), + // MQL: + "{'$arrayElemAt': [[1, 2, 3], 0.0]}"); + + assertExpression( + Arrays.asList(1, 2, 3).get(3 - 1), + array123.arrayElemAt(-1)); + + assertExpression( + true, + ofRem().eq(array123.arrayElemAt(99))); + assertExpression( + true, + ofRem().eq(array123.arrayElemAt(-99))); + } + + @Test + public void firstTest() { + // https://www.mongodb.com/docs/manual/reference/operator/aggregation/first/ + // https://www.mongodb.com/docs/manual/reference/operator/aggregation/first-array-element/ + assertExpression( + Arrays.asList(1, 2, 3).get(0), + array123.first(), + // MQL: + "{'$first': [[1, 2, 3]]}"); } + + @Test + public void lastTest() { + // https://www.mongodb.com/docs/manual/reference/operator/aggregation/last-array-element/ + assertExpression( + Arrays.asList(1, 2, 3).get(2), + array123.last(), + // MQL: + "{'$last': [[1, 2, 3]]}"); + } + + @Test + public void containsTest() { + // https://www.mongodb.com/docs/manual/reference/operator/aggregation/in/ + // The parameters of this expression are flipped + assertExpression( + Arrays.asList(1, 2, 3).contains(2), + array123.contains(of(2)), + // MQL: + "{'$in': [2, [1, 2, 3]]}"); + } + + @Test + public void concatArraysTest() { + // https://www.mongodb.com/docs/manual/reference/operator/aggregation/concatArrays/ + assertExpression( + Stream.concat(Stream.of(1, 2, 3), Stream.of(1, 2, 3)) + .collect(Collectors.toList()), + array123.concatArrays(array123), + // MQL: + "{'$concatArrays': [[1, 2, 3], [1, 2, 3]]}"); + } + + @Test + public void sliceTest() { + // https://www.mongodb.com/docs/manual/reference/operator/aggregation/slice/ + assertExpression( + Arrays.asList(1, 2, 3).subList(1, 3), + array123.slice(1, 10), + // MQL: + "{'$slice': [[1, 2, 3], 1, 10]}"); + + ArrayExpression array12345 = ofIntegerArray(1, 2, 3, 4, 5); + // sub-array: skipFirstN + firstN + assertExpression( + Arrays.asList(2, 3), + array12345.slice(1, 2)); + // lastN + firstN + assertExpression( + Arrays.asList(5), + array12345.slice(-1, 100)); + assertExpression( + Arrays.asList(1, 2, 3, 4, 5), + array12345.slice(-100, 100)); + } + + @Test + public void setUnionTest() { + // https://www.mongodb.com/docs/manual/reference/operator/aggregation/setUnion/ (40) + assertExpression( + Arrays.asList(1, 2, 3), + array123.setUnion(array123), + // MQL: + "{'$setUnion': [[1, 2, 3], [1, 2, 3]]}"); + // convenience + assertExpression( + Arrays.asList(1, 2, 3), + ofIntegerArray(1, 2, 1, 3, 3).distinct(), + // MQL: + "{'$setUnion': [[1, 2, 1, 3, 3]]}"); + } + } diff --git a/driver-core/src/test/functional/com/mongodb/client/model/expressions/ComparisonExpressionsFunctionalTest.java b/driver-core/src/test/functional/com/mongodb/client/model/expressions/ComparisonExpressionsFunctionalTest.java index 984119adaa8..ad1ca67a723 100644 --- a/driver-core/src/test/functional/com/mongodb/client/model/expressions/ComparisonExpressionsFunctionalTest.java +++ b/driver-core/src/test/functional/com/mongodb/client/model/expressions/ComparisonExpressionsFunctionalTest.java @@ -17,7 +17,6 @@ package com.mongodb.client.model.expressions; import org.bson.BsonDocument; -import org.bson.BsonString; import org.bson.BsonValue; import org.bson.codecs.BsonValueCodecProvider; import org.junit.jupiter.api.Test; @@ -40,12 +39,6 @@ class ComparisonExpressionsFunctionalTest extends AbstractExpressionsFunctionalT // (Complete as of 6.0) // Comparison expressions are part of the the generic Expression class. - static R ofRem() { - // $$REMOVE is intentionally not exposed to users - return new MqlExpression<>((cr) -> new MqlExpression.AstPlaceholder(new BsonString("$$REMOVE"))) - .assertImplementsAllExpressions(); - } - // https://www.mongodb.com/docs/manual/reference/bson-type-comparison-order/#std-label-bson-types-comparison-order private final List sampleValues = Arrays.asList( ofRem(), From 256e18f297fcaeecde61f48c97bb04de73bb0892 Mon Sep 17 00:00:00 2001 From: Maxim Katcharov Date: Mon, 14 Nov 2022 13:11:24 -0700 Subject: [PATCH 2/5] Remove "array" from names --- .../client/model/expressions/ArrayExpression.java | 8 ++++---- .../client/model/expressions/MqlExpression.java | 4 ++-- .../ArrayExpressionsFunctionalTest.java | 14 +++++++------- 3 files changed, 13 insertions(+), 13 deletions(-) diff --git a/driver-core/src/main/com/mongodb/client/model/expressions/ArrayExpression.java b/driver-core/src/main/com/mongodb/client/model/expressions/ArrayExpression.java index 5ef7d00799a..2ddd0072b6f 100644 --- a/driver-core/src/main/com/mongodb/client/model/expressions/ArrayExpression.java +++ b/driver-core/src/main/com/mongodb/client/model/expressions/ArrayExpression.java @@ -65,10 +65,10 @@ public interface ArrayExpression extends Expression { IntegerExpression size(); - T arrayElemAt(IntegerExpression i); + T elementAt(IntegerExpression i); - default T arrayElemAt(final int i) { - return this.arrayElemAt(of(i)); + default T elementAt(final int i) { + return this.elementAt(of(i)); } T first(); @@ -77,7 +77,7 @@ default T arrayElemAt(final int i) { BooleanExpression contains(T contains); - ArrayExpression concatArrays(ArrayExpression array); + ArrayExpression concat(ArrayExpression array); ArrayExpression slice(IntegerExpression start, IntegerExpression length); diff --git a/driver-core/src/main/com/mongodb/client/model/expressions/MqlExpression.java b/driver-core/src/main/com/mongodb/client/model/expressions/MqlExpression.java index 0d5c412c28b..6681813f192 100644 --- a/driver-core/src/main/com/mongodb/client/model/expressions/MqlExpression.java +++ b/driver-core/src/main/com/mongodb/client/model/expressions/MqlExpression.java @@ -198,7 +198,7 @@ public IntegerExpression size() { } @Override - public T arrayElemAt(final IntegerExpression at) { + public T elementAt(final IntegerExpression at) { return new MqlExpression<>(ast("$arrayElemAt", at)) .assertImplementsAllExpressions(); } @@ -233,7 +233,7 @@ public BooleanExpression contains(final T item) { } @Override - public ArrayExpression concatArrays(final ArrayExpression array) { + public ArrayExpression concat(final ArrayExpression array) { return new MqlExpression<>(ast("$concatArrays", array)) .assertImplementsAllExpressions(); } diff --git a/driver-core/src/test/functional/com/mongodb/client/model/expressions/ArrayExpressionsFunctionalTest.java b/driver-core/src/test/functional/com/mongodb/client/model/expressions/ArrayExpressionsFunctionalTest.java index 2f1f3728acc..4ca6716e827 100644 --- a/driver-core/src/test/functional/com/mongodb/client/model/expressions/ArrayExpressionsFunctionalTest.java +++ b/driver-core/src/test/functional/com/mongodb/client/model/expressions/ArrayExpressionsFunctionalTest.java @@ -163,24 +163,24 @@ public void sizeTest() { } @Test - public void arrayElemAtTest() { + public void elementAtTest() { // https://www.mongodb.com/docs/manual/reference/operator/aggregation/arrayElemAt/ assertExpression( Arrays.asList(1, 2, 3).get(0), - array123.arrayElemAt((IntegerExpression) of(0.0)), + array123.elementAt((IntegerExpression) of(0.0)), // MQL: "{'$arrayElemAt': [[1, 2, 3], 0.0]}"); assertExpression( Arrays.asList(1, 2, 3).get(3 - 1), - array123.arrayElemAt(-1)); + array123.elementAt(-1)); assertExpression( true, - ofRem().eq(array123.arrayElemAt(99))); + ofRem().eq(array123.elementAt(99))); assertExpression( true, - ofRem().eq(array123.arrayElemAt(-99))); + ofRem().eq(array123.elementAt(-99))); } @Test @@ -216,12 +216,12 @@ public void containsTest() { } @Test - public void concatArraysTest() { + public void concatTest() { // https://www.mongodb.com/docs/manual/reference/operator/aggregation/concatArrays/ assertExpression( Stream.concat(Stream.of(1, 2, 3), Stream.of(1, 2, 3)) .collect(Collectors.toList()), - array123.concatArrays(array123), + array123.concat(array123), // MQL: "{'$concatArrays': [[1, 2, 3], [1, 2, 3]]}"); } From 9e725fb0e3bb2d6f151ef43931f4befc2f596169 Mon Sep 17 00:00:00 2001 From: Maxim Katcharov Date: Mon, 21 Nov 2022 15:03:20 -0700 Subject: [PATCH 3/5] Fix return type --- .../com/mongodb/client/model/expressions/Expressions.java | 4 ++-- .../model/expressions/ArrayExpressionsFunctionalTest.java | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/driver-core/src/main/com/mongodb/client/model/expressions/Expressions.java b/driver-core/src/main/com/mongodb/client/model/expressions/Expressions.java index bc127a4a1ef..7346b0d1712 100644 --- a/driver-core/src/main/com/mongodb/client/model/expressions/Expressions.java +++ b/driver-core/src/main/com/mongodb/client/model/expressions/Expressions.java @@ -106,7 +106,7 @@ public static NumberExpression of(final double of) { return new MqlExpression<>((codecRegistry) -> new AstPlaceholder(new BsonDouble(of))); } - public static ArrayExpression ofNumberArray(final double... array) { + public static ArrayExpression ofNumberArray(final double... array) { List list = Arrays.stream(array) .mapToObj(BsonDouble::new) .collect(Collectors.toList()); @@ -118,7 +118,7 @@ public static NumberExpression of(final Decimal128 of) { return new MqlExpression<>((codecRegistry) -> new AstPlaceholder(new BsonDecimal128(of))); } - public static ArrayExpression ofNumberArray(final Decimal128... array) { + public static ArrayExpression ofNumberArray(final Decimal128... array) { List result = new ArrayList<>(); for (Decimal128 e : array) { Assertions.notNull("elements of array", e); diff --git a/driver-core/src/test/functional/com/mongodb/client/model/expressions/ArrayExpressionsFunctionalTest.java b/driver-core/src/test/functional/com/mongodb/client/model/expressions/ArrayExpressionsFunctionalTest.java index 4ca6716e827..c56b0aefbb1 100644 --- a/driver-core/src/test/functional/com/mongodb/client/model/expressions/ArrayExpressionsFunctionalTest.java +++ b/driver-core/src/test/functional/com/mongodb/client/model/expressions/ArrayExpressionsFunctionalTest.java @@ -16,9 +16,9 @@ package com.mongodb.client.model.expressions; +import org.bson.types.Decimal128; import org.junit.jupiter.api.Test; -import java.math.BigDecimal; import java.time.Instant; import java.util.Arrays; import java.util.Collections; @@ -63,8 +63,8 @@ public void literalsTest() { ofNumberArray(1.0, 2.0, 3.0), "[1.0, 2.0, 3.0]"); assertExpression( - Arrays.asList(BigDecimal.valueOf(1.0)), - ofNumberArray(BigDecimal.valueOf(1.0)), + Arrays.asList(Decimal128.parse("1.0")), + ofNumberArray(Decimal128.parse("1.0")), "[{'$numberDecimal': '1.0'}]"); // String assertExpression( From f4a32992c89df34f4ae2e926546224bae2f5d8f0 Mon Sep 17 00:00:00 2001 From: Maxim Katcharov Date: Fri, 25 Nov 2022 09:56:02 -0700 Subject: [PATCH 4/5] Fixes --- .../client/model/expressions/Expressions.java | 45 ++++++++++++------- .../ArrayExpressionsFunctionalTest.java | 12 ++++- 2 files changed, 39 insertions(+), 18 deletions(-) diff --git a/driver-core/src/main/com/mongodb/client/model/expressions/Expressions.java b/driver-core/src/main/com/mongodb/client/model/expressions/Expressions.java index 7346b0d1712..1bb631015f1 100644 --- a/driver-core/src/main/com/mongodb/client/model/expressions/Expressions.java +++ b/driver-core/src/main/com/mongodb/client/model/expressions/Expressions.java @@ -66,11 +66,12 @@ public static BooleanExpression of(final boolean of) { * @return the boolean array expression */ public static ArrayExpression ofBooleanArray(final boolean... array) { - List result = new ArrayList<>(); + Assertions.notNull("array", array); + List list = new ArrayList<>(); for (boolean b : array) { - result.add(new BsonBoolean(b)); + list.add(new BsonBoolean(b)); } - return new MqlExpression<>((cr) -> new AstPlaceholder(new BsonArray(result))); + return new MqlExpression<>((cr) -> new AstPlaceholder(new BsonArray(list))); } /** @@ -85,9 +86,11 @@ public static IntegerExpression of(final int of) { } public static ArrayExpression ofIntegerArray(final int... array) { - List list = Arrays.stream(array) - .mapToObj(BsonInt32::new) - .collect(Collectors.toList()); + Assertions.notNull("array", array); + List list = new ArrayList<>(); + for (int i : array) { + list.add(new BsonInt32(i)); + } return new MqlExpression<>((cr) -> new AstPlaceholder(new BsonArray(list))); } @@ -96,9 +99,11 @@ public static IntegerExpression of(final long of) { } public static ArrayExpression ofIntegerArray(final long... array) { - List list = Arrays.stream(array) - .mapToObj(BsonInt64::new) - .collect(Collectors.toList()); + Assertions.notNull("array", array); + List list = new ArrayList<>(); + for (long i : array) { + list.add(new BsonInt64(i)); + } return new MqlExpression<>((cr) -> new AstPlaceholder(new BsonArray(list))); } @@ -107,9 +112,11 @@ public static NumberExpression of(final double of) { } public static ArrayExpression ofNumberArray(final double... array) { - List list = Arrays.stream(array) - .mapToObj(BsonDouble::new) - .collect(Collectors.toList()); + Assertions.notNull("array", array); + List list = new ArrayList<>(); + for (double n : array) { + list.add(new BsonDouble(n)); + } return new MqlExpression<>((cr) -> new AstPlaceholder(new BsonArray(list))); } @@ -119,6 +126,7 @@ public static NumberExpression of(final Decimal128 of) { } public static ArrayExpression ofNumberArray(final Decimal128... array) { + Assertions.notNull("array", array); List result = new ArrayList<>(); for (Decimal128 e : array) { Assertions.notNull("elements of array", e); @@ -133,6 +141,7 @@ public static DateExpression of(final Instant of) { } public static ArrayExpression ofDateArray(final Instant... array) { + Assertions.notNull("array", array); List result = new ArrayList<>(); for (Instant e : array) { Assertions.notNull("elements of array", e); @@ -155,6 +164,7 @@ public static StringExpression of(final String of) { public static ArrayExpression ofStringArray(final String... array) { + Assertions.notNull("array", array); List result = new ArrayList<>(); for (String e : array) { Assertions.notNull("elements of array", e); @@ -167,10 +177,12 @@ public static ArrayExpression ofStringArray(final String... ar public static ArrayExpression ofArray(final T... array) { Assertions.notNull("array", array); return new MqlExpression<>((cr) -> { - List array2 = Arrays.stream(array) - .map(v -> ((MqlExpression) v).toBsonValue(cr)) - .collect(Collectors.toList()); - return new AstPlaceholder(new BsonArray(array2)); + List list = new ArrayList<>(); + for (T v : array) { + Assertions.notNull("elements of array", v); + list.add(((MqlExpression) v).toBsonValue(cr)); + } + return new AstPlaceholder(new BsonArray(list)); }); } @@ -189,6 +201,7 @@ public static R ofNull() { } static NumberExpression numberToExpression(final Number number) { + Assertions.notNull("number", number); if (number instanceof Integer) { return of((int) number); } else if (number instanceof Long) { diff --git a/driver-core/src/test/functional/com/mongodb/client/model/expressions/ArrayExpressionsFunctionalTest.java b/driver-core/src/test/functional/com/mongodb/client/model/expressions/ArrayExpressionsFunctionalTest.java index c56b0aefbb1..f7ec5f56e41 100644 --- a/driver-core/src/test/functional/com/mongodb/client/model/expressions/ArrayExpressionsFunctionalTest.java +++ b/driver-core/src/test/functional/com/mongodb/client/model/expressions/ArrayExpressionsFunctionalTest.java @@ -22,6 +22,7 @@ import java.time.Instant; import java.util.Arrays; import java.util.Collections; +import java.util.LinkedList; import java.util.stream.Collectors; import java.util.stream.Stream; @@ -32,6 +33,7 @@ import static com.mongodb.client.model.expressions.Expressions.ofIntegerArray; import static com.mongodb.client.model.expressions.Expressions.ofNumberArray; import static com.mongodb.client.model.expressions.Expressions.ofStringArray; +import static org.testng.internal.collections.Ints.asList; @SuppressWarnings({"ConstantConditions", "Convert2MethodRef"}) class ArrayExpressionsFunctionalTest extends AbstractExpressionsFunctionalTest { @@ -160,6 +162,11 @@ public void sizeTest() { array123.size(), // MQL: "{'$size': [[1, 2, 3]]}"); + assertExpression( + 0, + ofIntegerArray().size(), + // MQL: + "{'$size': [[]]}"); } @Test @@ -167,6 +174,7 @@ public void elementAtTest() { // https://www.mongodb.com/docs/manual/reference/operator/aggregation/arrayElemAt/ assertExpression( Arrays.asList(1, 2, 3).get(0), + // 0.0 is a valid integer value array123.elementAt((IntegerExpression) of(0.0)), // MQL: "{'$arrayElemAt': [[1, 2, 3], 0.0]}"); @@ -188,7 +196,7 @@ public void firstTest() { // https://www.mongodb.com/docs/manual/reference/operator/aggregation/first/ // https://www.mongodb.com/docs/manual/reference/operator/aggregation/first-array-element/ assertExpression( - Arrays.asList(1, 2, 3).get(0), + new LinkedList<>(asList(1, 2, 3)).getFirst(), array123.first(), // MQL: "{'$first': [[1, 2, 3]]}"); @@ -198,7 +206,7 @@ public void firstTest() { public void lastTest() { // https://www.mongodb.com/docs/manual/reference/operator/aggregation/last-array-element/ assertExpression( - Arrays.asList(1, 2, 3).get(2), + new LinkedList<>(asList(1, 2, 3)).getLast(), array123.last(), // MQL: "{'$last': [[1, 2, 3]]}"); From 39674f4ebe74cc92573a014a5f430938aa27ff83 Mon Sep 17 00:00:00 2001 From: Maxim Katcharov Date: Mon, 28 Nov 2022 16:12:53 -0700 Subject: [PATCH 5/5] Fixes --- .../mongodb/client/model/expressions/ArrayExpression.java | 2 +- .../mongodb/client/model/expressions/MqlExpression.java | 2 +- .../model/expressions/ArrayExpressionsFunctionalTest.java | 7 +++---- 3 files changed, 5 insertions(+), 6 deletions(-) diff --git a/driver-core/src/main/com/mongodb/client/model/expressions/ArrayExpression.java b/driver-core/src/main/com/mongodb/client/model/expressions/ArrayExpression.java index 2ddd0072b6f..99f7da587fa 100644 --- a/driver-core/src/main/com/mongodb/client/model/expressions/ArrayExpression.java +++ b/driver-core/src/main/com/mongodb/client/model/expressions/ArrayExpression.java @@ -85,7 +85,7 @@ default ArrayExpression slice(final int start, final int length) { return this.slice(of(start), of(length)); } - ArrayExpression setUnion(ArrayExpression set); + ArrayExpression union(ArrayExpression set); ArrayExpression distinct(); } diff --git a/driver-core/src/main/com/mongodb/client/model/expressions/MqlExpression.java b/driver-core/src/main/com/mongodb/client/model/expressions/MqlExpression.java index 6681813f192..218a396b0bc 100644 --- a/driver-core/src/main/com/mongodb/client/model/expressions/MqlExpression.java +++ b/driver-core/src/main/com/mongodb/client/model/expressions/MqlExpression.java @@ -245,7 +245,7 @@ public ArrayExpression slice(final IntegerExpression start, final IntegerExpr } @Override - public ArrayExpression setUnion(final ArrayExpression set) { + public ArrayExpression union(final ArrayExpression set) { return new MqlExpression<>(ast("$setUnion", set)) .assertImplementsAllExpressions(); } diff --git a/driver-core/src/test/functional/com/mongodb/client/model/expressions/ArrayExpressionsFunctionalTest.java b/driver-core/src/test/functional/com/mongodb/client/model/expressions/ArrayExpressionsFunctionalTest.java index f7ec5f56e41..e38058551e7 100644 --- a/driver-core/src/test/functional/com/mongodb/client/model/expressions/ArrayExpressionsFunctionalTest.java +++ b/driver-core/src/test/functional/com/mongodb/client/model/expressions/ArrayExpressionsFunctionalTest.java @@ -33,7 +33,6 @@ import static com.mongodb.client.model.expressions.Expressions.ofIntegerArray; import static com.mongodb.client.model.expressions.Expressions.ofNumberArray; import static com.mongodb.client.model.expressions.Expressions.ofStringArray; -import static org.testng.internal.collections.Ints.asList; @SuppressWarnings({"ConstantConditions", "Convert2MethodRef"}) class ArrayExpressionsFunctionalTest extends AbstractExpressionsFunctionalTest { @@ -196,7 +195,7 @@ public void firstTest() { // https://www.mongodb.com/docs/manual/reference/operator/aggregation/first/ // https://www.mongodb.com/docs/manual/reference/operator/aggregation/first-array-element/ assertExpression( - new LinkedList<>(asList(1, 2, 3)).getFirst(), + new LinkedList<>(Arrays.asList(1, 2, 3)).getFirst(), array123.first(), // MQL: "{'$first': [[1, 2, 3]]}"); @@ -206,7 +205,7 @@ public void firstTest() { public void lastTest() { // https://www.mongodb.com/docs/manual/reference/operator/aggregation/last-array-element/ assertExpression( - new LinkedList<>(asList(1, 2, 3)).getLast(), + new LinkedList<>(Arrays.asList(1, 2, 3)).getLast(), array123.last(), // MQL: "{'$last': [[1, 2, 3]]}"); @@ -262,7 +261,7 @@ public void setUnionTest() { // https://www.mongodb.com/docs/manual/reference/operator/aggregation/setUnion/ (40) assertExpression( Arrays.asList(1, 2, 3), - array123.setUnion(array123), + array123.union(array123), // MQL: "{'$setUnion': [[1, 2, 3], [1, 2, 3]]}"); // convenience