entities/schemaobjs.py
author Sylvain Thénault <sylvain.thenault@logilab.fr>
Tue, 22 Dec 2009 21:02:37 +0100
branchstable
changeset 4195 86dcaf6bb92f
parent 3353 1003a6f3d298
child 3377 dd9d292b6a6d
child 4212 ab6573088b4a
permissions -rw-r--r--
closes #601987 1) sqlutils.restore_from_file have to use its confirm argument when a command fail, to propose to continue there (this can't be handled by the caller) 2) source.restore method hence needs to take this confirmation callback as argument 3) properly fix places where 'drop' was given instead of 'confirm'

"""schema definition related entities

:organization: Logilab
:copyright: 2001-2009 LOGILAB S.A. (Paris, FRANCE), license is LGPL v2.
:contact: http://www.logilab.fr/ -- mailto:contact@logilab.fr
:license: GNU Lesser General Public License, v2.1 - http://www.gnu.org/licenses
"""
__docformat__ = "restructuredtext en"

from logilab.common.decorators import cached

from cubicweb import ValidationError
from cubicweb.schema import ERQLExpression, RRQLExpression

from cubicweb.entities import AnyEntity, fetch_config


class CWEType(AnyEntity):
    id = 'CWEType'
    fetch_attrs, fetch_order = fetch_config(['name'])

    def dc_title(self):
        return u'%s (%s)' % (self.name, self.req._(self.name))

    def dc_long_title(self):
        stereotypes = []
        _ = self.req._
        if self.final:
            stereotypes.append(_('final'))
        if stereotypes:
            return u'%s <<%s>>' % (self.dc_title(), ', '.join(stereotypes))
        return self.dc_title()

    def db_key_name(self):
        """XXX goa specific"""
        return self.get('name')


class CWRType(AnyEntity):
    id = 'CWRType'
    fetch_attrs, fetch_order = fetch_config(['name'])

    def dc_title(self):
        return u'%s (%s)' % (self.name, self.req._(self.name))

    def dc_long_title(self):
        stereotypes = []
        _ = self.req._
        if self.symetric:
            stereotypes.append(_('symetric'))
        if self.inlined:
            stereotypes.append(_('inlined'))
        if self.final:
            stereotypes.append(_('final'))
        if stereotypes:
            return u'%s <<%s>>' % (self.dc_title(), ', '.join(stereotypes))
        return self.dc_title()

    def inlined_changed(self, inlined):
        """check inlining is necessary and possible:

        * return False if nothing has changed
        * raise ValidationError if inlining is'nt possible
        * eventually return True
        """
        rschema = self.schema.rschema(self.name)
        if inlined == rschema.inlined:
            return False
        if inlined:
            # don't use the persistent schema, we may miss cardinality changes
            # in the same transaction
            for rdef in self.reverse_relation_type:
                card = rdef.cardinality[0]
                if not card in '?1':
                    rtype = self.name
                    stype = rdef.stype
                    otype = rdef.otype
                    msg = self.req._("can't set inlined=%(inlined)s, "
                                     "%(stype)s %(rtype)s %(otype)s "
                                     "has cardinality=%(card)s")
                    raise ValidationError(self.eid, {'inlined': msg % locals()})
        return True

    def db_key_name(self):
        """XXX goa specific"""
        return self.get('name')


class CWRelation(AnyEntity):
    id = 'CWRelation'
    fetch_attrs = fetch_config(['cardinality'])[0]

    def dc_title(self):
        return u'%s %s %s' % (
            self.from_entity[0].name,
            self.relation_type[0].name,
            self.to_entity[0].name)

    def dc_long_title(self):
        card = self.cardinality
        scard, ocard = u'', u''
        if card[0] != '1':
            scard = '[%s]' % card[0]
        if card[1] != '1':
            ocard = '[%s]' % card[1]
        return u'%s %s%s%s %s' % (
            self.from_entity[0].name,
            scard, self.relation_type[0].name, ocard,
            self.to_entity[0].name)

    def after_deletion_path(self):
        """return (path, parameters) which should be used as redirect
        information when this entity is being deleted
        """
        if self.relation_type:
            return self.relation_type[0].rest_path(), {}
        return super(CWRelation, self).after_deletion_path()

    @property
    def rtype(self):
        return self.relation_type[0]

    @property
    def stype(self):
        return self.from_entity[0]

    @property
    def otype(self):
        return self.to_entity[0]


class CWAttribute(CWRelation):
    id = 'CWAttribute'

    def dc_long_title(self):
        card = self.cardinality
        scard = u''
        if card[0] == '1':
            scard = '+'
        return u'%s %s%s %s' % (
            self.from_entity[0].name,
            scard, self.relation_type[0].name,
            self.to_entity[0].name)


class CWConstraint(AnyEntity):
    id = 'CWConstraint'
    fetch_attrs, fetch_order = fetch_config(['value'])

    def dc_title(self):
        return '%s(%s)' % (self.cstrtype[0].name, self.value or u'')

    def after_deletion_path(self):
        """return (path, parameters) which should be used as redirect
        information when this entity is being deleted
        """
        if self.reverse_constrained_by:
            return self.reverse_constrained_by[0].rest_path(), {}
        return super(CWConstraint, self).after_deletion_path()

    @property
    def type(self):
        return self.cstrtype[0].name


class RQLExpression(AnyEntity):
    id = 'RQLExpression'
    fetch_attrs, fetch_order = fetch_config(['exprtype', 'mainvars', 'expression'])

    def dc_title(self):
        return '%s(%s)' % (self.exprtype, self.expression or u'')

    @property
    def expression_of(self):
        for rel in ('read_permission', 'add_permission', 'delete_permission',
                    'update_permission', 'condition'):
            values = getattr(self, 'reverse_%s' % rel)
            if values:
                return values[0]

    @cached
    def _rqlexpr(self):
        if self.exprtype == 'ERQLExpression':
            return ERQLExpression(self.expression, self.mainvars, self.eid)
        #if self.exprtype == 'RRQLExpression':
        return RRQLExpression(self.expression, self.mainvars, self.eid)

    def check_expression(self, *args, **kwargs):
        return self._rqlexpr().check(*args, **kwargs)

    def after_deletion_path(self):
        """return (path, parameters) which should be used as redirect
        information when this entity is being deleted
        """
        if self.expression_of:
            return self.expression_of.rest_path(), {}
        return super(RQLExpression, self).after_deletion_path()


class CWPermission(AnyEntity):
    id = 'CWPermission'
    fetch_attrs, fetch_order = fetch_config(['name', 'label'])

    def dc_title(self):
        if self.label:
            return '%s (%s)' % (self.req._(self.name), self.label)
        return self.req._(self.name)

    def after_deletion_path(self):
        """return (path, parameters) which should be used as redirect
        information when this entity is being deleted
        """
        permissionof = getattr(self, 'reverse_require_permission', ())
        if len(permissionof) == 1:
            return permissionof[0].rest_path(), {}
        return super(CWPermission, self).after_deletion_path()