sparql 0.0.1 → 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- data/AUTHORS +3 -0
- data/CREDITS +0 -0
- data/README.markdown +103 -53
- data/UNLICENSE +24 -0
- data/VERSION +1 -0
- data/bin/sparql +87 -0
- data/lib/sparql.rb +105 -22
- data/lib/sparql/algebra.rb +369 -0
- data/lib/sparql/algebra/evaluatable.rb +37 -0
- data/lib/sparql/algebra/expression.rb +284 -0
- data/lib/sparql/algebra/extensions.rb +159 -0
- data/lib/sparql/algebra/operator.rb +492 -0
- data/lib/sparql/algebra/operator/add.rb +34 -0
- data/lib/sparql/algebra/operator/and.rb +65 -0
- data/lib/sparql/algebra/operator/asc.rb +29 -0
- data/lib/sparql/algebra/operator/ask.rb +46 -0
- data/lib/sparql/algebra/operator/base.rb +46 -0
- data/lib/sparql/algebra/operator/bgp.rb +26 -0
- data/lib/sparql/algebra/operator/bound.rb +48 -0
- data/lib/sparql/algebra/operator/compare.rb +84 -0
- data/lib/sparql/algebra/operator/construct.rb +85 -0
- data/lib/sparql/algebra/operator/dataset.rb +77 -0
- data/lib/sparql/algebra/operator/datatype.rb +42 -0
- data/lib/sparql/algebra/operator/desc.rb +17 -0
- data/lib/sparql/algebra/operator/describe.rb +71 -0
- data/lib/sparql/algebra/operator/distinct.rb +50 -0
- data/lib/sparql/algebra/operator/divide.rb +43 -0
- data/lib/sparql/algebra/operator/equal.rb +32 -0
- data/lib/sparql/algebra/operator/exprlist.rb +52 -0
- data/lib/sparql/algebra/operator/filter.rb +71 -0
- data/lib/sparql/algebra/operator/graph.rb +28 -0
- data/lib/sparql/algebra/operator/greater_than.rb +32 -0
- data/lib/sparql/algebra/operator/greater_than_or_equal.rb +33 -0
- data/lib/sparql/algebra/operator/is_blank.rb +35 -0
- data/lib/sparql/algebra/operator/is_iri.rb +37 -0
- data/lib/sparql/algebra/operator/is_literal.rb +36 -0
- data/lib/sparql/algebra/operator/join.rb +67 -0
- data/lib/sparql/algebra/operator/lang.rb +29 -0
- data/lib/sparql/algebra/operator/lang_matches.rb +53 -0
- data/lib/sparql/algebra/operator/left_join.rb +95 -0
- data/lib/sparql/algebra/operator/less_than.rb +32 -0
- data/lib/sparql/algebra/operator/less_than_or_equal.rb +32 -0
- data/lib/sparql/algebra/operator/minus.rb +31 -0
- data/lib/sparql/algebra/operator/multiply.rb +34 -0
- data/lib/sparql/algebra/operator/not.rb +35 -0
- data/lib/sparql/algebra/operator/not_equal.rb +26 -0
- data/lib/sparql/algebra/operator/or.rb +65 -0
- data/lib/sparql/algebra/operator/order.rb +69 -0
- data/lib/sparql/algebra/operator/plus.rb +31 -0
- data/lib/sparql/algebra/operator/prefix.rb +45 -0
- data/lib/sparql/algebra/operator/project.rb +46 -0
- data/lib/sparql/algebra/operator/reduced.rb +47 -0
- data/lib/sparql/algebra/operator/regex.rb +70 -0
- data/lib/sparql/algebra/operator/same_term.rb +46 -0
- data/lib/sparql/algebra/operator/slice.rb +60 -0
- data/lib/sparql/algebra/operator/str.rb +35 -0
- data/lib/sparql/algebra/operator/subtract.rb +32 -0
- data/lib/sparql/algebra/operator/union.rb +55 -0
- data/lib/sparql/algebra/query.rb +99 -0
- data/lib/sparql/algebra/sxp_extensions.rb +35 -0
- data/lib/sparql/algebra/version.rb +20 -0
- data/lib/sparql/extensions.rb +102 -0
- data/lib/sparql/grammar.rb +298 -0
- data/lib/sparql/grammar/lexer.rb +609 -0
- data/lib/sparql/grammar/parser.rb +1383 -0
- data/lib/sparql/grammar/parser/meta.rb +1801 -0
- data/lib/sparql/results.rb +220 -0
- data/lib/sparql/version.rb +20 -0
- metadata +232 -62
- data/Rakefile +0 -22
- data/coverage/index.html +0 -252
- data/coverage/lib-sparql-execute_sparql_rb.html +0 -621
- data/coverage/lib-sparql_rb.html +0 -622
- data/lib/sparql/execute_sparql.rb +0 -27
- data/lib/sparql/sparql.treetop +0 -159
- data/sparql.gemspec +0 -16
- data/spec/spec.opts +0 -2
- data/spec/spec_helper.rb +0 -24
- data/spec/unit/graph_parsing_spec.rb +0 -76
- data/spec/unit/iri_parsing_spec.rb +0 -46
- data/spec/unit/prefixed_names_parsing_spec.rb +0 -40
- data/spec/unit/primitives_parsing_spec.rb +0 -26
- data/spec/unit/sparql_parsing_spec.rb +0 -72
- data/spec/unit/variables_parsing_spec.rb +0 -36
@@ -0,0 +1,34 @@
|
|
1
|
+
module SPARQL; module Algebra
|
2
|
+
class Operator
|
3
|
+
include Evaluatable
|
4
|
+
|
5
|
+
##
|
6
|
+
# The SPARQL numeric `add` operator.
|
7
|
+
#
|
8
|
+
# @example
|
9
|
+
# (+ 1 ?x)
|
10
|
+
# (add 1 ?x)
|
11
|
+
#
|
12
|
+
# @see http://www.w3.org/TR/xpath-functions/#func-numeric-add
|
13
|
+
class Add < Operator::Binary
|
14
|
+
NAME = [:+, :add]
|
15
|
+
|
16
|
+
##
|
17
|
+
# Returns the arithmetic sum of the operands.
|
18
|
+
#
|
19
|
+
# @param [RDF::Literal::Numeric] left
|
20
|
+
# a numeric literal
|
21
|
+
# @param [RDF::Literal::Numeric] right
|
22
|
+
# a numeric literal
|
23
|
+
# @return [RDF::Literal::Numeric]
|
24
|
+
# @raise [TypeError] if either operand is not a numeric literal
|
25
|
+
def apply(left, right)
|
26
|
+
case
|
27
|
+
when left.is_a?(RDF::Literal::Numeric) && right.is_a?(RDF::Literal::Numeric)
|
28
|
+
left + right
|
29
|
+
else raise TypeError, "expected two RDF::Literal::Numeric operands, but got #{left.inspect} and #{right.inspect}"
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end # Add
|
33
|
+
end # Operator
|
34
|
+
end; end # SPARQL::Algebra
|
@@ -0,0 +1,65 @@
|
|
1
|
+
module SPARQL; module Algebra
|
2
|
+
class Operator
|
3
|
+
##
|
4
|
+
# The SPARQL logical `and` operator.
|
5
|
+
#
|
6
|
+
# @example
|
7
|
+
# (&& ?x ?y)
|
8
|
+
# (and ?x ?y)
|
9
|
+
#
|
10
|
+
# @see http://www.w3.org/TR/rdf-sparql-query/#func-logical-and
|
11
|
+
# @see http://www.w3.org/TR/rdf-sparql-query/#evaluation
|
12
|
+
class And < Operator::Binary
|
13
|
+
include Evaluatable
|
14
|
+
|
15
|
+
NAME = [:and, :'&&']
|
16
|
+
|
17
|
+
##
|
18
|
+
# Initializes a new operator instance.
|
19
|
+
#
|
20
|
+
# @param [RDF::Literal::Boolean] left
|
21
|
+
# the left operand
|
22
|
+
# @param [RDF::Literal::Boolean] right
|
23
|
+
# the right operand
|
24
|
+
# @param [Hash{Symbol => Object}] options
|
25
|
+
# any additional options (see {Operator#initialize})
|
26
|
+
# @raise [TypeError] if any operand is invalid
|
27
|
+
def initialize(left, right, options = {})
|
28
|
+
super
|
29
|
+
end
|
30
|
+
|
31
|
+
##
|
32
|
+
# Returns the logical `AND` of the left operand and the right operand.
|
33
|
+
#
|
34
|
+
# Note that this operator operates on the effective boolean value
|
35
|
+
# (EBV) of its operands.
|
36
|
+
#
|
37
|
+
# @param [RDF::Query::Solution, #[]] bindings
|
38
|
+
# @return [RDF::Literal::Boolean] `true` or `false`
|
39
|
+
# @raise [TypeError] if the operands could not be coerced to boolean literals
|
40
|
+
def evaluate(bindings = {})
|
41
|
+
begin
|
42
|
+
left = boolean(operand(0).evaluate(bindings)).true?
|
43
|
+
rescue TypeError
|
44
|
+
left = nil
|
45
|
+
end
|
46
|
+
|
47
|
+
begin
|
48
|
+
right = boolean(operand(1).evaluate(bindings)).true?
|
49
|
+
rescue TypeError
|
50
|
+
right = nil
|
51
|
+
end
|
52
|
+
|
53
|
+
# From http://www.w3.org/TR/rdf-sparql-query/#evaluation
|
54
|
+
# A logical-and that encounters an error on only one branch will return an error if the other branch is
|
55
|
+
# TRUE and FALSE if the other branch is FALSE.
|
56
|
+
case
|
57
|
+
when left.nil? && right.nil? then raise(TypeError)
|
58
|
+
when left.nil? then right ? raise(TypeError) : RDF::Literal::FALSE
|
59
|
+
when right.nil? then left ? raise(TypeError) : RDF::Literal::FALSE
|
60
|
+
else RDF::Literal(left && right)
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end # And
|
64
|
+
end # Operator
|
65
|
+
end; end # SPARQL::Algebra
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module SPARQL; module Algebra
|
2
|
+
class Operator
|
3
|
+
##
|
4
|
+
# The SPARQL ascending sort operator.
|
5
|
+
#
|
6
|
+
# @example
|
7
|
+
# (prefix ((foaf: <http://xmlns.com/foaf/0.1/>))
|
8
|
+
# (project (?name)
|
9
|
+
# (order ((asc ?name))
|
10
|
+
# (bgp (triple ?x foaf:name ?name)))))
|
11
|
+
#
|
12
|
+
# @see http://www.w3.org/TR/rdf-sparql-query/#func-isLiteral
|
13
|
+
class Asc < Operator::Unary
|
14
|
+
include Evaluatable
|
15
|
+
|
16
|
+
NAME = :asc
|
17
|
+
|
18
|
+
##
|
19
|
+
# Returns the evaluation of it's operand. Default comparison is in
|
20
|
+
# ascending order. Ordering is applied in {Order}.
|
21
|
+
#
|
22
|
+
# @param [RDF::Query::Solution, #[]] bindings
|
23
|
+
# @return [RDF::Term]
|
24
|
+
def evaluate(bindings = {})
|
25
|
+
operand(0).evaluate(bindings)
|
26
|
+
end
|
27
|
+
end # Asc
|
28
|
+
end # Operator
|
29
|
+
end; end # SPARQL::Algebra
|
@@ -0,0 +1,46 @@
|
|
1
|
+
module SPARQL; module Algebra
|
2
|
+
class Operator
|
3
|
+
##
|
4
|
+
# The SPARQL GraphPattern `ask` operator.
|
5
|
+
#
|
6
|
+
# @example
|
7
|
+
# (prefix ((: <http://example/>))
|
8
|
+
# (ask
|
9
|
+
# (bgp (triple :x :p ?x))))
|
10
|
+
#
|
11
|
+
# @see http://www.w3.org/TR/rdf-sparql-query/#ask
|
12
|
+
class Ask < Operator::Unary
|
13
|
+
include Query
|
14
|
+
|
15
|
+
NAME = [:ask]
|
16
|
+
|
17
|
+
##
|
18
|
+
# Executes this query on the given `queryable` graph or repository.
|
19
|
+
# Returns true if any solutions are found, false otherwise.
|
20
|
+
#
|
21
|
+
# @param [RDF::Queryable] queryable
|
22
|
+
# the graph or repository to query
|
23
|
+
# @param [Hash{Symbol => Object}] options
|
24
|
+
# any additional keyword options
|
25
|
+
# @return [RDF::Literal::Boolean]
|
26
|
+
# the resulting solution sequence
|
27
|
+
# @see http://www.w3.org/TR/rdf-sparql-query/#sparqlAlgebra
|
28
|
+
def execute(queryable, options = {})
|
29
|
+
debug(options) {"Ask #{operands.first}"}
|
30
|
+
boolean(!operands.last.
|
31
|
+
execute(queryable, options.merge(:depth => options[:depth].to_i + 1)).
|
32
|
+
empty?)
|
33
|
+
end
|
34
|
+
|
35
|
+
##
|
36
|
+
# Returns an optimized version of this query.
|
37
|
+
#
|
38
|
+
# Return optimized query
|
39
|
+
#
|
40
|
+
# @return [Union, RDF::Query] `self`
|
41
|
+
def optimize
|
42
|
+
operands = operands.map(&:optimize)
|
43
|
+
end
|
44
|
+
end # Ask
|
45
|
+
end # Operator
|
46
|
+
end; end # SPARQL::Algebra
|
@@ -0,0 +1,46 @@
|
|
1
|
+
module SPARQL; module Algebra
|
2
|
+
class Operator
|
3
|
+
##
|
4
|
+
# The SPARQL GraphPattern `base` operator.
|
5
|
+
#
|
6
|
+
# @example
|
7
|
+
# (base <http://example.org/>
|
8
|
+
# (bgp (triple <a> <b> 123.0)))
|
9
|
+
#
|
10
|
+
# @see http://www.w3.org/TR/rdf-sparql-query/#QSynIRI
|
11
|
+
class Base < Binary
|
12
|
+
include Query
|
13
|
+
|
14
|
+
NAME = [:base]
|
15
|
+
|
16
|
+
##
|
17
|
+
# Executes this query on the given `queryable` graph or repository.
|
18
|
+
# Really a pass-through, as this is a syntactic object used for providing
|
19
|
+
# context for relative URIs.
|
20
|
+
#
|
21
|
+
# @param [RDF::Queryable] queryable
|
22
|
+
# the graph or repository to query
|
23
|
+
# @param [Hash{Symbol => Object}] options
|
24
|
+
# any additional keyword options
|
25
|
+
# @return [RDF::Query::Solutions]
|
26
|
+
# the resulting solution sequence
|
27
|
+
# @see http://www.w3.org/TR/rdf-sparql-query/#sparqlAlgebra
|
28
|
+
def execute(queryable, options = {})
|
29
|
+
debug(options) {"Base #{operands.first}"}
|
30
|
+
@solutions = operands.last.execute(queryable, options.merge(:depth => options[:depth].to_i + 1))
|
31
|
+
debug(options) {"=> #{@solutions.inspect}"}
|
32
|
+
@solutions
|
33
|
+
end
|
34
|
+
|
35
|
+
##
|
36
|
+
# Returns an optimized version of this query.
|
37
|
+
#
|
38
|
+
# Return optimized query
|
39
|
+
#
|
40
|
+
# @return [Union, RDF::Query] `self`
|
41
|
+
def optimize
|
42
|
+
operands.last.optimize
|
43
|
+
end
|
44
|
+
end # Base
|
45
|
+
end # Operator
|
46
|
+
end; end # SPARQL::Algebra
|
@@ -0,0 +1,26 @@
|
|
1
|
+
module SPARQL; module Algebra
|
2
|
+
class Operator
|
3
|
+
##
|
4
|
+
# The SPARQL GraphPattern `bgp` operator.
|
5
|
+
#
|
6
|
+
# Query with `context` set to false.
|
7
|
+
#
|
8
|
+
# @example
|
9
|
+
# (prefix ((: <http://example/>))
|
10
|
+
# (bgp (triple ?s ?p ?o)))
|
11
|
+
#
|
12
|
+
# @see http://www.w3.org/TR/rdf-sparql-query/#sparqlAlgebra
|
13
|
+
class BGP < Operator
|
14
|
+
NAME = [:bgp]
|
15
|
+
##
|
16
|
+
# A `graph` is an RDF::Query with a context.
|
17
|
+
#
|
18
|
+
# @param [RDF::URI, RDF::Query::Variable] context
|
19
|
+
# @param [RDF::Query] bgp
|
20
|
+
# @return [RDF::Query]
|
21
|
+
def self.new(*patterns)
|
22
|
+
RDF::Query.new(*(patterns + [{:context => false}]))
|
23
|
+
end
|
24
|
+
end # BGP
|
25
|
+
end # Operator
|
26
|
+
end; end # SPARQL::Algebra
|
@@ -0,0 +1,48 @@
|
|
1
|
+
module SPARQL; module Algebra
|
2
|
+
class Operator
|
3
|
+
##
|
4
|
+
# The SPARQL `bound` operator.
|
5
|
+
#
|
6
|
+
# @example
|
7
|
+
# (prefix ((: <http://example.org/ns#>))
|
8
|
+
# (project (?a ?c)
|
9
|
+
# (filter (! (bound ?e))
|
10
|
+
# (leftjoin
|
11
|
+
# (bgp (triple ?a :b ?c))
|
12
|
+
# (bgp (triple ?c :d ?e))))))
|
13
|
+
#
|
14
|
+
# @see http://www.w3.org/TR/rdf-sparql-query/#func-bound
|
15
|
+
class Bound < Operator::Unary
|
16
|
+
include Evaluatable
|
17
|
+
|
18
|
+
NAME = :bound
|
19
|
+
|
20
|
+
##
|
21
|
+
# Initializes a new operator instance.
|
22
|
+
#
|
23
|
+
# @param [RDF::Query::Variable] var
|
24
|
+
# a variable
|
25
|
+
# @param [Hash{Symbol => Object}] options
|
26
|
+
# any additional options (see {Operator#initialize})
|
27
|
+
# @raise [TypeError] if any operand is invalid
|
28
|
+
def initialize(var, options = {})
|
29
|
+
super
|
30
|
+
end
|
31
|
+
|
32
|
+
##
|
33
|
+
# Returns `true` if the operand is a variable that is bound to a
|
34
|
+
# value in the given `bindings`, `false` otherwise.
|
35
|
+
#
|
36
|
+
# @param [RDF::Query::Solution, #[]] bindings
|
37
|
+
# @return [RDF::Literal::Boolean] `true` or `false`
|
38
|
+
# @raise [TypeError] if the operand is not a variable
|
39
|
+
def evaluate(bindings = {})
|
40
|
+
case var = operand
|
41
|
+
when Variable
|
42
|
+
operand.evaluate(bindings) ? RDF::Literal::TRUE : RDF::Literal::FALSE
|
43
|
+
else raise TypeError, "expected an RDF::Query::Variable, but got #{var.inspect}"
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end # Bound
|
47
|
+
end # Operator
|
48
|
+
end; end # SPARQL::Algebra
|
@@ -0,0 +1,84 @@
|
|
1
|
+
module SPARQL; module Algebra
|
2
|
+
class Operator
|
3
|
+
##
|
4
|
+
# A SPARQL relational `<=>` comparison operator.
|
5
|
+
#
|
6
|
+
# @example
|
7
|
+
# (<=> ?x ?y)
|
8
|
+
#
|
9
|
+
# @see http://www.w3.org/TR/rdf-sparql-query/#OperatorMapping
|
10
|
+
# @see http://www.w3.org/TR/xpath-functions/#func-compare
|
11
|
+
class Compare < Operator::Binary
|
12
|
+
include Evaluatable
|
13
|
+
|
14
|
+
NAME = :<=>
|
15
|
+
|
16
|
+
##
|
17
|
+
# Returns -1, 0, or 1, depending on whether the first operand is
|
18
|
+
# respectively less than, equal to, or greater than the second
|
19
|
+
# operand.
|
20
|
+
#
|
21
|
+
# SPARQL also fixes an order between some kinds of RDF terms that would not otherwise be ordered:
|
22
|
+
#
|
23
|
+
# (Lowest) no value assigned to the variable or expression in this solution.
|
24
|
+
# Blank nodes
|
25
|
+
# IRIs
|
26
|
+
# RDF literals
|
27
|
+
#
|
28
|
+
# @param [RDF::Literal] left
|
29
|
+
# a literal
|
30
|
+
# @param [RDF::Literal] right
|
31
|
+
# a literal
|
32
|
+
# @return [RDF::Literal::Integer] `-1`, `0`, or `1`
|
33
|
+
# @raise [TypeError] if either operand is not a literal
|
34
|
+
def apply(left, right)
|
35
|
+
case
|
36
|
+
# @see http://www.w3.org/TR/rdf-sparql-query/#OperatorMapping
|
37
|
+
# @see http://www.w3.org/TR/rdf-sparql-query/#modOrderBy
|
38
|
+
when left.is_a?(RDF::Literal) && right.is_a?(RDF::Literal)
|
39
|
+
case
|
40
|
+
# @see http://www.w3.org/TR/xpath-functions/#string-compare
|
41
|
+
# @see http://www.w3.org/TR/xpath-functions/#comp.numeric
|
42
|
+
# @see http://www.w3.org/TR/xpath-functions/#op.boolean
|
43
|
+
# @see http://www.w3.org/TR/xpath-functions/#comp.duration.datetime
|
44
|
+
when (left.simple? && right.simple?) ||
|
45
|
+
(left.is_a?(RDF::Literal::Numeric) && right.is_a?(RDF::Literal::Numeric)) ||
|
46
|
+
(left.datatype == right.datatype && left.language == right.language)
|
47
|
+
RDF::Literal(left.send(self.class.const_get(:NAME), right))
|
48
|
+
|
49
|
+
# A plain literal is lower than an RDF literal with type xsd:string of the same lexical form.
|
50
|
+
when left.simple? && right.datatype == RDF::XSD.string && left.value == right.value
|
51
|
+
RDF::Literal(-1)
|
52
|
+
when right.simple? && left.datatype == RDF::XSD.string && right.value == left.value
|
53
|
+
RDF::Literal(-1)
|
54
|
+
|
55
|
+
else raise TypeError, "unable to compare #{left.inspect} and #{right.inspect}"
|
56
|
+
end
|
57
|
+
|
58
|
+
when left.is_a?(RDF::URI) && right.is_a?(RDF::URI)
|
59
|
+
# Pairs of IRIs are ordered by comparing them as simple literals.
|
60
|
+
RDF::Literal(RDF::Literal(left.to_s).send(self.class.const_get(:NAME), RDF::Literal(right.to_s)))
|
61
|
+
when left.is_a?(RDF::Node) && right.is_a?(RDF::Node)
|
62
|
+
# BNode comparison is undefined.
|
63
|
+
RDF::Literal(0)
|
64
|
+
when left.nil? && right.nil?
|
65
|
+
RDF::Literal(0)
|
66
|
+
|
67
|
+
# SPARQL also fixes an order between some kinds of RDF terms that would not otherwise be ordered:
|
68
|
+
# 2. Blank nodes
|
69
|
+
when left.is_a?(RDF::Node) && right.is_a?(RDF::Term)
|
70
|
+
RDF::Literal(-1)
|
71
|
+
when right.is_a?(RDF::Node) && left.is_a?(RDF::Term)
|
72
|
+
RDF::Literal(1)
|
73
|
+
|
74
|
+
# 3. IRIs
|
75
|
+
when left.is_a?(RDF::URI) && right.is_a?(RDF::Term)
|
76
|
+
RDF::Literal(-1)
|
77
|
+
when right.is_a?(RDF::URI) && left.is_a?(RDF::Term)
|
78
|
+
RDF::Literal(1)
|
79
|
+
else raise TypeError, "expected two RDF::Term operands, but got #{left.inspect} and #{right.inspect}"
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end # Compare
|
83
|
+
end # Operator
|
84
|
+
end; end # SPARQL::Algebra
|
@@ -0,0 +1,85 @@
|
|
1
|
+
module SPARQL; module Algebra
|
2
|
+
class Operator
|
3
|
+
##
|
4
|
+
# The SPARQL GraphPattern `construct` operator.
|
5
|
+
#
|
6
|
+
# @example
|
7
|
+
# (prefix ((rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>)
|
8
|
+
# (foaf: <http://xmlns.com/foaf/0.1/>))
|
9
|
+
# (construct ((triple ?s ?p ?o))
|
10
|
+
# (project (?s ?p ?o)
|
11
|
+
# (bgp (triple ?s ?p ?o)))))
|
12
|
+
#
|
13
|
+
# @see http://www.w3.org/TR/rdf-sparql-query/#ask
|
14
|
+
class Construct < Operator::Binary
|
15
|
+
include Query
|
16
|
+
|
17
|
+
NAME = [:construct]
|
18
|
+
|
19
|
+
##
|
20
|
+
# Executes this query on the given {RDF::Queryable} object.
|
21
|
+
# Binds variables to the array of patterns in the first operand and returns the resulting RDF::Graph object
|
22
|
+
#
|
23
|
+
# If any such instantiation produces a triple containing an unbound variable or an illegal RDF construct,
|
24
|
+
# such as an RDF::Literal in _subject_ or _predicate_ position, then that triple is not included in the output RDF
|
25
|
+
# graph. The graph template can contain triples with no variables (known as ground or explicit triples),
|
26
|
+
# and these also appear in the output RDF graph returned by the CONSTRUCT query form.
|
27
|
+
#
|
28
|
+
# @param [RDF::Queryable] queryable
|
29
|
+
# the graph or repository to query
|
30
|
+
# @param [Hash{Symbol => Object}] options
|
31
|
+
# any additional keyword options
|
32
|
+
# @return [RDF::Query::Solutions]
|
33
|
+
# the resulting solution sequence
|
34
|
+
# @see http://www.w3.org/TR/rdf-sparql-query/#construct
|
35
|
+
def execute(queryable, options = {})
|
36
|
+
debug(options) {"Construct #{operands.first}, #{options.inspect}"}
|
37
|
+
graph = RDF::Graph.new
|
38
|
+
patterns = operands.first
|
39
|
+
query = operands.last
|
40
|
+
|
41
|
+
query.execute(queryable, options.merge(:depth => options[:depth].to_i + 1)).each do |solution|
|
42
|
+
debug(options) {"=> Apply #{solution.inspect} to BGP"}
|
43
|
+
|
44
|
+
# Create a mapping from BNodes within the pattern list to newly constructed BNodes
|
45
|
+
nodes = {}
|
46
|
+
patterns.each do |pattern|
|
47
|
+
terms = {}
|
48
|
+
[:subject, :predicate, :object].each do |r|
|
49
|
+
terms[r] = case o = pattern.send(r)
|
50
|
+
when RDF::Node then nodes[o] ||= RDF::Node.new
|
51
|
+
when RDF::Query::Variable then solution[o]
|
52
|
+
else o
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
statement = RDF::Statement.from(terms)
|
57
|
+
|
58
|
+
# Sanity checking on statement
|
59
|
+
if statement.subject.nil? || statement.predicate.nil? || statement.object.nil? ||
|
60
|
+
statement.subject.literal? || statement.predicate.literal?
|
61
|
+
debug(options) {"==> skip #{statement.inspect}"}
|
62
|
+
next
|
63
|
+
end
|
64
|
+
|
65
|
+
debug(options) {"==> add #{statement.inspect}"}
|
66
|
+
graph << statement
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
debug(options) {"=>\n#{graph.dump(:ttl, :standard_prefixes => true)}"}
|
71
|
+
graph
|
72
|
+
end
|
73
|
+
|
74
|
+
##
|
75
|
+
# Returns an optimized version of this query.
|
76
|
+
#
|
77
|
+
# Return optimized query
|
78
|
+
#
|
79
|
+
# @return [Union, RDF::Query] `self`
|
80
|
+
def optimize
|
81
|
+
operands = operands.map(&:optimize)
|
82
|
+
end
|
83
|
+
end # Construct
|
84
|
+
end # Operator
|
85
|
+
end; end # SPARQL::Algebra
|