Source code for sqlalchemy_unchained.session_manager

from contextlib import contextmanager
from py_meta_utils import Singleton
from sqlalchemy.orm import Session
from typing import *

from .base_model import BaseModel
from .base_query import BaseQuery


class _SessionDescriptor:
    def __get__(self, instance, cls):
        return cls._session_factory()


class _QueryDescriptor:
    def __get__(self, instance, cls):
        return cls.session.query


class SessionManagerMetaclass(Singleton):
    def __call__(cls, *args, **kwargs):
        cls = super().__call__(*args, **kwargs)
        if cls._session_factory is None:
            raise Exception('SessionManager was not properly initialized. '
                            'Please set the session factory via '
                            '`SessionManager.set_session_factory')
        return cls


[docs]class SessionManager(metaclass=SessionManagerMetaclass): """ The session manager for SQLAlchemy Unchained. """ _session_factory = None session: Session = _SessionDescriptor() query: BaseQuery = _QueryDescriptor()
[docs] @classmethod def set_session_factory(cls, session_factory): """ Classmethod to set the session factory :class:`~sqlalchemy_unchained.SessionManager` should use. :param session_factory: The session factory callable. """ cls._session_factory = session_factory
[docs] def save(self, instance: BaseModel, commit: bool = False) -> BaseModel: """ Add a model instance to the session, optionally committing the current transaction immediately. :param instance: The model instance to save. :param commit: Whether or not to immediately commit. **WARNING:** This will commit the *entire* session, including any other model instances that may have been added to the session but not yet committed. :return: The model instance. """ instance.validate(partial=False) self.session.add(instance) if commit: self.commit() return instance
[docs] def save_all(self, instances: List[BaseModel], commit: bool = False, ) -> List[BaseModel]: """ Adds a list of model instances to the session, optionally committing the current transaction immediately. :param instances: The list of model instance to save. :param commit: Whether or not to immediately commit. **WARNING:** This will commit the *entire* session, including any other model instances that may have been added to the session but not yet committed. :return: The list of model instances. """ self.session.add_all(instances) if commit: self.commit() return instances
def delete(self, instance: BaseModel, commit: bool = False) -> None: self.session.delete(instance) if commit: self.commit() def delete_all(self, instances: List[BaseModel], commit: bool = False) -> None: for instance in instances: self.session.delete(instance) if commit: self.commit()
[docs] def commit(self) -> None: """ Commits the current transaction. """ self.session.commit()
@property @contextmanager def no_autoflush(self): """ Return a context manager that disables autoflush. e.g.:: with session.no_autoflush: some_object = SomeClass() session.add(some_object) # won't autoflush some_object.related_thing = session.query(SomeRelated).first() Operations that proceed within the ``with:`` block will not be subject to flushes occurring upon query access. This is useful when initializing a series of objects which involve existing database queries, where the uncompleted object should not yet be flushed. """ autoflush = self.session.autoflush self.session.autoflush = False try: yield self finally: self.session.autoflush = autoflush
__all__ = [ 'SessionManager', 'SessionManagerMetaclass', ]