17
17
18
18
import java .util .ArrayList ;
19
19
import java .util .Arrays ;
20
+ import java .util .Collection ;
20
21
import java .util .Collections ;
21
22
import java .util .LinkedHashMap ;
22
23
import java .util .List ;
@@ -2344,6 +2345,7 @@ public static Abs absoluteValueOf(AggregationExpression expression) {
2344
2345
Assert .notNull (expression , "Expression must not be null!" );
2345
2346
return new Abs (expression );
2346
2347
}
2348
+
2347
2349
/**
2348
2350
* Creates new {@link Abs}.
2349
2351
*
@@ -2495,7 +2497,6 @@ protected String getMongoMethod() {
2495
2497
return "$divide" ;
2496
2498
}
2497
2499
2498
-
2499
2500
/**
2500
2501
* Creates new {@link Divide}.
2501
2502
*
@@ -4390,7 +4391,7 @@ protected String getMongoMethod() {
4390
4391
4391
4392
/**
4392
4393
* Creates new {@link Second}.
4393
- *
4394
+ *
4394
4395
* @param fieldReference must not be {@literal null}.
4395
4396
* @return
4396
4397
*/
@@ -4705,7 +4706,7 @@ protected String getMongoMethod() {
4705
4706
4706
4707
/**
4707
4708
* Creates new {@link Max}.
4708
- *
4709
+ *
4709
4710
* @param fieldReference must not be {@literal null}.
4710
4711
* @return
4711
4712
*/
@@ -4730,7 +4731,7 @@ public static Max maxOf(AggregationExpression expression) {
4730
4731
/**
4731
4732
* Creates new {@link Max} with all previously added arguments appending the given one. <br />
4732
4733
* <strong>NOTE:</strong> Only possible in {@code $project} stage.
4733
- *
4734
+ *
4734
4735
* @param fieldReference must not be {@literal null}.
4735
4736
* @return
4736
4737
*/
@@ -4809,7 +4810,7 @@ public static Min minOf(AggregationExpression expression) {
4809
4810
/**
4810
4811
* Creates new {@link Min} with all previously added arguments appending the given one. <br />
4811
4812
* <strong>NOTE:</strong> Only possible in {@code $project} stage.
4812
- *
4813
+ *
4813
4814
* @param fieldReference must not be {@literal null}.
4814
4815
* @return
4815
4816
*/
@@ -4942,7 +4943,7 @@ protected String getMongoMethod() {
4942
4943
4943
4944
/**
4944
4945
* Creates new {@link StdDevSamp}.
4945
- *
4946
+ *
4946
4947
* @param fieldReference must not be {@literal null}.
4947
4948
* @return
4948
4949
*/
@@ -5715,4 +5716,184 @@ public static Not not(AggregationExpression expression) {
5715
5716
}
5716
5717
}
5717
5718
5719
+ /**
5720
+ * {@link AggregationExpression} for {@code $let} that binds {@link AggregationExpression} to variables for use in the
5721
+ * specified {@code in} expression, and returns the result of the expression.
5722
+ *
5723
+ * @author Christoph Strobl
5724
+ * @since 1.10
5725
+ */
5726
+ class Let implements AggregationExpression {
5727
+
5728
+ private final List <ExpressionVariable > vars ;
5729
+ private final AggregationExpression expression ;
5730
+
5731
+ private Let (List <ExpressionVariable > vars , AggregationExpression expression ) {
5732
+
5733
+ this .vars = vars ;
5734
+ this .expression = expression ;
5735
+ }
5736
+
5737
+ /**
5738
+ * Start creating new {@link Let} by defining the variables for {@code $vars}.
5739
+ *
5740
+ * @param variables must not be {@literal null}.
5741
+ * @return
5742
+ */
5743
+ public static LetBuilder define (final Collection <ExpressionVariable > variables ) {
5744
+
5745
+ Assert .notNull (variables , "Variables must not be null!" );
5746
+
5747
+ return new LetBuilder () {
5748
+ @ Override
5749
+ public Let andApply (final AggregationExpression expression ) {
5750
+
5751
+ Assert .notNull (expression , "Expression must not be null!" );
5752
+ return new Let (new ArrayList <ExpressionVariable >(variables ), expression );
5753
+ }
5754
+ };
5755
+ }
5756
+
5757
+ /**
5758
+ * Start creating new {@link Let} by defining the variables for {@code $vars}.
5759
+ *
5760
+ * @param variables must not be {@literal null}.
5761
+ * @return
5762
+ */
5763
+ public static LetBuilder define (final ExpressionVariable ... variables ) {
5764
+
5765
+ Assert .notNull (variables , "Variables must not be null!" );
5766
+
5767
+ return new LetBuilder () {
5768
+ @ Override
5769
+ public Let andApply (final AggregationExpression expression ) {
5770
+
5771
+ Assert .notNull (expression , "Expression must not be null!" );
5772
+ return new Let (Arrays .asList (variables ), expression );
5773
+ }
5774
+ };
5775
+ }
5776
+
5777
+ public interface LetBuilder {
5778
+
5779
+ /**
5780
+ * Define the {@link AggregationExpression} to evaluate.
5781
+ *
5782
+ * @param expression must not be {@literal null}.
5783
+ * @return
5784
+ */
5785
+ Let andApply (AggregationExpression expression );
5786
+ }
5787
+
5788
+ @ Override
5789
+ public DBObject toDbObject (final AggregationOperationContext context ) {
5790
+
5791
+ return toLet (new ExposedFieldsAggregationOperationContext (
5792
+ ExposedFields .synthetic (Fields .fields (getVariableNames ())), context ) {
5793
+
5794
+ @ Override
5795
+ public FieldReference getReference (Field field ) {
5796
+
5797
+ FieldReference ref = null ;
5798
+ try {
5799
+ ref = context .getReference (field );
5800
+ } catch (Exception e ) {
5801
+ // just ignore that one.
5802
+ }
5803
+ return ref != null ? ref : super .getReference (field );
5804
+ }
5805
+ });
5806
+ }
5807
+
5808
+ private String [] getVariableNames () {
5809
+
5810
+ String [] varNames = new String [this .vars .size ()];
5811
+ for (int i = 0 ; i < this .vars .size (); i ++) {
5812
+ varNames [i ] = this .vars .get (i ).variableName ;
5813
+ }
5814
+ return varNames ;
5815
+ }
5816
+
5817
+ private DBObject toLet (AggregationOperationContext context ) {
5818
+
5819
+ DBObject letExpression = new BasicDBObject ();
5820
+
5821
+ DBObject mappedVars = new BasicDBObject ();
5822
+ for (ExpressionVariable var : this .vars ) {
5823
+ mappedVars .putAll (getMappedVariable (var , context ));
5824
+ }
5825
+
5826
+ letExpression .put ("vars" , mappedVars );
5827
+ letExpression .put ("in" , getMappedIn (context ));
5828
+
5829
+ return new BasicDBObject ("$let" , letExpression );
5830
+ }
5831
+
5832
+ private DBObject getMappedVariable (ExpressionVariable var , AggregationOperationContext context ) {
5833
+
5834
+ return new BasicDBObject (var .variableName , var .expression instanceof AggregationExpression
5835
+ ? ((AggregationExpression ) var .expression ).toDbObject (context ) : var .expression );
5836
+ }
5837
+
5838
+ private Object getMappedIn (AggregationOperationContext context ) {
5839
+ return expression .toDbObject (new NestedDelegatingExpressionAggregationOperationContext (context ));
5840
+ }
5841
+
5842
+ /**
5843
+ * @author Christoph Strobl
5844
+ */
5845
+ public static class ExpressionVariable {
5846
+
5847
+ private final String variableName ;
5848
+ private final Object expression ;
5849
+
5850
+ /**
5851
+ * Creates new {@link ExpressionVariable}.
5852
+ *
5853
+ * @param variableName can be {@literal null}.
5854
+ * @param expression can be {@literal null}.
5855
+ */
5856
+ private ExpressionVariable (String variableName , Object expression ) {
5857
+
5858
+ this .variableName = variableName ;
5859
+ this .expression = expression ;
5860
+ }
5861
+
5862
+ /**
5863
+ * Create a new {@link ExpressionVariable} with given name.
5864
+ *
5865
+ * @param variableName must not be {@literal null}.
5866
+ * @return never {@literal null}.
5867
+ */
5868
+ public static ExpressionVariable newVariable (String variableName ) {
5869
+
5870
+ Assert .notNull (variableName , "VariableName must not be null!" );
5871
+ return new ExpressionVariable (variableName , null );
5872
+ }
5873
+
5874
+ /**
5875
+ * Create a new {@link ExpressionVariable} with current name and given {@literal expression}.
5876
+ *
5877
+ * @param expression must not be {@literal null}.
5878
+ * @return never {@literal null}.
5879
+ */
5880
+ public ExpressionVariable forExpression (AggregationExpression expression ) {
5881
+
5882
+ Assert .notNull (expression , "Expression must not be null!" );
5883
+ return new ExpressionVariable (variableName , expression );
5884
+ }
5885
+
5886
+ /**
5887
+ * Create a new {@link ExpressionVariable} with current name and given {@literal expressionObject}.
5888
+ *
5889
+ * @param expressionObject must not be {@literal null}.
5890
+ * @return never {@literal null}.
5891
+ */
5892
+ public ExpressionVariable forExpression (DBObject expressionObject ) {
5893
+
5894
+ Assert .notNull (expressionObject , "Expression must not be null!" );
5895
+ return new ExpressionVariable (variableName , expressionObject );
5896
+ }
5897
+ }
5898
+ }
5718
5899
}
0 commit comments