15
15
*/
16
16
package org .springframework .data .mongodb .core .aggregation ;
17
17
18
- import static org .mockito .Mockito .eq ;
19
- import static org .mockito . Mockito . mock ;
20
- import static org .mockito . Mockito . verify ;
18
+ import static org .mockito .Mockito .* ;
19
+ import static org .springframework . data . domain . Sort . Direction .* ;
20
+ import static org .springframework . data . mongodb . core . aggregation . Aggregation .* ;
21
21
22
+ import java .time .ZonedDateTime ;
22
23
import java .util .List ;
24
+ import java .util .Set ;
25
+ import java .util .stream .Stream ;
23
26
27
+ import org .assertj .core .api .Assertions ;
28
+ import org .bson .Document ;
24
29
import org .junit .jupiter .api .Test ;
30
+ import org .junit .jupiter .params .ParameterizedTest ;
31
+ import org .junit .jupiter .params .provider .Arguments ;
32
+ import org .junit .jupiter .params .provider .MethodSource ;
33
+
34
+ import org .springframework .data .annotation .Id ;
35
+ import org .springframework .data .convert .ConverterBuilder ;
36
+ import org .springframework .data .convert .CustomConversions ;
37
+ import org .springframework .data .convert .CustomConversions .StoreConversions ;
38
+ import org .springframework .data .domain .Sort .Direction ;
39
+ import org .springframework .data .mongodb .core .convert .MappingMongoConverter ;
40
+ import org .springframework .data .mongodb .core .convert .NoOpDbRefResolver ;
41
+ import org .springframework .data .mongodb .core .convert .QueryMapper ;
42
+ import org .springframework .data .mongodb .core .mapping .Field ;
43
+ import org .springframework .data .mongodb .core .query .Criteria ;
44
+ import org .springframework .data .mongodb .test .util .MongoTestMappingContext ;
25
45
26
46
/**
27
47
* @author Christoph Strobl
@@ -40,4 +60,101 @@ void nonFieldsExposingAggregationOperationContinuesWithSameContextForNextStage()
40
60
verify (stage1 ).toPipelineStages (eq (rootContext ));
41
61
verify (stage2 ).toPipelineStages (eq (rootContext ));
42
62
}
63
+
64
+ @ Test
65
+ void contextShouldCarryOnRelaxedFieldMapping () {
66
+
67
+ MongoTestMappingContext ctx = new MongoTestMappingContext (cfg -> {
68
+ cfg .initialEntitySet (TestRecord .class );
69
+ });
70
+
71
+ MappingMongoConverter mongoConverter = new MappingMongoConverter (NoOpDbRefResolver .INSTANCE , ctx );
72
+
73
+ Aggregation agg = Aggregation .newAggregation (Aggregation .unwind ("layerOne.layerTwo" ),
74
+ project ().and ("layerOne.layerTwo.layerThree" ).as ("layerOne.layerThree" ),
75
+ sort (DESC , "layerOne.layerThree.fieldA" ));
76
+
77
+ AggregationOperationRenderer .toDocument (agg .getPipeline ().getOperations (),
78
+ new RelaxedTypeBasedAggregationOperationContext (TestRecord .class , ctx , new QueryMapper (mongoConverter )));
79
+ }
80
+
81
+ @ Test // GH-4722
82
+ void appliesConversionToValuesUsedInAggregation () {
83
+
84
+ MongoTestMappingContext ctx = new MongoTestMappingContext (cfg -> {
85
+ cfg .initialEntitySet (TestRecord .class );
86
+ });
87
+
88
+ MappingMongoConverter mongoConverter = new MappingMongoConverter (NoOpDbRefResolver .INSTANCE , ctx );
89
+ mongoConverter .setCustomConversions (new CustomConversions (StoreConversions .NONE ,
90
+ Set .copyOf (ConverterBuilder .writing (ZonedDateTime .class , String .class , ZonedDateTime ::toString )
91
+ .andReading (it -> ZonedDateTime .parse (it )).getConverters ())));
92
+ mongoConverter .afterPropertiesSet ();
93
+
94
+ var agg = Aggregation .newAggregation (Aggregation .sort (Direction .DESC , "version" ),
95
+ Aggregation .group ("entityId" ).first (Aggregation .ROOT ).as ("value" ), Aggregation .replaceRoot ("value" ),
96
+ Aggregation .match (Criteria .where ("createdDate" ).lt (ZonedDateTime .now ())) // here is the problem
97
+ );
98
+
99
+ List <Document > document = AggregationOperationRenderer .toDocument (agg .getPipeline ().getOperations (),
100
+ new RelaxedTypeBasedAggregationOperationContext (TestRecord .class , ctx , new QueryMapper (mongoConverter )));
101
+ Assertions .assertThat (document ).last ()
102
+ .extracting (it -> it .getEmbedded (List .of ("$match" , "createdDate" , "$lt" ), Object .class ))
103
+ .isInstanceOf (String .class );
104
+ }
105
+
106
+ @ ParameterizedTest // GH-4722
107
+ @ MethodSource ("studentAggregationContexts" )
108
+ void mapsOperationThatDoesNotExposeDedicatedFieldsCorrectly (AggregationOperationContext aggregationContext ) {
109
+
110
+ var agg = newAggregation (Student .class , Aggregation .unwind ("grades" ), Aggregation .replaceRoot ("grades" ),
111
+ Aggregation .project ("grades" ));
112
+
113
+ List <Document > mappedPipeline = AggregationOperationRenderer .toDocument (agg .getPipeline ().getOperations (),
114
+ aggregationContext );
115
+
116
+ Assertions .assertThat (mappedPipeline ).last ().isEqualTo (Document .parse ("{\" $project\" : {\" grades\" : 1}}" ));
117
+ }
118
+
119
+ private static Stream <Arguments > studentAggregationContexts () {
120
+
121
+ MongoTestMappingContext ctx = new MongoTestMappingContext (cfg -> {
122
+ cfg .initialEntitySet (Student .class );
123
+ });
124
+
125
+ MappingMongoConverter mongoConverter = new MappingMongoConverter (NoOpDbRefResolver .INSTANCE , ctx );
126
+ mongoConverter .afterPropertiesSet ();
127
+
128
+ QueryMapper queryMapper = new QueryMapper (mongoConverter );
129
+
130
+ return Stream .of (
131
+ Arguments
132
+ .of (new TypeBasedAggregationOperationContext (Student .class , ctx , queryMapper , FieldLookupPolicy .strict ())),
133
+ Arguments .of (
134
+ new TypeBasedAggregationOperationContext (Student .class , ctx , queryMapper , FieldLookupPolicy .relaxed ())));
135
+ }
136
+
137
+ record TestRecord (@ Id String field1 , String field2 , LayerOne layerOne ) {
138
+ record LayerOne (List <LayerTwo > layerTwo ) {
139
+ }
140
+
141
+ record LayerTwo (LayerThree layerThree ) {
142
+ }
143
+
144
+ record LayerThree (int fieldA , int fieldB ) {
145
+ }
146
+ }
147
+
148
+ static class Student {
149
+
150
+ @ Field ("mark" ) List <Grade > grades ;
151
+
152
+ }
153
+
154
+ static class Grade {
155
+
156
+ int points ;
157
+ String grades ;
158
+ }
159
+
43
160
}
0 commit comments