sparql support for limit/offset/orderby
authorSylvain Thénault <sylvain.thenault@logilab.fr>
Thu, 23 Jul 2009 12:47:09 +0200
changeset 2431 93c061eac647
parent 2430 7d9ed6c740ec
child 2433 1d46c016a564
sparql support for limit/offset/orderby
spa2rql.py
test/unittest_spa2rql.py
--- a/spa2rql.py	Thu Jul 23 12:08:39 2009 +0200
+++ b/spa2rql.py	Thu Jul 23 12:47:09 2009 +0200
@@ -15,6 +15,17 @@
 
 class UnsupportedQuery(Exception): pass
 
+def order_limit_offset(sparqlst):
+    addons = ''
+    if sparqlst.orderby:
+        sortterms = ', '.join('%s %s' % (var.name.upper(), ascdesc.upper())
+                              for var, ascdesc in sparqlst.orderby)
+        addons += ' ORDERBY %s' % sortterms
+    if sparqlst.limit:
+        addons += ' LIMIT %s' % sparqlst.limit
+    if sparqlst.offset:
+        addons += ' OFFSET %s' % sparqlst.offset
+    return addons
 
 class QueryInfo(object):
     """wrapper class containing necessary information to generate a RQL query
@@ -49,15 +60,22 @@
                 unions = thisunions
             else:
                 unions = zip(*make_domains([unions, thisunions]))
-        baserql = 'Any %s WHERE %s' % (', '.join(self.selection),
-                                       ', '.join(self.restrictions))
-        if self.sparqlst.distinct:
-            baserql = 'DISTINCT ' + baserql
+        selection = 'Any ' + ', '.join(self.selection)
+        sparqlst = self.sparqlst
+        if sparqlst.distinct:
+            selection = 'DISTINCT ' + selection
         if not unions:
-            return baserql
+            return '%s%s WHERE %s' % (selection, order_limit_offset(sparqlst),
+                                      ', '.join(self.restrictions))
+        baserql = '%s WHERE %s' % (selection, ', '.join(self.restrictions))
         rqls = ['(%s, %s)' % (baserql, ', '.join(unionrestrs))
                 for unionrestrs in unions]
-        return ' UNION '.join(rqls)
+        rql = ' UNION '.join(rqls)
+        if sparqlst.orderby or sparqlst.limit or sparqlst.offset:
+            rql = '%s%s WITH %s BEING (%s)' % (
+                selection, order_limit_offset(sparqlst),
+                ', '.join(self.selection), rql)
+        return rql
 
     def set_possible_types(self, var, varpossibletypes):
         """set/restrict possible types for the given variable.
--- a/test/unittest_spa2rql.py	Thu Jul 23 12:08:39 2009 +0200
+++ b/test/unittest_spa2rql.py	Thu Jul 23 12:47:09 2009 +0200
@@ -24,6 +24,7 @@
     def XXX_test_base_01(self):
         self._test('SELECT * WHERE { }', 'Any X')
 
+
     def test_base_is(self):
         self._test('''
     PREFIX doap: <http://usefulinc.com/ns/doap#>
@@ -42,6 +43,7 @@
               doap:created ?created.
     }''', 'Any CREATED WHERE PROJECT creation_date CREATED, PROJECT is Project')
 
+
     def test_base_attr_sel_distinct(self):
         self._test('''
     PREFIX doap: <http://usefulinc.com/ns/doap#>
@@ -51,6 +53,7 @@
               doap:name ?name.
     }''', 'DISTINCT Any NAME WHERE PROJECT name NAME, PROJECT is Project')
 
+
     def test_base_attr_sel_reduced(self):
         self._test('''
     PREFIX doap: <http://usefulinc.com/ns/doap#>
@@ -61,6 +64,37 @@
     }''', 'Any NAME WHERE PROJECT name NAME, PROJECT is Project')
 
 
+    def test_base_attr_sel_limit_offset(self):
+        self._test('''
+    PREFIX doap: <http://usefulinc.com/ns/doap#>
+    SELECT ?name
+    WHERE  {
+      ?project a doap:Project;
+              doap:name ?name.
+    }
+    LIMIT 20''', 'Any NAME LIMIT 20 WHERE PROJECT name NAME, PROJECT is Project')
+        self._test('''
+    PREFIX doap: <http://usefulinc.com/ns/doap#>
+    SELECT ?name
+    WHERE  {
+      ?project a doap:Project;
+              doap:name ?name.
+    }
+    LIMIT 20 OFFSET 10''', 'Any NAME LIMIT 20 OFFSET 10 WHERE PROJECT name NAME, PROJECT is Project')
+
+
+    def test_base_attr_sel_orderby(self):
+        self._test('''
+    PREFIX doap: <http://usefulinc.com/ns/doap#>
+    SELECT ?name
+    WHERE  {
+      ?project a doap:Project;
+              doap:name ?name;
+              doap:created ?created.
+    }
+    ORDER BY ?name DESC(?created)''', 'Any NAME ORDERBY NAME ASC, CREATED DESC WHERE PROJECT name NAME, PROJECT creation_date CREATED, PROJECT is Project')
+
+
     def test_base_any_attr_sel(self):
         self._test('''
     PREFIX dc: <http://purl.org/dc/elements/1.1/>
@@ -69,6 +103,7 @@
       ?x dc:date ?cd;
     }''', 'Any X, CD WHERE X creation_date CD')
 
+
     def test_base_any_attr_sel_amb(self):
         xy.add_equivalence('Version publication_date', 'doap:Version dc:date')
         try:
@@ -81,6 +116,34 @@
         finally:
             xy.remove_equivalence('Version publication_date', 'doap:Version dc:date')
 
+
+    def test_base_any_attr_sel_amb_limit_offset(self):
+        xy.add_equivalence('Version publication_date', 'doap:Version dc:date')
+        try:
+            self._test('''
+    PREFIX dc: <http://purl.org/dc/elements/1.1/>
+    SELECT ?x ?cd
+    WHERE  {
+      ?x dc:date ?cd;
+    }
+    LIMIT 20 OFFSET 10''', 'Any X, CD LIMIT 20 OFFSET 10 WITH X, CD BEING ((Any X, CD WHERE , X creation_date CD) UNION (Any X, CD WHERE , X publication_date CD, X is Version))')
+        finally:
+            xy.remove_equivalence('Version publication_date', 'doap:Version dc:date')
+
+
+    def test_base_any_attr_sel_amb_orderby(self):
+        xy.add_equivalence('Version publication_date', 'doap:Version dc:date')
+        try:
+            self._test('''
+    PREFIX dc: <http://purl.org/dc/elements/1.1/>
+    SELECT ?x ?cd
+    WHERE  {
+      ?x dc:date ?cd;
+    }
+    ORDER BY DESC(?cd)''', 'Any X, CD ORDERBY CD DESC WITH X, CD BEING ((Any X, CD WHERE , X creation_date CD) UNION (Any X, CD WHERE , X publication_date CD, X is Version))')
+        finally:
+            xy.remove_equivalence('Version publication_date', 'doap:Version dc:date')
+
 # # Two elements in the group
 # PREFIX :  <http://example.org/ns#>
 # SELECT *