Source code for ciowarehouse.models.dbhandler

"""SQLAlchemy-powered model definitions for file handlers."""

from sqlalchemy import Column, ForeignKey, String, Integer
from sqlalchemy.orm import relationship
from lxml import etree

from chrysalio.lib.utils import make_id
from chrysalio.models import ID_LEN, DBDeclarativeClass
from chrysalio.models.dbbase import DBBaseClass
from ..relaxng import RELAXNG_CIOWAREHOUSE
from ..lib.i18n import _
from ..models.dbindexfield import INDEXFIELD_DEFAULTS


# =============================================================================
[docs]class DBHandler(DBDeclarativeClass, DBBaseClass): """SQLAlchemy-powered file handler class.""" suffix = 'ciohdl' __tablename__ = 'wrh_handlers' __table_args__ = {'mysql_engine': 'InnoDB'} handler_id = Column(String(ID_LEN), primary_key=True) indexers = relationship('DBHandlerIndexer', cascade='all, delete') # -------------------------------------------------------------------------
[docs] @classmethod def xml2db(cls, dbsession, handler_elt, error_if_exists=True, kwargs=None): """Load a file handler from a XML element. :type dbsession: sqlalchemy.orm.session.Session :param dbsession: SQLAlchemy session. :type handler_elt: lxml.etree.Element :param handler_elt: File handler XML element. :param bool error_if_exists: (default=True) It returns an error if file handler already exists. :param dict kwargs: (optional) Dictionary of keyword arguments. :rtype: :class:`pyramid.i18n.TranslationString` or ``None`` :return: Error message or ``None``. """ # Check if already exists handler_id = make_id(handler_elt.get('id'), 'token', ID_LEN) dbhandler = dbsession.query(cls).filter_by( handler_id=handler_id).first() if dbhandler is not None: if error_if_exists: return _( 'File handler "${h}" already exists.', {'h': handler_id}) return None # Create handler record = cls.record_from_xml(handler_id) error = cls.record_format(record) if error: return error dbhandler = cls(**record) dbsession.add(dbhandler) # Add indexers dbsession.flush() namespace = RELAXNG_CIOWAREHOUSE['namespace'] if kwargs is None: kwargs = {} refs = kwargs.get('indexrefs') or INDEXFIELD_DEFAULTS done = set() for elt in handler_elt.xpath( 'ns0:indexer', namespaces={'ns0': namespace}): ref = elt.get('indexref') if ref not in done and ref in refs: done.add(ref) dbsession.add(DBHandlerIndexer( handler_id=handler_id, indexfield_id=ref, argument=elt.text.strip() if elt.text else None, limit=int(elt.get('limit', '0')) or None)) return None
# -------------------------------------------------------------------------
[docs] @classmethod def record_from_xml(cls, handler_id): """Convert a handler XML element into a dictionary. :param str handler_id: Handler ID. :rtype: dict """ return {'handler_id': handler_id}
# -------------------------------------------------------------------------
[docs] @classmethod def record_format(cls, record): """Check and possibly correct a record before inserting it in the database. :param dict record: Dictionary of values to check. :rtype: ``None`` or :class:`pyramid.i18n.TranslationString` :return: ``None`` or error message. """ for k in [i for i in record if record[i] is None]: del record[k] # File handler ID if not record.get('handler_id'): return _('File handler without ID.') record['handler_id'] = make_id( record['handler_id'], 'token', ID_LEN) return None
# -------------------------------------------------------------------------
[docs] def db2xml(self, dbsession=None): """Serialize a file handler to a XML representation. :type dbsession: sqlalchemy.orm.session.Session :param dbsession: (optional) SQLAlchemy session. :rtype: lxml.etree.Element """ # pylint: disable = unused-argument handler_elt = etree.Element('handler') handler_elt.set('id', self.handler_id) for dbindexer in self.indexers: elt = etree.SubElement( handler_elt, 'indexer', indexref=dbindexer.indexfield_id) if dbindexer.limit: elt.set('limit', str(dbindexer.limit)) if dbindexer.argument: elt.text = dbindexer.argument return handler_elt
# =============================================================================
[docs]class DBHandlerIndexer(DBDeclarativeClass): """Class to link handlers with their indexers (one-to-many).""" # pylint: disable = too-few-public-methods __tablename__ = 'wrh_handlers_indexers' __table_args__ = {'mysql_engine': 'InnoDB'} handler_id = Column( String(ID_LEN), ForeignKey('wrh_handlers.handler_id', ondelete='CASCADE'), primary_key=True) indexfield_id = Column(String(ID_LEN), primary_key=True) argument = Column(String(255)) limit = Column(Integer())