// Path: grooves-groovy/src/main/java/com/github/rahulsom/grooves/groovy/transformations/internal/QueryASTTransformation.java
// @GroovyASTTransformation
// public class QueryASTTransformation extends AbstractASTTransformation {
// 
//     private static final Class<Query> MY_CLASS = Query.class;
//     private static final ClassNode MY_TYPE = ClassHelper.make(MY_CLASS);
//     private final Logger log = Logger.getLogger(getClass().getName());
// 
//     @Override
//     public void visit(ASTNode[] nodes, SourceUnit source) {
//         init(nodes, source);
//         AnnotatedNode annotatedNode = (AnnotatedNode) nodes[1];
//         final AnnotationNode annotationNode = (AnnotationNode) nodes[0];
// 
//         if (MY_TYPE.equals(annotationNode.getClassNode()) && annotatedNode instanceof ClassNode) {
//             final Expression theSnapshot = annotationNode.getMember("snapshot");
//             Expression theAggregate = annotationNode.getMember("aggregate");
//             final ClassNode theClassNode = (ClassNode) annotatedNode;
//             log.fine("Checking " + theClassNode.getNameWithoutPackage() + " for methods");
//             List<ClassNode> eventClasses =
//                     AggregateASTTransformation.getEventsForAggregate(
//                             theAggregate.getType().getName());
// 
//             eventClasses.forEach(eventClass -> {
//                 final String methodName = "apply" + eventClass.getNameWithoutPackage();
//                 log.fine("  -> Checking for " + methodName);
// 
//                 List<MethodNode> methodsByName =
//                         theClassNode.getMethods().stream()
//                                 .filter(it -> it.getName().equals(methodName))
//                                 .collect(Collectors.toList());
// 
//                 final String methodSignature = String.format("%s %s(%s event, %s snapshot)",
//                         getObservableEventApplyOutcome(), methodName,
//                         eventClass.getName(), theSnapshot.getType().getName());
// 
//                 final String methodSignatureString = String.valueOf(methodSignature);
//                 if (methodsByName.isEmpty()) {
//                     addError(
//                             String.format("Missing expected method %s", methodSignatureString),
//                             annotationNode);
//                 } else {
//                     Optional<MethodNode> matchingMethod = methodsByName.stream()
//                             .filter(implMethod -> {
//                                 final Parameter[] parameters = implMethod.getParameters();
//                                 final ClassNode returnType = implMethod.getReturnType();
//                                 return parameters != null && parameters.length == 2
//                                         && returnType.getName()
//                                                 .equals(Publisher.class.getName())
//                                         && returnType.getGenericsTypes()[0].getType().getName()
//                                                 .equals(EventApplyOutcome.class.getName())
//                                         && parameters[0].getType().getName()
//                                                 .equals(eventClass.getName())
//                                         && parameters[1].getType().getName()
//                                                 .equals(theSnapshot.getType().getName());
//                             })
//                             .findFirst();
// 
//                     if (!matchingMethod.isPresent()) {
//                         addError(String.format("Missing expected method %s. %s",
//                                 methodSignatureString, "Signature was different when name matched"),
//                                 annotationNode);
//                     }
//                 }
//             });
// 
//         }
// 
//     }
// 
//     private String getObservableEventApplyOutcome() {
//         return ClassHelper.make(Publisher.class).getName() + "<"
//                 + ClassHelper.make(EventApplyOutcome.class).getName() + ">";
//     }
// }


import com.github.rahulsom.grooves.api.snapshots.Snapshot;
import com.github.rahulsom.grooves.groovy.transformations.internal.QueryASTTransformation;
import org.codehaus.groovy.transform.GroovyASTTransformationClass;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
package com.github.rahulsom.grooves.groovy.transformations;



/**
 * Marks a class as a Query.
 *
 * <p>The query is something that computes a snapshot out of an aggregate and a collection of events
 *
 * @author Rahul Somasunderam
 */
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.SOURCE)
// Path: grooves-groovy/src/main/java/com/github/rahulsom/grooves/groovy/transformations/internal/QueryASTTransformation.java
// @GroovyASTTransformation
// public class QueryASTTransformation extends AbstractASTTransformation {
// 
//     private static final Class<Query> MY_CLASS = Query.class;
//     private static final ClassNode MY_TYPE = ClassHelper.make(MY_CLASS);
//     private final Logger log = Logger.getLogger(getClass().getName());
// 
//     @Override
//     public void visit(ASTNode[] nodes, SourceUnit source) {
//         init(nodes, source);
//         AnnotatedNode annotatedNode = (AnnotatedNode) nodes[1];
//         final AnnotationNode annotationNode = (AnnotationNode) nodes[0];
// 
//         if (MY_TYPE.equals(annotationNode.getClassNode()) && annotatedNode instanceof ClassNode) {
//             final Expression theSnapshot = annotationNode.getMember("snapshot");
//             Expression theAggregate = annotationNode.getMember("aggregate");
//             final ClassNode theClassNode = (ClassNode) annotatedNode;
//             log.fine("Checking " + theClassNode.getNameWithoutPackage() + " for methods");
//             List<ClassNode> eventClasses =
//                     AggregateASTTransformation.getEventsForAggregate(
//                             theAggregate.getType().getName());
// 
//             eventClasses.forEach(eventClass -> {
//                 final String methodName = "apply" + eventClass.getNameWithoutPackage();
//                 log.fine("  -> Checking for " + methodName);
// 
//                 List<MethodNode> methodsByName =
//                         theClassNode.getMethods().stream()
//                                 .filter(it -> it.getName().equals(methodName))
//                                 .collect(Collectors.toList());
// 
//                 final String methodSignature = String.format("%s %s(%s event, %s snapshot)",
//                         getObservableEventApplyOutcome(), methodName,
//                         eventClass.getName(), theSnapshot.getType().getName());
// 
//                 final String methodSignatureString = String.valueOf(methodSignature);
//                 if (methodsByName.isEmpty()) {
//                     addError(
//                             String.format("Missing expected method %s", methodSignatureString),
//                             annotationNode);
//                 } else {
//                     Optional<MethodNode> matchingMethod = methodsByName.stream()
//                             .filter(implMethod -> {
//                                 final Parameter[] parameters = implMethod.getParameters();
//                                 final ClassNode returnType = implMethod.getReturnType();
//                                 return parameters != null && parameters.length == 2
//                                         && returnType.getName()
//                                                 .equals(Publisher.class.getName())
//                                         && returnType.getGenericsTypes()[0].getType().getName()
//                                                 .equals(EventApplyOutcome.class.getName())
//                                         && parameters[0].getType().getName()
//                                                 .equals(eventClass.getName())
//                                         && parameters[1].getType().getName()
//                                                 .equals(theSnapshot.getType().getName());
//                             })
//                             .findFirst();
// 
//                     if (!matchingMethod.isPresent()) {
//                         addError(String.format("Missing expected method %s. %s",
//                                 methodSignatureString, "Signature was different when name matched"),
//                                 annotationNode);
//                     }
//                 }
//             });
// 
//         }
// 
//     }
// 
//     private String getObservableEventApplyOutcome() {
//         return ClassHelper.make(Publisher.class).getName() + "<"
//                 + ClassHelper.make(EventApplyOutcome.class).getName() + ">";
//     }
// }


// Path: grooves-groovy/src/main/java/com/github/rahulsom/grooves/groovy/transformations/Query.java
import com.github.rahulsom.grooves.api.snapshots.Snapshot;
import com.github.rahulsom.grooves.groovy.transformations.internal.QueryASTTransformation;
import org.codehaus.groovy.transform.GroovyASTTransformationClass;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

package com.github.rahulsom.grooves.groovy.transformations;



/**
 * Marks a class as a Query.
 *
 * <p>The query is something that computes a snapshot out of an aggregate and a collection of events
 *
 * @author Rahul Somasunderam
 */
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.SOURCE)
@GroovyASTTransformationClass(classes = QueryASTTransformation.class)