diff --git a/nodes.py b/nodes.py index 91c4cbe2eeb39e1075fefd7266d94f08c83d8527_bm9kZXMucHk=..ef50aa5ed8ceb9f29880f5868e39e0b0319beab3_bm9kZXMucHk= 100644 --- a/nodes.py +++ b/nodes.py @@ -220,5 +220,4 @@ """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': @@ -224,4 +223,5 @@ if typerel.r_type == 'is': + istarget = typerel.children[1].children[0] if isinstance(istarget, Constant): etypes = (istarget.value,) else: # Function (IN) @@ -233,4 +233,5 @@ for child in istarget.children[:]: if child.value != etype: typerel.stmt.remove_node(child) + return typerel else: @@ -236,22 +237,6 @@ 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') diff --git a/test/unittest_nodes.py b/test/unittest_nodes.py index 91c4cbe2eeb39e1075fefd7266d94f08c83d8527_dGVzdC91bml0dGVzdF9ub2Rlcy5weQ==..ef50aa5ed8ceb9f29880f5868e39e0b0319beab3_dGVzdC91bml0dGVzdF9ub2Rlcy5weQ== 100644 --- a/test/unittest_nodes.py +++ b/test/unittest_nodes.py @@ -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)