eventing

package module
v0.0.0-...-aec17be Latest Latest
Warning

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

Go to latest
Published: Feb 10, 2020 License: MIT Imports: 4 Imported by: 0

README

MIT license codecov Go Report Card

Eventing

This package make working with events easy. Its provides functions for store events and derive projections (your entities) from the list of events.

This package is under heavy development. The API may encounter breaking changes. You are welcome to contribute.

Wording

Term Description
Entity An entity is an object which is defined through its identity and not through its attributes. You can read more about in any Domain Driven Design book. A Entity always have a unique id.
Event Describes an relevant event for a referenced entity.
Projection The current state of an Entity, based on all belonging events.
Controller Provides a interface for managing a Projection and its Events. Every Event that is registered and saved through the Controller automatically updates the Projection.
StorageProvider Provides an interface for storing Events and Projections to a Datastore (e.g. database).

Basic Functionality

You can find a combined usage-example in the example directory

Event

A Event needs to implement the Event-interface. This is typically done by embedding the BasicEvent struct and providing a constructor function:

type ExampleEvent struct {
	eventing.BasicEvent `bson:",inline"` // Using inline here is recommended
	MyData       string `json:"my_data" bson:"my_data"` // Providing custom json and bson-keys for MongoDB
}

func NewExampleEvent(data string) *ExampleEvent {
	return &ExampleEvent{
		BasicEvent: eventing.NewBasicEvent(uuid.NewV4().String(), "ExampleEvent"),
		MyData:     data,
	}
}
Projection

A Projection needs to implement the Projection-interface. This is typically done by embedding the BasicProjection struct and providing some functions:

  • Implement / override the Apply function to apply specific events. Its highly recommended to call the Apply function of the embedded BasicProjection first, to apply basic event data.
  • A (private) function to build the concrete Projection by a list of Events. This is necessary as long as go does not support of generics.
type ExampleProjection struct {
	eventing.BasicProjection `bson:",inline"`
	SomeString               string `json:"some_string" bson:"some_string"`
}

func (ex *ExampleProjection) Apply(event eventing.Event) {
	ex.BasicProjection.Apply(event)
	switch v := event.(type) {
	case *ExampleEvent:
		ex.SomeString = v.Data.SomeString
	default:
		fmt.Println("could not handle event")
	}
}

func buildExampleProjection(ctx context.Context, events []eventing.Event) (eventing.Projection, error) {
	ex := &ExampleProjection{}
	for _, event := range events {
		ex.Apply(event)
	}
	return ex, nil
}
Controller

You should create one Controller per Projection. A Controller can be initialized like this:

func main() {
    projectionController := eventing.NewController(&ExampleProjection{}, buildExampleProjection, SOME_STORAGE_PROVIDER)
}

Storage Providers

To store Events and Projections you will need a StorageProvider, e.g. A database. This project holds a example provider for MongoDB which can be easily be used:

func main() {
    database := connectToMongo("localhost", "27017", "root", "root", "testEventing")
    storage := provider.NewMongoStorageProvider(database, "events", eventing.BasicProjectionGenerator)
}
Registering Events

You may need to provide a function to build a concrete Event by the raw Database output. The provided MongoDB-implementation depends on. Make sure to register all your events. This can be done by using the fluent API:

func main() {
    storage := provider.NewMongoStorageProvider(database, "events", eventing.BasicProjectionGenerator).
            WithEvent("ExampleEvent", exampleEventFromCursor)
}

func exampleEventFromCursor(raw *mongo.Cursor) (eventing.Event, error) {
	e := &ExampleEvent{}
	err := raw.Decode(e)
	if err != nil {
		return nil, err
	}
	return e, nil
}

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type BasicEvent

type BasicEvent struct {
	EntityID  string    `json:"entity_id" bson:"entity_id"`
	EventID   string    `json:"event_id" bson:"event_id"`
	EventName string    `json:"event_type" bson:"event_type"`
	CreatedAt time.Time `json:"created_at" bson:"created_at"`
}

func NewBasicEvent

func NewBasicEvent(entityID string, name string) BasicEvent

func (BasicEvent) GetCreatedAt

func (basicEvent BasicEvent) GetCreatedAt() time.Time

func (BasicEvent) GetEntityID

func (basicEvent BasicEvent) GetEntityID() string

func (BasicEvent) GetEventID

func (basicEvent BasicEvent) GetEventID() string

func (BasicEvent) GetEventName

func (basicEvent BasicEvent) GetEventName() string

type BasicProjection

type BasicProjection struct {
	EntityID      string    `json:"entity_id" bson:"entity_id"`
	LastEventID   string    `json:"last_event_id" bson:"last_event_id"`
	LastEventTime time.Time `json:"last_event_time" bson:"last_event_time"`
}

func (*BasicProjection) Apply

func (basicProjection *BasicProjection) Apply(event Event)

func (BasicProjection) GetCollectionName

func (BasicProjection) GetCollectionName() string

func (*BasicProjection) GetEntityID

func (basicProjection *BasicProjection) GetEntityID() string

func (*BasicProjection) GetLastEventID

func (basicProjection *BasicProjection) GetLastEventID() string

type BuildProjectionFunc

type BuildProjectionFunc func(ctx context.Context, events []Event) (Projection, error)

type Controller

type Controller struct {
	// contains filtered or unexported fields
}

Controllers are the primary way to save events and build projections based upon these.

func NewController

func NewController(projection Projection, buildProjection BuildProjectionFunc, provider StorageProvider) *Controller

NewController creates a new instance of an controller by collection all necessary data.

func (*Controller) GetLatestProjection

func (controller *Controller) GetLatestProjection(ctx context.Context, entityID string) (Projection, error)

GetLatestProjection retrieves the latest projection the managed projection-entity.

func (*Controller) SaveEvent

func (controller *Controller) SaveEvent(ctx context.Context, event Event) error

SaveEvent stores an event and builds an up-to-date projection.

type Event

type Event interface {
	GetEntityID() string
	GetEventID() string
	GetEventName() string
	GetCreatedAt() time.Time
}

type Projection

type Projection interface {
	Apply(Event)
	GetCollectionName() string
	GetEntityID() string
	GetLastEventID() string
}

func BasicProjectionGenerator

func BasicProjectionGenerator(result *mongo.SingleResult) (Projection, error)

type StorageProvider

type StorageProvider interface {
	SaveEvent(ctx context.Context, event Event) error
	SaveProjection(ctx context.Context, projection Projection) error
	GetProjection(ctx context.Context, entityID string, projection Projection) (Projection, error)
	GetLatestEventIDForEntityID(ctx context.Context, entityID string) (string, error)
	GetSortedEventsForEntityID(ctx context.Context, entityID string) ([]Event, error)
}

Directories

Path Synopsis

Jump to

Keyboard shortcuts

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