1+ from seedwork .application .event_dispatcher import EventDispatcher
12from seedwork .infrastructure .logging import logger
23
34
@@ -26,7 +27,8 @@ def handle(module, query_or_command, *args, **kwargs):
2627
2728from sqlalchemy .orm import Session
2829
29- from seedwork .application .decorators import registry
30+ from seedwork .application .decorators import registry as default_registry
31+ from seedwork .domain .events import DomainEvent
3032from seedwork .domain .repositories import GenericRepository
3133from seedwork .infrastructure .request_context import request_context
3234
@@ -61,11 +63,34 @@ class BusinessModule:
6163 unit_of_work_class = UnitOfWork
6264 supported_commands = ()
6365 supported_queries = ()
64- supported_events = ()
66+ event_handlers = ()
67+ registry = default_registry
6568
66- def __init__ (self , ** kwargs ):
69+ def __init__ (self , domain_event_dispatcher : type [ EventDispatcher ], ** kwargs ):
6770 self ._uow : ContextVar [UnitOfWork ] = ContextVar ("_uow" , default = None )
6871 self .init_kwargs = kwargs
72+ self ._domain_event_dispatcher = domain_event_dispatcher
73+ self .register_event_handlers ()
74+
75+ def register_event_handlers (self ):
76+ """Registers all event handlers declared in this module"""
77+ if self ._domain_event_dispatcher is None :
78+ return
79+
80+ for event_class in self .get_handleable_domain_events ():
81+ self ._domain_event_dispatcher .add_event_handler (
82+ event_class = event_class , event_handler = self .handle_domain_event
83+ )
84+
85+ def get_handleable_domain_events (self ) -> list [type [DomainEvent ]]:
86+ """Returns a list of domain event classes that this module is capable of handling"""
87+ handled_event_types = set ()
88+ for handler in self .event_handlers :
89+ event_class , handler_parameters = self .registry .inspect_handler_parameters (
90+ handler
91+ )
92+ handled_event_types .add (event_class )
93+ return handled_event_types
6994
7095 @contextmanager
7196 def unit_of_work (self , ** kwargs ):
@@ -84,7 +109,7 @@ def unit_of_work(self, **kwargs):
84109 request_context .correlation_id .set (None )
85110
86111 def create_unit_of_work (self , correlation_id , db_session ):
87- """Unit of Work factory"""
112+ """Unit of Work factory, creates new unit of work """
88113 uow = self .unit_of_work_class (
89114 module = self ,
90115 correlation_id = correlation_id ,
@@ -94,11 +119,11 @@ def create_unit_of_work(self, correlation_id, db_session):
94119 return uow
95120
96121 def get_unit_of_work_init_kwargs (self ):
97- """Provide additional kwargs for Unit of Work if you are using a custom one """
122+ """Returns additional kwargs used for initialization of new Unit of Work """
98123 return dict ()
99124
100125 def configure_unit_of_work (self , uow ):
101- """Allows to alter Unit of Work (i.e. add extra attributes)"""
126+ """Allows to alter Unit of Work (i.e. add extra attributes) after it is instantiated """
102127
103128 def end_unit_of_work (self , uow ):
104129 uow .db_session .commit ()
@@ -107,35 +132,54 @@ def configure(self, **kwargs):
107132 self .init_kwargs = kwargs
108133
109134 def execute_command (self , command ):
135+ """Module entrypoint. Use it to change the state of the module by passing a command object"""
110136 command_class = type (command )
111137 assert (
112138 command_class in self .supported_commands
113139 ), f"{ command_class } is not included in { type (self ).__name__ } .supported_commands"
114- handler = registry .get_command_handler_for (command_class )
115- kwarg_params = registry .get_command_handler_parameters_for (command_class )
140+ handler = self . registry .get_command_handler_for (command_class )
141+ kwarg_params = self . registry .get_command_handler_parameters_for (command_class )
116142 kwargs = self .resolve_handler_kwargs (kwarg_params )
117- return handler (command , ** kwargs )
143+ command_result = handler (command , ** kwargs )
144+ if command_result .is_success ():
145+ self .publish_domain_events (command_result .events )
146+ return command_result
118147
119148 def execute_query (self , query ):
149+ """Module entrypoint. Use it to read the state of the module by passing a query object"""
120150 query_class = type (query )
121151 assert (
122152 query_class in self .supported_queries
123153 ), f"{ query_class } is not included in { type (self ).__name__ } .supported_queries"
124- handler = registry .get_query_handler_for (query_class )
125- kwarg_params = registry .get_query_handler_parameters_for (query_class )
154+ handler = self . registry .get_query_handler_for (query_class )
155+ kwarg_params = self . registry .get_query_handler_parameters_for (query_class )
126156 kwargs = self .resolve_handler_kwargs (kwarg_params )
127157 return handler (query , ** kwargs )
128158
129159 @property
130160 def uow (self ) -> UnitOfWork :
161+ """Get current unit of work. Use self.unit_of_work() to create a new instance of UoW"""
131162 uow = self ._uow .get ()
132163 assert uow , "Unit of work not set, use context manager"
133164 return uow
134165
135166 def resolve_handler_kwargs (self , kwarg_params ) -> dict :
167+ """Match kwargs required by a function to attributes available in a unit of work"""
136168 kwargs = {}
137169 for param_name , param_type in kwarg_params .items ():
138170 for attr in self .uow .__dict__ .values ():
139171 if isinstance (attr , param_type ):
140172 kwargs [param_name ] = attr
141173 return kwargs
174+
175+ def publish_domain_events (self , events ):
176+ ...
177+
178+ def handle_domain_event (self , event : type [DomainEvent ]):
179+ """Execute all registered handlers within this module for this event type"""
180+ for handler in self .event_handlers :
181+ event_class , handler_parameters = self .registry .inspect_handler_parameters (
182+ handler
183+ )
184+ if event_class is type (event ):
185+ handler (event , self )
0 commit comments