Message Composition and Decomposition¶
If there are multiple command handlers (i.e. in different modules) for the same Command, all handlers for that command will be executed (decomposition), and the results of command handlers will be merged into single response (composition).
from lato import Application, ApplicationModule, Command
class GetItemDetails(Command):
item_id: str
pricing_module = ApplicationModule("pricing")
@pricing_module.handler(GetItemDetails)
def get_item_price(command: GetItemDetails):
prices = {"pencil": 1, "pen": 2}
return {"price": prices[command.item_id]}
warehouse_module = ApplicationModule("warehouse")
@warehouse_module.handler(GetItemDetails)
def get_item_stock(command: GetItemDetails):
stocks = {"pencil": 100, "pen": 80}
return {"stock": stocks[command.item_id]}
app = Application()
app.include_submodule(pricing_module)
app.include_submodule(warehouse_module)
assert app.execute(GetItemDetails(item_id="pen")) == {"price": 2, "stock": 80}
By default, handler responses of type dict will be recursively merged into a single dict, and responses of type
list will be merged a into single list.
You can use Application.compose decorator to declare a custom composer. A custom composer will receive kwargs
with names of the modules handling the response.
from lato import Application, ApplicationModule, Command
class GetAllItemDetails(Command):
pass
pricing_module = ApplicationModule("pricing")
@pricing_module.handler(GetAllItemDetails)
def get_item_price(command: GetAllItemDetails):
prices = {"pencil": 1, "pen": 2}
return prices
warehouse_module = ApplicationModule("warehouse")
@warehouse_module.handler(GetAllItemDetails)
def get_item_stock(command: GetAllItemDetails):
stocks = {"pencil": 100, "pen": 80}
return stocks
app = Application()
app.include_submodule(pricing_module)
app.include_submodule(warehouse_module)
@app.compose(GetAllItemDetails)
def compose_item_details(pricing, warehouse):
assert pricing == {"pencil": 1, "pen": 2}
assert warehouse == {"pencil": 100, "pen": 80}
details = [
dict(item_id=x, price=pricing[x], stock=warehouse[x]) for x in pricing.keys()
]
return details
assert app.execute(GetAllItemDetails()) == [
{"item_id": "pencil", "price": 1, "stock": 100},
{"item_id": "pen", "price": 2, "stock": 80},
]