From cf05c849ec1ddbc29c2d03906cfbce10b31f98f9 Mon Sep 17 00:00:00 2001 From: James Harris Date: Wed, 29 Jan 2020 10:31:54 +1000 Subject: [PATCH 1/3] Add ranging methods to `HandlerSet`. --- CHANGELOG.md | 4 + handlerset.go | 74 ++++++++++++++++++ handlerset_test.go | 186 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 264 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 640a3357..2cbc8d48 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,6 +16,10 @@ The format is based on [Keep a Changelog], and this project adheres to - **[BC]** Rename `message.NameCollection.Each()` to `Range()` for consistency with the Go standard library - **[BC]** Rename `message.TypeCollection.Each()` to `Range()` for consistency with the Go standard library +### Added + +- Add `HandlerSet.Range[Aggregates|Processes|Integrations|Projections]()` + ## [0.2.2] - 2020-01-29 ### Added diff --git a/handlerset.go b/handlerset.go index 247ed6cd..e419faad 100644 --- a/handlerset.go +++ b/handlerset.go @@ -147,6 +147,80 @@ func (s HandlerSet) AcceptVisitor(ctx context.Context, v Visitor) error { return nil } +// RangeAggregates invokes fn once for each aggregate handler in the container. +// +// Iteration stops when fn returns false or once fn has been invoked for all +// aggregate handlers in the container. +// +// It returns true if fn returned true for all aggregate handlers. +func (s HandlerSet) RangeAggregates(fn func(Aggregate) bool) bool { + for _, h := range s { + if h.HandlerType() == AggregateHandlerType { + if !fn(h) { + return false + } + } + } + + return true +} + +// RangeProcesses invokes fn once for each process handler in the container. +// +// Iteration stops when fn returns false or once fn has been invoked for all +// process handlers in the container. +// +// It returns true if fn returned true for all process handlers. +func (s HandlerSet) RangeProcesses(fn func(Process) bool) bool { + for _, h := range s { + if h.HandlerType() == ProcessHandlerType { + if !fn(h) { + return false + } + } + } + + return true +} + +// RangeIntegrations invokes fn once for each integration handler in the +// container. +// +// Iteration stops when fn returns false or once fn has been invoked for all +// integration handlers in the container. +// +// It returns true if fn returned true for all integration handlers. +func (s HandlerSet) RangeIntegrations(fn func(Integration) bool) bool { + for _, h := range s { + if h.HandlerType() == IntegrationHandlerType { + if !fn(h) { + return false + } + } + } + + return true +} + +// RangeProjections invokes fn once for each projection handler in the +// container. +// +// Iteration stops when fn returns false or once fn has been invoked for all +// projection handlers in the container. +// +// It returns true if fn returned true for all projection handlers. +func (s HandlerSet) RangeProjections(fn func(Projection) bool) bool { + for _, h := range s { + if h.HandlerType() == ProjectionHandlerType { + if !fn(h) { + return false + } + } + } + + return true +} + // RichHandlerSet is a collection of rich handlers. type RichHandlerSet map[Identity]RichHandler diff --git a/handlerset_test.go b/handlerset_test.go index 8fd57aa8..668c9b64 100644 --- a/handlerset_test.go +++ b/handlerset_test.go @@ -301,6 +301,192 @@ var _ = Describe("type HandlerSet", func() { Expect(err).To(MatchError("")) }) }) + + Context("each functions", func() { + var ( + aggregate1, aggregate2 Aggregate + process1, process2 Process + integration1, integration2 Integration + projection1, projection2 Projection + ) + + BeforeEach(func() { + aggregate1 = FromAggregate(&fixtures.AggregateMessageHandler{ + ConfigureFunc: func(c dogma.AggregateConfigurer) { + c.Identity("", "") + c.ConsumesCommandType(fixtures.MessageC{}) + c.ProducesEventType(fixtures.MessageD{}) + }, + }) + + aggregate2 = FromAggregate(&fixtures.AggregateMessageHandler{ + ConfigureFunc: func(c dogma.AggregateConfigurer) { + c.Identity("", "") + c.ConsumesCommandType(fixtures.MessageC{}) + c.ProducesEventType(fixtures.MessageD{}) + }, + }) + + process1 = FromProcess(&fixtures.ProcessMessageHandler{ + ConfigureFunc: func(c dogma.ProcessConfigurer) { + c.Identity("", "") + c.ConsumesEventType(fixtures.MessageE{}) + c.ProducesCommandType(fixtures.MessageC{}) + }, + }) + + process2 = FromProcess(&fixtures.ProcessMessageHandler{ + ConfigureFunc: func(c dogma.ProcessConfigurer) { + c.Identity("", "") + c.ConsumesEventType(fixtures.MessageE{}) + c.ProducesCommandType(fixtures.MessageC{}) + }, + }) + + integration1 = FromIntegration(&fixtures.IntegrationMessageHandler{ + ConfigureFunc: func(c dogma.IntegrationConfigurer) { + c.Identity("", "") + c.ConsumesCommandType(fixtures.MessageC{}) + c.ProducesEventType(fixtures.MessageD{}) + }, + }) + + integration2 = FromIntegration(&fixtures.IntegrationMessageHandler{ + ConfigureFunc: func(c dogma.IntegrationConfigurer) { + c.Identity("", "") + c.ConsumesCommandType(fixtures.MessageC{}) + c.ProducesEventType(fixtures.MessageD{}) + }, + }) + + projection1 = FromProjection(&fixtures.ProjectionMessageHandler{ + ConfigureFunc: func(c dogma.ProjectionConfigurer) { + c.Identity("", "") + c.ConsumesEventType(fixtures.MessageE{}) + }, + }) + + projection2 = FromProjection(&fixtures.ProjectionMessageHandler{ + ConfigureFunc: func(c dogma.ProjectionConfigurer) { + c.Identity("", "") + c.ConsumesEventType(fixtures.MessageE{}) + }, + }) + + set.Add(aggregate1) + set.Add(aggregate2) + set.Add(process1) + set.Add(process2) + set.Add(integration1) + set.Add(integration2) + set.Add(projection1) + set.Add(projection2) + }) + + Describe("func RangeAggregates()", func() { + It("calls fn for each aggregate in the set", func() { + var names []string + + all := set.RangeAggregates(func(h Aggregate) bool { + names = append(names, h.Identity().Name) + return true + }) + + Expect(names).To(ConsistOf("", "")) + Expect(all).To(BeTrue()) + }) + + It("stops iterating if fn returns false", func() { + count := 0 + + all := set.RangeAggregates(func(h Aggregate) bool { + count++ + return false + }) + + Expect(count).To(BeNumerically("==", 1)) + Expect(all).To(BeFalse()) + }) + }) + + Describe("func RangeProcesses()", func() { + It("calls fn for each process in the set", func() { + var names []string + + all := set.RangeProcesses(func(h Process) bool { + names = append(names, h.Identity().Name) + return true + }) + + Expect(names).To(ConsistOf("", "")) + Expect(all).To(BeTrue()) + }) + + It("stops iterating if fn returns false", func() { + count := 0 + + all := set.RangeProcesses(func(h Process) bool { + count++ + return false + }) + + Expect(count).To(BeNumerically("==", 1)) + Expect(all).To(BeFalse()) + }) + }) + + Describe("func RangeIntegrations()", func() { + It("calls fn for each integration in the set", func() { + var names []string + + all := set.RangeIntegrations(func(h Integration) bool { + names = append(names, h.Identity().Name) + return true + }) + + Expect(names).To(ConsistOf("", "")) + Expect(all).To(BeTrue()) + }) + + It("stops iterating if fn returns false", func() { + count := 0 + + all := set.RangeIntegrations(func(h Integration) bool { + count++ + return false + }) + + Expect(count).To(BeNumerically("==", 1)) + Expect(all).To(BeFalse()) + }) + }) + + Describe("func RangeProjections()", func() { + It("calls fn for each projection in the set", func() { + var names []string + + all := set.RangeProjections(func(h Projection) bool { + names = append(names, h.Identity().Name) + return true + }) + + Expect(names).To(ConsistOf("", "")) + Expect(all).To(BeTrue()) + }) + + It("stops iterating if fn returns false", func() { + count := 0 + + all := set.RangeProjections(func(h Projection) bool { + count++ + return false + }) + + Expect(count).To(BeNumerically("==", 1)) + Expect(all).To(BeFalse()) + }) + }) + }) }) var _ = Describe("type RichHandlerSet", func() { From f05d88b6cf8b3ea9da247463978f17b431bc5ae6 Mon Sep 17 00:00:00 2001 From: James Harris Date: Wed, 29 Jan 2020 10:34:23 +1000 Subject: [PATCH 2/3] Add ranging methods to `RichHandlerSet`. --- CHANGELOG.md | 1 + handlerset.go | 74 ++++++++++++++++++ handlerset_test.go | 188 ++++++++++++++++++++++++++++++++++++++++++++- 3 files changed, 262 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2cbc8d48..4ebc7c4e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -19,6 +19,7 @@ The format is based on [Keep a Changelog], and this project adheres to ### Added - Add `HandlerSet.Range[Aggregates|Processes|Integrations|Projections]()` +- Add `RichHandlerSet.Range[Aggregates|Processes|Integrations|Projections]()` ## [0.2.2] - 2020-01-29 diff --git a/handlerset.go b/handlerset.go index e419faad..6e35e753 100644 --- a/handlerset.go +++ b/handlerset.go @@ -387,3 +387,77 @@ func (s RichHandlerSet) AcceptRichVisitor(ctx context.Context, v RichVisitor) er return nil } + +// RangeAggregates invokes fn once for each aggregate handler in the container. +// +// Iteration stops when fn returns false or once fn has been invoked for all +// aggregate handlers in the container. +// +// It returns true if fn returned true for all aggregate handlers. +func (s RichHandlerSet) RangeAggregates(fn func(RichAggregate) bool) bool { + for _, h := range s { + if x, ok := h.(RichAggregate); ok { + if !fn(x) { + return false + } + } + } + + return true +} + +// RangeProcesses invokes fn once for each process handler in the container. +// +// Iteration stops when fn returns false or once fn has been invoked for all +// process handlers in the container. +// +// It returns true if fn returned true for all process handlers. +func (s RichHandlerSet) RangeProcesses(fn func(RichProcess) bool) bool { + for _, h := range s { + if x, ok := h.(RichProcess); ok { + if !fn(x) { + return false + } + } + } + + return true +} + +// RangeIntegrations invokes fn once for each integration handler in the +// container. +// +// Iteration stops when fn returns false or once fn has been invoked for all +// integration handlers in the container. +// +// It returns true if fn returned true for all integration handlers. +func (s RichHandlerSet) RangeIntegrations(fn func(RichIntegration) bool) bool { + for _, h := range s { + if x, ok := h.(RichIntegration); ok { + if !fn(x) { + return false + } + } + } + + return true +} + +// RangeProjections invokes fn once for each projection handler in the +// container. +// +// Iteration stops when fn returns false or once fn has been invoked for all +// projection handlers in the container. +// +// It returns true if fn returned true for all projection handlers. +func (s RichHandlerSet) RangeProjections(fn func(RichProjection) bool) bool { + for _, h := range s { + if x, ok := h.(RichProjection); ok { + if !fn(x) { + return false + } + } + } + + return true +} diff --git a/handlerset_test.go b/handlerset_test.go index 668c9b64..7e368c5c 100644 --- a/handlerset_test.go +++ b/handlerset_test.go @@ -302,7 +302,7 @@ var _ = Describe("type HandlerSet", func() { }) }) - Context("each functions", func() { + Context("ranging functions", func() { var ( aggregate1, aggregate2 Aggregate process1, process2 Process @@ -777,4 +777,190 @@ var _ = Describe("type RichHandlerSet", func() { Expect(err).To(MatchError("")) }) }) + + Context("ranging functions", func() { + var ( + aggregate1, aggregate2 RichAggregate + process1, process2 RichProcess + integration1, integration2 RichIntegration + projection1, projection2 RichProjection + ) + + BeforeEach(func() { + aggregate1 = FromAggregate(&fixtures.AggregateMessageHandler{ + ConfigureFunc: func(c dogma.AggregateConfigurer) { + c.Identity("", "") + c.ConsumesCommandType(fixtures.MessageC{}) + c.ProducesEventType(fixtures.MessageD{}) + }, + }) + + aggregate2 = FromAggregate(&fixtures.AggregateMessageHandler{ + ConfigureFunc: func(c dogma.AggregateConfigurer) { + c.Identity("", "") + c.ConsumesCommandType(fixtures.MessageC{}) + c.ProducesEventType(fixtures.MessageD{}) + }, + }) + + process1 = FromProcess(&fixtures.ProcessMessageHandler{ + ConfigureFunc: func(c dogma.ProcessConfigurer) { + c.Identity("", "") + c.ConsumesEventType(fixtures.MessageE{}) + c.ProducesCommandType(fixtures.MessageC{}) + }, + }) + + process2 = FromProcess(&fixtures.ProcessMessageHandler{ + ConfigureFunc: func(c dogma.ProcessConfigurer) { + c.Identity("", "") + c.ConsumesEventType(fixtures.MessageE{}) + c.ProducesCommandType(fixtures.MessageC{}) + }, + }) + + integration1 = FromIntegration(&fixtures.IntegrationMessageHandler{ + ConfigureFunc: func(c dogma.IntegrationConfigurer) { + c.Identity("", "") + c.ConsumesCommandType(fixtures.MessageC{}) + c.ProducesEventType(fixtures.MessageD{}) + }, + }) + + integration2 = FromIntegration(&fixtures.IntegrationMessageHandler{ + ConfigureFunc: func(c dogma.IntegrationConfigurer) { + c.Identity("", "") + c.ConsumesCommandType(fixtures.MessageC{}) + c.ProducesEventType(fixtures.MessageD{}) + }, + }) + + projection1 = FromProjection(&fixtures.ProjectionMessageHandler{ + ConfigureFunc: func(c dogma.ProjectionConfigurer) { + c.Identity("", "") + c.ConsumesEventType(fixtures.MessageE{}) + }, + }) + + projection2 = FromProjection(&fixtures.ProjectionMessageHandler{ + ConfigureFunc: func(c dogma.ProjectionConfigurer) { + c.Identity("", "") + c.ConsumesEventType(fixtures.MessageE{}) + }, + }) + + set.Add(aggregate1) + set.Add(aggregate2) + set.Add(process1) + set.Add(process2) + set.Add(integration1) + set.Add(integration2) + set.Add(projection1) + set.Add(projection2) + }) + + Describe("func RangeAggregates()", func() { + It("calls fn for each aggregate in the set", func() { + var names []string + + all := set.RangeAggregates(func(h RichAggregate) bool { + names = append(names, h.Identity().Name) + return true + }) + + Expect(names).To(ConsistOf("", "")) + Expect(all).To(BeTrue()) + }) + + It("stops iterating if fn returns false", func() { + count := 0 + + all := set.RangeAggregates(func(h RichAggregate) bool { + count++ + return false + }) + + Expect(count).To(BeNumerically("==", 1)) + Expect(all).To(BeFalse()) + }) + }) + + Describe("func RangeProcesses()", func() { + It("calls fn for each process in the set", func() { + var names []string + + all := set.RangeProcesses(func(h RichProcess) bool { + names = append(names, h.Identity().Name) + return true + }) + + Expect(names).To(ConsistOf("", "")) + Expect(all).To(BeTrue()) + }) + + It("stops iterating if fn returns false", func() { + count := 0 + + all := set.RangeProcesses(func(h RichProcess) bool { + count++ + return false + }) + + Expect(count).To(BeNumerically("==", 1)) + Expect(all).To(BeFalse()) + }) + }) + + Describe("func RangeIntegrations()", func() { + It("calls fn for each integration in the set", func() { + var names []string + + all := set.RangeIntegrations(func(h RichIntegration) bool { + names = append(names, h.Identity().Name) + return true + }) + + Expect(names).To(ConsistOf("", "")) + Expect(all).To(BeTrue()) + }) + + It("stops iterating if fn returns false", func() { + count := 0 + + all := set.RangeIntegrations(func(h RichIntegration) bool { + count++ + return false + }) + + Expect(count).To(BeNumerically("==", 1)) + Expect(all).To(BeFalse()) + }) + }) + + Describe("func RangeProjections()", func() { + It("calls fn for each projection in the set", func() { + var names []string + + all := set.RangeProjections(func(h RichProjection) bool { + names = append(names, h.Identity().Name) + return true + }) + + Expect(names).To(ConsistOf("", "")) + Expect(all).To(BeTrue()) + }) + + It("stops iterating if fn returns false", func() { + count := 0 + + all := set.RangeProjections(func(h RichProjection) bool { + count++ + return false + }) + + Expect(count).To(BeNumerically("==", 1)) + Expect(all).To(BeFalse()) + }) + }) + }) }) From d9f670156e2223fe8cd18f153217f9cfc65d3e66 Mon Sep 17 00:00:00 2001 From: James Harris Date: Wed, 29 Jan 2020 10:42:38 +1000 Subject: [PATCH 3/3] Use consistent wording in handler set documentation. --- handlerset.go | 36 ++++++++++++++++-------------------- 1 file changed, 16 insertions(+), 20 deletions(-) diff --git a/handlerset.go b/handlerset.go index 6e35e753..daa6b9c6 100644 --- a/handlerset.go +++ b/handlerset.go @@ -147,10 +147,10 @@ func (s HandlerSet) AcceptVisitor(ctx context.Context, v Visitor) error { return nil } -// RangeAggregates invokes fn once for each aggregate handler in the container. +// RangeAggregates invokes fn once for each aggregate handler in the set. // // Iteration stops when fn returns false or once fn has been invoked for all -// aggregate handlers in the container. +// aggregate handlers in the set. // // It returns true if fn returned true for all aggregate handlers. func (s HandlerSet) RangeAggregates(fn func(Aggregate) bool) bool { @@ -165,10 +165,10 @@ func (s HandlerSet) RangeAggregates(fn func(Aggregate) bool) bool { return true } -// RangeProcesses invokes fn once for each process handler in the container. +// RangeProcesses invokes fn once for each process handler in the set. // // Iteration stops when fn returns false or once fn has been invoked for all -// process handlers in the container. +// process handlers in the set. // // It returns true if fn returned true for all process handlers. func (s HandlerSet) RangeProcesses(fn func(Process) bool) bool { @@ -183,11 +183,10 @@ func (s HandlerSet) RangeProcesses(fn func(Process) bool) bool { return true } -// RangeIntegrations invokes fn once for each integration handler in the -// container. +// RangeIntegrations invokes fn once for each integration handler in the set. // // Iteration stops when fn returns false or once fn has been invoked for all -// integration handlers in the container. +// integration handlers in the set. // // It returns true if fn returned true for all integration handlers. func (s HandlerSet) RangeIntegrations(fn func(Integration) bool) bool { @@ -202,11 +201,10 @@ func (s HandlerSet) RangeIntegrations(fn func(Integration) bool) bool { return true } -// RangeProjections invokes fn once for each projection handler in the -// container. +// RangeProjections invokes fn once for each projection handler in the set. // // Iteration stops when fn returns false or once fn has been invoked for all -// projection handlers in the container. +// projection handlers in the set. // // It returns true if fn returned true for all projection handlers. func (s HandlerSet) RangeProjections(fn func(Projection) bool) bool { @@ -388,10 +386,10 @@ func (s RichHandlerSet) AcceptRichVisitor(ctx context.Context, v RichVisitor) er return nil } -// RangeAggregates invokes fn once for each aggregate handler in the container. +// RangeAggregates invokes fn once for each aggregate handler in the set. // // Iteration stops when fn returns false or once fn has been invoked for all -// aggregate handlers in the container. +// aggregate handlers in the set. // // It returns true if fn returned true for all aggregate handlers. func (s RichHandlerSet) RangeAggregates(fn func(RichAggregate) bool) bool { @@ -406,10 +404,10 @@ func (s RichHandlerSet) RangeAggregates(fn func(RichAggregate) bool) bool { return true } -// RangeProcesses invokes fn once for each process handler in the container. +// RangeProcesses invokes fn once for each process handler in the set. // // Iteration stops when fn returns false or once fn has been invoked for all -// process handlers in the container. +// process handlers in the set. // // It returns true if fn returned true for all process handlers. func (s RichHandlerSet) RangeProcesses(fn func(RichProcess) bool) bool { @@ -424,11 +422,10 @@ func (s RichHandlerSet) RangeProcesses(fn func(RichProcess) bool) bool { return true } -// RangeIntegrations invokes fn once for each integration handler in the -// container. +// RangeIntegrations invokes fn once for each integration handler in the set. // // Iteration stops when fn returns false or once fn has been invoked for all -// integration handlers in the container. +// integration handlers in the set. // // It returns true if fn returned true for all integration handlers. func (s RichHandlerSet) RangeIntegrations(fn func(RichIntegration) bool) bool { @@ -443,11 +440,10 @@ func (s RichHandlerSet) RangeIntegrations(fn func(RichIntegration) bool) bool { return true } -// RangeProjections invokes fn once for each projection handler in the -// container. +// RangeProjections invokes fn once for each projection handler in the set. // // Iteration stops when fn returns false or once fn has been invoked for all -// projection handlers in the container. +// projection handlers in the set. // // It returns true if fn returned true for all projection handlers. func (s RichHandlerSet) RangeProjections(fn func(RichProjection) bool) bool {