feat: add create salty user
This commit is contained in:
@@ -3,7 +3,6 @@ package diskstore
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
@@ -94,12 +93,14 @@ func (d *diskStore) Open(ctx context.Context, dsn string) (driver.Driver, error)
|
||||
|
||||
err := w.Close()
|
||||
if err != nil {
|
||||
log.Print(err)
|
||||
span.RecordError(err)
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
})
|
||||
})
|
||||
if err != nil {
|
||||
span.RecordError(err)
|
||||
return nil, err
|
||||
}
|
||||
logs := &openlogs{logs: c}
|
||||
@@ -127,6 +128,7 @@ func (ds *diskStore) EventLog(ctx context.Context, streamID string) (driver.Even
|
||||
|
||||
l, err := wal.Open(filepath.Join(ds.path, streamID), wal.DefaultOptions)
|
||||
if err != nil {
|
||||
span.RecordError(err)
|
||||
return err
|
||||
}
|
||||
el.events = locker.New(l)
|
||||
@@ -155,6 +157,7 @@ func (es *eventLog) Append(ctx context.Context, events event.Events, version uin
|
||||
|
||||
last, err := l.LastIndex()
|
||||
if err != nil {
|
||||
span.RecordError(err)
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -170,6 +173,8 @@ func (es *eventLog) Append(ctx context.Context, events event.Events, version uin
|
||||
|
||||
b, err = event.MarshalText(e)
|
||||
if err != nil {
|
||||
span.RecordError(err)
|
||||
|
||||
return err
|
||||
}
|
||||
pos := last + uint64(i) + 1
|
||||
@@ -196,10 +201,12 @@ func (es *eventLog) Read(ctx context.Context, pos, count int64) (event.Events, e
|
||||
|
||||
first, err := stream.FirstIndex()
|
||||
if err != nil {
|
||||
span.RecordError(err)
|
||||
return err
|
||||
}
|
||||
last, err := stream.LastIndex()
|
||||
if err != nil {
|
||||
span.RecordError(err)
|
||||
return err
|
||||
}
|
||||
// ---
|
||||
@@ -208,7 +215,7 @@ func (es *eventLog) Read(ctx context.Context, pos, count int64) (event.Events, e
|
||||
}
|
||||
|
||||
start, count := math.PagerBox(first, last, pos, count)
|
||||
log.Println("reading", first, last, pos, count, start)
|
||||
span.AddEvent(fmt.Sprint("reading", first, last, pos, count, start))
|
||||
if count == 0 {
|
||||
return nil
|
||||
}
|
||||
@@ -221,10 +228,12 @@ func (es *eventLog) Read(ctx context.Context, pos, count int64) (event.Events, e
|
||||
var b []byte
|
||||
b, err = stream.Read(start)
|
||||
if err != nil {
|
||||
span.RecordError(err)
|
||||
return err
|
||||
}
|
||||
events[i], err = event.UnmarshalText(ctx, b, start)
|
||||
if err != nil {
|
||||
span.RecordError(err)
|
||||
return err
|
||||
}
|
||||
// ---
|
||||
@@ -242,12 +251,13 @@ func (es *eventLog) Read(ctx context.Context, pos, count int64) (event.Events, e
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
span.RecordError(err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
event.SetStreamID(es.streamID, events...)
|
||||
|
||||
return events, err
|
||||
return events, nil
|
||||
}
|
||||
func (es *eventLog) FirstIndex(ctx context.Context) (uint64, error) {
|
||||
_, span := logz.Span(ctx)
|
||||
@@ -277,3 +287,6 @@ func (es *eventLog) LastIndex(ctx context.Context) (uint64, error) {
|
||||
|
||||
return idx, err
|
||||
}
|
||||
func (es *eventLog) LoadForUpdate(ctx context.Context, a event.Aggregate, fn func(context.Context, event.Aggregate) error) (uint64, error) {
|
||||
panic("not implemented")
|
||||
}
|
||||
|
||||
@@ -14,8 +14,10 @@ type Driver interface {
|
||||
type EventLog interface {
|
||||
Read(ctx context.Context, pos, count int64) (event.Events, error)
|
||||
Append(ctx context.Context, events event.Events, version uint64) (uint64, error)
|
||||
FirstIndex(ctx context.Context) (uint64, error)
|
||||
LastIndex(ctx context.Context) (uint64, error)
|
||||
FirstIndex(context.Context) (uint64, error)
|
||||
LastIndex(context.Context) (uint64, error)
|
||||
|
||||
LoadForUpdate(context.Context, event.Aggregate, func(context.Context, event.Aggregate) error) (uint64, error)
|
||||
}
|
||||
|
||||
type Subscription interface {
|
||||
|
||||
@@ -79,6 +79,8 @@ func (m *eventLog) Append(ctx context.Context, events event.Events, version uint
|
||||
_, span := logz.Span(ctx)
|
||||
defer span.End()
|
||||
|
||||
span.AddEvent(fmt.Sprintf(" %s %#v %d", m.streamID, stream, len(*stream)))
|
||||
|
||||
last := uint64(len(*stream))
|
||||
if version != AppendOnly && version != last {
|
||||
return fmt.Errorf("current version wrong %d != %d", version, last)
|
||||
@@ -97,16 +99,18 @@ func (m *eventLog) Append(ctx context.Context, events event.Events, version uint
|
||||
}
|
||||
|
||||
// Read implements driver.EventStore
|
||||
func (es *eventLog) Read(ctx context.Context, pos int64, count int64) (event.Events, error) {
|
||||
func (m *eventLog) Read(ctx context.Context, pos int64, count int64) (event.Events, error) {
|
||||
ctx, span := logz.Span(ctx)
|
||||
defer span.End()
|
||||
|
||||
var events event.Events
|
||||
|
||||
err := es.events.Modify(ctx, func(stream *event.Events) error {
|
||||
err := m.events.Modify(ctx, func(stream *event.Events) error {
|
||||
_, span := logz.Span(ctx)
|
||||
defer span.End()
|
||||
|
||||
span.AddEvent(fmt.Sprintf(" %s %#v %d", m.streamID, stream, len(*stream)))
|
||||
|
||||
first := stream.First().EventMeta().Position
|
||||
last := stream.Last().EventMeta().Position
|
||||
// ---
|
||||
@@ -118,7 +122,7 @@ func (es *eventLog) Read(ctx context.Context, pos int64, count int64) (event.Eve
|
||||
if count == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
span.AddEvent(fmt.Sprint("box", first, last, pos, count))
|
||||
events = make([]event.Event, math.Abs(count))
|
||||
for i := range events {
|
||||
span.AddEvent(fmt.Sprintf("read event %d of %d", i, math.Abs(count)))
|
||||
@@ -143,7 +147,7 @@ func (es *eventLog) Read(ctx context.Context, pos int64, count int64) (event.Eve
|
||||
return nil, err
|
||||
}
|
||||
|
||||
event.SetStreamID(es.streamID, events...)
|
||||
event.SetStreamID(m.streamID, events...)
|
||||
|
||||
return events, nil
|
||||
}
|
||||
@@ -165,3 +169,7 @@ func (m *eventLog) LastIndex(ctx context.Context) (uint64, error) {
|
||||
events, err := m.events.Copy(ctx)
|
||||
return events.Last().EventMeta().Position, err
|
||||
}
|
||||
|
||||
func (m *eventLog) LoadForUpdate(ctx context.Context, a event.Aggregate, fn func(context.Context, event.Aggregate) error) (uint64, error) {
|
||||
panic("not implemented")
|
||||
}
|
||||
|
||||
@@ -169,6 +169,10 @@ func (w *wrapper) LastIndex(ctx context.Context) (uint64, error) {
|
||||
return w.up.LastIndex(ctx)
|
||||
}
|
||||
|
||||
func (w *wrapper) LoadForUpdate(ctx context.Context, a event.Aggregate, fn func(context.Context, event.Aggregate) error) (uint64, error) {
|
||||
return w.up.LoadForUpdate(ctx, a, fn)
|
||||
}
|
||||
|
||||
type position struct {
|
||||
size int64
|
||||
idx int64
|
||||
|
||||
70
pkg/es/es.go
70
pkg/es/es.go
@@ -110,13 +110,17 @@ func (es *EventStore) Save(ctx context.Context, agg event.Aggregate) (uint64, er
|
||||
ctx, span := logz.Span(ctx)
|
||||
defer span.End()
|
||||
|
||||
events := agg.Events(true)
|
||||
if len(events) == 0 {
|
||||
return 0, nil
|
||||
}
|
||||
|
||||
Mes_save.Add(ctx, 1)
|
||||
|
||||
l, err := es.EventLog(ctx, agg.StreamID())
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
events := agg.Events(true)
|
||||
|
||||
count, err := l.Append(ctx, events, agg.StreamVersion())
|
||||
if err != nil {
|
||||
@@ -141,6 +145,7 @@ func (es *EventStore) Load(ctx context.Context, agg event.Aggregate) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
event.Append(agg, events...)
|
||||
|
||||
return nil
|
||||
@@ -189,7 +194,6 @@ func (es *EventStore) LastIndex(ctx context.Context, streamID string) (uint64, e
|
||||
}
|
||||
return l.LastIndex(ctx)
|
||||
}
|
||||
|
||||
func (es *EventStore) EventStream() driver.EventStream {
|
||||
d := es.Driver
|
||||
for d != nil {
|
||||
@@ -212,3 +216,65 @@ func Unwrap[T any](t T) T {
|
||||
}
|
||||
|
||||
var ErrNoDriver = errors.New("no driver")
|
||||
|
||||
type PA[T any] interface {
|
||||
event.Aggregate
|
||||
*T
|
||||
}
|
||||
|
||||
// Create uses fn to create a new aggregate and store in db.
|
||||
func Create[A any, T PA[A]](ctx context.Context, es *EventStore, streamID string, fn func(context.Context, T) error) (agg T, err error) {
|
||||
ctx, span := logz.Span(ctx)
|
||||
defer span.End()
|
||||
|
||||
agg = new(A)
|
||||
agg.SetStreamID(streamID)
|
||||
|
||||
if err = es.Load(ctx, agg); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if err = event.NotExists(agg); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if err = fn(ctx, agg); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
var i uint64
|
||||
if i, err = es.Save(ctx, agg); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
span.AddEvent(fmt.Sprint("wrote events = ", i))
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// Update uses fn to update an exsisting aggregate and store in db.
|
||||
func Update[A any, T PA[A]](ctx context.Context, es *EventStore, streamID string, fn func(context.Context, T) error) (agg T, err error) {
|
||||
ctx, span := logz.Span(ctx)
|
||||
defer span.End()
|
||||
|
||||
agg = new(A)
|
||||
agg.SetStreamID(streamID)
|
||||
|
||||
if err = es.Load(ctx, agg); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if err = event.ShouldExist(agg); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if err = fn(ctx, agg); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if _, err = es.Save(ctx, agg); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
@@ -9,7 +9,6 @@ import (
|
||||
type Aggregate interface {
|
||||
// ApplyEvent applies the event to the aggrigate state
|
||||
ApplyEvent(...Event)
|
||||
StreamID() string
|
||||
|
||||
AggregateRootInterface
|
||||
}
|
||||
@@ -28,14 +27,6 @@ func Append(a Aggregate, lis ...Event) {
|
||||
a.ApplyEvent(lis...)
|
||||
}
|
||||
|
||||
// CheckVersion returns an error if the version does not match.
|
||||
func CheckVersion(a Aggregate, version uint64) error {
|
||||
if version != uint64(a.StreamVersion()) {
|
||||
return fmt.Errorf("version wrong, got (proposed) %d != (expected) %d", version, a.StreamVersion())
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// NotExists returns error if there are no events present.
|
||||
func NotExists(a Aggregate) error {
|
||||
if a.StreamVersion() != 0 {
|
||||
@@ -44,10 +35,22 @@ func NotExists(a Aggregate) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// ShouldExists returns error if there are no events present.
|
||||
func ShouldExist(a Aggregate) error {
|
||||
if a.StreamVersion() == 0 {
|
||||
return fmt.Errorf("%w, got version == %d", ErrShouldExist, a.StreamVersion())
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type AggregateRootInterface interface {
|
||||
// Events returns the aggrigate events
|
||||
// Events returns the aggregate events
|
||||
// pass true for only uncommitted events
|
||||
Events(bool) Events
|
||||
// StreamID returns aggregate stream ID
|
||||
StreamID() string
|
||||
// SetStreamID sets aggregate stream ID
|
||||
SetStreamID(streamID string)
|
||||
// StreamVersion returns last commit events
|
||||
StreamVersion() uint64
|
||||
// Version returns the current aggrigate version. (committed + uncommitted)
|
||||
@@ -62,18 +65,17 @@ var _ AggregateRootInterface = &AggregateRoot{}
|
||||
|
||||
type AggregateRoot struct {
|
||||
events Events
|
||||
streamID string
|
||||
streamVersion uint64
|
||||
|
||||
mu sync.RWMutex
|
||||
}
|
||||
|
||||
func (a *AggregateRoot) Commit() {
|
||||
a.streamVersion = uint64(len(a.events))
|
||||
}
|
||||
|
||||
func (a *AggregateRoot) StreamVersion() uint64 {
|
||||
return a.streamVersion
|
||||
}
|
||||
func (a *AggregateRoot) Commit() { a.streamVersion = 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.streamVersion }
|
||||
func (a *AggregateRoot) Version() uint64 { return uint64(len(a.events)) }
|
||||
func (a *AggregateRoot) Events(new bool) Events {
|
||||
a.mu.RLock()
|
||||
defer a.mu.RUnlock()
|
||||
@@ -88,9 +90,6 @@ func (a *AggregateRoot) Events(new bool) Events {
|
||||
|
||||
return lis
|
||||
}
|
||||
func (a *AggregateRoot) Version() uint64 {
|
||||
return uint64(len(a.events))
|
||||
}
|
||||
|
||||
//lint:ignore U1000 is called by embeded interface
|
||||
func (a *AggregateRoot) raise(lis ...Event) { //nolint
|
||||
@@ -122,3 +121,4 @@ func (a *AggregateRoot) posStartAt(lis ...Event) {
|
||||
}
|
||||
|
||||
var ErrShouldNotExist = errors.New("should not exist")
|
||||
var ErrShouldExist = errors.New("should exist")
|
||||
|
||||
56
pkg/es/event/aggregate_test.go
Normal file
56
pkg/es/event/aggregate_test.go
Normal file
@@ -0,0 +1,56 @@
|
||||
package event_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/sour-is/ev/pkg/es/event"
|
||||
)
|
||||
|
||||
type Agg struct {
|
||||
Value string
|
||||
|
||||
event.AggregateRoot
|
||||
}
|
||||
|
||||
var _ event.Aggregate = (*Agg)(nil)
|
||||
|
||||
func (a *Agg) streamID() string {
|
||||
return "value-" + a.Value
|
||||
}
|
||||
|
||||
// ApplyEvent applies the event to the aggrigate state
|
||||
func (a *Agg) ApplyEvent(lis ...event.Event) {
|
||||
for _, e := range lis {
|
||||
switch e := e.(type) {
|
||||
case *ValueApplied:
|
||||
a.Value = e.Value
|
||||
a.SetStreamID(a.streamID())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
type ValueApplied struct {
|
||||
Value string
|
||||
|
||||
eventMeta event.Meta
|
||||
}
|
||||
|
||||
var _ event.Event = (*ValueApplied)(nil)
|
||||
|
||||
func (e *ValueApplied) EventMeta() event.Meta {
|
||||
if e == nil {
|
||||
return event.Meta{}
|
||||
}
|
||||
return e.eventMeta
|
||||
}
|
||||
|
||||
func (e *ValueApplied) SetEventMeta(m event.Meta) {
|
||||
if e != nil {
|
||||
e.eventMeta = m
|
||||
}
|
||||
}
|
||||
|
||||
func TestAggregate(t *testing.T) {
|
||||
agg := &Agg{}
|
||||
event.Append(agg, &ValueApplied{Value: "one"})
|
||||
}
|
||||
Reference in New Issue
Block a user