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,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
|