コード例 #1
0
    def __init__(self,
                 event_store,
                 mutator=None,
                 snapshot_strategy=None,
                 use_cache=False,
                 *args,
                 **kwargs):
        super(EventSourcedRepository, self).__init__(*args, **kwargs)
        self._cache = {}
        self._snapshot_strategy = snapshot_strategy
        # self._use_cache = use_cache

        # Check we got an event store.
        assert isinstance(event_store, AbstractEventStore), type(event_store)
        self._event_store = event_store

        # Instantiate an event player for this repo.
        mutator = mutator or type(self).mutator
        self.event_player = EventPlayer(
            event_store=self.event_store,
            mutator=mutator,
            page_size=self.__page_size__,
            is_short=self.__is_short__,
            snapshot_strategy=self._snapshot_strategy,
        )
コード例 #2
0
    def __init__(self,
                 event_store,
                 mutator=None,
                 snapshot_strategy=None,
                 use_cache=False):
        self._cache = {}
        self._snapshot_strategy = snapshot_strategy
        # self._use_cache = use_cache

        # Check we got an event store.
        assert isinstance(event_store, AbstractEventStore)
        self.event_store = event_store

        # Instantiate an event player for this repo.
        mutator = mutator or type(self).mutator
        if mutator is None:
            raise ValueError(
                "Repository needs a mutator function (set class attribute or pass constructor arg)"
            )
        self.event_player = EventPlayer(
            event_store=self.event_store,
            mutator=mutator,
            page_size=self.__page_size__,
            is_short=self.__is_short__,
            snapshot_strategy=self._snapshot_strategy,
        )
コード例 #3
0
    def test_replay_entity(self):
        # Store example events.

        # Create entity1.
        entity_id1 = uuid4()
        event1 = Example.Created(originator_id=entity_id1, a=1, b=2)
        self.entity_event_store.append(event1)

        # Create entity2.
        entity_id2 = uuid4()
        event2 = Example.Created(originator_id=entity_id2, a=2, b=4)
        self.entity_event_store.append(event2)

        # Create entity3.
        entity_id3 = uuid4()
        event3 = Example.Created(originator_id=entity_id3, a=3, b=6)
        self.entity_event_store.append(event3)

        # Discard entity3.
        event4 = Example.Discarded(originator_id=entity_id3,
                                   originator_version=1)
        self.entity_event_store.append(event4)

        # Check the entities can be replayed.
        event_player = EventPlayer(event_store=self.entity_event_store,
                                   mutator=Example._mutate)

        # Check recovered entities have correct attribute values.
        recovered1 = event_player.replay_entity(entity_id1)
        self.assertEqual(entity_id1, recovered1.id)
        self.assertEqual(1, recovered1.a)

        recovered2 = event_player.replay_entity(entity_id2)
        self.assertEqual(2, recovered2.a)

        recovered3 = event_player.replay_entity(entity_id3)
        self.assertEqual(None, recovered3)

        # Check it works for "short" entities (should be faster, but the main thing is that it still works).
        # - just use a trivial mutate that always instantiates the 'Example'.
        event5 = Example.AttributeChanged(originator_id=entity_id1,
                                          originator_version=1,
                                          name='a',
                                          value=10)
        self.entity_event_store.append(event5)

        recovered1 = event_player.replay_entity(entity_id1)
        self.assertEqual(10, recovered1.a)

        event_player = EventPlayer(
            event_store=self.entity_event_store,
            mutator=Example._mutate,
            is_short=True,
        )
        self.assertEqual(10, event_player.replay_entity(entity_id1).a)
コード例 #4
0
    def test_replay_entity(self):
        # Store example events.

        # Create entity1.
        entity_id1 = uuid4()
        event1 = Example.Created(originator_id=entity_id1, a=1, b=2)
        self.entity_event_store.append(event1)

        # Create entity2.
        entity_id2 = uuid4()
        event2 = Example.Created(originator_id=entity_id2, a=2, b=4)
        self.entity_event_store.append(event2)

        # Create entity3.
        entity_id3 = uuid4()
        event3 = Example.Created(originator_id=entity_id3, a=3, b=6)
        self.entity_event_store.append(event3)

        # Discard entity3.
        event4 = Example.Discarded(originator_id=entity_id3, originator_version=1)
        self.entity_event_store.append(event4)

        # Check the entities can be replayed.
        event_player = EventPlayer(event_store=self.entity_event_store, mutator=Example._mutate)

        # Check recovered entities have correct attribute values.
        recovered1 = event_player.replay_entity(entity_id1)
        self.assertEqual(entity_id1, recovered1.id)
        self.assertEqual(1, recovered1.a)

        recovered2 = event_player.replay_entity(entity_id2)
        self.assertEqual(2, recovered2.a)

        recovered3 = event_player.replay_entity(entity_id3)
        self.assertEqual(None, recovered3)

        # Check it works for "short" entities (should be faster, but the main thing is that it still works).
        # - just use a trivial mutate that always instantiates the 'Example'.
        event5 = Example.AttributeChanged(originator_id=entity_id1, originator_version=1, name='a', value=10)
        self.entity_event_store.append(event5)

        recovered1 = event_player.replay_entity(entity_id1)
        self.assertEqual(10, recovered1.a)

        event_player = EventPlayer(
            event_store=self.entity_event_store,
            mutator=Example._mutate,
            is_short=True,
        )
        self.assertEqual(10, event_player.replay_entity(entity_id1).a)
コード例 #5
0
    def __init__(self, event_store, mutator=None, snapshot_strategy=None, use_cache=False, *args, **kwargs):
        super(EventSourcedRepository, self).__init__(*args, **kwargs)
        self._cache = {}
        self._snapshot_strategy = snapshot_strategy
        # self._use_cache = use_cache

        # Check we got an event store.
        assert isinstance(event_store, AbstractEventStore), type(event_store)
        self._event_store = event_store

        # Instantiate an event player for this repo.
        mutator = mutator or type(self).mutator
        self.event_player = EventPlayer(
            event_store=self.event_store,
            mutator=mutator,
            page_size=self.__page_size__,
            is_short=self.__is_short__,
            snapshot_strategy=self._snapshot_strategy,
        )
コード例 #6
0
    def test_take_snapshot(self):
        self.entity_persistence_policy = PersistencePolicy(
            event_store=self.entity_event_store,
            event_type=VersionedEntity.Event,
        )
        self.snapshot_persistence_policy = PersistencePolicy(
            event_store=self.snapshot_store,
            event_type=Snapshot,
        )
        snapshot_strategy = EventSourcedSnapshotStrategy(
            event_store=self.snapshot_store
        )
        event_player = EventPlayer(
            event_store=self.entity_event_store,
            mutator=Example._mutate,
            snapshot_strategy=snapshot_strategy
        )

        # Take a snapshot with a non-existent ID.
        unregistered_id = uuid4()
        # Check no snapshot is taken.
        self.assertIsNone(event_player.take_snapshot(unregistered_id))
        # Check no snapshot is available.
        self.assertIsNone(event_player.get_snapshot(unregistered_id))

        # Create a new entity.
        registered_example = create_new_example(a=123, b=234)

        # Take a snapshot of the new entity (no previous snapshots).
        snapshot1 = event_player.take_snapshot(registered_example.id, lt=registered_example.version)

        # Check the snapshot is pegged to the last applied version.
        self.assertEqual(snapshot1.originator_version, 0)

        # Replay from this snapshot.
        entity_from_snapshot1 = entity_from_snapshot(snapshot1)
        retrieved_example = event_player.replay_entity(registered_example.id,
                                                       initial_state=entity_from_snapshot1,
                                                       gte=entity_from_snapshot1._version)

        # Check the attributes are correct.
        self.assertEqual(retrieved_example.a, 123)

        # Remember the version now.
        version1 = retrieved_example._version
        self.assertEqual(version1, 1)

        # Change attribute value.
        retrieved_example.a = 999

        # Remember the version now.
        version2 = retrieved_example._version
        self.assertEqual(version2, 2)

        # Change attribute value.
        retrieved_example.a = 9999

        # Remember the version now.
        version3 = retrieved_example._version
        self.assertEqual(version3, 3)

        # Check the event sourced entities are correct.
        retrieved_example = event_player.replay_entity(registered_example.id)
        self.assertEqual(retrieved_example.a, 9999)

        # Take another snapshot.
        snapshot2 = event_player.take_snapshot(retrieved_example.id, lt=retrieved_example.version)

        # Replay from this snapshot.
        initial_state = entity_from_snapshot(snapshot2)
        retrieved_example = event_player.replay_entity(
            registered_example.id,
            initial_state=initial_state,
            gte=initial_state._version,
        )
        # Check the attributes are correct.
        self.assertEqual(retrieved_example.a, 9999)

        # Check we can get historical state at version1.
        retrieved_example = event_player.replay_entity(registered_example.id, lt=version1)
        self.assertEqual(retrieved_example.a, 123)

        # Check we can get historical state at version2.
        retrieved_example = event_player.replay_entity(registered_example.id, lt=version2)
        self.assertEqual(retrieved_example.a, 999)

        # Check we can get historical state at version3.
        retrieved_example = event_player.replay_entity(registered_example.id, lt=version3)
        self.assertEqual(retrieved_example.a, 9999)

        # Similarly, check we can get historical state using a snapshot
        initial_state = entity_from_snapshot(snapshot1)
        retrieved_example = event_player.replay_entity(
            registered_example.id,
            initial_state=initial_state,
            gte=initial_state._version,
            lt=version2,
        )
        self.assertEqual(retrieved_example.a, 999)

        # Discard the entity.
        registered_example = event_player.replay_entity(registered_example.id)
        registered_example.discard()

        # Take snapshot of discarded entity.
        snapshot3 = event_player.take_snapshot(registered_example.id)
        self.assertIsNone(snapshot3.state)
        self.assertIsNone(entity_from_snapshot(snapshot3))
コード例 #7
0
class EventSourcedRepository(AbstractEntityRepository):
    # If the entity won't have very many events, marking the entity as
    # "short" by setting __is_short__ value equal to True will mean
    # the fastest path for getting all the events is used. If you set
    # a value for page size (see below), this option will have no effect.
    __is_short__ = False

    # The page size by which events are retrieved. If this
    # value is set to a positive integer, the events of
    # the entity will be retrieved in pages, using a series
    # of queries, rather than with one potentially large query.
    __page_size__ = None

    # The mutator function used by this repository. Can either
    # be set as a class attribute, or passed as a constructor arg.
    mutator = mutate_entity

    def __init__(self, event_store, mutator=None, snapshot_strategy=None, use_cache=False, *args, **kwargs):
        super(EventSourcedRepository, self).__init__(*args, **kwargs)
        self._cache = {}
        self._snapshot_strategy = snapshot_strategy
        # self._use_cache = use_cache

        # Check we got an event store.
        assert isinstance(event_store, AbstractEventStore), type(event_store)
        self._event_store = event_store

        # Instantiate an event player for this repo.
        mutator = mutator or type(self).mutator
        self.event_player = EventPlayer(
            event_store=self.event_store,
            mutator=mutator,
            page_size=self.__page_size__,
            is_short=self.__is_short__,
            snapshot_strategy=self._snapshot_strategy,
        )

    @property
    def event_store(self):
        return self._event_store

    def __contains__(self, entity_id):
        """
        Returns a boolean value according to whether entity with given ID exists.
        """
        return self.get_entity(entity_id) is not None

    def __getitem__(self, entity_id):
        """
        Returns entity with given ID.
        """
        # # Get entity from the cache.
        # if self._use_cache:
        #     try:
        #         return self._cache[entity_id]
        #     except KeyError:
        #         pass

        # Reconstitute the entity.
        entity = self.get_entity(entity_id)

        # Never created or already discarded?
        if entity is None:
            raise RepositoryKeyError(entity_id)

        # # Put entity in the cache.
        # if self._use_cache:
        #     self.add_cache(entity_id, entity)

        # Return entity.
        return entity

    # def add_cache(self, entity_id, entity):
    #     self._cache[entity_id] = entity

    def get_entity(self, entity_id, lt=None, lte=None):
        """
        Returns entity with given ID, optionally until position.
        """

        # Get a snapshot (None if none exist).
        if self._snapshot_strategy is not None:
            snapshot = self._snapshot_strategy.get_snapshot(entity_id, lt=lt, lte=lte)
        else:
            snapshot = None

        # Decide the initial state of the entity, and the
        # version of the last item applied to the entity.
        if snapshot is None:
            initial_state = None
            gt = None
        else:
            initial_state = entity_from_snapshot(snapshot)
            gt = snapshot.originator_version

        # Replay domain events.
        return self.event_player.replay_entity(entity_id, gt=gt, lt=lt, lte=lte, initial_state=initial_state)

    def take_snapshot(self, entity_id, lt=None, lte=None):
        return self.event_player.take_snapshot(entity_id, lt=lt, lte=lte)
コード例 #8
0
    def test_take_snapshot(self):
        self.entity_persistence_policy = PersistencePolicy(
            event_store=self.entity_event_store,
            event_type=VersionedEntity.Event,
        )
        self.snapshot_persistence_policy = PersistencePolicy(
            event_store=self.snapshot_store,
            event_type=Snapshot,
        )
        snapshot_strategy = EventSourcedSnapshotStrategy(
            event_store=self.snapshot_store)
        event_player = EventPlayer(event_store=self.entity_event_store,
                                   mutator=Example._mutate,
                                   snapshot_strategy=snapshot_strategy)

        # Take a snapshot with a non-existent ID.
        unregistered_id = uuid4()
        # Check no snapshot is taken.
        self.assertIsNone(event_player.take_snapshot(unregistered_id))
        # Check no snapshot is available.
        self.assertIsNone(event_player.get_snapshot(unregistered_id))

        # Create a new entity.
        registered_example = create_new_example(a=123, b=234)

        # Take a snapshot of the new entity (no previous snapshots).
        snapshot1 = event_player.take_snapshot(registered_example.id,
                                               lt=registered_example.version)

        # Check the snapshot is pegged to the last applied version.
        self.assertEqual(snapshot1.originator_version, 0)

        # Replay from this snapshot.
        entity_from_snapshot1 = entity_from_snapshot(snapshot1)
        retrieved_example = event_player.replay_entity(
            registered_example.id,
            initial_state=entity_from_snapshot1,
            gte=entity_from_snapshot1._version)

        # Check the attributes are correct.
        self.assertEqual(retrieved_example.a, 123)

        # Remember the version now.
        version1 = retrieved_example._version
        self.assertEqual(version1, 1)

        # Change attribute value.
        retrieved_example.a = 999

        # Remember the version now.
        version2 = retrieved_example._version
        self.assertEqual(version2, 2)

        # Change attribute value.
        retrieved_example.a = 9999

        # Remember the version now.
        version3 = retrieved_example._version
        self.assertEqual(version3, 3)

        # Check the event sourced entities are correct.
        retrieved_example = event_player.replay_entity(registered_example.id)
        self.assertEqual(retrieved_example.a, 9999)

        # Take another snapshot.
        snapshot2 = event_player.take_snapshot(retrieved_example.id,
                                               lt=retrieved_example.version)

        # Replay from this snapshot.
        initial_state = entity_from_snapshot(snapshot2)
        retrieved_example = event_player.replay_entity(
            registered_example.id,
            initial_state=initial_state,
            gte=initial_state._version,
        )
        # Check the attributes are correct.
        self.assertEqual(retrieved_example.a, 9999)

        # Check we can get historical state at version1.
        retrieved_example = event_player.replay_entity(registered_example.id,
                                                       lt=version1)
        self.assertEqual(retrieved_example.a, 123)

        # Check we can get historical state at version2.
        retrieved_example = event_player.replay_entity(registered_example.id,
                                                       lt=version2)
        self.assertEqual(retrieved_example.a, 999)

        # Check we can get historical state at version3.
        retrieved_example = event_player.replay_entity(registered_example.id,
                                                       lt=version3)
        self.assertEqual(retrieved_example.a, 9999)

        # Similarly, check we can get historical state using a snapshot
        initial_state = entity_from_snapshot(snapshot1)
        retrieved_example = event_player.replay_entity(
            registered_example.id,
            initial_state=initial_state,
            gte=initial_state._version,
            lt=version2,
        )
        self.assertEqual(retrieved_example.a, 999)

        # Discard the entity.
        registered_example = event_player.replay_entity(registered_example.id)
        registered_example.discard()

        # Take snapshot of discarded entity.
        snapshot3 = event_player.take_snapshot(registered_example.id)
        self.assertIsNone(snapshot3.state)
        self.assertIsNone(entity_from_snapshot(snapshot3))
コード例 #9
0
class EventSourcedRepository(AbstractEntityRepository):
    # If the entity won't have very many events, marking the entity as
    # "short" by setting __is_short__ value equal to True will mean
    # the fastest path for getting all the events is used. If you set
    # a value for page size (see below), this option will have no effect.
    __is_short__ = False

    # The page size by which events are retrieved. If this
    # value is set to a positive integer, the events of
    # the entity will be retrieved in pages, using a series
    # of queries, rather than with one potentially large query.
    __page_size__ = None

    # The mutator function used by this repository. Can either
    # be set as a class attribute, or passed as a constructor arg.
    mutator = mutate_entity

    def __init__(self,
                 event_store,
                 mutator=None,
                 snapshot_strategy=None,
                 use_cache=False,
                 *args,
                 **kwargs):
        super(EventSourcedRepository, self).__init__(*args, **kwargs)
        self._cache = {}
        self._snapshot_strategy = snapshot_strategy
        # self._use_cache = use_cache

        # Check we got an event store.
        assert isinstance(event_store, AbstractEventStore), type(event_store)
        self._event_store = event_store

        # Instantiate an event player for this repo.
        mutator = mutator or type(self).mutator
        self.event_player = EventPlayer(
            event_store=self.event_store,
            mutator=mutator,
            page_size=self.__page_size__,
            is_short=self.__is_short__,
            snapshot_strategy=self._snapshot_strategy,
        )

    @property
    def event_store(self):
        return self._event_store

    def __contains__(self, entity_id):
        """
        Returns a boolean value according to whether entity with given ID exists.
        """
        return self.get_entity(entity_id) is not None

    def __getitem__(self, entity_id):
        """
        Returns entity with given ID.
        """
        # # Get entity from the cache.
        # if self._use_cache:
        #     try:
        #         return self._cache[entity_id]
        #     except KeyError:
        #         pass

        # Reconstitute the entity.
        entity = self.get_entity(entity_id)

        # Never created or already discarded?
        if entity is None:
            raise RepositoryKeyError(entity_id)

        # # Put entity in the cache.
        # if self._use_cache:
        #     self.add_cache(entity_id, entity)

        # Return entity.
        return entity

    # def add_cache(self, entity_id, entity):
    #     self._cache[entity_id] = entity

    def get_entity(self, entity_id, lt=None, lte=None):
        """
        Returns entity with given ID, optionally until position.
        """

        # Get a snapshot (None if none exist).
        if self._snapshot_strategy is not None:
            snapshot = self._snapshot_strategy.get_snapshot(entity_id,
                                                            lt=lt,
                                                            lte=lte)
        else:
            snapshot = None

        # Decide the initial state of the entity, and the
        # version of the last item applied to the entity.
        if snapshot is None:
            initial_state = None
            gt = None
        else:
            initial_state = entity_from_snapshot(snapshot)
            gt = snapshot.originator_version

        # Replay domain events.
        return self.event_player.replay_entity(entity_id,
                                               gt=gt,
                                               lt=lt,
                                               lte=lte,
                                               initial_state=initial_state)

    def take_snapshot(self, entity_id, lt=None, lte=None):
        return self.event_player.take_snapshot(entity_id, lt=lt, lte=lte)
コード例 #10
0
    def test_get_entity(self):
        # Store example events.
        entity_id1 = uuid4()
        event1 = Example.Created(entity_id=entity_id1, a=1, b=2)
        self.version_entity_event_store.append(event1)
        entity_id2 = uuid4()
        event2 = Example.Created(entity_id=entity_id2, a=2, b=4)
        self.version_entity_event_store.append(event2)
        entity_id3 = uuid4()
        event3 = Example.Created(entity_id=entity_id3, a=3, b=6)
        self.version_entity_event_store.append(event3)
        event4 = Example.Discarded(entity_id=entity_id3, entity_version=1)
        self.version_entity_event_store.append(event4)

        # Check the event sourced entities are correct.
        # - just use a trivial mutate that always instantiates the 'Example'.
        event_player = EventPlayer(event_store=self.version_entity_event_store, mutator=Example.mutate)

        # The the reconstituted entity has correct attribute values.
        self.assertEqual(entity_id1, event_player.replay_entity(entity_id1).id)
        self.assertEqual(1, event_player.replay_entity(entity_id1).a)
        self.assertEqual(2, event_player.replay_entity(entity_id2).a)
        self.assertEqual(None, event_player.replay_entity(entity_id3))

        # Check entity3 raises KeyError.
        self.assertEqual(event_player.replay_entity(entity_id3), None)

        # Check it works for "short" entities (should be faster, but the main thing is that it still works).
        # - just use a trivial mutate that always instantiates the 'Example'.
        event5 = Example.AttributeChanged(entity_id=entity_id1, entity_version=1, name='a', value=10)
        self.version_entity_event_store.append(event5)

        event_player = EventPlayer(event_store=self.version_entity_event_store, mutator=Example.mutate)
        self.assertEqual(10, event_player.replay_entity(entity_id1).a)

        event_player = EventPlayer(
            event_store=self.version_entity_event_store,
            mutator=Example.mutate,
            is_short=True,
        )
        self.assertEqual(10, event_player.replay_entity(entity_id1).a)
コード例 #11
0
    def test_snapshots(self):
        self.policy = CombinedPersistencePolicy(
            versioned_entity_event_store=self.version_entity_event_store,
            timestamped_entity_event_store=self.timestamp_entity_event_store,

        )
        event_player = EventPlayer(
            event_store=self.version_entity_event_store,
            mutator=Example.mutate,
            snapshot_strategy=EventSourcedSnapshotStrategy(
                event_store=self.timestamp_entity_event_store
            )
        )

        # Take a snapshot with a non-existent ID.
        self.assertIsNone(event_player.take_snapshot(uuid4()))

        # Create a new entity.
        registered_example = register_new_example(a=123, b=234)

        # Take a snapshot.
        snapshot1 = event_player.take_snapshot(registered_example.id)

        # Replay from this snapshot.
        initial_state = entity_from_snapshot(snapshot1)
        retrieved_example = event_player.replay_entity(registered_example.id,
                                                       initial_state=initial_state,
                                                       gte=initial_state._version)

        # Check the attributes are correct.
        self.assertEqual(retrieved_example.a, 123)

        # Remember the version now.
        version1 = retrieved_example._version

        # Change attribute value.
        retrieved_example.a = 999

        # Remember the version now.
        version2 = retrieved_example._version

        # Change attribute value.
        retrieved_example.a = 9999

        # Remember the version now.
        version3 = retrieved_example._version

        # Check the event sourced entities are correct.
        retrieved_example = event_player.replay_entity(registered_example.id)
        self.assertEqual(retrieved_example.a, 9999)

        # Take another snapshot.
        snapshot2 = event_player.take_snapshot(retrieved_example.id)

        # Check we can replay from this snapshot.
        initial_state = entity_from_snapshot(snapshot2)
        retrieved_example = event_player.replay_entity(
            registered_example.id,
            initial_state=initial_state,
            gte=initial_state._version,
        )
        # Check the attributes are correct.
        self.assertEqual(retrieved_example.a, 9999)

        # Check we can get historical state at version1.
        retrieved_example = event_player.replay_entity(registered_example.id, lt=version1)
        self.assertEqual(retrieved_example.a, 123)

        # Check we can get historical state at version2.
        retrieved_example = event_player.replay_entity(registered_example.id, lt=version2)
        self.assertEqual(retrieved_example.a, 999)

        # Check we can get historical state at version3.
        retrieved_example = event_player.replay_entity(registered_example.id, lt=version3)
        self.assertEqual(retrieved_example.a, 9999)

        # Similarly, check we can get historical state using a snapshot
        initial_state = entity_from_snapshot(snapshot1)
        retrieved_example = event_player.replay_entity(
            registered_example.id,
            initial_state=initial_state,
            gte=initial_state._version,
            lt=version2,
        )
        self.assertEqual(retrieved_example.a, 999)