Skip to content

Commit

Permalink
refactor aggregate package (#9)
Browse files Browse the repository at this point in the history
* rename advanced aggregate to EventSourced
* change aggregate factory to get rid of extra dependencies
* update tests with better examples and test case names
* provide excessive documentation and examples
  • Loading branch information
screwyprof authored Apr 2, 2023
1 parent 9701cc6 commit d877767
Show file tree
Hide file tree
Showing 33 changed files with 736 additions and 474 deletions.
9 changes: 4 additions & 5 deletions .golangci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,9 @@ linters:
- durationcheck
- errcheck
- errchkjson
#- errname
- errname
- errorlint
- execinquery
#- errorsas
- exhaustive
- exportloopref
#- forbidigo
Expand Down Expand Up @@ -68,7 +67,7 @@ linters:
#- ireturn
- ineffassign
- lll
#- logrlint
- logrlint
- maintidx
- makezero
- misspell
Expand All @@ -80,7 +79,7 @@ linters:
- nolintlint
- nonamedreturns
- nosprintfhostport
#- paralleltest
- paralleltest
- prealloc
- predeclared
- promlinter
Expand All @@ -94,7 +93,7 @@ linters:
- tenv
- testpackage
- thelper
#- tparallel
- tparallel
- typecheck
- unconvert
- unparam
Expand Down
10 changes: 7 additions & 3 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,17 @@ tools: ## install dev tools, linters, code generators, etc..
@echo -e "$(OK_COLOR)--> Installing tools from tools/tools.go$(NO_COLOR)"
@export GOBIN=$$PWD/tools/bin; export PATH=$$GOBIN:$$PATH; cat tools/tools.go | grep _ | awk -F'"' '{print $$2}' | xargs -tI % go install %

lint: ## run linters
lint: ## run linters for the current changes
@echo -e "$(OK_COLOR)--> Running linters$(NO_COLOR)"
@tools/bin/golangci-lint run

lint-all: ## run linters
@echo -e "$(OK_COLOR)==> Linting$(NO_COLOR)"
golangci-lint run ./... --new-from-rev=""

test: ## run tests
@echo -e "$(OK_COLOR)--> Running unit tests$(NO_COLOR)"
go test -v --race --count=1 -coverprofile=coverage.tmp ./...
go test -v --race --count=1 -covermode atomic -coverprofile=coverage.tmp ./...
@set -euo pipefail && cat coverage.tmp | grep -v $(IGNORE_COVERAGE_FOR) > coverage.out && rm coverage.tmp

coverage: test ## show test coverage report
Expand All @@ -55,4 +59,4 @@ help: ## show this help screen
# To avoid unintended conflicts with file names, always add to .PHONY
# unless there is a reason not to.
# https://www.gnu.org/software/make/manual/html_node/Phony-Targets.html
.PHONY: all deps tools lint test coverage fmt clean help
.PHONY: all deps tools lint lint-all test coverage fmt clean help
64 changes: 0 additions & 64 deletions aggregate/advanced.go

This file was deleted.

160 changes: 0 additions & 160 deletions aggregate/advanced_test.go

This file was deleted.

35 changes: 35 additions & 0 deletions aggregate/aggregate.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
// Package aggregate provides a base implementation for event sourced aggregates.
//
// To create an event sourced aggregate, a user must define their own domain
// aggregate that implements the cqrs.Aggregate interface. The user's domain
// aggregate should define its own identifier type and event type.
//
// Additionally, command handlers and event appliers should be defined within
// the user's domain aggregate. The command handlers handle commands and produce
// events, while the event appliers apply events to update the aggregate's state.
//
// Once the user's domain aggregate is defined, it can be transformed into
// a cqrs.ESAggregate using the aggregate.FromAggregate function. This function
// automatically registers the command handlers and event appliers defined in
// the user's domain aggregate.
//
// For a detailed example of how to use the aggregate package, please refer to
// the Example function in the example_test.go file.
//
// More examples can be found in the examples directory.
package aggregate

import (
"errors"
)

var (
// ErrCommandHandlerNotFound is returned when a command handler is not found.
ErrCommandHandlerNotFound = errors.New("command handler not found")

// ErrEventApplierNotFound is returned when an event applier is not found.
ErrEventApplierNotFound = errors.New("event applier not found")

// ErrAggregateNotRegistered is returned when an aggregate is not registered in the factory.
ErrAggregateNotRegistered = errors.New("aggregate is not registered")
)
29 changes: 13 additions & 16 deletions aggregate/aggtest/aggregate.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,9 @@ import (
)

var (
ErrItCanHappenOnceOnly = errors.New("some business rule error occurred")
ErrMakeSomethingHandlerNotFound = errors.New("handler for MakeSomethingHappen command is not found")
ErrOnSomethingHappenedApplierNotFound = errors.New("event applier for OnSomethingHappened event is not found")
ErrItCanHappenOnceOnly = errors.New("some business rule error occurred")

TestAggregateType = "mock.TestAggregate"
TestAggregateType = "mock.TestAggregate" //nolint:gochecknoglobals
)

type StringIdentifier string
Expand All @@ -20,40 +18,39 @@ func (i StringIdentifier) String() string {
return string(i)
}

// TestAggregate a pure aggregate (has no external dependencies or dark magic method) used for testing.
// TestAggregate is a user-defined aggregate (has no external dependencies or dark magic methods) used for testing.
type TestAggregate struct {
id cqrs.Identifier
version int
aggType string
id Identifier

alreadyHappened bool
}

// NewTestAggregate creates a new instance of TestAggregate.
func NewTestAggregate(ID cqrs.Identifier) *TestAggregate {
return &TestAggregate{id: ID}
func NewTestAggregate(id cqrs.Identifier) *TestAggregate {
return &TestAggregate{id: id}
}

// AggregateID implements cqrs.Aggregate interface.
func (a *TestAggregate) AggregateID() cqrs.Identifier {
func (a *TestAggregate) AggregateID() Identifier {
return a.id
}

// AggregateType implements cqrs.Aggregate interface.
func (a *TestAggregate) AggregateType() string {
return "mock.TestAggregate"
return TestAggregateType
}

func (a *TestAggregate) MakeSomethingHappen(c MakeSomethingHappen) ([]cqrs.DomainEvent, error) {
func (a *TestAggregate) MakeSomethingHappen(_ MakeSomethingHappen) ([]Event, error) {
if a.alreadyHappened {
return nil, ErrItCanHappenOnceOnly
}
return []cqrs.DomainEvent{SomethingHappened{}}, nil

return []Event{SomethingHappened{}}, nil
}

func (a *TestAggregate) OnSomethingHappened(e SomethingHappened) {
func (a *TestAggregate) OnSomethingHappened(_ SomethingHappened) {
a.alreadyHappened = true
}

func (a *TestAggregate) OnSomethingElseHappened(e SomethingElseHappened) {
func (a *TestAggregate) OnSomethingElseHappened(_ SomethingElseHappened) {
}
Loading

0 comments on commit d877767

Please sign in to comment.