// Path: src/main/java/com/oasisdigital/nges/event/Event.java
// public class Event implements Serializable {
//     private static final long serialVersionUID = 1L;
// 
//     /**
//      * <p>
//      * Number assigned from a globally increasing sequence. Might contain holes, i.e. it is possible for
//      * events with IDs 100 and 102 to exist without an event with ID 101. Event with ID N+1 must have been
//      * saved after the event with ID N.
//      * </p>
//      * <p>
//      * Automatically populated by the system on save, never empty.
//      * </p>
//      */
//     private long eventId;
// 
//     /**
//      * ID of a stream of events, for example identifying a DDD aggregeate or another kind of entity. Populated
//      * by the caller on save, mandatory.
//      */
//     private UUID streamId;
// 
//     /**
//      * Type of the event, useful for interpreting the payload etc. Populated by the caller on save.
//      */
//     private String type;
// 
//     /**
//      * Correlation ID. Populated by the caller on save, mandatory.
//      */
//     private UUID correlationId;
// 
//     /**
//      * Sequence number within this particular stream. Events within a stream are automatically assigned
//      * consecutive numbers starting with 1, without gaps. Never empry.
//      */
//     private long sequence;
// 
//     /**
//      * Time when the event was saved. Events saved in one transaction are assigned the exact same timestamp.
//      * Automatically populated by the system on save, never empty.
//      */
//     private OffsetDateTime transactionTime;
// 
//     /**
//      * JSON payload.
//      */
//     private String payload;
// 
//     public Event() {
//     }
// 
//     public Event(UUID streamId, String type, UUID correlationId, String payload) {
//         this.streamId = streamId;
//         this.type = type;
//         this.correlationId = correlationId;
//         this.payload = payload;
//     }
// 
//     public void setEventId(long eventId) {
//         this.eventId = eventId;
//     }
// 
//     public void setStreamId(UUID streamId) {
//         this.streamId = streamId;
//     }
// 
//     public void setType(String type) {
//         this.type = type;
//     }
// 
//     public void setTransactionTime(OffsetDateTime transactionTime) {
//         this.transactionTime = transactionTime;
//     }
// 
//     public void setPayload(String payload) {
//         this.payload = payload;
//     }
// 
//     public void setCorrelationId(UUID correlationId) {
//         this.correlationId = correlationId;
//     }
// 
//     public long getEventId() {
//         return eventId;
//     }
// 
//     public UUID getStreamId() {
//         return streamId;
//     }
// 
//     public String getType() {
//         return type;
//     }
// 
//     public OffsetDateTime getTransactionTime() {
//         return transactionTime;
//     }
// 
//     public String getPayload() {
//         return payload;
//     }
// 
//     public UUID getCorrelationId() {
//         return correlationId;
//     }
// 
//     public long getSequence() {
//         return sequence;
//     }
// 
//     public void setSequence(long sequence) {
//         this.sequence = sequence;
//     }
// 
// }
// 
// Path: src/main/java/com/oasisdigital/nges/event/EventStoreException.java
// public class EventStoreException extends RuntimeException {
// 
//     private static final long serialVersionUID = -1237680703226042282L;
// 
//     public EventStoreException() {
//         super();
//     }
// 
//     public EventStoreException(String message, Throwable cause, boolean enableSuppression,
//             boolean writableStackTrace) {
//         super(message, cause, enableSuppression, writableStackTrace);
//     }
// 
//     public EventStoreException(String message, Throwable cause) {
//         super(message, cause);
//     }
// 
//     public EventStoreException(String message) {
//         super(message);
//     }
// 
//     public EventStoreException(Throwable cause) {
//         super(cause);
//     }
// }


import static java.util.stream.Collectors.toList;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.UUID;
import com.oasisdigital.nges.event.Event;
import com.oasisdigital.nges.event.EventStoreException;

    public Event getEvent(long eventId) throws EventStoreException {
        return queries.queryForObject("select * from event_log where event_id = ?", EventLogDao::toEvent,
                eventId);
    }

    public List<Event> getLatestEvents(int limit) throws EventStoreException {
        return queryForList("select * from event_log order by event_id desc limit ?", limit);
    }

    public List<Event> getEventsForAllStreams(long afterEventId, int limit) throws EventStoreException {
        return queryForList("select * from event_log where event_id > ? order by event_id limit ?",
                afterEventId, limit);
    }

    public List<Event> getEventsForStream(UUID streamId, long afterSequenceId, int limit)
            throws EventStoreException {
        return queryForList(
                "select * from event_log where stream_id = ? and seq_no > ? order by seq_no limit ?",
                streamId, afterSequenceId, limit);
    }

    public List<Long> save(List<Event> events) throws EventStoreException {
        if (events.isEmpty()) {
            return Collections.emptyList();
        }
        List<Map<String, Object>> keyHolder = new LinkedList<>();
        List<Object> values = new ArrayList<>();
        StringBuilder statement = new StringBuilder();
        statement.append("insert into event_log(stream_id, type, correlation_id, seq_no, payload) values\n");
// Path: src/main/java/com/oasisdigital/nges/event/Event.java
// public class Event implements Serializable {
//     private static final long serialVersionUID = 1L;
// 
//     /**
//      * <p>
//      * Number assigned from a globally increasing sequence. Might contain holes, i.e. it is possible for
//      * events with IDs 100 and 102 to exist without an event with ID 101. Event with ID N+1 must have been
//      * saved after the event with ID N.
//      * </p>
//      * <p>
//      * Automatically populated by the system on save, never empty.
//      * </p>
//      */
//     private long eventId;
// 
//     /**
//      * ID of a stream of events, for example identifying a DDD aggregeate or another kind of entity. Populated
//      * by the caller on save, mandatory.
//      */
//     private UUID streamId;
// 
//     /**
//      * Type of the event, useful for interpreting the payload etc. Populated by the caller on save.
//      */
//     private String type;
// 
//     /**
//      * Correlation ID. Populated by the caller on save, mandatory.
//      */
//     private UUID correlationId;
// 
//     /**
//      * Sequence number within this particular stream. Events within a stream are automatically assigned
//      * consecutive numbers starting with 1, without gaps. Never empry.
//      */
//     private long sequence;
// 
//     /**
//      * Time when the event was saved. Events saved in one transaction are assigned the exact same timestamp.
//      * Automatically populated by the system on save, never empty.
//      */
//     private OffsetDateTime transactionTime;
// 
//     /**
//      * JSON payload.
//      */
//     private String payload;
// 
//     public Event() {
//     }
// 
//     public Event(UUID streamId, String type, UUID correlationId, String payload) {
//         this.streamId = streamId;
//         this.type = type;
//         this.correlationId = correlationId;
//         this.payload = payload;
//     }
// 
//     public void setEventId(long eventId) {
//         this.eventId = eventId;
//     }
// 
//     public void setStreamId(UUID streamId) {
//         this.streamId = streamId;
//     }
// 
//     public void setType(String type) {
//         this.type = type;
//     }
// 
//     public void setTransactionTime(OffsetDateTime transactionTime) {
//         this.transactionTime = transactionTime;
//     }
// 
//     public void setPayload(String payload) {
//         this.payload = payload;
//     }
// 
//     public void setCorrelationId(UUID correlationId) {
//         this.correlationId = correlationId;
//     }
// 
//     public long getEventId() {
//         return eventId;
//     }
// 
//     public UUID getStreamId() {
//         return streamId;
//     }
// 
//     public String getType() {
//         return type;
//     }
// 
//     public OffsetDateTime getTransactionTime() {
//         return transactionTime;
//     }
// 
//     public String getPayload() {
//         return payload;
//     }
// 
//     public UUID getCorrelationId() {
//         return correlationId;
//     }
// 
//     public long getSequence() {
//         return sequence;
//     }
// 
//     public void setSequence(long sequence) {
//         this.sequence = sequence;
//     }
// 
// }
// 
// Path: src/main/java/com/oasisdigital/nges/event/EventStoreException.java
// public class EventStoreException extends RuntimeException {
// 
//     private static final long serialVersionUID = -1237680703226042282L;
// 
//     public EventStoreException() {
//         super();
//     }
// 
//     public EventStoreException(String message, Throwable cause, boolean enableSuppression,
//             boolean writableStackTrace) {
//         super(message, cause, enableSuppression, writableStackTrace);
//     }
// 
//     public EventStoreException(String message, Throwable cause) {
//         super(message, cause);
//     }
// 
//     public EventStoreException(String message) {
//         super(message);
//     }
// 
//     public EventStoreException(Throwable cause) {
//         super(cause);
//     }
// }


// Path: src/main/java/com/oasisdigital/nges/event/jdbc/EventLogDao.java
import static java.util.stream.Collectors.toList;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.UUID;
import com.oasisdigital.nges.event.Event;
import com.oasisdigital.nges.event.EventStoreException;


    public Event getEvent(long eventId) throws EventStoreException {
        return queries.queryForObject("select * from event_log where event_id = ?", EventLogDao::toEvent,
                eventId);
    }

    public List<Event> getLatestEvents(int limit) throws EventStoreException {
        return queryForList("select * from event_log order by event_id desc limit ?", limit);
    }

    public List<Event> getEventsForAllStreams(long afterEventId, int limit) throws EventStoreException {
        return queryForList("select * from event_log where event_id > ? order by event_id limit ?",
                afterEventId, limit);
    }

    public List<Event> getEventsForStream(UUID streamId, long afterSequenceId, int limit)
            throws EventStoreException {
        return queryForList(
                "select * from event_log where stream_id = ? and seq_no > ? order by seq_no limit ?",
                streamId, afterSequenceId, limit);
    }

    public List<Long> save(List<Event> events) throws EventStoreException {
        if (events.isEmpty()) {
            return Collections.emptyList();
        }
        List<Map<String, Object>> keyHolder = new LinkedList<>();
        List<Object> values = new ArrayList<>();
        StringBuilder statement = new StringBuilder();
        statement.append("insert into event_log(stream_id, type, correlation_id, seq_no, payload) values\n");
        boolean first = true;