add_type_restriction properly behave vs is_instance_of relation. Closes #176472 stable
authorSylvain Thénault <sylvain.thenault@logilab.fr>
Wed, 11 Sep 2013 12:57:23 +0200
branchstable
changeset 722 ef50aa5ed8ce
parent 721 91c4cbe2eeb3
child 723 e2d6622493d5
add_type_restriction properly behave vs is_instance_of relation. Closes #176472
nodes.py
test/unittest_nodes.py
--- a/nodes.py	Wed Sep 11 12:56:19 2013 +0200
+++ b/nodes.py	Wed Sep 11 12:57:23 2013 +0200
@@ -220,8 +220,8 @@
         """builds a restriction node to express : variable is etype"""
         typerel = var.stinfo.get('typerel', None)
         if typerel:
-            istarget = typerel.children[1].children[0]
             if typerel.r_type == 'is':
+                istarget = typerel.children[1].children[0]
                 if isinstance(istarget, Constant):
                     etypes = (istarget.value,)
                 else: # Function (IN)
@@ -233,25 +233,10 @@
                     for child in istarget.children[:]:
                         if child.value != etype:
                             typerel.stmt.remove_node(child)
+                return typerel
             else:
-                # let's botte en touche IN cases (who would do that anyway ?)
-                if isinstance(istarget, Function):
-                    msg = 'adding type restriction over is_instance_of IN is not supported'
-                    raise NotImplementedError(msg)
-                schema = self.root.schema
-                if schema is None:
-                    msg = 'restriction with is_instance_of cannot be done without a schema'
-                    raise RQLException(msg)
-                # let's check the restriction is compatible
-                eschema = schema[etype]
-                ancestors = set(eschema.ancestors())
-                ancestors.add(etype) # let's be unstrict
-                if istarget.value in ancestors:
-                    istarget.value = etype
-                else:
-                    raise RQLException('type restriction %s-%s cannot be made on %s' %
-                                       (var, etype, self))
-            return typerel
+                assert typerel.r_type == 'is_instance_of'
+                typerel.stmt.remove_node(typerel)
         return self.add_constant_restriction(var, 'is', etype, 'etype')
 
 
--- a/test/unittest_nodes.py	Wed Sep 11 12:56:19 2013 +0200
+++ b/test/unittest_nodes.py	Wed Sep 11 12:57:23 2013 +0200
@@ -91,13 +91,19 @@
         self.assertRaises(RQLException, select.add_type_restriction, x.variable, 'Babar')
         self.assertEqual(tree.as_string(), "Any X WHERE X is IN(Person, Company), X name ILIKE 'A%'")
 
-    # XXX a full schema is needed, see test in cw/server/test/unittest_security
-    # def test_add_is_against_isintance_type_restriction(self):
-    #     tree = self.parse('Any X WHERE X is_instance_of Person')
-    #     select = tree.children[0]
-    #     x = select.get_selected_variables().next()
-    #     select.add_type_restriction(x.variable, 'Student')
-    #     self.parse(tree.as_string())
+    def test_add_is_type_restriction_on_is_instance_of(self):
+        select = self.parse("Any X WHERE X is_instance_of Person, X name ILIKE 'A%'").children[0]
+        x = select.get_selected_variables().next()
+        select.add_type_restriction(x.variable, 'Person')
+        self.assertEqual(select.as_string(), "Any X WHERE X name ILIKE 'A%', X is Person")
+
+    def test_add_new_is_type_restriction_in_on_is_instance_of(self):
+        tree = self.parse("Any X WHERE X is_instance_of IN(Person, Company), X name ILIKE 'A%'")
+        select = tree.children[0]
+        x = select.get_selected_variables().next()
+        select.add_type_restriction(x.variable, 'Company')
+        self.assertEqual(tree.as_string(), "Any X WHERE X name ILIKE 'A%', X is Company")
+
 
 class NodesTest(TestCase):
     def _parse(self, rql, normrql=None):
@@ -310,6 +316,18 @@
         tree.check_references()
         self.assertEqual(tree.as_string(), "Any X WHERE X is IN(Person, Company), X name ILIKE 'A%'")
 
+    def test_recover_add_type_restriction_is_instance_of(self):
+        tree = self._parse("Any X WHERE X is_instance_of IN(Person, Company), X name ILIKE 'A%'")
+        annotator.annotate(tree) # needed to get typerel index
+        tree.save_state()
+        select = tree.children[0]
+        x = select.get_selected_variables().next()
+        select.add_type_restriction(x.variable, 'Company')
+        self.assertEqual(tree.as_string(), "Any X WHERE X name ILIKE 'A%', X is Company")
+        tree.recover()
+        tree.check_references()
+        self.assertEqual(tree.as_string(), "Any X WHERE X is_instance_of IN(Person, Company), X name ILIKE 'A%'")
+
     def test_select_base_1(self):
         tree = self._parse("Any X WHERE X is Person")
         self.assertIsInstance(tree, stmts.Union)