2022-08-04 14:37:51 -06:00
|
|
|
package event
|
|
|
|
|
|
|
|
import (
|
|
|
|
"errors"
|
|
|
|
"fmt"
|
|
|
|
"sync"
|
|
|
|
)
|
|
|
|
|
2022-10-13 15:32:25 -06:00
|
|
|
// Aggregate implements functionality for working with event store streams as an aggregate.
|
|
|
|
// When creating a new Aggregate the struct should have an ApplyEvent method and embed the AggregateRoot.
|
2022-08-04 14:37:51 -06:00
|
|
|
type Aggregate interface {
|
|
|
|
// ApplyEvent applies the event to the aggrigate state
|
|
|
|
ApplyEvent(...Event)
|
|
|
|
|
|
|
|
AggregateRootInterface
|
|
|
|
}
|
|
|
|
|
2023-01-15 17:00:25 -07:00
|
|
|
func Start(a Aggregate, i uint64) {
|
|
|
|
a.start(i)
|
|
|
|
}
|
|
|
|
|
2022-08-04 14:37:51 -06:00
|
|
|
// Raise adds new uncommitted events
|
|
|
|
func Raise(a Aggregate, lis ...Event) {
|
|
|
|
lis = NewEvents(lis...)
|
|
|
|
SetStreamID(a.StreamID(), lis...)
|
|
|
|
a.raise(lis...)
|
|
|
|
a.ApplyEvent(lis...)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Append adds new committed events
|
|
|
|
func Append(a Aggregate, lis ...Event) {
|
|
|
|
a.append(lis...)
|
|
|
|
a.ApplyEvent(lis...)
|
|
|
|
}
|
|
|
|
|
|
|
|
// NotExists returns error if there are no events present.
|
|
|
|
func NotExists(a Aggregate) error {
|
2022-08-23 21:24:13 -06:00
|
|
|
if a.Version() != 0 {
|
|
|
|
return fmt.Errorf("%w, got version == %d", ErrShouldNotExist, a.Version())
|
2022-08-04 14:37:51 -06:00
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2022-08-14 10:04:15 -06:00
|
|
|
// ShouldExists returns error if there are no events present.
|
|
|
|
func ShouldExist(a Aggregate) error {
|
2022-08-23 21:24:13 -06:00
|
|
|
if a.Version() == 0 {
|
|
|
|
return fmt.Errorf("%w, got version == %d", ErrShouldExist, a.Version())
|
2022-08-14 10:04:15 -06:00
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2022-08-04 14:37:51 -06:00
|
|
|
type AggregateRootInterface interface {
|
2022-08-14 10:04:15 -06:00
|
|
|
// Events returns the aggregate events
|
2022-08-04 14:37:51 -06:00
|
|
|
// pass true for only uncommitted events
|
|
|
|
Events(bool) Events
|
2022-08-14 10:04:15 -06:00
|
|
|
// StreamID returns aggregate stream ID
|
|
|
|
StreamID() string
|
|
|
|
// SetStreamID sets aggregate stream ID
|
|
|
|
SetStreamID(streamID string)
|
2022-08-04 14:37:51 -06:00
|
|
|
// StreamVersion returns last commit events
|
|
|
|
StreamVersion() uint64
|
|
|
|
// Version returns the current aggrigate version. (committed + uncommitted)
|
|
|
|
Version() uint64
|
|
|
|
|
2023-01-15 17:00:25 -07:00
|
|
|
start(uint64)
|
2022-08-04 14:37:51 -06:00
|
|
|
raise(lis ...Event)
|
|
|
|
append(lis ...Event)
|
|
|
|
Commit()
|
|
|
|
}
|
|
|
|
|
|
|
|
var _ AggregateRootInterface = &AggregateRoot{}
|
|
|
|
|
|
|
|
type AggregateRoot struct {
|
2023-01-15 17:00:25 -07:00
|
|
|
events Events
|
|
|
|
streamID string
|
|
|
|
firstIndex uint64
|
|
|
|
lastIndex uint64
|
2022-08-04 14:37:51 -06:00
|
|
|
|
|
|
|
mu sync.RWMutex
|
|
|
|
}
|
|
|
|
|
2023-01-15 17:00:25 -07:00
|
|
|
func (a *AggregateRoot) Commit() { a.lastIndex = uint64(len(a.events)) }
|
|
|
|
func (a *AggregateRoot) StreamID() string { return a.streamID }
|
|
|
|
func (a *AggregateRoot) SetStreamID(streamID string) { a.streamID = streamID }
|
|
|
|
func (a *AggregateRoot) StreamVersion() uint64 { return a.lastIndex }
|
|
|
|
func (a *AggregateRoot) Version() uint64 { return a.firstIndex + uint64(len(a.events)) }
|
2022-08-04 14:37:51 -06:00
|
|
|
func (a *AggregateRoot) Events(new bool) Events {
|
|
|
|
a.mu.RLock()
|
|
|
|
defer a.mu.RUnlock()
|
|
|
|
|
|
|
|
events := a.events
|
|
|
|
if new {
|
2023-01-15 17:00:25 -07:00
|
|
|
events = events[a.lastIndex-a.firstIndex:]
|
2022-08-04 14:37:51 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
lis := make(Events, len(events))
|
|
|
|
copy(lis, events)
|
|
|
|
|
|
|
|
return lis
|
|
|
|
}
|
|
|
|
|
2023-01-15 17:00:25 -07:00
|
|
|
func (a *AggregateRoot) start(i uint64) {
|
|
|
|
a.firstIndex = i
|
|
|
|
a.lastIndex = i
|
|
|
|
}
|
|
|
|
|
2022-08-04 14:37:51 -06:00
|
|
|
//lint:ignore U1000 is called by embeded interface
|
|
|
|
func (a *AggregateRoot) raise(lis ...Event) { //nolint
|
|
|
|
a.mu.Lock()
|
|
|
|
defer a.mu.Unlock()
|
|
|
|
|
|
|
|
a.posStartAt(lis...)
|
|
|
|
|
|
|
|
a.events = append(a.events, lis...)
|
|
|
|
}
|
|
|
|
|
|
|
|
//lint:ignore U1000 is called by embeded interface
|
|
|
|
func (a *AggregateRoot) append(lis ...Event) {
|
|
|
|
a.mu.Lock()
|
|
|
|
defer a.mu.Unlock()
|
|
|
|
|
|
|
|
a.posStartAt(lis...)
|
|
|
|
|
|
|
|
a.events = append(a.events, lis...)
|
2023-01-15 17:00:25 -07:00
|
|
|
a.lastIndex += uint64(len(lis))
|
2022-08-04 14:37:51 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
func (a *AggregateRoot) posStartAt(lis ...Event) {
|
|
|
|
for i, e := range lis {
|
|
|
|
m := e.EventMeta()
|
2023-01-15 17:00:25 -07:00
|
|
|
m.Position = a.lastIndex + uint64(i) + 1
|
2022-08-04 14:37:51 -06:00
|
|
|
e.SetEventMeta(m)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
var ErrShouldNotExist = errors.New("should not exist")
|
2022-08-14 10:04:15 -06:00
|
|
|
var ErrShouldExist = errors.New("should exist")
|