Event Store

Events

An event is something that has occurred in the past, often with associated information.

An event stream is a uniquely-identified, ordered sequence of events.

Estoria represents an event as:

type Event struct {
	ID            typeid.ID
	StreamID      typeid.ID
	StreamVersion int64
	Timestamp     time.Time
	Data          []byte
}

Event Stores

An event store reads events from and appends events to event streams.

Reading Streams

The ReadStream method reads events from an event stream, returning a StreamIterator that can be used to iterate over the events in the stream.

iter, _ := eventStore.ReadStream(ctx, streamID, eventstore.ReadStreamOptions{}) (StreamIterator, error)

for {
	event, err := iter.Next(ctx)
	if errors.Is(err, eventstore.ErrEndOfEventStream) {
		break
	}

	// process event
}

Appending to Streams

The AppendStream method appends one or more events to an event stream.

_ = eventStore.AppendStream(ctx, streamID, events []*eventstore.WritableEvent{
    {Type: "balancechanged", Data: []byte(`{"amount": 100}`)},
}, eventstore.AppendStreamOptions{}) error

Event Store Implementations

For production applications, Estoria provides a number of vendor-specific event store implementations via the Component Library.

The core library also includes a simple in-memory event store for testing and prototyping.

Alternatively, you can implement your own event store. Anything implementing ReadStream and AppendStream can be used as an event store with Estoria:

import (
  "github.com/go-estoria/estoria/eventstore"
  "github.com/go-estoria/estoria/typeid"
)

interface {
    AppendStream(context.Context, typeid.ID, []*eventstore.WritableEvent, eventstore.AppendStreamOptions) error
    ReadStream(context.Context, typeid.ID, eventstore.ReadStreamOptions) (eventstore.StreamIterator, error)
}

Reading and writing event streams are low-level operations in Estoria. Next, we’ll see how to create an Aggregate Store that uses an event store to persist aggregates.