aggregate

package
v0.3.0-prerelease.3 Latest Latest
Warning

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

Go to latest
Published: Mar 20, 2024 License: MIT Imports: 9 Imported by: 0

Documentation

Overview

Package aggregate defines interfaces and types necessary to allow users to define their own Aggregate types.

Index

Constants

This section is empty.

Variables

View Source
var ErrRootNotFound = fmt.Errorf("aggregate: root not found")

ErrRootNotFound is returned when the Aggregate Root requested through a Repository was not found.

Functions

func RecordThat

func RecordThat[I ID](root Root[I], events ...event.Envelope) error

RecordThat records the Domain Event for the specified Aggregate Root.

An error is typically returned if applying the Domain Event on the Aggregate Root instance fails with an error.

func RehydrateFromEvents

func RehydrateFromEvents[I ID](root Root[I], eventStream event.StreamRead) error

RehydrateFromEvents rehydrates an Aggregate Root from a read-only Event Stream.

func RehydrateFromState

func RehydrateFromState[I ID, Src Root[I], Dst any](
	v version.Version,
	dst Dst,
	deserializer serde.Deserializer[Src, Dst],
) (Src, error)

RehydrateFromState rehydrates an aggregate.Root instance using a state type, typically coming from an external state type (e.g. Protobuf type) and aggregate.Repository implementation (e.g. postgres.AggregateRepository).

Types

type Aggregate

type Aggregate interface {
	// Apply applies the specified Event to the Aggregate Root,
	// by causing a state change in the Aggregate Root instance.
	//
	// Since this method cause a state change, implementors should make sure
	// to use pointer semantics on their Aggregate Root method receivers.
	//
	// Please note, this method should not perform any kind of external request
	// and should be, save for the Aggregate Root state mutation, free of side effects.
	// For this reason, this method does not include a context.Context instance
	// in the input parameters.
	Apply(event.Event) error
}

Aggregate is the segregated interface, part of the Aggregate Root interface, that describes the left-folding behavior of Domain Events to update the Aggregate Root state.

type BaseRoot

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

BaseRoot segregates and completes the aggregate.Root interface implementation when embedded to a user-defined Aggregate Root type.

BaseRoot provides some common traits, such as tracking the current Aggregate Root version, and the recorded-but-uncommitted Domain Events, through the aggregate.RecordThat function.

func (*BaseRoot) FlushRecordedEvents

func (br *BaseRoot) FlushRecordedEvents() []event.Envelope

FlushRecordedEvents returns the list of uncommitted, recorded Domain Events through the Aggregate Root.

The internal list kept by aggregate.BaseRoot is reset.

func (BaseRoot) Version

func (br BaseRoot) Version() version.Version

Version returns the current version of the Aggregate Root instance.

type EventSourcedRepository

type EventSourcedRepository[I ID, T Root[I]] struct {
	// contains filtered or unexported fields
}

EventSourcedRepository provides an aggregate.Repository interface implementation that uses an event.Store to store and load the state of the Aggregate Root.

func NewEventSourcedRepository

func NewEventSourcedRepository[I ID, T Root[I]](eventStore event.Store, typ Type[I, T]) EventSourcedRepository[I, T]

NewEventSourcedRepository returns a new EventSourcedRepository implementation to store and load Aggregate Roots, specified by the aggregate.Type, using the provided event.Store implementation.

func (EventSourcedRepository[I, T]) Get

func (repo EventSourcedRepository[I, T]) Get(ctx context.Context, id I) (T, error)

Get returns the Aggregate Root with the specified id.

aggregate.ErrRootNotFound is returned if no Aggregate Root was found with that id.

An error is returned if the underlying Event Store fails, or if an error occurs while trying to rehydrate the Aggregate Root state from its Event Stream.

func (EventSourcedRepository[I, T]) Save

func (repo EventSourcedRepository[I, T]) Save(ctx context.Context, root T) error

Save stores the Aggregate Root to the Event Store, by adding the new, uncommitted Domain Events recorded through the Root, if any.

An error is returned if the underlying Event Store fails.

type Factory

type Factory[I ID, T Root[I]] func() T

Factory is a function that creates new zero-valued instances of an aggregate.Root implementation.

type FusedRepository

type FusedRepository[I ID, T Root[I]] struct {
	Getter[I, T]
	Saver[I, T]
}

FusedRepository is a convenience type that can be used to fuse together different implementations for the Getter and Saver Repository interface components.

type Getter

type Getter[I ID, T Root[I]] interface {
	Get(ctx context.Context, id I) (T, error)
}

Getter is an Aggregate Repository interface component, that can be used for retrieving Aggregate Roots from some storage.

type ID

type ID interface {
	fmt.Stringer
}

ID represents an Aggregate ID type.

Aggregate IDs should be able to be marshaled into a string format, in order to be saved onto a named Event Stream.

type Internal

type Internal interface {
	FlushRecordedEvents() []event.Envelope
}

Internal contains some Aggregate Root methods that are used by internal packages and modules for this library.

Direct usage of these methods are discouraged.

type Repository

type Repository[I ID, T Root[I]] interface {
	Getter[I, T]
	Saver[I, T]
}

Repository is an interface used to get Aggregate Roots from and save them to some kind of storage, depending on the implementation.

type Root

type Root[I ID] interface {
	Aggregate
	Internal

	// AggregateID returns the Aggregate Root identifier.
	AggregateID() I

	// Version returns the current Aggregate Root version.
	// The version gets updated each time a new event is recorded
	// through the aggregate.RecordThat function.
	Version() version.Version
	// contains filtered or unexported methods
}

Root is the interface describing an Aggregate Root instance.

This interface should be implemented by your Aggregate Root types. Make sure your Aggregate Root types embed the aggregate.BaseRoot type to complete the implementation of this interface.

type Saver

type Saver[I ID, T Root[I]] interface {
	Save(ctx context.Context, root T) error
}

Saver is an Aggregate Repository interface component, that can be used for storing Aggregate Roots in some storage.

type ScenarioGiven

type ScenarioGiven[I ID, T Root[I]] struct {
	// contains filtered or unexported fields
}

ScenarioGiven is the state of the scenario once the Aggregate Root preconditions have been set through the Scenario().Given() method.

This state gives access to the When() method to specify the aggregate method to test using the desired Aggregate Root.

func (ScenarioGiven[I, T]) When

func (sc ScenarioGiven[I, T]) When(fn func(T) error) ScenarioWhen[I, T]

When allows to call the aggregate method method on the Aggregate Root instance provided by the previous Scenario().Given() call.

The aggregate method must be called inside the required closure parameter.

type ScenarioInit

type ScenarioInit[I ID, T Root[I]] struct {
	// contains filtered or unexported fields
}

ScenarioInit is the entrypoint of the Aggregate Root scenario API.

An Aggregate Root scenario can either set the current evaluation context by using Given(), or test a "clean-slate" scenario by using When() directly.

func Scenario

func Scenario[I ID, T Root[I]](typ Type[I, T]) ScenarioInit[I, T]

Scenario is a scenario type to test the result of methods called on an Aggregate Root and their effects.

These methods are meant to produce side-effects in the Aggregate Root state, and thus in the overall system, enforcing the aggregate invariants represented by the Aggregate Root itself.

func (ScenarioInit[I, T]) Given

func (sc ScenarioInit[I, T]) Given(events ...event.Persisted) ScenarioGiven[I, T]

Given allows to set an Aggregate Root state as precondition to the scenario test, by specifying ordered Domain Events.

func (ScenarioInit[I, T]) When

func (sc ScenarioInit[I, T]) When(fn func() (T, error)) ScenarioWhen[I, T]

When allows to call for a aggregate method/function that creates a new Aggregate Root instance.

This method requires a closure that return said new Aggregate Root instance (hence why no input parameter) or an error.

type ScenarioThen

type ScenarioThen[I ID, T Root[I]] struct {
	// contains filtered or unexported fields
}

ScenarioThen is the state of the scenario where all parameters have been set and it's ready to be executed using a testing.T instance.

Use the AssertOn method to run the test scenario.

func (ScenarioThen[I, T]) AssertOn

func (sc ScenarioThen[I, T]) AssertOn(t *testing.T)

AssertOn runs the test scenario using the specified testing.T instance.

type ScenarioWhen

type ScenarioWhen[I ID, T Root[I]] struct {
	// contains filtered or unexported fields
}

ScenarioWhen is the state of the scenario once the aggregate method to test has been provided through either Scenario().When() or Scenario().Given().When() paths.

This state allows to specify the expected outcome on the scenario using either Then(), ThenFails(), ThenError() or ThenErrors() methods.

func (ScenarioWhen[I, T]) Then

func (sc ScenarioWhen[I, T]) Then(v version.Version, events ...event.Envelope) ScenarioThen[I, T]

Then specifies a successful outcome of the scenario, allowing to assert the expected new Aggregate Root version and Domain Events recorded during the aggregate method execution.

func (ScenarioWhen[I, T]) ThenError

func (sc ScenarioWhen[I, T]) ThenError(err error) ScenarioThen[I, T]

ThenError specifies an unsuccessful outcome of the scenario, where the aggregate method execution fails with an error.

Use this method when you want to assert that the error retured by the aggregate method execution is of a specific type or value.

func (ScenarioWhen[I, T]) ThenErrors

func (sc ScenarioWhen[I, T]) ThenErrors(errs ...error) ScenarioThen[I, T]

ThenErrors specifies an unsuccessful outcome of the scenario, where the aggregate method execution fails with a specific error that wraps multiple error types (e.g. through `errors.Join`).

Use this method when you want to assert that the error returned by the aggregate method matches ALL of the errors specified.

func (ScenarioWhen[I, T]) ThenFails

func (sc ScenarioWhen[I, T]) ThenFails() ScenarioThen[I, T]

ThenFails specifies an unsuccessful outcome of the scenario, where the aggregate method execution fails with an error.

Use this method when there is no need to assert the error returned by the aggregate method is of a specific type or value.

type Type

type Type[I ID, T Root[I]] struct {
	Name    string
	Factory func() T
}

Type represents the type of an Aggregate, which will expose the name of the Aggregate (used as Event Store type).

If your Aggregate implementation uses pointers, use the factory to return a non-nil instance of the type.

Jump to

Keyboard shortcuts

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