From 12caad823247838d23a8e2b6ee782f8490187b91 Mon Sep 17 00:00:00 2001 From: Maxim Katcharov Date: Wed, 23 Nov 2022 14:10:02 -0700 Subject: [PATCH 01/15] Implement switch expression --- .../client/model/expressions/Branches.java | 92 ++++++++ .../expressions/BranchesIntermediary.java | 97 +++++++++ .../model/expressions/BranchesTerminal.java | 47 ++++ .../client/model/expressions/Expression.java | 15 ++ .../model/expressions/MqlExpression.java | 44 +++- .../client/model/expressions/SwitchCase.java | 35 +++ .../ComparisonExpressionsFunctionalTest.java | 11 + .../ControlExpressionsFunctionalTest.java | 205 ++++++++++++++++++ 8 files changed, 542 insertions(+), 4 deletions(-) create mode 100644 driver-core/src/main/com/mongodb/client/model/expressions/Branches.java create mode 100644 driver-core/src/main/com/mongodb/client/model/expressions/BranchesIntermediary.java create mode 100644 driver-core/src/main/com/mongodb/client/model/expressions/BranchesTerminal.java create mode 100644 driver-core/src/main/com/mongodb/client/model/expressions/SwitchCase.java create mode 100644 driver-core/src/test/functional/com/mongodb/client/model/expressions/ControlExpressionsFunctionalTest.java diff --git a/driver-core/src/main/com/mongodb/client/model/expressions/Branches.java b/driver-core/src/main/com/mongodb/client/model/expressions/Branches.java new file mode 100644 index 00000000000..3ab56e8b6fa --- /dev/null +++ b/driver-core/src/main/com/mongodb/client/model/expressions/Branches.java @@ -0,0 +1,92 @@ +/* + * Copyright 2008-present MongoDB, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.mongodb.client.model.expressions; + +import java.util.ArrayList; +import java.util.List; +import java.util.function.Function; + +public final class Branches { + + Branches() { + // package-private + } + + private BranchesIntermediary with(final Function> switchCase) { + List>> v = new ArrayList<>(); + v.add(switchCase); + return new BranchesIntermediary<>(v); + } + + private static MqlExpression mqlEx(final T value) { + return (MqlExpression) value; + } + + // is fn + + public BranchesIntermediary is(final Function o, final Function r) { + return this.with(value -> new SwitchCase<>(o.apply(value), r.apply(value))); + } + + // eq lt lte + + public BranchesIntermediary eq(final T v, final Function r) { + return this.with(value -> new SwitchCase<>(value.eq(v), r.apply(value))); + } + + public BranchesIntermediary lt(final T v, final Function r) { + return this.with(value -> new SwitchCase<>(value.lt(v), r.apply(value))); + } + + public BranchesIntermediary lte(final T v, final Function r) { + return this.with(value -> new SwitchCase<>(value.lte(v), r.apply(value))); + } + + // is type + + public BranchesIntermediary isBoolean(final Function r) { + return this.with(value -> new SwitchCase<>(mqlEx(value).isBoolean(), r.apply((BooleanExpression) value))); + } + + public BranchesIntermediary isNumber(final Function r) { + return this.with(value -> new SwitchCase<>(mqlEx(value).isNumber(), r.apply((NumberExpression) value))); + } + + public BranchesIntermediary isString(final Function r) { + return this.with(value -> new SwitchCase<>(mqlEx(value).isString(), r.apply((StringExpression) value))); + } + + public BranchesIntermediary isDate(final Function r) { + return this.with(value -> new SwitchCase<>(mqlEx(value).isDate(), r.apply((DateExpression) value))); + } + + public BranchesIntermediary isArray(final Function, R> r) { + return this.with(value -> new SwitchCase<>(mqlEx(value).isArray(), r.apply((ArrayExpression) value))); + } + + public BranchesIntermediary isDocument(final Function r) { + return this.with(value -> new SwitchCase<>(mqlEx(value).isDocument(), r.apply((DocumentExpression) value))); + } + + public BranchesIntermediary isMap(final Function, R> r) { + return this.with(value -> new SwitchCase<>(mqlEx(value).isDocument(), r.apply((MapExpression) value))); + } + + public BranchesIntermediary isNull(final Function isNull) { + return this.with(value -> new SwitchCase<>(mqlEx(value).isNull(), isNull.apply(value))); + } +} diff --git a/driver-core/src/main/com/mongodb/client/model/expressions/BranchesIntermediary.java b/driver-core/src/main/com/mongodb/client/model/expressions/BranchesIntermediary.java new file mode 100644 index 00000000000..48e8843df73 --- /dev/null +++ b/driver-core/src/main/com/mongodb/client/model/expressions/BranchesIntermediary.java @@ -0,0 +1,97 @@ +/* + * Copyright 2008-present MongoDB, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.mongodb.client.model.expressions; + +import java.util.ArrayList; +import java.util.List; +import java.util.function.Function; + +public final class BranchesIntermediary extends BranchesTerminal { + BranchesIntermediary(final List>> branches) { + super(branches, null); + } + + private BranchesIntermediary with(final Function> switchCase) { + List>> v = new ArrayList<>(this.getBranches()); + v.add(switchCase); + return new BranchesIntermediary<>(v); + } + + private static MqlExpression mqlEx(final T value) { + return (MqlExpression) value; + } + + // is fn + + public BranchesIntermediary is(final Function o, final Function r) { + return this.with(value -> new SwitchCase<>(o.apply(value), r.apply(value))); + } + + // eq lt lte + + public BranchesIntermediary eq(final T v, final Function r) { + return this.with(value -> new SwitchCase<>(value.eq(v), r.apply(value))); + } + + public BranchesIntermediary lt(final T v, final Function r) { + return this.with(value -> new SwitchCase<>(value.lt(v), r.apply(value))); + } + + public BranchesIntermediary lte(final T v, final Function r) { + return this.with(value -> new SwitchCase<>(value.lte(v), r.apply(value))); + } + + // is type + + public BranchesIntermediary isBoolean(final Function r) { + return this.with(v -> new SwitchCase<>(mqlEx(v).isBoolean(), r.apply((BooleanExpression) v))); + } + + public BranchesIntermediary isNumber(final Function r) { + return this.with(v -> new SwitchCase<>(mqlEx(v).isNumber(), r.apply((NumberExpression) v))); + } + + + public BranchesIntermediary isString(final Function r) { + return this.with(value -> new SwitchCase<>(mqlEx(value).isString(), r.apply((StringExpression) value))); + } + + public BranchesIntermediary isDate(final Function r) { + return this.with(value -> new SwitchCase<>(mqlEx(value).isDate(), r.apply((DateExpression) value))); + } + + public BranchesIntermediary isArray(final Function, R> r) { + return this.with(value -> new SwitchCase<>(mqlEx(value).isArray(), r.apply((ArrayExpression) value))); + } + + public BranchesIntermediary isDocument(final Function r) { + return this.with(value -> new SwitchCase<>(mqlEx(value).isDocument(), r.apply((DocumentExpression) value))); + } + + public BranchesIntermediary isMap(final Function, R> r) { + return this.with(value -> new SwitchCase<>(mqlEx(value).isDocument(), r.apply((MapExpression) value))); + } + + public BranchesIntermediary isNull(final Function r) { + return this.with(value -> new SwitchCase<>(mqlEx(value).isNull(), r.apply(value))); + } + + public BranchesTerminal defaults(final Function r) { + return this.withDefault(value -> r.apply(value)); + } + +} diff --git a/driver-core/src/main/com/mongodb/client/model/expressions/BranchesTerminal.java b/driver-core/src/main/com/mongodb/client/model/expressions/BranchesTerminal.java new file mode 100644 index 00000000000..97d0b85f233 --- /dev/null +++ b/driver-core/src/main/com/mongodb/client/model/expressions/BranchesTerminal.java @@ -0,0 +1,47 @@ +/* + * Copyright 2008-present MongoDB, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.mongodb.client.model.expressions; + +import com.mongodb.lang.Nullable; + +import java.util.List; +import java.util.function.Function; + +public class BranchesTerminal { + + private final List>> branches; + + private final Function defaults; + + BranchesTerminal(final List>> branches, @Nullable final Function defaults) { + this.branches = branches; + this.defaults = defaults; + } + + protected BranchesTerminal withDefault(final Function defaults) { + return new BranchesTerminal<>(branches, defaults); + } + + protected List>> getBranches() { + return branches; + } + + @Nullable + protected Function getDefaults() { + return defaults; + } +} diff --git a/driver-core/src/main/com/mongodb/client/model/expressions/Expression.java b/driver-core/src/main/com/mongodb/client/model/expressions/Expression.java index e2000d24aaa..3b92dd4557a 100644 --- a/driver-core/src/main/com/mongodb/client/model/expressions/Expression.java +++ b/driver-core/src/main/com/mongodb/client/model/expressions/Expression.java @@ -18,6 +18,8 @@ import com.mongodb.annotations.Evolving; +import java.util.function.Function; + /** * Expressions express values that may be represented in (or computations that * may be performed within) a MongoDB server. Each expression evaluates to some @@ -114,4 +116,17 @@ public interface Expression { MapExpression isMapOr(MapExpression other); StringExpression asString(); + + /** + * Applies the given function to this argument. Note that "apply" usually + * applies functions to arguments; here, the parameters are reversed. + * + * @param f + * @return + * @param + * @param + */ + R apply(Function f); + + R0 switchMap(Function> switchMap); } 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 e26643ddf80..c86d38f9c19 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 @@ -28,6 +28,7 @@ import java.util.function.Function; import static com.mongodb.client.model.expressions.Expressions.of; +import static com.mongodb.client.model.expressions.Expressions.ofNull; import static com.mongodb.client.model.expressions.Expressions.ofStringArray; final class MqlExpression @@ -282,6 +283,11 @@ public DocumentExpression unsetField(final String fieldName) { /** @see Expression */ + @Override + public R apply(final Function f) { + return f.apply(this.assertImplementsAllExpressions()); + } + @Override public BooleanExpression eq(final Expression eq) { return new MqlExpression<>(ast("$eq", eq)); @@ -313,7 +319,7 @@ public BooleanExpression lte(final Expression lte) { } public BooleanExpression isBoolean() { - return new MqlExpression<>(ast("$type")).eq(of("bool")); + return new MqlExpression<>(astWrapped("$type")).eq(of("bool")); } @Override @@ -340,7 +346,7 @@ public IntegerExpression isIntegerOr(final IntegerExpression other) { } public BooleanExpression isString() { - return new MqlExpression<>(ast("$type")).eq(of("string")); + return new MqlExpression<>(astWrapped("$type")).eq(of("string")); } @Override @@ -349,7 +355,7 @@ public StringExpression isStringOr(final StringExpression other) { } public BooleanExpression isDate() { - return ofStringArray("date").contains(new MqlExpression<>(ast("$type"))); + return ofStringArray("date").contains(new MqlExpression<>(astWrapped("$type"))); } @Override @@ -362,7 +368,7 @@ public BooleanExpression isArray() { } private Expression ifNull(final Expression ifNull) { - return new MqlExpression<>(ast("$ifNull", ifNull, Expressions.ofNull())) + return new MqlExpression<>(ast("$ifNull", ifNull, ofNull())) .assertImplementsAllExpressions(); } @@ -395,6 +401,10 @@ public MapExpression isMapOr(final MapExpression(astWrapped("$toString")); @@ -407,6 +417,32 @@ private Function convertInternal(final String to, .append("to", new BsonString(to))); } + @Override + public R0 switchMap( + final Function> switchMap) { + T0 value = this.assertImplementsAllExpressions(); + BranchesTerminal construct = switchMap.apply(new Branches()); + return switchMapInternal(value, construct); + } + + private R0 switchMapInternal( + final T0 value, final BranchesTerminal construct) { + return newMqlExpression((cr) -> { + BsonArray branches = new BsonArray(); + for (Function> fn : construct.getBranches()) { + SwitchCase result = fn.apply(value); + branches.add(new BsonDocument() + .append("case", extractBsonValue(cr, result.getCaseValue())) + .append("then", extractBsonValue(cr, result.getThenValue()))); + } + BsonDocument switchBson = new BsonDocument().append("branches", branches); + if (construct.getDefaults() != null) { + switchBson = switchBson.append("default", extractBsonValue(cr, construct.getDefaults().apply(value))); + } + return astDoc("$switch", switchBson); + }); + } + @Override public IntegerExpression parseInteger() { Expression asLong = new MqlExpression<>(ast("$toLong")); diff --git a/driver-core/src/main/com/mongodb/client/model/expressions/SwitchCase.java b/driver-core/src/main/com/mongodb/client/model/expressions/SwitchCase.java new file mode 100644 index 00000000000..bbdc608391c --- /dev/null +++ b/driver-core/src/main/com/mongodb/client/model/expressions/SwitchCase.java @@ -0,0 +1,35 @@ +/* + * Copyright 2008-present MongoDB, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.mongodb.client.model.expressions; + +final class SwitchCase { + private final BooleanExpression caseValue; + private final R thenValue; + + SwitchCase(final BooleanExpression caseValue, final R thenValue) { + this.caseValue = caseValue; + this.thenValue = thenValue; + } + + BooleanExpression getCaseValue() { + return caseValue; + } + + R getThenValue() { + return thenValue; + } +} 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 b044128f039..283eaca1c1f 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 @@ -60,6 +60,17 @@ class ComparisonExpressionsFunctionalTest extends AbstractExpressionsFunctionalT of(Instant.now()) ); + @Test + public void literalsTest() { + // special values + assertExpression(null, ofNull(), "null"); + // the "missing" value is obtained via getField. + // the "$$REMOVE" value is intentionally not exposed. It is used internally. + // the "undefined" value is deprecated. + // https://www.mongodb.com/docs/manual/reference/operator/aggregation/literal/ + // $literal is intentionally not exposed. It is used internally. + } + @Test public void eqTest() { // https://www.mongodb.com/docs/manual/reference/operator/aggregation/eq/ diff --git a/driver-core/src/test/functional/com/mongodb/client/model/expressions/ControlExpressionsFunctionalTest.java b/driver-core/src/test/functional/com/mongodb/client/model/expressions/ControlExpressionsFunctionalTest.java new file mode 100644 index 00000000000..d1f67336d55 --- /dev/null +++ b/driver-core/src/test/functional/com/mongodb/client/model/expressions/ControlExpressionsFunctionalTest.java @@ -0,0 +1,205 @@ +/* + * Copyright 2008-present MongoDB, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.mongodb.client.model.expressions; + +import org.bson.Document; +import org.junit.jupiter.api.Test; + +import java.time.Instant; +import java.util.function.Function; + +import static com.mongodb.client.model.expressions.Expressions.of; +import static com.mongodb.client.model.expressions.Expressions.ofIntegerArray; +import static com.mongodb.client.model.expressions.Expressions.ofMap; +import static com.mongodb.client.model.expressions.Expressions.ofNull; + +class ControlExpressionsFunctionalTest extends AbstractExpressionsFunctionalTest { + + @Test + public void applyTest() { + Function decrement = (e) -> e.subtract(of(1)); + // "nested functional" function application: + assertExpression( + 2 - 1, + decrement.apply(of(2)), + "{'$subtract': [2, 1]}"); + // "chained" function application: + assertExpression( + 2 - 1, // = 0 + of(2).apply(decrement), + "{'$subtract': [2, 1]}"); + // the parameters are reversed, compared to Java's function.apply + } + + @Test + public void switchTest() { + // https://www.mongodb.com/docs/manual/reference/operator/aggregation/switch/ + assertExpression("a", of(0).switchMap(on -> on.is(v -> v.eq(of(0)), v -> of("a")))); + assertExpression("a", of(0).switchMap(on -> on.isNumber(v -> of("a")))); + assertExpression("a", of(0).switchMap(on -> on.lte(of(9), v -> of("a")))); + + // test branches + Function isOver10 = v -> v.subtract(10).gt(of(0)); + Function s = e -> e + .switchMap((Branches on) -> on + .eq(of(0), v -> of("A")) + .lt(of(10), v -> of("B")) + .is(isOver10, v -> of("C")) + .defaults(v -> of("D"))) + .toLower(); + + assertExpression("a", of(0).apply(s)); + assertExpression("b", of(9).apply(s)); + assertExpression("b", of(-9).apply(s)); + assertExpression("c", of(11).apply(s)); + assertExpression("d", of(10).apply(s)); + } + + @Test + public void switchTypesTest() { + Function label = expr -> expr.switchMap(on -> on + .isBoolean(v -> v.asString().concat(of(" - bool"))) + .isNumber(v -> v.asString().concat(of(" - number"))) + .isString(v -> v.asString().concat(of(" - string"))) + .isDate(v -> v.asString().concat(of(" - date"))) + .isArray((ArrayExpression v) -> v.sum(a -> a).asString().concat(of(" - array"))) + .isDocument(v -> v.getString("_id").concat(of(" - document"))) + .isNull(v -> of("null - null")) + .defaults(v -> of("default")) + ).toLower(); + assertExpression("true - bool", of(true).apply(label)); + assertExpression("false - bool", of(false).apply(label)); + assertExpression("1 - number", of(1).apply(label)); + assertExpression("1 - number", of(1.0).apply(label)); + assertExpression("abc - string", of("abc").apply(label)); + assertExpression("1970-01-01t00:00:00.123z - date", of(Instant.ofEpochMilli(123)).apply(label)); + assertExpression("3 - array", ofIntegerArray(1, 2).apply(label)); + assertExpression("a - document", of(Document.parse("{_id: 'a'}")).apply(label)); + assertExpression("null - null", ofNull().apply(label)); + assertExpression( + "ab - map", + ofMap(Document.parse("{a: 1, b: 2}")).switchMap(on -> on + .isMap((MapExpression v) -> v.entrySet() + .join(e -> e.getKey()).concat(of(" - map"))))); + } + + @Test + public void switchTestInitial() { + assertExpression("A", + of(0).switchMap(on -> on.is(v -> v.gt(of(-1)), v -> of("A"))), + "{'$switch': {'branches': [{'case': {'$gt': [0, -1]}, 'then': 'A'}]}}"); + // eq lt lte + assertExpression("A", + of(0).switchMap(on -> on.eq(of(0), v -> of("A"))), + "{'$switch': {'branches': [{'case': {'$eq': [0, 0]}, 'then': 'A'}]}}"); + assertExpression("A", + of(0).switchMap(on -> on.lt(of(1), v -> of("A"))), + "{'$switch': {'branches': [{'case': {'$lt': [0, 1]}, 'then': 'A'}]}}"); + assertExpression("A", + of(0).switchMap(on -> on.lte(of(0), v -> of("A"))), + "{'$switch': {'branches': [{'case': {'$lte': [0, 0]}, 'then': 'A'}]}}"); + // is type + assertExpression("A", + of(true).switchMap(on -> on.isBoolean(v -> of("A"))), + "{'$switch': {'branches': [{'case': {'$eq': [{'$type': [true]}, 'bool']}, 'then': 'A'}]}}"); + assertExpression("A", + of(1).switchMap(on -> on.isNumber(v -> of("A"))), + "{'$switch': {'branches': [{'case': {'$isNumber': [1]}, 'then': 'A'}]}}"); + assertExpression("A", + of("x").switchMap(on -> on.isString(v -> of("A"))), + "{'$switch': {'branches': [{'case': {'$eq': [{'$type': ['x']}, 'string']}, 'then': 'A'}]}}"); + assertExpression("A", + of(Instant.ofEpochMilli(123)).switchMap(on -> on.isDate(v -> of("A"))), + "{'$switch': {'branches': [{'case': {'$in': [{'$type': " + + "[{'$date': '1970-01-01T00:00:00.123Z'}]}, ['date', 'timestamp']]}, 'then': 'A'}]}}"); + assertExpression("A", + ofIntegerArray(0).switchMap(on -> on.isArray(v -> of("A"))), + "{'$switch': {'branches': [{'case': {'$isArray': [[0]]}, 'then': 'A'}]}}"); + assertExpression("A", + of(Document.parse("{}")).switchMap(on -> on.isDocument(v -> of("A"))), + "{'$switch': {'branches': [{'case': {'$eq': [{'$type': " + + "[{'$literal': {}}]}, 'object']}, 'then': 'A'}]}}"); + assertExpression("A", + ofMap(Document.parse("{}")).switchMap(on -> on.isMap(v -> of("A"))), + "{'$switch': {'branches': [{'case': {'$eq': [{'$type': " + + "[{'$literal': {}}]}, 'object']}, 'then': 'A'}]}}"); + assertExpression("A", + ofNull().switchMap(on -> on.isNull(v -> of("A"))), + "{'$switch': {'branches': [{'case': {'$eq': [null, null]}, 'then': 'A'}]}}"); + } + + @Test + public void switchTestPartial() { + assertExpression("A", + of(0).switchMap(on -> on.isNull(v -> of("X")).is(v -> v.gt(of(-1)), v -> of("A"))), + "{'$switch': {'branches': [{'case': {'$eq': [0, null]}, 'then': 'X'}, " + + "{'case': {'$gt': [0, -1]}, 'then': 'A'}]}}"); + assertExpression("A", + of(0).switchMap(on -> on.isNull(v -> of("X")).defaults(v -> of("A"))), + "{'$switch': {'branches': [{'case': {'$eq': [0, null]}, 'then': 'X'}], " + + "'default': 'A'}}"); + // eq lt lte + assertExpression("A", + of(0).switchMap(on -> on.isNull(v -> of("X")).eq(of(0), v -> of("A"))), + "{'$switch': {'branches': [{'case': {'$eq': [0, null]}, 'then': 'X'}, " + + "{'case': {'$eq': [0, 0]}, 'then': 'A'}]}}"); + assertExpression("A", + of(0).switchMap(on -> on.isNull(v -> of("X")).lt(of(1), v -> of("A"))), + "{'$switch': {'branches': [{'case': {'$eq': [0, null]}, 'then': 'X'}, " + + "{'case': {'$lt': [0, 1]}, 'then': 'A'}]}}"); + assertExpression("A", + of(0).switchMap(on -> on.isNull(v -> of("X")).lte(of(0), v -> of("A"))), + "{'$switch': {'branches': [{'case': {'$eq': [0, null]}, 'then': 'X'}, " + + "{'case': {'$lte': [0, 0]}, 'then': 'A'}]}}"); + // is type + assertExpression("A", + of(true).switchMap(on -> on.isNull(v -> of("X")).isBoolean(v -> of("A"))), + "{'$switch': {'branches': [{'case': {'$eq': [true, null]}, 'then': 'X'}, " + + "{'case': {'$eq': [{'$type': [true]}, 'bool']}, 'then': 'A'}]}}"); + assertExpression("A", + of(1).switchMap(on -> on.isNull(v -> of("X")).isNumber(v -> of("A"))), + "{'$switch': {'branches': [{'case': {'$eq': [1, null]}, 'then': 'X'}, " + + "{'case': {'$isNumber': [1]}, 'then': 'A'}]}}"); + assertExpression("A", + of("x").switchMap(on -> on.isNull(v -> of("X")).isString(v -> of("A"))), + "{'$switch': {'branches': [{'case': {'$eq': ['x', null]}, 'then': 'X'}, " + + "{'case': {'$eq': [{'$type': ['x']}, 'string']}, 'then': 'A'}]}}"); + assertExpression("A", + of(Instant.ofEpochMilli(123)).switchMap(on -> on.isNull(v -> of("X")).isDate(v -> of("A"))), + "{'$switch': {'branches': [" + + "{'case': {'$eq': [{'$date': '1970-01-01T00:00:00.123Z'}, null]}, 'then': 'X'}, " + + "{'case': {'$in': [{'$type': [{'$date': '1970-01-01T00:00:00.123Z'}]}, " + + "['date', 'timestamp']]}, 'then': 'A'}]}}"); + assertExpression("A", + ofIntegerArray(0).switchMap(on -> on.isNull(v -> of("X")).isArray(v -> of("A"))), + "{'$switch': {'branches': [{'case': {'$eq': [[0], null]}, 'then': 'X'}, " + + "{'case': {'$isArray': [[0]]}, 'then': 'A'}]}}"); + assertExpression("A", + of(Document.parse("{}")).switchMap(on -> on.isNull(v -> of("X")).isDocument(v -> of("A"))), + "{'$switch': {'branches': [{'case': {'$eq': [{'$literal': {}}, null]}, 'then': 'X'}, " + + "{'case': {'$eq': [{'$type': [{'$literal': {}}]}, 'object']}, 'then': 'A'}]}}"); + assertExpression("A", + ofMap(Document.parse("{}")).switchMap(on -> on.isNull(v -> of("X")).isMap(v -> of("A"))), + " {'$switch': {'branches': [" + + "{'case': {'$eq': [{'$literal': {}}, null]}, 'then': 'X'}, " + + "{'case': {'$eq': [{'$type': [{'$literal': {}}]}, 'object']}, 'then': 'A'}]}}"); + assertExpression("A", + ofNull().switchMap(on -> on.isNumber(v -> of("X")).isNull(v -> of("A"))), + "{'$switch': {'branches': [{'case': {'$isNumber': [null]}, 'then': 'X'}, " + + "{'case': {'$eq': [null, null]}, 'then': 'A'}]}}"); + } +} From 396ae10a480453c03e246a5be68bd11c04062f3a Mon Sep 17 00:00:00 2001 From: Maxim Katcharov Date: Wed, 7 Dec 2022 18:19:49 -0700 Subject: [PATCH 02/15] Expand pass and switch; add tests; fix broken test --- .../model/expressions/ArrayExpression.java | 4 + .../model/expressions/BooleanExpression.java | 6 + .../model/expressions/DateExpression.java | 4 + .../model/expressions/DocumentExpression.java | 4 + .../client/model/expressions/Expression.java | 14 +- .../model/expressions/IntegerExpression.java | 5 + .../model/expressions/MapExpression.java | 5 + .../model/expressions/MqlExpression.java | 131 ++++++++++++---- .../model/expressions/NumberExpression.java | 5 + .../model/expressions/StringExpression.java | 5 + .../ComparisonExpressionsFunctionalTest.java | 1 + .../ControlExpressionsFunctionalTest.java | 147 +++++++++++------- .../TypeExpressionsFunctionalTest.java | 8 +- 13 files changed, 243 insertions(+), 96 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 dc1e7b84261..b6be283286d 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 @@ -112,4 +112,8 @@ default ArrayExpression slice(final int start, final int length) { ArrayExpression union(ArrayExpression set); ArrayExpression distinct(); + + R passArrayTo(Function, R> f); + + R switchArrayOn(Function, R>> on); } diff --git a/driver-core/src/main/com/mongodb/client/model/expressions/BooleanExpression.java b/driver-core/src/main/com/mongodb/client/model/expressions/BooleanExpression.java index fcf0eca939e..7f745a1142c 100644 --- a/driver-core/src/main/com/mongodb/client/model/expressions/BooleanExpression.java +++ b/driver-core/src/main/com/mongodb/client/model/expressions/BooleanExpression.java @@ -16,6 +16,8 @@ package com.mongodb.client.model.expressions; +import java.util.function.Function; + /** * Expresses a boolean value. */ @@ -58,4 +60,8 @@ public interface BooleanExpression extends Expression { * @param The type of the resulting expression. */ T cond(T left, T right); + + R passBooleanTo(Function f); + + R switchBooleanOn(Function> on); } diff --git a/driver-core/src/main/com/mongodb/client/model/expressions/DateExpression.java b/driver-core/src/main/com/mongodb/client/model/expressions/DateExpression.java index 04eb6b00ea5..5fb34124ecc 100644 --- a/driver-core/src/main/com/mongodb/client/model/expressions/DateExpression.java +++ b/driver-core/src/main/com/mongodb/client/model/expressions/DateExpression.java @@ -16,6 +16,8 @@ package com.mongodb.client.model.expressions; +import java.util.function.Function; + /** * Expresses a date value. */ @@ -33,4 +35,6 @@ public interface DateExpression extends Expression { StringExpression asString(StringExpression timezone, StringExpression format); + R passDateTo(Function f); + R switchDateOn(Function> on); } diff --git a/driver-core/src/main/com/mongodb/client/model/expressions/DocumentExpression.java b/driver-core/src/main/com/mongodb/client/model/expressions/DocumentExpression.java index 3ce4f8946b5..770371297bd 100644 --- a/driver-core/src/main/com/mongodb/client/model/expressions/DocumentExpression.java +++ b/driver-core/src/main/com/mongodb/client/model/expressions/DocumentExpression.java @@ -19,6 +19,7 @@ import org.bson.conversions.Bson; import java.time.Instant; +import java.util.function.Function; import static com.mongodb.client.model.expressions.Expressions.of; import static com.mongodb.client.model.expressions.Expressions.ofMap; @@ -100,4 +101,7 @@ default MapExpression getMap(final String fieldName, f DocumentExpression merge(DocumentExpression other); MapExpression asMap(); + + R passDocumentTo(Function f); + R switchDocumentOn(Function> on); } diff --git a/driver-core/src/main/com/mongodb/client/model/expressions/Expression.java b/driver-core/src/main/com/mongodb/client/model/expressions/Expression.java index 3b92dd4557a..5187ca68909 100644 --- a/driver-core/src/main/com/mongodb/client/model/expressions/Expression.java +++ b/driver-core/src/main/com/mongodb/client/model/expressions/Expression.java @@ -117,16 +117,8 @@ public interface Expression { StringExpression asString(); - /** - * Applies the given function to this argument. Note that "apply" usually - * applies functions to arguments; here, the parameters are reversed. - * - * @param f - * @return - * @param - * @param - */ - R apply(Function f); + R passTo(Function f); + + R switchOn(Function> on); - R0 switchMap(Function> switchMap); } diff --git a/driver-core/src/main/com/mongodb/client/model/expressions/IntegerExpression.java b/driver-core/src/main/com/mongodb/client/model/expressions/IntegerExpression.java index eab541c0474..b673c44e5b0 100644 --- a/driver-core/src/main/com/mongodb/client/model/expressions/IntegerExpression.java +++ b/driver-core/src/main/com/mongodb/client/model/expressions/IntegerExpression.java @@ -16,6 +16,8 @@ package com.mongodb.client.model.expressions; +import java.util.function.Function; + /** * Expresses an integer value. */ @@ -42,4 +44,7 @@ default IntegerExpression subtract(final int subtract) { IntegerExpression min(IntegerExpression i); IntegerExpression abs(); + + R passIntegerTo(Function f); + R switchIntegerOn(Function> on); } diff --git a/driver-core/src/main/com/mongodb/client/model/expressions/MapExpression.java b/driver-core/src/main/com/mongodb/client/model/expressions/MapExpression.java index 2271a77025d..f25afefdc4d 100644 --- a/driver-core/src/main/com/mongodb/client/model/expressions/MapExpression.java +++ b/driver-core/src/main/com/mongodb/client/model/expressions/MapExpression.java @@ -16,6 +16,8 @@ package com.mongodb.client.model.expressions; +import java.util.function.Function; + import static com.mongodb.client.model.expressions.Expressions.of; public interface MapExpression extends Expression { @@ -57,4 +59,7 @@ default MapExpression unset(final String key) { ArrayExpression> entrySet(); R asDocument(); + + R passMapTo(Function, R> f); + R switchMapOn(Function, R>> on); } 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 c86d38f9c19..f4962c1a7c3 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 @@ -284,10 +284,113 @@ public DocumentExpression unsetField(final String fieldName) { /** @see Expression */ @Override - public R apply(final Function f) { + public R passTo(final Function f) { return f.apply(this.assertImplementsAllExpressions()); } + @Override + public R switchOn(final Function> switchMap) { + return switchMapInternal(this.assertImplementsAllExpressions(), switchMap.apply(new Branches())); + } + + @Override + public R passBooleanTo(final Function f) { + return f.apply(this.assertImplementsAllExpressions()); + } + + @Override + public R switchBooleanOn(final Function> switchMap) { + return switchMapInternal(this.assertImplementsAllExpressions(), switchMap.apply(new Branches())); + } + + @Override + public R passIntegerTo(final Function f) { + return f.apply(this.assertImplementsAllExpressions()); + } + + @Override + public R switchIntegerOn(final Function> switchMap) { + return switchMapInternal(this.assertImplementsAllExpressions(), switchMap.apply(new Branches())); + } + + @Override + public R passNumberTo(final Function f) { + return f.apply(this.assertImplementsAllExpressions()); + } + + @Override + public R switchNumberOn(final Function> switchMap) { + return switchMapInternal(this.assertImplementsAllExpressions(), switchMap.apply(new Branches())); + } + + @Override + public R passStringTo(final Function f) { + return f.apply(this.assertImplementsAllExpressions()); + } + + @Override + public R switchStringOn(final Function> switchMap) { + return switchMapInternal(this.assertImplementsAllExpressions(), switchMap.apply(new Branches())); + } + + @Override + public R passDateTo(final Function f) { + return f.apply(this.assertImplementsAllExpressions()); + } + + @Override + public R switchDateOn(final Function> switchMap) { + return switchMapInternal(this.assertImplementsAllExpressions(), switchMap.apply(new Branches())); + } + + @Override + public R passArrayTo(final Function, R> f) { + return f.apply(this.assertImplementsAllExpressions()); + } + + @Override + public R switchArrayOn(final Function, R>> switchMap) { + return switchMapInternal(this.assertImplementsAllExpressions(), switchMap.apply(new Branches())); + } + + @Override + public R passMapTo(final Function, R> f) { + return f.apply(this.assertImplementsAllExpressions()); + } + + @Override + public R switchMapOn(final Function, R>> switchMap) { + return switchMapInternal(this.assertImplementsAllExpressions(), switchMap.apply(new Branches())); + } + + @Override + public R passDocumentTo(final Function f) { + return f.apply(this.assertImplementsAllExpressions()); + } + + @Override + public R switchDocumentOn(final Function> switchMap) { + return switchMapInternal(this.assertImplementsAllExpressions(), switchMap.apply(new Branches())); + } + + private R0 switchMapInternal( + final T0 value, final BranchesTerminal construct) { + return newMqlExpression((cr) -> { + BsonArray branches = new BsonArray(); + for (Function> fn : construct.getBranches()) { + SwitchCase result = fn.apply(value); + branches.add(new BsonDocument() + .append("case", extractBsonValue(cr, result.getCaseValue())) + .append("then", extractBsonValue(cr, result.getThenValue()))); + } + BsonDocument switchBson = new BsonDocument().append("branches", branches); + if (construct.getDefaults() != null) { + switchBson = switchBson.append("default", extractBsonValue(cr, construct.getDefaults().apply(value))); + } + return astDoc("$switch", switchBson); + }); + } + @Override public BooleanExpression eq(final Expression eq) { return new MqlExpression<>(ast("$eq", eq)); @@ -417,32 +520,6 @@ private Function convertInternal(final String to, .append("to", new BsonString(to))); } - @Override - public R0 switchMap( - final Function> switchMap) { - T0 value = this.assertImplementsAllExpressions(); - BranchesTerminal construct = switchMap.apply(new Branches()); - return switchMapInternal(value, construct); - } - - private R0 switchMapInternal( - final T0 value, final BranchesTerminal construct) { - return newMqlExpression((cr) -> { - BsonArray branches = new BsonArray(); - for (Function> fn : construct.getBranches()) { - SwitchCase result = fn.apply(value); - branches.add(new BsonDocument() - .append("case", extractBsonValue(cr, result.getCaseValue())) - .append("then", extractBsonValue(cr, result.getThenValue()))); - } - BsonDocument switchBson = new BsonDocument().append("branches", branches); - if (construct.getDefaults() != null) { - switchBson = switchBson.append("default", extractBsonValue(cr, construct.getDefaults().apply(value))); - } - return astDoc("$switch", switchBson); - }); - } - @Override public IntegerExpression parseInteger() { Expression asLong = new MqlExpression<>(ast("$toLong")); diff --git a/driver-core/src/main/com/mongodb/client/model/expressions/NumberExpression.java b/driver-core/src/main/com/mongodb/client/model/expressions/NumberExpression.java index f08b9a57d00..e46b54b1587 100644 --- a/driver-core/src/main/com/mongodb/client/model/expressions/NumberExpression.java +++ b/driver-core/src/main/com/mongodb/client/model/expressions/NumberExpression.java @@ -16,6 +16,8 @@ package com.mongodb.client.model.expressions; +import java.util.function.Function; + /** * Expresses a numeric value. */ @@ -56,4 +58,7 @@ default NumberExpression subtract(final Number subtract) { NumberExpression abs(); DateExpression millisecondsToDate(); + + R passNumberTo(Function f); + R switchNumberOn(Function> on); } diff --git a/driver-core/src/main/com/mongodb/client/model/expressions/StringExpression.java b/driver-core/src/main/com/mongodb/client/model/expressions/StringExpression.java index c5cc7a8eb72..8799ab1f3e2 100644 --- a/driver-core/src/main/com/mongodb/client/model/expressions/StringExpression.java +++ b/driver-core/src/main/com/mongodb/client/model/expressions/StringExpression.java @@ -16,6 +16,8 @@ package com.mongodb.client.model.expressions; +import java.util.function.Function; + import static com.mongodb.client.model.expressions.Expressions.of; /** @@ -52,4 +54,7 @@ default StringExpression substrBytes(final int start, final int length) { DateExpression parseDate(StringExpression format); DateExpression parseDate(StringExpression timezone, StringExpression format); + + R passStringTo(Function f); + R switchStringOn(Function> on); } 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 283eaca1c1f..1dc30aea020 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 @@ -44,6 +44,7 @@ class ComparisonExpressionsFunctionalTest extends AbstractExpressionsFunctionalT ofNull(), of(0), of(1), + of(2.0), of(""), of("str"), of(BsonDocument.parse("{}")), diff --git a/driver-core/src/test/functional/com/mongodb/client/model/expressions/ControlExpressionsFunctionalTest.java b/driver-core/src/test/functional/com/mongodb/client/model/expressions/ControlExpressionsFunctionalTest.java index d1f67336d55..a6e8a0c3885 100644 --- a/driver-core/src/test/functional/com/mongodb/client/model/expressions/ControlExpressionsFunctionalTest.java +++ b/driver-core/src/test/functional/com/mongodb/client/model/expressions/ControlExpressionsFunctionalTest.java @@ -30,48 +30,69 @@ class ControlExpressionsFunctionalTest extends AbstractExpressionsFunctionalTest { @Test - public void applyTest() { - Function decrement = (e) -> e.subtract(of(1)); + public void passToTest() { + Function intDecrement = (e) -> e.subtract(of(1)); + Function numDecrement = (e) -> e.subtract(of(1)); + // "nested functional" function application: assertExpression( 2 - 1, - decrement.apply(of(2)), + intDecrement.apply(of(2)), "{'$subtract': [2, 1]}"); - // "chained" function application: + // "chained" function application produces the same MQL: assertExpression( - 2 - 1, // = 0 - of(2).apply(decrement), + 2 - 1, + of(2).passIntegerTo(intDecrement), "{'$subtract': [2, 1]}"); - // the parameters are reversed, compared to Java's function.apply + + // variations + assertExpression( + 2 - 1, + of(2).passIntegerTo(numDecrement)); + assertExpression( + 2 - 1, + of(2).passNumberTo(numDecrement)); + + // all types + Function test = on -> of("A"); + assertExpression("A", of(true).passTo(test)); + assertExpression("A", of(false).passBooleanTo(test)); + assertExpression("A", of(0).passIntegerTo(test)); + assertExpression("A", of(0).passNumberTo(test)); + assertExpression("A", of("").passStringTo(test)); + assertExpression("A", of(Instant.ofEpochMilli(123)).passDateTo(test)); + assertExpression("A", ofIntegerArray(1, 2).passArrayTo(test)); + assertExpression("A", of(Document.parse("{_id: 'a'}")).passDocumentTo(test)); + assertExpression("A", ofMap(Document.parse("{_id: 'a'}")).passMapTo(test)); } @Test public void switchTest() { // https://www.mongodb.com/docs/manual/reference/operator/aggregation/switch/ - assertExpression("a", of(0).switchMap(on -> on.is(v -> v.eq(of(0)), v -> of("a")))); - assertExpression("a", of(0).switchMap(on -> on.isNumber(v -> of("a")))); - assertExpression("a", of(0).switchMap(on -> on.lte(of(9), v -> of("a")))); + assertExpression("a", of(0).switchOn(on -> on.is(v -> v.eq(of(0)), v -> of("a")))); + assertExpression("a", of(0).switchOn(on -> on.isNumber(v -> of("a")))); + assertExpression("a", of(0).switchOn(on -> on.lte(of(9), v -> of("a")))); // test branches Function isOver10 = v -> v.subtract(10).gt(of(0)); Function s = e -> e - .switchMap((Branches on) -> on + .switchIntegerOn((Branches on) -> on .eq(of(0), v -> of("A")) .lt(of(10), v -> of("B")) .is(isOver10, v -> of("C")) .defaults(v -> of("D"))) .toLower(); - assertExpression("a", of(0).apply(s)); - assertExpression("b", of(9).apply(s)); - assertExpression("b", of(-9).apply(s)); - assertExpression("c", of(11).apply(s)); - assertExpression("d", of(10).apply(s)); + assertExpression("a", of(0).passIntegerTo(s)); + assertExpression("b", of(9).passIntegerTo(s)); + assertExpression("b", of(-9).passIntegerTo(s)); + assertExpression("c", of(11).passIntegerTo(s)); + assertExpression("d", of(10).passIntegerTo(s)); } @Test public void switchTypesTest() { - Function label = expr -> expr.switchMap(on -> on + Function label = expr -> expr.switchOn(on -> on .isBoolean(v -> v.asString().concat(of(" - bool"))) .isNumber(v -> v.asString().concat(of(" - number"))) .isString(v -> v.asString().concat(of(" - string"))) @@ -81,124 +102,142 @@ public void switchTypesTest() { .isNull(v -> of("null - null")) .defaults(v -> of("default")) ).toLower(); - assertExpression("true - bool", of(true).apply(label)); - assertExpression("false - bool", of(false).apply(label)); - assertExpression("1 - number", of(1).apply(label)); - assertExpression("1 - number", of(1.0).apply(label)); - assertExpression("abc - string", of("abc").apply(label)); - assertExpression("1970-01-01t00:00:00.123z - date", of(Instant.ofEpochMilli(123)).apply(label)); - assertExpression("3 - array", ofIntegerArray(1, 2).apply(label)); - assertExpression("a - document", of(Document.parse("{_id: 'a'}")).apply(label)); - assertExpression("null - null", ofNull().apply(label)); + assertExpression("true - bool", of(true).passTo(label)); + assertExpression("false - bool", of(false).passBooleanTo(label)); + assertExpression("1 - number", of(1).passIntegerTo(label)); + assertExpression("1 - number", of(1.0).passNumberTo(label)); + assertExpression("abc - string", of("abc").passStringTo(label)); + assertExpression("1970-01-01t00:00:00.123z - date", of(Instant.ofEpochMilli(123)).passDateTo(label)); + assertExpression("3 - array", ofIntegerArray(1, 2).passArrayTo(label)); + assertExpression("a - document", of(Document.parse("{_id: 'a'}")).passDocumentTo(label)); + // maps are considered documents + assertExpression("a - document", ofMap(Document.parse("{_id: 'a'}")).passMapTo(label)); + assertExpression("null - null", ofNull().passTo(label)); + // maps via isMap: assertExpression( "ab - map", - ofMap(Document.parse("{a: 1, b: 2}")).switchMap(on -> on + ofMap(Document.parse("{a: 1, b: 2}")).switchOn(on -> on .isMap((MapExpression v) -> v.entrySet() .join(e -> e.getKey()).concat(of(" - map"))))); } + @Test + public void switchTestVariants() { + Function> test + = on -> on.is(v -> of(true), v -> of("A")); + assertExpression("A", of(true).switchOn(test)); + assertExpression("A", of(false).switchBooleanOn(test)); + assertExpression("A", of(0).switchIntegerOn(test)); + assertExpression("A", of(0).switchNumberOn(test)); + assertExpression("A", of("").switchStringOn(test)); + assertExpression("A", of(Instant.ofEpochMilli(123)).switchDateOn(test)); + assertExpression("A", ofIntegerArray(1, 2).switchArrayOn(test)); + assertExpression("A", of(Document.parse("{_id: 'a'}")).switchDocumentOn(test)); + assertExpression("A", ofMap(Document.parse("{_id: 'a'}")).switchMapOn(test)); + } + @Test public void switchTestInitial() { assertExpression("A", - of(0).switchMap(on -> on.is(v -> v.gt(of(-1)), v -> of("A"))), + of(0).switchOn(on -> on.is(v -> v.gt(of(-1)), v -> of("A"))), "{'$switch': {'branches': [{'case': {'$gt': [0, -1]}, 'then': 'A'}]}}"); // eq lt lte assertExpression("A", - of(0).switchMap(on -> on.eq(of(0), v -> of("A"))), + of(0).switchOn(on -> on.eq(of(0), v -> of("A"))), "{'$switch': {'branches': [{'case': {'$eq': [0, 0]}, 'then': 'A'}]}}"); assertExpression("A", - of(0).switchMap(on -> on.lt(of(1), v -> of("A"))), + of(0).switchOn(on -> on.lt(of(1), v -> of("A"))), "{'$switch': {'branches': [{'case': {'$lt': [0, 1]}, 'then': 'A'}]}}"); assertExpression("A", - of(0).switchMap(on -> on.lte(of(0), v -> of("A"))), + of(0).switchOn(on -> on.lte(of(0), v -> of("A"))), "{'$switch': {'branches': [{'case': {'$lte': [0, 0]}, 'then': 'A'}]}}"); // is type assertExpression("A", - of(true).switchMap(on -> on.isBoolean(v -> of("A"))), + of(true).switchOn(on -> on.isBoolean(v -> of("A"))), "{'$switch': {'branches': [{'case': {'$eq': [{'$type': [true]}, 'bool']}, 'then': 'A'}]}}"); assertExpression("A", - of(1).switchMap(on -> on.isNumber(v -> of("A"))), + of(1).switchOn(on -> on.isNumber(v -> of("A"))), "{'$switch': {'branches': [{'case': {'$isNumber': [1]}, 'then': 'A'}]}}"); assertExpression("A", - of("x").switchMap(on -> on.isString(v -> of("A"))), + of("x").switchOn(on -> on.isString(v -> of("A"))), "{'$switch': {'branches': [{'case': {'$eq': [{'$type': ['x']}, 'string']}, 'then': 'A'}]}}"); assertExpression("A", - of(Instant.ofEpochMilli(123)).switchMap(on -> on.isDate(v -> of("A"))), + of(Instant.ofEpochMilli(123)).switchOn(on -> on.isDate(v -> of("A"))), "{'$switch': {'branches': [{'case': {'$in': [{'$type': " - + "[{'$date': '1970-01-01T00:00:00.123Z'}]}, ['date', 'timestamp']]}, 'then': 'A'}]}}"); + + "[{'$date': '1970-01-01T00:00:00.123Z'}]}, ['date']]}, 'then': 'A'}]}}"); assertExpression("A", - ofIntegerArray(0).switchMap(on -> on.isArray(v -> of("A"))), + ofIntegerArray(0).switchOn(on -> on.isArray(v -> of("A"))), "{'$switch': {'branches': [{'case': {'$isArray': [[0]]}, 'then': 'A'}]}}"); assertExpression("A", - of(Document.parse("{}")).switchMap(on -> on.isDocument(v -> of("A"))), + of(Document.parse("{}")).switchOn(on -> on.isDocument(v -> of("A"))), "{'$switch': {'branches': [{'case': {'$eq': [{'$type': " + "[{'$literal': {}}]}, 'object']}, 'then': 'A'}]}}"); assertExpression("A", - ofMap(Document.parse("{}")).switchMap(on -> on.isMap(v -> of("A"))), + ofMap(Document.parse("{}")).switchOn(on -> on.isMap(v -> of("A"))), "{'$switch': {'branches': [{'case': {'$eq': [{'$type': " + "[{'$literal': {}}]}, 'object']}, 'then': 'A'}]}}"); assertExpression("A", - ofNull().switchMap(on -> on.isNull(v -> of("A"))), + ofNull().switchOn(on -> on.isNull(v -> of("A"))), "{'$switch': {'branches': [{'case': {'$eq': [null, null]}, 'then': 'A'}]}}"); } @Test public void switchTestPartial() { assertExpression("A", - of(0).switchMap(on -> on.isNull(v -> of("X")).is(v -> v.gt(of(-1)), v -> of("A"))), + of(0).switchOn(on -> on.isNull(v -> of("X")).is(v -> v.gt(of(-1)), v -> of("A"))), "{'$switch': {'branches': [{'case': {'$eq': [0, null]}, 'then': 'X'}, " + "{'case': {'$gt': [0, -1]}, 'then': 'A'}]}}"); assertExpression("A", - of(0).switchMap(on -> on.isNull(v -> of("X")).defaults(v -> of("A"))), + of(0).switchOn(on -> on.isNull(v -> of("X")).defaults(v -> of("A"))), "{'$switch': {'branches': [{'case': {'$eq': [0, null]}, 'then': 'X'}], " + "'default': 'A'}}"); // eq lt lte assertExpression("A", - of(0).switchMap(on -> on.isNull(v -> of("X")).eq(of(0), v -> of("A"))), + of(0).switchOn(on -> on.isNull(v -> of("X")).eq(of(0), v -> of("A"))), "{'$switch': {'branches': [{'case': {'$eq': [0, null]}, 'then': 'X'}, " + "{'case': {'$eq': [0, 0]}, 'then': 'A'}]}}"); assertExpression("A", - of(0).switchMap(on -> on.isNull(v -> of("X")).lt(of(1), v -> of("A"))), + of(0).switchOn(on -> on.isNull(v -> of("X")).lt(of(1), v -> of("A"))), "{'$switch': {'branches': [{'case': {'$eq': [0, null]}, 'then': 'X'}, " + "{'case': {'$lt': [0, 1]}, 'then': 'A'}]}}"); assertExpression("A", - of(0).switchMap(on -> on.isNull(v -> of("X")).lte(of(0), v -> of("A"))), + of(0).switchOn(on -> on.isNull(v -> of("X")).lte(of(0), v -> of("A"))), "{'$switch': {'branches': [{'case': {'$eq': [0, null]}, 'then': 'X'}, " + "{'case': {'$lte': [0, 0]}, 'then': 'A'}]}}"); // is type assertExpression("A", - of(true).switchMap(on -> on.isNull(v -> of("X")).isBoolean(v -> of("A"))), + of(true).switchOn(on -> on.isNull(v -> of("X")).isBoolean(v -> of("A"))), "{'$switch': {'branches': [{'case': {'$eq': [true, null]}, 'then': 'X'}, " + "{'case': {'$eq': [{'$type': [true]}, 'bool']}, 'then': 'A'}]}}"); assertExpression("A", - of(1).switchMap(on -> on.isNull(v -> of("X")).isNumber(v -> of("A"))), + of(1).switchOn(on -> on.isNull(v -> of("X")).isNumber(v -> of("A"))), "{'$switch': {'branches': [{'case': {'$eq': [1, null]}, 'then': 'X'}, " + "{'case': {'$isNumber': [1]}, 'then': 'A'}]}}"); assertExpression("A", - of("x").switchMap(on -> on.isNull(v -> of("X")).isString(v -> of("A"))), + of("x").switchOn(on -> on.isNull(v -> of("X")).isString(v -> of("A"))), "{'$switch': {'branches': [{'case': {'$eq': ['x', null]}, 'then': 'X'}, " + "{'case': {'$eq': [{'$type': ['x']}, 'string']}, 'then': 'A'}]}}"); assertExpression("A", - of(Instant.ofEpochMilli(123)).switchMap(on -> on.isNull(v -> of("X")).isDate(v -> of("A"))), + of(Instant.ofEpochMilli(123)).switchOn(on -> on.isNull(v -> of("X")).isDate(v -> of("A"))), "{'$switch': {'branches': [" + "{'case': {'$eq': [{'$date': '1970-01-01T00:00:00.123Z'}, null]}, 'then': 'X'}, " + "{'case': {'$in': [{'$type': [{'$date': '1970-01-01T00:00:00.123Z'}]}, " - + "['date', 'timestamp']]}, 'then': 'A'}]}}"); + + "['date']]}, 'then': 'A'}]}}"); assertExpression("A", - ofIntegerArray(0).switchMap(on -> on.isNull(v -> of("X")).isArray(v -> of("A"))), + ofIntegerArray(0).switchOn(on -> on.isNull(v -> of("X")).isArray(v -> of("A"))), "{'$switch': {'branches': [{'case': {'$eq': [[0], null]}, 'then': 'X'}, " + "{'case': {'$isArray': [[0]]}, 'then': 'A'}]}}"); assertExpression("A", - of(Document.parse("{}")).switchMap(on -> on.isNull(v -> of("X")).isDocument(v -> of("A"))), + of(Document.parse("{}")).switchOn(on -> on.isNull(v -> of("X")).isDocument(v -> of("A"))), "{'$switch': {'branches': [{'case': {'$eq': [{'$literal': {}}, null]}, 'then': 'X'}, " + "{'case': {'$eq': [{'$type': [{'$literal': {}}]}, 'object']}, 'then': 'A'}]}}"); assertExpression("A", - ofMap(Document.parse("{}")).switchMap(on -> on.isNull(v -> of("X")).isMap(v -> of("A"))), + ofMap(Document.parse("{}")).switchOn(on -> on.isNull(v -> of("X")).isMap(v -> of("A"))), " {'$switch': {'branches': [" + "{'case': {'$eq': [{'$literal': {}}, null]}, 'then': 'X'}, " + "{'case': {'$eq': [{'$type': [{'$literal': {}}]}, 'object']}, 'then': 'A'}]}}"); assertExpression("A", - ofNull().switchMap(on -> on.isNumber(v -> of("X")).isNull(v -> of("A"))), + ofNull().switchOn(on -> on.isNumber(v -> of("X")).isNull(v -> of("A"))), "{'$switch': {'branches': [{'case': {'$isNumber': [null]}, 'then': 'X'}, " + "{'case': {'$eq': [null, null]}, 'then': 'A'}]}}"); } diff --git a/driver-core/src/test/functional/com/mongodb/client/model/expressions/TypeExpressionsFunctionalTest.java b/driver-core/src/test/functional/com/mongodb/client/model/expressions/TypeExpressionsFunctionalTest.java index adb4a82e9ce..d0927c3c099 100644 --- a/driver-core/src/test/functional/com/mongodb/client/model/expressions/TypeExpressionsFunctionalTest.java +++ b/driver-core/src/test/functional/com/mongodb/client/model/expressions/TypeExpressionsFunctionalTest.java @@ -46,7 +46,7 @@ public void isBooleanOrTest() { assertExpression( true, of(true).isBooleanOr(of(false)), - "{'$cond': [{'$eq': [{'$type': true}, 'bool']}, true, false]}"); + "{'$cond': [{'$eq': [{'$type': [true]}, 'bool']}, true, false]}"); // non-boolean: assertExpression(false, ofIntegerArray(1).isBooleanOr(of(false))); assertExpression(false, ofNull().isBooleanOr(of(false))); @@ -70,7 +70,7 @@ public void isStringOrTest() { assertExpression( "abc", of("abc").isStringOr(of("or")), - "{'$cond': [{'$eq': [{'$type': 'abc'}, 'string']}, 'abc', 'or']}"); + "{'$cond': [{'$eq': [{'$type': ['abc']}, 'string']}, 'abc', 'or']}"); // non-string: assertExpression("or", ofIntegerArray(1).isStringOr(of("or"))); assertExpression("or", ofNull().isStringOr(of("or"))); @@ -82,7 +82,7 @@ public void isDateOrTest() { assertExpression( date, of(date).isDateOr(of(date.plusMillis(10))), - "{'$cond': [{'$in': [{'$type': {'$date': '2007-12-03T10:15:30.005Z'}}, ['date']]}, " + "{'$cond': [{'$in': [{'$type': [{'$date': '2007-12-03T10:15:30.005Z'}]}, ['date']]}, " + "{'$date': '2007-12-03T10:15:30.005Z'}, {'$date': '2007-12-03T10:15:30.015Z'}]}"); // non-date: assertExpression(date, ofIntegerArray(1).isDateOr(of(date))); @@ -107,7 +107,7 @@ public void isDocumentOrTest() { assertExpression( doc, of(doc).isDocumentOr(of(BsonDocument.parse("{b: 2}"))), - "{'$cond': [{'$eq': [{'$type': {'$literal': {'a': 1}}}, 'object']}, " + "{'$cond': [{'$eq': [{'$type': [{'$literal': {'a': 1}}]}, 'object']}, " + "{'$literal': {'a': 1}}, {'$literal': {'b': 2}}]}"); // non-document: assertExpression(doc, ofIntegerArray(1).isDocumentOr(of(doc))); From 5c094dc30c56648350185651c5836039e3566de7 Mon Sep 17 00:00:00 2001 From: Maxim Katcharov Date: Fri, 13 Jan 2023 13:36:15 -0700 Subject: [PATCH 03/15] Fixes --- .../model/expressions/ArrayExpression.java | 4 +- .../model/expressions/BooleanExpression.java | 4 +- .../client/model/expressions/Branches.java | 35 ++++++------ .../expressions/BranchesIntermediary.java | 27 ++++----- .../model/expressions/DateExpression.java | 4 +- .../model/expressions/DocumentExpression.java | 4 +- .../client/model/expressions/Expression.java | 4 +- .../model/expressions/IntegerExpression.java | 4 +- .../model/expressions/MapExpression.java | 4 +- .../model/expressions/MqlExpression.java | 56 +++++++++---------- .../model/expressions/NumberExpression.java | 4 +- .../model/expressions/StringExpression.java | 4 +- .../ControlExpressionsFunctionalTest.java | 15 +++-- 13 files changed, 90 insertions(+), 79 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 b6be283286d..dc3feefe46d 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 @@ -113,7 +113,7 @@ default ArrayExpression slice(final int start, final int length) { ArrayExpression distinct(); - R passArrayTo(Function, R> f); + R passArrayTo(Function, ? extends R> f); - R switchArrayOn(Function, R>> on); + R switchArrayOn(Function, ? extends R>> on); } diff --git a/driver-core/src/main/com/mongodb/client/model/expressions/BooleanExpression.java b/driver-core/src/main/com/mongodb/client/model/expressions/BooleanExpression.java index 7f745a1142c..411d16208cf 100644 --- a/driver-core/src/main/com/mongodb/client/model/expressions/BooleanExpression.java +++ b/driver-core/src/main/com/mongodb/client/model/expressions/BooleanExpression.java @@ -61,7 +61,7 @@ public interface BooleanExpression extends Expression { */ T cond(T left, T right); - R passBooleanTo(Function f); + R passBooleanTo(Function f); - R switchBooleanOn(Function> on); + R switchBooleanOn(Function> on); } diff --git a/driver-core/src/main/com/mongodb/client/model/expressions/Branches.java b/driver-core/src/main/com/mongodb/client/model/expressions/Branches.java index 3ab56e8b6fa..ea41859e79d 100644 --- a/driver-core/src/main/com/mongodb/client/model/expressions/Branches.java +++ b/driver-core/src/main/com/mongodb/client/model/expressions/Branches.java @@ -22,11 +22,12 @@ public final class Branches { - Branches() { - // package-private + static final Branches EMPTY = new Branches(); + + private Branches() { } - private BranchesIntermediary with(final Function> switchCase) { + private static BranchesIntermediary with(final Function> switchCase) { List>> v = new ArrayList<>(); v.add(switchCase); return new BranchesIntermediary<>(v); @@ -39,54 +40,56 @@ private static MqlExpression mqlEx(final T value) { // is fn public BranchesIntermediary is(final Function o, final Function r) { - return this.with(value -> new SwitchCase<>(o.apply(value), r.apply(value))); + return with(value -> new SwitchCase<>(o.apply(value), r.apply(value))); } // eq lt lte public BranchesIntermediary eq(final T v, final Function r) { - return this.with(value -> new SwitchCase<>(value.eq(v), r.apply(value))); + return is(v::eq, r); } public BranchesIntermediary lt(final T v, final Function r) { - return this.with(value -> new SwitchCase<>(value.lt(v), r.apply(value))); + return is(v::lt, r); } public BranchesIntermediary lte(final T v, final Function r) { - return this.with(value -> new SwitchCase<>(value.lte(v), r.apply(value))); + return is(v::lte, r); } // is type public BranchesIntermediary isBoolean(final Function r) { - return this.with(value -> new SwitchCase<>(mqlEx(value).isBoolean(), r.apply((BooleanExpression) value))); + return is(v -> mqlEx(v).isBoolean(), v -> r.apply((BooleanExpression) v)); } public BranchesIntermediary isNumber(final Function r) { - return this.with(value -> new SwitchCase<>(mqlEx(value).isNumber(), r.apply((NumberExpression) value))); + return is(v -> mqlEx(v).isNumber(), v -> r.apply((NumberExpression) v)); } public BranchesIntermediary isString(final Function r) { - return this.with(value -> new SwitchCase<>(mqlEx(value).isString(), r.apply((StringExpression) value))); + return is(v -> mqlEx(v).isString(), v -> r.apply((StringExpression) v)); } public BranchesIntermediary isDate(final Function r) { - return this.with(value -> new SwitchCase<>(mqlEx(value).isDate(), r.apply((DateExpression) value))); + return is(v -> mqlEx(v).isDate(), v -> r.apply((DateExpression) v)); } + @SuppressWarnings("unchecked") public BranchesIntermediary isArray(final Function, R> r) { - return this.with(value -> new SwitchCase<>(mqlEx(value).isArray(), r.apply((ArrayExpression) value))); + return is(v -> mqlEx(v).isArray(), v -> r.apply((ArrayExpression) v)); } public BranchesIntermediary isDocument(final Function r) { - return this.with(value -> new SwitchCase<>(mqlEx(value).isDocument(), r.apply((DocumentExpression) value))); + return is(v -> mqlEx(v).isDocument(), v -> r.apply((DocumentExpression) v)); } + @SuppressWarnings("unchecked") public BranchesIntermediary isMap(final Function, R> r) { - return this.with(value -> new SwitchCase<>(mqlEx(value).isDocument(), r.apply((MapExpression) value))); + return is(v -> mqlEx(v).isMap(), v -> r.apply((MapExpression) v)); } - public BranchesIntermediary isNull(final Function isNull) { - return this.with(value -> new SwitchCase<>(mqlEx(value).isNull(), isNull.apply(value))); + public BranchesIntermediary isNull(final Function r) { + return is(v -> mqlEx(v).isNull(), v -> r.apply(v)); } } diff --git a/driver-core/src/main/com/mongodb/client/model/expressions/BranchesIntermediary.java b/driver-core/src/main/com/mongodb/client/model/expressions/BranchesIntermediary.java index 48e8843df73..7bb7409030d 100644 --- a/driver-core/src/main/com/mongodb/client/model/expressions/BranchesIntermediary.java +++ b/driver-core/src/main/com/mongodb/client/model/expressions/BranchesIntermediary.java @@ -44,53 +44,54 @@ public BranchesIntermediary is(final Function o, fin // eq lt lte public BranchesIntermediary eq(final T v, final Function r) { - return this.with(value -> new SwitchCase<>(value.eq(v), r.apply(value))); + return is(v::eq, r); } public BranchesIntermediary lt(final T v, final Function r) { - return this.with(value -> new SwitchCase<>(value.lt(v), r.apply(value))); + return is(v::lt, r); } public BranchesIntermediary lte(final T v, final Function r) { - return this.with(value -> new SwitchCase<>(value.lte(v), r.apply(value))); + return is(v::lte, r); } // is type public BranchesIntermediary isBoolean(final Function r) { - return this.with(v -> new SwitchCase<>(mqlEx(v).isBoolean(), r.apply((BooleanExpression) v))); + return is(v -> mqlEx(v).isBoolean(), v -> r.apply((BooleanExpression) v)); } public BranchesIntermediary isNumber(final Function r) { - return this.with(v -> new SwitchCase<>(mqlEx(v).isNumber(), r.apply((NumberExpression) v))); + return is(v -> mqlEx(v).isNumber(), v -> r.apply((NumberExpression) v)); } - public BranchesIntermediary isString(final Function r) { - return this.with(value -> new SwitchCase<>(mqlEx(value).isString(), r.apply((StringExpression) value))); + return is(v -> mqlEx(v).isString(), v -> r.apply((StringExpression) v)); } public BranchesIntermediary isDate(final Function r) { - return this.with(value -> new SwitchCase<>(mqlEx(value).isDate(), r.apply((DateExpression) value))); + return is(v -> mqlEx(v).isDate(), v -> r.apply((DateExpression) v)); } + @SuppressWarnings("unchecked") public BranchesIntermediary isArray(final Function, R> r) { - return this.with(value -> new SwitchCase<>(mqlEx(value).isArray(), r.apply((ArrayExpression) value))); + return is(v -> mqlEx(v).isArray(), v -> r.apply((ArrayExpression) v)); } public BranchesIntermediary isDocument(final Function r) { - return this.with(value -> new SwitchCase<>(mqlEx(value).isDocument(), r.apply((DocumentExpression) value))); + return is(v -> mqlEx(v).isDocument(), v -> r.apply((DocumentExpression) v)); } + @SuppressWarnings("unchecked") public BranchesIntermediary isMap(final Function, R> r) { - return this.with(value -> new SwitchCase<>(mqlEx(value).isDocument(), r.apply((MapExpression) value))); + return is(v -> mqlEx(v).isMap(), v -> r.apply((MapExpression) v)); } public BranchesIntermediary isNull(final Function r) { - return this.with(value -> new SwitchCase<>(mqlEx(value).isNull(), r.apply(value))); + return is(v -> mqlEx(v).isNull(), v -> r.apply(v)); } - public BranchesTerminal defaults(final Function r) { + public BranchesTerminal defaults(final Function r) { return this.withDefault(value -> r.apply(value)); } diff --git a/driver-core/src/main/com/mongodb/client/model/expressions/DateExpression.java b/driver-core/src/main/com/mongodb/client/model/expressions/DateExpression.java index 5fb34124ecc..4a1cea56174 100644 --- a/driver-core/src/main/com/mongodb/client/model/expressions/DateExpression.java +++ b/driver-core/src/main/com/mongodb/client/model/expressions/DateExpression.java @@ -35,6 +35,6 @@ public interface DateExpression extends Expression { StringExpression asString(StringExpression timezone, StringExpression format); - R passDateTo(Function f); - R switchDateOn(Function> on); + R passDateTo(Function f); + R switchDateOn(Function> on); } diff --git a/driver-core/src/main/com/mongodb/client/model/expressions/DocumentExpression.java b/driver-core/src/main/com/mongodb/client/model/expressions/DocumentExpression.java index 770371297bd..939df99cfca 100644 --- a/driver-core/src/main/com/mongodb/client/model/expressions/DocumentExpression.java +++ b/driver-core/src/main/com/mongodb/client/model/expressions/DocumentExpression.java @@ -102,6 +102,6 @@ default MapExpression getMap(final String fieldName, f MapExpression asMap(); - R passDocumentTo(Function f); - R switchDocumentOn(Function> on); + R passDocumentTo(Function f); + R switchDocumentOn(Function> on); } diff --git a/driver-core/src/main/com/mongodb/client/model/expressions/Expression.java b/driver-core/src/main/com/mongodb/client/model/expressions/Expression.java index 5187ca68909..f3548b938b1 100644 --- a/driver-core/src/main/com/mongodb/client/model/expressions/Expression.java +++ b/driver-core/src/main/com/mongodb/client/model/expressions/Expression.java @@ -117,8 +117,8 @@ public interface Expression { StringExpression asString(); - R passTo(Function f); + R passTo(Function f); - R switchOn(Function> on); + R switchOn(Function> on); } diff --git a/driver-core/src/main/com/mongodb/client/model/expressions/IntegerExpression.java b/driver-core/src/main/com/mongodb/client/model/expressions/IntegerExpression.java index b673c44e5b0..5c9c74f4f29 100644 --- a/driver-core/src/main/com/mongodb/client/model/expressions/IntegerExpression.java +++ b/driver-core/src/main/com/mongodb/client/model/expressions/IntegerExpression.java @@ -45,6 +45,6 @@ default IntegerExpression subtract(final int subtract) { IntegerExpression abs(); - R passIntegerTo(Function f); - R switchIntegerOn(Function> on); + R passIntegerTo(Function f); + R switchIntegerOn(Function> on); } diff --git a/driver-core/src/main/com/mongodb/client/model/expressions/MapExpression.java b/driver-core/src/main/com/mongodb/client/model/expressions/MapExpression.java index f25afefdc4d..517a41319c8 100644 --- a/driver-core/src/main/com/mongodb/client/model/expressions/MapExpression.java +++ b/driver-core/src/main/com/mongodb/client/model/expressions/MapExpression.java @@ -60,6 +60,6 @@ default MapExpression unset(final String key) { R asDocument(); - R passMapTo(Function, R> f); - R switchMapOn(Function, R>> on); + R passMapTo(Function, ? extends R> f); + R switchMapOn(Function, ? extends R>> on); } 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 f4962c1a7c3..636a8e6a17f 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 @@ -284,93 +284,93 @@ public DocumentExpression unsetField(final String fieldName) { /** @see Expression */ @Override - public R passTo(final Function f) { + public R passTo(final Function f) { return f.apply(this.assertImplementsAllExpressions()); } @Override - public R switchOn(final Function> switchMap) { - return switchMapInternal(this.assertImplementsAllExpressions(), switchMap.apply(new Branches())); + public R switchOn(final Function> switchMap) { + return switchMapInternal(this.assertImplementsAllExpressions(), switchMap.apply(Branches.EMPTY)); } @Override - public R passBooleanTo(final Function f) { + public R passBooleanTo(final Function f) { return f.apply(this.assertImplementsAllExpressions()); } @Override - public R switchBooleanOn(final Function> switchMap) { - return switchMapInternal(this.assertImplementsAllExpressions(), switchMap.apply(new Branches())); + public R switchBooleanOn(final Function> switchMap) { + return switchMapInternal(this.assertImplementsAllExpressions(), switchMap.apply(Branches.EMPTY)); } @Override - public R passIntegerTo(final Function f) { + public R passIntegerTo(final Function f) { return f.apply(this.assertImplementsAllExpressions()); } @Override - public R switchIntegerOn(final Function> switchMap) { - return switchMapInternal(this.assertImplementsAllExpressions(), switchMap.apply(new Branches())); + public R switchIntegerOn(final Function> switchMap) { + return switchMapInternal(this.assertImplementsAllExpressions(), switchMap.apply(Branches.EMPTY)); } @Override - public R passNumberTo(final Function f) { + public R passNumberTo(final Function f) { return f.apply(this.assertImplementsAllExpressions()); } @Override - public R switchNumberOn(final Function> switchMap) { - return switchMapInternal(this.assertImplementsAllExpressions(), switchMap.apply(new Branches())); + public R switchNumberOn(final Function> switchMap) { + return switchMapInternal(this.assertImplementsAllExpressions(), switchMap.apply(Branches.EMPTY)); } @Override - public R passStringTo(final Function f) { + public R passStringTo(final Function f) { return f.apply(this.assertImplementsAllExpressions()); } @Override - public R switchStringOn(final Function> switchMap) { - return switchMapInternal(this.assertImplementsAllExpressions(), switchMap.apply(new Branches())); + public R switchStringOn(final Function> switchMap) { + return switchMapInternal(this.assertImplementsAllExpressions(), switchMap.apply(Branches.EMPTY)); } @Override - public R passDateTo(final Function f) { + public R passDateTo(final Function f) { return f.apply(this.assertImplementsAllExpressions()); } @Override - public R switchDateOn(final Function> switchMap) { - return switchMapInternal(this.assertImplementsAllExpressions(), switchMap.apply(new Branches())); + public R switchDateOn(final Function> switchMap) { + return switchMapInternal(this.assertImplementsAllExpressions(), switchMap.apply(Branches.EMPTY)); } @Override - public R passArrayTo(final Function, R> f) { + public R passArrayTo(final Function, ? extends R> f) { return f.apply(this.assertImplementsAllExpressions()); } @Override - public R switchArrayOn(final Function, R>> switchMap) { - return switchMapInternal(this.assertImplementsAllExpressions(), switchMap.apply(new Branches())); + public R switchArrayOn(final Function, ? extends R>> switchMap) { + return switchMapInternal(this.assertImplementsAllExpressions(), switchMap.apply(Branches.EMPTY)); } @Override - public R passMapTo(final Function, R> f) { + public R passMapTo(final Function, ? extends R> f) { return f.apply(this.assertImplementsAllExpressions()); } @Override - public R switchMapOn(final Function, R>> switchMap) { - return switchMapInternal(this.assertImplementsAllExpressions(), switchMap.apply(new Branches())); + public R switchMapOn(final Function, ? extends R>> switchMap) { + return switchMapInternal(this.assertImplementsAllExpressions(), switchMap.apply(Branches.EMPTY)); } @Override - public R passDocumentTo(final Function f) { + public R passDocumentTo(final Function f) { return f.apply(this.assertImplementsAllExpressions()); } @Override - public R switchDocumentOn(final Function> switchMap) { - return switchMapInternal(this.assertImplementsAllExpressions(), switchMap.apply(new Branches())); + public R switchDocumentOn(final Function> switchMap) { + return switchMapInternal(this.assertImplementsAllExpressions(), switchMap.apply(Branches.EMPTY)); } private R0 switchMapInternal( @@ -504,7 +504,7 @@ public MapExpression isMapOr(final MapExpression R passNumberTo(Function f); - R switchNumberOn(Function> on); + R passNumberTo(Function f); + R switchNumberOn(Function> on); } diff --git a/driver-core/src/main/com/mongodb/client/model/expressions/StringExpression.java b/driver-core/src/main/com/mongodb/client/model/expressions/StringExpression.java index 8799ab1f3e2..80ef49ddbfa 100644 --- a/driver-core/src/main/com/mongodb/client/model/expressions/StringExpression.java +++ b/driver-core/src/main/com/mongodb/client/model/expressions/StringExpression.java @@ -55,6 +55,6 @@ default StringExpression substrBytes(final int start, final int length) { DateExpression parseDate(StringExpression timezone, StringExpression format); - R passStringTo(Function f); - R switchStringOn(Function> on); + R passStringTo(Function f); + R switchStringOn(Function> on); } diff --git a/driver-core/src/test/functional/com/mongodb/client/model/expressions/ControlExpressionsFunctionalTest.java b/driver-core/src/test/functional/com/mongodb/client/model/expressions/ControlExpressionsFunctionalTest.java index a6e8a0c3885..9a5f6c3e264 100644 --- a/driver-core/src/test/functional/com/mongodb/client/model/expressions/ControlExpressionsFunctionalTest.java +++ b/driver-core/src/test/functional/com/mongodb/client/model/expressions/ControlExpressionsFunctionalTest.java @@ -23,6 +23,7 @@ import java.util.function.Function; 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.ofIntegerArray; import static com.mongodb.client.model.expressions.Expressions.ofMap; import static com.mongodb.client.model.expressions.Expressions.ofNull; @@ -76,7 +77,7 @@ public void switchTest() { // test branches Function isOver10 = v -> v.subtract(10).gt(of(0)); Function s = e -> e - .switchIntegerOn((Branches on) -> on + .switchIntegerOn(on -> on .eq(of(0), v -> of("A")) .lt(of(10), v -> of("B")) .is(isOver10, v -> of("C")) @@ -115,10 +116,16 @@ public void switchTypesTest() { assertExpression("null - null", ofNull().passTo(label)); // maps via isMap: assertExpression( - "ab - map", - ofMap(Document.parse("{a: 1, b: 2}")).switchOn(on -> on + "12 - map", + ofMap(Document.parse("{a: '1', b: '2'}")).switchOn(on -> on .isMap((MapExpression v) -> v.entrySet() - .join(e -> e.getKey()).concat(of(" - map"))))); + .join(e -> e.getValue()).concat(of(" - map"))))); + // arrays via isArray, and tests signature: + assertExpression( + "ab - array", + ofArray(of("a"), of("b")).switchOn(on -> on + .isArray((ArrayExpression v) -> v + .join(e -> e).concat(of(" - array"))))); } @Test From b8749c43721ae9806ccff823c4488310547788a9 Mon Sep 17 00:00:00 2001 From: Maxim Katcharov Date: Fri, 13 Jan 2023 14:57:23 -0700 Subject: [PATCH 04/15] Signature fixes --- .../client/model/expressions/Branches.java | 24 +++++++++---------- .../expressions/BranchesIntermediary.java | 24 +++++++++---------- 2 files changed, 24 insertions(+), 24 deletions(-) diff --git a/driver-core/src/main/com/mongodb/client/model/expressions/Branches.java b/driver-core/src/main/com/mongodb/client/model/expressions/Branches.java index ea41859e79d..fd052418cc4 100644 --- a/driver-core/src/main/com/mongodb/client/model/expressions/Branches.java +++ b/driver-core/src/main/com/mongodb/client/model/expressions/Branches.java @@ -39,57 +39,57 @@ private static MqlExpression mqlEx(final T value) { // is fn - public BranchesIntermediary is(final Function o, final Function r) { + public BranchesIntermediary is(final Function o, final Function r) { return with(value -> new SwitchCase<>(o.apply(value), r.apply(value))); } // eq lt lte - public BranchesIntermediary eq(final T v, final Function r) { + public BranchesIntermediary eq(final T v, final Function r) { return is(v::eq, r); } - public BranchesIntermediary lt(final T v, final Function r) { + public BranchesIntermediary lt(final T v, final Function r) { return is(v::lt, r); } - public BranchesIntermediary lte(final T v, final Function r) { + public BranchesIntermediary lte(final T v, final Function r) { return is(v::lte, r); } // is type - public BranchesIntermediary isBoolean(final Function r) { + public BranchesIntermediary isBoolean(final Function r) { return is(v -> mqlEx(v).isBoolean(), v -> r.apply((BooleanExpression) v)); } - public BranchesIntermediary isNumber(final Function r) { + public BranchesIntermediary isNumber(final Function r) { return is(v -> mqlEx(v).isNumber(), v -> r.apply((NumberExpression) v)); } - public BranchesIntermediary isString(final Function r) { + public BranchesIntermediary isString(final Function r) { return is(v -> mqlEx(v).isString(), v -> r.apply((StringExpression) v)); } - public BranchesIntermediary isDate(final Function r) { + public BranchesIntermediary isDate(final Function r) { return is(v -> mqlEx(v).isDate(), v -> r.apply((DateExpression) v)); } @SuppressWarnings("unchecked") - public BranchesIntermediary isArray(final Function, R> r) { + public BranchesIntermediary isArray(final Function, ? extends R> r) { return is(v -> mqlEx(v).isArray(), v -> r.apply((ArrayExpression) v)); } - public BranchesIntermediary isDocument(final Function r) { + public BranchesIntermediary isDocument(final Function r) { return is(v -> mqlEx(v).isDocument(), v -> r.apply((DocumentExpression) v)); } @SuppressWarnings("unchecked") - public BranchesIntermediary isMap(final Function, R> r) { + public BranchesIntermediary isMap(final Function, ? extends R> r) { return is(v -> mqlEx(v).isMap(), v -> r.apply((MapExpression) v)); } - public BranchesIntermediary isNull(final Function r) { + public BranchesIntermediary isNull(final Function r) { return is(v -> mqlEx(v).isNull(), v -> r.apply(v)); } } diff --git a/driver-core/src/main/com/mongodb/client/model/expressions/BranchesIntermediary.java b/driver-core/src/main/com/mongodb/client/model/expressions/BranchesIntermediary.java index 7bb7409030d..83de384767f 100644 --- a/driver-core/src/main/com/mongodb/client/model/expressions/BranchesIntermediary.java +++ b/driver-core/src/main/com/mongodb/client/model/expressions/BranchesIntermediary.java @@ -37,57 +37,57 @@ private static MqlExpression mqlEx(final T value) { // is fn - public BranchesIntermediary is(final Function o, final Function r) { + public BranchesIntermediary is(final Function o, final Function r) { return this.with(value -> new SwitchCase<>(o.apply(value), r.apply(value))); } // eq lt lte - public BranchesIntermediary eq(final T v, final Function r) { + public BranchesIntermediary eq(final T v, final Function r) { return is(v::eq, r); } - public BranchesIntermediary lt(final T v, final Function r) { + public BranchesIntermediary lt(final T v, final Function r) { return is(v::lt, r); } - public BranchesIntermediary lte(final T v, final Function r) { + public BranchesIntermediary lte(final T v, final Function r) { return is(v::lte, r); } // is type - public BranchesIntermediary isBoolean(final Function r) { + public BranchesIntermediary isBoolean(final Function r) { return is(v -> mqlEx(v).isBoolean(), v -> r.apply((BooleanExpression) v)); } - public BranchesIntermediary isNumber(final Function r) { + public BranchesIntermediary isNumber(final Function r) { return is(v -> mqlEx(v).isNumber(), v -> r.apply((NumberExpression) v)); } - public BranchesIntermediary isString(final Function r) { + public BranchesIntermediary isString(final Function r) { return is(v -> mqlEx(v).isString(), v -> r.apply((StringExpression) v)); } - public BranchesIntermediary isDate(final Function r) { + public BranchesIntermediary isDate(final Function r) { return is(v -> mqlEx(v).isDate(), v -> r.apply((DateExpression) v)); } @SuppressWarnings("unchecked") - public BranchesIntermediary isArray(final Function, R> r) { + public BranchesIntermediary isArray(final Function, ? extends R> r) { return is(v -> mqlEx(v).isArray(), v -> r.apply((ArrayExpression) v)); } - public BranchesIntermediary isDocument(final Function r) { + public BranchesIntermediary isDocument(final Function r) { return is(v -> mqlEx(v).isDocument(), v -> r.apply((DocumentExpression) v)); } @SuppressWarnings("unchecked") - public BranchesIntermediary isMap(final Function, R> r) { + public BranchesIntermediary isMap(final Function, ? extends R> r) { return is(v -> mqlEx(v).isMap(), v -> r.apply((MapExpression) v)); } - public BranchesIntermediary isNull(final Function r) { + public BranchesIntermediary isNull(final Function r) { return is(v -> mqlEx(v).isNull(), v -> r.apply(v)); } From 820abdd0c4729ec80bd10c4d18d5517eef75b61f Mon Sep 17 00:00:00 2001 From: Maxim Katcharov Date: Fri, 13 Jan 2023 15:43:15 -0700 Subject: [PATCH 05/15] Fixes --- .../main/com/mongodb/client/model/expressions/Branches.java | 6 +++--- .../client/model/expressions/BranchesIntermediary.java | 6 +++--- .../model/expressions/ControlExpressionsFunctionalTest.java | 5 +++-- 3 files changed, 9 insertions(+), 8 deletions(-) diff --git a/driver-core/src/main/com/mongodb/client/model/expressions/Branches.java b/driver-core/src/main/com/mongodb/client/model/expressions/Branches.java index fd052418cc4..a600c444d51 100644 --- a/driver-core/src/main/com/mongodb/client/model/expressions/Branches.java +++ b/driver-core/src/main/com/mongodb/client/model/expressions/Branches.java @@ -46,15 +46,15 @@ public BranchesIntermediary i // eq lt lte public BranchesIntermediary eq(final T v, final Function r) { - return is(v::eq, r); + return is(value -> value.eq(v), r); } public BranchesIntermediary lt(final T v, final Function r) { - return is(v::lt, r); + return is(value -> value.lt(v), r); } public BranchesIntermediary lte(final T v, final Function r) { - return is(v::lte, r); + return is(value -> value.lte(v), r); } // is type diff --git a/driver-core/src/main/com/mongodb/client/model/expressions/BranchesIntermediary.java b/driver-core/src/main/com/mongodb/client/model/expressions/BranchesIntermediary.java index 83de384767f..4a1edb21346 100644 --- a/driver-core/src/main/com/mongodb/client/model/expressions/BranchesIntermediary.java +++ b/driver-core/src/main/com/mongodb/client/model/expressions/BranchesIntermediary.java @@ -44,15 +44,15 @@ public BranchesIntermediary is(final Function o, fin // eq lt lte public BranchesIntermediary eq(final T v, final Function r) { - return is(v::eq, r); + return is(value -> value.eq(v), r); } public BranchesIntermediary lt(final T v, final Function r) { - return is(v::lt, r); + return is(value -> value.lt(v), r); } public BranchesIntermediary lte(final T v, final Function r) { - return is(v::lte, r); + return is(value -> value.lte(v), r); } // is type diff --git a/driver-core/src/test/functional/com/mongodb/client/model/expressions/ControlExpressionsFunctionalTest.java b/driver-core/src/test/functional/com/mongodb/client/model/expressions/ControlExpressionsFunctionalTest.java index 9a5f6c3e264..f416dfb79fa 100644 --- a/driver-core/src/test/functional/com/mongodb/client/model/expressions/ControlExpressionsFunctionalTest.java +++ b/driver-core/src/test/functional/com/mongodb/client/model/expressions/ControlExpressionsFunctionalTest.java @@ -72,6 +72,7 @@ public void switchTest() { // https://www.mongodb.com/docs/manual/reference/operator/aggregation/switch/ assertExpression("a", of(0).switchOn(on -> on.is(v -> v.eq(of(0)), v -> of("a")))); assertExpression("a", of(0).switchOn(on -> on.isNumber(v -> of("a")))); + assertExpression("a", of(0).switchOn(on -> on.eq(of(0), v -> of("a")))); assertExpression("a", of(0).switchOn(on -> on.lte(of(9), v -> of("a")))); // test branches @@ -182,7 +183,7 @@ public void switchTestInitial() { assertExpression("A", ofMap(Document.parse("{}")).switchOn(on -> on.isMap(v -> of("A"))), "{'$switch': {'branches': [{'case': {'$eq': [{'$type': " - + "[{'$literal': {}}]}, 'object']}, 'then': 'A'}]}}"); + + "{'$literal': {}}}, 'object']}, 'then': 'A'}]}}"); assertExpression("A", ofNull().switchOn(on -> on.isNull(v -> of("A"))), "{'$switch': {'branches': [{'case': {'$eq': [null, null]}, 'then': 'A'}]}}"); @@ -242,7 +243,7 @@ public void switchTestPartial() { ofMap(Document.parse("{}")).switchOn(on -> on.isNull(v -> of("X")).isMap(v -> of("A"))), " {'$switch': {'branches': [" + "{'case': {'$eq': [{'$literal': {}}, null]}, 'then': 'X'}, " - + "{'case': {'$eq': [{'$type': [{'$literal': {}}]}, 'object']}, 'then': 'A'}]}}"); + + "{'case': {'$eq': [{'$type': {'$literal': {}}}, 'object']}, 'then': 'A'}]}}"); assertExpression("A", ofNull().switchOn(on -> on.isNumber(v -> of("X")).isNull(v -> of("A"))), "{'$switch': {'branches': [{'case': {'$isNumber': [null]}, 'then': 'X'}, " From 44822516cd0f9f20bba61a8acd459ea4142ff371 Mon Sep 17 00:00:00 2001 From: Maxim Katcharov Date: Mon, 16 Jan 2023 12:57:35 -0700 Subject: [PATCH 06/15] Fixes, add isInteger --- .../client/model/expressions/Branches.java | 4 ++++ .../expressions/BranchesIntermediary.java | 4 ++++ .../model/expressions/MqlExpression.java | 5 +++-- .../ArrayExpressionsFunctionalTest.java | 4 ++-- .../ControlExpressionsFunctionalTest.java | 17 ++++++++++++--- .../TypeExpressionsFunctionalTest.java | 21 +++++++++++++++++++ 6 files changed, 48 insertions(+), 7 deletions(-) diff --git a/driver-core/src/main/com/mongodb/client/model/expressions/Branches.java b/driver-core/src/main/com/mongodb/client/model/expressions/Branches.java index a600c444d51..bb93a9d0012 100644 --- a/driver-core/src/main/com/mongodb/client/model/expressions/Branches.java +++ b/driver-core/src/main/com/mongodb/client/model/expressions/Branches.java @@ -67,6 +67,10 @@ public BranchesIntermediary i return is(v -> mqlEx(v).isNumber(), v -> r.apply((NumberExpression) v)); } + public BranchesIntermediary isInteger(final Function r) { + return is(v -> mqlEx(v).isInteger(), v -> r.apply((IntegerExpression) v)); + } + public BranchesIntermediary isString(final Function r) { return is(v -> mqlEx(v).isString(), v -> r.apply((StringExpression) v)); } diff --git a/driver-core/src/main/com/mongodb/client/model/expressions/BranchesIntermediary.java b/driver-core/src/main/com/mongodb/client/model/expressions/BranchesIntermediary.java index 4a1edb21346..cae2970a847 100644 --- a/driver-core/src/main/com/mongodb/client/model/expressions/BranchesIntermediary.java +++ b/driver-core/src/main/com/mongodb/client/model/expressions/BranchesIntermediary.java @@ -65,6 +65,10 @@ public BranchesIntermediary isNumber(final Function mqlEx(v).isNumber(), v -> r.apply((NumberExpression) v)); } + public BranchesIntermediary isInteger(final Function r) { + return is(v -> mqlEx(v).isInteger(), v -> r.apply((IntegerExpression) v)); + } + public BranchesIntermediary isString(final Function r) { return is(v -> mqlEx(v).isString(), v -> r.apply((StringExpression) v)); } 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 636a8e6a17f..87b1a080cd1 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 @@ -440,12 +440,13 @@ public NumberExpression isNumberOr(final NumberExpression other) { } public BooleanExpression isInteger() { - return this.isNumber().cond(this.eq(this.round()), of(false)); + return this.isNumber().and(this.eq(this.round())); } @Override public IntegerExpression isIntegerOr(final IntegerExpression other) { - return this.isInteger().cond(this, other); + return this.isNumber().and(this.eq(this.round())) + .cond(this, other); } public BooleanExpression isString() { 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 b622688b49f..a34acb8acdb 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 @@ -321,8 +321,8 @@ public void elementAtTest() { // 0.0 is a valid integer value array123.elementAt(of(0.0).isIntegerOr(of(-1))), // MQL: - "{'$arrayElemAt': [[1, 2, 3], {'$cond': [{'$cond': " - + "[{'$isNumber': [0.0]}, {'$eq': [0.0, {'$round': 0.0}]}, false]}, 0.0, -1]}]}"); + "{'$arrayElemAt': [[1, 2, 3], {'$cond': [{'$and': " + + "[{'$isNumber': [0.0]}, {'$eq': [0.0, {'$round': 0.0}]}]}, 0.0, -1]}]}"); // negatives assertExpression( Arrays.asList(1, 2, 3).get(3 - 1), diff --git a/driver-core/src/test/functional/com/mongodb/client/model/expressions/ControlExpressionsFunctionalTest.java b/driver-core/src/test/functional/com/mongodb/client/model/expressions/ControlExpressionsFunctionalTest.java index f416dfb79fa..ff44a64c8ff 100644 --- a/driver-core/src/test/functional/com/mongodb/client/model/expressions/ControlExpressionsFunctionalTest.java +++ b/driver-core/src/test/functional/com/mongodb/client/model/expressions/ControlExpressionsFunctionalTest.java @@ -16,6 +16,7 @@ package com.mongodb.client.model.expressions; +import org.bson.BsonDocument; import org.bson.Document; import org.junit.jupiter.api.Test; @@ -96,18 +97,20 @@ public void switchTest() { public void switchTypesTest() { Function label = expr -> expr.switchOn(on -> on .isBoolean(v -> v.asString().concat(of(" - bool"))) - .isNumber(v -> v.asString().concat(of(" - number"))) .isString(v -> v.asString().concat(of(" - string"))) .isDate(v -> v.asString().concat(of(" - date"))) .isArray((ArrayExpression v) -> v.sum(a -> a).asString().concat(of(" - array"))) .isDocument(v -> v.getString("_id").concat(of(" - document"))) .isNull(v -> of("null - null")) + .isInteger(v -> v.asString().concat(of(" - integer"))) + .isNumber(v -> v.asString().concat(of(" - number"))) .defaults(v -> of("default")) ).toLower(); assertExpression("true - bool", of(true).passTo(label)); assertExpression("false - bool", of(false).passBooleanTo(label)); - assertExpression("1 - number", of(1).passIntegerTo(label)); - assertExpression("1 - number", of(1.0).passNumberTo(label)); + assertExpression("1 - integer", of(1).passIntegerTo(label)); + assertExpression("1 - integer", of(1.0).passNumberTo(label)); + assertExpression("1.01 - number", of(1.01).passNumberTo(label)); assertExpression("abc - string", of("abc").passStringTo(label)); assertExpression("1970-01-01t00:00:00.123z - date", of(Instant.ofEpochMilli(123)).passDateTo(label)); assertExpression("3 - array", ofIntegerArray(1, 2).passArrayTo(label)); @@ -166,6 +169,10 @@ public void switchTestInitial() { assertExpression("A", of(1).switchOn(on -> on.isNumber(v -> of("A"))), "{'$switch': {'branches': [{'case': {'$isNumber': [1]}, 'then': 'A'}]}}"); + assertExpression("A", + of(1).switchOn(on -> on.isInteger(v -> of("A"))), + "{'$switch': {'branches': [{'case': {'$and': [{'$isNumber': [1]}, " + + "{'$eq': [1, {'$round': 1}]}]}, 'then': 'A'}]}}"); assertExpression("A", of("x").switchOn(on -> on.isString(v -> of("A"))), "{'$switch': {'branches': [{'case': {'$eq': [{'$type': ['x']}, 'string']}, 'then': 'A'}]}}"); @@ -221,6 +228,10 @@ public void switchTestPartial() { of(1).switchOn(on -> on.isNull(v -> of("X")).isNumber(v -> of("A"))), "{'$switch': {'branches': [{'case': {'$eq': [1, null]}, 'then': 'X'}, " + "{'case': {'$isNumber': [1]}, 'then': 'A'}]}}"); + assertExpression("A", + of(1).switchOn(on -> on.isNull(v -> of("X")).isInteger(v -> of("A"))), + "{'$switch': {'branches': [{'case': {'$eq': [1, null]}, 'then': 'X'}, {'case': " + + "{'$and': [{'$isNumber': [1]}, {'$eq': [1, {'$round': 1}]}]}, 'then': 'A'}]}}"); assertExpression("A", of("x").switchOn(on -> on.isNull(v -> of("X")).isString(v -> of("A"))), "{'$switch': {'branches': [{'case': {'$eq': ['x', null]}, 'then': 'X'}, " diff --git a/driver-core/src/test/functional/com/mongodb/client/model/expressions/TypeExpressionsFunctionalTest.java b/driver-core/src/test/functional/com/mongodb/client/model/expressions/TypeExpressionsFunctionalTest.java index d0927c3c099..bb08ae4487d 100644 --- a/driver-core/src/test/functional/com/mongodb/client/model/expressions/TypeExpressionsFunctionalTest.java +++ b/driver-core/src/test/functional/com/mongodb/client/model/expressions/TypeExpressionsFunctionalTest.java @@ -65,6 +65,27 @@ public void isNumberOrTest() { assertExpression(99, ofNull().isNumberOr(of(99))); } + @Test + public void isIntegerOr() { + assertExpression( + 1, + of(1).isIntegerOr(of(99)), + "{'$cond': [{'$and': [{'$isNumber': [1]}, {'$eq': [1, {'$round': 1}]}]}, 1, 99]}"); + // other numeric values: + assertExpression(1L, of(1L).isIntegerOr(of(99))); + assertExpression(1.0, of(1.0).isIntegerOr(of(99))); + assertExpression(Decimal128.parse("1"), of(Decimal128.parse("1")).isIntegerOr(of(99))); + // non-numeric: + assertExpression(99, ofIntegerArray(1).isIntegerOr(of(99))); + assertExpression(99, ofNull().isIntegerOr(of(99))); + + assertExpression(99, + of(BsonDocument.parse("{'a': 'str'}")).getField("a").isIntegerOr(of(99))); + // the following leads to "$round only supports numeric types, not string" + // because the literal type is known. + // assertExpression(99, of("str").isIntegerOr(of(99))); + } + @Test public void isStringOrTest() { assertExpression( From 0306b4589b3be37b84bf4039a1a343357d020764 Mon Sep 17 00:00:00 2001 From: Maxim Katcharov Date: Mon, 16 Jan 2023 15:24:17 -0700 Subject: [PATCH 07/15] Parameterize Branches using initiating method --- .../model/expressions/ArrayExpression.java | 2 +- .../model/expressions/BooleanExpression.java | 2 +- .../client/model/expressions/Branches.java | 32 ++++++++-------- .../model/expressions/DateExpression.java | 2 +- .../model/expressions/DocumentExpression.java | 2 +- .../client/model/expressions/Expression.java | 2 +- .../model/expressions/IntegerExpression.java | 2 +- .../model/expressions/MapExpression.java | 2 +- .../model/expressions/MqlExpression.java | 36 +++++++++--------- .../model/expressions/NumberExpression.java | 2 +- .../model/expressions/StringExpression.java | 2 +- .../ControlExpressionsFunctionalTest.java | 38 +++++++++++++------ 12 files changed, 68 insertions(+), 56 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 dc3feefe46d..9d4f2b5e044 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 @@ -115,5 +115,5 @@ default ArrayExpression slice(final int start, final int length) { R passArrayTo(Function, ? extends R> f); - R switchArrayOn(Function, ? extends R>> on); + R switchArrayOn(Function>, ? extends BranchesTerminal, ? extends R>> on); } diff --git a/driver-core/src/main/com/mongodb/client/model/expressions/BooleanExpression.java b/driver-core/src/main/com/mongodb/client/model/expressions/BooleanExpression.java index 411d16208cf..0ebd1e8ea02 100644 --- a/driver-core/src/main/com/mongodb/client/model/expressions/BooleanExpression.java +++ b/driver-core/src/main/com/mongodb/client/model/expressions/BooleanExpression.java @@ -63,5 +63,5 @@ public interface BooleanExpression extends Expression { R passBooleanTo(Function f); - R switchBooleanOn(Function> on); + R switchBooleanOn(Function, ? extends BranchesTerminal> on); } diff --git a/driver-core/src/main/com/mongodb/client/model/expressions/Branches.java b/driver-core/src/main/com/mongodb/client/model/expressions/Branches.java index bb93a9d0012..3b410def7eb 100644 --- a/driver-core/src/main/com/mongodb/client/model/expressions/Branches.java +++ b/driver-core/src/main/com/mongodb/client/model/expressions/Branches.java @@ -20,11 +20,9 @@ import java.util.List; import java.util.function.Function; -public final class Branches { - - static final Branches EMPTY = new Branches(); - - private Branches() { +public final class Branches { + + Branches() { } private static BranchesIntermediary with(final Function> switchCase) { @@ -45,55 +43,55 @@ public BranchesIntermediary i // eq lt lte - public BranchesIntermediary eq(final T v, final Function r) { + public BranchesIntermediary eq(final T v, final Function r) { return is(value -> value.eq(v), r); } - public BranchesIntermediary lt(final T v, final Function r) { + public BranchesIntermediary lt(final T v, final Function r) { return is(value -> value.lt(v), r); } - public BranchesIntermediary lte(final T v, final Function r) { + public BranchesIntermediary lte(final T v, final Function r) { return is(value -> value.lte(v), r); } // is type - public BranchesIntermediary isBoolean(final Function r) { + public BranchesIntermediary isBoolean(final Function r) { return is(v -> mqlEx(v).isBoolean(), v -> r.apply((BooleanExpression) v)); } - public BranchesIntermediary isNumber(final Function r) { + public BranchesIntermediary isNumber(final Function r) { return is(v -> mqlEx(v).isNumber(), v -> r.apply((NumberExpression) v)); } - public BranchesIntermediary isInteger(final Function r) { + public BranchesIntermediary isInteger(final Function r) { return is(v -> mqlEx(v).isInteger(), v -> r.apply((IntegerExpression) v)); } - public BranchesIntermediary isString(final Function r) { + public BranchesIntermediary isString(final Function r) { return is(v -> mqlEx(v).isString(), v -> r.apply((StringExpression) v)); } - public BranchesIntermediary isDate(final Function r) { + public BranchesIntermediary isDate(final Function r) { return is(v -> mqlEx(v).isDate(), v -> r.apply((DateExpression) v)); } @SuppressWarnings("unchecked") - public BranchesIntermediary isArray(final Function, ? extends R> r) { + public BranchesIntermediary isArray(final Function, ? extends R> r) { return is(v -> mqlEx(v).isArray(), v -> r.apply((ArrayExpression) v)); } - public BranchesIntermediary isDocument(final Function r) { + public BranchesIntermediary isDocument(final Function r) { return is(v -> mqlEx(v).isDocument(), v -> r.apply((DocumentExpression) v)); } @SuppressWarnings("unchecked") - public BranchesIntermediary isMap(final Function, ? extends R> r) { + public BranchesIntermediary isMap(final Function, ? extends R> r) { return is(v -> mqlEx(v).isMap(), v -> r.apply((MapExpression) v)); } - public BranchesIntermediary isNull(final Function r) { + public BranchesIntermediary isNull(final Function r) { return is(v -> mqlEx(v).isNull(), v -> r.apply(v)); } } diff --git a/driver-core/src/main/com/mongodb/client/model/expressions/DateExpression.java b/driver-core/src/main/com/mongodb/client/model/expressions/DateExpression.java index 4a1cea56174..13edec175c9 100644 --- a/driver-core/src/main/com/mongodb/client/model/expressions/DateExpression.java +++ b/driver-core/src/main/com/mongodb/client/model/expressions/DateExpression.java @@ -36,5 +36,5 @@ public interface DateExpression extends Expression { StringExpression asString(StringExpression timezone, StringExpression format); R passDateTo(Function f); - R switchDateOn(Function> on); + R switchDateOn(Function, ? extends BranchesTerminal> on); } diff --git a/driver-core/src/main/com/mongodb/client/model/expressions/DocumentExpression.java b/driver-core/src/main/com/mongodb/client/model/expressions/DocumentExpression.java index 939df99cfca..27b295e86eb 100644 --- a/driver-core/src/main/com/mongodb/client/model/expressions/DocumentExpression.java +++ b/driver-core/src/main/com/mongodb/client/model/expressions/DocumentExpression.java @@ -103,5 +103,5 @@ default MapExpression getMap(final String fieldName, f MapExpression asMap(); R passDocumentTo(Function f); - R switchDocumentOn(Function> on); + R switchDocumentOn(Function, ? extends BranchesTerminal> on); } diff --git a/driver-core/src/main/com/mongodb/client/model/expressions/Expression.java b/driver-core/src/main/com/mongodb/client/model/expressions/Expression.java index f3548b938b1..a803134cc4f 100644 --- a/driver-core/src/main/com/mongodb/client/model/expressions/Expression.java +++ b/driver-core/src/main/com/mongodb/client/model/expressions/Expression.java @@ -119,6 +119,6 @@ public interface Expression { R passTo(Function f); - R switchOn(Function> on); + R switchOn(Function, ? extends BranchesTerminal> on); } diff --git a/driver-core/src/main/com/mongodb/client/model/expressions/IntegerExpression.java b/driver-core/src/main/com/mongodb/client/model/expressions/IntegerExpression.java index 5c9c74f4f29..5f6fa5cc607 100644 --- a/driver-core/src/main/com/mongodb/client/model/expressions/IntegerExpression.java +++ b/driver-core/src/main/com/mongodb/client/model/expressions/IntegerExpression.java @@ -46,5 +46,5 @@ default IntegerExpression subtract(final int subtract) { IntegerExpression abs(); R passIntegerTo(Function f); - R switchIntegerOn(Function> on); + R switchIntegerOn(Function, ? extends BranchesTerminal> on); } diff --git a/driver-core/src/main/com/mongodb/client/model/expressions/MapExpression.java b/driver-core/src/main/com/mongodb/client/model/expressions/MapExpression.java index 517a41319c8..ed53f6aaf81 100644 --- a/driver-core/src/main/com/mongodb/client/model/expressions/MapExpression.java +++ b/driver-core/src/main/com/mongodb/client/model/expressions/MapExpression.java @@ -61,5 +61,5 @@ default MapExpression unset(final String key) { R asDocument(); R passMapTo(Function, ? extends R> f); - R switchMapOn(Function, ? extends R>> on); + R switchMapOn(Function>, ? extends BranchesTerminal, ? extends R>> on); } 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 87b1a080cd1..cdc2af3c8ee 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 @@ -289,8 +289,8 @@ public R passTo(final Function R switchOn(final Function> switchMap) { - return switchMapInternal(this.assertImplementsAllExpressions(), switchMap.apply(Branches.EMPTY)); + public R switchOn(final Function, ? extends BranchesTerminal> switchMap) { + return switchMapInternal(this.assertImplementsAllExpressions(), switchMap.apply(new Branches<>())); } @Override @@ -299,8 +299,8 @@ public R passBooleanTo(final Function R switchBooleanOn(final Function> switchMap) { - return switchMapInternal(this.assertImplementsAllExpressions(), switchMap.apply(Branches.EMPTY)); + public R switchBooleanOn(final Function, ? extends BranchesTerminal> switchMap) { + return switchMapInternal(this.assertImplementsAllExpressions(), switchMap.apply(new Branches<>())); } @Override @@ -309,8 +309,8 @@ public R passIntegerTo(final Function R switchIntegerOn(final Function> switchMap) { - return switchMapInternal(this.assertImplementsAllExpressions(), switchMap.apply(Branches.EMPTY)); + public R switchIntegerOn(final Function, ? extends BranchesTerminal> switchMap) { + return switchMapInternal(this.assertImplementsAllExpressions(), switchMap.apply(new Branches<>())); } @Override @@ -319,8 +319,8 @@ public R passNumberTo(final Function R switchNumberOn(final Function> switchMap) { - return switchMapInternal(this.assertImplementsAllExpressions(), switchMap.apply(Branches.EMPTY)); + public R switchNumberOn(final Function, ? extends BranchesTerminal> switchMap) { + return switchMapInternal(this.assertImplementsAllExpressions(), switchMap.apply(new Branches<>())); } @Override @@ -329,8 +329,8 @@ public R passStringTo(final Function R switchStringOn(final Function> switchMap) { - return switchMapInternal(this.assertImplementsAllExpressions(), switchMap.apply(Branches.EMPTY)); + public R switchStringOn(final Function, ? extends BranchesTerminal> switchMap) { + return switchMapInternal(this.assertImplementsAllExpressions(), switchMap.apply(new Branches<>())); } @Override @@ -339,8 +339,8 @@ public R passDateTo(final Function R switchDateOn(final Function> switchMap) { - return switchMapInternal(this.assertImplementsAllExpressions(), switchMap.apply(Branches.EMPTY)); + public R switchDateOn(final Function, ? extends BranchesTerminal> switchMap) { + return switchMapInternal(this.assertImplementsAllExpressions(), switchMap.apply(new Branches<>())); } @Override @@ -349,8 +349,8 @@ public R passArrayTo(final Function R switchArrayOn(final Function, ? extends R>> switchMap) { - return switchMapInternal(this.assertImplementsAllExpressions(), switchMap.apply(Branches.EMPTY)); + public R switchArrayOn(final Function>, ? extends BranchesTerminal, ? extends R>> switchMap) { + return switchMapInternal(this.assertImplementsAllExpressions(), switchMap.apply(new Branches<>())); } @Override @@ -359,8 +359,8 @@ public R passMapTo(final Function R switchMapOn(final Function, ? extends R>> switchMap) { - return switchMapInternal(this.assertImplementsAllExpressions(), switchMap.apply(Branches.EMPTY)); + public R switchMapOn(final Function>, ? extends BranchesTerminal, ? extends R>> switchMap) { + return switchMapInternal(this.assertImplementsAllExpressions(), switchMap.apply(new Branches<>())); } @Override @@ -369,8 +369,8 @@ public R passDocumentTo(final Function R switchDocumentOn(final Function> switchMap) { - return switchMapInternal(this.assertImplementsAllExpressions(), switchMap.apply(Branches.EMPTY)); + public R switchDocumentOn(final Function, ? extends BranchesTerminal> switchMap) { + return switchMapInternal(this.assertImplementsAllExpressions(), switchMap.apply(new Branches<>())); } private R0 switchMapInternal( diff --git a/driver-core/src/main/com/mongodb/client/model/expressions/NumberExpression.java b/driver-core/src/main/com/mongodb/client/model/expressions/NumberExpression.java index 218f6b2d1cd..3502aa01916 100644 --- a/driver-core/src/main/com/mongodb/client/model/expressions/NumberExpression.java +++ b/driver-core/src/main/com/mongodb/client/model/expressions/NumberExpression.java @@ -60,5 +60,5 @@ default NumberExpression subtract(final Number subtract) { DateExpression millisecondsToDate(); R passNumberTo(Function f); - R switchNumberOn(Function> on); + R switchNumberOn(Function, ? extends BranchesTerminal> on); } diff --git a/driver-core/src/main/com/mongodb/client/model/expressions/StringExpression.java b/driver-core/src/main/com/mongodb/client/model/expressions/StringExpression.java index 80ef49ddbfa..d3ab537a424 100644 --- a/driver-core/src/main/com/mongodb/client/model/expressions/StringExpression.java +++ b/driver-core/src/main/com/mongodb/client/model/expressions/StringExpression.java @@ -56,5 +56,5 @@ default StringExpression substrBytes(final int start, final int length) { DateExpression parseDate(StringExpression timezone, StringExpression format); R passStringTo(Function f); - R switchStringOn(Function> on); + R switchStringOn(Function, ? extends BranchesTerminal> on); } diff --git a/driver-core/src/test/functional/com/mongodb/client/model/expressions/ControlExpressionsFunctionalTest.java b/driver-core/src/test/functional/com/mongodb/client/model/expressions/ControlExpressionsFunctionalTest.java index ff44a64c8ff..8d8e9d3b3c0 100644 --- a/driver-core/src/test/functional/com/mongodb/client/model/expressions/ControlExpressionsFunctionalTest.java +++ b/driver-core/src/test/functional/com/mongodb/client/model/expressions/ControlExpressionsFunctionalTest.java @@ -16,7 +16,6 @@ package com.mongodb.client.model.expressions; -import org.bson.BsonDocument; import org.bson.Document; import org.junit.jupiter.api.Test; @@ -93,6 +92,19 @@ public void switchTest() { assertExpression("d", of(10).passIntegerTo(s)); } + @Test + public void switchInferenceTest() { + // the following must compile: + assertExpression( + "b", + of(1).switchOn(on -> on + .eq(of(0), v -> of("a")) + .eq(of(1), v -> of("b")) + )); + // the "of(0)" must not cause a type inference of T being an integer, + // since switchOn expects an Expression. + } + @Test public void switchTypesTest() { Function label = expr -> expr.switchOn(on -> on @@ -132,19 +144,21 @@ public void switchTypesTest() { .join(e -> e).concat(of(" - array"))))); } + private BranchesIntermediary branches(Branches on) { + return on.is(v -> of(true), v -> of("A")); + } + @Test public void switchTestVariants() { - Function> test - = on -> on.is(v -> of(true), v -> of("A")); - assertExpression("A", of(true).switchOn(test)); - assertExpression("A", of(false).switchBooleanOn(test)); - assertExpression("A", of(0).switchIntegerOn(test)); - assertExpression("A", of(0).switchNumberOn(test)); - assertExpression("A", of("").switchStringOn(test)); - assertExpression("A", of(Instant.ofEpochMilli(123)).switchDateOn(test)); - assertExpression("A", ofIntegerArray(1, 2).switchArrayOn(test)); - assertExpression("A", of(Document.parse("{_id: 'a'}")).switchDocumentOn(test)); - assertExpression("A", ofMap(Document.parse("{_id: 'a'}")).switchMapOn(test)); + assertExpression("A", of(true).switchOn(this::branches)); + assertExpression("A", of(false).switchBooleanOn(this::branches)); + assertExpression("A", of(0).switchIntegerOn(this::branches)); + assertExpression("A", of(0).switchNumberOn(this::branches)); + assertExpression("A", of("").switchStringOn(this::branches)); + assertExpression("A", of(Instant.ofEpochMilli(123)).switchDateOn(this::branches)); + assertExpression("A", ofIntegerArray(1, 2).switchArrayOn(this::branches)); + assertExpression("A", of(Document.parse("{_id: 'a'}")).switchDocumentOn(this::branches)); + assertExpression("A", ofMap(Document.parse("{_id: 'a'}")).switchMapOn(this::branches)); } @Test From 3d79be37e23b2ce277bdf3b85a2b394a19074efb Mon Sep 17 00:00:00 2001 From: Maxim Katcharov Date: Mon, 16 Jan 2023 15:42:58 -0700 Subject: [PATCH 08/15] Fix --- .../mongodb/client/model/expressions/BranchesIntermediary.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/driver-core/src/main/com/mongodb/client/model/expressions/BranchesIntermediary.java b/driver-core/src/main/com/mongodb/client/model/expressions/BranchesIntermediary.java index cae2970a847..bc5984de0ca 100644 --- a/driver-core/src/main/com/mongodb/client/model/expressions/BranchesIntermediary.java +++ b/driver-core/src/main/com/mongodb/client/model/expressions/BranchesIntermediary.java @@ -95,7 +95,7 @@ public BranchesIntermediary isNull(final Function return is(v -> mqlEx(v).isNull(), v -> r.apply(v)); } - public BranchesTerminal defaults(final Function r) { + public BranchesTerminal defaults(final Function r) { return this.withDefault(value -> r.apply(value)); } From f814af107e0f947cfc45c0d07f58528ff58e8b60 Mon Sep 17 00:00:00 2001 From: Maxim Katcharov Date: Tue, 17 Jan 2023 12:21:14 -0700 Subject: [PATCH 09/15] Use switch --- .../client/model/expressions/MqlExpression.java | 15 +++++++++++++-- .../ArrayExpressionsFunctionalTest.java | 5 +++-- .../TypeExpressionsFunctionalTest.java | 11 ++++------- 3 files changed, 20 insertions(+), 11 deletions(-) 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 cdc2af3c8ee..85e070fb64a 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 @@ -445,8 +445,19 @@ public BooleanExpression isInteger() { @Override public IntegerExpression isIntegerOr(final IntegerExpression other) { - return this.isNumber().and(this.eq(this.round())) - .cond(this, other); + /* + The server does not evaluate both branches of and/or/cond unless needed. + However, the server has a pipeline optimization stage prior to + evaluation that does attempt to optimize both branches, and fails with + "Failed to optimize pipeline" when there is a problem arising from the + use of literals and typed expressions. Using "switch" avoids this, + otherwise we could just use: + this.isNumber().and(this.eq(this.round())) + */ + + return this.switchOn(on -> on + .isNumber(v -> (IntegerExpression) v.round().eq(v).cond(v, other)) + .defaults(v -> other)); } public BooleanExpression isString() { 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 a34acb8acdb..a72fbcd29fc 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 @@ -321,8 +321,9 @@ public void elementAtTest() { // 0.0 is a valid integer value array123.elementAt(of(0.0).isIntegerOr(of(-1))), // MQL: - "{'$arrayElemAt': [[1, 2, 3], {'$cond': [{'$and': " - + "[{'$isNumber': [0.0]}, {'$eq': [0.0, {'$round': 0.0}]}]}, 0.0, -1]}]}"); + "{'$arrayElemAt': [[1, 2, 3], {'$switch': {'branches': [{'case': " + + "{'$isNumber': [0.0]}, 'then': {'$cond': " + + "[{'$eq': [{'$round': 0.0}, 0.0]}, 0.0, -1]}}], 'default': -1}}]} "); // negatives assertExpression( Arrays.asList(1, 2, 3).get(3 - 1), diff --git a/driver-core/src/test/functional/com/mongodb/client/model/expressions/TypeExpressionsFunctionalTest.java b/driver-core/src/test/functional/com/mongodb/client/model/expressions/TypeExpressionsFunctionalTest.java index bb08ae4487d..db600647ab5 100644 --- a/driver-core/src/test/functional/com/mongodb/client/model/expressions/TypeExpressionsFunctionalTest.java +++ b/driver-core/src/test/functional/com/mongodb/client/model/expressions/TypeExpressionsFunctionalTest.java @@ -70,7 +70,9 @@ public void isIntegerOr() { assertExpression( 1, of(1).isIntegerOr(of(99)), - "{'$cond': [{'$and': [{'$isNumber': [1]}, {'$eq': [1, {'$round': 1}]}]}, 1, 99]}"); + "{'$switch': {'branches': [{'case': {'$isNumber': [1]}, 'then': " + + "{'$cond': [{'$eq': [{'$round': 1}, 1]}, 1, 99]}}], 'default': 99}}" + ); // other numeric values: assertExpression(1L, of(1L).isIntegerOr(of(99))); assertExpression(1.0, of(1.0).isIntegerOr(of(99))); @@ -78,12 +80,7 @@ public void isIntegerOr() { // non-numeric: assertExpression(99, ofIntegerArray(1).isIntegerOr(of(99))); assertExpression(99, ofNull().isIntegerOr(of(99))); - - assertExpression(99, - of(BsonDocument.parse("{'a': 'str'}")).getField("a").isIntegerOr(of(99))); - // the following leads to "$round only supports numeric types, not string" - // because the literal type is known. - // assertExpression(99, of("str").isIntegerOr(of(99))); + assertExpression(99, of("str").isIntegerOr(of(99))); } @Test From bb6a3bfb406958f2c554f6efe6770f5e14d2cec7 Mon Sep 17 00:00:00 2001 From: Maxim Katcharov Date: Tue, 17 Jan 2023 12:27:38 -0700 Subject: [PATCH 10/15] Remove ? super --- .../model/expressions/ArrayExpression.java | 2 +- .../model/expressions/BooleanExpression.java | 2 +- .../client/model/expressions/DateExpression.java | 2 +- .../model/expressions/DocumentExpression.java | 2 +- .../model/expressions/IntegerExpression.java | 2 +- .../client/model/expressions/MapExpression.java | 2 +- .../client/model/expressions/MqlExpression.java | 16 ++++++++-------- .../model/expressions/NumberExpression.java | 2 +- .../model/expressions/StringExpression.java | 2 +- 9 files changed, 16 insertions(+), 16 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 9d4f2b5e044..7b499f7ada0 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 @@ -115,5 +115,5 @@ default ArrayExpression slice(final int start, final int length) { R passArrayTo(Function, ? extends R> f); - R switchArrayOn(Function>, ? extends BranchesTerminal, ? extends R>> on); + R switchArrayOn(Function>, ? extends BranchesTerminal, ? extends R>> on); } diff --git a/driver-core/src/main/com/mongodb/client/model/expressions/BooleanExpression.java b/driver-core/src/main/com/mongodb/client/model/expressions/BooleanExpression.java index 0ebd1e8ea02..7f0b43370dc 100644 --- a/driver-core/src/main/com/mongodb/client/model/expressions/BooleanExpression.java +++ b/driver-core/src/main/com/mongodb/client/model/expressions/BooleanExpression.java @@ -63,5 +63,5 @@ public interface BooleanExpression extends Expression { R passBooleanTo(Function f); - R switchBooleanOn(Function, ? extends BranchesTerminal> on); + R switchBooleanOn(Function, ? extends BranchesTerminal> on); } diff --git a/driver-core/src/main/com/mongodb/client/model/expressions/DateExpression.java b/driver-core/src/main/com/mongodb/client/model/expressions/DateExpression.java index 13edec175c9..cd211d1fd85 100644 --- a/driver-core/src/main/com/mongodb/client/model/expressions/DateExpression.java +++ b/driver-core/src/main/com/mongodb/client/model/expressions/DateExpression.java @@ -36,5 +36,5 @@ public interface DateExpression extends Expression { StringExpression asString(StringExpression timezone, StringExpression format); R passDateTo(Function f); - R switchDateOn(Function, ? extends BranchesTerminal> on); + R switchDateOn(Function, ? extends BranchesTerminal> on); } diff --git a/driver-core/src/main/com/mongodb/client/model/expressions/DocumentExpression.java b/driver-core/src/main/com/mongodb/client/model/expressions/DocumentExpression.java index 27b295e86eb..4d7d2ef678f 100644 --- a/driver-core/src/main/com/mongodb/client/model/expressions/DocumentExpression.java +++ b/driver-core/src/main/com/mongodb/client/model/expressions/DocumentExpression.java @@ -103,5 +103,5 @@ default MapExpression getMap(final String fieldName, f MapExpression asMap(); R passDocumentTo(Function f); - R switchDocumentOn(Function, ? extends BranchesTerminal> on); + R switchDocumentOn(Function, ? extends BranchesTerminal> on); } diff --git a/driver-core/src/main/com/mongodb/client/model/expressions/IntegerExpression.java b/driver-core/src/main/com/mongodb/client/model/expressions/IntegerExpression.java index 5f6fa5cc607..40cde216ce3 100644 --- a/driver-core/src/main/com/mongodb/client/model/expressions/IntegerExpression.java +++ b/driver-core/src/main/com/mongodb/client/model/expressions/IntegerExpression.java @@ -46,5 +46,5 @@ default IntegerExpression subtract(final int subtract) { IntegerExpression abs(); R passIntegerTo(Function f); - R switchIntegerOn(Function, ? extends BranchesTerminal> on); + R switchIntegerOn(Function, ? extends BranchesTerminal> on); } diff --git a/driver-core/src/main/com/mongodb/client/model/expressions/MapExpression.java b/driver-core/src/main/com/mongodb/client/model/expressions/MapExpression.java index ed53f6aaf81..d5d782c7728 100644 --- a/driver-core/src/main/com/mongodb/client/model/expressions/MapExpression.java +++ b/driver-core/src/main/com/mongodb/client/model/expressions/MapExpression.java @@ -61,5 +61,5 @@ default MapExpression unset(final String key) { R asDocument(); R passMapTo(Function, ? extends R> f); - R switchMapOn(Function>, ? extends BranchesTerminal, ? extends R>> on); + R switchMapOn(Function>, ? extends BranchesTerminal, ? extends R>> on); } 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 85e070fb64a..9be4eda2526 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 @@ -299,7 +299,7 @@ public R passBooleanTo(final Function R switchBooleanOn(final Function, ? extends BranchesTerminal> switchMap) { + public R switchBooleanOn(final Function, ? extends BranchesTerminal> switchMap) { return switchMapInternal(this.assertImplementsAllExpressions(), switchMap.apply(new Branches<>())); } @@ -309,7 +309,7 @@ public R passIntegerTo(final Function R switchIntegerOn(final Function, ? extends BranchesTerminal> switchMap) { + public R switchIntegerOn(final Function, ? extends BranchesTerminal> switchMap) { return switchMapInternal(this.assertImplementsAllExpressions(), switchMap.apply(new Branches<>())); } @@ -319,7 +319,7 @@ public R passNumberTo(final Function R switchNumberOn(final Function, ? extends BranchesTerminal> switchMap) { + public R switchNumberOn(final Function, ? extends BranchesTerminal> switchMap) { return switchMapInternal(this.assertImplementsAllExpressions(), switchMap.apply(new Branches<>())); } @@ -329,7 +329,7 @@ public R passStringTo(final Function R switchStringOn(final Function, ? extends BranchesTerminal> switchMap) { + public R switchStringOn(final Function, ? extends BranchesTerminal> switchMap) { return switchMapInternal(this.assertImplementsAllExpressions(), switchMap.apply(new Branches<>())); } @@ -339,7 +339,7 @@ public R passDateTo(final Function R switchDateOn(final Function, ? extends BranchesTerminal> switchMap) { + public R switchDateOn(final Function, ? extends BranchesTerminal> switchMap) { return switchMapInternal(this.assertImplementsAllExpressions(), switchMap.apply(new Branches<>())); } @@ -349,7 +349,7 @@ public R passArrayTo(final Function R switchArrayOn(final Function>, ? extends BranchesTerminal, ? extends R>> switchMap) { + public R switchArrayOn(final Function>, ? extends BranchesTerminal, ? extends R>> switchMap) { return switchMapInternal(this.assertImplementsAllExpressions(), switchMap.apply(new Branches<>())); } @@ -359,7 +359,7 @@ public R passMapTo(final Function R switchMapOn(final Function>, ? extends BranchesTerminal, ? extends R>> switchMap) { + public R switchMapOn(final Function>, ? extends BranchesTerminal, ? extends R>> switchMap) { return switchMapInternal(this.assertImplementsAllExpressions(), switchMap.apply(new Branches<>())); } @@ -369,7 +369,7 @@ public R passDocumentTo(final Function R switchDocumentOn(final Function, ? extends BranchesTerminal> switchMap) { + public R switchDocumentOn(final Function, ? extends BranchesTerminal> switchMap) { return switchMapInternal(this.assertImplementsAllExpressions(), switchMap.apply(new Branches<>())); } diff --git a/driver-core/src/main/com/mongodb/client/model/expressions/NumberExpression.java b/driver-core/src/main/com/mongodb/client/model/expressions/NumberExpression.java index 3502aa01916..91d922dd476 100644 --- a/driver-core/src/main/com/mongodb/client/model/expressions/NumberExpression.java +++ b/driver-core/src/main/com/mongodb/client/model/expressions/NumberExpression.java @@ -60,5 +60,5 @@ default NumberExpression subtract(final Number subtract) { DateExpression millisecondsToDate(); R passNumberTo(Function f); - R switchNumberOn(Function, ? extends BranchesTerminal> on); + R switchNumberOn(Function, ? extends BranchesTerminal> on); } diff --git a/driver-core/src/main/com/mongodb/client/model/expressions/StringExpression.java b/driver-core/src/main/com/mongodb/client/model/expressions/StringExpression.java index d3ab537a424..f4990b54949 100644 --- a/driver-core/src/main/com/mongodb/client/model/expressions/StringExpression.java +++ b/driver-core/src/main/com/mongodb/client/model/expressions/StringExpression.java @@ -56,5 +56,5 @@ default StringExpression substrBytes(final int start, final int length) { DateExpression parseDate(StringExpression timezone, StringExpression format); R passStringTo(Function f); - R switchStringOn(Function, ? extends BranchesTerminal> on); + R switchStringOn(Function, ? extends BranchesTerminal> on); } From 08ad9907ffb25d1e966b1b33d4af0db8c2d5183b Mon Sep 17 00:00:00 2001 From: Maxim Katcharov Date: Tue, 17 Jan 2023 12:32:12 -0700 Subject: [PATCH 11/15] Add ?super to Branches/Intermediary. --- .../client/model/expressions/Branches.java | 18 ++++++++--------- .../expressions/BranchesIntermediary.java | 20 +++++++++---------- 2 files changed, 19 insertions(+), 19 deletions(-) diff --git a/driver-core/src/main/com/mongodb/client/model/expressions/Branches.java b/driver-core/src/main/com/mongodb/client/model/expressions/Branches.java index 3b410def7eb..b3dab702660 100644 --- a/driver-core/src/main/com/mongodb/client/model/expressions/Branches.java +++ b/driver-core/src/main/com/mongodb/client/model/expressions/Branches.java @@ -57,41 +57,41 @@ public BranchesIntermediary lte(final T v, final Fu // is type - public BranchesIntermediary isBoolean(final Function r) { + public BranchesIntermediary isBoolean(final Function r) { return is(v -> mqlEx(v).isBoolean(), v -> r.apply((BooleanExpression) v)); } - public BranchesIntermediary isNumber(final Function r) { + public BranchesIntermediary isNumber(final Function r) { return is(v -> mqlEx(v).isNumber(), v -> r.apply((NumberExpression) v)); } - public BranchesIntermediary isInteger(final Function r) { + public BranchesIntermediary isInteger(final Function r) { return is(v -> mqlEx(v).isInteger(), v -> r.apply((IntegerExpression) v)); } - public BranchesIntermediary isString(final Function r) { + public BranchesIntermediary isString(final Function r) { return is(v -> mqlEx(v).isString(), v -> r.apply((StringExpression) v)); } - public BranchesIntermediary isDate(final Function r) { + public BranchesIntermediary isDate(final Function r) { return is(v -> mqlEx(v).isDate(), v -> r.apply((DateExpression) v)); } @SuppressWarnings("unchecked") - public BranchesIntermediary isArray(final Function, ? extends R> r) { + public BranchesIntermediary isArray(final Function, ? extends R> r) { return is(v -> mqlEx(v).isArray(), v -> r.apply((ArrayExpression) v)); } - public BranchesIntermediary isDocument(final Function r) { + public BranchesIntermediary isDocument(final Function r) { return is(v -> mqlEx(v).isDocument(), v -> r.apply((DocumentExpression) v)); } @SuppressWarnings("unchecked") - public BranchesIntermediary isMap(final Function, ? extends R> r) { + public BranchesIntermediary isMap(final Function, ? extends R> r) { return is(v -> mqlEx(v).isMap(), v -> r.apply((MapExpression) v)); } - public BranchesIntermediary isNull(final Function r) { + public BranchesIntermediary isNull(final Function r) { return is(v -> mqlEx(v).isNull(), v -> r.apply(v)); } } diff --git a/driver-core/src/main/com/mongodb/client/model/expressions/BranchesIntermediary.java b/driver-core/src/main/com/mongodb/client/model/expressions/BranchesIntermediary.java index bc5984de0ca..e4ecf78e899 100644 --- a/driver-core/src/main/com/mongodb/client/model/expressions/BranchesIntermediary.java +++ b/driver-core/src/main/com/mongodb/client/model/expressions/BranchesIntermediary.java @@ -37,7 +37,7 @@ private static MqlExpression mqlEx(final T value) { // is fn - public BranchesIntermediary is(final Function o, final Function r) { + public BranchesIntermediary is(final Function o, final Function r) { return this.with(value -> new SwitchCase<>(o.apply(value), r.apply(value))); } @@ -57,41 +57,41 @@ public BranchesIntermediary lte(final T v, final Function isBoolean(final Function r) { + public BranchesIntermediary isBoolean(final Function r) { return is(v -> mqlEx(v).isBoolean(), v -> r.apply((BooleanExpression) v)); } - public BranchesIntermediary isNumber(final Function r) { + public BranchesIntermediary isNumber(final Function r) { return is(v -> mqlEx(v).isNumber(), v -> r.apply((NumberExpression) v)); } - public BranchesIntermediary isInteger(final Function r) { + public BranchesIntermediary isInteger(final Function r) { return is(v -> mqlEx(v).isInteger(), v -> r.apply((IntegerExpression) v)); } - public BranchesIntermediary isString(final Function r) { + public BranchesIntermediary isString(final Function r) { return is(v -> mqlEx(v).isString(), v -> r.apply((StringExpression) v)); } - public BranchesIntermediary isDate(final Function r) { + public BranchesIntermediary isDate(final Function r) { return is(v -> mqlEx(v).isDate(), v -> r.apply((DateExpression) v)); } @SuppressWarnings("unchecked") - public BranchesIntermediary isArray(final Function, ? extends R> r) { + public BranchesIntermediary isArray(final Function, ? extends R> r) { return is(v -> mqlEx(v).isArray(), v -> r.apply((ArrayExpression) v)); } - public BranchesIntermediary isDocument(final Function r) { + public BranchesIntermediary isDocument(final Function r) { return is(v -> mqlEx(v).isDocument(), v -> r.apply((DocumentExpression) v)); } @SuppressWarnings("unchecked") - public BranchesIntermediary isMap(final Function, ? extends R> r) { + public BranchesIntermediary isMap(final Function, ? extends R> r) { return is(v -> mqlEx(v).isMap(), v -> r.apply((MapExpression) v)); } - public BranchesIntermediary isNull(final Function r) { + public BranchesIntermediary isNull(final Function r) { return is(v -> mqlEx(v).isNull(), v -> r.apply(v)); } From 43fc637f4097dafd04cfb5fbf254bbf444027386 Mon Sep 17 00:00:00 2001 From: Maxim Katcharov Date: Tue, 17 Jan 2023 16:42:36 -0700 Subject: [PATCH 12/15] Fixes --- .../mongodb/client/model/expressions/MqlExpression.java | 4 +++- .../expressions/ControlExpressionsFunctionalTest.java | 9 +++++---- 2 files changed, 8 insertions(+), 5 deletions(-) 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 9be4eda2526..973fb7f8006 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 @@ -440,7 +440,9 @@ public NumberExpression isNumberOr(final NumberExpression other) { } public BooleanExpression isInteger() { - return this.isNumber().and(this.eq(this.round())); + return switchOn(on -> on + .isNumber(v -> v.round().eq(v)) + .defaults(v -> of(false))); } @Override diff --git a/driver-core/src/test/functional/com/mongodb/client/model/expressions/ControlExpressionsFunctionalTest.java b/driver-core/src/test/functional/com/mongodb/client/model/expressions/ControlExpressionsFunctionalTest.java index 8d8e9d3b3c0..ef855691a8a 100644 --- a/driver-core/src/test/functional/com/mongodb/client/model/expressions/ControlExpressionsFunctionalTest.java +++ b/driver-core/src/test/functional/com/mongodb/client/model/expressions/ControlExpressionsFunctionalTest.java @@ -185,8 +185,8 @@ public void switchTestInitial() { "{'$switch': {'branches': [{'case': {'$isNumber': [1]}, 'then': 'A'}]}}"); assertExpression("A", of(1).switchOn(on -> on.isInteger(v -> of("A"))), - "{'$switch': {'branches': [{'case': {'$and': [{'$isNumber': [1]}, " + - "{'$eq': [1, {'$round': 1}]}]}, 'then': 'A'}]}}"); + "{'$switch': {'branches': [{'case': {'$switch': {'branches': [{'case': {'$isNumber': [1]}," + + "'then': {'$eq': [{'$round': 1}, 1]}}], 'default': false}}, 'then': 'A'}]}}"); assertExpression("A", of("x").switchOn(on -> on.isString(v -> of("A"))), "{'$switch': {'branches': [{'case': {'$eq': [{'$type': ['x']}, 'string']}, 'then': 'A'}]}}"); @@ -244,8 +244,9 @@ public void switchTestPartial() { + "{'case': {'$isNumber': [1]}, 'then': 'A'}]}}"); assertExpression("A", of(1).switchOn(on -> on.isNull(v -> of("X")).isInteger(v -> of("A"))), - "{'$switch': {'branches': [{'case': {'$eq': [1, null]}, 'then': 'X'}, {'case': " + - "{'$and': [{'$isNumber': [1]}, {'$eq': [1, {'$round': 1}]}]}, 'then': 'A'}]}}"); + "{'$switch': {'branches': [{'case': {'$eq': [1, null]}, 'then': 'X'}, {'case': " + + "{'$switch': {'branches': [{'case': {'$isNumber': [1]}, " + + "'then': {'$eq': [{'$round': 1}, 1]}}], 'default': false}}, 'then': 'A'}]}}"); assertExpression("A", of("x").switchOn(on -> on.isNull(v -> of("X")).isString(v -> of("A"))), "{'$switch': {'branches': [{'case': {'$eq': ['x', null]}, 'then': 'X'}, " From 40693a5026655e6f27ec11c6157742fe6fb83b6c Mon Sep 17 00:00:00 2001 From: Maxim Katcharov Date: Wed, 18 Jan 2023 09:12:41 -0700 Subject: [PATCH 13/15] Fix --- .../model/expressions/ControlExpressionsFunctionalTest.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/driver-core/src/test/functional/com/mongodb/client/model/expressions/ControlExpressionsFunctionalTest.java b/driver-core/src/test/functional/com/mongodb/client/model/expressions/ControlExpressionsFunctionalTest.java index ef855691a8a..a88b44cae5f 100644 --- a/driver-core/src/test/functional/com/mongodb/client/model/expressions/ControlExpressionsFunctionalTest.java +++ b/driver-core/src/test/functional/com/mongodb/client/model/expressions/ControlExpressionsFunctionalTest.java @@ -109,13 +109,14 @@ public void switchInferenceTest() { public void switchTypesTest() { Function label = expr -> expr.switchOn(on -> on .isBoolean(v -> v.asString().concat(of(" - bool"))) + // integer should be checked before string + .isInteger(v -> v.asString().concat(of(" - integer"))) + .isNumber(v -> v.asString().concat(of(" - number"))) .isString(v -> v.asString().concat(of(" - string"))) .isDate(v -> v.asString().concat(of(" - date"))) .isArray((ArrayExpression v) -> v.sum(a -> a).asString().concat(of(" - array"))) .isDocument(v -> v.getString("_id").concat(of(" - document"))) .isNull(v -> of("null - null")) - .isInteger(v -> v.asString().concat(of(" - integer"))) - .isNumber(v -> v.asString().concat(of(" - number"))) .defaults(v -> of("default")) ).toLower(); assertExpression("true - bool", of(true).passTo(label)); From a5f8b34a01dd6dc0ea5fa972d8a0a8c39fabe360 Mon Sep 17 00:00:00 2001 From: Maxim Katcharov Date: Wed, 18 Jan 2023 10:15:56 -0700 Subject: [PATCH 14/15] Post-rebase fixes, method renamed --- .../main/com/mongodb/client/model/expressions/Branches.java | 4 ++-- .../client/model/expressions/BranchesIntermediary.java | 4 ++-- .../com/mongodb/client/model/expressions/MqlExpression.java | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/driver-core/src/main/com/mongodb/client/model/expressions/Branches.java b/driver-core/src/main/com/mongodb/client/model/expressions/Branches.java index b3dab702660..1c9f53ef6aa 100644 --- a/driver-core/src/main/com/mongodb/client/model/expressions/Branches.java +++ b/driver-core/src/main/com/mongodb/client/model/expressions/Branches.java @@ -83,12 +83,12 @@ public BranchesIntermediary i } public BranchesIntermediary isDocument(final Function r) { - return is(v -> mqlEx(v).isDocument(), v -> r.apply((DocumentExpression) v)); + return is(v -> mqlEx(v).isDocumentOrMap(), v -> r.apply((DocumentExpression) v)); } @SuppressWarnings("unchecked") public BranchesIntermediary isMap(final Function, ? extends R> r) { - return is(v -> mqlEx(v).isMap(), v -> r.apply((MapExpression) v)); + return is(v -> mqlEx(v).isDocumentOrMap(), v -> r.apply((MapExpression) v)); } public BranchesIntermediary isNull(final Function r) { diff --git a/driver-core/src/main/com/mongodb/client/model/expressions/BranchesIntermediary.java b/driver-core/src/main/com/mongodb/client/model/expressions/BranchesIntermediary.java index e4ecf78e899..9ef53d4a7c7 100644 --- a/driver-core/src/main/com/mongodb/client/model/expressions/BranchesIntermediary.java +++ b/driver-core/src/main/com/mongodb/client/model/expressions/BranchesIntermediary.java @@ -83,12 +83,12 @@ public BranchesIntermediary isArray(final Function< } public BranchesIntermediary isDocument(final Function r) { - return is(v -> mqlEx(v).isDocument(), v -> r.apply((DocumentExpression) v)); + return is(v -> mqlEx(v).isDocumentOrMap(), v -> r.apply((DocumentExpression) v)); } @SuppressWarnings("unchecked") public BranchesIntermediary isMap(final Function, ? extends R> r) { - return is(v -> mqlEx(v).isMap(), v -> r.apply((MapExpression) v)); + return is(v -> mqlEx(v).isDocumentOrMap(), v -> r.apply((MapExpression) v)); } public BranchesIntermediary isNull(final Function r) { 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 973fb7f8006..2f62b05b11a 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 @@ -503,7 +503,7 @@ public ArrayExpression isArrayOr(final ArrayExpression return (ArrayExpression) this.isArray().cond(this.assertImplementsAllExpressions(), other); } - private BooleanExpression isDocumentOrMap() { + BooleanExpression isDocumentOrMap() { return new MqlExpression<>(ast("$type")).eq(of("object")); } From 647e307276ba9bce8195009f120b6376d6c59fa9 Mon Sep 17 00:00:00 2001 From: Maxim Katcharov Date: Wed, 18 Jan 2023 10:16:47 -0700 Subject: [PATCH 15/15] Checkstyle --- .../src/main/com/mongodb/client/model/expressions/Branches.java | 2 +- .../model/expressions/ControlExpressionsFunctionalTest.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/driver-core/src/main/com/mongodb/client/model/expressions/Branches.java b/driver-core/src/main/com/mongodb/client/model/expressions/Branches.java index 1c9f53ef6aa..40a726b4c9c 100644 --- a/driver-core/src/main/com/mongodb/client/model/expressions/Branches.java +++ b/driver-core/src/main/com/mongodb/client/model/expressions/Branches.java @@ -21,7 +21,7 @@ import java.util.function.Function; public final class Branches { - + Branches() { } diff --git a/driver-core/src/test/functional/com/mongodb/client/model/expressions/ControlExpressionsFunctionalTest.java b/driver-core/src/test/functional/com/mongodb/client/model/expressions/ControlExpressionsFunctionalTest.java index a88b44cae5f..77a539f418d 100644 --- a/driver-core/src/test/functional/com/mongodb/client/model/expressions/ControlExpressionsFunctionalTest.java +++ b/driver-core/src/test/functional/com/mongodb/client/model/expressions/ControlExpressionsFunctionalTest.java @@ -145,7 +145,7 @@ public void switchTypesTest() { .join(e -> e).concat(of(" - array"))))); } - private BranchesIntermediary branches(Branches on) { + private BranchesIntermediary branches(final Branches on) { return on.is(v -> of(true), v -> of("A")); }