// Path: grooves-api/src/main/java/com/github/rahulsom/grooves/queries/internal/SimpleExecutor.java
// public class SimpleExecutor<
//         AggregateT,
//         EventIdT,
//         EventT extends BaseEvent<AggregateT, EventIdT, EventT>,
//         ApplicableEventT extends EventT,
//         SnapshotIdT,
//         SnapshotT extends BaseSnapshot<AggregateT, SnapshotIdT, EventIdT, EventT>,
//         QueryT extends
//                 SimpleQuery<AggregateT, EventIdT, EventT, ApplicableEventT, SnapshotIdT, SnapshotT>
//         > extends
//         QueryExecutor<AggregateT, EventIdT, EventT, SnapshotIdT, SnapshotT, QueryT> {
// 
//     @NotNull
//     @Override
//     protected Flowable<EventApplyOutcome> callMethod(
//             @NotNull QueryT query,
//             @NotNull String methodName,
//             @NotNull SnapshotT snapshot,
//             @NotNull EventT event) {
//         return fromPublisher(query.applyEvent((ApplicableEventT) event, snapshot));
//     }
// }
// 
// Path: grooves-api/src/main/java/com/github/rahulsom/grooves/queries/internal/SimpleQuery.java
// public interface SimpleQuery<
//         AggregateT,
//         EventIdT,
//         EventT extends BaseEvent<AggregateT, EventIdT, EventT>,
//         ApplicableEventT extends EventT,
//         SnapshotIdT,
//         SnapshotT extends BaseSnapshot<AggregateT, SnapshotIdT, EventIdT, EventT>
//         > extends
//         BaseQuery<AggregateT, EventIdT, EventT, SnapshotIdT, SnapshotT> {
// 
//     @NotNull Publisher<EventApplyOutcome> applyEvent(
//             @NotNull ApplicableEventT event, @NotNull SnapshotT snapshot);
// 
//     @NotNull
//     @Override
//     default SimpleExecutor<AggregateT, EventIdT, EventT, ?, SnapshotIdT, SnapshotT,
//             ?> getExecutor() {
//         return new SimpleExecutor<>();
//     }
// }


import com.github.rahulsom.grooves.api.EventApplyOutcome;
import com.github.rahulsom.grooves.api.events.BaseEvent;
import com.github.rahulsom.grooves.api.snapshots.VersionedSnapshot;
import com.github.rahulsom.grooves.queries.internal.SimpleExecutor;
import com.github.rahulsom.grooves.queries.internal.SimpleQuery;
import org.jetbrains.annotations.NotNull;
import org.reactivestreams.Publisher;
import java.util.function.BiConsumer;
import java.util.function.BiFunction;
import java.util.function.Predicate;
import java.util.function.Supplier;
package com.github.rahulsom.grooves.queries;



/**
 * Util class to build Versioned Queries in a Functional Style.
 *
 * @param <AggregateT>   The aggregate over which the query executes
 * @param <EventIdT>     The type of the EventT's id field
 * @param <EventT>       The type of the Event
 * @param <SnapshotIdT>  The type of the SnapshotT's id field
 * @param <SnapshotT>    The type of the Snapshot
 *
 * @author Rahul Somasunderam
 */
public class FunctionalVersionedQuery<
        AggregateT,
        EventIdT,
        EventT extends BaseEvent<AggregateT, EventIdT, EventT>,
        SnapshotIdT,
        SnapshotT extends VersionedSnapshot<AggregateT, SnapshotIdT, EventIdT,
                EventT>
        > implements
        VersionedQuerySupport<AggregateT, EventIdT, EventT, SnapshotIdT, SnapshotT
                >,
        SimpleQuery<AggregateT, EventIdT, EventT, EventT, SnapshotIdT, SnapshotT
                > {

    private BiFunction<Long, AggregateT, Publisher<SnapshotT>> snapshot;
    private Supplier<SnapshotT> emptySnapshot;
    private TriFunction<AggregateT, SnapshotT, Long, Publisher<EventT>> events;
    private Predicate<SnapshotT> applyEvents;
    private BiConsumer<SnapshotT, AggregateT> deprecator;
    private TriFunction<Exception, SnapshotT, EventT,
            Publisher<EventApplyOutcome>> exceptionHandler;
    private BiFunction<EventT, SnapshotT, Publisher<EventApplyOutcome>> eventHandler;

    private FunctionalVersionedQuery() {
    }

    @NotNull
    @Override
// Path: grooves-api/src/main/java/com/github/rahulsom/grooves/queries/internal/SimpleExecutor.java
// public class SimpleExecutor<
//         AggregateT,
//         EventIdT,
//         EventT extends BaseEvent<AggregateT, EventIdT, EventT>,
//         ApplicableEventT extends EventT,
//         SnapshotIdT,
//         SnapshotT extends BaseSnapshot<AggregateT, SnapshotIdT, EventIdT, EventT>,
//         QueryT extends
//                 SimpleQuery<AggregateT, EventIdT, EventT, ApplicableEventT, SnapshotIdT, SnapshotT>
//         > extends
//         QueryExecutor<AggregateT, EventIdT, EventT, SnapshotIdT, SnapshotT, QueryT> {
// 
//     @NotNull
//     @Override
//     protected Flowable<EventApplyOutcome> callMethod(
//             @NotNull QueryT query,
//             @NotNull String methodName,
//             @NotNull SnapshotT snapshot,
//             @NotNull EventT event) {
//         return fromPublisher(query.applyEvent((ApplicableEventT) event, snapshot));
//     }
// }
// 
// Path: grooves-api/src/main/java/com/github/rahulsom/grooves/queries/internal/SimpleQuery.java
// public interface SimpleQuery<
//         AggregateT,
//         EventIdT,
//         EventT extends BaseEvent<AggregateT, EventIdT, EventT>,
//         ApplicableEventT extends EventT,
//         SnapshotIdT,
//         SnapshotT extends BaseSnapshot<AggregateT, SnapshotIdT, EventIdT, EventT>
//         > extends
//         BaseQuery<AggregateT, EventIdT, EventT, SnapshotIdT, SnapshotT> {
// 
//     @NotNull Publisher<EventApplyOutcome> applyEvent(
//             @NotNull ApplicableEventT event, @NotNull SnapshotT snapshot);
// 
//     @NotNull
//     @Override
//     default SimpleExecutor<AggregateT, EventIdT, EventT, ?, SnapshotIdT, SnapshotT,
//             ?> getExecutor() {
//         return new SimpleExecutor<>();
//     }
// }


// Path: grooves-api/src/main/java/com/github/rahulsom/grooves/queries/FunctionalVersionedQuery.java
import com.github.rahulsom.grooves.api.EventApplyOutcome;
import com.github.rahulsom.grooves.api.events.BaseEvent;
import com.github.rahulsom.grooves.api.snapshots.VersionedSnapshot;
import com.github.rahulsom.grooves.queries.internal.SimpleExecutor;
import com.github.rahulsom.grooves.queries.internal.SimpleQuery;
import org.jetbrains.annotations.NotNull;
import org.reactivestreams.Publisher;
import java.util.function.BiConsumer;
import java.util.function.BiFunction;
import java.util.function.Predicate;
import java.util.function.Supplier;

package com.github.rahulsom.grooves.queries;



/**
 * Util class to build Versioned Queries in a Functional Style.
 *
 * @param <AggregateT>   The aggregate over which the query executes
 * @param <EventIdT>     The type of the EventT's id field
 * @param <EventT>       The type of the Event
 * @param <SnapshotIdT>  The type of the SnapshotT's id field
 * @param <SnapshotT>    The type of the Snapshot
 *
 * @author Rahul Somasunderam
 */
public class FunctionalVersionedQuery<
        AggregateT,
        EventIdT,
        EventT extends BaseEvent<AggregateT, EventIdT, EventT>,
        SnapshotIdT,
        SnapshotT extends VersionedSnapshot<AggregateT, SnapshotIdT, EventIdT,
                EventT>
        > implements
        VersionedQuerySupport<AggregateT, EventIdT, EventT, SnapshotIdT, SnapshotT
                >,
        SimpleQuery<AggregateT, EventIdT, EventT, EventT, SnapshotIdT, SnapshotT
                > {

    private BiFunction<Long, AggregateT, Publisher<SnapshotT>> snapshot;
    private Supplier<SnapshotT> emptySnapshot;
    private TriFunction<AggregateT, SnapshotT, Long, Publisher<EventT>> events;
    private Predicate<SnapshotT> applyEvents;
    private BiConsumer<SnapshotT, AggregateT> deprecator;
    private TriFunction<Exception, SnapshotT, EventT,
            Publisher<EventApplyOutcome>> exceptionHandler;
    private BiFunction<EventT, SnapshotT, Publisher<EventApplyOutcome>> eventHandler;

    private FunctionalVersionedQuery() {
    }

    @NotNull
    @Override
    public SimpleExecutor<AggregateT, EventIdT, EventT, ?, SnapshotIdT, SnapshotT,