mirror of
https://github.com/zitadel/zitadel.git
synced 2024-12-04 23:45:07 +00:00
feat(eventstore): sdk (#39)
* sdk * fix(sdk): return correct error type * AppendEventError instead of Aggregater error * fix(tests): tests * fix(tests): wantErr to is error func
This commit is contained in:
parent
970586dfc9
commit
191690d905
@ -17,11 +17,11 @@ type AlreadyExistsError struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func ThrowAlreadyExists(parent error, id, message string) error {
|
func ThrowAlreadyExists(parent error, id, message string) error {
|
||||||
return &AlreadyExistsError{createCaosError(parent, id, message)}
|
return &AlreadyExistsError{CreateCaosError(parent, id, message)}
|
||||||
}
|
}
|
||||||
|
|
||||||
func ThrowAlreadyExistsf(parent error, id, format string, a ...interface{}) error {
|
func ThrowAlreadyExistsf(parent error, id, format string, a ...interface{}) error {
|
||||||
return &AlreadyExistsError{createCaosError(parent, id, fmt.Sprintf(format, a...))}
|
return &AlreadyExistsError{CreateCaosError(parent, id, fmt.Sprintf(format, a...))}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (err *AlreadyExistsError) IsAlreadyExists() {}
|
func (err *AlreadyExistsError) IsAlreadyExists() {}
|
||||||
|
@ -13,10 +13,10 @@ type CaosError struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func ThrowError(parent error, id, message string) error {
|
func ThrowError(parent error, id, message string) error {
|
||||||
return createCaosError(parent, id, message)
|
return CreateCaosError(parent, id, message)
|
||||||
}
|
}
|
||||||
|
|
||||||
func createCaosError(parent error, id, message string) *CaosError {
|
func CreateCaosError(parent error, id, message string) *CaosError {
|
||||||
return &CaosError{
|
return &CaosError{
|
||||||
Parent: parent,
|
Parent: parent,
|
||||||
ID: id,
|
ID: id,
|
||||||
|
@ -19,7 +19,7 @@ type DeadlineExceededError struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func ThrowDeadlineExceeded(parent error, id, message string) error {
|
func ThrowDeadlineExceeded(parent error, id, message string) error {
|
||||||
return &DeadlineExceededError{createCaosError(parent, id, message)}
|
return &DeadlineExceededError{CreateCaosError(parent, id, message)}
|
||||||
}
|
}
|
||||||
|
|
||||||
func ThrowDeadlineExceededf(parent error, id, format string, a ...interface{}) error {
|
func ThrowDeadlineExceededf(parent error, id, format string, a ...interface{}) error {
|
||||||
|
@ -19,7 +19,7 @@ type {{.ErrorName}}Error struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func Throw{{.ErrorName}}(parent error, id, message string) error {
|
func Throw{{.ErrorName}}(parent error, id, message string) error {
|
||||||
return &{{.ErrorName}}Error{createCaosError(parent, id, message)}
|
return &{{.ErrorName}}Error{CreateCaosError(parent, id, message)}
|
||||||
}
|
}
|
||||||
|
|
||||||
func Throw{{.ErrorName}}f(parent error, id, format string, a ...interface{}) error {
|
func Throw{{.ErrorName}}f(parent error, id, format string, a ...interface{}) error {
|
||||||
|
@ -12,7 +12,7 @@ import (
|
|||||||
func Test{{.ErrorName}}Error(t *testing.T) {
|
func Test{{.ErrorName}}Error(t *testing.T) {
|
||||||
var err interface{}
|
var err interface{}
|
||||||
err = new(caos_errs.{{.ErrorName}}Error)
|
err = new(caos_errs.{{.ErrorName}}Error)
|
||||||
_, ok := err.(caos_errs.{{.ErrorName}})
|
_, ok := err.(*caos_errs.{{.ErrorName}})
|
||||||
assert.True(t, ok)
|
assert.True(t, ok)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -19,7 +19,7 @@ type InternalError struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func ThrowInternal(parent error, id, message string) error {
|
func ThrowInternal(parent error, id, message string) error {
|
||||||
return &InternalError{createCaosError(parent, id, message)}
|
return &InternalError{CreateCaosError(parent, id, message)}
|
||||||
}
|
}
|
||||||
|
|
||||||
func ThrowInternalf(parent error, id, format string, a ...interface{}) error {
|
func ThrowInternalf(parent error, id, format string, a ...interface{}) error {
|
||||||
|
@ -17,7 +17,7 @@ type InvalidArgumentError struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func ThrowInvalidArgument(parent error, id, message string) error {
|
func ThrowInvalidArgument(parent error, id, message string) error {
|
||||||
return &InvalidArgumentError{createCaosError(parent, id, message)}
|
return &InvalidArgumentError{CreateCaosError(parent, id, message)}
|
||||||
}
|
}
|
||||||
|
|
||||||
func ThrowInvalidArgumentf(parent error, id, format string, a ...interface{}) error {
|
func ThrowInvalidArgumentf(parent error, id, format string, a ...interface{}) error {
|
||||||
|
@ -12,7 +12,7 @@ type NotFoundError struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func ThrowNotFound(parent error, id, message string) error {
|
func ThrowNotFound(parent error, id, message string) error {
|
||||||
return &NotFoundError{createCaosError(parent, id, message)}
|
return &NotFoundError{CreateCaosError(parent, id, message)}
|
||||||
}
|
}
|
||||||
|
|
||||||
func ThrowNotFoundf(parent error, id, format string, a ...interface{}) error {
|
func ThrowNotFoundf(parent error, id, format string, a ...interface{}) error {
|
||||||
|
@ -19,7 +19,7 @@ type PermissionDeniedError struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func ThrowPermissionDenied(parent error, id, message string) error {
|
func ThrowPermissionDenied(parent error, id, message string) error {
|
||||||
return &PermissionDeniedError{createCaosError(parent, id, message)}
|
return &PermissionDeniedError{CreateCaosError(parent, id, message)}
|
||||||
}
|
}
|
||||||
|
|
||||||
func ThrowPermissionDeniedf(parent error, id, format string, a ...interface{}) error {
|
func ThrowPermissionDeniedf(parent error, id, format string, a ...interface{}) error {
|
||||||
|
@ -19,7 +19,7 @@ type PreconditionFailedError struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func ThrowPreconditionFailed(parent error, id, message string) error {
|
func ThrowPreconditionFailed(parent error, id, message string) error {
|
||||||
return &PreconditionFailedError{createCaosError(parent, id, message)}
|
return &PreconditionFailedError{CreateCaosError(parent, id, message)}
|
||||||
}
|
}
|
||||||
|
|
||||||
func ThrowPreconditionFailedf(parent error, id, format string, a ...interface{}) error {
|
func ThrowPreconditionFailedf(parent error, id, format string, a ...interface{}) error {
|
||||||
|
@ -19,7 +19,7 @@ type UnauthenticatedError struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func ThrowUnauthenticated(parent error, id, message string) error {
|
func ThrowUnauthenticated(parent error, id, message string) error {
|
||||||
return &UnauthenticatedError{createCaosError(parent, id, message)}
|
return &UnauthenticatedError{CreateCaosError(parent, id, message)}
|
||||||
}
|
}
|
||||||
|
|
||||||
func ThrowUnauthenticatedf(parent error, id, format string, a ...interface{}) error {
|
func ThrowUnauthenticatedf(parent error, id, format string, a ...interface{}) error {
|
||||||
|
@ -19,7 +19,7 @@ type UnavailableError struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func ThrowUnavailable(parent error, id, message string) error {
|
func ThrowUnavailable(parent error, id, message string) error {
|
||||||
return &UnavailableError{createCaosError(parent, id, message)}
|
return &UnavailableError{CreateCaosError(parent, id, message)}
|
||||||
}
|
}
|
||||||
|
|
||||||
func ThrowUnavailablef(parent error, id, format string, a ...interface{}) error {
|
func ThrowUnavailablef(parent error, id, format string, a ...interface{}) error {
|
||||||
|
@ -19,7 +19,7 @@ type UnimplementedError struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func ThrowUnimplemented(parent error, id, message string) error {
|
func ThrowUnimplemented(parent error, id, message string) error {
|
||||||
return &UnimplementedError{createCaosError(parent, id, message)}
|
return &UnimplementedError{CreateCaosError(parent, id, message)}
|
||||||
}
|
}
|
||||||
|
|
||||||
func ThrowUnimplementedf(parent error, id, format string, a ...interface{}) error {
|
func ThrowUnimplementedf(parent error, id, format string, a ...interface{}) error {
|
||||||
|
@ -19,7 +19,7 @@ type UnknownError struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func ThrowUnknown(parent error, id, message string) error {
|
func ThrowUnknown(parent error, id, message string) error {
|
||||||
return &UnknownError{createCaosError(parent, id, message)}
|
return &UnknownError{CreateCaosError(parent, id, message)}
|
||||||
}
|
}
|
||||||
|
|
||||||
func ThrowUnknownf(parent error, id, format string, a ...interface{}) error {
|
func ThrowUnknownf(parent error, id, format string, a ...interface{}) error {
|
||||||
|
@ -33,7 +33,7 @@ func (es *eventstore) PushAggregates(ctx context.Context, aggregates ...*models.
|
|||||||
}
|
}
|
||||||
for _, event := range aggregate.Events {
|
for _, event := range aggregate.Events {
|
||||||
if err = event.Validate(); err != nil {
|
if err = event.Validate(); err != nil {
|
||||||
return err
|
return errors.ThrowInvalidArgument(err, "EVENT-tzIhl", "validate event failed")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -42,12 +42,6 @@ func (es *eventstore) PushAggregates(ctx context.Context, aggregates ...*models.
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, aggregate := range aggregates {
|
|
||||||
if aggregate.Appender != nil {
|
|
||||||
aggregate.Appender(aggregate.Events...)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -24,11 +24,8 @@ type Aggregate struct {
|
|||||||
editorUser string
|
editorUser string
|
||||||
resourceOwner string
|
resourceOwner string
|
||||||
Events []*Event
|
Events []*Event
|
||||||
Appender appender
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type appender func(...*Event)
|
|
||||||
|
|
||||||
func (a *Aggregate) AppendEvent(typ EventType, payload interface{}) (*Aggregate, error) {
|
func (a *Aggregate) AppendEvent(typ EventType, payload interface{}) (*Aggregate, error) {
|
||||||
if string(typ) == "" {
|
if string(typ) == "" {
|
||||||
return a, errors.ThrowInvalidArgument(nil, "MODEL-TGoCb", "no event type")
|
return a, errors.ThrowInvalidArgument(nil, "MODEL-TGoCb", "no event type")
|
||||||
@ -81,8 +78,3 @@ func (a *Aggregate) Validate() error {
|
|||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *Aggregate) SetAppender(appendFn appender) *Aggregate {
|
|
||||||
a.Appender = appendFn
|
|
||||||
return a
|
|
||||||
}
|
|
||||||
|
36
internal/eventstore/sdk/append_event_error.go
Normal file
36
internal/eventstore/sdk/append_event_error.go
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
package sdk
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/caos/zitadel/internal/errors"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
_ AppendEventError = (*appendEventError)(nil)
|
||||||
|
_ errors.Error = (*appendEventError)(nil)
|
||||||
|
)
|
||||||
|
|
||||||
|
type AppendEventError interface {
|
||||||
|
error
|
||||||
|
IsAppendEventError()
|
||||||
|
}
|
||||||
|
|
||||||
|
type appendEventError struct {
|
||||||
|
*errors.CaosError
|
||||||
|
}
|
||||||
|
|
||||||
|
func ThrowAppendEventError(parent error, id, message string) error {
|
||||||
|
return &appendEventError{errors.CreateCaosError(parent, id, message)}
|
||||||
|
}
|
||||||
|
|
||||||
|
func ThrowAggregaterf(parent error, id, format string, a ...interface{}) error {
|
||||||
|
return ThrowAppendEventError(parent, id, fmt.Sprintf(format, a...))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (err *appendEventError) IsAppendEventError() {}
|
||||||
|
|
||||||
|
func IsAppendEventError(err error) bool {
|
||||||
|
_, ok := err.(AppendEventError)
|
||||||
|
return ok
|
||||||
|
}
|
31
internal/eventstore/sdk/append_event_error_test.go
Normal file
31
internal/eventstore/sdk/append_event_error_test.go
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
package sdk
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestAppendEventError(t *testing.T) {
|
||||||
|
var err interface{}
|
||||||
|
err = new(appendEventError)
|
||||||
|
_, ok := err.(*appendEventError)
|
||||||
|
assert.True(t, ok)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestThrowAppendEventErrorf(t *testing.T) {
|
||||||
|
err := ThrowAggregaterf(nil, "id", "msg")
|
||||||
|
_, ok := err.(*appendEventError)
|
||||||
|
assert.True(t, ok)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestIsAppendEventError(t *testing.T) {
|
||||||
|
err := ThrowAppendEventError(nil, "id", "msg")
|
||||||
|
ok := IsAppendEventError(err)
|
||||||
|
assert.True(t, ok)
|
||||||
|
|
||||||
|
err = errors.New("i am found")
|
||||||
|
ok = IsAppendEventError(err)
|
||||||
|
assert.False(t, ok)
|
||||||
|
}
|
72
internal/eventstore/sdk/sdk.go
Normal file
72
internal/eventstore/sdk/sdk.go
Normal file
@ -0,0 +1,72 @@
|
|||||||
|
package sdk
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"github.com/caos/zitadel/internal/errors"
|
||||||
|
"github.com/caos/zitadel/internal/eventstore/models"
|
||||||
|
es_models "github.com/caos/zitadel/internal/eventstore/models"
|
||||||
|
)
|
||||||
|
|
||||||
|
type filterFunc func(context.Context, *es_models.SearchQuery) ([]*es_models.Event, error)
|
||||||
|
type appendFunc func(...*es_models.Event) error
|
||||||
|
type aggregateFunc func(context.Context) (*es_models.Aggregate, error)
|
||||||
|
type pushFunc func(context.Context, ...*es_models.Aggregate) error
|
||||||
|
|
||||||
|
func Filter(ctx context.Context, filter filterFunc, appender appendFunc, query *es_models.SearchQuery) error {
|
||||||
|
events, err := filter(ctx, query)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if len(events) == 0 {
|
||||||
|
return errors.ThrowNotFound(nil, "EVENT-8due3", "no events found")
|
||||||
|
}
|
||||||
|
err = appender(events...)
|
||||||
|
if err != nil{
|
||||||
|
return ThrowAppendEventError(err, "SDK-awiWK", "appender failed")
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Push creates the aggregates from aggregater
|
||||||
|
// and pushes the aggregates to the given pushFunc
|
||||||
|
// the given events are appended by the appender
|
||||||
|
func Push(ctx context.Context, push pushFunc, appender appendFunc, aggregaters ...aggregateFunc) (err error) {
|
||||||
|
if len(aggregaters) < 1 {
|
||||||
|
return errors.ThrowPreconditionFailed(nil, "SDK-q9wjp", "no aggregaters passed")
|
||||||
|
}
|
||||||
|
|
||||||
|
aggregates, err := makeAggregates(ctx, aggregaters)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
err = push(ctx, aggregates...)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
return appendAggregates(appender, aggregates)
|
||||||
|
}
|
||||||
|
|
||||||
|
func appendAggregates(appender appendFunc, aggregates []*models.Aggregate) error {
|
||||||
|
for _, aggregate := range aggregates {
|
||||||
|
err := appender(aggregate.Events...)
|
||||||
|
if err != nil {
|
||||||
|
return ThrowAppendEventError(err, "SDK-o6kzK", "aggregator failed")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func makeAggregates(ctx context.Context, aggregaters []aggregateFunc) (aggregates []*models.Aggregate, err error) {
|
||||||
|
aggregates = make([]*models.Aggregate, len(aggregaters))
|
||||||
|
for i, aggregater := range aggregaters {
|
||||||
|
aggregates[i], err = aggregater(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return aggregates, nil
|
||||||
|
}
|
193
internal/eventstore/sdk/sdk_test.go
Normal file
193
internal/eventstore/sdk/sdk_test.go
Normal file
@ -0,0 +1,193 @@
|
|||||||
|
package sdk
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/caos/zitadel/internal/errors"
|
||||||
|
es_models "github.com/caos/zitadel/internal/eventstore/models"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestFilter(t *testing.T) {
|
||||||
|
type args struct {
|
||||||
|
filter filterFunc
|
||||||
|
appender appendFunc
|
||||||
|
}
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
args args
|
||||||
|
wantErr func(error) bool
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "filter error",
|
||||||
|
args: args{
|
||||||
|
filter: func(context.Context, *es_models.SearchQuery) ([]*es_models.Event, error) {
|
||||||
|
return nil, errors.ThrowInternal(nil, "test-46VX2", "test error")
|
||||||
|
},
|
||||||
|
appender: nil,
|
||||||
|
},
|
||||||
|
wantErr: errors.IsInternal,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "no events found",
|
||||||
|
args: args{
|
||||||
|
filter: func(context.Context, *es_models.SearchQuery) ([]*es_models.Event, error) {
|
||||||
|
return []*es_models.Event{}, nil
|
||||||
|
},
|
||||||
|
appender: nil,
|
||||||
|
},
|
||||||
|
wantErr: errors.IsNotFound,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "append fails",
|
||||||
|
args: args{
|
||||||
|
filter: func(context.Context, *es_models.SearchQuery) ([]*es_models.Event, error) {
|
||||||
|
return []*es_models.Event{&es_models.Event{}}, nil
|
||||||
|
},
|
||||||
|
appender: func(...*es_models.Event) error {
|
||||||
|
return errors.ThrowInvalidArgument(nil, "SDK-DhBzl", "test error")
|
||||||
|
},
|
||||||
|
},
|
||||||
|
wantErr: IsAppendEventError,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "filter correct",
|
||||||
|
args: args{
|
||||||
|
filter: func(context.Context, *es_models.SearchQuery) ([]*es_models.Event, error) {
|
||||||
|
return []*es_models.Event{&es_models.Event{}}, nil
|
||||||
|
},
|
||||||
|
appender: func(...*es_models.Event) error {
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
},
|
||||||
|
wantErr: nil,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
err := Filter(context.Background(), tt.args.filter, tt.args.appender, nil)
|
||||||
|
if tt.wantErr == nil && err != nil {
|
||||||
|
t.Errorf("no error expected %v", err)
|
||||||
|
}
|
||||||
|
if tt.wantErr != nil && !tt.wantErr(err) {
|
||||||
|
t.Errorf("no error has wrong type %v", err)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestPush(t *testing.T) {
|
||||||
|
type args struct {
|
||||||
|
push pushFunc
|
||||||
|
appender appendFunc
|
||||||
|
aggregaters []aggregateFunc
|
||||||
|
}
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
args args
|
||||||
|
wantErr func(error) bool
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "no aggregates",
|
||||||
|
args: args{
|
||||||
|
push: nil,
|
||||||
|
appender: nil,
|
||||||
|
aggregaters: nil,
|
||||||
|
},
|
||||||
|
wantErr: errors.IsPreconditionFailed,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "aggregater fails",
|
||||||
|
args: args{
|
||||||
|
push: nil,
|
||||||
|
appender: nil,
|
||||||
|
aggregaters: []aggregateFunc{
|
||||||
|
func(context.Context) (*es_models.Aggregate, error) {
|
||||||
|
return nil, errors.ThrowInternal(nil, "SDK-Ec5x2", "test err")
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
wantErr: errors.IsInternal,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "push fails",
|
||||||
|
args: args{
|
||||||
|
push: func(context.Context, ...*es_models.Aggregate) error {
|
||||||
|
return errors.ThrowInternal(nil, "SDK-0g4gW", "test error")
|
||||||
|
},
|
||||||
|
appender: nil,
|
||||||
|
aggregaters: []aggregateFunc{
|
||||||
|
func(context.Context) (*es_models.Aggregate, error) {
|
||||||
|
return &es_models.Aggregate{}, nil
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
wantErr: errors.IsInternal,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "append aggregates fails",
|
||||||
|
args: args{
|
||||||
|
push: func(context.Context, ...*es_models.Aggregate) error {
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
appender: func(...*es_models.Event) error {
|
||||||
|
return errors.ThrowInvalidArgument(nil, "SDK-BDhcT", "test err")
|
||||||
|
},
|
||||||
|
aggregaters: []aggregateFunc{
|
||||||
|
func(context.Context) (*es_models.Aggregate, error) {
|
||||||
|
return &es_models.Aggregate{Events: []*es_models.Event{&es_models.Event{}}}, nil
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
wantErr: IsAppendEventError,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "correct one aggregate",
|
||||||
|
args: args{
|
||||||
|
push: func(context.Context, ...*es_models.Aggregate) error {
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
appender: func(...*es_models.Event) error {
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
aggregaters: []aggregateFunc{
|
||||||
|
func(context.Context) (*es_models.Aggregate, error) {
|
||||||
|
return &es_models.Aggregate{Events: []*es_models.Event{&es_models.Event{}}}, nil
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
wantErr: nil,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "correct multiple aggregate",
|
||||||
|
args: args{
|
||||||
|
push: func(context.Context, ...*es_models.Aggregate) error {
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
appender: func(...*es_models.Event) error {
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
aggregaters: []aggregateFunc{
|
||||||
|
func(context.Context) (*es_models.Aggregate, error) {
|
||||||
|
return &es_models.Aggregate{Events: []*es_models.Event{&es_models.Event{}}}, nil
|
||||||
|
},
|
||||||
|
func(context.Context) (*es_models.Aggregate, error) {
|
||||||
|
return &es_models.Aggregate{Events: []*es_models.Event{&es_models.Event{}}}, nil
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
wantErr: nil,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
err := Push(context.Background(), tt.args.push, tt.args.appender, tt.args.aggregaters...)
|
||||||
|
if tt.wantErr == nil && err != nil {
|
||||||
|
t.Errorf("no error expected %v", err)
|
||||||
|
}
|
||||||
|
if tt.wantErr != nil && !tt.wantErr(err) {
|
||||||
|
t.Errorf("no error has wrong type %v", err)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
@ -2,6 +2,7 @@ package eventsourcing
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
|
||||||
proj_model "github.com/caos/zitadel/internal/project/model"
|
proj_model "github.com/caos/zitadel/internal/project/model"
|
||||||
proj_event "github.com/caos/zitadel/internal/project/repository/eventsourcing"
|
proj_event "github.com/caos/zitadel/internal/project/repository/eventsourcing"
|
||||||
)
|
)
|
||||||
@ -26,11 +27,7 @@ func (repo *ProjectRepo) ProjectByID(ctx context.Context, id string) (project *p
|
|||||||
|
|
||||||
func (repo *ProjectRepo) CreateProject(ctx context.Context, name string) (*proj_model.Project, error) {
|
func (repo *ProjectRepo) CreateProject(ctx context.Context, name string) (*proj_model.Project, error) {
|
||||||
project := &proj_model.Project{Name: name}
|
project := &proj_model.Project{Name: name}
|
||||||
project, err := repo.ProjectEvents.CreateProject(ctx, project)
|
return repo.ProjectEvents.CreateProject(ctx, project)
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return project, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (repo *ProjectRepo) UpdateProject(ctx context.Context, project *proj_model.Project) (*proj_model.Project, error) {
|
func (repo *ProjectRepo) UpdateProject(ctx context.Context, project *proj_model.Project) (*proj_model.Project, error) {
|
||||||
@ -39,11 +36,7 @@ func (repo *ProjectRepo) UpdateProject(ctx context.Context, project *proj_model.
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
project, err = repo.ProjectEvents.UpdateProject(ctx, existingProject, project)
|
return repo.ProjectEvents.UpdateProject(ctx, existingProject, project)
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return project, err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (repo *ProjectRepo) DeactivateProject(ctx context.Context, id string) (*proj_model.Project, error) {
|
func (repo *ProjectRepo) DeactivateProject(ctx context.Context, id string) (*proj_model.Project, error) {
|
||||||
@ -52,11 +45,7 @@ func (repo *ProjectRepo) DeactivateProject(ctx context.Context, id string) (*pro
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
project, err = repo.ProjectEvents.DeactivateProject(ctx, project)
|
return repo.ProjectEvents.DeactivateProject(ctx, project)
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return project, err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (repo *ProjectRepo) ReactivateProject(ctx context.Context, id string) (*proj_model.Project, error) {
|
func (repo *ProjectRepo) ReactivateProject(ctx context.Context, id string) (*proj_model.Project, error) {
|
||||||
@ -65,9 +54,5 @@ func (repo *ProjectRepo) ReactivateProject(ctx context.Context, id string) (*pro
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
project, err = repo.ProjectEvents.ReactivateProject(ctx, project)
|
return repo.ProjectEvents.ReactivateProject(ctx, project)
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return project, err
|
|
||||||
}
|
}
|
||||||
|
@ -2,8 +2,10 @@ package eventsourcing
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
|
||||||
caos_errs "github.com/caos/zitadel/internal/errors"
|
caos_errs "github.com/caos/zitadel/internal/errors"
|
||||||
es_int "github.com/caos/zitadel/internal/eventstore"
|
es_int "github.com/caos/zitadel/internal/eventstore"
|
||||||
|
es_sdk "github.com/caos/zitadel/internal/eventstore/sdk"
|
||||||
proj_model "github.com/caos/zitadel/internal/project/model"
|
proj_model "github.com/caos/zitadel/internal/project/model"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -20,22 +22,17 @@ func StartProject(conf ProjectConfig) (*ProjectEventstore, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (es *ProjectEventstore) ProjectByID(ctx context.Context, project *proj_model.Project) (*proj_model.Project, error) {
|
func (es *ProjectEventstore) ProjectByID(ctx context.Context, project *proj_model.Project) (*proj_model.Project, error) {
|
||||||
filter, err := ProjectByIDQuery(project.ID, project.Sequence)
|
query, err := ProjectByIDQuery(project.ID, project.Sequence)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
events, err := es.Eventstore.FilterEvents(ctx, filter)
|
|
||||||
|
p := ProjectFromModel(project)
|
||||||
|
err = es_sdk.Filter(ctx, es.FilterEvents, p.AppendEvents, query)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if len(events) == 0 {
|
return ProjectToModel(p), nil
|
||||||
return nil, caos_errs.ThrowNotFound(nil, "EVENT-8due3", "Could not find project events")
|
|
||||||
}
|
|
||||||
foundProject, err := ProjectFromEvents(nil, events...)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return ProjectToModel(foundProject), nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (es *ProjectEventstore) CreateProject(ctx context.Context, project *proj_model.Project) (*proj_model.Project, error) {
|
func (es *ProjectEventstore) CreateProject(ctx context.Context, project *proj_model.Project) (*proj_model.Project, error) {
|
||||||
@ -44,34 +41,29 @@ func (es *ProjectEventstore) CreateProject(ctx context.Context, project *proj_mo
|
|||||||
}
|
}
|
||||||
project.State = proj_model.Active
|
project.State = proj_model.Active
|
||||||
repoProject := ProjectFromModel(project)
|
repoProject := ProjectFromModel(project)
|
||||||
projectAggregate, err := ProjectCreateAggregate(ctx, es.Eventstore.AggregateCreator(), repoProject)
|
|
||||||
if err != nil {
|
createAggregate := ProjectCreateAggregate(es.AggregateCreator(), repoProject)
|
||||||
return nil, err
|
err := es_sdk.Push(ctx, es.PushAggregates, repoProject.AppendEvents, createAggregate)
|
||||||
}
|
|
||||||
err = es.PushAggregates(ctx, projectAggregate)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
repoProject.AppendEvents(projectAggregate.Events...)
|
|
||||||
return ProjectToModel(repoProject), nil
|
return ProjectToModel(repoProject), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (es *ProjectEventstore) UpdateProject(ctx context.Context, existing *proj_model.Project, new *proj_model.Project) (*proj_model.Project, error) {
|
func (es *ProjectEventstore) UpdateProject(ctx context.Context, existingProject *proj_model.Project, project *proj_model.Project) (*proj_model.Project, error) {
|
||||||
if !new.IsValid() {
|
if !project.IsValid() {
|
||||||
return nil, caos_errs.ThrowPreconditionFailed(nil, "EVENT-9dk45", "Name is required")
|
return nil, caos_errs.ThrowPreconditionFailed(nil, "EVENT-9dk45", "Name is required")
|
||||||
}
|
}
|
||||||
repoExisting := ProjectFromModel(existing)
|
repoExisting := ProjectFromModel(existingProject)
|
||||||
repoNew := ProjectFromModel(new)
|
repoNew := ProjectFromModel(project)
|
||||||
projectAggregate, err := ProjectUpdateAggregate(ctx, es.AggregateCreator(), repoExisting, repoNew)
|
|
||||||
|
updateAggregate := ProjectUpdateAggregate(es.AggregateCreator(), repoExisting, repoNew)
|
||||||
|
err := es_sdk.Push(ctx, es.PushAggregates, repoExisting.AppendEvents, updateAggregate)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
err = es.PushAggregates(ctx, projectAggregate)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
repoExisting.AppendEvents(projectAggregate.Events...)
|
|
||||||
return ProjectToModel(repoExisting), nil
|
return ProjectToModel(repoExisting), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -79,16 +71,10 @@ func (es *ProjectEventstore) DeactivateProject(ctx context.Context, existing *pr
|
|||||||
if !existing.IsActive() {
|
if !existing.IsActive() {
|
||||||
return nil, caos_errs.ThrowPreconditionFailed(nil, "EVENT-die45", "project must be active")
|
return nil, caos_errs.ThrowPreconditionFailed(nil, "EVENT-die45", "project must be active")
|
||||||
}
|
}
|
||||||
|
|
||||||
repoExisting := ProjectFromModel(existing)
|
repoExisting := ProjectFromModel(existing)
|
||||||
projectAggregate, err := ProjectDeactivateAggregate(ctx, es.AggregateCreator(), repoExisting)
|
aggregate := ProjectDeactivateAggregate(es.AggregateCreator(), repoExisting)
|
||||||
if err != nil {
|
es_sdk.Push(ctx, es.PushAggregates, repoExisting.AppendEvents, aggregate)
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
err = es.PushAggregates(ctx, projectAggregate)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
repoExisting.AppendEvents(projectAggregate.Events...)
|
|
||||||
return ProjectToModel(repoExisting), nil
|
return ProjectToModel(repoExisting), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -96,15 +82,9 @@ func (es *ProjectEventstore) ReactivateProject(ctx context.Context, existing *pr
|
|||||||
if existing.IsActive() {
|
if existing.IsActive() {
|
||||||
return nil, caos_errs.ThrowPreconditionFailed(nil, "EVENT-die45", "project must be inactive")
|
return nil, caos_errs.ThrowPreconditionFailed(nil, "EVENT-die45", "project must be inactive")
|
||||||
}
|
}
|
||||||
|
|
||||||
repoExisting := ProjectFromModel(existing)
|
repoExisting := ProjectFromModel(existing)
|
||||||
projectAggregate, err := ProjectReactivateAggregate(ctx, es.AggregateCreator(), repoExisting)
|
aggregate := ProjectReactivateAggregate(es.AggregateCreator(), repoExisting)
|
||||||
if err != nil {
|
es_sdk.Push(ctx, es.PushAggregates, repoExisting.AppendEvents, aggregate)
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
err = es.PushAggregates(ctx, projectAggregate)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
repoExisting.AppendEvents(projectAggregate.Events...)
|
|
||||||
return ProjectToModel(repoExisting), nil
|
return ProjectToModel(repoExisting), nil
|
||||||
}
|
}
|
||||||
|
@ -2,11 +2,48 @@ package eventsourcing
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
|
||||||
"github.com/caos/logging"
|
"github.com/caos/logging"
|
||||||
es_models "github.com/caos/zitadel/internal/eventstore/models"
|
es_models "github.com/caos/zitadel/internal/eventstore/models"
|
||||||
"github.com/caos/zitadel/internal/project/model"
|
"github.com/caos/zitadel/internal/project/model"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
projectVersion = "v1"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Project struct {
|
||||||
|
es_models.ObjectRoot
|
||||||
|
Name string `json:"name,omitempty"`
|
||||||
|
State int32 `json:"-"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func ProjectFromModel(project *model.Project) *Project {
|
||||||
|
return &Project{
|
||||||
|
ObjectRoot: es_models.ObjectRoot{
|
||||||
|
ID: project.ObjectRoot.ID,
|
||||||
|
Sequence: project.Sequence,
|
||||||
|
ChangeDate: project.ChangeDate,
|
||||||
|
CreationDate: project.CreationDate,
|
||||||
|
},
|
||||||
|
Name: project.Name,
|
||||||
|
State: model.ProjectStateToInt(project.State),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func ProjectToModel(project *Project) *model.Project {
|
||||||
|
return &model.Project{
|
||||||
|
ObjectRoot: es_models.ObjectRoot{
|
||||||
|
ID: project.ID,
|
||||||
|
ChangeDate: project.ChangeDate,
|
||||||
|
CreationDate: project.CreationDate,
|
||||||
|
Sequence: project.Sequence,
|
||||||
|
},
|
||||||
|
Name: project.Name,
|
||||||
|
State: model.ProjectStateFromInt(project.State),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func ProjectFromEvents(project *Project, events ...*es_models.Event) (*Project, error) {
|
func ProjectFromEvents(project *Project, events ...*es_models.Event) (*Project, error) {
|
||||||
if project == nil {
|
if project == nil {
|
||||||
project = &Project{}
|
project = &Project{}
|
||||||
@ -15,6 +52,14 @@ func ProjectFromEvents(project *Project, events ...*es_models.Event) (*Project,
|
|||||||
return project, project.AppendEvents(events...)
|
return project, project.AppendEvents(events...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (p *Project) Changes(changed *Project) map[string]interface{} {
|
||||||
|
changes := make(map[string]interface{}, 1)
|
||||||
|
if changed.Name != "" && p.Name != changed.Name {
|
||||||
|
changes["name"] = changed.Name
|
||||||
|
}
|
||||||
|
return changes
|
||||||
|
}
|
||||||
|
|
||||||
func (p *Project) AppendEvents(events ...*es_models.Event) error {
|
func (p *Project) AppendEvents(events ...*es_models.Event) error {
|
||||||
for _, event := range events {
|
for _, event := range events {
|
||||||
if err := p.AppendEvent(event); err != nil {
|
if err := p.AppendEvent(event); err != nil {
|
@ -2,9 +2,10 @@ package eventsourcing
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"testing"
|
||||||
|
|
||||||
es_models "github.com/caos/zitadel/internal/eventstore/models"
|
es_models "github.com/caos/zitadel/internal/eventstore/models"
|
||||||
"github.com/caos/zitadel/internal/project/model"
|
"github.com/caos/zitadel/internal/project/model"
|
||||||
"testing"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestProjectFromEvents(t *testing.T) {
|
func TestProjectFromEvents(t *testing.T) {
|
||||||
@ -167,3 +168,47 @@ func TestAppendReactivatedEvent(t *testing.T) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestChanges(t *testing.T) {
|
||||||
|
type args struct {
|
||||||
|
existing *Project
|
||||||
|
new *Project
|
||||||
|
}
|
||||||
|
type res struct {
|
||||||
|
changesLen int
|
||||||
|
}
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
args args
|
||||||
|
res res
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "project name changes",
|
||||||
|
args: args{
|
||||||
|
existing: &Project{Name: "Name"},
|
||||||
|
new: &Project{Name: "NameChanged"},
|
||||||
|
},
|
||||||
|
res: res{
|
||||||
|
changesLen: 1,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "no changes",
|
||||||
|
args: args{
|
||||||
|
existing: &Project{Name: "Name"},
|
||||||
|
new: &Project{Name: "Name"},
|
||||||
|
},
|
||||||
|
res: res{
|
||||||
|
changesLen: 0,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
changes := tt.args.existing.Changes(tt.args.new)
|
||||||
|
if len(changes) != tt.res.changesLen {
|
||||||
|
t.Errorf("got wrong changes len: expected: %v, actual: %v ", tt.res.changesLen, len(changes))
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
@ -5,6 +5,7 @@ import (
|
|||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
"github.com/caos/zitadel/internal/errors"
|
"github.com/caos/zitadel/internal/errors"
|
||||||
|
"github.com/caos/zitadel/internal/eventstore/models"
|
||||||
es_models "github.com/caos/zitadel/internal/eventstore/models"
|
es_models "github.com/caos/zitadel/internal/eventstore/models"
|
||||||
"github.com/caos/zitadel/internal/project/model"
|
"github.com/caos/zitadel/internal/project/model"
|
||||||
"github.com/sony/sonyflake"
|
"github.com/sony/sonyflake"
|
||||||
@ -12,50 +13,6 @@ import (
|
|||||||
|
|
||||||
var idGenerator = sonyflake.NewSonyflake(sonyflake.Settings{})
|
var idGenerator = sonyflake.NewSonyflake(sonyflake.Settings{})
|
||||||
|
|
||||||
const (
|
|
||||||
projectVersion = "v1"
|
|
||||||
)
|
|
||||||
|
|
||||||
type Project struct {
|
|
||||||
es_models.ObjectRoot
|
|
||||||
Name string `json:"name,omitempty"`
|
|
||||||
State int32 `json:"-"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *Project) Changes(changed *Project) map[string]interface{} {
|
|
||||||
changes := make(map[string]interface{}, 1)
|
|
||||||
if changed.Name != "" && p.Name != changed.Name {
|
|
||||||
changes["name"] = changed.Name
|
|
||||||
}
|
|
||||||
return changes
|
|
||||||
}
|
|
||||||
|
|
||||||
func ProjectFromModel(project *model.Project) *Project {
|
|
||||||
return &Project{
|
|
||||||
ObjectRoot: es_models.ObjectRoot{
|
|
||||||
ID: project.ObjectRoot.ID,
|
|
||||||
Sequence: project.Sequence,
|
|
||||||
ChangeDate: project.ChangeDate,
|
|
||||||
CreationDate: project.CreationDate,
|
|
||||||
},
|
|
||||||
Name: project.Name,
|
|
||||||
State: model.ProjectStateToInt(project.State),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func ProjectToModel(project *Project) *model.Project {
|
|
||||||
return &model.Project{
|
|
||||||
ObjectRoot: es_models.ObjectRoot{
|
|
||||||
ID: project.ID,
|
|
||||||
ChangeDate: project.ChangeDate,
|
|
||||||
CreationDate: project.CreationDate,
|
|
||||||
Sequence: project.Sequence,
|
|
||||||
},
|
|
||||||
Name: project.Name,
|
|
||||||
State: model.ProjectStateFromInt(project.State),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func ProjectByIDQuery(id string, latestSequence uint64) (*es_models.SearchQuery, error) {
|
func ProjectByIDQuery(id string, latestSequence uint64) (*es_models.SearchQuery, error) {
|
||||||
if id == "" {
|
if id == "" {
|
||||||
return nil, errors.ThrowPreconditionFailed(nil, "EVENT-dke74", "id should be filled")
|
return nil, errors.ThrowPreconditionFailed(nil, "EVENT-dke74", "id should be filled")
|
||||||
@ -74,58 +31,61 @@ func ProjectAggregate(ctx context.Context, aggCreator *es_models.AggregateCreato
|
|||||||
return aggCreator.NewAggregate(ctx, id, model.ProjectAggregate, projectVersion, sequence)
|
return aggCreator.NewAggregate(ctx, id, model.ProjectAggregate, projectVersion, sequence)
|
||||||
}
|
}
|
||||||
|
|
||||||
func ProjectCreateAggregate(ctx context.Context, aggCreator *es_models.AggregateCreator, project *Project) (*es_models.Aggregate, error) {
|
func ProjectCreateAggregate(aggCreator *es_models.AggregateCreator, project *Project) func(ctx context.Context) (*es_models.Aggregate, error) {
|
||||||
if project == nil {
|
return func(ctx context.Context) (*es_models.Aggregate, error) {
|
||||||
return nil, errors.ThrowPreconditionFailed(nil, "EVENT-kdie6", "project should not be nil")
|
if project == nil {
|
||||||
}
|
return nil, errors.ThrowPreconditionFailed(nil, "EVENT-kdie6", "project should not be nil")
|
||||||
var err error
|
}
|
||||||
id, err := idGenerator.NextID()
|
var err error
|
||||||
if err != nil {
|
id, err := idGenerator.NextID()
|
||||||
return nil, err
|
if err != nil {
|
||||||
}
|
return nil, err
|
||||||
project.ID = strconv.FormatUint(id, 10)
|
}
|
||||||
|
project.ID = strconv.FormatUint(id, 10)
|
||||||
|
|
||||||
agg, err := ProjectAggregate(ctx, aggCreator, project.ID, project.Sequence)
|
agg, err := ProjectAggregate(ctx, aggCreator, project.ID, project.Sequence)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return agg.AppendEvent(model.ProjectAdded, project)
|
return agg.AppendEvent(model.ProjectAdded, project)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func ProjectUpdateAggregate(ctx context.Context, aggCreator *es_models.AggregateCreator, existing *Project, new *Project) (*es_models.Aggregate, error) {
|
func ProjectUpdateAggregate(aggCreator *es_models.AggregateCreator, existing *Project, new *Project) func(ctx context.Context) (*es_models.Aggregate, error) {
|
||||||
if existing == nil {
|
return func(ctx context.Context) (*es_models.Aggregate, error) {
|
||||||
return nil, errors.ThrowPreconditionFailed(nil, "EVENT-dk93d", "existing project should not be nil")
|
if existing == nil {
|
||||||
|
return nil, errors.ThrowPreconditionFailed(nil, "EVENT-dk93d", "existing project should not be nil")
|
||||||
|
}
|
||||||
|
if new == nil {
|
||||||
|
return nil, errors.ThrowPreconditionFailed(nil, "EVENT-dhr74", "new project should not be nil")
|
||||||
|
}
|
||||||
|
agg, err := ProjectAggregate(ctx, aggCreator, existing.ID, existing.Sequence)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
changes := existing.Changes(new)
|
||||||
|
return agg.AppendEvent(model.ProjectChanged, changes)
|
||||||
}
|
}
|
||||||
if new == nil {
|
|
||||||
return nil, errors.ThrowPreconditionFailed(nil, "EVENT-dhr74", "new project should not be nil")
|
|
||||||
}
|
|
||||||
agg, err := ProjectAggregate(ctx, aggCreator, existing.ID, existing.Sequence)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
changes := existing.Changes(new)
|
|
||||||
return agg.AppendEvent(model.ProjectChanged, changes)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func ProjectDeactivateAggregate(ctx context.Context, aggCreator *es_models.AggregateCreator, existing *Project) (*es_models.Aggregate, error) {
|
func ProjectDeactivateAggregate(aggCreator *es_models.AggregateCreator, project *Project) func(ctx context.Context) (*es_models.Aggregate, error) {
|
||||||
if existing == nil {
|
return projectStateAggregate(aggCreator, project, model.ProjectDeactivated)
|
||||||
return nil, errors.ThrowPreconditionFailed(nil, "EVENT-ueh45", "existing project should not be nil")
|
|
||||||
}
|
|
||||||
agg, err := ProjectAggregate(ctx, aggCreator, existing.ID, existing.Sequence)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return agg.AppendEvent(model.ProjectDeactivated, nil)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func ProjectReactivateAggregate(ctx context.Context, aggCreator *es_models.AggregateCreator, existing *Project) (*es_models.Aggregate, error) {
|
func ProjectReactivateAggregate(aggCreator *es_models.AggregateCreator, project *Project) func(ctx context.Context) (*es_models.Aggregate, error) {
|
||||||
if existing == nil {
|
return projectStateAggregate(aggCreator, project, model.ProjectReactivated)
|
||||||
return nil, errors.ThrowPreconditionFailed(nil, "EVENT-37dur", "existing project should not be nil")
|
}
|
||||||
}
|
|
||||||
agg, err := ProjectAggregate(ctx, aggCreator, existing.ID, existing.Sequence)
|
func projectStateAggregate(aggCreator *es_models.AggregateCreator, project *Project, state models.EventType) func(ctx context.Context) (*es_models.Aggregate, error) {
|
||||||
if err != nil {
|
return func(ctx context.Context) (*es_models.Aggregate, error) {
|
||||||
return nil, err
|
if project == nil {
|
||||||
}
|
return nil, errors.ThrowPreconditionFailed(nil, "EVENT-37dur", "existing project should not be nil")
|
||||||
return agg.AppendEvent(model.ProjectReactivated, nil)
|
}
|
||||||
|
agg, err := ProjectAggregate(ctx, aggCreator, project.ID, project.Sequence)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return agg.AppendEvent(state, nil)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,57 +2,14 @@ package eventsourcing
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"testing"
|
||||||
|
|
||||||
"github.com/caos/zitadel/internal/api/auth"
|
"github.com/caos/zitadel/internal/api/auth"
|
||||||
caos_errs "github.com/caos/zitadel/internal/errors"
|
caos_errs "github.com/caos/zitadel/internal/errors"
|
||||||
"github.com/caos/zitadel/internal/eventstore/models"
|
"github.com/caos/zitadel/internal/eventstore/models"
|
||||||
"github.com/caos/zitadel/internal/project/model"
|
"github.com/caos/zitadel/internal/project/model"
|
||||||
"testing"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestChanges(t *testing.T) {
|
|
||||||
type args struct {
|
|
||||||
existing *Project
|
|
||||||
new *Project
|
|
||||||
}
|
|
||||||
type res struct {
|
|
||||||
changesLen int
|
|
||||||
}
|
|
||||||
tests := []struct {
|
|
||||||
name string
|
|
||||||
args args
|
|
||||||
res res
|
|
||||||
}{
|
|
||||||
{
|
|
||||||
name: "project name changes",
|
|
||||||
args: args{
|
|
||||||
existing: &Project{Name: "Name"},
|
|
||||||
new: &Project{Name: "NameChanged"},
|
|
||||||
},
|
|
||||||
res: res{
|
|
||||||
changesLen: 1,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "no changes",
|
|
||||||
args: args{
|
|
||||||
existing: &Project{Name: "Name"},
|
|
||||||
new: &Project{Name: "Name"},
|
|
||||||
},
|
|
||||||
res: res{
|
|
||||||
changesLen: 0,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
for _, tt := range tests {
|
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
|
||||||
changes := tt.args.existing.Changes(tt.args.new)
|
|
||||||
if len(changes) != tt.res.changesLen {
|
|
||||||
t.Errorf("got wrong changes len: expected: %v, actual: %v ", tt.res.changesLen, len(changes))
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestProjectByIDQuery(t *testing.T) {
|
func TestProjectByIDQuery(t *testing.T) {
|
||||||
type args struct {
|
type args struct {
|
||||||
id string
|
id string
|
||||||
@ -231,7 +188,7 @@ func TestProjectCreateAggregate(t *testing.T) {
|
|||||||
}
|
}
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
agg, err := ProjectCreateAggregate(tt.args.ctx, tt.args.aggCreator, tt.args.new)
|
agg, err := ProjectCreateAggregate(tt.args.aggCreator, tt.args.new)(tt.args.ctx)
|
||||||
|
|
||||||
if !tt.res.wantErr && len(agg.Events) != tt.res.eventLen {
|
if !tt.res.wantErr && len(agg.Events) != tt.res.eventLen {
|
||||||
t.Errorf("got wrong event len: expected: %v, actual: %v ", tt.res.eventLen, len(agg.Events))
|
t.Errorf("got wrong event len: expected: %v, actual: %v ", tt.res.eventLen, len(agg.Events))
|
||||||
@ -312,7 +269,7 @@ func TestProjectUpdateAggregate(t *testing.T) {
|
|||||||
}
|
}
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
agg, err := ProjectUpdateAggregate(tt.args.ctx, tt.args.aggCreator, tt.args.existing, tt.args.new)
|
agg, err := ProjectUpdateAggregate(tt.args.aggCreator, tt.args.existing, tt.args.new)(tt.args.ctx)
|
||||||
|
|
||||||
if !tt.res.wantErr && len(agg.Events) != tt.res.eventLen {
|
if !tt.res.wantErr && len(agg.Events) != tt.res.eventLen {
|
||||||
t.Errorf("got wrong event len: expected: %v, actual: %v ", tt.res.eventLen, len(agg.Events))
|
t.Errorf("got wrong event len: expected: %v, actual: %v ", tt.res.eventLen, len(agg.Events))
|
||||||
@ -376,7 +333,7 @@ func TestProjectDeactivateAggregate(t *testing.T) {
|
|||||||
}
|
}
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
agg, err := ProjectDeactivateAggregate(tt.args.ctx, tt.args.aggCreator, tt.args.existing)
|
agg, err := ProjectDeactivateAggregate(tt.args.aggCreator, tt.args.existing)(tt.args.ctx)
|
||||||
|
|
||||||
if !tt.res.wantErr && len(agg.Events) != tt.res.eventLen {
|
if !tt.res.wantErr && len(agg.Events) != tt.res.eventLen {
|
||||||
t.Errorf("got wrong event len: expected: %v, actual: %v ", tt.res.eventLen, len(agg.Events))
|
t.Errorf("got wrong event len: expected: %v, actual: %v ", tt.res.eventLen, len(agg.Events))
|
||||||
@ -437,7 +394,7 @@ func TestProjectReactivateAggregate(t *testing.T) {
|
|||||||
}
|
}
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
agg, err := ProjectReactivateAggregate(tt.args.ctx, tt.args.aggCreator, tt.args.existing)
|
agg, err := ProjectReactivateAggregate(tt.args.aggCreator, tt.args.existing)(tt.args.ctx)
|
||||||
|
|
||||||
if !tt.res.wantErr && len(agg.Events) != tt.res.eventLen {
|
if !tt.res.wantErr && len(agg.Events) != tt.res.eventLen {
|
||||||
t.Errorf("got wrong event len: expected: %v, actual: %v ", tt.res.eventLen, len(agg.Events))
|
t.Errorf("got wrong event len: expected: %v, actual: %v ", tt.res.eventLen, len(agg.Events))
|
||||||
|
Loading…
Reference in New Issue
Block a user