2323import org .bson .Document ;
2424import org .jspecify .annotations .NullUnmarked ;
2525import org .jspecify .annotations .Nullable ;
26+
2627import org .springframework .core .annotation .MergedAnnotation ;
2728import org .springframework .data .domain .SliceImpl ;
2829import org .springframework .data .domain .Sort .Order ;
4041import org .springframework .data .mongodb .core .query .BasicUpdate ;
4142import org .springframework .data .mongodb .core .query .Collation ;
4243import org .springframework .data .mongodb .repository .Hint ;
44+ import org .springframework .data .mongodb .repository .Meta ;
4345import org .springframework .data .mongodb .repository .ReadPreference ;
4446import org .springframework .data .mongodb .repository .query .MongoQueryExecution .DeleteExecution ;
4547import org .springframework .data .mongodb .repository .query .MongoQueryExecution .PagedExecution ;
@@ -256,15 +258,13 @@ CodeBlock build() {
256258 updateReference );
257259 } else if (ClassUtils .isAssignable (Long .class , returnType )) {
258260 builder .addStatement ("return $L.matching($L).apply($L).all().getModifiedCount()" ,
259- context .localVariable ("updater" ), queryVariableName ,
260- updateReference );
261+ context .localVariable ("updater" ), queryVariableName , updateReference );
261262 } else {
262263 builder .addStatement ("$T $L = $L.matching($L).apply($L).all().getModifiedCount()" , Long .class ,
263- context .localVariable ("modifiedCount" ), context .localVariable ("updater" ),
264- queryVariableName , updateReference );
264+ context .localVariable ("modifiedCount" ), context .localVariable ("updater" ), queryVariableName ,
265+ updateReference );
265266 builder .addStatement ("return $T.convertNumberToTargetClass($L, $T.class)" , NumberUtils .class ,
266- context .localVariable ("modifiedCount" ),
267- returnType );
267+ context .localVariable ("modifiedCount" ), returnType );
268268 }
269269
270270 return builder .build ();
@@ -319,11 +319,9 @@ CodeBlock build() {
319319 Class <?> returnType = ClassUtils .resolvePrimitiveIfNecessary (queryMethod .getReturnedObjectType ());
320320
321321 builder .addStatement ("$T $L = $L.aggregate($L, $T.class)" , AggregationResults .class ,
322- context .localVariable ("results" ), mongoOpsRef ,
323- aggregationVariableName , outputType );
322+ context .localVariable ("results" ), mongoOpsRef , aggregationVariableName , outputType );
324323 if (!queryMethod .isCollectionQuery ()) {
325- builder .addStatement (
326- "return $T.<$T>firstElement(convertSimpleRawResults($T.class, $L.getMappedResults()))" ,
324+ builder .addStatement ("return $T.<$T>firstElement(convertSimpleRawResults($T.class, $L.getMappedResults()))" ,
327325 CollectionUtils .class , returnType , returnType , context .localVariable ("results" ));
328326 } else {
329327 builder .addStatement ("return convertSimpleRawResults($T.class, $L.getMappedResults())" , returnType ,
@@ -332,8 +330,7 @@ CodeBlock build() {
332330 } else {
333331 if (queryMethod .isSliceQuery ()) {
334332 builder .addStatement ("$T $L = $L.aggregate($L, $T.class)" , AggregationResults .class ,
335- context .localVariable ("results" ), mongoOpsRef ,
336- aggregationVariableName , outputType );
333+ context .localVariable ("results" ), mongoOpsRef , aggregationVariableName , outputType );
337334 builder .addStatement ("boolean $L = $L.getMappedResults().size() > $L.getPageSize()" ,
338335 context .localVariable ("hasNext" ), context .localVariable ("results" ), context .getPageableParameterName ());
339336 builder .addStatement (
@@ -378,12 +375,16 @@ CodeBlock build() {
378375
379376 boolean isProjecting = context .getReturnedType ().isProjecting ();
380377 Class <?> domainType = context .getRepositoryInformation ().getDomainType ();
381- Object actualReturnType = isProjecting ? context .getActualReturnType ().getType ()
378+ Object actualReturnType = queryMethod .getParameters ().hasDynamicProjection () || isProjecting
379+ ? TypeName .get (context .getActualReturnType ().getType ())
382380 : domainType ;
383381
384382 builder .add ("\n " );
385383
386- if (isProjecting ) {
384+ if (queryMethod .getParameters ().hasDynamicProjection ()) {
385+ builder .addStatement ("$T<$T> $L = $L.query($T.class).as($L)" , FindWithQuery .class , actualReturnType ,
386+ context .localVariable ("finder" ), mongoOpsRef , domainType , context .getDynamicProjectionParameterName ());
387+ } else if (isProjecting ) {
387388 builder .addStatement ("$T<$T> $L = $L.query($T.class).as($T.class)" , FindWithQuery .class , actualReturnType ,
388389 context .localVariable ("finder" ), mongoOpsRef , domainType , actualReturnType );
389390 } else {
@@ -400,6 +401,8 @@ CodeBlock build() {
400401 terminatingMethod = "count()" ;
401402 } else if (query .isExists ()) {
402403 terminatingMethod = "exists()" ;
404+ } else if (queryMethod .isStreamQuery ()) {
405+ terminatingMethod = "stream()" ;
403406 } else {
404407 terminatingMethod = Optional .class .isAssignableFrom (context .getReturnType ().toClass ()) ? "one()" : "oneValue()" ;
405408 }
@@ -410,6 +413,12 @@ CodeBlock build() {
410413 } else if (queryMethod .isSliceQuery ()) {
411414 builder .addStatement ("return new $T($L, $L).execute($L)" , SlicedExecution .class ,
412415 context .localVariable ("finder" ), context .getPageableParameterName (), query .name ());
416+ } else if (queryMethod .isScrollQuery ()) {
417+
418+ String scrollPositionParameterName = context .getScrollPositionParameterName ();
419+
420+ builder .addStatement ("return $L.matching($L).scroll($L)" , context .localVariable ("finder" ), query .name (),
421+ scrollPositionParameterName );
413422 } else {
414423 builder .addStatement ("return $L.matching($L).$L" , context .localVariable ("finder" ), query .name (),
415424 terminatingMethod );
@@ -544,8 +553,7 @@ private CodeBlock aggregationOptions(String aggregationVariableName) {
544553
545554 Builder optionsBuilder = CodeBlock .builder ();
546555 optionsBuilder .add ("$T $L = $T.builder()\n " , AggregationOptions .class ,
547- context .localVariable ("aggregationOptions" ),
548- AggregationOptions .class );
556+ context .localVariable ("aggregationOptions" ), AggregationOptions .class );
549557 optionsBuilder .indent ();
550558 for (CodeBlock optionBlock : options ) {
551559 optionsBuilder .add (optionBlock );
@@ -709,7 +717,27 @@ CodeBlock build() {
709717 com .mongodb .ReadPreference .class , readPreference );
710718 }
711719
712- // TODO: Meta annotation
720+ MergedAnnotation <Meta > metaAnnotation = context .getAnnotation (Meta .class );
721+
722+ if (metaAnnotation .isPresent ()) {
723+
724+ long maxExecutionTimeMs = metaAnnotation .getLong ("maxExecutionTimeMs" );
725+ if (maxExecutionTimeMs != -1 ) {
726+ builder .addStatement ("$L.maxTimeMsec($L)" , queryVariableName , maxExecutionTimeMs );
727+ }
728+
729+ int cursorBatchSize = metaAnnotation .getInt ("cursorBatchSize" );
730+ if (cursorBatchSize != 0 ) {
731+ builder .addStatement ("$L.cursorBatchSize($L)" , queryVariableName , cursorBatchSize );
732+ }
733+
734+ String comment = metaAnnotation .getString ("comment" );
735+ if (StringUtils .hasText ("comment" )) {
736+ builder .addStatement ("$L.comment($S)" , queryVariableName , comment );
737+ }
738+ }
739+
740+ // TODO: Meta annotation: Disk usage
713741
714742 return builder .build ();
715743 }
0 commit comments