def convert_sdb( env: Environment, sess: Session, sdb: StoredDataBlockMetadata, conversion_path: ConversionPath, target_storage: Storage, storages: Optional[List[Storage]] = None, ) -> StoredDataBlockMetadata: if not conversion_path.conversions: return sdb if storages is None: storages = env.storages prev_sdb = sdb next_sdb: Optional[StoredDataBlockMetadata] = None prev_storage = sdb.storage next_storage: Optional[Storage] = None realized_schema = sdb.realized_schema(env, sess) for conversion_edge in conversion_path.conversions: conversion = conversion_edge.conversion target_storage_format = conversion.to_storage_format next_storage = select_storage(target_storage, storages, target_storage_format) logger.debug( f"CONVERSION: {conversion.from_storage_format} -> {conversion.to_storage_format}" ) next_sdb = StoredDataBlockMetadata( # type: ignore id=get_datablock_id(), data_block_id=prev_sdb.data_block_id, data_block=prev_sdb.data_block, data_format=target_storage_format.data_format, storage_url=next_storage.url, ) sess.add(next_sdb) conversion_edge.copier.copy( from_name=prev_sdb.get_name(), to_name=next_sdb.get_name(), conversion=conversion, from_storage_api=prev_storage.get_api(), to_storage_api=next_storage.get_api(), schema=realized_schema, ) if (prev_sdb.data_format.is_python_format() and not prev_sdb.data_format.is_storable()): # If the records obj is in python and not storable, and we just used it, then it can be reused # TODO: Bit of a hack. Is there a central place we can do this? # also is reusable a better name than storable? prev_storage.get_api().remove(prev_sdb.get_name()) prev_sdb.data_block.stored_data_blocks.remove(prev_sdb) if prev_sdb in sess.new: sess.expunge(prev_sdb) else: sess.delete(prev_sdb) prev_sdb = next_sdb prev_storage = next_storage return next_sdb
def test_meta(session: Session) -> None: e = DummyContact(name="test") e.meta["key"] = "value" e.meta["number"] = 42 session.add(e) session.flush() e_id = e.id session.expunge(e) del e e = session.query(DummyContact).get(e_id) assert e.meta["key"] == "value" assert e.meta["number"] == 42
def start(self, session: Session) -> None: """Start a new run. Must run in the recorder thread. """ self._current_run_info = RecorderRuns( start=self.recording_start, created=dt_util.utcnow() ) session.add(self._current_run_info) session.flush() session.expunge(self._current_run_info) self.load_from_db(session)
def load_from_db(self, session: Session) -> None: """Update the run cache. Must run in the recorder thread. """ run_timestamps: list[int] = [] runs_by_timestamp: dict[int, RecorderRuns] = {} for run in session.query(RecorderRuns).order_by(RecorderRuns.start.asc()).all(): session.expunge(run) if run_dt := process_timestamp(run.start): timestamp = run_dt.timestamp() run_timestamps.append(timestamp) runs_by_timestamp[timestamp] = run
def run_information_with_session( session: Session, point_in_time: datetime | None = None) -> RecorderRuns | None: """Return information about current run from the database.""" recorder_runs = RecorderRuns query = session.query(recorder_runs) if point_in_time: query = query.filter((recorder_runs.start < point_in_time) & (recorder_runs.end > point_in_time)) if (res := query.first()) is not None: session.expunge(res) return cast(RecorderRuns, res)
def get_existing(self, session: Session) -> Optional["Album"]: """Gets a matching Album in the library either by its path or unique tags.""" existing_album = (session.query(Album).filter( or_( and_( Album.artist == self.artist, Album.title == self.title, Album.date == self.date, ), Album.path == self.path, )).options(joinedload("*")).one_or_none()) if not existing_album: return None session.expunge(existing_album) return existing_album
class InboxSession(object): """ Inbox custom ORM (with SQLAlchemy compatible API). Parameters ---------- engine : <sqlalchemy.engine.Engine> A configured database engine to use for this session versioned : bool Do you want to enable the transaction log? ignore_soft_deletes : bool Whether or not to ignore soft-deleted objects in query results. namespace_id : int Namespace to limit query results with. """ def __init__(self, engine, versioned=True, ignore_soft_deletes=True, namespace_id=None): # TODO: support limiting on namespaces assert engine, "Must set the database engine" args = dict(bind=engine, autoflush=True, autocommit=False) self.ignore_soft_deletes = ignore_soft_deletes if ignore_soft_deletes: args['query_cls'] = InboxQuery self._session = Session(**args) if versioned: from inbox.models.transaction import create_revisions @event.listens_for(self._session, 'after_flush') def after_flush(session, flush_context): """ Hook to log revision snapshots. Must be post-flush in order to grab object IDs on new objects. """ create_revisions(session) def query(self, *args, **kwargs): q = self._session.query(*args, **kwargs) if self.ignore_soft_deletes: return q.options(IgnoreSoftDeletesOption()) else: return q def add(self, instance): if not self.ignore_soft_deletes or not instance.is_deleted: self._session.add(instance) else: raise Exception("Why are you adding a deleted object?") def add_all(self, instances): if True not in [i.is_deleted for i in instances] or \ not self.ignore_soft_deletes: self._session.add_all(instances) else: raise Exception("Why are you adding a deleted object?") def delete(self, instance): if self.ignore_soft_deletes: instance.mark_deleted() # just to make sure self._session.add(instance) else: self._session.delete(instance) def begin(self): self._session.begin() def commit(self): self._session.commit() def rollback(self): self._session.rollback() def flush(self): self._session.flush() def close(self): self._session.close() def expunge(self, obj): self._session.expunge(obj) def merge(self, obj): return self._session.merge(obj) @property def no_autoflush(self): return self._session.no_autoflush
# inspect the current state of an object state = inspect(user) assert state.persistent ################################################################################ # expunge # Expunging removes an object from the session. # Pending instances are sent to the transient state. # Persistent instances from flush() are sent to detached state. Qualify # their attributes are valid. # Persistent instances from query are sent to detached state and expired. # By default, qualify their attribute will cause DetachedInstanceError, for no # no session can be used to reload these instances from database again. # All the scenes will not change the instances' attributes. ################################################################################ session.expunge(user) ################################################################################ # rollback # rollback DOES NOT remove all the instances from the session. # For pending instances and persistent instances that result by flush(), # they are expunged and set to transient state. Their attributes will not be # changed. # For persistent instances result by query(), they are still persistent # but expired, which means that qualify their attributes will reload them by # emitting a query. # All objects not expunged are fully expired. ################################################################################ session.rollback()
# inspect the current state of an object state = inspect(user) assert state.persistent ################################################################################ # expunge # Expunging removes an object from the session. # Pending instances are sent to the transient state. # Persistent instances from flush() are sent to detached state. Qualify # their attributes are valid. # Persistent instances from query are sent to detached state and expired. # By default, qualify their attribute will cause DetachedInstanceError, for no # no session can be used to reload these instances from database again. # All the scenes will not change the instances' attributes. ################################################################################ session.expunge(user) ################################################################################ # rollback # rollback DOES NOT remove all the instances from the session. # For pending instances and persistent instances that result by flush(), # they are expunged and set to transient state. Their attributes will not be # changed. # For persistent instances result by query(), they are still persistent # but expired, which means that qualify their attributes will reload them by # emitting a query. # All objects not expunged are fully expired. ################################################################################ session.rollback() ################################################################################