Skip to content

Commit

Permalink
Add Ch/Qh multi-middleware
Browse files Browse the repository at this point in the history
  • Loading branch information
theskyinflames-macos authored and theskyinflames-macos committed Dec 20, 2022
1 parent 95e1903 commit 4c34cdd
Show file tree
Hide file tree
Showing 3 changed files with 220 additions and 0 deletions.
28 changes: 28 additions & 0 deletions pkg/cqrs/cqrs.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ import (
"github.com/google/uuid"
)

//go:generate moq -stub -out zmock_cqrs_event_test.go -pkg cqrs_test . Event

// Logger is an interface
type Logger interface {
Printf(format string, v ...interface{})
Expand Down Expand Up @@ -42,6 +44,19 @@ func (chf CommandHandlerFunc) Handle(ctx context.Context, cmd Command) ([]Event,
// CommandHandlerMiddleware is self-described
type CommandHandlerMiddleware func(CommandHandler) CommandHandler

// CommandHandlerMultiMiddleware is self-described
func CommandHandlerMultiMiddleware(mws ...CommandHandlerMiddleware) CommandHandlerMiddleware {
return func(ch CommandHandler) CommandHandler {
return CommandHandlerFunc(func(ctx context.Context, cmd Command) ([]Event, error) {
mw := mws[0](ch)
for _, outerMw := range mws[1:] {
mw = outerMw(mw)
}
return mw.Handle(ctx, cmd)
})
}
}

// ChErrMw is a command handler middleware
func ChErrMw(l Logger) CommandHandlerMiddleware {
return func(ch CommandHandler) CommandHandler {
Expand Down Expand Up @@ -80,6 +95,19 @@ func (chf QueryHandlerFunc) Handle(ctx context.Context, q Query) (QueryResult, e
// QueryHandlerMiddleware is self-described
type QueryHandlerMiddleware func(QueryHandler) QueryHandler

// QueryHandlerMultiMiddleware is self-described
func QueryHandlerMultiMiddleware(mws ...QueryHandlerMiddleware) QueryHandlerMiddleware {
return func(ch QueryHandler) QueryHandler {
return QueryHandlerFunc(func(ctx context.Context, cmd Query) (QueryResult, error) {
mw := mws[0](ch)
for _, outerMw := range mws[1:] {
mw = outerMw(mw)
}
return mw.Handle(ctx, cmd)
})
}
}

// QhErrMw is a query handler middleware
func QhErrMw(l Logger) QueryHandlerMiddleware {
return func(ch QueryHandler) QueryHandler {
Expand Down
80 changes: 80 additions & 0 deletions pkg/cqrs/cqrs_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,3 +45,83 @@ func TestQhErrMw(t *testing.T) {
require.Len(t, logger.PrintfCalls(), 1)
})
}

func TestCommandHandlerMultiMiddleware(t *testing.T) {
t.Run(`Given a sequence of ch middlewares,
when it's called,
then the ch is executed wrapped by all middlewares in the right order`, func(t *testing.T) {
var (
calls []string
chMw1 = chTestMw("mw1", &calls)
chMw2 = chTestMw("mw2", &calls)
chMw3 = chTestMw("mw3", &calls)
chMw4 = chTestMw("mw4", &calls)

ev = &EventMock{}

ch = &CommandHandlerMock{
HandleFunc: func(_ context.Context, _ cqrs.Command) ([]cqrs.Event, error) {
return []cqrs.Event{ev}, nil
},
}
)

multiChMw := cqrs.CommandHandlerMultiMiddleware(chMw1, chMw2, chMw3, chMw4)

evs, err := multiChMw(ch).Handle(context.Background(), &CommandMock{})

require.Len(t, ch.HandleCalls(), 1)
require.NoError(t, err)
require.Len(t, evs, 1)
require.Equal(t, ev, evs[0])
require.Equal(t, []string{"mw4", "mw3", "mw2", "mw1"}, calls)
})
}

func chTestMw(name string, calls *[]string) cqrs.CommandHandlerMiddleware {
return func(ch cqrs.CommandHandler) cqrs.CommandHandler {
return cqrs.CommandHandlerFunc(func(ctx context.Context, cmd cqrs.Command) ([]cqrs.Event, error) {
*calls = append(*calls, name)
return ch.Handle(ctx, cmd)
})
}
}

func TestQueryHandlerMultiMiddleware(t *testing.T) {
t.Run(`Given a sequence of ch middlewares,
when it's called,
then the ch is executed wrapped by all middlewares in the right order`, func(t *testing.T) {
var (
calls []string
qhMw1 = qhTestMw("mw1", &calls)
qhMw2 = qhTestMw("mw2", &calls)
qhMw3 = qhTestMw("mw3", &calls)
qhMw4 = qhTestMw("mw4", &calls)

queryResult = "result"

qh = &QueryHandlerMock{
HandleFunc: func(_ context.Context, _ cqrs.Query) (cqrs.QueryResult, error) {
return queryResult, nil
},
}
)

multiQhMw := cqrs.QueryHandlerMultiMiddleware(qhMw1, qhMw2, qhMw3, qhMw4)

qrs, err := multiQhMw(qh).Handle(context.Background(), &QueryMock{})

require.Len(t, qh.HandleCalls(), 1)
require.NoError(t, err)
require.Equal(t, queryResult, qrs)
})
}

func qhTestMw(name string, calls *[]string) cqrs.QueryHandlerMiddleware {
return func(ch cqrs.QueryHandler) cqrs.QueryHandler {
return cqrs.QueryHandlerFunc(func(ctx context.Context, cmd cqrs.Query) (cqrs.QueryResult, error) {
*calls = append(*calls, name)
return ch.Handle(ctx, cmd)
})
}
}
112 changes: 112 additions & 0 deletions pkg/cqrs/zmock_cqrs_event_test.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit 4c34cdd

Please sign in to comment.