--- a/spa2rql.py Thu Jul 23 13:07:22 2009 +0200
+++ b/spa2rql.py Thu Jul 23 13:35:06 2009 +0200
@@ -27,6 +27,7 @@
addons += ' OFFSET %s' % sparqlst.offset
return addons
+
class QueryInfo(object):
"""wrapper class containing necessary information to generate a RQL query
from a sparql syntax tree
@@ -41,41 +42,14 @@
self.infer_types_info = []
self.union_params = []
self.restrictions = []
+ self.literals = {}
+ self._litcount = 0
- def finalize(self):
- """return corresponding rql query"""
- for varname, ptypes in self.possible_types.iteritems():
- if len(ptypes) == 1:
- self.restrictions.append('%s is %s' % (varname, iter(ptypes).next()))
- unions = []
- for releq, subjvar, objvar in self.union_params:
- thisunions = []
- for st, rt, ot in releq:
- thisunions.append(['%s %s %s' % (subjvar, rt, objvar)])
- if st != '*':
- thisunions[-1].append('%s is %s' % (subjvar, st))
- if ot != '*':
- thisunions[-1].append('%s is %s' % (objvar, ot))
- if not unions:
- unions = thisunions
- else:
- unions = zip(*make_domains([unions, thisunions]))
- selection = 'Any ' + ', '.join(self.selection)
- sparqlst = self.sparqlst
- if sparqlst.distinct:
- selection = 'DISTINCT ' + selection
- if not unions:
- 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]
- 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 add_literal(self, value):
+ key = chr(ord('a') + self._litcount)
+ self._litcount += 1
+ self.literals[key] = value
+ return key
def set_possible_types(self, var, varpossibletypes):
"""set/restrict possible types for the given variable.
@@ -131,19 +105,69 @@
raise TypeResolverException()
if len(yams_predicates) != nbchoices:
modified = True
+
+ def build_restrictions(self):
# now, for each predicate
for yams_predicates, subjvar, obj in self.infer_types_info:
rel = yams_predicates[0]
- objvar = obj.name.upper()
# if there are several yams relation type equivalences, we will have
# to generate several unioned rql queries
for s, r, o in yams_predicates[1:]:
if r != rel[1]:
- self.union_params.append((yams_predicates, subjvar, objvar))
+ self.union_params.append((yams_predicates, subjvar, obj))
break
+ # else we can simply add it to base rql restrictions
else:
- # else we can simply add it to base rql restrictions
- self.restrictions.append('%s %s %s' % (subjvar, rel[1], objvar))
+ restr = self.build_restriction(subjvar, rel[1], obj)
+ self.restrictions.append(restr)
+
+ def build_restriction(self, subjvar, rtype, obj):
+ if isinstance(obj, ast.SparqlLiteral):
+ key = self.add_literal(obj.value)
+ objvar = '%%(%s)s' % key
+ else:
+ assert isinstance(obj, ast.SparqlVar)
+ # make a valid rql var name
+ objvar = obj.name.upper()
+ # else we can simply add it to base rql restrictions
+ return '%s %s %s' % (subjvar, rtype, objvar)
+
+ def finalize(self):
+ """return corresponding rql query (string) / args (dict)"""
+ for varname, ptypes in self.possible_types.iteritems():
+ if len(ptypes) == 1:
+ self.restrictions.append('%s is %s' % (varname, iter(ptypes).next()))
+ unions = []
+ for releq, subjvar, obj in self.union_params:
+ thisunions = []
+ for st, rt, ot in releq:
+ thisunions.append([self.build_restriction(subjvar, rt, obj)])
+ if st != '*':
+ thisunions[-1].append('%s is %s' % (subjvar, st))
+ if isinstance(obj, ast.SparqlVar) and ot != '*':
+ objvar = obj.name.upper()
+ thisunions[-1].append('%s is %s' % (objvar, objvar))
+ if not unions:
+ unions = thisunions
+ else:
+ unions = zip(*make_domains([unions, thisunions]))
+ selection = 'Any ' + ', '.join(self.selection)
+ sparqlst = self.sparqlst
+ if sparqlst.distinct:
+ selection = 'DISTINCT ' + selection
+ if unions:
+ baserql = '%s WHERE %s' % (selection, ', '.join(self.restrictions))
+ rqls = ['(%s, %s)' % (baserql, ', '.join(unionrestrs))
+ for unionrestrs in unions]
+ 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)
+ else:
+ rql = '%s%s WHERE %s' % (selection, order_limit_offset(sparqlst),
+ ', '.join(self.restrictions))
+ return rql, self.literals
class Sparql2rqlTranslator(object):
@@ -176,10 +200,8 @@
# where subject / object entity type may '*' if not specified
yams_predicates = xy.yeq(':'.join(predicate))
qi.infer_types_info.append((yams_predicates, subjvar, obj))
- if isinstance(obj, ast.SparqlVar):
- # make a valid rql var name
- objvar = obj.name.upper()
- else:
+ if not isinstance(obj, (ast.SparqlLiteral, ast.SparqlVar)):
raise UnsupportedQuery()
qi.infer_types()
+ qi.build_restrictions()
return qi
--- a/test/unittest_spa2rql.py Thu Jul 23 13:07:22 2009 +0200
+++ b/test/unittest_spa2rql.py Thu Jul 23 13:35:06 2009 +0200
@@ -17,9 +17,9 @@
def setUp(self):
self.tr = Sparql2rqlTranslator(schema)
- def _test(self, sparql, rql):
+ def _test(self, sparql, rql, args={}):
qi = self.tr.translate(sparql)
- self.assertEquals(qi.finalize(), rql)
+ self.assertEquals(qi.finalize(), (rql, args))
def XXX_test_base_01(self):
self._test('SELECT * WHERE { }', 'Any X')
@@ -144,6 +144,16 @@
finally:
xy.remove_equivalence('Version publication_date', 'doap:Version dc:date')
+
+ def test_restr_attr(self):
+ self._test('''
+ PREFIX doap: <http://usefulinc.com/ns/doap#>
+ SELECT ?project
+ WHERE {
+ ?project a doap:Project;
+ doap:name "cubicweb".
+ }''', 'Any PROJECT WHERE PROJECT name %(a)s, PROJECT is Project', {'a': 'cubicweb'})
+
# # Two elements in the group
# PREFIX : <http://example.org/ns#>
# SELECT *