# HG changeset patch # User Denis Laxalde # Date 1394461070 -3600 # Node ID fa00fc251d57f61e619d9c905502745fae21c58c # Parent e2d5b07129742c64f37415623a46e93dba35c5b5 [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. diff -r e2d5b0712974 -r fa00fc251d57 hooks/syncschema.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) diff -r e2d5b0712974 -r fa00fc251d57 schema.py --- 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 diff -r e2d5b0712974 -r fa00fc251d57 server/migractions.py --- 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 diff -r e2d5b0712974 -r fa00fc251d57 server/test/data/migratedapp/schema.py --- 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'), + ] diff -r e2d5b0712974 -r fa00fc251d57 server/test/data/schema.py --- 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 diff -r e2d5b0712974 -r fa00fc251d57 server/test/unittest_migractions.py --- 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