def __init__(self, connection_uri, dbtype="mysql", **kwargs): if not connection_uri: raise IllegalArgumentException("The database connection URI is required") super(Backend, self).__init__() self._session = None self._uri = dbtype + CONNECTION_URI_DELIM + connection_uri self._dbtype = dbtype self._tables = {} """ TODO verify that 'create_engine' and 'MetaData __init__' don't have conflicting args - if so, then being a cowboy and passing in kwargs will not work. This will need testing obv...we might actually have to expand kwargs out rather than passing it in. """ self._engine = create_engine(self._uri, **kwargs) self._meta = MetaData(bind=self._engine, **kwargs) if kwargs.get("load", False): self._meta.reflect(**kwargs)
class SQL(Backend): """ Wrapper object to adapt data source model for use with a Transactor """ def __init__(self, connection_uri, dbtype="mysql", **kwargs): if not connection_uri: raise IllegalArgumentException("The database connection URI is required") super(Backend, self).__init__() self._session = None self._uri = dbtype + CONNECTION_URI_DELIM + connection_uri self._dbtype = dbtype self._tables = {} """ TODO verify that 'create_engine' and 'MetaData __init__' don't have conflicting args - if so, then being a cowboy and passing in kwargs will not work. This will need testing obv...we might actually have to expand kwargs out rather than passing it in. """ self._engine = create_engine(self._uri, **kwargs) self._meta = MetaData(bind=self._engine, **kwargs) if kwargs.get("load", False): self._meta.reflect(**kwargs) @property def engine(self): return self._engine @property def meta(self): return self._meta @property def tables(self): return self._tables ########################################################################### # Instance functionality # # The following methods provide an interface/proxy to the current Session ########################################################################### def unbind(self): pass #TODO unbind sqlalchemy session def destroy(self): self.unbind() # TODO Any additional cleanup on the table? Drop the table from the session? def defaults(self): # TODO pass def to_string(self): return self._uri def clear(self): self._meta.clear() ########################################################################### # CRUD API ########################################################################### def get(self, name): """ Loads a Table from the Database. If the tables have already been loaded (either in Meta or SQL), then the cached object is returned; otherwise get creates a new Table Object. :param name: :param method: :return: """ if name in self.tables: return self.tables[name] _table = None try: _table = self.meta.tables[name] except KeyError: pass table = Table(self.engine, self.meta) self._tables[name] = _table return table @coroutine def create(self, model, **kwargs): pass @coroutine def update(self, model, **kwargs): # Updates a new row with the specified content if not model: raise IllegalArgumentException("'model' is required") _sync_stratey = kwargs.pop("synchronize_session", "evaluate") _update_args = kwargs.pop("update_args", None) _ret = self.session.query(self) name = model.name if name: _ret = _ret.get(name) _ret.filter_by(kwargs).update(model.export(), synchronize_session=_sync_stratey, update_args=_update_args) @coroutine def replace(self, model, **kwargs): # Replace is semantically no different than update in SQLAlchemy self.update(model, **kwargs) @coroutine def delete(self, model, **kwargs): # Deletes rows matched by a query # TODO do we need to consider session.expunge? _sync_stratey = kwargs.pop("synchronize_session", "evaluate") _ret = self.session.query(self) name = model.name if name: _ret = _ret.get(name) _ret.filter_by(kwargs).delete(synchronize_session=_sync_stratey) ########################################################################### # Transactional API ########################################################################### def close(self): if self._session: self._session.close() self._session = None def commit(self): if not self._session: raise IllegalStateException("No Session to commit. You must begin a Session prior to committing") self._session.commit() def flush(self): if not self._session: raise IllegalStateException("No Session to commit. You must begin a Session prior to flushing") self._session.flush() def cancel(self): if not self._session: raise IllegalStateException("No Session to commit. You must begin a Session prior to cancelling") self._session.cancel() def rollback(self): if not self._session: raise IllegalStateException("No Session to rollback. You must begin a Session prior to rolling back one") self._session.rollback() if self._session: self._session.close() self._session = None def invalidate(self): # Useful for calls in except statements if self._session: self._session.invalidate() def begin(self): self._session = self._session_factory() if not self._session else self._session return self._session def tag(self): if not self._session: raise IllegalStateException( "No Session to tag. You must begin a Session prior to tagging (creating a save point)") return self._session.begin_nested() def commit(self): if not self._session: raise IllegalStateException("No Session to commit. You must begin a Session prior to committing") self._session.commit() def flush(self): if not self._session: raise IllegalStateException("No Session to commit. You must begin a Session prior to flushing") self._session.flush() def cancel(self): if not self._session: raise IllegalStateException("No Session to commit. You must begin a Session prior to cancelling") self._session.cancel() def rollback(self): if not self._session: raise IllegalStateException("No Session to rollback. You must begin a Session prior to rolling back one") self._session.rollback()