60 'CWConstraint', 'CWConstraintType', 'CWUniqueTogetherConstraint', |
60 'CWConstraint', 'CWConstraintType', 'CWUniqueTogetherConstraint', |
61 'RQLExpression', |
61 'RQLExpression', |
62 'relation_type', 'from_entity', 'to_entity', |
62 'relation_type', 'from_entity', 'to_entity', |
63 'constrained_by', 'cstrtype', |
63 'constrained_by', 'cstrtype', |
64 'constraint_of', 'relations', |
64 'constraint_of', 'relations', |
|
65 'read_permission', 'add_permission', |
|
66 'delete_permission', 'update_permission', |
65 )) |
67 )) |
66 |
68 |
67 WORKFLOW_TYPES = set(('Transition', 'State', 'TrInfo', 'Workflow', |
69 WORKFLOW_TYPES = set(('Transition', 'State', 'TrInfo', 'Workflow', |
68 'WorkflowTransition', 'BaseTransition', |
70 'WorkflowTransition', 'BaseTransition', |
69 'SubWorkflowExitPoint')) |
71 'SubWorkflowExitPoint')) |
611 # Possible constraints ######################################################## |
613 # Possible constraints ######################################################## |
612 |
614 |
613 class BaseRQLConstraint(BaseConstraint): |
615 class BaseRQLConstraint(BaseConstraint): |
614 """base class for rql constraints |
616 """base class for rql constraints |
615 """ |
617 """ |
|
618 distinct_query = None |
616 |
619 |
617 def __init__(self, restriction, mainvars=None): |
620 def __init__(self, restriction, mainvars=None): |
618 self.restriction = normalize_expression(restriction) |
621 self.restriction = normalize_expression(restriction) |
619 if mainvars is None: |
622 if mainvars is None: |
620 mainvars = guess_rrqlexpr_mainvars(restriction) |
623 mainvars = guess_rrqlexpr_mainvars(restriction) |
650 """raise ValidationError if the relation doesn't satisfy the constraint |
653 """raise ValidationError if the relation doesn't satisfy the constraint |
651 """ |
654 """ |
652 pass # this is a vocabulary constraint, not enforce XXX why? |
655 pass # this is a vocabulary constraint, not enforce XXX why? |
653 |
656 |
654 def __str__(self): |
657 def __str__(self): |
655 return '%s(Any %s WHERE %s)' % (self.__class__.__name__, self.mainvars, |
658 if self.distinct_query: |
656 self.restriction) |
659 selop = 'Any' |
|
660 else: |
|
661 selop = 'DISTINCT Any' |
|
662 return '%s(%s %s WHERE %s)' % (self.__class__.__name__, selop, |
|
663 self.mainvars, self.restriction) |
657 |
664 |
658 def __repr__(self): |
665 def __repr__(self): |
659 return '<%s @%#x>' % (self.__str__(), id(self)) |
666 return '<%s @%#x>' % (self.__str__(), id(self)) |
660 |
667 |
661 |
668 |
743 return self.exec_query(session, eidfrom, eidto) |
750 return self.exec_query(session, eidfrom, eidto) |
744 |
751 |
745 |
752 |
746 class RQLUniqueConstraint(RepoEnforcedRQLConstraintMixIn, BaseRQLConstraint): |
753 class RQLUniqueConstraint(RepoEnforcedRQLConstraintMixIn, BaseRQLConstraint): |
747 """the unique rql constraint check that the result of the query isn't |
754 """the unique rql constraint check that the result of the query isn't |
748 greater than one |
755 greater than one. |
749 """ |
756 |
|
757 You *must* specify mainvars when instantiating the constraint since there is |
|
758 no way to guess it correctly (e.g. if using S,O or U the constraint will |
|
759 always be satisfied because we've to use a DISTINCT query). |
|
760 """ |
|
761 # XXX turns mainvars into a required argument in __init__ |
750 distinct_query = True |
762 distinct_query = True |
751 |
|
752 # XXX turns mainvars into a required argument in __init__, since we've no |
|
753 # way to guess it correctly (eg if using S,O or U the constraint will |
|
754 # always be satisfied since we've to use a DISTINCT query) |
|
755 |
763 |
756 def match_condition(self, session, eidfrom, eidto): |
764 def match_condition(self, session, eidfrom, eidto): |
757 return len(self.exec_query(session, eidfrom, eidto)) <= 1 |
765 return len(self.exec_query(session, eidfrom, eidto)) <= 1 |
758 |
766 |
759 |
767 |