[computed attribute] ensure attribute's formula apply only to the correct type. Closes #4901163
authorSylvain Thénault <sylvain.thenault@logilab.fr>
Mon, 02 Feb 2015 23:17:15 +0100
changeset 10192 365e5a0287d6
parent 10191 cc4b8021bdf3
child 10193 a0a11be5a9cb
[computed attribute] ensure attribute's formula apply only to the correct type. Closes #4901163
hooks/synccomputed.py
hooks/test/data-computed/schema.py
hooks/test/unittest_synccomputed.py
schema.py
test/unittest_schema.py
--- a/hooks/synccomputed.py	Mon Feb 02 22:05:00 2015 +0100
+++ b/hooks/synccomputed.py	Mon Feb 02 23:17:15 2015 +0100
@@ -161,6 +161,8 @@
             # expected to have been set by finalize_computed_attributes
             select = rdef.formula_select
             for rel_node in select.get_nodes(nodes.Relation):
+                if rel_node.is_types_restriction():
+                    continue
                 rschema = schema.rschema(rel_node.r_type)
                 lhs, rhs = rel_node.get_variable_parts()
                 for sol in select.solutions:
--- a/hooks/test/data-computed/schema.py	Mon Feb 02 22:05:00 2015 +0100
+++ b/hooks/test/data-computed/schema.py	Mon Feb 02 23:17:15 2015 +0100
@@ -29,3 +29,18 @@
 class Societe(EntityType):
     nom = String()
     salaire_total = Int(formula='Any SUM(SA) GROUPBY X WHERE P travaille X, P salaire SA')
+
+
+class Agent(EntityType):
+    asalae_id = String(formula='Any E WHERE M mirror_of X, M extid E')
+
+class MirrorEntity(EntityType):
+    extid = String(required=True, unique=True,
+                   description=_('external identifier of the object'))
+
+
+class mirror_of(RelationDefinition):
+    subject  = 'MirrorEntity'
+    object = ('Agent', 'Societe')
+    cardinality = '?*'
+    inlined = True
--- a/hooks/test/unittest_synccomputed.py	Mon Feb 02 22:05:00 2015 +0100
+++ b/hooks/test/unittest_synccomputed.py	Mon Feb 02 23:17:15 2015 +0100
@@ -134,6 +134,13 @@
             self.assertEqual(rset[0][0], 2014 - 1990)
 
 
+    def test_recompute_on_ambiguous_relation(self):
+        # check we don't end up with TypeResolverException as in #4901163
+        with self.admin_access.client_cnx() as cnx:
+            societe = cnx.create_entity('Societe', nom=u'Foo')
+            cnx.create_entity('MirrorEntity', mirror_of=societe, extid=u'1')
+            cnx.commit()
+
 if __name__ == '__main__':
     from logilab.common.testlib import unittest_main
     unittest_main()
--- a/schema.py	Mon Feb 02 22:05:00 2015 +0100
+++ b/schema.py	Mon Feb 02 23:17:15 2015 +0100
@@ -1072,6 +1072,7 @@
         for rdef in self.iter_computed_attributes():
             rqlst = parse(rdef.formula)
             select = rqlst.children[0]
+            select.add_type_restriction(select.defined_vars['X'], str(rdef.subject))
             analyzer.visit(select)
             _check_valid_formula(rdef, rqlst)
             rdef.formula_select = select # avoid later recomputation
--- a/test/unittest_schema.py	Mon Feb 02 22:05:00 2015 +0100
+++ b/test/unittest_schema.py	Mon Feb 02 23:17:15 2015 +0100
@@ -299,6 +299,10 @@
                                        'P works_for X, P salary SA')
         good_schema = build_schema_from_namespace(vars().items())
 
+        # ensure 'X is Company' is added to the rqlst to avoid ambiguities, see #4901163
+        self.assertEqual(str(good_schema['Company'].rdef('total_salary').formula_select),
+                         'Any SUM(SA) GROUPBY X WHERE P works_for X, P salary SA, X is Company')
+
         class Company(EntityType):
             total_salary = String(formula='Any SUM(SA) GROUPBY X WHERE '
                                           'P works_for X, P salary SA')