Skip to content

Commit b8e5ef3

Browse files
committed
Implement arithmetic expressions (from top 50, and others)
1 parent 1a776bf commit b8e5ef3

File tree

6 files changed

+383
-30
lines changed

6 files changed

+383
-30
lines changed

driver-core/src/main/com/mongodb/client/model/expressions/Expressions.java

Lines changed: 17 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
package com.mongodb.client.model.expressions;
1818

1919
import com.mongodb.assertions.Assertions;
20+
import com.mongodb.lang.NonNull;
2021
import org.bson.BsonArray;
2122
import org.bson.BsonBoolean;
2223
import org.bson.BsonDateTime;
@@ -35,6 +36,7 @@
3536
import java.util.List;
3637
import java.util.stream.Collectors;
3738

39+
import static com.mongodb.client.model.expressions.MqlExpression.AstPlaceholder;
3840

3941
/**
4042
* Convenience methods related to {@link Expression}.
@@ -52,7 +54,7 @@ private Expressions() {}
5254
*/
5355
public static BooleanExpression of(final boolean of) {
5456
// we intentionally disallow ofBoolean(null)
55-
return new MqlExpression<>((codecRegistry) -> new BsonBoolean(of));
57+
return new MqlExpression<>((codecRegistry) -> new AstPlaceholder(new BsonBoolean(of)));
5658
}
5759

5860
/**
@@ -63,16 +65,17 @@ public static BooleanExpression of(final boolean of) {
6365
* @return the integer expression
6466
*/
6567
public static IntegerExpression of(final int of) {
66-
return new MqlExpression<>((codecRegistry) -> new BsonInt32(of));
68+
return new MqlExpression<>((codecRegistry) -> new AstPlaceholder(new BsonInt32(of)));
6769
}
6870
public static IntegerExpression of(final long of) {
69-
return new MqlExpression<>((codecRegistry) -> new BsonInt64(of));
71+
return new MqlExpression<>((codecRegistry) -> new AstPlaceholder(new BsonInt64(of)));
7072
}
7173
public static NumberExpression of(final double of) {
72-
return new MqlExpression<>((codecRegistry) -> new BsonDouble(of));
74+
return new MqlExpression<>((codecRegistry) -> new AstPlaceholder(new BsonDouble(of)));
7375
}
74-
public static DateExpression of(final Instant of) {
75-
return new MqlExpression<>((codecRegistry) -> new BsonDateTime(of.toEpochMilli()));
76+
public static DateExpression of(@NonNull final Instant of) {
77+
Assertions.notNull("Instant", of);
78+
return new MqlExpression<>((codecRegistry) -> new AstPlaceholder(new BsonDateTime(of.toEpochMilli())));
7679
}
7780

7881
/**
@@ -82,9 +85,9 @@ public static DateExpression of(final Instant of) {
8285
* @param of the string
8386
* @return the string expression
8487
*/
85-
public static StringExpression of(final String of) {
88+
public static StringExpression of(@NonNull final String of) {
8689
Assertions.notNull("String", of);
87-
return new MqlExpression<>((codecRegistry) -> new BsonString(of));
90+
return new MqlExpression<>((codecRegistry) -> new AstPlaceholder(new BsonString(of)));
8891
}
8992

9093
/**
@@ -99,27 +102,28 @@ public static ArrayExpression<BooleanExpression> ofBooleanArray(final boolean...
99102
for (boolean b : array) {
100103
result.add(new BsonBoolean(b));
101104
}
102-
return new MqlExpression<>((cr) -> new BsonArray(result));
105+
return new MqlExpression<>((cr) -> new AstPlaceholder(new BsonArray(result)));
103106
}
104107

105108

106109
public static ArrayExpression<IntegerExpression> ofIntegerArray(final int... ofIntegerArray) {
107110
List<BsonValue> array = Arrays.stream(ofIntegerArray)
108111
.mapToObj(BsonInt32::new)
109112
.collect(Collectors.toList());
110-
return new MqlExpression<>((cr) -> new BsonArray(array));
113+
return new MqlExpression<>((cr) -> new AstPlaceholder(new BsonArray(array)));
111114
}
112115

113116
public static DocumentExpression ofDocument(final Bson document) {
114117
Assertions.notNull("document", document);
115118
// All documents are wrapped in a $literal. If we don't wrap, we need to
116119
// check for empty documents and documents that are actually expressions
117120
// (and need to be wrapped in $literal anyway). This would be brittle.
118-
return new MqlExpression<>((cr) -> new BsonDocument("$literal",
119-
document.toBsonDocument(BsonDocument.class, cr)));
121+
return new MqlExpression<>((cr) -> new AstPlaceholder(new BsonDocument("$literal",
122+
document.toBsonDocument(BsonDocument.class, cr))));
120123
}
121124

122125
public static <R extends Expression> R ofNull() {
123-
return new MqlExpression<>((cr) -> new BsonNull()).assertImplementsAllExpressions();
126+
return new MqlExpression<>((cr) -> new AstPlaceholder(new BsonNull()))
127+
.assertImplementsAllExpressions();
124128
}
125129
}

driver-core/src/main/com/mongodb/client/model/expressions/IntegerExpression.java

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,5 +20,26 @@
2020
* Expresses an integer value.
2121
*/
2222
public interface IntegerExpression extends NumberExpression {
23+
IntegerExpression multiply(IntegerExpression i);
2324

25+
default IntegerExpression multiply(final int multiply) {
26+
return this.multiply(Expressions.of(multiply));
27+
}
28+
29+
IntegerExpression add(IntegerExpression i);
30+
31+
default IntegerExpression add(final int add) {
32+
return this.add(Expressions.of(add));
33+
}
34+
35+
IntegerExpression subtract(IntegerExpression i);
36+
37+
default IntegerExpression subtract(final int subtract) {
38+
return this.subtract(Expressions.of(subtract));
39+
}
40+
41+
IntegerExpression max(IntegerExpression i);
42+
IntegerExpression min(IntegerExpression i);
43+
44+
IntegerExpression abs();
2445
}

driver-core/src/main/com/mongodb/client/model/expressions/MqlExpression.java

Lines changed: 98 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -29,9 +29,9 @@ final class MqlExpression<T extends Expression>
2929
implements Expression, BooleanExpression, IntegerExpression, NumberExpression,
3030
StringExpression, DateExpression, DocumentExpression, ArrayExpression<T> {
3131

32-
private final Function<CodecRegistry, BsonValue> fn;
32+
private final Function<CodecRegistry, AstPlaceholder> fn;
3333

34-
MqlExpression(final Function<CodecRegistry, BsonValue> fn) {
34+
MqlExpression(final Function<CodecRegistry, AstPlaceholder> fn) {
3535
this.fn = fn;
3636
}
3737

@@ -41,33 +41,41 @@ final class MqlExpression<T extends Expression>
4141
* {@link MqlExpressionCodec}.
4242
*/
4343
BsonValue toBsonValue(final CodecRegistry codecRegistry) {
44-
return fn.apply(codecRegistry);
44+
return fn.apply(codecRegistry).bsonValue;
4545
}
4646

47-
private Function<CodecRegistry, BsonValue> astDoc(final String name, final BsonDocument value) {
48-
return (cr) -> new BsonDocument(name, value);
47+
private AstPlaceholder astDoc(final String name, final BsonDocument value) {
48+
return new AstPlaceholder(new BsonDocument(name, value));
4949
}
5050

51-
private Function<CodecRegistry, BsonValue> ast(final String name) {
52-
return (cr) -> new BsonDocument(name, this.toBsonValue(cr));
51+
static class AstPlaceholder {
52+
private BsonValue bsonValue;
53+
54+
AstPlaceholder(final BsonValue bsonValue) {
55+
this.bsonValue = bsonValue;
56+
}
57+
}
58+
59+
private Function<CodecRegistry, AstPlaceholder> ast(final String name) {
60+
return (cr) -> new AstPlaceholder(new BsonDocument(name, this.toBsonValue(cr)));
5361
}
5462

55-
private Function<CodecRegistry, BsonValue> ast(final String name, final Expression param1) {
63+
private Function<CodecRegistry, AstPlaceholder> ast(final String name, final Expression param1) {
5664
return (cr) -> {
5765
BsonArray value = new BsonArray();
5866
value.add(this.toBsonValue(cr));
5967
value.add(extractBsonValue(cr, param1));
60-
return new BsonDocument(name, value);
68+
return new AstPlaceholder(new BsonDocument(name, value));
6169
};
6270
}
6371

64-
private Function<CodecRegistry, BsonValue> ast(final String name, final Expression param1, final Expression param2) {
72+
private Function<CodecRegistry, AstPlaceholder> ast(final String name, final Expression param1, final Expression param2) {
6573
return (cr) -> {
6674
BsonArray value = new BsonArray();
6775
value.add(this.toBsonValue(cr));
6876
value.add(extractBsonValue(cr, param1));
6977
value.add(extractBsonValue(cr, param2));
70-
return new BsonDocument(name, value);
78+
return new AstPlaceholder(new BsonDocument(name, value));
7179
};
7280
}
7381

@@ -89,12 +97,12 @@ <R extends Expression> R assertImplementsAllExpressions() {
8997
return (R) this;
9098
}
9199

92-
private static <R extends Expression> R newMqlExpression(final Function<CodecRegistry, BsonValue> ast) {
100+
private static <R extends Expression> R newMqlExpression(final Function<CodecRegistry, AstPlaceholder> ast) {
93101
return new MqlExpression<>(ast).assertImplementsAllExpressions();
94102
}
95103

96104
private <R extends Expression> R variable(final String variable) {
97-
return newMqlExpression((cr) -> new BsonString(variable));
105+
return newMqlExpression((cr) -> new AstPlaceholder(new BsonString(variable)));
98106
}
99107

100108
/** @see BooleanExpression */
@@ -159,15 +167,15 @@ public <R extends Expression> ArrayExpression<R> map(final Function<? super T, ?
159167
T varThis = variable("$$this");
160168
return new MqlExpression<>((cr) -> astDoc("$map", new BsonDocument()
161169
.append("input", this.toBsonValue(cr))
162-
.append("in", extractBsonValue(cr, in.apply(varThis)))).apply(cr));
170+
.append("in", extractBsonValue(cr, in.apply(varThis)))));
163171
}
164172

165173
@Override
166174
public ArrayExpression<T> filter(final Function<? super T, ? extends BooleanExpression> cond) {
167175
T varThis = variable("$$this");
168176
return new MqlExpression<T>((cr) -> astDoc("$filter", new BsonDocument()
169177
.append("input", this.toBsonValue(cr))
170-
.append("cond", extractBsonValue(cr, cond.apply(varThis)))).apply(cr));
178+
.append("cond", extractBsonValue(cr, cond.apply(varThis)))));
171179
}
172180

173181
@Override
@@ -177,7 +185,81 @@ public T reduce(final T initialValue, final BinaryOperator<T> in) {
177185
return newMqlExpression((cr) -> astDoc("$reduce", new BsonDocument()
178186
.append("input", this.toBsonValue(cr))
179187
.append("initialValue", extractBsonValue(cr, initialValue))
180-
.append("in", extractBsonValue(cr, in.apply(varThis, varValue)))).apply(cr));
188+
.append("in", extractBsonValue(cr, in.apply(varThis, varValue)))));
189+
}
190+
191+
192+
/** @see IntegerExpression
193+
* @see NumberExpression */
194+
195+
@Override
196+
public IntegerExpression multiply(final NumberExpression n) {
197+
return newMqlExpression(ast("$multiply", n));
198+
}
199+
200+
@Override
201+
public NumberExpression add(final NumberExpression n) {
202+
return new MqlExpression<>(ast("$add", n));
203+
}
204+
205+
@Override
206+
public NumberExpression divide(final NumberExpression n) {
207+
return new MqlExpression<>(ast("$divide", n));
208+
}
209+
210+
@Override
211+
public NumberExpression max(final NumberExpression n) {
212+
return new MqlExpression<>(ast("$max", n));
213+
}
214+
215+
@Override
216+
public NumberExpression min(final NumberExpression n) {
217+
return new MqlExpression<>(ast("$min", n));
218+
}
219+
220+
@Override
221+
public IntegerExpression round() {
222+
return new MqlExpression<>(ast("$round"));
223+
}
224+
225+
@Override
226+
public NumberExpression round(final IntegerExpression place) {
227+
return new MqlExpression<>(ast("$round", place));
228+
}
229+
230+
@Override
231+
public IntegerExpression multiply(final IntegerExpression i) {
232+
return new MqlExpression<>(ast("$multiply", i));
233+
}
234+
235+
@Override
236+
public IntegerExpression abs() {
237+
return newMqlExpression(ast("$abs"));
238+
}
239+
240+
@Override
241+
public NumberExpression subtract(final NumberExpression n) {
242+
return new MqlExpression<>(ast("$subtract", n));
243+
}
244+
245+
@Override
246+
public IntegerExpression add(final IntegerExpression i) {
247+
return new MqlExpression<>(ast("$add", i));
248+
}
249+
250+
@Override
251+
public IntegerExpression subtract(final IntegerExpression i) {
252+
return new MqlExpression<>(ast("$subtract", i));
253+
}
254+
255+
@Override
256+
public IntegerExpression max(final IntegerExpression i) {
257+
return new MqlExpression<>(ast("$max", i));
258+
}
259+
260+
@Override
261+
public IntegerExpression min(final IntegerExpression i) {
262+
return new MqlExpression<>(ast("$min", i));
181263
}
182264

183265

driver-core/src/main/com/mongodb/client/model/expressions/NumberExpression.java

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,4 +21,39 @@
2121
*/
2222
public interface NumberExpression extends Expression {
2323

24+
// TODO this must not return <T extends NumberExpression> T
25+
// since it allows: IntegerEx result = oneNum.multiply(oneInt)
26+
NumberExpression multiply(NumberExpression n);
27+
28+
default NumberExpression multiply(final double multiply) {
29+
return this.multiply(Expressions.of(multiply));
30+
}
31+
32+
NumberExpression divide(NumberExpression n);
33+
34+
default NumberExpression divide(final double divide) {
35+
return this.divide(Expressions.of(divide));
36+
}
37+
38+
NumberExpression add(NumberExpression n);
39+
40+
default NumberExpression add(final double add) {
41+
return this.add(Expressions.of(add));
42+
}
43+
44+
NumberExpression subtract(NumberExpression n);
45+
46+
default NumberExpression subtract(final double subtract) {
47+
return this.subtract(Expressions.of(subtract));
48+
}
49+
50+
NumberExpression max(NumberExpression n);
51+
52+
NumberExpression min(NumberExpression n);
53+
54+
IntegerExpression round();
55+
56+
NumberExpression round(IntegerExpression place);
57+
58+
NumberExpression abs();
2459
}

0 commit comments

Comments
 (0)