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 })
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})
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 )
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
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 })
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"]
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), )
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'])
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
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
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
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)
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)
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, ))
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()
def construct_datastore(self): return SQLAlchemyDatastore(base=Base, settings=SQLAlchemySettings(), tables=(ExtendedIntegerSequencedRecord, ))
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)
def setup_datastore(self, session, uri, pool_size=5): self.datastore = SQLAlchemyDatastore( settings=SQLAlchemySettings(uri=uri, pool_size=pool_size), session=session, )
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()
def setup_datastore(self, session, uri): self.datastore = SQLAlchemyDatastore( settings=SQLAlchemySettings(uri=uri), session=session, )