eventsource

package module
v0.0.0-...-015de62 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Apr 2, 2017 License: Apache-2.0 Imports: 11 Imported by: 5

README

event source

golang event sourcing library

Installation

go get github.com/savaki/eventsource

Example

package main

import (
	"context"
	"fmt"
	"log"
	"time"

	"github.com/savaki/eventsource"
)

// UserCreated defines a user creation event
type UserCreated struct {
	eventsource.Model
}

// UserFirstSet defines an event by simple struct embedding
type UserNameSet struct {
	eventsource.Model
	Name string
}

// UserLastSet implements the eventsource.Event interface directly
type UserEmailSet struct {
	ID      string
	Version int
	At      time.Time
	Email   string
}

func (m UserEmailSet) AggregateID() string {
	return m.ID
}

func (m UserEmailSet) EventVersion() int {
	return m.Version
}

func (m UserEmailSet) EventAt() time.Time {
	return m.At
}

type User struct { 
	ID      string
	Version int
	Name    string
	Email   string
}

func (item *User) On(event eventsource.Event) bool {
	switch v := event.(type) {
	case *UserCreated:
		item.Version = v.Model.Version
		item.ID = v.Model.ID

	case *UserNameSet:
		item.Version = v.Model.Version
		item.Name = v.Name

	case *UserEmailSet:
		item.Version = v.Version
		item.Email = v.Email

	default:
		return false
	}

	return true
}

func main() {
	userEvents := eventsource.New(&User{})
	err := userEvents.Bind(
		UserCreated{},
		UserNameSet{},
		UserEmailSet{},
	)
	if err != nil {
		log.Fatalln(err)
	}

	id := "123"
	setNameEvent := &UserNameSet{
		Model: eventsource.Model{ID: id, Version: 1},
		Name:  "Joe Public",
	}
	setEmailEvent := &UserEmailSet{
		ID:      id,
		Version: 2,
		Email:   "joe.public@example.com",
	}

	ctx := context.Background()
	err = userEvents.Save(ctx, setEmailEvent, setNameEvent)
	if err != nil {
		log.Fatalln(err)
	}

	v, err := userEvents.Load(ctx, id)
	if err != nil {
		log.Fatalln(err)
	}

	user := v.(*User)
	fmt.Printf("Hello %v %v\n", user.Name, user.Email) // prints "Hello Joe Public joe.public@example.com"
}

Documentation

Index

Constants

View Source
const (
	AggregateNil      = "AggregateNil"
	DuplicateID       = "DuplicateID"
	DuplicateVersion  = "DuplicateVersion"
	DuplicateAt       = "DuplicateAt"
	DuplicateType     = "DuplicateType"
	InvalidID         = "InvalidID"
	InvalidAt         = "InvalidAt"
	InvalidVersion    = "InvalidVersion"
	InvalidEncoding   = "InvalidEncoding"
	UnboundEventType  = "UnboundEventType"
	AggregateNotFound = "AggregateNotFound"
	UnhandledEvent    = "UnhandledEvent"
)

Variables

This section is empty.

Functions

func EventType

func EventType(event Event) (string, reflect.Type)

EventType is a helper func that extracts the event type of the event along with the reflect.Type of the event.

Primarily useful for serializers that need to understand how marshal and unmarshal instances of Event to a []byte

func NewError

func NewError(err error, code, format string, args ...interface{}) error

Types

type Aggregate

type Aggregate interface {

	// On will be called for each event processed; returns true if aggregate was able to handle the event, false otherwise
	On(event Event) bool
}

Aggregate represents the aggregate root in the domain driven design sense. It aggregates the events and presents the current view of the domain object

type EpochMillis

type EpochMillis int64

EpochMillis represents the number of millis since Jan 1, 1970

func Now

func Now() EpochMillis

Now is the current time in epoch millis; akin to time.Now()

func Time

func Time(t time.Time) EpochMillis

Time converts a time.Time to an EpochMillis ; units of time less than millis are lost

func (EpochMillis) Int64

func (e EpochMillis) Int64() int64

Int64 converts EpochMillis to int64 representation

func (EpochMillis) String

func (e EpochMillis) String() string

String represents EpochMillis as a numeric string

func (EpochMillis) Time

func (e EpochMillis) Time() time.Time

Time converts EpochMillis to an instance of time.Time

type Error

type Error interface {
	error

	// Returns the original error if one was set.  Nil is returned if not set.
	Cause() error

	// Returns the short phrase depicting the classification of the error.
	Code() string

	// Returns the error details message.
	Message() string
}

Error provides a standardized error interface for eventsource

type Event

type Event interface {
	// AggregateID returns the aggregate id of the event
	AggregateID() string

	// Version contains version number of aggregate
	EventVersion() int

	// At indicates when the event took place
	EventAt() time.Time
}

Event describes a change that happened to the aggregate.

* Past tense, EmailChanged * Contains intent, EmailChanged is better than EmailSet

type EventTyper

type EventTyper interface {
	// EventType returns the name of event type
	EventType() string
}

EventTyper is an optional interface that can be applied to an Event that allows it to specify an event type different than the name of the struct

type History

type History []Record

History represents the events to be applied to recreate the aggregate in version order

type Model

type Model struct {
	// ID contains the AggregateID
	ID string

	// Version holds the event version
	Version int

	// At contains the event time
	At time.Time
}

Model provides a default implementation of an Event that is suitable for being embedded

func (Model) AggregateID

func (m Model) AggregateID() string

AggregateID implements part of the Event interface

func (Model) EventAt

func (m Model) EventAt() time.Time

EventAt implements part of the Event interface

func (Model) EventVersion

func (m Model) EventVersion() int

EventVersion implements part of the Event interface

type Option

type Option func(registry *repository)

func WithDebug

func WithDebug(w io.Writer) Option

func WithSerializer

func WithSerializer(serializer Serializer) Option

func WithStore

func WithStore(store Store) Option

type Record

type Record struct {
	// Version is the event version the Data represents
	Version int

	// At indicates when the event happened; provided as a utility for the store
	At EpochMillis

	// Data contains the Serializer encoded version of the data
	Data []byte
}

Record provides the shape of the records to be saved to the db

type Repository

type Repository interface {
	Bind(events ...Event) error
	Load(ctx context.Context, aggregateID string) (Aggregate, error)
	Save(ctx context.Context, events ...Event) error
	New() Aggregate
}

func New

func New(prototype Aggregate, opts ...Option) Repository

type Serializer

type Serializer interface {
	Bind(events ...Event) error
	Serialize(event Event) (Record, error)
	Deserialize(record Record) (Event, error)
}

func JSONSerializer

func JSONSerializer() Serializer

type Store

type Store interface {
	// Save saves events to the store
	Save(ctx context.Context, aggregateID string, records ...Record) error

	// Fetch retrieves the History of events with the specified aggregate id
	Fetch(ctx context.Context, aggregateID string, version int) (History, error)
}

Store provides storage for events

Directories

Path Synopsis
examples
provider

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL