diff --git a/CHANGELOG.md b/CHANGELOG.md index 640a3357..4ebc7c4e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,6 +16,11 @@ 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]()` +- Add `RichHandlerSet.Range[Aggregates|Processes|Integrations|Projections]()` + ## [0.2.2] - 2020-01-29 ### Added diff --git a/handlerset.go b/handlerset.go index 247ed6cd..daa6b9c6 100644 --- a/handlerset.go +++ b/handlerset.go @@ -147,6 +147,78 @@ func (s HandlerSet) AcceptVisitor(ctx context.Context, v Visitor) error { return nil } +// 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 set. +// +// 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 set. +// +// Iteration stops when fn returns false or once fn has been invoked for all +// 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 { + 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 set. +// +// Iteration stops when fn returns false or once fn has been invoked for all +// 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 { + 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 set. +// +// Iteration stops when fn returns false or once fn has been invoked for all +// 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 { + 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 @@ -313,3 +385,75 @@ func (s RichHandlerSet) AcceptRichVisitor(ctx context.Context, v RichVisitor) er return nil } + +// 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 set. +// +// 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 set. +// +// Iteration stops when fn returns false or once fn has been invoked for all +// 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 { + 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 set. +// +// Iteration stops when fn returns false or once fn has been invoked for all +// 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 { + 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 set. +// +// Iteration stops when fn returns false or once fn has been invoked for all +// 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 { + 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 8fd57aa8..7e368c5c 100644 --- a/handlerset_test.go +++ b/handlerset_test.go @@ -301,6 +301,192 @@ var _ = Describe("type HandlerSet", func() { Expect(err).To(MatchError("")) }) }) + + Context("ranging 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() { @@ -591,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()) + }) + }) + }) })