[migractions] Better handle removal of RQLConstraint in sync_schema
In rdef synchronisation, filter unmodified constraints before processing the
sets of old and new constraints.
Add a new `constraint_by_eid` method on RelationDefinitionSchema, which
eliminates the ambiguity of `constraint_by_type` usage when several
constraints of the same type are involved in the same migration.
Closes #3633644.
--- a/hooks/syncschema.py Mon Mar 10 16:07:41 2014 +0100
+++ b/hooks/syncschema.py Mon Mar 10 15:17:50 2014 +0100
@@ -1168,12 +1168,11 @@
if self._cw.deleted_in_transaction(self.eidfrom):
return
schema = self._cw.vreg.schema
- entity = self._cw.entity_from_eid(self.eidto)
rdef = schema.schema_by_eid(self.eidfrom)
try:
- cstr = rdef.constraint_by_type(entity.type)
- except IndexError:
- self._cw.critical('constraint type no more accessible')
+ cstr = rdef.constraint_by_eid(self.eidto)
+ except ValueError:
+ self._cw.critical('constraint no more accessible')
else:
CWConstraintDelOp(self._cw, rdef=rdef, oldcstr=cstr)
--- a/schema.py Mon Mar 10 16:07:41 2014 +0100
+++ b/schema.py Mon Mar 10 15:17:50 2014 +0100
@@ -323,6 +323,13 @@
raise BadSchemaDefinition(msg % self)
RelationDefinitionSchema.check_permission_definitions = check_permission_definitions
+def constraint_by_eid(self, eid):
+ for cstr in self.constraints:
+ if cstr.eid == eid:
+ return cstr
+ raise ValueError('No constraint with eid %d' % eid)
+RelationDefinitionSchema.constraint_by_eid = constraint_by_eid
+
class CubicWebEntitySchema(EntitySchema):
"""a entity has a type, a set of subject and or object relations
--- a/server/migractions.py Mon Mar 10 16:07:41 2014 +0100
+++ b/server/migractions.py Mon Mar 10 15:17:50 2014 +0100
@@ -619,12 +619,18 @@
self.rqlexecall(ss.updaterdef2rql(rdef, repordef.eid),
ask_confirm=confirm)
# constraints
- newconstraints = list(rdef.constraints)
+ # 0. eliminate the set of unmodified constraints from the sets of
+ # old/new constraints
+ newconstraints = set(rdef.constraints)
+ oldconstraints = set(repordef.constraints)
+ unchanged_constraints = newconstraints & oldconstraints
+ newconstraints -= unchanged_constraints
+ oldconstraints -= unchanged_constraints
# 1. remove old constraints and update constraints of the same type
# NOTE: don't use rschema.constraint_by_type because it may be
# out of sync with newconstraints when multiple
# constraints of the same type are used
- for cstr in repordef.constraints:
+ for cstr in oldconstraints:
for newcstr in newconstraints:
if newcstr.type() == cstr.type():
break
--- a/server/test/data/migratedapp/schema.py Mon Mar 10 16:07:41 2014 +0100
+++ b/server/test/data/migratedapp/schema.py Mon Mar 10 15:17:50 2014 +0100
@@ -21,6 +21,7 @@
RichString, String, Int, Boolean, Datetime, Date)
from yams.constraints import SizeConstraint, UniqueConstraint
from cubicweb.schema import (WorkflowableEntityType, RQLConstraint,
+ RQLVocabularyConstraint,
ERQLExpression, RRQLExpression)
class Affaire(EntityType):
@@ -149,3 +150,6 @@
class evaluee(RelationDefinition):
subject = ('Personne', 'CWUser', 'Societe')
object = ('Note')
+ constraints = [
+ RQLVocabularyConstraint('S owned_by U'),
+ ]
--- a/server/test/data/schema.py Mon Mar 10 16:07:41 2014 +0100
+++ b/server/test/data/schema.py Mon Mar 10 15:17:50 2014 +0100
@@ -22,6 +22,7 @@
from yams.constraints import SizeConstraint
from cubicweb.schema import (WorkflowableEntityType,
RQLConstraint, RQLUniqueConstraint,
+ RQLVocabularyConstraint,
ERQLExpression, RRQLExpression)
class Affaire(WorkflowableEntityType):
@@ -151,6 +152,8 @@
}
subject = 'Personne'
object = 'Societe'
+ constraints = [RQLVocabularyConstraint('S owned_by U'),
+ RQLVocabularyConstraint('S created_by U')]
class comments(RelationDefinition):
subject = 'Comment'
@@ -189,6 +192,10 @@
class evaluee(RelationDefinition):
subject = ('Personne', 'CWUser', 'Societe')
object = ('Note')
+ constraints = [
+ RQLVocabularyConstraint('S created_by U'),
+ RQLVocabularyConstraint('S owned_by U'),
+ ]
class ecrit_par(RelationType):
inlined = True
--- a/server/test/unittest_migractions.py Mon Mar 10 16:07:41 2014 +0100
+++ b/server/test/unittest_migractions.py Mon Mar 10 15:17:50 2014 +0100
@@ -345,6 +345,26 @@
self.mh.cmd_change_relation_props('Personne', 'adel', 'String',
fulltextindexed=False)
+ def test_sync_schema_props_perms_rqlconstraints(self):
+ # Drop one of the RQLConstraint.
+ rdef = self.schema['evaluee'].rdefs[('Personne', 'Note')]
+ oldconstraints = rdef.constraints
+ self.assertIn('S created_by U',
+ [cstr.expression for cstr in oldconstraints])
+ self.mh.cmd_sync_schema_props_perms('evaluee', commit=True)
+ newconstraints = rdef.constraints
+ self.assertNotIn('S created_by U',
+ [cstr.expression for cstr in newconstraints])
+
+ # Drop all RQLConstraint.
+ rdef = self.schema['travaille'].rdefs[('Personne', 'Societe')]
+ oldconstraints = rdef.constraints
+ self.assertEqual(len(oldconstraints), 2)
+ self.mh.cmd_sync_schema_props_perms('travaille', commit=True)
+ rdef = self.schema['travaille'].rdefs[('Personne', 'Societe')]
+ newconstraints = rdef.constraints
+ self.assertEqual(len(newconstraints), 0)
+
@tag('longrun')
def test_sync_schema_props_perms(self):
cursor = self.mh.session