[schema] Add a method on yams constraints to compute its unique name
used to identify it in the DB backend.
--- a/cubicweb/entities/adapters.py Fri Jul 08 10:17:14 2016 +0200
+++ b/cubicweb/entities/adapters.py Fri Jul 08 10:17:42 2016 +0200
@@ -21,7 +21,6 @@
from cubicweb import _
from itertools import chain
-from hashlib import md5
from logilab.mtconverter import TransformError
from logilab.common.decorators import cached
@@ -413,9 +412,7 @@
for rschema, attrschema in eschema.attribute_definitions():
rdef = rschema.rdef(eschema, attrschema)
for constraint in rdef.constraints:
- if cstrname == 'cstr' + md5(
- (eschema.type + rschema.type + constraint.type() +
- (constraint.serialize() or '')).encode('ascii')).hexdigest():
+ if cstrname == constraint.name_for(rdef):
break
else:
continue
--- a/cubicweb/hooks/syncschema.py Fri Jul 08 10:17:14 2016 +0200
+++ b/cubicweb/hooks/syncschema.py Fri Jul 08 10:17:42 2016 +0200
@@ -28,7 +28,6 @@
import json
from copy import copy
-from hashlib import md5
from yams.schema import BASE_TYPES, BadSchemaDefinition, RelationDefinitionSchema
from yams.constraints import UniqueConstraint
@@ -754,10 +753,11 @@
elif cstrtype == 'UniqueConstraint':
syssource.update_rdef_unique(cnx, rdef)
self.unique_changed = True
- if cstrtype in ('BoundaryConstraint', 'IntervalBoundConstraint', 'StaticVocabularyConstraint'):
- cstrname = 'cstr' + md5((rdef.subject.type + rdef.rtype.type + cstrtype +
- (self.oldcstr.serialize() or '')).encode('utf-8')).hexdigest()
- cnx.system_sql('ALTER TABLE %s%s DROP CONSTRAINT %s' % (SQL_PREFIX, rdef.subject.type, cstrname))
+ elif cstrtype in ('BoundaryConstraint',
+ 'IntervalBoundConstraint',
+ 'StaticVocabularyConstraint'):
+ cnx.system_sql('ALTER TABLE %s%s DROP CONSTRAINT %s'
+ % (SQL_PREFIX, rdef.subject, self.oldcstr.name_for(rdef)))
def revertprecommit_event(self):
# revert changes on in memory schema
@@ -811,13 +811,12 @@
# oldcstr is the new constraint when the attribute is being added in the same
# transaction or when constraint value is updated. So we've to take care...
if oldcstr is not None:
- oldcstrname = 'cstr' + md5((rdef.subject.type + rdef.rtype.type + cstrtype +
- (self.oldcstr.serialize() or '')).encode('utf-8')).hexdigest()
+ oldcstrname = self.oldcstr.name_for(rdef)
if oldcstrname != cstrname:
cnx.system_sql('ALTER TABLE %s%s DROP CONSTRAINT %s'
- % (SQL_PREFIX, rdef.subject.type, oldcstrname))
+ % (SQL_PREFIX, rdef.subject, oldcstrname))
cnx.system_sql('ALTER TABLE %s%s ADD CONSTRAINT %s CHECK(%s)' %
- (SQL_PREFIX, rdef.subject.type, cstrname, check))
+ (SQL_PREFIX, rdef.subject, cstrname, check))
class CWUniqueTogetherConstraintAddOp(MemSchemaOperation):
--- a/cubicweb/schema.py Fri Jul 08 10:17:14 2016 +0200
+++ b/cubicweb/schema.py Fri Jul 08 10:17:42 2016 +0200
@@ -1,4 +1,4 @@
-# copyright 2003-2014 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
+# copyright 2003-2016 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
# contact http://www.logilab.fr/ -- mailto:contact@logilab.fr
#
# This file is part of CubicWeb.
@@ -22,6 +22,7 @@
import re
from os.path import join, basename
+from hashlib import md5
from logging import getLogger
from warnings import warn
@@ -1145,6 +1146,16 @@
# additional cw specific constraints ###########################################
+@monkeypatch(BaseConstraint)
+def name_for(self, rdef):
+ """Return a unique, size controlled, name for this constraint applied to given `rdef`.
+
+ This name may be used as name for the constraint in the database.
+ """
+ return 'cstr' + md5((rdef.subject.type + rdef.rtype.type + self.type() +
+ (self.serialize() or '')).encode('ascii')).hexdigest()
+
+
class BaseRQLConstraint(RRQLExpression, BaseConstraint):
"""base class for rql constraints"""
distinct_query = None
--- a/cubicweb/server/schema2sql.py Fri Jul 08 10:17:14 2016 +0200
+++ b/cubicweb/server/schema2sql.py Fri Jul 08 10:17:42 2016 +0200
@@ -168,11 +168,8 @@
"""Return (constraint name, constraint SQL definition) for the given relation definition's
constraint. Maybe (None, None) if the constraint is not handled in the backend.
"""
- eschema = rdef.subject
attr = rdef.rtype.type
- # XXX should find a better name
- cstrname = 'cstr' + md5((eschema.type + attr + constraint.type() +
- (constraint.serialize() or '')).encode('ascii')).hexdigest()
+ cstrname = constraint.name_for(rdef)
if constraint.type() == 'BoundaryConstraint':
value = constraint_value_as_sql(constraint.boundary, dbhelper, prefix)
return cstrname, '%s%s %s %s' % (prefix, attr, constraint.operator, value)
--- a/cubicweb/server/test/unittest_migractions.py Fri Jul 08 10:17:14 2016 +0200
+++ b/cubicweb/server/test/unittest_migractions.py Fri Jul 08 10:17:42 2016 +0200
@@ -602,9 +602,7 @@
self.assertEqual(len(constraints), 1, constraints)
rdef = migrschema['promo'].rdefs['Personne', 'String']
cstr = rdef.constraint_by_type('StaticVocabularyConstraint')
- cstrname = 'cstr' + md5((rdef.subject.type + rdef.rtype.type + cstr.type() +
- (cstr.serialize() or '')).encode('ascii')).hexdigest()
- self.assertIn(cstrname, constraints)
+ self.assertIn(cstr.name_for(rdef), constraints)
def _erqlexpr_rset(self, cnx, action, ertype):
rql = 'RQLExpression X WHERE ET is CWEType, ET %s_permission X, ET name %%(name)s' % action