Skip to content

Commit bda1005

Browse files
committed
Implement arithmetic expressions (#1037)
Implement arithmetic expressions (from top 50, and others) JAVA-4803
1 parent 7e108a8 commit bda1005

File tree

7 files changed

+432
-29
lines changed

7 files changed

+432
-29
lines changed

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

Lines changed: 34 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
import org.bson.BsonArray;
2121
import org.bson.BsonBoolean;
2222
import org.bson.BsonDateTime;
23+
import org.bson.BsonDecimal128;
2324
import org.bson.BsonDocument;
2425
import org.bson.BsonDouble;
2526
import org.bson.BsonInt32;
@@ -28,13 +29,15 @@
2829
import org.bson.BsonString;
2930
import org.bson.BsonValue;
3031
import org.bson.conversions.Bson;
32+
import org.bson.types.Decimal128;
3133

3234
import java.time.Instant;
3335
import java.util.ArrayList;
3436
import java.util.Arrays;
3537
import java.util.List;
3638
import java.util.stream.Collectors;
3739

40+
import static com.mongodb.client.model.expressions.MqlExpression.AstPlaceholder;
3841

3942
/**
4043
* Convenience methods related to {@link Expression}.
@@ -52,7 +55,7 @@ private Expressions() {}
5255
*/
5356
public static BooleanExpression of(final boolean of) {
5457
// we intentionally disallow ofBoolean(null)
55-
return new MqlExpression<>((codecRegistry) -> new BsonBoolean(of));
58+
return new MqlExpression<>((codecRegistry) -> new AstPlaceholder(new BsonBoolean(of)));
5659
}
5760

5861
/**
@@ -63,16 +66,21 @@ public static BooleanExpression of(final boolean of) {
6366
* @return the integer expression
6467
*/
6568
public static IntegerExpression of(final int of) {
66-
return new MqlExpression<>((codecRegistry) -> new BsonInt32(of));
69+
return new MqlExpression<>((codecRegistry) -> new AstPlaceholder(new BsonInt32(of)));
6770
}
6871
public static IntegerExpression of(final long of) {
69-
return new MqlExpression<>((codecRegistry) -> new BsonInt64(of));
72+
return new MqlExpression<>((codecRegistry) -> new AstPlaceholder(new BsonInt64(of)));
7073
}
7174
public static NumberExpression of(final double of) {
72-
return new MqlExpression<>((codecRegistry) -> new BsonDouble(of));
75+
return new MqlExpression<>((codecRegistry) -> new AstPlaceholder(new BsonDouble(of)));
76+
}
77+
public static NumberExpression of(final Decimal128 of) {
78+
Assertions.notNull("Decimal128", of);
79+
return new MqlExpression<>((codecRegistry) -> new AstPlaceholder(new BsonDecimal128(of)));
7380
}
7481
public static DateExpression of(final Instant of) {
75-
return new MqlExpression<>((codecRegistry) -> new BsonDateTime(of.toEpochMilli()));
82+
Assertions.notNull("Instant", of);
83+
return new MqlExpression<>((codecRegistry) -> new AstPlaceholder(new BsonDateTime(of.toEpochMilli())));
7684
}
7785

7886
/**
@@ -84,7 +92,7 @@ public static DateExpression of(final Instant of) {
8492
*/
8593
public static StringExpression of(final String of) {
8694
Assertions.notNull("String", of);
87-
return new MqlExpression<>((codecRegistry) -> new BsonString(of));
95+
return new MqlExpression<>((codecRegistry) -> new AstPlaceholder(new BsonString(of)));
8896
}
8997

9098
/**
@@ -99,27 +107,42 @@ public static ArrayExpression<BooleanExpression> ofBooleanArray(final boolean...
99107
for (boolean b : array) {
100108
result.add(new BsonBoolean(b));
101109
}
102-
return new MqlExpression<>((cr) -> new BsonArray(result));
110+
return new MqlExpression<>((cr) -> new AstPlaceholder(new BsonArray(result)));
103111
}
104112

105113

106114
public static ArrayExpression<IntegerExpression> ofIntegerArray(final int... ofIntegerArray) {
107115
List<BsonValue> array = Arrays.stream(ofIntegerArray)
108116
.mapToObj(BsonInt32::new)
109117
.collect(Collectors.toList());
110-
return new MqlExpression<>((cr) -> new BsonArray(array));
118+
return new MqlExpression<>((cr) -> new AstPlaceholder(new BsonArray(array)));
111119
}
112120

113121
public static DocumentExpression ofDocument(final Bson document) {
114122
Assertions.notNull("document", document);
115123
// All documents are wrapped in a $literal. If we don't wrap, we need to
116124
// check for empty documents and documents that are actually expressions
117125
// (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)));
126+
return new MqlExpression<>((cr) -> new AstPlaceholder(new BsonDocument("$literal",
127+
document.toBsonDocument(BsonDocument.class, cr))));
120128
}
121129

122130
public static <R extends Expression> R ofNull() {
123-
return new MqlExpression<>((cr) -> new BsonNull()).assertImplementsAllExpressions();
131+
return new MqlExpression<>((cr) -> new AstPlaceholder(new BsonNull()))
132+
.assertImplementsAllExpressions();
133+
}
134+
135+
static NumberExpression numberToExpression(final Number number) {
136+
if (number instanceof Integer) {
137+
return of((int) number);
138+
} else if (number instanceof Long) {
139+
return of((long) number);
140+
} else if (number instanceof Double) {
141+
return of((double) number);
142+
} else if (number instanceof Decimal128) {
143+
return of((Decimal128) number);
144+
} else {
145+
throw new IllegalArgumentException("Number must be one of: Integer, Long, Double, Decimal128");
146+
}
124147
}
125148
}

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 final class AstPlaceholder {
52+
private final 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: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,4 +21,37 @@
2121
*/
2222
public interface NumberExpression extends Expression {
2323

24+
NumberExpression multiply(NumberExpression n);
25+
26+
default NumberExpression multiply(final Number multiply) {
27+
return this.multiply(Expressions.numberToExpression(multiply));
28+
}
29+
30+
NumberExpression divide(NumberExpression n);
31+
32+
default NumberExpression divide(final Number divide) {
33+
return this.divide(Expressions.numberToExpression(divide));
34+
}
35+
36+
NumberExpression add(NumberExpression n);
37+
38+
default NumberExpression add(final Number add) {
39+
return this.add(Expressions.numberToExpression(add));
40+
}
41+
42+
NumberExpression subtract(NumberExpression n);
43+
44+
default NumberExpression subtract(final Number subtract) {
45+
return this.subtract(Expressions.numberToExpression(subtract));
46+
}
47+
48+
NumberExpression max(NumberExpression n);
49+
50+
NumberExpression min(NumberExpression n);
51+
52+
IntegerExpression round();
53+
54+
NumberExpression round(IntegerExpression place);
55+
56+
NumberExpression abs();
2457
}

0 commit comments

Comments
 (0)