command

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: 8 Imported by: 0

Documentation

Overview

Package command contains types and interfaces for implementing Command Handlers, necessary for producing side effects in your Aggregates and system, and implement your Domain's business logic.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Command

type Command message.Message

Command is a specific kind of Message that represents an intent. Commands should be phrased in the present, imperative tense, such as "ActivateUser" or "CreateOrder".

type Envelope

type Envelope[T Command] message.Envelope[T]

Envelope carries both a Command and some optional Metadata attached to it.

func FromGenericEnvelope

func FromGenericEnvelope[T Command](cmd GenericEnvelope) (Envelope[T], bool)

FromGenericEnvelope attempts to type-cast a GenericEnvelope instance into a strongly-typed Command Envelope.

A boolean guard is returned to signal whether the type-casting was successful or not.

func ToEnvelope

func ToEnvelope[T Command](cmd T) Envelope[T]

ToEnvelope is a convenience function that wraps the provided Command type into an Envelope, with no metadata attached to it.

func (Envelope[T]) ToGenericEnvelope

func (cmd Envelope[T]) ToGenericEnvelope() GenericEnvelope

ToGenericEnvelope returns a GenericEnvelope version of the current Envelope instance.

type GenericEnvelope

type GenericEnvelope Envelope[Command]

GenericEnvelope is a Command Envelope that depends solely on the Command interface, not a specific generic Command type.

type Handler

type Handler[T Command] interface {
	Handle(ctx context.Context, cmd Envelope[T]) error
}

Handler is the interface that defines a Command Handler, a component that receives a specific kind of Command and executes the business logic related to that particular Command.

type HandlerFunc

type HandlerFunc[T Command] func(context.Context, Envelope[T]) error

HandlerFunc is a functional type that implements the Handler interface. Useful for testing and stateless Handlers.

func (HandlerFunc[T]) Handle

func (fn HandlerFunc[T]) Handle(ctx context.Context, cmd Envelope[T]) error

Handle handles the provided Command through the functional Handler.

type ScenarioGiven

type ScenarioGiven[Cmd Command, T Handler[Cmd]] struct {
	// contains filtered or unexported fields
}

ScenarioGiven is the state of the scenario once a set of Domain Events have been provided using Given(), to represent the state of the system at the time of evaluating a Command.

func (ScenarioGiven[Cmd, T]) When

func (sc ScenarioGiven[Cmd, T]) When(cmd Envelope[Cmd]) ScenarioWhen[Cmd, T]

When provides the Command to evaluate.

type ScenarioInit

type ScenarioInit[Cmd Command, T Handler[Cmd]] struct{}

ScenarioInit is the entrypoint of the Command Handler scenario API.

A Command Handler 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[Cmd Command, T Handler[Cmd]]() ScenarioInit[Cmd, T]

Scenario is a scenario type to test the result of Commands being handled by a Command Handler.

Command Handlers in Event-sourced systems produce side effects by means of Domain Events. This scenario API helps you with testing the Domain Events produced by a Command Handler when handling a specific Command.

func (ScenarioInit[Cmd, T]) Given

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

Given sets the Command Handler scenario preconditions.

Domain Events are used in Event-sourced systems to represent a side effect that has taken place in the system. In order to set a given state for the system to be in while testing a specific Command evaluation, you should specify the Domain Events that have happened thus far.

When you're testing Commands with a clean-slate system, you should either specify no Domain Events, or skip directly to When().

func (ScenarioInit[Cmd, T]) When

func (sc ScenarioInit[Cmd, T]) When(cmd Envelope[Cmd]) ScenarioWhen[Cmd, T]

When provides the Command to evaluate.

type ScenarioThen

type ScenarioThen[Cmd Command, T Handler[Cmd]] struct {
	ScenarioWhen[Cmd, T]
	// contains filtered or unexported fields
}

ScenarioThen is the state of the scenario once the preconditions and expectations have been fully specified.

func (ScenarioThen[Cmd, T]) AssertOn

func (sc ScenarioThen[Cmd, T]) AssertOn(
	t *testing.T,
	handlerFactory func(event.Store) T,
)

AssertOn performs the specified expectations of the scenario, using the Command Handler instance produced by the provided factory function.

A Command Handler should only use a single Aggregate type, to ensure that the side effects happen in a well-defined transactional boundary. If your Command Handler needs to modify more than one Aggregate, you might be doing something wrong in your domain model.

The type of the Aggregate used to evaluate the Command must be specified, so that the Event-sourced Repository instance can be provided to the factory function to build the desired Command Handler.

type ScenarioWhen

type ScenarioWhen[Cmd Command, T Handler[Cmd]] struct {
	ScenarioGiven[Cmd, T]
	// contains filtered or unexported fields
}

ScenarioWhen is the state of the scenario once the state of the system and the Command to evaluate have been provided.

func (ScenarioWhen[Cmd, T]) Then

func (sc ScenarioWhen[Cmd, T]) Then(events ...event.Persisted) ScenarioThen[Cmd, T]

Then sets a positive expectation on the scenario outcome, to produce the Domain Events provided in input.

The list of Domain Events specified should be ordered as the expected order of recording by the Command Handler.

func (ScenarioWhen[Cmd, T]) ThenError

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

ThenError sets a negative expectation on the scenario outcome, to produce an error value that is similar to the one provided in input.

Error assertion happens using errors.Is(), so the error returned by the Command Handler is unwrapped until the cause error to match the provided expectation.

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 domain command 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 domain command matches ALL of the errors specified.

func (ScenarioWhen[Cmd, T]) ThenFails

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

ThenFails sets a negative expectation on the scenario outcome, to fail the Command execution with no particular assertion on the error returned.

This is useful when the error returned is not important for the Command you're trying to test.

Jump to

Keyboard shortcuts

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