1
+ from seedwork .application .event_dispatcher import EventDispatcher
1
2
from seedwork .infrastructure .logging import logger
2
3
3
4
@@ -26,7 +27,8 @@ def handle(module, query_or_command, *args, **kwargs):
26
27
27
28
from sqlalchemy .orm import Session
28
29
29
- from seedwork .application .decorators import registry
30
+ from seedwork .application .decorators import registry as default_registry
31
+ from seedwork .domain .events import DomainEvent
30
32
from seedwork .domain .repositories import GenericRepository
31
33
from seedwork .infrastructure .request_context import request_context
32
34
@@ -61,11 +63,34 @@ class BusinessModule:
61
63
unit_of_work_class = UnitOfWork
62
64
supported_commands = ()
63
65
supported_queries = ()
64
- supported_events = ()
66
+ event_handlers = ()
67
+ registry = default_registry
65
68
66
- def __init__ (self , ** kwargs ):
69
+ def __init__ (self , domain_event_dispatcher : type [ EventDispatcher ], ** kwargs ):
67
70
self ._uow : ContextVar [UnitOfWork ] = ContextVar ("_uow" , default = None )
68
71
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
69
94
70
95
@contextmanager
71
96
def unit_of_work (self , ** kwargs ):
@@ -84,7 +109,7 @@ def unit_of_work(self, **kwargs):
84
109
request_context .correlation_id .set (None )
85
110
86
111
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 """
88
113
uow = self .unit_of_work_class (
89
114
module = self ,
90
115
correlation_id = correlation_id ,
@@ -94,11 +119,11 @@ def create_unit_of_work(self, correlation_id, db_session):
94
119
return uow
95
120
96
121
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 """
98
123
return dict ()
99
124
100
125
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 """
102
127
103
128
def end_unit_of_work (self , uow ):
104
129
uow .db_session .commit ()
@@ -107,35 +132,54 @@ def configure(self, **kwargs):
107
132
self .init_kwargs = kwargs
108
133
109
134
def execute_command (self , command ):
135
+ """Module entrypoint. Use it to change the state of the module by passing a command object"""
110
136
command_class = type (command )
111
137
assert (
112
138
command_class in self .supported_commands
113
139
), 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 )
116
142
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
118
147
119
148
def execute_query (self , query ):
149
+ """Module entrypoint. Use it to read the state of the module by passing a query object"""
120
150
query_class = type (query )
121
151
assert (
122
152
query_class in self .supported_queries
123
153
), 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 )
126
156
kwargs = self .resolve_handler_kwargs (kwarg_params )
127
157
return handler (query , ** kwargs )
128
158
129
159
@property
130
160
def uow (self ) -> UnitOfWork :
161
+ """Get current unit of work. Use self.unit_of_work() to create a new instance of UoW"""
131
162
uow = self ._uow .get ()
132
163
assert uow , "Unit of work not set, use context manager"
133
164
return uow
134
165
135
166
def resolve_handler_kwargs (self , kwarg_params ) -> dict :
167
+ """Match kwargs required by a function to attributes available in a unit of work"""
136
168
kwargs = {}
137
169
for param_name , param_type in kwarg_params .items ():
138
170
for attr in self .uow .__dict__ .values ():
139
171
if isinstance (attr , param_type ):
140
172
kwargs [param_name ] = attr
141
173
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