Files
2026-09-15 21:27:46 +05:00

200 lines
6.2 KiB
Go

package cqrs
import (
stdErrors "errors"
"github.com/ThreeDotsLabs/watermill"
"github.com/ThreeDotsLabs/watermill/message"
"github.com/pkg/errors"
)
// Deprecated: use CommandProcessor and EventProcessor instead.
type FacadeConfig struct {
// GenerateCommandsTopic generates topic name based on the command name.
// Command name is generated by CommandEventMarshaler's Name method.
//
// It allows you to use topic per command or one topic for every command.
GenerateCommandsTopic func(commandName string) string
// CommandHandlers return command handlers which should be executed.
CommandHandlers func(commandBus *CommandBus, eventBus *EventBus) []CommandHandler
// CommandsPublisher is Publisher used to publish commands.
CommandsPublisher message.Publisher
// CommandsSubscriberConstructor is constructor for subscribers which will subscribe for messages.
// It will be called for every command handler.
// It allows you to create separated customized Subscriber for every command handler.
CommandsSubscriberConstructor CommandsSubscriberConstructor
// GenerateEventsTopic generates topic name based on the event name.
// Event name is generated by CommandEventMarshaler's Name method.
//
// It allows you to use topic per command or one topic for every command.
GenerateEventsTopic func(eventName string) string
// EventHandlers return event handlers which should be executed.
EventHandlers func(commandBus *CommandBus, eventBus *EventBus) []EventHandler
// EventsPublisher is Publisher used to publish commands.
EventsPublisher message.Publisher
// EventsSubscriberConstructor is constructor for subscribers which will subscribe for messages.
// It will be called for every event handler.
// It allows you to create separated customized Subscriber for every event handler.
EventsSubscriberConstructor EventsSubscriberConstructor
// Router is a Watermill router, which will be used to handle events and commands.
// Router handlers will be automatically generated by AddHandlersToRouter of Command and Event handlers.
Router *message.Router
CommandEventMarshaler CommandEventMarshaler
Logger watermill.LoggerAdapter
}
func (c FacadeConfig) Validate() error {
var err error
if c.CommandsEnabled() {
if c.GenerateCommandsTopic == nil {
err = stdErrors.Join(err, errors.New("GenerateCommandsTopic is nil"))
}
if c.CommandsSubscriberConstructor == nil {
err = stdErrors.Join(err, errors.New("CommandsSubscriberConstructor is nil"))
}
if c.CommandsPublisher == nil {
err = stdErrors.Join(err, errors.New("CommandsPublisher is nil"))
}
}
if c.EventsEnabled() {
if c.GenerateEventsTopic == nil {
err = stdErrors.Join(err, errors.New("GenerateEventsTopic is nil"))
}
if c.EventsSubscriberConstructor == nil {
err = stdErrors.Join(err, errors.New("EventsSubscriberConstructor is nil"))
}
if c.EventsPublisher == nil {
err = stdErrors.Join(err, errors.New("EventsPublisher is nil"))
}
}
if c.Router == nil {
err = stdErrors.Join(err, errors.New("Router is nil"))
}
if c.Logger == nil {
err = stdErrors.Join(err, errors.New("Logger is nil"))
}
if c.CommandEventMarshaler == nil {
err = stdErrors.Join(err, errors.New("CommandEventMarshaler is nil"))
}
return err
}
func (c FacadeConfig) EventsEnabled() bool {
return c.GenerateEventsTopic != nil || c.EventsPublisher != nil || c.EventsSubscriberConstructor != nil
}
func (c FacadeConfig) CommandsEnabled() bool {
return c.GenerateCommandsTopic != nil || c.CommandsPublisher != nil || c.CommandsSubscriberConstructor != nil
}
// Deprecated: use CommandHandler and EventHandler instead.
//
// Facade is a facade for creating the Command and Event buses and processors.
// It was created to avoid boilerplate, when using CQRS in the standard way.
// You can also create buses and processors manually, drawing inspiration from how it's done in NewFacade.
type Facade struct {
commandsTopic func(commandName string) string
commandBus *CommandBus
eventsTopic func(eventName string) string
eventBus *EventBus
commandEventMarshaler CommandEventMarshaler
}
func (f Facade) CommandBus() *CommandBus {
return f.commandBus
}
func (f Facade) EventBus() *EventBus {
return f.eventBus
}
func (f Facade) CommandEventMarshaler() CommandEventMarshaler {
return f.commandEventMarshaler
}
// Deprecated: use CommandHandler and EventHandler instead.
func NewFacade(config FacadeConfig) (*Facade, error) {
if err := config.Validate(); err != nil {
return nil, errors.Wrap(err, "invalid config")
}
c := &Facade{
commandsTopic: config.GenerateCommandsTopic,
eventsTopic: config.GenerateEventsTopic,
commandEventMarshaler: config.CommandEventMarshaler,
}
if config.CommandsEnabled() {
var err error
c.commandBus, err = NewCommandBus(
config.CommandsPublisher,
config.GenerateCommandsTopic,
config.CommandEventMarshaler,
)
if err != nil {
return nil, errors.Wrap(err, "cannot create command bus")
}
} else {
config.Logger.Info("Empty GenerateCommandsTopic, command bus will be not created", nil)
}
if config.EventsEnabled() {
var err error
c.eventBus, err = NewEventBus(config.EventsPublisher, config.GenerateEventsTopic, config.CommandEventMarshaler)
if err != nil {
return nil, errors.Wrap(err, "cannot create event bus")
}
} else {
config.Logger.Info("Empty GenerateEventsTopic, event bus will be not created", nil)
}
if config.CommandHandlers != nil {
commandProcessor, err := NewCommandProcessor(
config.CommandHandlers(c.commandBus, c.eventBus),
config.GenerateCommandsTopic,
config.CommandsSubscriberConstructor,
config.CommandEventMarshaler,
config.Logger,
)
if err != nil {
return nil, errors.Wrap(err, "cannot create command processor")
}
if err := commandProcessor.AddHandlersToRouter(config.Router); err != nil {
return nil, err
}
}
if config.EventHandlers != nil {
eventProcessor, err := NewEventProcessor(
config.EventHandlers(c.commandBus, c.eventBus),
config.GenerateEventsTopic,
config.EventsSubscriberConstructor,
config.CommandEventMarshaler,
config.Logger,
)
if err != nil {
return nil, errors.Wrap(err, "cannot create event processor")
}
if err := eventProcessor.AddHandlersToRouter(config.Router); err != nil {
return nil, err
}
}
return c, nil
}