Пример #1
0
async def test_aggregate_should_decode_to_json_filtering_by_fields(dbsession):
    # arrange
    class BankAccount(aggregates.Aggregate):
        id = aggregates.IntegerField()
        owner = aggregates.CharField()
        balance = aggregates.IntegerField()

        def apply_bank_account_created(self, event):
            self.id = event.id
            self.owner = event.owner
            self.balance = 0

        def apply_deposit_performed(self, event):
            self.balance += event.amount

    events = EventStream(
        [BankAccountCreated(id=123, owner="John Doe", version=0)])
    deposit_performed = DepositPerformed(amount=20)
    # act
    bank_account = BankAccount()
    bank_account.fetch_events(events)
    bank_account.dispatch(deposit_performed)
    result = bank_account.json(only=("id", ))
    # assert
    expected_result = '{"id": 123}'
    assert isinstance(result, str)
    assert result == expected_result
Пример #2
0
async def test_aggregate_should_return_stored_events(dbsession):
    # arrange
    class BankAccount(aggregates.Aggregate):
        id = aggregates.IntegerField()
        owner = aggregates.CharField()
        balance = aggregates.IntegerField()

        def apply_bank_account_created(self, event):
            self.id = event.get("id")
            self.owner = event.get("owner")
            self.balance = 0

        def apply_deposit_performed(self, event):
            self.balance += event.get("amount")

    events = EventStream(
        [BankAccountCreated(id=123, owner="John Doe", version=0)])
    deposit_performed = DepositPerformed(amount=20)
    # act
    bank_account = BankAccount()
    bank_account.fetch_events(events)
    bank_account.dispatch(deposit_performed)
    result = list(bank_account.stored_events())
    # assert
    assert len(result) == 1
    assert result[0].version == 0
    assert result[0].id == 123
    assert result[0].owner == "John Doe"
Пример #3
0
async def test_aggregate_should_be_created_from_events(dbsession):
    # arrange

    class BankAccount(aggregates.Aggregate):
        id = aggregates.IntegerField()
        owner = aggregates.CharField()
        balance = aggregates.IntegerField()

        def apply_bank_account_created(self, event):
            self.id = event.get("id")
            self.owner = event.get("owner")
            self.balance = 0

        def apply_deposit_performed(self, event):
            self.balance += event.get("amount")

    events = EventStream(
        [BankAccountCreated(id=123, owner="John Doe", version=0)])
    deposit_performed = DepositPerformed(amount=20)
    # act
    bank_account = BankAccount.from_stream(events)
    bank_account.dispatch(deposit_performed)
    # assert
    assert bank_account.version == 0
    assert bank_account.current_version == 1
    assert bank_account.id == 123
    assert bank_account.owner == "John Doe"
    assert bank_account.balance == 20
Пример #4
0
async def test_aggregate_should_return_new_events(dbsession):
    # arrange

    class BankAccount(aggregates.Aggregate):
        id = aggregates.IntegerField()
        owner = aggregates.CharField()
        balance = aggregates.IntegerField()

        def apply_bank_account_created(self, event):
            self.id = event.get('id')
            self.owner = event.get('owner')
            self.balance = 0

        def apply_deposit_performed(self, event):
            self.balance += event.get('amount')

    events = EventStream(
        [BankAccountCreated(
            id=123,
            owner='John Doe',
            version=0,
        )])
    deposit_performed = DepositPerformed(amount=20, )

    # act
    bank_account = BankAccount()
    bank_account.fetch_events(events)
    bank_account.dispatch(deposit_performed)
    result = list(bank_account.get_events())
    # assert
    assert len(result) == 1
    assert result[0].version == 1
    assert result[0].amount == 20
Пример #5
0
async def test_aggregate_should_apply_event_after_load_events(dbsession):
    # arrange

    class BankAccount(aggregates.Aggregate):
        id = aggregates.IntegerField()
        owner = aggregates.CharField()
        balance = aggregates.IntegerField()

        def apply_bank_account_created(self, event):
            self.id = event.get('id')
            self.owner = event.get('owner')
            self.balance = 0

        def apply_deposit_performed(self, event):
            self.balance += event.get('amount')

    events = EventStream(
        [BankAccountCreated(
            id=123,
            owner='John Doe',
            version=0,
        )])
    deposit_performed = DepositPerformed(amount=20, )
    # act
    bank_account = BankAccount()
    bank_account.fetch_events(events)
    bank_account.dispatch(deposit_performed)
    # assert
    assert bank_account.version == 0
    assert bank_account.current_version == 1
    assert bank_account.id == 123
    assert bank_account.owner == 'John Doe'
    assert bank_account.balance == 20
Пример #6
0
 def __init__(self):
     super().__init__()
     self._all_events = EventStream()
     self._events = EventStream()
     self._stored_events = EventStream()
Пример #7
0
class Aggregate(FieldMapping, metaclass=AggregateMeta):
    def __init__(self):
        super().__init__()
        self._all_events = EventStream()
        self._events = EventStream()
        self._stored_events = EventStream()

    def all_events(self):
        return self._all_events

    def stored_events(self):
        return self._stored_events

    def get_events(self):
        return self._events

    def notify_save(self, new_version):
        self._events.clear()
        self._events.initial_version = new_version
        self._all_events.initial_version = new_version
        self._stored_events.initial_version = new_version

    def fetch_events(self, events: EventStream):
        self._stored_events = deepcopy(events)
        self._all_events = deepcopy(self._stored_events)
        self._events.initial_version = events.initial_version
        for event in events:
            self.dispatch(event, flush=False)

    def apply(self, event):
        event_name = underscore(event.__class__.__name__)
        method_name = 'apply_{0}'.format(event_name)
        try:
            method = getattr(self, method_name)
            method(event)
        except AggregateError:
            msg = "The command for '{}' is not defined".format(
                event.__class__.__name__)
            raise CommandError(msg)

    def dispatch(self, events, flush=True):
        if isinstance(events, list):
            received_events = list(events)
        else:
            received_events = [events]
        for event in received_events:
            self.apply(event)
            if flush:
                self._events.add(event)
                self._all_events.add(event)

    @property
    def current_version(self):
        return self._all_events.current_version

    @property
    def version(self):
        return self._all_events.initial_version

    @classmethod
    def from_stream(cls, stream):
        self = cls()
        self.fetch_events(stream)
        return self

    async def save(self):
        return await self.objects.save(self.get_pk(), self.get_events(),
                                       self.notify_save)

    async def refresh_from_db(self):
        stream = await self.objects.get_stream(self.get_pk())
        self.fetch_events(stream)
        return self

    def get_pk(self):
        primary_keys = list(self.primary_keys().values())
        if not primary_keys:
            msg = "Nothing primary key defined for '{}'".format(
                self.__class__.__name__)
            raise AggregateError(msg)
        elif len(primary_keys) > 1:
            msg = "Many primary keys defined for '{}'".format(
                self.__class__.__name__)
            raise AggregateError(msg)
        return primary_keys[0]