19
19
import static org .springframework .data .domain .Sort .Direction .*;
20
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 ;
25
33
26
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 ;
27
39
import org .springframework .data .mongodb .core .convert .MappingMongoConverter ;
28
40
import org .springframework .data .mongodb .core .convert .NoOpDbRefResolver ;
29
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 ;
30
44
import org .springframework .data .mongodb .test .util .MongoTestMappingContext ;
31
45
32
46
/**
@@ -47,32 +61,100 @@ void nonFieldsExposingAggregationOperationContinuesWithSameContextForNextStage()
47
61
verify (stage2 ).toPipelineStages (eq (rootContext ));
48
62
}
49
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
+
50
137
record TestRecord (@ Id String field1 , String field2 , LayerOne layerOne ) {
51
138
record LayerOne (List <LayerTwo > layerTwo ) {
52
139
}
53
140
54
141
record LayerTwo (LayerThree layerThree ) {
55
142
}
56
143
57
- record LayerThree (int fieldA , int fieldB )
58
- { }
144
+ record LayerThree (int fieldA , int fieldB ) {
145
+ }
59
146
}
60
147
61
- @ Test
62
- void xxx () {
148
+ static class Student {
63
149
64
- MongoTestMappingContext ctx = new MongoTestMappingContext (cfg -> {
65
- cfg .initialEntitySet (TestRecord .class );
66
- });
150
+ @ Field ("mark" ) List <Grade > grades ;
67
151
68
- MappingMongoConverter mongoConverter = new MappingMongoConverter ( NoOpDbRefResolver . INSTANCE , ctx );
152
+ }
69
153
70
- Aggregation agg = Aggregation .newAggregation (
71
- Aggregation .unwind ("layerOne.layerTwo" ),
72
- project ().and ("layerOne.layerTwo.layerThree" ).as ("layerOne.layerThree" ),
73
- sort (DESC , "layerOne.layerThree.fieldA" )
74
- );
154
+ static class Grade {
75
155
76
- AggregationOperationRenderer .toDocument (agg .getPipeline ().getOperations (), new RelaxedTypeBasedAggregationOperationContext (TestRecord .class , ctx , new QueryMapper (mongoConverter )));
156
+ int points ;
157
+ String grades ;
77
158
}
159
+
78
160
}
0 commit comments