Commits

Brian Beck committed 8ab7892

Compiler now supports TriplesSameSubject.

Comments (0)

Files changed (3)

lib/telescope/sparql/compiler.py

 from telescope.sparql.patterns import *
 from telescope.sparql.select import *
 from telescope.sparql.helpers import RDF, XSD, is_a
-from telescope.sparql.util import defrag, to_variable
+from telescope.sparql.util import defrag, to_variable, to_list
 
 __all__ = ['Compiler', 'ExpressionCompiler', 'SelectCompiler']
 
         yield ')'
     
     def conditional(self, expression):
-        for expr in expression.operands:
-            try:
-                operator
-            except NameError:
-                operator = self.operator(expression.operator)
-            else:
+        operator = self.operator(expression.operator)
+        for i, expr in enumerate(expression.operands):
+            if i:
                 yield operator
             bracketed = self.precedence_lt(expr, expression)
             yield self.compile(expr, bracketed)
-        del operator
     
     def binary(self, expression):
         left_bracketed = self.precedence_lt(expression.left, expression)
         self.expression_compiler = ExpressionCompiler(self.prefix_map)
     
     def compile(self, select):
+        """Compile `select` and return the resulting string.
+        
+        `select` is a `telescope.sparql.select.Select` instance.
+        
+        """
         return join(self.clauses(select), '\n')
     
     def expression(self, expression, bracketed=False):
-        yield self.expression_compiler.compile(expression, bracketed)
-    
-    def triple(self, triple):
-        subject, predicate, object = triple
-        yield self.expression_compiler.compile(subject)
-        yield self.expression_compiler.compile(predicate)
-        yield self.expression_compiler.compile(object)
+        """
+        Compile `expression` with this instance's `expression_compiler` and
+        return (not yield) the resulting string.
+        
+        If `bracketed` is true, the resulting string will be enclosed in
+        parentheses.
+        
+        """
+        return self.expression_compiler.compile(expression, bracketed)
     
     def clauses(self, select):
         for prefix in self.prefixes():
         if select._order_by:
             yield 'ORDER BY'
             for expression in select._order_by:
-                yield join(self.expression(expression))
+                yield self.expression(expression)
     
     def projection(self, select):
         if '*' in select.variables:
             yield '*'
         else:
             for variable in select.variables:
-                yield self.expression_compiler.term(variable)
+                yield self.expression(variable)
     
     def where(self, select):
         yield 'WHERE'
                 yield join(self.triple(pattern))
                 if patterns or filters:
                     yield '.'
+            elif isinstance(pattern, TriplesSameSubject):
+                yield join(self.triples_same_subject(pattern))
+                if patterns or filters:
+                    yield '.'
             elif isinstance(pattern, UnionGraphPattern):
-                for union_pattern in pattern.patterns:
-                    try:
-                        union_sep
-                    except NameError:
-                        union_sep = 'UNION'
-                    else:
-                        yield union_sep
-                    yield join(self.graph_pattern(union_pattern, True))
-                del union_sep
+                for i, alternative in enumerate(pattern.patterns):
+                    if i:
+                        yield 'UNION'
+                    yield join(self.graph_pattern(alternative, True))
             elif isinstance(pattern, GraphPattern):
                 token = None
                 for token in self.graph_pattern(pattern, False):
         if braces:
             yield '}'
     
+    def triple(self, triple):
+        subject, predicate, object = triple
+        yield self.expression(subject)
+        yield self.expression(predicate)
+        yield self.expression(object)
+    
+    def triples_same_subject(self, triples):
+        yield self.expression(triples.subject)
+        yield join(self.predicate_object_list(triples.predicate_object_list))
+    
+    def predicate_object_list(self, predicate_object_list):
+        for i, (predicate, object_list) in enumerate(predicate_object_list):
+            if i:
+                yield ';'
+            yield self.expression(predicate)
+            for j, object in enumerate(to_list(object_list)):
+                if j:
+                    yield ','
+                yield self.expression(object)
+    
     def filter(self, filter):
         yield 'FILTER'
         constraint = filter.constraint
                 break
         if not isinstance(constraint, FunctionCall):
             bracketed = True
-        yield join(self.expression(constraint, bracketed))
+        yield self.expression(constraint, bracketed)

lib/telescope/sparql/select.py

         
         Each argument may be a variable or a sequence of variables, and each
         variable is converted to a `rdflib.Variable` instance using
-        `to_variable` (which means variables may be specified as `Expression`
-        instances or strings).
+        `to_variable` (which means variables may also be specified as strings
+        and `Expression` instances).
         
         If the keyword-only argument `add` is true, the specified variables will
         be added to the projection instead of replacing the current projection.

tests/test_compiler.py

             assert tokens_equal(output, '?x %s 2' % token)
 
 class CompilingSelectBase:
-    PREFIXES = "PREFIX foaf: <http://xmlns.com/foaf/0.1/>"
+    PREFIXES = ["PREFIX foaf: <http://xmlns.com/foaf/0.1/>",
+                "PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>"]
     
     def setup(self):
-        self.compiler = SelectCompiler({FOAF: 'foaf'})
+        self.compiler = SelectCompiler({FOAF: 'foaf', RDF: 'rdf'})
 
 class TestCompilingTriple(CompilingSelectBase):
-    def test_compiling_triple_outputs_three_terms(self):
-        triple = (v.x, FOAF.name, "Brian")
+    def test_compiling_outputs_whitespace_joined_terms(self):
+        triple = (v.x, FOAF.name, "Alice")
         assert tokens_equal(
-            self.compiler.triple(triple), '?x foaf:name "Brian"')
+            self.compiler.triple(triple), '?x foaf:name "Alice"'
+        )
+
+class TestCompilingTriplesSameSubject(CompilingSelectBase):
+    def test_compiling_outputs_semicolon_joined_predicate_object_pairs(self):
+        triples = TriplesSameSubject(v.x)[RDF.type: FOAF.Person,
+                                          FOAF.name: "Alice",
+                                          FOAF.mbox: v.mbox]
+        assert tokens_equal(
+            self.compiler.triples_same_subject(triples),
+            '?x rdf:type foaf:Person ; foaf:name "Alice" ; foaf:mbox ?mbox'
+        )
 
 class TestCompilingSelectModifiers(CompilingSelectBase):
     def test_compiling_distinct_outputs_distinct_keyword(self):