[CWEP002] properly handle serialization of computed attributes
authorLea Capgen <lea.capgen@logilab.fr>
Tue, 16 Sep 2014 15:28:35 +0200
changeset 9968 50f046bf0e50
parent 9967 e65873ad0371
child 9969 0f64ef873f7a
[CWEP002] properly handle serialization of computed attributes Until this cset, only serialization of computed attribute's formula was handled (thanks to the relation definition's properties dict). We now: * properly serialize/deserialize attribute's formula * test first if the database has been migrated and contains related column or not Related to #3546717
misc/migration/3.20.0_Any.py
server/schemaserial.py
server/test/data-cwep002/schema.py
server/test/unittest_schemaserial.py
--- a/misc/migration/3.20.0_Any.py	Tue Sep 16 16:39:23 2014 +0200
+++ b/misc/migration/3.20.0_Any.py	Tue Sep 16 15:28:35 2014 +0200
@@ -1,1 +1,2 @@
 add_relation_type('CWComputedRType')
+add_attribute('CWAttribute', 'formula')
--- a/server/schemaserial.py	Tue Sep 16 16:39:23 2014 +0200
+++ b/server/schemaserial.py	Tue Sep 16 15:28:35 2014 +0200
@@ -100,6 +100,13 @@
             rtype = ybo.ComputedRelation(name=rule_name, rule=rule, eid=eid,
                                          description=description)
             schema.add_relation_type(rtype)
+    # computed attribute
+    try:
+        cnx.system_sql("SELECT cw_formula FROM cw_CWAttribute")
+        has_computed_attributes = True
+    except Exception:
+        cnx.rollback()
+        has_computed_attributes = False
 
     # XXX bw compat (3.6 migration)
     with cnx.ensure_cnx_set:
@@ -216,24 +223,32 @@
         cnx.critical('Previous CRITICAL notification about extra_props is not '
                      'a problem if you are migrating to cubicweb 3.17')
         extra_props = {} # not yet in the schema (introduced by 3.17 migration)
-    for values in cnx.execute(
-        'Any X,SE,RT,OE,CARD,ORD,DESC,IDX,FTIDX,I18N,DFLT WHERE X is CWAttribute,'
-        'X relation_type RT, X cardinality CARD, X ordernum ORD, X indexed IDX,'
-        'X description DESC, X internationalizable I18N, X defaultval DFLT,'
-        'X fulltextindexed FTIDX, X from_entity SE, X to_entity OE',
-        build_descr=False):
-        rdefeid, seid, reid, oeid, card, ord, desc, idx, ftidx, i18n, default = values
-        typeparams = extra_props.get(rdefeid)
-        typeparams = json.load(typeparams) if typeparams else {}
+
+    # load attributes
+    rql = ('Any X,SE,RT,OE,CARD,ORD,DESC,IDX,FTIDX,I18N,DFLT%(fm)s '
+           'WHERE X is CWAttribute, X relation_type RT, X cardinality CARD,'
+           '      X ordernum ORD, X indexed IDX, X description DESC, '
+           '      X internationalizable I18N, X defaultval DFLT,%(fmsnip)s'
+           '      X fulltextindexed FTIDX, X from_entity SE, X to_entity OE')
+    if has_computed_attributes:
+        rql = rql % {'fm': ',FM', 'fmsnip': 'X formula FM,'}
+    else:
+        rql = rql % {'fm': '', 'fmsnip': ''}
+    for values in cnx.execute(rql, build_descr=False):
+        attrs = dict(zip(
+            ('rdefeid', 'seid', 'reid', 'oeid', 'cardinality',
+             'order', 'description', 'indexed', 'fulltextindexed',
+             'internationalizable', 'default', 'formula'), values))
+        typeparams = extra_props.get(attrs['rdefeid'])
+        attrs.update(json.load(typeparams) if typeparams else {})
+        default = attrs['default']
         if default is not None:
             if isinstance(default, Binary):
                 # while migrating from 3.17 to 3.18, we still have to
                 # handle String defaults
-                default = default.unzpickle()
-        _add_rdef(rdefeid, seid, reid, oeid,
-                  cardinality=card, description=desc, order=ord,
-                  indexed=idx, fulltextindexed=ftidx, internationalizable=i18n,
-                  default=default, **typeparams)
+                attrs['default'] = default.unzpickle()
+        _add_rdef(**attrs)
+    # load relations
     for values in cnx.execute(
         'Any X,SE,RT,OE,CARD,ORD,DESC,C WHERE X is CWRelation, X relation_type RT,'
         'X cardinality CARD, X ordernum ORD, X description DESC, '
--- a/server/test/data-cwep002/schema.py	Tue Sep 16 16:39:23 2014 +0200
+++ b/server/test/data-cwep002/schema.py	Tue Sep 16 15:28:35 2014 +0200
@@ -27,7 +27,8 @@
     cardinality = '?*'
 
 class Company(EntityType):
-    total_salary = Int()
+    total_salary = Int(formula='Any SUM(SA) GROUPBY X WHERE '
+                       'P works_for X, P salary SA')
 
 class has_employee(ComputedRelation):
     rule = 'O works_for S'
--- a/server/test/unittest_schemaserial.py	Tue Sep 16 16:39:23 2014 +0200
+++ b/server/test/unittest_schemaserial.py	Tue Sep 16 15:28:35 2014 +0200
@@ -441,6 +441,8 @@
         self.assertEqual('O works_for S',
                          schema['has_employee'].rule)
         self.assertEqual([('Company', 'Int')], list(schema['total_salary'].rdefs))
+        self.assertEqual('Any SUM(SA) GROUPBY X WHERE P works_for X, P salary SA',
+                         schema['total_salary'].rdefs['Company', 'Int'].formula)
 
 if __name__ == '__main__':
     unittest_main()