Пример #1
0
    def start_app(self):
        # Make up a DB URI using a named temporary file.
        self.tempfile = NamedTemporaryFile()
        uri = 'sqlite:///{}'.format(self.tempfile.name)

        from eventsourcing.example.interface.flaskapp import IntegerSequencedItem
        # Close application, importing the module constructed
        # the application, which will leave event handlers subscribed.
        close_example_application()

        # Setup tables.
        datastore = SQLAlchemyDatastore(
            settings=SQLAlchemySettings(uri=uri),
            tables=(IntegerSequencedItem,),
        )
        datastore.setup_connection()
        datastore.setup_tables()
        datastore.close_connection()

        # Run uwsgi.
        path_to_uwsgi = join(path_to_virtualenv, 'bin', 'uwsgi')
        assert os.path.exists(path_to_uwsgi), path_to_uwsgi
        cmd = [path_to_uwsgi]
        if path_to_virtualenv is not None:
            cmd += ['-H', path_to_virtualenv]
        cmd += ['--master']
        cmd += ['--processes', '4']
        cmd += ['--threads', '2']
        cmd += ['--wsgi-file', path_to_flaskwsgi]
        cmd += ['--http', ':{}'.format(self.port)]
        pythonpath = ':'.join(os.getenv('PYTHONPATH', '').split(':') + [path_to_eventsourcing])
        return Popen(cmd, env={
            'PYTHONPATH': pythonpath,
            'DB_URI': uri
        })
Пример #2
0
    def start_app(self):
        # Make up a DB URI using a named temporary file.
        self.tempfile = NamedTemporaryFile()
        uri = "sqlite:///{}".format(self.tempfile.name)

        from eventsourcing.example.interface.flaskapp import IntegerSequencedItem

        # Close application, importing the module constructed
        # the application, which will leave event handlers subscribed.
        close_example_application()

        # Setup tables.
        datastore = SQLAlchemyDatastore(settings=SQLAlchemySettings(uri=uri),
                                        tables=(IntegerSequencedItem, ))
        datastore.setup_connection()
        datastore.setup_tables()
        datastore.close_connection()

        # Run uwsgi.
        path_to_uwsgi = shutil.which("uwsgi")
        if not os.path.exists(path_to_uwsgi):
            raise AssertionError("Can't find uwsgi: %s" % path_to_uwsgi)
        cmd = [path_to_uwsgi]
        if path_to_virtualenv is not None:
            cmd += ["-H", path_to_virtualenv]
        cmd += ["--master"]
        cmd += ["--processes", "4"]
        cmd += ["--threads", "2"]
        cmd += ["--wsgi-file", path_to_flaskapp]
        cmd += ["--http", ":{}".format(self.port)]
        pythonpath = ":".join(
            os.getenv("PYTHONPATH", "").split(":") + [path_to_eventsourcing])
        return Popen(cmd, env={"PYTHONPATH": pythonpath, "DB_URI": uri})
Пример #3
0
def construct_sqlalchemy_db(uri="sqlite://") -> SQLAlchemyDatastore:
    db = SQLAlchemyDatastore(settings=SQLAlchemySettings(uri),
                             tables=(StoredEventRecord, ))
    db.setup_connection()
    db.drop_tables()
    db.setup_tables()
    return db
    def construct_datastore(self):
        if self.use_named_temporary_file:
            self.temp_file = NamedTemporaryFile("a", delete=True)
            uri = "sqlite:///" + self.temp_file.name
        else:
            uri = DEFAULT_SQLALCHEMY_DB_URI

        # kwargs = {}
        # if not self.use_named_temporary_file:
        # kwargs['connect_args'] = {'check_same_thread':False}
        # kwargs['poolclass'] = StaticPool

        return SQLAlchemyDatastore(
            base=Base,
            settings=SQLAlchemySettings(uri=uri),
            tables=(
                IntegerSequencedWithIDRecord,
                IntegerSequencedNoIDRecord,
                TimestampSequencedWithIDRecord,
                TimestampSequencedNoIDRecord,
                SnapshotRecord,
            ),
            connection_strategy=self.connection_strategy,
            # **kwargs
        )
Пример #5
0
 def construct_datastore(self):
     datastore = SQLAlchemyDatastore(
         settings=SQLAlchemySettings(uri=self.uri,
                                     pool_size=self.pool_size),
         session=self.session,
     )
     self.session = datastore.session
     return datastore
Пример #6
0
    def start_app(self):
        # Make up a DB URI using a named temporary file.
        self.tempfile = NamedTemporaryFile()
        uri = 'sqlite:///{}'.format(self.tempfile.name)

        from eventsourcing.example.interface.flaskapp import IntegerSequencedItem
        # Close application, importing the module constructed
        # the application, which will leave event handlers subscribed.
        close_example_application()

        # Setup tables.
        datastore = SQLAlchemyDatastore(
            settings=SQLAlchemySettings(uri=uri),
            tables=(IntegerSequencedItem,),
        )
        datastore.setup_connection()
        datastore.setup_tables()
        datastore.drop_connection()

        # Run uwsgi.
        path_to_uwsgi = join(path_to_virtualenv, 'bin', 'uwsgi')
        assert os.path.exists(path_to_uwsgi), path_to_uwsgi
        cmd = [path_to_uwsgi]
        if path_to_virtualenv is not None:
            cmd += ['-H', path_to_virtualenv]
        cmd += ['--master']
        cmd += ['--processes', '4']
        cmd += ['--threads', '2']
        cmd += ['--wsgi-file', path_to_flaskwsgi]
        cmd += ['--http', ':{}'.format(self.port)]
        pythonpath = ':'.join(os.getenv('PYTHONPATH', '').split(':') + [path_to_eventsourcing])
        return Popen(cmd, env={
            'PYTHONPATH': pythonpath,
            'DB_URI': uri
        })
Пример #7
0
    def tearDown(self):
        clear_event_handlers()

        # Need to drop the stored events, because the __main__#Order topics
        # mess up the multiprocessing tests (because the Orders application
        # has the same ID so events from one test cause another to fail).
        os.environ[
            "DB_URI"] = "mysql+pymysql://{}:{}@{}/eventsourcing?charset=utf8mb4&binary_prefix=true".format(
                os.getenv("MYSQL_USER", "root"),
                os.getenv("MYSQL_PASSWORD", ""),
                os.getenv("MYSQL_HOST", "127.0.0.1"),
            )
        database = SQLAlchemyDatastore(settings=SQLAlchemySettings())
        database.setup_connection()
        # Might as well drop everything....
        Base.metadata.drop_all(database._engine)

        del os.environ["DB_URI"]
Пример #8
0
 def construct_datastore(self):
     if self.use_named_temporary_file:
         self.temp_file = NamedTemporaryFile('a', delete=True)
         uri = 'sqlite:///' + self.temp_file.name
     else:
         uri = DEFAULT_SQLALCHEMY_DB_URI
     return SQLAlchemyDatastore(
         base=Base,
         settings=SQLAlchemySettings(uri=uri),
         tables=(SqlIntegerSequencedItem, SqlTimestampSequencedItem),
     )
Пример #9
0
    def tearDown(self):
        from eventsourcing.domain.model.events import _event_handlers
        if _event_handlers:
            print("Warning: event handlers still subscribed: {}".format(
                _event_handlers))
        _event_handlers.clear()

        # Need to drop the stored events, because the __main__#Order topics
        # mess up the multiprocessing tests (because the Orders application
        # has the same ID so events from one test cause another to fail).
        os.environ['DB_URI'] = 'mysql+pymysql://{}:{}@{}/eventsourcing'.format(
            os.getenv('MYSQL_USER', 'root'),
            os.getenv('MYSQL_PASSWORD', ''),
            os.getenv('MYSQL_HOST', '127.0.0.1'),
        )
        database = SQLAlchemyDatastore(settings=SQLAlchemySettings())
        database.setup_connection()
        # Might as well drop everything....
        Base.metadata.drop_all(database._engine)

        del (os.environ['DB_URI'])
Пример #10
0
    def construct_datastore(self) -> Optional[AbstractDatastore]:
        """
        Constructs SQLAlchemy datastore.

        :rtype: SQLAlchemyDatastore
        """
        datastore = SQLAlchemyDatastore(
            settings=SQLAlchemySettings(uri=self.uri, pool_size=self.pool_size),
            session=self.session,
        )
        if self.session is None:
            assert datastore.session, "Datastore object session is None"
            self.session = datastore.session
        return datastore
Пример #11
0
def init_database(**kwargs):
    global _event_datastore
    if kwargs['uri'] is None:
        kwargs.pop('uri')
        uri = f'sqlite:///{BASEDIR}/event.db'
    else:
        uri = kwargs.pop('uri')
    if _event_datastore is not None:
        raise AssertionError("init_database() has already been called.")
    _event_datastore = SQLAlchemyDatastore(
        settings=SQLAlchemySettings(uri=uri),
        tables=(
            IntegerSequencedItemRecord,
            SnapshotRecord,
        ),
        **kwargs)
    return _event_datastore
Пример #12
0
    def __init__(self, session):
        # Construct event stores and persistence policies.
        datastore = SQLAlchemyDatastore(
            settings=SQLAlchemySettings(uri='sqlite:///:memory:'),
            tables=(IntegerSequencedItemRecord, ),
        )

        datastore.setup_connection()
        datastore.setup_tables()

        super(TodoApp, self).__init__()
        pass
Пример #13
0
def test():
    # Configure database.
    settings = SQLAlchemySettings(uri='sqlite:///:memory:')

    # Setup database.
    datastore = SQLAlchemyDatastore(
        settings=settings,
        tables=(IntegerSequencedItemRecord, ),
    )
    datastore.setup_connection()
    datastore.setup_tables()

    # Construct application.
    app = TodoApp(session=datastore.session)

    # Check the user initially has no lists.
    user_id = uuid4()
    todo_list_ids = app.get_todo_list_ids(user_id)
    assert todo_list_ids == []

    # Start a new list.
    todo_list_id = app.start_todo_list(user_id)

    # Check the user has one list.
    todo_list_ids = app.get_todo_list_ids(user_id)
    assert todo_list_ids == {todo_list_id}

    # Check the list has no items.
    assert app.get_todo_items(todo_list_id) == ()

    # Add an item to the list.
    app.add_todo_item(todo_list_id=todo_list_id, item='item1')

    # Check the list has one item.
    assert app.get_todo_items(todo_list_id) == ('item1', )

    # Update the item.
    app.update_todo_item(todo_list_id=todo_list_id, index=0, item='item1.1')

    # Get the list and see it has the updated item.
    assert app.get_todo_items(todo_list_id) == ('item1.1', )

    # Discard the item, and check by getting the list and checking it has no items.
    app.discard_todo_item(todo_list_id=todo_list_id, index=0)
    assert app.get_todo_items(todo_list_id) == ()

    # Discard the list, and check there are no list IDs for the user.
    app.discard_todo_list(todo_list_id=todo_list_id)
    todo_list_ids = app.get_todo_list_ids(user_id)
    assert len(todo_list_ids) == 0
    def start_app(self):
        # Make up a DB URI using a named temporary file.
        self.tempfile = NamedTemporaryFile()
        uri = "sqlite:///{}".format(self.tempfile.name)

        from eventsourcing.example.interface.flaskapp import IntegerSequencedItem

        # Close application, importing the module constructed
        # the application, which will leave event handlers subscribed.
        close_example_application()

        # Setup tables.
        datastore = SQLAlchemyDatastore(settings=SQLAlchemySettings(uri=uri),
                                        tables=(IntegerSequencedItem, ))
        datastore.setup_connection()
        datastore.setup_tables()
        datastore.close_connection()

        # Run uwsgi.
        if path_to_virtualenv:
            path_to_uwsgi = join(path_to_virtualenv, "bin", "uwsgi")
            assert os.path.exists(path_to_uwsgi), path_to_uwsgi
        else:
            # In a container, without a virtualenv?
            path_to_uwsgi = "/usr/local/bin/uwsgi"
            # Todo: Maybe use shutil.which, after dropping support for Python 2.7.

        cmd = [path_to_uwsgi]
        if path_to_virtualenv is not None:
            cmd += ["-H", path_to_virtualenv]
        cmd += ["--master"]
        cmd += ["--processes", "4"]
        cmd += ["--threads", "2"]
        cmd += ["--wsgi-file", path_to_flaskwsgi]
        cmd += ["--http", ":{}".format(self.port)]
        pythonpath = ":".join(
            os.getenv("PYTHONPATH", "").split(":") + [path_to_eventsourcing])
        return Popen(cmd, env={"PYTHONPATH": pythonpath, "DB_URI": uri})
    def test_construct_sqlalchemy_eventstore(self):
        # Construct the infrastructure.
        datastore = SQLAlchemyDatastore(settings=SQLAlchemySettings())
        datastore.setup_connection()

        event_store = construct_sqlalchemy_eventstore(
            session=datastore.session,
            contiguous_record_ids=True,
            application_name=uuid4().hex,
        )
        datastore.setup_table(event_store.record_manager.record_class)

        self.assertIsInstance(event_store, EventStore)

        # Store an event.
        aggregate_id = uuid4()
        aggregate_version = 0
        domain_event = DomainEvent(
            a=1,
            originator_id=aggregate_id,
            originator_version=aggregate_version,
        )
        event_store.append(domain_event)

        # Get the domain events.
        events = event_store.get_domain_events(originator_id=aggregate_id)
        self.assertEqual(len(events), 1)
        self.assertEqual(events[0], domain_event)

        # Test the while clause of all_sequence_ids() is filtering on application_name.
        self.assertEqual(event_store.record_manager.record_class,
                         StoredEventRecord)
        sequence_ids = event_store.record_manager.list_sequence_ids()
        self.assertEqual([aggregate_id], sequence_ids)

        # - check the aggregate ID isn't listed by another application
        event_store = construct_sqlalchemy_eventstore(
            session=datastore.session,
            contiguous_record_ids=True,
            application_name=uuid4().hex,
        )
        sequence_ids = event_store.record_manager.list_sequence_ids()
        self.assertEqual([], sequence_ids)
Пример #16
0
    def test_construct_sqlalchemy_eventstore(self):

        datastore = SQLAlchemyDatastore(settings=SQLAlchemySettings())
        datastore.setup_connection()

        event_store = construct_sqlalchemy_eventstore(datastore.session)
        datastore.setup_table(event_store.record_manager.record_class)

        self.assertIsInstance(event_store, EventStore)

        aggregate_id = uuid4()
        aggregate_version = 0
        domain_event = DomainEvent(
            a=1,
            originator_id=aggregate_id,
            originator_version=aggregate_version,
        )
        event_store.append(domain_event)
        events = event_store.get_domain_events(originator_id=aggregate_id)
        self.assertEqual(len(events), 1)
        self.assertEqual(events[0], domain_event)
Пример #17
0
import os

from eventsourcing.domain.services.aes_cipher import AESCipher
from eventsourcing.infrastructure.sqlalchemy.activerecords import IntegerSequencedItemRecord, SnapshotRecord
from eventsourcing.infrastructure.sqlalchemy.datastore import SQLAlchemyDatastore, SQLAlchemySettings

# DB_HOST = os.getenv('DB_HOST', 'sqlite:////Users/gonzo/Projects/eventsourcing-kanban/infrastructure/event.db')
DB_HOST = os.getenv('DB_HOST', 'sqlite:///:memory:')
AES_KEY = os.getenv('AES_KEY', '0123456789abcdef')

event_datastore = SQLAlchemyDatastore(settings=SQLAlchemySettings(uri=DB_HOST),
                                      tables=(
                                          IntegerSequencedItemRecord,
                                          SnapshotRecord,
                                      ))

cipher = AESCipher(AES_KEY)


def get_session(datastore=event_datastore):
    datastore.setup_connection()
    datastore.setup_tables()
    return datastore
 def construct_datastore(self):
     return SQLAlchemyDatastore(base=Base,
                                settings=SQLAlchemySettings(),
                                tables=(StoredEventRecord, ))
Пример #19
0
class SimpleApplication(object):
    def __init__(self, persist_event_type=None, uri=None, session=None, cipher_key=None,
                 stored_event_record_class=None, setup_table=True, contiguous_record_ids=True):

        # Setup cipher (optional).
        self.setup_cipher(cipher_key)

        # Setup connection to database.
        self.setup_datastore(session, uri)

        # Setup the event store.
        self.stored_event_record_class = stored_event_record_class
        self.contiguous_record_ids = contiguous_record_ids
        self.setup_event_store()

        # Setup notifications.
        self.notification_log = RecordManagerNotificationLog(
            self.event_store.record_manager,
            section_size=20,
        )

        # Setup an event sourced repository.
        self.setup_repository()

        # Setup a persistence policy.
        self.setup_persistence_policy(persist_event_type)

        # Setup table in database.
        if setup_table:
            self.setup_table()

    def setup_cipher(self, cipher_key):
        cipher_key = decode_random_bytes(cipher_key or os.getenv('CIPHER_KEY', ''))
        self.cipher = AESCipher(cipher_key) if cipher_key else None

    def setup_datastore(self, session, uri):
        self.datastore = SQLAlchemyDatastore(
            settings=SQLAlchemySettings(uri=uri),
            session=session,
        )

    def setup_event_store(self):
        # Construct event store.
        self.event_store = construct_sqlalchemy_eventstore(
            session=self.datastore.session,
            cipher=self.cipher,
            record_class=self.stored_event_record_class,
            contiguous_record_ids=self.contiguous_record_ids,
        )

    def setup_repository(self, **kwargs):
        self.repository = EventSourcedRepository(
            event_store=self.event_store,
            **kwargs
        )

    def setup_persistence_policy(self, persist_event_type):
        self.persistence_policy = PersistencePolicy(
            event_store=self.event_store,
            event_type=persist_event_type
        )

    def setup_table(self):
        # Setup the database table using event store's record class.
        self.datastore.setup_table(
            self.event_store.record_manager.record_class
        )

    def drop_table(self):
        # Setup the database table using event store's record class.
        self.datastore.drop_table(
            self.event_store.record_manager.record_class
        )

    def close(self):
        # Close the persistence policy.
        self.persistence_policy.close()

        # Close database connection.
        self.datastore.close_connection()

    def __enter__(self):
        return self

    def __exit__(self, exc_type, exc_val, exc_tb):
        self.close()
Пример #20
0
 def construct_datastore(self):
     return SQLAlchemyDatastore(base=Base,
                                settings=SQLAlchemySettings(),
                                tables=(ExtendedIntegerSequencedRecord, ))
Пример #21
0
import uuid
from eventsourcing.infrastructure.sequenceditemmapper import SequencedItemMapper
from eventsourcing.infrastructure.eventsourcedrepository import EventSourcedRepository
from eventsourcing.infrastructure.eventstore import EventStore
from eventsourcing.infrastructure.sequenceditem import StoredEvent
from eventsourcing.infrastructure.sqlalchemy.datastore import SQLAlchemyDatastore, SQLAlchemySettings
from eventsourcing.infrastructure.sqlalchemy.manager import SQLAlchemyRecordManager
from eventsourcing.infrastructure.sqlalchemy.records import StoredEventRecord

datastore = SQLAlchemyDatastore(
    tables=(StoredEventRecord, ),
    settings=SQLAlchemySettings(uri='sqlite:///mydatabase'))

datastore.setup_connection()
datastore.setup_tables()

recordmanager = SQLAlchemyRecordManager(session=datastore.session,
                                        record_class=StoredEventRecord,
                                        application_name=uuid.uuid4().hex,
                                        contiguous_record_ids=True,
                                        sequenced_item_class=StoredEvent)

sequenceitemmapper = SequencedItemMapper(sequenced_item_class=StoredEvent)

eventstore = EventStore(record_manager=recordmanager,
                        sequenced_item_mapper=sequenceitemmapper)

repository = EventSourcedRepository(event_store=eventstore)
Пример #22
0
 def setup_datastore(self, session, uri, pool_size=5):
     self.datastore = SQLAlchemyDatastore(
         settings=SQLAlchemySettings(uri=uri, pool_size=pool_size),
         session=session,
     )
Пример #23
0
class SimpleApplication(object):
    persist_event_type = None

    def __init__(self,
                 name='',
                 persistence_policy=None,
                 persist_event_type=None,
                 uri=None,
                 pool_size=5,
                 session=None,
                 cipher_key=None,
                 sequenced_item_class=None,
                 stored_event_record_class=None,
                 setup_table=True,
                 contiguous_record_ids=True,
                 pipeline_id=-1,
                 notification_log_section_size=None):

        self.notification_log_section_size = notification_log_section_size
        self.name = name or type(self).__name__.lower()

        # Setup cipher (optional).
        self.setup_cipher(cipher_key)

        # Setup connection to database.
        self.setup_datastore(session, uri, pool_size)

        # Setup the event store.
        self.sequenced_item_class = sequenced_item_class
        self.stored_event_record_class = stored_event_record_class
        self.contiguous_record_ids = contiguous_record_ids
        self.application_id = uuid_from_application_name(self.name)
        self.pipeline_id = pipeline_id
        self.setup_event_store()

        # Setup notifications.
        self.notification_log = RecordManagerNotificationLog(
            self.event_store.record_manager,
            section_size=self.notification_log_section_size)

        # Setup an event sourced repository.
        self.setup_repository()

        # Setup a persistence policy.
        self.persistence_policy = persistence_policy
        if self.persistence_policy is None:
            self.setup_persistence_policy(persist_event_type
                                          or type(self).persist_event_type)

        # Setup table in database.
        if setup_table and not session:
            self.setup_table()

    def change_pipeline(self, pipeline_id):
        self.pipeline_id = pipeline_id
        self.event_store.record_manager.pipeline_id = pipeline_id

    @property
    def session(self):
        return self.datastore.session

    def setup_cipher(self, cipher_key):
        cipher_key = decode_random_bytes(cipher_key
                                         or os.getenv('CIPHER_KEY', ''))
        self.cipher = AESCipher(cipher_key) if cipher_key else None

    def setup_datastore(self, session, uri, pool_size=5):
        self.datastore = SQLAlchemyDatastore(
            settings=SQLAlchemySettings(uri=uri, pool_size=pool_size),
            session=session,
        )

    def setup_event_store(self):
        # Construct event store.
        self.event_store = self.construct_event_store(self.application_id,
                                                      self.pipeline_id)

    def construct_event_store(self, application_id, pipeline_id):
        return construct_sqlalchemy_eventstore(
            sequenced_item_class=self.sequenced_item_class,
            session=self.datastore.session,
            cipher=self.cipher,
            record_class=self.stored_event_record_class,
            contiguous_record_ids=self.contiguous_record_ids,
            application_id=application_id,
            pipeline_id=pipeline_id,
        )

    def setup_repository(self, **kwargs):
        event_store = self.event_store
        self.repository = self.construct_repository(event_store, **kwargs)

    def construct_repository(self, event_store, **kwargs):
        return EventSourcedRepository(event_store=event_store, **kwargs)

    def setup_persistence_policy(self, persist_event_type):
        self.persistence_policy = PersistencePolicy(
            event_store=self.event_store, event_type=persist_event_type)

    def setup_table(self):
        # Setup the database table using event store's record class.
        self.datastore.setup_table(
            self.event_store.record_manager.record_class)

    def drop_table(self):
        # Setup the database table using event store's record class.
        self.datastore.drop_table(self.event_store.record_manager.record_class)

    def close(self):
        # Close the persistence policy.
        if self.persistence_policy:
            self.persistence_policy.close()

        # Close database connection.
        self.datastore.close_connection()

    def __enter__(self):
        return self

    def __exit__(self, exc_type, exc_val, exc_tb):
        self.close()
Пример #24
0
 def setup_datastore(self, session, uri):
     self.datastore = SQLAlchemyDatastore(
         settings=SQLAlchemySettings(uri=uri),
         session=session,
     )