support for CAST function (requires lgdb>=1.6.0)
authorAdrien Di Mascio <Adrien.DiMascio@logilab.fr>
Wed, 27 Apr 2011 11:37:03 +0200
changeset 617 64531b651183
parent 616 e0f450b12992
child 618 a170ddc7f4c6
support for CAST function (requires lgdb>=1.6.0)
ChangeLog
__pkginfo__.py
debian/control
nodes.py
stcheck.py
test/unittest_nodes.py
utils.py
--- a/ChangeLog	Wed Feb 09 19:02:40 2011 +0100
+++ b/ChangeLog	Wed Apr 27 11:37:03 2011 +0200
@@ -2,7 +2,9 @@
 =================
 
 --
-* suport != operator for non equality
+* support != operator for non equality
+* support for CAST function
+
 
 2011-01-12  --  0.28.0
     * enhance rewrite_shared_optional so one can specify where the new identity
--- a/__pkginfo__.py	Wed Feb 09 19:02:40 2011 +0100
+++ b/__pkginfo__.py	Wed Apr 27 11:37:03 2011 +0200
@@ -81,7 +81,7 @@
 
 install_requires = [
     'logilab-common >= 0.47.0',
-    'logilab-database',
+    'logilab-database >= 1.6.0',
     'yapps == 2.1.1', # XXX to ensure we don't use the broken pypi version
     'constraint', # fallback if the gecode compiled module is missing
     ]
--- a/debian/control	Wed Feb 09 19:02:40 2011 +0100
+++ b/debian/control	Wed Apr 27 11:37:03 2011 +0200
@@ -11,7 +11,7 @@
 Package: python-rql
 Architecture: any
 XB-Python-Version: ${python:Versions}
-Depends: ${python:Depends}, ${misc:Depends}, ${shlibs:Depends}, python-logilab-common (>= 0.35.3-1), yapps2-runtime, python-logilab-database
+Depends: ${python:Depends}, ${misc:Depends}, ${shlibs:Depends}, python-logilab-common (>= 0.35.3-1), yapps2-runtime, python-logilab-database (>= 1.6.0)
 Conflicts: cubicweb-common (<= 3.8.3)
 Provides: ${python:Provides}
 Description: relationship query language (RQL) utilities
--- a/nodes.py	Wed Feb 09 19:02:40 2011 +0100
+++ b/nodes.py	Wed Apr 27 11:37:03 2011 +0200
@@ -28,6 +28,8 @@
 from datetime import datetime, date, time, timedelta
 from time import localtime
 
+from logilab.database import DYNAMIC_RTYPE
+
 from rql import CoercionError
 from rql.base import BaseNode, Node, BinaryNode, LeafNode
 from rql.utils import (function_description, quote, uquote, build_visitor_stub,
@@ -440,12 +442,7 @@
             return False
         rhs = self.children[1]
         if isinstance(rhs, Comparison):
-            try:
-                rhs = rhs.children[0]
-            except:
-                print 'opppp', rhs
-                print rhs.root
-                raise
+            rhs = rhs.children[0]
         # else: relation used in SET OR DELETE selection
         return ((isinstance(rhs, Constant) and rhs.type == 'etype')
                 or (isinstance(rhs, Function) and rhs.name == 'IN'))
@@ -625,7 +622,8 @@
 
         solution is an optional variable/etype mapping
         """
-        rtype = self.descr().rtype
+        func_descr = self.descr()
+        rtype = func_descr.rql_return_type(self)
         if rtype is None:
             # XXX support one variable ref child
             try:
--- a/stcheck.py	Wed Feb 09 19:02:40 2011 +0100
+++ b/stcheck.py	Wed Apr 27 11:37:03 2011 +0200
@@ -455,11 +455,16 @@
     def visit_constant(self, constant, state):
         #assert len(constant.children)==0
         if constant.type == 'etype':
-            if constant.relation().r_type not in ('is', 'is_instance_of'):
-                msg ='using an entity type in only allowed with "is" relation'
-                state.error(msg)
-            if not constant.value in self.schema:
+            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()')
 
     def leave_constant(self, node, state):
         pass
--- a/test/unittest_nodes.py	Wed Feb 09 19:02:40 2011 +0100
+++ b/test/unittest_nodes.py	Wed Apr 27 11:37:03 2011 +0200
@@ -564,6 +564,12 @@
         tree = sparse('Any X,R,D,Y WHERE X work_for R, R creation_date D, Y connait X')
         self.assertEqual(tree.get_description(0), [['Person, Student', 'work_for', 'creation_date', 'connait']])
 
+    def test_get_description_cast(self):
+        tree = sparse('Any CAST(String, Y) WHERE X creation_date Y')
+        select = tree.children[0]
+        self.assertEqual(select.selection[0].get_type(), 'String')
+        self.assertEqual(tree.get_description(0), [['String']])
+
 
 class GetNodesFunctionTest(TestCase):
     def test_known_values_1(self):
--- a/utils.py	Wed Feb 09 19:02:40 2011 +0100
+++ b/utils.py	Wed Apr 27 11:37:03 2011 +0200
@@ -68,7 +68,7 @@
 
 
 from logilab.common.decorators import monkeypatch
-from logilab.database import SQL_FUNCTIONS_REGISTRY, FunctionDescr
+from logilab.database import SQL_FUNCTIONS_REGISTRY, FunctionDescr, CAST
 
 RQL_FUNCTIONS_REGISTRY = SQL_FUNCTIONS_REGISTRY.copy()
 
@@ -85,6 +85,19 @@
         raise BadRQLQuery("backend %s doesn't support function %s" % (backend, self.name))
 
 
+@monkeypatch(FunctionDescr)
+def rql_return_type(self, funcnode):
+    return self.rtype
+
+@monkeypatch(CAST)
+def st_description(self, funcnode, mainindex, tr):
+    return self.rql_return_type(funcnode)
+
+@monkeypatch(CAST)
+def rql_return_type(self, funcnode):
+    return funcnode.children[0].value
+
+
 def iter_funcnode_variables(funcnode):
     for term in funcnode.children:
         try: