func init() { eh.RegisterAggregate(func(id eh.UUID) eh.Aggregate { return &TestAggregate{AggregateBase: eh.NewAggregateBase(id)} }) eh.RegisterEvent(func() eh.Event { return &TestEvent{} }) eh.RegisterEvent(func() eh.Event { return &TestEventOther{} }) }
// Run runs the test scenario with the given EventStore and CommandBus. // EventStores and ReadRepositories are created as needed with the given functions. func Run(eventBus eventhorizon.EventBus, commandBus eventhorizon.CommandBus, newEventStore NewEventStoreFunc, newReadRepository NewReadRepositoryFunc) { eventBus.AddGlobalHandler(&loggerSubscriber{}) if remoteEventBus, ok := eventBus.(eventhorizon.RemoteEventBus); ok { fmt.Println("event registered") remoteEventBus.RegisterEventType(&InviteCreated{}, func() eventhorizon.Event { return &InviteCreated{} }) remoteEventBus.RegisterEventType(&InviteAccepted{}, func() eventhorizon.Event { return &InviteAccepted{} }) remoteEventBus.RegisterEventType(&InviteDeclined{}, func() eventhorizon.Event { return &InviteDeclined{} }) defer remoteEventBus.Close() } if remoteCommandBus, ok := commandBus.(eventhorizon.RemoteCommandBus); ok { fmt.Println("command registered") remoteCommandBus.RegisterCommandType(&CreateInvite{}, func() eventhorizon.Command { return &CreateInvite{} }) remoteCommandBus.RegisterCommandType(&AcceptInvite{}, func() eventhorizon.Command { return &AcceptInvite{} }) remoteCommandBus.RegisterCommandType(&DeclineInvite{}, func() eventhorizon.Command { return &DeclineInvite{} }) defer remoteCommandBus.Close() } // Create the event store. eventStore, err := newEventStore() if err != nil { log.Fatalf("could not create event store: %s", err) } if remoteEventStore, ok := eventStore.(eventhorizon.RemoteEventStore); ok { remoteEventStore.RegisterEventType(&InviteCreated{}, func() eventhorizon.Event { return &InviteCreated{} }) remoteEventStore.RegisterEventType(&InviteAccepted{}, func() eventhorizon.Event { return &InviteAccepted{} }) remoteEventStore.RegisterEventType(&InviteDeclined{}, func() eventhorizon.Event { return &InviteDeclined{} }) remoteEventStore.Clear() defer remoteEventStore.Close() } // Create the aggregate repository. repository, err := eventhorizon.NewCallbackRepository(eventStore) if err != nil { log.Fatalf("could not create repository: %s", err) } // Register an aggregate factory. repository.RegisterAggregate(&InvitationAggregate{}, func(id string) eventhorizon.Aggregate { return &InvitationAggregate{ AggregateBase: eventhorizon.NewAggregateBase(id), } }, ) // Create the aggregate command handler. handler, err := eventhorizon.NewAggregateCommandHandler(repository) if err != nil { log.Fatalf("could not create command handler: %s", err) } // Register the domain aggregates with the dispather. Remember to check for // errors here in a real app! handler.SetAggregate(&InvitationAggregate{}, &CreateInvite{}) handler.SetAggregate(&InvitationAggregate{}, &AcceptInvite{}) handler.SetAggregate(&InvitationAggregate{}, &DeclineInvite{}) // Create the command bus and register the handler for the commands. commandBus.SetHandler(handler, &CreateInvite{}) commandBus.SetHandler(handler, &AcceptInvite{}) commandBus.SetHandler(handler, &DeclineInvite{}) // Create and register a read model for individual invitations. invitationRepository, err := newReadRepository("invitations") if err != nil { log.Fatalf("could not create invitation repository: %s", err) } if remoteRepository, ok := invitationRepository.(eventhorizon.RemoteReadRepository); ok { remoteRepository.SetModel(func() interface{} { return &Invitation{} }) remoteRepository.Clear() defer remoteRepository.Close() } invitationProjector := NewInvitationProjector(invitationRepository) eventBus.AddHandler(invitationProjector, &InviteCreated{}) eventBus.AddHandler(invitationProjector, &InviteAccepted{}) eventBus.AddHandler(invitationProjector, &InviteDeclined{}) // Create and register a read model for a guest list. eventID := uuid.New() guestListRepository, err := newReadRepository("guest_lists") if err != nil { log.Fatalf("could not create guest list repository: %s", err) } if remoteRepository, ok := guestListRepository.(eventhorizon.RemoteReadRepository); ok { remoteRepository.SetModel(func() interface{} { return &GuestList{} }) remoteRepository.Clear() defer remoteRepository.Close() } guestListProjector := NewGuestListProjector(guestListRepository, eventID) eventBus.AddHandler(guestListProjector, &InviteCreated{}) eventBus.AddHandler(guestListProjector, &InviteAccepted{}) eventBus.AddHandler(guestListProjector, &InviteDeclined{}) // Issue some invitations and responses. // Note that Athena tries to decline the event, but that is not allowed // by the domain logic in InvitationAggregate. The result is that she is // still accepted. athenaID := uuid.New() commandBus.PublishCommand(&CreateInvite{InvitationID: athenaID, EventID: eventID, Name: "Athena", Age: 42}) commandBus.PublishCommand(&AcceptInvite{InvitationID: athenaID}) err = commandBus.PublishCommand(&DeclineInvite{InvitationID: athenaID}) if err != nil { fmt.Printf("error: %s\n", err) } hadesID := uuid.New() commandBus.PublishCommand(&CreateInvite{InvitationID: hadesID, EventID: eventID, Name: "Hades"}) commandBus.PublishCommand(&AcceptInvite{InvitationID: hadesID}) zeusID := uuid.New() commandBus.PublishCommand(&CreateInvite{InvitationID: zeusID, EventID: eventID, Name: "Zeus"}) commandBus.PublishCommand(&DeclineInvite{InvitationID: zeusID}) // TODO: Find a better way to ensure that all events were processed time.Sleep(1 * time.Second) // Read all invites. invitations, _ := invitationRepository.FindAll() for _, i := range invitations { fmt.Printf("invitation: %#v\n", i) } // Read the guest list. guestList, _ := guestListRepository.Find(eventID) fmt.Printf("guest list: %#v\n", guestList) }
func main() { // Create the event bus that distributes events. eventBus := eventhorizon.NewInternalEventBus() eventBus.AddGlobalHandler(&LoggerSubscriber{}) // Create the event store. eventStore, err := eventhorizon.NewMongoEventStore(eventBus, "localhost", "demo") if err != nil { log.Fatalf("could not create event store: %s", err) } eventStore.RegisterEventType(&InviteCreated{}, func() eventhorizon.Event { return &InviteCreated{} }) eventStore.RegisterEventType(&InviteAccepted{}, func() eventhorizon.Event { return &InviteAccepted{} }) eventStore.RegisterEventType(&InviteDeclined{}, func() eventhorizon.Event { return &InviteDeclined{} }) // Create the aggregate repository. repository, err := eventhorizon.NewCallbackRepository(eventStore) if err != nil { log.Fatalf("could not create repository: %s", err) } // Register an aggregate factory. repository.RegisterAggregate(&InvitationAggregate{}, func(id eventhorizon.UUID) eventhorizon.Aggregate { return &InvitationAggregate{ AggregateBase: eventhorizon.NewAggregateBase(id), } }, ) // Create the aggregate command handler. handler, err := eventhorizon.NewAggregateCommandHandler(repository) if err != nil { log.Fatalf("could not create command handler: %s", err) } // Register the domain aggregates with the dispather. Remember to check for // errors here in a real app! handler.SetAggregate(&InvitationAggregate{}, &CreateInvite{}) handler.SetAggregate(&InvitationAggregate{}, &AcceptInvite{}) handler.SetAggregate(&InvitationAggregate{}, &DeclineInvite{}) // Create the command bus and register the handler for the commands. commandBus := eventhorizon.NewInternalCommandBus() commandBus.SetHandler(handler, &CreateInvite{}) commandBus.SetHandler(handler, &AcceptInvite{}) commandBus.SetHandler(handler, &DeclineInvite{}) // Create and register a read model for individual invitations. invitationRepository, err := eventhorizon.NewMongoReadRepository("localhost", "demo", "invitations") if err != nil { log.Fatalf("could not create invitation repository: %s", err) } invitationRepository.SetModel(func() interface{} { return &Invitation{} }) invitationProjector := NewInvitationProjector(invitationRepository) eventBus.AddHandler(invitationProjector, &InviteCreated{}) eventBus.AddHandler(invitationProjector, &InviteAccepted{}) eventBus.AddHandler(invitationProjector, &InviteDeclined{}) // Create and register a read model for a guest list. eventID := eventhorizon.NewUUID() guestListRepository, err := eventhorizon.NewMongoReadRepository("localhost", "demo", "guest_lists") if err != nil { log.Fatalf("could not create guest list repository: %s", err) } guestListRepository.SetModel(func() interface{} { return &GuestList{} }) guestListProjector := NewGuestListProjector(guestListRepository, eventID) eventBus.AddHandler(guestListProjector, &InviteCreated{}) eventBus.AddHandler(guestListProjector, &InviteAccepted{}) eventBus.AddHandler(guestListProjector, &InviteDeclined{}) // Clear DB collections. eventStore.Clear() invitationRepository.Clear() guestListRepository.Clear() // Issue some invitations and responses. // Note that Athena tries to decline the event, but that is not allowed // by the domain logic in InvitationAggregate. The result is that she is // still accepted. athenaID := eventhorizon.NewUUID() commandBus.HandleCommand(&CreateInvite{InvitationID: athenaID, Name: "Athena", Age: 42}) commandBus.HandleCommand(&AcceptInvite{InvitationID: athenaID}) err = commandBus.HandleCommand(&DeclineInvite{InvitationID: athenaID}) if err != nil { fmt.Printf("error: %s\n", err) } hadesID := eventhorizon.NewUUID() commandBus.HandleCommand(&CreateInvite{InvitationID: hadesID, Name: "Hades"}) commandBus.HandleCommand(&AcceptInvite{InvitationID: hadesID}) zeusID := eventhorizon.NewUUID() commandBus.HandleCommand(&CreateInvite{InvitationID: zeusID, Name: "Zeus"}) commandBus.HandleCommand(&DeclineInvite{InvitationID: zeusID}) // Read all invites. invitations, _ := invitationRepository.FindAll() for _, i := range invitations { fmt.Printf("invitation: %#v\n", i) } // Read the guest list. guestList, _ := guestListRepository.Find(eventID) fmt.Printf("guest list: %#v\n", guestList) // records := eventStore.FindAllEventRecords() // fmt.Printf("event records:\n") // for _, r := range records { // fmt.Printf("%#v\n", r) // } }
// NewInvitationAggregate creates a new InvitationAggregate with an ID. func NewInvitationAggregate(id eh.UUID) *InvitationAggregate { return &InvitationAggregate{ AggregateBase: eh.NewAggregateBase(id), } }