# Path: m2core/db/sqlalchemy_mixins/session_mixin.py
# class SessionMixin:
#     __abstract__ = True
# 
#     @classmethod
#     def set_db_session(cls, session) -> scoped_session or Session:
#         """
#         Sets DB Session during M2Core initialization with this method
#         """
#         cls._db_session = session
# 
#     @classproperty
#     def s(cls) -> scoped_session or Session:
#         """
#         Returns DB Session
#         """
#         if cls._db_session:
#             return cls._db_session
#         else:
#             raise M2Error('No DB session defined')
# 
#     @classmethod
#     def set_redis_session(cls, session) -> scoped_session or Session:
#         """
#         Sets Redis Session during M2Core initialization with this method
#         """
#         cls._redis_session = session
# 
#     @classproperty
#     def r(cls) -> StrictRedis:
#         """
#         Returns Redis Session
#         """
#         if cls._redis_session:
#             return cls._redis_session
#         else:
#             raise M2Error('No Redis session defined')
# 
#     @classproperty
#     def sh(cls):
#         """
#         Returns instance of Session Helper
#         :return: 
#         """
#         if not cls.r:
#             raise M2Error('No Redis session defined')
#         return cls._sh_cls(cls.r['connector'], cls.r['scheme'])
# 
#     @classmethod
#     def set_sh(cls, sh_cls):
#         """
#         Sets DB Session during M2Core initialization with this method
#         """
#         cls._sh_cls = sh_cls
# 
#     @classproperty
#     def q(cls) -> Query:
#         """
#         Returns prepared Query taken from DB Session
#         """
#         if not cls.s:
#             raise M2Error('No DB session defined')
#         return cls.s.query(cls)
# 
# Path: m2core/utils/error.py
# class M2Error(Exception):
#     """
#     Raise this error wherever you want you exception to be raised, logged and showed up to user with custom message
#     """
#     def __init__(self, msg: str='', show_to_user: bool=False):
#         self.error_message = msg
#         self.show_to_user = show_to_user
#         self._log()
# 
#     def _log(self):
#         logger.error(self.error_message)
# 
#     def __repr__(self):
#         return self.error_message
# 
# Path: m2core/utils/decorators.py
# class classproperty(property):
#     def __get__(self, obj, objtype=None):
#         return super(classproperty, self).__get__(objtype)
# 
#     def __set__(self, obj, value):
#         super(classproperty, self).__set__(type(obj), value)
# 
#     def __delete__(self, obj):
#         super(classproperty, self).__delete__(type(obj))


from .session_mixin import SessionMixin
from sqlalchemy import func, text
from sqlalchemy.inspection import inspect
from sqlalchemy.orm import RelationshipProperty, class_mapper
from sqlalchemy.ext.hybrid import hybrid_property, hybrid_method
from sqlalchemy.exc import SQLAlchemyError
from sqlalchemy.engine import reflection
from m2core.utils.error import M2Error
from m2core.utils.decorators import classproperty
import operator
import copy
            mapper.get_property_by_column(column)
            for column in mapper.primary_key
        ]

    @classproperty
    def primary_keys(cls):
        return [pk.key for pk in cls.primary_keys_full]

    @classproperty
    def relations(cls):
        """
        Return a `list` of relationship names or the given model
        """
        return [c.key for c in cls.__mapper__.iterate_properties
                if isinstance(c, RelationshipProperty)]

    @classproperty
    def settable_relations(cls):
        """
        Return a `list` of relationship names or the given model
        """
        return [r for r in cls.relations
                if getattr(cls, r).property.viewonly is False]

    @classproperty
    def hybrid_properties(cls):
        items = inspect(cls).all_orm_descriptors
        return [item.__name__ for item in items
                if type(item) == hybrid_property]


# Path: m2core/db/sqlalchemy_mixins/session_mixin.py
# class SessionMixin:
#     __abstract__ = True
# 
#     @classmethod
#     def set_db_session(cls, session) -> scoped_session or Session:
#         """
#         Sets DB Session during M2Core initialization with this method
#         """
#         cls._db_session = session
# 
#     @classproperty
#     def s(cls) -> scoped_session or Session:
#         """
#         Returns DB Session
#         """
#         if cls._db_session:
#             return cls._db_session
#         else:
#             raise M2Error('No DB session defined')
# 
#     @classmethod
#     def set_redis_session(cls, session) -> scoped_session or Session:
#         """
#         Sets Redis Session during M2Core initialization with this method
#         """
#         cls._redis_session = session
# 
#     @classproperty
#     def r(cls) -> StrictRedis:
#         """
#         Returns Redis Session
#         """
#         if cls._redis_session:
#             return cls._redis_session
#         else:
#             raise M2Error('No Redis session defined')
# 
#     @classproperty
#     def sh(cls):
#         """
#         Returns instance of Session Helper
#         :return: 
#         """
#         if not cls.r:
#             raise M2Error('No Redis session defined')
#         return cls._sh_cls(cls.r['connector'], cls.r['scheme'])
# 
#     @classmethod
#     def set_sh(cls, sh_cls):
#         """
#         Sets DB Session during M2Core initialization with this method
#         """
#         cls._sh_cls = sh_cls
# 
#     @classproperty
#     def q(cls) -> Query:
#         """
#         Returns prepared Query taken from DB Session
#         """
#         if not cls.s:
#             raise M2Error('No DB session defined')
#         return cls.s.query(cls)
# 
# Path: m2core/utils/error.py
# class M2Error(Exception):
#     """
#     Raise this error wherever you want you exception to be raised, logged and showed up to user with custom message
#     """
#     def __init__(self, msg: str='', show_to_user: bool=False):
#         self.error_message = msg
#         self.show_to_user = show_to_user
#         self._log()
# 
#     def _log(self):
#         logger.error(self.error_message)
# 
#     def __repr__(self):
#         return self.error_message
# 
# Path: m2core/utils/decorators.py
# class classproperty(property):
#     def __get__(self, obj, objtype=None):
#         return super(classproperty, self).__get__(objtype)
# 
#     def __set__(self, obj, value):
#         super(classproperty, self).__set__(type(obj), value)
# 
#     def __delete__(self, obj):
#         super(classproperty, self).__delete__(type(obj))


# Path: m2core/db/sqlalchemy_mixins/data_mixin.py
from .session_mixin import SessionMixin
from sqlalchemy import func, text
from sqlalchemy.inspection import inspect
from sqlalchemy.orm import RelationshipProperty, class_mapper
from sqlalchemy.ext.hybrid import hybrid_property, hybrid_method
from sqlalchemy.exc import SQLAlchemyError
from sqlalchemy.engine import reflection
from m2core.utils.error import M2Error
from m2core.utils.decorators import classproperty
import operator
import copy

            mapper.get_property_by_column(column)
            for column in mapper.primary_key
        ]

    @classproperty
    def primary_keys(cls):
        return [pk.key for pk in cls.primary_keys_full]

    @classproperty
    def relations(cls):
        """
        Return a `list` of relationship names or the given model
        """
        return [c.key for c in cls.__mapper__.iterate_properties
                if isinstance(c, RelationshipProperty)]

    @classproperty
    def settable_relations(cls):
        """
        Return a `list` of relationship names or the given model
        """
        return [r for r in cls.relations
                if getattr(cls, r).property.viewonly is False]

    @classproperty
    def hybrid_properties(cls):
        items = inspect(cls).all_orm_descriptors
        return [item.__name__ for item in items
                if type(item) == hybrid_property]


    @classproperty