# HG changeset patch # User Julien Cristau # Date 1458125792 -3600 # Node ID 4e79acdc36a63f9ac82a7b74b1d0838650521eb8 # Parent 3309ddb970594cd54529f5c205d1ea5b5da4131e [schema] use json to serialize constraints Require yams 0.43: constraints are serialized to json, which means we need to recreate the actual checks in the database on upgrade. Temporary deps in tox.ini to pull respective changes in yams. diff -r 3309ddb97059 -r 4e79acdc36a6 cubicweb.spec --- a/cubicweb.spec Wed Mar 16 17:59:10 2016 +0100 +++ b/cubicweb.spec Wed Mar 16 11:56:32 2016 +0100 @@ -25,7 +25,7 @@ Requires: %{python}-logilab-common >= 1.2.0 Requires: %{python}-logilab-mtconverter >= 0.8.0 Requires: %{python}-rql >= 0.34.0 -Requires: %{python}-yams >= 0.42.0 +Requires: %{python}-yams >= 0.43.0 Requires: %{python}-logilab-database >= 1.15.0 Requires: %{python}-passlib Requires: %{python}-lxml diff -r 3309ddb97059 -r 4e79acdc36a6 cubicweb/__pkginfo__.py --- a/cubicweb/__pkginfo__.py Wed Mar 16 17:59:10 2016 +0100 +++ b/cubicweb/__pkginfo__.py Wed Mar 16 11:56:32 2016 +0100 @@ -43,7 +43,7 @@ 'logilab-common': '>= 1.2.0', 'logilab-mtconverter': '>= 0.8.0', 'rql': '>= 0.34.0', - 'yams': '>= 0.42.0', + 'yams': '>= 0.42.0', # TODO '>= 0.43.0' upon release. #gettext # for xgettext, msgcat, etc... # web dependencies 'lxml': '', diff -r 3309ddb97059 -r 4e79acdc36a6 cubicweb/misc/migration/3.23.0_Any.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/cubicweb/misc/migration/3.23.0_Any.py Wed Mar 16 11:56:32 2016 +0100 @@ -0,0 +1,24 @@ +# we changed constraint serialization, which also changes their name +from cubicweb.server.schema2sql import check_constraint + +helper = repo.system_source.dbhelper + +for table, cstr in sql(""" + SELECT table_name, constraint_name FROM information_schema.constraint_column_usage + WHERE constraint_name LIKE 'cstr%'"""): + sql("ALTER TABLE %(table)s DROP CONSTRAINT %(cstr)s" % locals()) + +for cwconstraint in rql('Any C WHERE R constrained_by C').entities(): + cwrdef = cwconstraint.reverse_constrained_by[0] + rdef = cwrdef.yams_schema() + cstr = rdef.constraint_by_eid(cwconstraint.eid) + if cstr.type() not in ('BoundaryConstraint', 'IntervalBoundConstraint', + 'StaticVocabularyConstraint'): + # These cannot be translate into backend CHECK. + continue + cstrname, check = check_constraint(rdef.subject, rdef.object, rdef.rtype.type, + cstr, helper, prefix='cw_') + args = {'e': rdef.subject.type, 'c': cstrname, 'v': check} + sql('ALTER TABLE cw_%(e)s ADD CONSTRAINT %(c)s CHECK(%(v)s)' % args) + +commit() diff -r 3309ddb97059 -r 4e79acdc36a6 cubicweb/schema.py --- a/cubicweb/schema.py Wed Mar 16 17:59:10 2016 +0100 +++ b/cubicweb/schema.py Wed Mar 16 11:56:32 2016 +0100 @@ -40,7 +40,8 @@ from yams.schema import Schema, ERSchema, EntitySchema, RelationSchema, \ RelationDefinitionSchema, PermissionMixIn, role_name from yams.constraints import (BaseConstraint, FormatConstraint, BoundaryConstraint, - IntervalBoundConstraint, StaticVocabularyConstraint) + IntervalBoundConstraint, StaticVocabularyConstraint, + cstr_json_dumps, cstr_json_loads) from yams.reader import (CONSTRAINTS, PyFileReader, SchemaLoader, cleanup_sys_modules, fill_schema_from_namespace) @@ -1145,13 +1146,17 @@ distinct_query = None def serialize(self): - # start with a semicolon for bw compat, see below - return ';' + ','.join(sorted(self.mainvars)) + ';' + self.expression + return cstr_json_dumps({u'mainvars': sorted(self.mainvars), + u'expression': self.expression}) @classmethod def deserialize(cls, value): - _, mainvars, expression = value.split(';', 2) - return cls(expression, mainvars) + try: + d = cstr_json_loads(value) + return cls(d['expression'], d['mainvars']) + except ValueError: + _, mainvars, expression = value.split(';', 2) + return cls(expression, mainvars) def check(self, entity, rtype, value): """return true if the value satisfy the constraint, else false""" @@ -1199,15 +1204,20 @@ self.msg = msg def serialize(self): - # start with a semicolon for bw compat, see below - return ';%s;%s\n%s' % (','.join(sorted(self.mainvars)), self.expression, - self.msg or '') + return cstr_json_dumps({ + u'mainvars': sorted(self.mainvars), + u'expression': self.expression, + u'msg': self.msg}) @classmethod def deserialize(cls, value): - value, msg = value.split('\n', 1) - _, mainvars, expression = value.split(';', 2) - return cls(expression, mainvars, msg) + try: + d = cstr_json_loads(value) + return cls(d['expression'], d['mainvars'], d['msg']) + except ValueError: + value, msg = value.split('\n', 1) + _, mainvars, expression = value.split(';', 2) + return cls(expression, mainvars, msg) def repo_check(self, session, eidfrom, rtype, eidto=None): """raise ValidationError if the relation doesn't satisfy the constraint diff -r 3309ddb97059 -r 4e79acdc36a6 cubicweb/server/test/unittest_schema2sql.py --- a/cubicweb/server/test/unittest_schema2sql.py Wed Mar 16 17:59:10 2016 +0100 +++ b/cubicweb/server/test/unittest_schema2sql.py Wed Mar 16 11:56:32 2016 +0100 @@ -52,7 +52,7 @@ d2 date, t1 time, t2 time -, CONSTRAINT cstredd407706bdfbd2285714dd689e8fcc0 CHECK(d1 <= CAST(clock_timestamp() AS DATE)) +, CONSTRAINT cstr67c656afbcbfadd4be34d75656a2521a CHECK(d1 <= CAST(clock_timestamp() AS DATE)) ); CREATE TABLE Division( @@ -97,7 +97,7 @@ datenaiss date, test boolean, salary float -, CONSTRAINT cstr41fe7db9ce1d5be95de2477e26590386 CHECK(promo IN ('bon', 'pasbon')) +, CONSTRAINT cstrdedefafc86dc831341c33547388c25bb CHECK(promo IN ('bon', 'pasbon')) ); CREATE UNIQUE INDEX unique_e6c2d219772dbf1715597f7d9a6b3892 ON Person(nom,prenom); @@ -115,7 +115,7 @@ datenaiss date, test boolean, salary float -, CONSTRAINT cstrc8556fcc665865217761cdbcd220cae0 CHECK(promo IN ('bon', 'pasbon')) +, CONSTRAINT cstrb62a1623de9e9b92eb552706b6ce0890 CHECK(promo IN ('bon', 'pasbon')) ); CREATE UNIQUE INDEX unique_98da0f9de8588baa8966f0b1a6f850a3 ON Salaried(nom,prenom); @@ -130,7 +130,7 @@ ad3 varchar(128), cp varchar(12), ville varchar(32) -, CONSTRAINT cstrc51dd462e9f6115506a0fe468d4c8114 CHECK(fax <= tel) +, CONSTRAINT cstraf91cb60287eec6d5c1175075edcccc0 CHECK(fax <= tel) ); CREATE TABLE State( @@ -159,8 +159,8 @@ author_email varchar(100) NOT NULL, mailinglist varchar(100), debian_handler varchar(6) -, CONSTRAINT cstr70f766f834557c715815d76f0a0db956 CHECK(license IN ('GPL', 'ZPL')) -, CONSTRAINT cstr831a117424d0007ae0278cc15f344f5e CHECK(debian_handler IN ('machin', 'bidule')) +, CONSTRAINT cstree063a486aa92d4f721ced56c819f38a CHECK(license IN ('GPL', 'ZPL')) +, CONSTRAINT cstrafb4b6de5d50b5a2eca60b33b7acf59b CHECK(debian_handler IN ('machin', 'bidule')) ); diff -r 3309ddb97059 -r 4e79acdc36a6 cubicweb/server/test/unittest_schemaserial.py --- a/cubicweb/server/test/unittest_schemaserial.py Wed Mar 16 17:59:10 2016 +0100 +++ b/cubicweb/server/test/unittest_schemaserial.py Wed Mar 16 11:56:32 2016 +0100 @@ -115,7 +115,7 @@ ('INSERT CWConstraint X: X value %(value)s, X cstrtype CT, EDEF constrained_by X ' 'WHERE CT eid %(ct)s, EDEF eid %(x)s', {'x': None, 'ct': u'RQLConstraint_eid', - 'value': u';O;O final TRUE\n'}), + 'value': u'{"expression": "O final TRUE", "mainvars": ["O"], "msg": null}'}), ('INSERT CWRelation X: X cardinality %(cardinality)s,X composite %(composite)s,' 'X description %(description)s,X ordernum %(ordernum)s,X relation_type ER,' @@ -125,7 +125,7 @@ 'ordernum': 1, 'cardinality': u'1*'}), ('INSERT CWConstraint X: X value %(value)s, X cstrtype CT, EDEF constrained_by X ' 'WHERE CT eid %(ct)s, EDEF eid %(x)s', - {'x': None, 'ct': u'RQLConstraint_eid', 'value': u';O;O final FALSE\n'}), + {'x': None, 'ct': u'RQLConstraint_eid', 'value': u'{"expression": "O final FALSE", "mainvars": ["O"], "msg": null}'}), ], list(rschema2rql(schema.rschema('relation_type'), cstrtypemap))) @@ -236,12 +236,12 @@ 'WHERE CT eid %(ct)s, EDEF eid %(x)s', {'x': None, 'ct': u'SizeConstraint_eid', - 'value': u'max=2'}), + 'value': u'{"max": 2, "min": null}'}), ('INSERT CWConstraint X: X value %(value)s, X cstrtype CT, EDEF constrained_by X ' 'WHERE CT eid %(ct)s, EDEF eid %(x)s', {'x': None, 'ct': u'StaticVocabularyConstraint_eid', - 'value': u"u'?1', u'11'"}), + 'value': u'["?1", "11"]'}), ('INSERT CWAttribute X: X cardinality %(cardinality)s,X defaultval %(defaultval)s,' 'X description %(description)s,X formula %(formula)s,X fulltextindexed %(fulltextindexed)s,' @@ -263,13 +263,13 @@ 'WHERE CT eid %(ct)s, EDEF eid %(x)s', {'x': None, 'ct': u'SizeConstraint_eid', - 'value': u'max=2'}), + 'value': u'{"max": 2, "min": null}'}), ('INSERT CWConstraint X: X value %(value)s, X cstrtype CT, EDEF constrained_by X ' 'WHERE CT eid %(ct)s, EDEF eid %(x)s', {'x': None, 'ct': u'StaticVocabularyConstraint_eid', - 'value': (u"u'?*', u'1*', u'+*', u'**', u'?+', u'1+', u'++', u'*+', u'?1', " - "u'11', u'+1', u'*1', u'??', u'1?', u'+?', u'*?'")})], + "value": (u'["?*", "1*", "+*", "**", "?+", "1+", "++", "*+", "?1", ' + u'"11", "+1", "*1", "??", "1?", "+?", "*?"]')})], list(rschema2rql(schema.rschema('cardinality'), cstrtypemap))) def test_rschema2rql_custom_type(self): @@ -334,7 +334,7 @@ ('INSERT CWConstraint X: X value %(value)s, X cstrtype CT, EDEF constrained_by X ' 'WHERE CT eid %(ct)s, EDEF eid %(x)s', {'x': None, - 'value': u'max=50', + 'value': u'{"max": 50, "min": null}', 'ct': 'SizeConstraint_eid'})], list(rdef2rql(schema['description_format'].rdefs[('CWRType', 'String')], cstrtypemap))) diff -r 3309ddb97059 -r 4e79acdc36a6 debian/control --- a/debian/control Wed Mar 16 17:59:10 2016 +0100 +++ b/debian/control Wed Mar 16 11:56:32 2016 +0100 @@ -16,7 +16,7 @@ python-markdown, python-tz, python-rql (>= 0.34.0), - python-yams (>= 0.42.0), + python-yams (>= 0.43.0), python-lxml, Standards-Version: 3.9.1 Homepage: https://www.cubicweb.org @@ -160,7 +160,7 @@ python-logilab-mtconverter (>= 0.8.0), python-logilab-common (>= 1.2.0), python-markdown, - python-yams (>= 0.42.0), + python-yams (>= 0.43.0), python-rql (>= 0.34.0), python-lxml Recommends: diff -r 3309ddb97059 -r 4e79acdc36a6 tox.ini --- a/tox.ini Wed Mar 16 17:59:10 2016 +0100 +++ b/tox.ini Wed Mar 16 11:56:32 2016 +0100 @@ -9,6 +9,7 @@ whitelist_externals = /usr/bin/touch deps = + hg+https://hg.logilab.org/review/yams@default#egg=yams py34: -e. cubicweb: -r{toxinidir}/cubicweb/test/requirements.txt devtools: -r{toxinidir}/cubicweb/devtools/test/requirements.txt