[syncschema] don't arbitrarily remove constraints from the in-memory schema
authorJulien Cristau <julien.cristau@logilab.fr>
Tue, 03 Nov 2015 18:10:58 +0100
changeset 10813 ab626726a70a
parent 10812 a747e211266b
child 10814 a13db4185129
[syncschema] don't arbitrarily remove constraints from the in-memory schema For some constraint types, it may make sense to have several constraints of that type simultaneously. In such a case, removing one of them from the in-memory schema is wrong. Closes #7446353
hooks/syncschema.py
hooks/test/unittest_syncschema.py
schema.py
server/checkintegrity.py
--- a/hooks/syncschema.py	Tue Nov 03 18:03:21 2015 +0100
+++ b/hooks/syncschema.py	Tue Nov 03 18:10:58 2015 +0100
@@ -37,7 +37,8 @@
 from cubicweb import validation_error
 from cubicweb.predicates import is_instance
 from cubicweb.schema import (SCHEMA_TYPES, META_RTYPES, VIRTUAL_RTYPES,
-                             CONSTRAINTS, ETYPE_NAME_MAP, display_name)
+                             CONSTRAINTS, UNIQUE_CONSTRAINTS, ETYPE_NAME_MAP,
+                             display_name)
 from cubicweb.server import hook, schemaserial as ss, schema2sql as y2sql
 from cubicweb.server.sqlutils import SQL_PREFIX
 from cubicweb.hooks.synccomputed import RecomputeAttributeOperation
@@ -749,7 +750,10 @@
             return
         rdef = self.rdef = cnx.vreg.schema.schema_by_eid(rdefentity.eid)
         cstrtype = self.entity.type
-        oldcstr = self.oldcstr = rdef.constraint_by_type(cstrtype)
+        if cstrtype in UNIQUE_CONSTRAINTS:
+            oldcstr = self.oldcstr = rdef.constraint_by_type(cstrtype)
+        else:
+            oldcstr = None
         newcstr = self.newcstr = CONSTRAINTS[cstrtype].deserialize(self.entity.value)
         # in-place modification of in-memory schema first
         _set_modifiable_constraints(rdef)
--- a/hooks/test/unittest_syncschema.py	Tue Nov 03 18:03:21 2015 +0100
+++ b/hooks/test/unittest_syncschema.py	Tue Nov 03 18:10:58 2015 +0100
@@ -19,6 +19,7 @@
 
 from logilab.common.testlib import unittest_main
 
+from yams.constraints import BoundaryConstraint
 from cubicweb import ValidationError, Binary
 from cubicweb.schema import META_RTYPES
 from cubicweb.devtools import startpgcluster, stoppgcluster, PostgresApptestConfiguration
@@ -382,5 +383,23 @@
             self.assertEqual(cstr.values, (u'normal', u'auto', u'new'))
             cnx.execute('INSERT Transition T: T name "hop", T type "new"')
 
+    def test_add_constraint(self):
+        with self.admin_access.repo_cnx() as cnx:
+            rdef = self.schema['EmailPart'].rdef('ordernum')
+            cstr = BoundaryConstraint('>=', 0)
+            cnx.execute('INSERT CWConstraint X: X value %(v)s, X cstrtype CT, '
+                        'EDEF constrained_by X WHERE CT name %(ct)s, EDEF eid %(x)s',
+                        {'ct': cstr.__class__.__name__, 'v': cstr.serialize(), 'x': rdef.eid})
+            cnx.commit()
+            cstr2 = rdef.constraint_by_type('BoundaryConstraint')
+            self.assertEqual(cstr, cstr2)
+            cstr3 = BoundaryConstraint('<=', 1000)
+            cnx.execute('INSERT CWConstraint X: X value %(v)s, X cstrtype CT, '
+                        'EDEF constrained_by X WHERE CT name %(ct)s, EDEF eid %(x)s',
+                        {'ct': cstr3.__class__.__name__, 'v': cstr3.serialize(), 'x': rdef.eid})
+            cnx.commit()
+            self.assertCountEqual(rdef.constraints, [cstr, cstr3])
+
+
 if __name__ == '__main__':
     unittest_main()
--- a/schema.py	Tue Nov 03 18:03:21 2015 +0100
+++ b/schema.py	Tue Nov 03 18:10:58 2015 +0100
@@ -105,6 +105,9 @@
 INTERNAL_TYPES = set(('CWProperty', 'CWCache', 'ExternalUri', 'CWDataImport',
                       'CWSource', 'CWSourceHostConfig', 'CWSourceSchemaConfig'))
 
+UNIQUE_CONSTRAINTS = ('SizeConstraint', 'FormatConstraint',
+                      'StaticVocabularyConstraint',
+                      'RQLVocabularyConstraint')
 
 _LOGGER = getLogger('cubicweb.schemaloader')
 
--- a/server/checkintegrity.py	Tue Nov 03 18:03:21 2015 +0100
+++ b/server/checkintegrity.py	Tue Nov 03 18:10:58 2015 +0100
@@ -29,7 +29,7 @@
 
 from logilab.common.shellutils import ProgressBar
 
-from cubicweb.schema import PURE_VIRTUAL_RTYPES, VIRTUAL_RTYPES
+from cubicweb.schema import PURE_VIRTUAL_RTYPES, VIRTUAL_RTYPES, UNIQUE_CONSTRAINTS
 from cubicweb.server.sqlutils import SQL_PREFIX
 
 def notify_fixed(fix):
@@ -138,9 +138,6 @@
 def check_schema(schema, cnx, eids, fix=1):
     """check serialized schema"""
     print('Checking serialized schema')
-    unique_constraints = ('SizeConstraint', 'FormatConstraint',
-                          'VocabularyConstraint',
-                          'RQLVocabularyConstraint')
     rql = ('Any COUNT(X),RN,SN,ON,CTN GROUPBY RN,SN,ON,CTN ORDERBY 1 '
            'WHERE X is CWConstraint, R constrained_by X, '
            'R relation_type RT, RT name RN, R from_entity ST, ST name SN, '
@@ -148,7 +145,7 @@
     for count, rn, sn, on, cstrname in cnx.execute(rql):
         if count == 1:
             continue
-        if cstrname in unique_constraints:
+        if cstrname in UNIQUE_CONSTRAINTS:
             print("ERROR: got %s %r constraints on relation %s.%s.%s" % (
                 count, cstrname, sn, rn, on))
             if fix: