# HG changeset patch # User Julien Cristau # Date 1446570658 -3600 # Node ID ab626726a70abf24e1a8de3ec90a81c46e7298b5 # Parent a747e211266b06cba79113233d6bfbbeecda2ef6 [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 diff -r a747e211266b -r ab626726a70a hooks/syncschema.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) diff -r a747e211266b -r ab626726a70a hooks/test/unittest_syncschema.py --- 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() diff -r a747e211266b -r ab626726a70a schema.py --- 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') diff -r a747e211266b -r ab626726a70a server/checkintegrity.py --- 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: