[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
--- 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: