# HG changeset patch # User Alain Leufroy <alain.leufroy@logilab.fr> # Date 1398347179 -7200 # Thu Apr 24 15:46:19 2014 +0200 # Node ID dbb9798ea5ad2a56d5aca5b77afdef62293d6e8b # Parent a9ef868f04446ffecaac831d2c5f52a879ab651e [stcheck] fix visit_constant checker: a etype inside a CAST is a good thing Actually, if you put a CAST after a relation (!= ``is`` or ``is_instance_of``), the checker raises an error saying that the etype (inside the CAST) must be after a ``is`` or ``is_instance_of`` relation. In fact the CAST case was tested too late. This allow to use CAST outside the selection section, so: Closes #79232 diff --git a/stcheck.py b/stcheck.py --- a/stcheck.py +++ b/stcheck.py @@ -457,18 +457,18 @@ pass def visit_constant(self, constant, state): - #assert len(constant.children)==0 - if constant.type == 'etype': - if constant.value not in self.schema: - state.error('unknown entity type %s' % constant.value) - rel = constant.relation() - if rel is not None: - if rel.r_type not in ('is', 'is_instance_of'): - msg ='using an entity type in only allowed with "is" relation' - state.error(msg) - elif not (isinstance(constant.parent, Function) and - constant.parent.name == 'CAST'): - state.error('Entity types can only be used inside a CAST()') + if constant.type != 'etype': + return + if constant.value not in self.schema: + state.error('unknown entity type %s' % constant.value) + if (isinstance(constant.parent, Function) and + constant.parent.name == 'CAST'): + return + rel = constant.relation() + if rel is not None and rel.r_type in ('is', 'is_instance_of'): + return + state.error('Entity types can only be used inside a CAST() ' + 'or with "is" relation') def leave_constant(self, node, state): pass diff --git a/test/unittest_analyze.py b/test/unittest_analyze.py --- a/test/unittest_analyze.py +++ b/test/unittest_analyze.py @@ -548,5 +548,22 @@ self.assertEqual(sols, [{'U': 'Person'}]) + def test_selection_with_cast(self): + node = self.helper.parse('Any X WHERE X name CAST(String, E), Y eid E, X owned_by Y') + self.helper.compute_solutions(node, debug=DEBUG) + sols = sorted(node.children[0].solutions) + self.assertEqual(sols, [{'E': 'Int', 'X': 'Company', 'Y': 'Person'}, + {'E': 'Int', 'X': 'Person', 'Y': 'Person'}, + {'E': 'Int', 'X': 'Student', 'Y': 'Person'}]) + + def test_set_with_cast(self): + node = self.helper.parse('SET X name CAST(String, E), X work_for Y WHERE Y eid E') + self.helper.compute_solutions(node, debug=DEBUG) + sols = sorted(node.solutions) + self.assertEqual(sols, [{'X': 'Person', 'Y': 'Company', 'E': 'Int'}, + {'X': 'Student', 'Y': 'Company', 'E': 'Int'}]) + + + if __name__ == '__main__': unittest_main() diff --git a/test/unittest_stcheck.py b/test/unittest_stcheck.py --- a/test/unittest_stcheck.py +++ b/test/unittest_stcheck.py @@ -80,11 +80,10 @@ # variable with only ?1 cardinality 'DISTINCT Any P ORDERBY PN WHERE P work_for X, P name PN', 'DISTINCT Any P ORDERBY XN WHERE P work_for X, X name XN', - 'Any X WHERE X eid > 0, X eid < 42', 'Any X WHERE X eid 1, X eid < 42', - - + 'Any X WHERE X number CAST(Int, Y), X name Y', + 'SET X number CAST(Int, Y) WHERE X name Y', ) class CheckClassTest(TestCase):