// Path: grooves-api/src/main/java/com/github/rahulsom/grooves/queries/QuerySupport.java
// public interface QuerySupport<
//         AggregateT,
//         EventIdT,
//         EventT extends BaseEvent<AggregateT, EventIdT, EventT>,
//         SnapshotIdT,
//         SnapshotT extends Snapshot<AggregateT, SnapshotIdT, EventIdT, EventT>
//         >
//         extends
//         TemporalQuerySupport<AggregateT, EventIdT, EventT, SnapshotIdT, SnapshotT>,
//         VersionedQuerySupport<AggregateT, EventIdT, EventT, SnapshotIdT, SnapshotT> {
// 
//     @NotNull
//     @Override
//     default QueryExecutor<AggregateT, EventIdT, EventT, SnapshotIdT, SnapshotT, ?> getExecutor() {
//         return new QueryExecutor<>();
//     }
// 
//     @NotNull
//     @Override
//     default Publisher<EventT> findEventsBefore(@NotNull EventT event) {
//         return VersionedQuerySupport.super.findEventsBefore(event);
//     }
// }
// 
// Path: grooves-api/src/main/java/com/github/rahulsom/grooves/queries/internal/Pair.java
// public class Pair<FirstT, SecondT> {
//     private final FirstT first;
//     private final SecondT second;
// 
//     public Pair(@NotNull FirstT first, @NotNull SecondT second) {
//         this.first = first;
//         this.second = second;
//     }
// 
//     @NotNull public FirstT getFirst() {
//         return first;
//     }
// 
//     @NotNull public SecondT getSecond() {
//         return second;
//     }
// }
// 
// Path: examples/javaee/src/main/java/grooves/example/javaee/Database.java
// @Singleton
// public class Database {
// 
//     private final List<PatientEvent> eventList = new ArrayList<>();
//     private final List<Patient> patientList = new ArrayList<>();
//     private final List snapshotList = new ArrayList();
// 
//     public Stream<PatientEvent> events() {
//         return eventList.stream();
//     }
// 
//     public Stream<Patient> patients() {
//         return patientList.stream();
//     }
// 
//     /**
//      * Finds snapshots of type.
//      *
//      * @param clazz The class representing the type
//      * @param <T>   The type
//      *
//      * @return A Stream of type
//      */
//     @NotNull
//     public <T extends Snapshot> Stream<T> snapshots(Class<T> clazz) {
//         return (Stream<T>) snapshotList
//                 .stream()
//                 .filter(it -> clazz.isAssignableFrom(it.getClass()));
//     }
// 
//     public void addPatient(Patient patient) {
//         patientList.add(patient);
//     }
// 
//     public void addEvent(PatientEvent event) {
//         eventList.add(event);
//     }
// 
//     public void addSnapshot(Object snapshot) {
//         snapshotList.add(snapshot);
//     }
// 
//     public static boolean isTimestampInRange(
//             Date lowerBoundExclusive, Date timestamp, Date upperBoundInclusive) {
//         return (lowerBoundExclusive == null || timestamp.compareTo(lowerBoundExclusive) > 0)
//                 && timestamp.compareTo(upperBoundInclusive) <= 0;
//     }
// 
// }
// 
// Path: examples/javaee/src/main/java/grooves/example/javaee/domain/Patient.java
// @Data
// @Aggregate // <1>
// public class Patient implements Serializable {
//     private Long id;
//     private final String uniqueId;
// }
// 
// Path: examples/javaee/src/main/java/grooves/example/javaee/domain/PatientEvent.java
// @Data
// public abstract class PatientEvent implements BaseEvent<Patient, Long, PatientEvent> { // <1>
//     private Patient aggregate;
//     private Long id;
//     private RevertEvent<Patient, Long, PatientEvent> revertedBy;  // <2>
//     private Date timestamp; // <3>
//     private long position; // <4>
// 
//     // end::documented[]
//     @XmlTransient
//     // tag::documented[]
//     @Override
//     @NotNull
//     public Publisher<Patient> getAggregateObservable() { // <5>
//         return toPublisher(aggregate != null ? just(aggregate) : empty());
//     }
// }
// 
// Path: examples/javaee/src/main/java/grooves/example/javaee/Database.java
// public static boolean isTimestampInRange(
//         Date lowerBoundExclusive, Date timestamp, Date upperBoundInclusive) {
//     return (lowerBoundExclusive == null || timestamp.compareTo(lowerBoundExclusive) > 0)
//             && timestamp.compareTo(upperBoundInclusive) <= 0;
// }


import com.github.rahulsom.grooves.api.EventApplyOutcome;
import com.github.rahulsom.grooves.api.snapshots.Snapshot;
import com.github.rahulsom.grooves.queries.QuerySupport;
import com.github.rahulsom.grooves.queries.internal.Pair;
import grooves.example.javaee.Database;
import grooves.example.javaee.domain.Patient;
import grooves.example.javaee.domain.PatientEvent;
import org.apache.commons.lang3.SerializationUtils;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.reactivestreams.Publisher;
import org.slf4j.LoggerFactory;
import java.io.Serializable;
import java.util.Date;
import java.util.List;
import java.util.Objects;
import java.util.function.Predicate;
import java.util.stream.Stream;
import static com.github.rahulsom.grooves.api.EventApplyOutcome.CONTINUE;
import static grooves.example.javaee.Database.isTimestampInRange;
import static java.util.stream.Collectors.toList;
import static rx.Observable.from;
import static rx.Observable.just;
import static rx.RxReactiveStreams.toObservable;
import static rx.RxReactiveStreams.toPublisher;
package grooves.example.javaee.queries;




// tag::documented[]
public interface CustomQuerySupport<
        SnapshotT extends Snapshot<Patient, Long, Long, PatientEvent> & Serializable // <1>
        > extends QuerySupport<Patient, Long, PatientEvent, Long, SnapshotT> { // <2>

    // end::documented[]
// Path: grooves-api/src/main/java/com/github/rahulsom/grooves/queries/QuerySupport.java
// public interface QuerySupport<
//         AggregateT,
//         EventIdT,
//         EventT extends BaseEvent<AggregateT, EventIdT, EventT>,
//         SnapshotIdT,
//         SnapshotT extends Snapshot<AggregateT, SnapshotIdT, EventIdT, EventT>
//         >
//         extends
//         TemporalQuerySupport<AggregateT, EventIdT, EventT, SnapshotIdT, SnapshotT>,
//         VersionedQuerySupport<AggregateT, EventIdT, EventT, SnapshotIdT, SnapshotT> {
// 
//     @NotNull
//     @Override
//     default QueryExecutor<AggregateT, EventIdT, EventT, SnapshotIdT, SnapshotT, ?> getExecutor() {
//         return new QueryExecutor<>();
//     }
// 
//     @NotNull
//     @Override
//     default Publisher<EventT> findEventsBefore(@NotNull EventT event) {
//         return VersionedQuerySupport.super.findEventsBefore(event);
//     }
// }
// 
// Path: grooves-api/src/main/java/com/github/rahulsom/grooves/queries/internal/Pair.java
// public class Pair<FirstT, SecondT> {
//     private final FirstT first;
//     private final SecondT second;
// 
//     public Pair(@NotNull FirstT first, @NotNull SecondT second) {
//         this.first = first;
//         this.second = second;
//     }
// 
//     @NotNull public FirstT getFirst() {
//         return first;
//     }
// 
//     @NotNull public SecondT getSecond() {
//         return second;
//     }
// }
// 
// Path: examples/javaee/src/main/java/grooves/example/javaee/Database.java
// @Singleton
// public class Database {
// 
//     private final List<PatientEvent> eventList = new ArrayList<>();
//     private final List<Patient> patientList = new ArrayList<>();
//     private final List snapshotList = new ArrayList();
// 
//     public Stream<PatientEvent> events() {
//         return eventList.stream();
//     }
// 
//     public Stream<Patient> patients() {
//         return patientList.stream();
//     }
// 
//     /**
//      * Finds snapshots of type.
//      *
//      * @param clazz The class representing the type
//      * @param <T>   The type
//      *
//      * @return A Stream of type
//      */
//     @NotNull
//     public <T extends Snapshot> Stream<T> snapshots(Class<T> clazz) {
//         return (Stream<T>) snapshotList
//                 .stream()
//                 .filter(it -> clazz.isAssignableFrom(it.getClass()));
//     }
// 
//     public void addPatient(Patient patient) {
//         patientList.add(patient);
//     }
// 
//     public void addEvent(PatientEvent event) {
//         eventList.add(event);
//     }
// 
//     public void addSnapshot(Object snapshot) {
//         snapshotList.add(snapshot);
//     }
// 
//     public static boolean isTimestampInRange(
//             Date lowerBoundExclusive, Date timestamp, Date upperBoundInclusive) {
//         return (lowerBoundExclusive == null || timestamp.compareTo(lowerBoundExclusive) > 0)
//                 && timestamp.compareTo(upperBoundInclusive) <= 0;
//     }
// 
// }
// 
// Path: examples/javaee/src/main/java/grooves/example/javaee/domain/Patient.java
// @Data
// @Aggregate // <1>
// public class Patient implements Serializable {
//     private Long id;
//     private final String uniqueId;
// }
// 
// Path: examples/javaee/src/main/java/grooves/example/javaee/domain/PatientEvent.java
// @Data
// public abstract class PatientEvent implements BaseEvent<Patient, Long, PatientEvent> { // <1>
//     private Patient aggregate;
//     private Long id;
//     private RevertEvent<Patient, Long, PatientEvent> revertedBy;  // <2>
//     private Date timestamp; // <3>
//     private long position; // <4>
// 
//     // end::documented[]
//     @XmlTransient
//     // tag::documented[]
//     @Override
//     @NotNull
//     public Publisher<Patient> getAggregateObservable() { // <5>
//         return toPublisher(aggregate != null ? just(aggregate) : empty());
//     }
// }
// 
// Path: examples/javaee/src/main/java/grooves/example/javaee/Database.java
// public static boolean isTimestampInRange(
//         Date lowerBoundExclusive, Date timestamp, Date upperBoundInclusive) {
//     return (lowerBoundExclusive == null || timestamp.compareTo(lowerBoundExclusive) > 0)
//             && timestamp.compareTo(upperBoundInclusive) <= 0;
// }


// Path: examples/javaee/src/main/java/grooves/example/javaee/queries/CustomQuerySupport.java
import com.github.rahulsom.grooves.api.EventApplyOutcome;
import com.github.rahulsom.grooves.api.snapshots.Snapshot;
import com.github.rahulsom.grooves.queries.QuerySupport;
import com.github.rahulsom.grooves.queries.internal.Pair;
import grooves.example.javaee.Database;
import grooves.example.javaee.domain.Patient;
import grooves.example.javaee.domain.PatientEvent;
import org.apache.commons.lang3.SerializationUtils;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.reactivestreams.Publisher;
import org.slf4j.LoggerFactory;
import java.io.Serializable;
import java.util.Date;
import java.util.List;
import java.util.Objects;
import java.util.function.Predicate;
import java.util.stream.Stream;
import static com.github.rahulsom.grooves.api.EventApplyOutcome.CONTINUE;
import static grooves.example.javaee.Database.isTimestampInRange;
import static java.util.stream.Collectors.toList;
import static rx.Observable.from;
import static rx.Observable.just;
import static rx.RxReactiveStreams.toObservable;
import static rx.RxReactiveStreams.toPublisher;

package grooves.example.javaee.queries;




// tag::documented[]
public interface CustomQuerySupport<
        SnapshotT extends Snapshot<Patient, Long, Long, PatientEvent> & Serializable // <1>
        > extends QuerySupport<Patient, Long, PatientEvent, Long, SnapshotT> { // <2>

    // end::documented[]
    Database getDatabase();