[migractions] Better handle removal of RQLConstraint in sync_schema stable cubicweb-centos-version-3.17.14-1 cubicweb-debian-version-3.17.14-1 cubicweb-version-3.17.14
authorDenis Laxalde <denis.laxalde@logilab.fr>
Mon, 10 Mar 2014 15:17:50 +0100
branchstable
changeset 9565 fa00fc251d57
parent 9564 e2d5b0712974
child 9566 cc7e0f4eb10f
[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.
hooks/syncschema.py
schema.py
server/migractions.py
server/test/data/migratedapp/schema.py
server/test/data/schema.py
server/test/unittest_migractions.py
--- 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