32
32
33
33
final class MqlExpression <T extends Expression >
34
34
implements Expression , BooleanExpression , IntegerExpression , NumberExpression ,
35
- StringExpression , DateExpression , DocumentExpression , ArrayExpression <T > {
35
+ StringExpression , DateExpression , DocumentExpression , ArrayExpression <T >, MapExpression < T >, EntryExpression < T > {
36
36
37
37
private final Function <CodecRegistry , AstPlaceholder > fn ;
38
38
@@ -53,6 +53,26 @@ private AstPlaceholder astDoc(final String name, final BsonDocument value) {
53
53
return new AstPlaceholder (new BsonDocument (name , value ));
54
54
}
55
55
56
+ @ Override
57
+ public StringExpression getKey () {
58
+ return new MqlExpression <>(getFieldInternal ("k" ));
59
+ }
60
+
61
+ @ Override
62
+ public T getValue () {
63
+ return newMqlExpression (getFieldInternal ("v" ));
64
+ }
65
+
66
+ @ Override
67
+ public EntryExpression <T > setValue (final T value ) {
68
+ return setFieldInternal ("v" , value );
69
+ }
70
+
71
+ @ Override
72
+ public EntryExpression <T > setKey (final StringExpression key ) {
73
+ return setFieldInternal ("k" , key );
74
+ }
75
+
56
76
static final class AstPlaceholder {
57
77
private final BsonValue bsonValue ;
58
78
@@ -95,7 +115,7 @@ private Function<CodecRegistry, AstPlaceholder> ast(final String name, final Exp
95
115
* the only implementation of Expression and all subclasses, so this will
96
116
* not mis-cast an expression as anything else.
97
117
*/
98
- private static BsonValue extractBsonValue (final CodecRegistry cr , final Expression expression ) {
118
+ static BsonValue extractBsonValue (final CodecRegistry cr , final Expression expression ) {
99
119
return ((MqlExpression <?>) expression ).toBsonValue (cr );
100
120
}
101
121
@@ -211,6 +231,16 @@ public DocumentExpression getDocument(final String fieldName) {
211
231
return new MqlExpression <>(getFieldInternal (fieldName ));
212
232
}
213
233
234
+ @ Override
235
+ public <R extends Expression > MapExpression <R > getMap (final String field ) {
236
+ return new MqlExpression <>(getFieldInternal (field ));
237
+ }
238
+
239
+ @ Override
240
+ public <R extends Expression > MapExpression <R > getMap (final String field , final MapExpression <? extends R > other ) {
241
+ return getMap (field ).isMapOr (other );
242
+ }
243
+
214
244
@ Override
215
245
public DocumentExpression getDocument (final String fieldName , final DocumentExpression other ) {
216
246
return getDocument (fieldName ).isDocumentOr (other );
@@ -233,6 +263,10 @@ public DocumentExpression merge(final DocumentExpression other) {
233
263
234
264
@ Override
235
265
public DocumentExpression setField (final String fieldName , final Expression exp ) {
266
+ return setFieldInternal (fieldName , exp );
267
+ }
268
+
269
+ private MqlExpression <T > setFieldInternal (final String fieldName , final Expression exp ) {
236
270
return newMqlExpression ((cr ) -> astDoc ("$setField" , new BsonDocument ()
237
271
.append ("field" , new BsonString (fieldName ))
238
272
.append ("input" , this .toBsonValue (cr ))
@@ -327,6 +361,11 @@ public BooleanExpression isArray() {
327
361
return new MqlExpression <>(astWrapped ("$isArray" ));
328
362
}
329
363
364
+ private Expression ifNull (final Expression ifNull ) {
365
+ return new MqlExpression <>(ast ("$ifNull" , ifNull , Expressions .ofNull ()))
366
+ .assertImplementsAllExpressions ();
367
+ }
368
+
330
369
/**
331
370
* checks if array (but cannot check type)
332
371
* user asserts array is of type R
@@ -341,24 +380,30 @@ public <R extends Expression> ArrayExpression<R> isArrayOr(final ArrayExpression
341
380
return (ArrayExpression <R >) this .isArray ().cond (this .assertImplementsAllExpressions (), other );
342
381
}
343
382
344
- public BooleanExpression isDocument () {
383
+ private BooleanExpression isDocumentOrMap () {
345
384
return new MqlExpression <>(ast ("$type" )).eq (of ("object" ));
346
385
}
347
386
348
387
@ Override
349
388
public <R extends DocumentExpression > R isDocumentOr (final R other ) {
350
- return this .isDocument ().cond (this .assertImplementsAllExpressions (), other );
389
+ return this .isDocumentOrMap ().cond (this .assertImplementsAllExpressions (), other );
390
+ }
391
+
392
+ @ Override
393
+ public <R extends Expression > MapExpression <R > isMapOr (final MapExpression <? extends R > other ) {
394
+ MqlExpression <?> isMap = (MqlExpression <?>) this .isDocumentOrMap ();
395
+ return newMqlExpression (isMap .ast ("$cond" , this .assertImplementsAllExpressions (), other ));
351
396
}
352
397
353
398
@ Override
354
399
public StringExpression asString () {
355
400
return new MqlExpression <>(astWrapped ("$toString" ));
356
401
}
357
402
358
- private Function <CodecRegistry , AstPlaceholder > convertInternal (final String to , final Expression orElse ) {
403
+ private Function <CodecRegistry , AstPlaceholder > convertInternal (final String to , final Expression other ) {
359
404
return (cr ) -> astDoc ("$convert" , new BsonDocument ()
360
405
.append ("input" , this .fn .apply (cr ).bsonValue )
361
- .append ("onError" , extractBsonValue (cr , orElse ))
406
+ .append ("onError" , extractBsonValue (cr , other ))
362
407
.append ("to" , new BsonString (to )));
363
408
}
364
409
@@ -731,4 +776,76 @@ public StringExpression substr(final IntegerExpression start, final IntegerExpre
731
776
public StringExpression substrBytes (final IntegerExpression start , final IntegerExpression length ) {
732
777
return new MqlExpression <>(ast ("$substrBytes" , start , length ));
733
778
}
779
+
780
+ @ Override
781
+ public BooleanExpression has (final StringExpression key ) {
782
+ return get (key ).ne (ofRem ());
783
+ }
784
+
785
+ static <R extends Expression > R ofRem () {
786
+ // $$REMOVE is intentionally not exposed to users
787
+ return new MqlExpression <>((cr ) -> new MqlExpression .AstPlaceholder (new BsonString ("$$REMOVE" )))
788
+ .assertImplementsAllExpressions ();
789
+ }
790
+
791
+ /** @see MapExpression
792
+ * @see EntryExpression */
793
+
794
+ @ Override
795
+ public T get (final StringExpression key ) {
796
+ return newMqlExpression ((cr ) -> astDoc ("$getField" , new BsonDocument ()
797
+ .append ("input" , this .fn .apply (cr ).bsonValue )
798
+ .append ("field" , extractBsonValue (cr , key ))));
799
+ }
800
+
801
+ @ SuppressWarnings ("unchecked" )
802
+ @ Override
803
+ public T get (final StringExpression key , final T other ) {
804
+ return (T ) ((MqlExpression <?>) get (key )).ifNull (other );
805
+ }
806
+
807
+ @ Override
808
+ public MapExpression <T > set (final StringExpression key , final T value ) {
809
+ return newMqlExpression ((cr ) -> astDoc ("$setField" , new BsonDocument ()
810
+ .append ("field" , extractBsonValue (cr , key ))
811
+ .append ("input" , this .toBsonValue (cr ))
812
+ .append ("value" , extractBsonValue (cr , value ))));
813
+ }
814
+
815
+ @ Override
816
+ public MapExpression <T > unset (final StringExpression key ) {
817
+ return newMqlExpression ((cr ) -> astDoc ("$unsetField" , new BsonDocument ()
818
+ .append ("field" , extractBsonValue (cr , key ))
819
+ .append ("input" , this .toBsonValue (cr ))));
820
+ }
821
+
822
+ @ Override
823
+ public MapExpression <T > merge (final MapExpression <? extends T > map ) {
824
+ return new MqlExpression <>(ast ("$mergeObjects" , map ));
825
+ }
826
+
827
+ @ Override
828
+ public ArrayExpression <EntryExpression <T >> entrySet () {
829
+ return newMqlExpression (ast ("$objectToArray" ));
830
+ }
831
+
832
+ @ Override
833
+ public <R extends Expression > MapExpression <R > asMap (
834
+ final Function <? super T , ? extends EntryExpression <? extends R >> mapper ) {
835
+ @ SuppressWarnings ("unchecked" )
836
+ MqlExpression <EntryExpression <? extends R >> array = (MqlExpression <EntryExpression <? extends R >>) this .map (mapper );
837
+ return newMqlExpression (array .astWrapped ("$arrayToObject" ));
838
+ }
839
+
840
+ @ SuppressWarnings ("unchecked" )
841
+ @ Override
842
+ public MapExpression <Expression > asMap () {
843
+ return (MapExpression <Expression >) this ;
844
+ }
845
+
846
+ @ SuppressWarnings ("unchecked" )
847
+ @ Override
848
+ public <R extends DocumentExpression > R asDocument () {
849
+ return (R ) this ;
850
+ }
734
851
}
0 commit comments