1717
1818import java .nio .ByteBuffer ;
1919import java .util .Map ;
20- import java .util .Optional ;
2120
2221import org .jspecify .annotations .NullUnmarked ;
2322import org .jspecify .annotations .Nullable ;
3938import org .springframework .data .convert .CustomConversions ;
4039import org .springframework .data .domain .Limit ;
4140import org .springframework .data .domain .Sort ;
41+ import org .springframework .data .javapoet .LordOfTheStrings ;
42+ import org .springframework .data .javapoet .TypeNames ;
4243import org .springframework .data .repository .aot .generate .AotQueryMethodGenerationContext ;
44+ import org .springframework .data .repository .aot .generate .MethodReturn ;
4345import org .springframework .javapoet .CodeBlock ;
4446import org .springframework .javapoet .CodeBlock .Builder ;
4547import org .springframework .javapoet .TypeName ;
@@ -88,7 +90,6 @@ static class QueryBlockBuilder {
8890
8991 private final AotQueryMethodGenerationContext context ;
9092 private final CassandraQueryMethod queryMethod ;
91- private final String parameterNames ;
9293
9394 private @ Nullable AotQuery query ;
9495 private String queryVariableName ;
@@ -98,14 +99,6 @@ static class QueryBlockBuilder {
9899
99100 this .context = context ;
100101 this .queryMethod = queryMethod ;
101-
102- String parameterNames = StringUtils .collectionToDelimitedString (context .getAllParameterNames (), ", " );
103-
104- if (StringUtils .hasText (parameterNames )) {
105- this .parameterNames = ", " + parameterNames ;
106- } else {
107- this .parameterNames = "" ;
108- }
109102 }
110103
111104 QueryBlockBuilder query (AotQuery query ) {
@@ -178,8 +171,7 @@ private CodeBlock buildQuery(StringAotQuery query) {
178171 for (ParameterBinding binding : query .getParameterBindings ()) {
179172
180173 // TODO:Conversion, Data type
181- builder .addStatement ("$1L[$2L] = $3L" , context .localVariable ("args" ), index ++,
182- getParameter (binding .getOrigin ()));
174+ builder .addStatement ("$1L[$2L] = $3L" , context .localVariable ("args" ), index ++, getParameter (binding ));
183175 }
184176
185177 builder .addStatement ("$1T $2L = $1T.newInstance($3S, $4L)" , SimpleStatement .class , queryVariableName ,
@@ -259,28 +251,22 @@ private CodeBlock buildQuery(org.springframework.data.cassandra.core.query.Query
259251 return queryBuilder .build ();
260252 }
261253
262- boolean first = true ;
263- queryBuilder .add ("$[" );
264- queryBuilder .add ("$1T $2L = $1T.query(" , org .springframework .data .cassandra .core .query .Query .class ,
265- queryVariableName );
254+ LordOfTheStrings .CodeBlockBuilder CodeBlockBuilder = LordOfTheStrings .builder (queryBuilder );
255+ CodeBlockBuilder .addStatement (it -> {
256+ it .add ("$1T $2L = $1T.query(" , org .springframework .data .cassandra .core .query .Query .class , queryVariableName );
266257
267- for ( CriteriaDefinition criteriaDefinition : query ) {
258+ it . addAll ( query , ".and(" , ( criteria ) -> {
268259
269- if (first ) {
270- first = false ;
271- } else {
272- queryBuilder .add (".and(" );
273- }
260+ LordOfTheStrings .CodeBlockBuilder builder = LordOfTheStrings .builder ("$1T.where($2S)" , Criteria .class ,
261+ criteria .getColumnName ().toCql ());
262+ appendPredicate (criteria , builder );
263+ builder .add (")" );
274264
275- queryBuilder .add ("$1T.where($2S)" , Criteria .class , criteriaDefinition .getColumnName ().toCql ());
276- appendPredicate (criteriaDefinition , queryBuilder );
277-
278- queryBuilder .add (")" );
279- }
265+ return builder .build ();
266+ });
267+ });
280268
281- queryBuilder .add (";\n $]" );
282-
283- return queryBuilder .build ();
269+ return CodeBlockBuilder .build ();
284270 }
285271
286272 private CodeBlock buildColumns (Columns columns ) {
@@ -368,27 +354,21 @@ private CodeBlock buildSortScrollLimit(DerivedAotQuery derived,
368354
369355 private static CodeBlock buildSort (Sort sort ) {
370356
371- Builder sortBuilder = CodeBlock .builder ();
372- sortBuilder .add ("$T.by(" , Sort .class );
357+ LordOfTheStrings .InvocationBuilder invocation = LordOfTheStrings .invoke ("$T.by($L)" , Sort .class );
373358
374- boolean first = true ;
375- for (Sort .Order order : sort ) {
359+ invocation .arguments (sort , order -> {
376360
377- sortBuilder .add ("$T.$L($S)" , Sort .Order .class , order .isAscending () ? "asc" : "desc" , order .getProperty ());
378- if (order .isIgnoreCase ()) {
379- sortBuilder .add (".ignoreCase()" );
380- }
361+ LordOfTheStrings .CodeBlockBuilder builder = LordOfTheStrings .builder ("$T.$L($S)" , Sort .Order .class ,
362+ order .isAscending () ? "asc" : "desc" , order .getProperty ());
381363
382- if (first ) {
383- first = false ;
384- } else {
385- sortBuilder .add (", " );
364+ if (order .isIgnoreCase ()) {
365+ builder .add (".ignoreCase()" );
386366 }
387- }
388367
389- sortBuilder .add (")" );
368+ return builder .build ();
369+ });
390370
391- return sortBuilder .build ();
371+ return invocation .build ();
392372 }
393373
394374 private CodeBlock buildQueryOptions (DerivedAotQuery derived ) {
@@ -456,7 +436,8 @@ private void applyOptions(Limit limit, Builder builder) {
456436 }
457437 }
458438
459- private void appendPredicate (CriteriaDefinition criteriaDefinition , Builder criteriaBuilder ) {
439+ private void appendPredicate (CriteriaDefinition criteriaDefinition ,
440+ LordOfTheStrings .CodeBlockBuilder criteriaBuilder ) {
460441
461442 CriteriaDefinition .Predicate predicate = criteriaDefinition .getPredicate ();
462443
@@ -524,42 +505,26 @@ String getParameterName(ParameterBinding binding) {
524505 throw new UnsupportedOperationException ("Unsupported origin: " + binding .getOrigin ());
525506 }
526507
527- private CodeBlock getParameter (ParameterBinding . ParameterOrigin origin ) {
508+ private CodeBlock getParameter (ParameterBinding binding ) {
528509
510+ ParameterBinding .ParameterOrigin origin = binding .getOrigin ();
529511 if (origin .isMethodArgument () && origin instanceof ParameterBinding .MethodInvocationArgument mia ) {
530-
531- CodeBlock .Builder builder = CodeBlock .builder ();
532-
533- builder .add ("potentiallyConvertBindingValue(" );
534-
535- if (mia .identifier ().hasPosition ()) {
536- builder .add ("$L" , context .getRequiredBindableParameterName (mia .identifier ().getPosition ()));
537- } else if (mia .identifier ().hasName ()) {
538- builder .add ("$L" , context .getMethodParameter (mia .identifier ().getName ()).getParameterName ());
539- }
540- else {
541- throw new IllegalStateException (
542- "MethodInvocationArgument '%s' does not define a name or a position" .formatted (mia ));
543- }
544- builder .add (")" );
545-
546- return builder .build ();
512+ return CodeBlock .of ("potentiallyConvertBindingValue($L)" , getParameterName (binding ));
547513 }
548514
549515 if (origin .isExpression () && origin instanceof ParameterBinding .Expression expr ) {
550516
551- Builder builder = CodeBlock .builder ();
552-
553517 String expressionString = expr .expression ().getExpressionString ();
554518 // re-wrap expression
555519 if (!expressionString .startsWith ("$" )) {
556520 expressionString = "#{" + expressionString + "}" ;
557521 }
558522
559- builder .add ("evaluateExpression($L, $S$L)" , context .getExpressionMarker ().enclosingMethod (), expressionString ,
560- parameterNames );
561-
562- return builder .build ();
523+ return LordOfTheStrings .invoke ("evaluateExpression($L)" )
524+ .argument (context .getExpressionMarker ().enclosingMethod ()) //
525+ .argument ("$S" , expressionString ) //
526+ .arguments (context .getAllParameterNames ()) //
527+ .build ();
563528 }
564529
565530 throw new UnsupportedOperationException ("Not supported yet for: " + origin );
@@ -598,43 +563,49 @@ QueryExecutionBlockBuilder usingQueryVariableName(String queryVariableName) {
598563 CodeBlock build () {
599564
600565 Builder builder = CodeBlock .builder ();
566+ MethodReturn methodReturn = context .getMethodReturn ();
601567
602568 boolean isProjecting = !query .isCount () && !query .isExists ()
603- && (context .getReturnedType ().isProjecting ()
604- && !customConversions .isSimpleType (context .getReturnedType ().getReturnedType ()))
569+ && (context .getMethodReturn ().isProjecting ()
570+ && !customConversions .isSimpleType (context .getMethodReturn ().toClass ()))
605571 || StringUtils .hasText (context .getDynamicProjectionParameterName ());
606572 Class <?> domainType = context .getRepositoryInformation ().getDomainType ();
607573
608574 builder .add ("\n " );
609575
610576 if (query .isDelete ()) {
611577
578+ LordOfTheStrings .InvocationBuilder method ;
612579 if (query instanceof StringAotQuery ) {
613580
614- builder . addStatement ( "boolean $1L = $2L .getCqlOperations().execute($3L)" , context . localVariable ( "result" ) ,
581+ method = LordOfTheStrings . invoke ( "$L .getCqlOperations().execute($L)" ,
615582 context .fieldNameOf (CassandraOperations .class ), queryVariableName );
616583 } else {
617- builder . addStatement ( "boolean $1L = $2L .delete($3L , $4T .class)" , context .localVariable ( "result" ),
618- context . fieldNameOf ( CassandraOperations . class ), queryVariableName , domainType );
584+ method = LordOfTheStrings . invoke ( "$L .delete($L , $T .class)" , context .fieldNameOf ( CassandraOperations . class ),
585+ queryVariableName , domainType );
619586 }
620587
621- if (context .getReturnType ().isAssignableFrom (Boolean .class )
622- || context .getReturnType ().isAssignableFrom (Boolean .TYPE )) {
623- builder .addStatement ("return $1L" , context .localVariable ("result" ));
588+ if (methodReturn .isVoid ()) {
589+ builder .addStatement (method .build ());
590+ } else {
591+ builder .addStatement (method .assignTo ("boolean $L" , context .localVariable ("result" )));
624592 }
625593
594+ builder .addStatement (LordOfTheStrings .returning (methodReturn .toClass ()) //
595+ .whenBoolean ("$L" , context .localVariable ("result" )) //
596+ .build ());
597+
626598 return builder .build ();
627599 }
628600
629- boolean isInterfaceProjection = context . getActualReturnType (). toClass (). isInterface ();
601+ boolean isInterfaceProjection = methodReturn . isInterfaceProjection ();
630602 boolean requiresConversion = false ;
631603
632- boolean isMapProjection = Map . class . isAssignableFrom ( context . getActualReturnType (). toClass () );
633- boolean rawProjection = isMapProjection || ResultSet . class . isAssignableFrom ( context . getReturnType (). toClass () );
604+ boolean isMapProjection = methodReturn . getActualReturnClass (). equals ( Map . class );
605+ boolean rawProjection = isMapProjection || methodReturn . toClass (). equals ( ResultSet . class );
634606
635- TypeName actualReturnType = isMapProjection
636- ? TypeName .get (Map .class )
637- : context .getActualReturnTypeName ();
607+ TypeName actualReturnType = isMapProjection ? methodReturn .getActualClassName ()
608+ : TypeNames .typeNameOrWrapper (methodReturn .getActualType ());
638609 Object asDynamicTypeNameOrProjectionTypeParameter = actualReturnType ;
639610
640611 if (StringUtils .hasText (context .getDynamicProjectionParameterName ())) {
@@ -703,54 +674,52 @@ CodeBlock build() {
703674 } else if (query .isLimited ()) {
704675 terminatingMethod = "firstValue()" ;
705676 } else {
706- terminatingMethod = Optional . class . isAssignableFrom ( context . getReturnType (). toClass ()) ? "one()" : "oneValue()" ;
677+ terminatingMethod = "oneValue()" ;
707678 }
708679
709680 Builder execution = CodeBlock .builder ();
710681
711682 if (queryMethod .isScrollQuery ()) {
712683 execution .add ("$T.of($L.$L)" , WindowUtil .class , context .localVariable ("select" ), terminatingMethod );
713- } else if (context . getReturnType () .isArray ()) {
684+ } else if (methodReturn .isArray ()) {
714685 execution .add ("$L.$L.toArray(new $T[0])" , context .localVariable ("select" ), terminatingMethod ,
715- context . getActualReturnTypeName ());
686+ methodReturn . getActualClassName ());
716687 } else {
717688
718689 if (rawProjection && isMapProjection ) {
719- execution .add ("($T) $L.$L" , context . getReturnType (). toClass (), context .localVariable ("select" ),
690+ execution .add ("($T) $L.$L" , methodReturn . getClassName (), context .localVariable ("select" ),
720691 terminatingMethod );
721692 } else {
722693 execution .add ("$L.$L" , context .localVariable ("select" ), terminatingMethod );
723694 }
724695 }
725696
697+ LordOfTheStrings .TypedReturnBuilder returnBuilder = LordOfTheStrings .returning (methodReturn .toClass ());
726698 if (requiresConversion ) {
727699
728- if (Optional .class .isAssignableFrom (context .getReturnType ().toClass ())) {
729- builder .addStatement ("return ($T) $T.ofNullable(convertOne($L, $T.class))" , context .getReturnTypeName (),
730- Optional .class , execution .build (), actualReturnType );
731- } else {
732-
733- String conversionMethod ;
734-
735- if (queryMethod .isCollectionQuery () || queryMethod .isPageQuery () || queryMethod .isSliceQuery ()
736- || queryMethod .isStreamQuery ()) {
737- conversionMethod = "convertMany" ;
738- } else {
739- conversionMethod = "convertOne" ;
740- }
700+ String conversionMethod ;
741701
742- builder .addStatement ("return ($T) $L($L, $T.class)" , context .getReturnTypeName (), conversionMethod ,
743- execution .build (), actualReturnType );
702+ if (queryMethod .isCollectionQuery () || queryMethod .isPageQuery () || queryMethod .isSliceQuery ()
703+ || queryMethod .isStreamQuery ()) {
704+ conversionMethod = "convertMany" ;
705+ } else {
706+ conversionMethod = "convertOne" ;
744707 }
745708
709+ builder .addStatement (returnBuilder //
710+ .optional ("($T) $L($L, $T.class)" , methodReturn .getTypeName (), conversionMethod , execution .build (),
711+ actualReturnType ) //
712+ .build ());
746713 } else {
747714
748- if (query .isCount () && (context .getReturnType ().isAssignableFrom (Integer .class )
749- || context .getReturnType ().isAssignableFrom (int .class ))) {
750- builder .addStatement ("return (int) $L" , execution .build ());
751- } else {
752- builder .addStatement ("return $L" , execution .build ());
715+ CodeBlock executionBlock = execution .build ();
716+
717+ if (query .isCount ()) {
718+ returnBuilder .whenPrimitiveOrBoxed (Integer .class , "(int) $L" , executionBlock );
753719 }
720+
721+ builder .addStatement (returnBuilder .optional (executionBlock ) //
722+ .build ());
754723 }
755724
756725 return builder .build ();
0 commit comments