// 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);
//     }
// }


import com.github.rahulsom.grooves.api.events.BaseEvent;
import com.github.rahulsom.grooves.api.snapshots.Snapshot;
import com.github.rahulsom.grooves.queries.QuerySupport;
import org.jetbrains.annotations.NotNull;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.Date;
import java.util.function.Consumer;
import java.util.function.Supplier;
import static io.reactivex.Flowable.fromPublisher;
package com.github.rahulsom.grooves.test;




public class OnSpec<
        AggregateT,
        EventIdT,
        EventT extends BaseEvent<AggregateT, EventIdT, EventT>,
        SnapshotIdT,
        SnapshotT extends Snapshot<AggregateT, SnapshotIdT, EventIdT, EventT>> {
    private AggregateT aggregate;
    private Consumer entityConsumer;
    private Supplier<Date> timestampSupplier;
    private Supplier<Long> positionSupplier;

    private static final Logger log = LoggerFactory.getLogger(OnSpec.class);

    /**
     * Applies an event to an aggregate. This involves checking if any important fields are
     * missing and populating them based on the suppliers.
     *
     * @param <T> type of event
     * @param event The event to be applied
     *
     * @return The event after persisting
     */
    @NotNull public <T extends EventT> T apply(@NotNull T event) {
        event.setAggregate(aggregate);

        if (event.getPosition() == 0) {
            event.setPosition(positionSupplier.get());
        }
        //if (event.getTimestamp() == null) {
        event.setTimestamp(timestampSupplier.get());
        //}

        entityConsumer.accept(event);

        return event;
    }

    /**
     * Computes and persists a snapshot based on a QueryUtil on the aggregate that this
     * OnSpec applies on
     *
     * @param <QueryT>      The type of Query to be executed
     * @param query         The Query Util to compute the snapshot
     * @param beforePersist Code to execute before persisting the snapshot.
     *
     * @return The snapshot after persisting
     */
    @NotNull
// 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-example-test/src/main/groovy/com/github/rahulsom/grooves/test/OnSpec.java
import com.github.rahulsom.grooves.api.events.BaseEvent;
import com.github.rahulsom.grooves.api.snapshots.Snapshot;
import com.github.rahulsom.grooves.queries.QuerySupport;
import org.jetbrains.annotations.NotNull;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.Date;
import java.util.function.Consumer;
import java.util.function.Supplier;
import static io.reactivex.Flowable.fromPublisher;

package com.github.rahulsom.grooves.test;




public class OnSpec<
        AggregateT,
        EventIdT,
        EventT extends BaseEvent<AggregateT, EventIdT, EventT>,
        SnapshotIdT,
        SnapshotT extends Snapshot<AggregateT, SnapshotIdT, EventIdT, EventT>> {
    private AggregateT aggregate;
    private Consumer entityConsumer;
    private Supplier<Date> timestampSupplier;
    private Supplier<Long> positionSupplier;

    private static final Logger log = LoggerFactory.getLogger(OnSpec.class);

    /**
     * Applies an event to an aggregate. This involves checking if any important fields are
     * missing and populating them based on the suppliers.
     *
     * @param <T> type of event
     * @param event The event to be applied
     *
     * @return The event after persisting
     */
    @NotNull public <T extends EventT> T apply(@NotNull T event) {
        event.setAggregate(aggregate);

        if (event.getPosition() == 0) {
            event.setPosition(positionSupplier.get());
        }
        //if (event.getTimestamp() == null) {
        event.setTimestamp(timestampSupplier.get());
        //}

        entityConsumer.accept(event);

        return event;
    }

    /**
     * Computes and persists a snapshot based on a QueryUtil on the aggregate that this
     * OnSpec applies on
     *
     * @param <QueryT>      The type of Query to be executed
     * @param query         The Query Util to compute the snapshot
     * @param beforePersist Code to execute before persisting the snapshot.
     *
     * @return The snapshot after persisting
     */
    @NotNull
    public <QueryT extends QuerySupport<AggregateT, EventIdT, EventT, SnapshotIdT,