sparql 0.0.1 → 0.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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,77 @@
|
|
1
|
+
module SPARQL; module Algebra
|
2
|
+
class Operator
|
3
|
+
##
|
4
|
+
# The SPARQL GraphPattern `dataset` operator.
|
5
|
+
#
|
6
|
+
# Instintiated with two operands, the first being an array of data source URIs,
|
7
|
+
# either bare, indicating a default dataset, or expressed as an array [:named, <uri>],
|
8
|
+
# indicating that it represents a named data source.
|
9
|
+
#
|
10
|
+
# @example
|
11
|
+
# (prefix ((: <http://example/>))
|
12
|
+
# (dataset (<data-g1.ttl> (named <data-g2.ttl>))
|
13
|
+
# (bgp (triple ?s ?p ?o))))
|
14
|
+
#
|
15
|
+
# @see http://www.w3.org/TR/rdf-sparql-query/#specifyingDataset
|
16
|
+
class Dataset < Binary
|
17
|
+
include Query
|
18
|
+
|
19
|
+
NAME = [:dataset]
|
20
|
+
|
21
|
+
##
|
22
|
+
# Executes this query on the given `queryable` graph or repository.
|
23
|
+
# Reads specified data sources into queryable. Named data sources
|
24
|
+
# are added using a _context_ of the data source URI.
|
25
|
+
#
|
26
|
+
# Datasets are specified in operand(1), which is an array of default or named graph URIs.
|
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/#sparqlAlgebra
|
35
|
+
def execute(queryable, options = {})
|
36
|
+
debug(options) {"Dataset"}
|
37
|
+
operand(0).each do |ds|
|
38
|
+
load_opts = {}
|
39
|
+
case ds
|
40
|
+
when Array
|
41
|
+
# Format is (named <uri>), only need the URI part
|
42
|
+
uri = if self.base_uri
|
43
|
+
u = self.base_uri.join(ds.last)
|
44
|
+
u.lexical = "<#{ds.last}>" unless u.to_s == ds.last.to_s
|
45
|
+
u
|
46
|
+
else
|
47
|
+
ds.last
|
48
|
+
end
|
49
|
+
uri = self.base_uri ? self.base_uri.join(ds.last) : ds.last
|
50
|
+
uri.lexical = ds.last
|
51
|
+
load_opts[:context] = uri
|
52
|
+
debug(options) {"=> read named data source #{uri}"}
|
53
|
+
else
|
54
|
+
debug(options) {"=> array: join #{self.base_uri.inspect} to #{ds.inspect}"}
|
55
|
+
uri = self.base_uri ? self.base_uri.join(ds) : ds
|
56
|
+
debug(options) {"=> read default data source #{uri}"}
|
57
|
+
end
|
58
|
+
load_opts[:base_uri] = uri
|
59
|
+
queryable.load(uri.to_s, load_opts)
|
60
|
+
end
|
61
|
+
|
62
|
+
@solutions = operands.last.execute(queryable, options.merge(:depth => options[:depth].to_i + 1))
|
63
|
+
end
|
64
|
+
|
65
|
+
##
|
66
|
+
# Returns an optimized version of this query.
|
67
|
+
#
|
68
|
+
# If optimize operands, and if the first two operands are both Queries, replace
|
69
|
+
# with the unique sum of the query elements
|
70
|
+
#
|
71
|
+
# @return [Union, RDF::Query] `self`
|
72
|
+
def optimize
|
73
|
+
operands.last.optimize
|
74
|
+
end
|
75
|
+
end # Dataset
|
76
|
+
end # Operator
|
77
|
+
end; end # SPARQL::Algebra
|
@@ -0,0 +1,42 @@
|
|
1
|
+
module SPARQL; module Algebra
|
2
|
+
class Operator
|
3
|
+
##
|
4
|
+
# The SPARQL `datatype` operator.
|
5
|
+
#
|
6
|
+
# @example
|
7
|
+
# (prefix ((xsd: <http://www.w3.org/2001/XMLSchema#>)
|
8
|
+
# (rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>)
|
9
|
+
# (: <http://example.org/>))
|
10
|
+
# (project (?s)
|
11
|
+
# (filter (= (datatype (xsd:double ?v)) xsd:double)
|
12
|
+
# (bgp (triple ?s :p ?v)))))
|
13
|
+
#
|
14
|
+
# @see http://www.w3.org/TR/rdf-sparql-query/#func-datatype
|
15
|
+
class Datatype < Operator::Unary
|
16
|
+
include Evaluatable
|
17
|
+
|
18
|
+
NAME = :datatype
|
19
|
+
|
20
|
+
##
|
21
|
+
# Returns the datatype IRI of the operand.
|
22
|
+
#
|
23
|
+
# If the operand is a simple literal, returns a datatype of
|
24
|
+
# `xsd:string`.
|
25
|
+
#
|
26
|
+
# @param [RDF::Literal] literal
|
27
|
+
# a typed or simple literal
|
28
|
+
# @return [RDF::URI] the datatype IRI, or `xsd:string` for simple literals
|
29
|
+
# @raise [TypeError] if the operand is not a typed or simple literal
|
30
|
+
def apply(literal)
|
31
|
+
case literal
|
32
|
+
when RDF::Literal then case
|
33
|
+
when literal.typed? then RDF::URI(literal.datatype)
|
34
|
+
when literal.simple? then RDF::XSD.string
|
35
|
+
else raise TypeError, "expected a typed or simple RDF::Literal, but got #{literal.inspect}"
|
36
|
+
end
|
37
|
+
else raise TypeError, "expected an RDF::Literal, but got #{literal.inspect}"
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end # Datatype
|
41
|
+
end # Operator
|
42
|
+
end; end # SPARQL::Algebra
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module SPARQL; module Algebra
|
2
|
+
class Operator
|
3
|
+
##
|
4
|
+
# The SPARQL descending sort operator.
|
5
|
+
#
|
6
|
+
# @example
|
7
|
+
# (prefix ((foaf: <http://xmlns.com/foaf/0.1/>))
|
8
|
+
# (project (?name)
|
9
|
+
# (order ((desc ?name))
|
10
|
+
# (bgp (triple ?x foaf:name ?name)))))
|
11
|
+
#
|
12
|
+
# @see http://www.w3.org/TR/rdf-sparql-query/#func-isLiteral
|
13
|
+
class Desc < Operator::Asc
|
14
|
+
NAME = :desc
|
15
|
+
end # Desc
|
16
|
+
end # Operator
|
17
|
+
end; end # SPARQL::Algebra
|
@@ -0,0 +1,71 @@
|
|
1
|
+
module SPARQL; module Algebra
|
2
|
+
class Operator
|
3
|
+
##
|
4
|
+
# The SPARQL GraphPattern `describe` operator.
|
5
|
+
#
|
6
|
+
# Generages a graph across specified terms using {RDF::Queryable}`#concise_bounded_description`.
|
7
|
+
#
|
8
|
+
# @example
|
9
|
+
# (prefix ((exOrg: <http://org.example.com/employees#>))
|
10
|
+
# (describe (?x)
|
11
|
+
# (bgp (triple ?x exOrg:employeeId "1234"))))
|
12
|
+
#
|
13
|
+
# @see http://www.w3.org/TR/rdf-sparql-query/#describe
|
14
|
+
class Describe < Operator::Binary
|
15
|
+
include Query
|
16
|
+
|
17
|
+
NAME = [:describe]
|
18
|
+
|
19
|
+
##
|
20
|
+
# Executes this query on the given {RDF::Queryable} object.
|
21
|
+
# Generates a graph containing the Concise Bounded Description
|
22
|
+
# variables and URIs listed in the first operand.
|
23
|
+
#
|
24
|
+
# @example
|
25
|
+
# (describe (<http://example/>))
|
26
|
+
#
|
27
|
+
# @example
|
28
|
+
# (prefix ((foaf: <http://xmlns.com/foaf/0.1/>))
|
29
|
+
# (describe (?x)
|
30
|
+
# (bgp (triple ?x foaf:mbox <mailto:alice@org>))))
|
31
|
+
#
|
32
|
+
# @param [RDF::Queryable] queryable
|
33
|
+
# the graph or repository to query
|
34
|
+
# @param [Hash{Symbol => Object}] options
|
35
|
+
# any additional keyword options
|
36
|
+
# @return [RDF::Query::Solutions]
|
37
|
+
# the resulting solution sequence
|
38
|
+
# @see http://www.w3.org/TR/rdf-sparql-query/#describe
|
39
|
+
def execute(queryable, options = {})
|
40
|
+
debug(options) {"Describe #{operands.first}, #{options.inspect}"}
|
41
|
+
|
42
|
+
# Describe any constand URIs
|
43
|
+
to_describe = operands.first.select {|t| t.uri?}
|
44
|
+
|
45
|
+
to_describe.each {|t| debug(options) {"=> describe #{t}"}}
|
46
|
+
|
47
|
+
operands.last.execute(queryable).each do |solution|
|
48
|
+
solution.each_variable do |v|
|
49
|
+
if operands.first.any? {|bound| v.eql?(bound)}
|
50
|
+
debug(options) {"=> describe #{v}"}
|
51
|
+
to_describe << v.value
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
# Return Concise Bounded Description
|
57
|
+
queryable.concise_bounded_description(*to_describe)
|
58
|
+
end
|
59
|
+
|
60
|
+
##
|
61
|
+
# Returns an optimized version of this query.
|
62
|
+
#
|
63
|
+
# Return optimized query
|
64
|
+
#
|
65
|
+
# @return [Union, RDF::Query] `self`
|
66
|
+
def optimize
|
67
|
+
operands = operands.map(&:optimize)
|
68
|
+
end
|
69
|
+
end # Construct
|
70
|
+
end # Operator
|
71
|
+
end; end # SPARQL::Algebra
|
@@ -0,0 +1,50 @@
|
|
1
|
+
module SPARQL; module Algebra
|
2
|
+
class Operator
|
3
|
+
##
|
4
|
+
# The SPARQL GraphPattern `distinct` operator.
|
5
|
+
#
|
6
|
+
# @example
|
7
|
+
# (prefix ((xsd: <http://www.w3.org/2001/XMLSchema#>)
|
8
|
+
# (: <http://example/>))
|
9
|
+
# (distinct
|
10
|
+
# (project (?v)
|
11
|
+
# (bgp (triple ?x ?p ?v)))))
|
12
|
+
#
|
13
|
+
# @see http://www.w3.org/TR/rdf-sparql-query/#sparqlAlgebra
|
14
|
+
class Distinct < Operator::Unary
|
15
|
+
include Query
|
16
|
+
|
17
|
+
NAME = [:distinct]
|
18
|
+
|
19
|
+
##
|
20
|
+
# Executes this query on the given `queryable` graph or repository.
|
21
|
+
# Removes duplicate solutions from the solution set.
|
22
|
+
#
|
23
|
+
# @param [RDF::Queryable] queryable
|
24
|
+
# the graph or repository to query
|
25
|
+
# @param [Hash{Symbol => Object}] options
|
26
|
+
# any additional keyword options
|
27
|
+
# @return [RDF::Query::Solutions]
|
28
|
+
# the resulting solution sequence
|
29
|
+
# @see http://www.w3.org/TR/rdf-sparql-query/#sparqlAlgebra
|
30
|
+
def execute(queryable, options = {})
|
31
|
+
debug(options) {"Distinct"}
|
32
|
+
@solutions = operands.last.execute(queryable, options.merge(:depth => options[:depth].to_i + 1))
|
33
|
+
debug(options) {"=>(before) #{@solutions.inspect}"}
|
34
|
+
@solutions = @solutions.distinct
|
35
|
+
debug(options) {"=>(after) #{@solutions.inspect}"}
|
36
|
+
@solutions
|
37
|
+
end
|
38
|
+
|
39
|
+
##
|
40
|
+
# Returns an optimized version of this query.
|
41
|
+
#
|
42
|
+
# Return optimized query
|
43
|
+
#
|
44
|
+
# @return [Union, RDF::Query] `self`
|
45
|
+
def optimize
|
46
|
+
operands = operands.map(&:optimize)
|
47
|
+
end
|
48
|
+
end # Distinct
|
49
|
+
end # Operator
|
50
|
+
end; end # SPARQL::Algebra
|
@@ -0,0 +1,43 @@
|
|
1
|
+
module SPARQL; module Algebra
|
2
|
+
class Operator
|
3
|
+
##
|
4
|
+
# The SPARQL numeric `divide` operator.
|
5
|
+
#
|
6
|
+
# @example
|
7
|
+
# (/ 4 2)
|
8
|
+
#
|
9
|
+
# @see http://www.w3.org/TR/xpath-functions/#func-numeric-divide
|
10
|
+
class Divide < Operator::Binary
|
11
|
+
include Evaluatable
|
12
|
+
|
13
|
+
NAME = [:'/', :divide]
|
14
|
+
|
15
|
+
##
|
16
|
+
# Returns the arithmetic quotient of the operands.
|
17
|
+
#
|
18
|
+
# @param [RDF::Literal::Numeric] left
|
19
|
+
# a numeric literal
|
20
|
+
# @param [RDF::Literal::Numeric] right
|
21
|
+
# a numeric literal
|
22
|
+
# @return [RDF::Literal::Numeric]
|
23
|
+
# @raise [TypeError] if either operand is not a numeric literal
|
24
|
+
def apply(left, right)
|
25
|
+
case
|
26
|
+
when left.is_a?(RDF::Literal::Numeric) && right.is_a?(RDF::Literal::Numeric)
|
27
|
+
# For xsd:decimal and xsd:integer operands, if the divisor is
|
28
|
+
# (positive or negative) zero, an error is raised.
|
29
|
+
raise ZeroDivisionError, "divided by #{right}" if left.is_a?(RDF::Literal::Decimal) && right.zero?
|
30
|
+
|
31
|
+
# As a special case, if the types of both operands are
|
32
|
+
# xsd:integer, then the return type is xsd:decimal.
|
33
|
+
if left.is_a?(RDF::Literal::Integer) && right.is_a?(RDF::Literal::Integer)
|
34
|
+
RDF::Literal(left.to_d / right.to_d)
|
35
|
+
else
|
36
|
+
left / right
|
37
|
+
end
|
38
|
+
else raise TypeError, "expected two RDF::Literal::Numeric operands, but got #{left.inspect} and #{right.inspect}"
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end # Divide
|
42
|
+
end # Operator
|
43
|
+
end; end # SPARQL::Algebra
|
@@ -0,0 +1,32 @@
|
|
1
|
+
module SPARQL; module Algebra
|
2
|
+
class Operator
|
3
|
+
##
|
4
|
+
# The SPARQL relational `=` (equal) 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/rdf-sparql-query/#func-RDFterm-equal
|
11
|
+
class Equal < Compare
|
12
|
+
NAME = :'='
|
13
|
+
|
14
|
+
##
|
15
|
+
# Returns `true` if the operands are equal; returns `false` otherwise.
|
16
|
+
#
|
17
|
+
# @param [RDF::Term] term1
|
18
|
+
# an RDF term
|
19
|
+
# @param [RDF::Term] term2
|
20
|
+
# an RDF term
|
21
|
+
# @return [RDF::Literal::Boolean] `true` or `false`
|
22
|
+
# @raise [TypeError] if either operand is not an RDF term or operands are not comperable
|
23
|
+
#
|
24
|
+
# @see {RDF::Term#==}
|
25
|
+
def apply(term1, term2)
|
26
|
+
term1 = term1.dup.extend(RDF::TypeCheck)
|
27
|
+
term2 = term2.dup.extend(RDF::TypeCheck)
|
28
|
+
RDF::Literal(term1 == term2)
|
29
|
+
end
|
30
|
+
end # Equal
|
31
|
+
end # Operator
|
32
|
+
end; end # SPARQL::Algebra
|
@@ -0,0 +1,52 @@
|
|
1
|
+
module SPARQL; module Algebra
|
2
|
+
class Operator
|
3
|
+
##
|
4
|
+
# The SPARQL GraphPattern `exprlist` operator.
|
5
|
+
#
|
6
|
+
# Used for filters with more than one expression.
|
7
|
+
#
|
8
|
+
# @example
|
9
|
+
# (prefix ((: <http://example/>))
|
10
|
+
# (project (?v ?w)
|
11
|
+
# (filter (exprlist (= ?v 2) (= ?w 3))
|
12
|
+
# (bgp
|
13
|
+
# (triple ?s :p ?v)
|
14
|
+
# (triple ?s :q ?w)
|
15
|
+
# ))))
|
16
|
+
#
|
17
|
+
# @see http://www.w3.org/TR/rdf-sparql-query/#evaluation
|
18
|
+
class Exprlist < Operator
|
19
|
+
include Evaluatable
|
20
|
+
|
21
|
+
NAME = [:exprlist]
|
22
|
+
|
23
|
+
##
|
24
|
+
# Returns `true` if all operands evaluate to `true`.
|
25
|
+
#
|
26
|
+
# Note that this operator operates on the effective boolean value
|
27
|
+
# (EBV) of its operands.
|
28
|
+
#
|
29
|
+
# @example
|
30
|
+
#
|
31
|
+
# (exprlist (= 1 1) (!= 1 0))
|
32
|
+
#
|
33
|
+
# @param [RDF::Query::Solution, #[]] bindings
|
34
|
+
# @return [RDF::Literal::Boolean] `true` or `false`
|
35
|
+
# @raise [TypeError] if the operands could not be coerced to a boolean literal
|
36
|
+
def evaluate(bindings = {})
|
37
|
+
res = operands.all? {|op| boolean(op.evaluate(bindings)).true? }
|
38
|
+
RDF::Literal(res) # FIXME: error handling
|
39
|
+
end
|
40
|
+
|
41
|
+
##
|
42
|
+
# Returns an optimized version of this query.
|
43
|
+
#
|
44
|
+
# Return optimized query
|
45
|
+
#
|
46
|
+
# @return [Union, RDF::Query] `self`
|
47
|
+
def optimize
|
48
|
+
operands = operands.map(&:optimize)
|
49
|
+
end
|
50
|
+
end # Exprlist
|
51
|
+
end # Operator
|
52
|
+
end; end # SPARQL::Algebra
|
@@ -0,0 +1,71 @@
|
|
1
|
+
module SPARQL; module Algebra
|
2
|
+
class Operator
|
3
|
+
##
|
4
|
+
# The SPARQL GraphPattern `filter` operator.
|
5
|
+
#
|
6
|
+
# @example
|
7
|
+
# (select (?v)
|
8
|
+
# (project (?v)
|
9
|
+
# (filter (= ?v 2)
|
10
|
+
# (bgp (triple ?s <http://example/p> ?v)))))
|
11
|
+
#
|
12
|
+
# @see http://www.w3.org/TR/rdf-sparql-query/#evaluation
|
13
|
+
class Filter < Operator::Binary
|
14
|
+
include Query
|
15
|
+
|
16
|
+
NAME = [:filter]
|
17
|
+
|
18
|
+
##
|
19
|
+
# Executes this query on the given `queryable` graph or repository.
|
20
|
+
# Then it passes each solution through one or more filters and removes
|
21
|
+
# those that evaluate to false or generate a _TypeError_.
|
22
|
+
#
|
23
|
+
# Note that the last operand returns a solution set, while the first
|
24
|
+
# is an expression. This may be a variable, simple expression,
|
25
|
+
# or exprlist.
|
26
|
+
#
|
27
|
+
# @param [RDF::Queryable] queryable
|
28
|
+
# the graph or repository to query
|
29
|
+
# @param [Hash{Symbol => Object}] options
|
30
|
+
# any additional keyword options
|
31
|
+
# @return [RDF::Query::Solutions]
|
32
|
+
# the resulting solution sequence
|
33
|
+
# @see http://www.w3.org/TR/rdf-sparql-query/#sparqlAlgebra
|
34
|
+
# @see http://www.w3.org/TR/rdf-sparql-query/#ebv
|
35
|
+
def execute(queryable, options = {})
|
36
|
+
debug(options) {"Filter #{operands.first}"}
|
37
|
+
@solutions = operands.last.execute(queryable, options.merge(:depth => options[:depth].to_i + 1))
|
38
|
+
debug(options) {"=>(before) #{@solutions.map(&:to_hash).inspect}"}
|
39
|
+
@solutions = @solutions.filter do |solution|
|
40
|
+
# Evaluate the solution, which will return true or false
|
41
|
+
#debug(options) {"===>(evaluate) #{operands.first.inspect} against #{solution.to_hash.inspect}"}
|
42
|
+
|
43
|
+
# From http://www.w3.org/TR/rdf-sparql-query/#tests
|
44
|
+
# FILTERs eliminate any solutions that, when substituted into the expression, either
|
45
|
+
# result in an effective boolean value of false or produce an error.
|
46
|
+
begin
|
47
|
+
res = boolean(operands.first.evaluate(solution)).true?
|
48
|
+
debug(options) {"===>#{res} #{solution.to_hash.inspect}"}
|
49
|
+
res
|
50
|
+
rescue
|
51
|
+
debug(options) {"rescue(#{$!}): #{solution.to_hash.inspect}"}
|
52
|
+
false
|
53
|
+
end
|
54
|
+
end
|
55
|
+
@solutions = RDF::Query::Solutions.new(@solutions)
|
56
|
+
debug(options) {"=>(after) #{@solutions.map(&:to_hash).inspect}"}
|
57
|
+
@solutions
|
58
|
+
end
|
59
|
+
|
60
|
+
##
|
61
|
+
# Returns an optimized version of this query.
|
62
|
+
#
|
63
|
+
# Return optimized query
|
64
|
+
#
|
65
|
+
# @return [Union, RDF::Query] `self`
|
66
|
+
def optimize
|
67
|
+
operands = operands.map(&:optimize)
|
68
|
+
end
|
69
|
+
end # Filter
|
70
|
+
end # Operator
|
71
|
+
end; end # SPARQL::Algebra
|