entities/schemaobjs.py
author sylvain.thenault@logilab.fr
Wed, 08 Apr 2009 14:11:34 +0200
branchtls-sprint
changeset 1300 62d2b890a980
parent 1154 9b23a6836c32
child 1398 5fe84a5f7035
permissions -rw-r--r--
move tests where they belong

"""schema definition related entities

:organization: Logilab
:copyright: 2001-2009 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
:contact: http://www.logilab.fr/ -- mailto:contact@logilab.fr
"""
__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 EEType(AnyEntity):
    id = 'EEType'
    fetch_attrs, fetch_order = fetch_config(['name'])

    def dc_title(self):
        return self.req._(self.name)
    
    def dc_long_title(self):
        stereotypes = []
        _ = self.req._
        if self.meta:
            stereotypes.append(_('meta'))
        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 ERType(AnyEntity):
    id = 'ERType'
    fetch_attrs, fetch_order = fetch_config(['name'])
    
    def dc_title(self):
        return self.req._(self.name)
    
    def dc_long_title(self):
        stereotypes = []
        _ = self.req._
        if self.meta:
            stereotypes.append(_('meta'))
        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
        """
        rtype = self.name
        rschema = self.schema.rschema(rtype)
        if inlined == rschema.inlined:
            return False
        if inlined:
            for (stype, otype) in rschema.iter_rdefs():
                card = rschema.rproperty(stype, otype, 'cardinality')[0]
                if not card in '?1':
                    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 ENFRDef(AnyEntity):
    id = 'ENFRDef'
    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(ENFRDef, self).after_deletion_path()


class EFRDef(ENFRDef):
    id = 'EFRDef'
    
    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 EConstraint(AnyEntity):
    id = 'EConstraint'
    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(EConstraint, 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 EPermission(AnyEntity):
    id = 'EPermission'
    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(EPermission, self).after_deletion_path()