add_type_restriction properly behave vs is_instance_of relation. Closes #176472
--- 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)