sparql 3.1.6 → 3.2.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (145) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +31 -22
  3. data/VERSION +1 -1
  4. data/bin/sparql +14 -4
  5. data/lib/sparql/algebra/aggregate.rb +1 -1
  6. data/lib/sparql/algebra/evaluatable.rb +4 -4
  7. data/lib/sparql/algebra/expression.rb +28 -3
  8. data/lib/sparql/algebra/extensions.rb +109 -45
  9. data/lib/sparql/algebra/operator/abs.rb +23 -3
  10. data/lib/sparql/algebra/operator/add.rb +21 -2
  11. data/lib/sparql/algebra/operator/alt.rb +26 -2
  12. data/lib/sparql/algebra/operator/and.rb +25 -3
  13. data/lib/sparql/algebra/operator/asc.rb +20 -1
  14. data/lib/sparql/algebra/operator/ask.rb +17 -1
  15. data/lib/sparql/algebra/operator/avg.rb +20 -2
  16. data/lib/sparql/algebra/operator/base.rb +18 -1
  17. data/lib/sparql/algebra/operator/bgp.rb +13 -1
  18. data/lib/sparql/algebra/operator/bnode.rb +34 -11
  19. data/lib/sparql/algebra/operator/bound.rb +22 -1
  20. data/lib/sparql/algebra/operator/ceil.rb +26 -3
  21. data/lib/sparql/algebra/operator/clear.rb +26 -2
  22. data/lib/sparql/algebra/operator/coalesce.rb +33 -11
  23. data/lib/sparql/algebra/operator/compare.rb +48 -40
  24. data/lib/sparql/algebra/operator/concat.rb +26 -2
  25. data/lib/sparql/algebra/operator/construct.rb +29 -6
  26. data/lib/sparql/algebra/operator/contains.rb +25 -3
  27. data/lib/sparql/algebra/operator/copy.rb +19 -2
  28. data/lib/sparql/algebra/operator/count.rb +53 -7
  29. data/lib/sparql/algebra/operator/create.rb +20 -2
  30. data/lib/sparql/algebra/operator/dataset.rb +27 -2
  31. data/lib/sparql/algebra/operator/datatype.rb +26 -7
  32. data/lib/sparql/algebra/operator/day.rb +24 -6
  33. data/lib/sparql/algebra/operator/delete.rb +29 -2
  34. data/lib/sparql/algebra/operator/delete_data.rb +23 -2
  35. data/lib/sparql/algebra/operator/delete_where.rb +24 -2
  36. data/lib/sparql/algebra/operator/desc.rb +20 -1
  37. data/lib/sparql/algebra/operator/describe.rb +27 -4
  38. data/lib/sparql/algebra/operator/distinct.rb +20 -3
  39. data/lib/sparql/algebra/operator/divide.rb +27 -3
  40. data/lib/sparql/algebra/operator/drop.rb +27 -3
  41. data/lib/sparql/algebra/operator/encode_for_uri.rb +23 -3
  42. data/lib/sparql/algebra/operator/equal.rb +13 -3
  43. data/lib/sparql/algebra/operator/exists.rb +28 -4
  44. data/lib/sparql/algebra/operator/exprlist.rb +15 -2
  45. data/lib/sparql/algebra/operator/extend.rb +64 -6
  46. data/lib/sparql/algebra/operator/filter.rb +27 -5
  47. data/lib/sparql/algebra/operator/floor.rb +26 -3
  48. data/lib/sparql/algebra/operator/function_call.rb +64 -0
  49. data/lib/sparql/algebra/operator/graph.rb +69 -6
  50. data/lib/sparql/algebra/operator/greater_than.rb +14 -4
  51. data/lib/sparql/algebra/operator/greater_than_or_equal.rb +14 -4
  52. data/lib/sparql/algebra/operator/group.rb +105 -8
  53. data/lib/sparql/algebra/operator/group_concat.rb +44 -8
  54. data/lib/sparql/algebra/operator/hours.rb +24 -6
  55. data/lib/sparql/algebra/operator/if.rb +20 -3
  56. data/lib/sparql/algebra/operator/in.rb +18 -1
  57. data/lib/sparql/algebra/operator/insert.rb +24 -2
  58. data/lib/sparql/algebra/operator/insert_data.rb +23 -2
  59. data/lib/sparql/algebra/operator/iri.rb +22 -5
  60. data/lib/sparql/algebra/operator/is_blank.rb +21 -4
  61. data/lib/sparql/algebra/operator/is_iri.rb +21 -4
  62. data/lib/sparql/algebra/operator/is_literal.rb +21 -4
  63. data/lib/sparql/algebra/operator/is_numeric.rb +23 -6
  64. data/lib/sparql/algebra/operator/is_triple.rb +33 -1
  65. data/lib/sparql/algebra/operator/join.rb +56 -1
  66. data/lib/sparql/algebra/operator/lang.rb +26 -1
  67. data/lib/sparql/algebra/operator/lang_matches.rb +23 -2
  68. data/lib/sparql/algebra/operator/lcase.rb +23 -3
  69. data/lib/sparql/algebra/operator/left_join.rb +42 -1
  70. data/lib/sparql/algebra/operator/less_than.rb +14 -4
  71. data/lib/sparql/algebra/operator/less_than_or_equal.rb +14 -4
  72. data/lib/sparql/algebra/operator/load.rb +25 -2
  73. data/lib/sparql/algebra/operator/max.rb +20 -2
  74. data/lib/sparql/algebra/operator/md5.rb +23 -6
  75. data/lib/sparql/algebra/operator/min.rb +22 -4
  76. data/lib/sparql/algebra/operator/minus.rb +65 -7
  77. data/lib/sparql/algebra/operator/minutes.rb +24 -6
  78. data/lib/sparql/algebra/operator/modify.rb +41 -5
  79. data/lib/sparql/algebra/operator/month.rb +24 -6
  80. data/lib/sparql/algebra/operator/move.rb +20 -2
  81. data/lib/sparql/algebra/operator/multiply.rb +27 -4
  82. data/lib/sparql/algebra/operator/negate.rb +24 -4
  83. data/lib/sparql/algebra/operator/not.rb +25 -4
  84. data/lib/sparql/algebra/operator/not_equal.rb +16 -1
  85. data/lib/sparql/algebra/operator/notexists.rb +30 -6
  86. data/lib/sparql/algebra/operator/notin.rb +20 -3
  87. data/lib/sparql/algebra/operator/notoneof.rb +21 -2
  88. data/lib/sparql/algebra/operator/now.rb +25 -6
  89. data/lib/sparql/algebra/operator/object.rb +33 -1
  90. data/lib/sparql/algebra/operator/or.rb +26 -3
  91. data/lib/sparql/algebra/operator/order.rb +71 -2
  92. data/lib/sparql/algebra/operator/path.rb +29 -2
  93. data/lib/sparql/algebra/operator/path_opt.rb +21 -2
  94. data/lib/sparql/algebra/operator/path_plus.rb +21 -2
  95. data/lib/sparql/algebra/operator/path_star.rb +20 -2
  96. data/lib/sparql/algebra/operator/plus.rb +43 -4
  97. data/lib/sparql/algebra/operator/predicate.rb +33 -1
  98. data/lib/sparql/algebra/operator/prefix.rb +24 -3
  99. data/lib/sparql/algebra/operator/project.rb +69 -5
  100. data/lib/sparql/algebra/operator/rand.rb +31 -3
  101. data/lib/sparql/algebra/operator/reduced.rb +20 -3
  102. data/lib/sparql/algebra/operator/regex.rb +27 -19
  103. data/lib/sparql/algebra/operator/replace.rb +27 -7
  104. data/lib/sparql/algebra/operator/reverse.rb +31 -2
  105. data/lib/sparql/algebra/operator/round.rb +26 -3
  106. data/lib/sparql/algebra/operator/same_term.rb +25 -7
  107. data/lib/sparql/algebra/operator/sample.rb +33 -9
  108. data/lib/sparql/algebra/operator/seconds.rb +24 -6
  109. data/lib/sparql/algebra/operator/seq.rb +20 -2
  110. data/lib/sparql/algebra/operator/sequence.rb +4 -11
  111. data/lib/sparql/algebra/operator/sha1.rb +19 -2
  112. data/lib/sparql/algebra/operator/sha256.rb +19 -2
  113. data/lib/sparql/algebra/operator/sha384.rb +19 -2
  114. data/lib/sparql/algebra/operator/sha512.rb +19 -2
  115. data/lib/sparql/algebra/operator/slice.rb +27 -5
  116. data/lib/sparql/algebra/operator/str.rb +22 -2
  117. data/lib/sparql/algebra/operator/strafter.rb +26 -3
  118. data/lib/sparql/algebra/operator/strbefore.rb +26 -3
  119. data/lib/sparql/algebra/operator/strdt.rb +23 -2
  120. data/lib/sparql/algebra/operator/strends.rb +26 -4
  121. data/lib/sparql/algebra/operator/strlang.rb +25 -7
  122. data/lib/sparql/algebra/operator/strlen.rb +24 -3
  123. data/lib/sparql/algebra/operator/strstarts.rb +26 -3
  124. data/lib/sparql/algebra/operator/struuid.rb +30 -10
  125. data/lib/sparql/algebra/operator/subject.rb +33 -1
  126. data/lib/sparql/algebra/operator/substr.rb +24 -3
  127. data/lib/sparql/algebra/operator/subtract.rb +29 -3
  128. data/lib/sparql/algebra/operator/sum.rb +25 -7
  129. data/lib/sparql/algebra/operator/table.rb +76 -4
  130. data/lib/sparql/algebra/operator/timezone.rb +24 -6
  131. data/lib/sparql/algebra/operator/tz.rb +23 -6
  132. data/lib/sparql/algebra/operator/ucase.rb +24 -3
  133. data/lib/sparql/algebra/operator/union.rb +29 -6
  134. data/lib/sparql/algebra/operator/update.rb +46 -4
  135. data/lib/sparql/algebra/operator/using.rb +49 -2
  136. data/lib/sparql/algebra/operator/uuid.rb +28 -9
  137. data/lib/sparql/algebra/operator/with.rb +38 -4
  138. data/lib/sparql/algebra/operator/year.rb +24 -6
  139. data/lib/sparql/algebra/operator.rb +135 -14
  140. data/lib/sparql/algebra/sxp_extensions.rb +3 -3
  141. data/lib/sparql/algebra.rb +20 -3
  142. data/lib/sparql/grammar/meta.rb +1103 -907
  143. data/lib/sparql/grammar/parser11.rb +63 -56
  144. metadata +43 -29
  145. data/lib/sparql/algebra/operator/triple.rb +0 -27
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 383f162fe715a1ff7eebb78e095a77f1e1823d29045c673b57c5bf68acbcb70f
4
- data.tar.gz: fc7f7ea801e556ee25a77dd340ea7268a7a5d0c39ee9bf2686cb71e887a58446
3
+ metadata.gz: e9bcab10eb6706316b68b44a0fd917d7b735b18a8353b51e49ef124fc966176d
4
+ data.tar.gz: 6da59b4e90fd1b7a7d80c42d941f7c27f6bf95892d17302caf16a13809b03afa
5
5
  SHA512:
6
- metadata.gz: 662583eb75d9cca1a34d8d8299cee4eb7e97dc6d3251982300a077c888523bd63f8350be3ce1fed753692e2f26d056afd7381f26ac8115f6b72a7e8f2e89296e
7
- data.tar.gz: 8cb4ee544f52b9599fb1d5dc6ac3b8a68a7755caded5b3baef706222565c9b59511e69f0921c2b00ece9f3fd22aebff543caa37c93a6d45b02a9e8211660931d
6
+ metadata.gz: d2f99aee7d5b9482bbd653333eeefd215da872291993a2ba138ed9bcfc3f92812672cd1508dfbd11a729d527c9724f0a80ec816c5c84fd2df9933b4b91b5a296
7
+ data.tar.gz: 41a11caf8e85ca4bd01213bb0c0c236314560338dbd2825bd2437afbf4fd9855b994150737dbcad00838dc5ac50e368d72e5bfe2e516566a6319f824bdcacc56
data/README.md CHANGED
@@ -23,8 +23,7 @@ This is a [Ruby][] implementation of [SPARQL][] for [RDF.rb][].
23
23
  * Compatible with any [Rack][] or [Sinatra][] application and any Rack-based framework.
24
24
  * Helper method for describing [SPARQL Service Description][SSD]
25
25
  * Implementation Report: {file:etc/earl.html EARL}
26
- * Compatible with Ruby >= 2.2.2.
27
- * Compatible with older Ruby versions with the help of the [Backports][] gem.
26
+ * Compatible with Ruby >= 2.6.
28
27
  * Supports Unicode query strings both on all versions of Ruby.
29
28
  * Provisional support for [SPARQL-star][].
30
29
 
@@ -248,27 +247,27 @@ a full set of RDF formats.
248
247
  ### Querying a repository with a SPARQL query
249
248
 
250
249
  queryable = RDF::Repository.load("etc/doap.ttl")
251
- sse = SPARQL.parse("SELECT * WHERE { ?s ?p ?o }")
252
- queryable.query(sse) do |result|
250
+ query = SPARQL.parse("SELECT * WHERE { ?s ?p ?o }")
251
+ queryable.query(query) do |result|
253
252
  result.inspect
254
253
  end
255
254
 
256
255
  ### Executing a SPARQL query against a repository
257
256
 
258
257
  queryable = RDF::Repository.load("etc/doap.ttl")
259
- sse = SPARQL.parse("SELECT * WHERE { ?s ?p ?o }")
260
- sse.execute(queryable) do |result|
258
+ query = SPARQL.parse("SELECT * WHERE { ?s ?p ?o }")
259
+ query.execute(queryable) do |result|
261
260
  result.inspect
262
261
  end
263
262
 
264
263
  ### Updating a repository
265
264
 
266
265
  queryable = RDF::Repository.load("etc/doap.ttl")
267
- sse = SPARQL.parse(%(
266
+ update = SPARQL.parse(%(
268
267
  PREFIX doap: <http://usefulinc.com/ns/doap#>
269
268
  INSERT DATA { <https://rubygems> doap:implements <http://www.w3.org/TR/sparql11-update/>}
270
269
  ), update: true)
271
- sse.execute(queryable)
270
+ update.execute(queryable)
272
271
 
273
272
  ### Rendering solutions as JSON, XML, CSV, TSV or HTML
274
273
  queryable = RDF::Repository.load("etc/doap.ttl")
@@ -277,8 +276,15 @@ a full set of RDF formats.
277
276
 
278
277
  ### Parsing a SPARQL query string to SSE
279
278
 
280
- sse = SPARQL.parse("SELECT * WHERE { ?s ?p ?o }")
281
- sse.to_sxp #=> (bgp (triple ?s ?p ?o))
279
+ query = SPARQL.parse("SELECT * WHERE { ?s ?p ?o }")
280
+ query.to_sxp #=> (bgp (triple ?s ?p ?o))
281
+
282
+ ### Parsing a SSE to SPARQL query or update string to SPARQL
283
+
284
+ # Note: if the SSE uses extension functions, they either must be XSD casting functions, or custom functions which are registered extensions. (See [SPARQL Extension Functions](#sparql-extension-functions))
285
+
286
+ query = SPARQL::Algebra.parse(%{(bgp (triple ?s ?p ?o))})
287
+ sparql = query.to_sparql #=> "SELECT * WHERE { ?s ?p ?o }"
282
288
 
283
289
  ### Command line processing
284
290
 
@@ -289,6 +295,10 @@ a full set of RDF formats.
289
295
  sparql parse etc/input.rq
290
296
  sparql parse -e "SELECT * WHERE { ?s ?p ?o }"
291
297
 
298
+ # Generate SPARQL Query from SSE
299
+ sparql parse --sse etc/input.sse --format sparql
300
+ sparql parse --sse --format sparql -e "(dataset (<http://usefulinc.com/ns/doap>) (bgp (triple ?s ?p ?o))))"
301
+
292
302
  # Run query using SSE input
293
303
  sparql execute --dataset etc/doap.ttl --sse etc/input.sse
294
304
  sparql execute --sse -e "(dataset (<etc/doap.ttl>) (bgp (triple ?s ?p ?o))))"
@@ -368,19 +378,19 @@ Full documentation available on [Rubydoc.info][SPARQL doc]
368
378
 
369
379
  ## Dependencies
370
380
 
371
- * [Ruby](https://ruby-lang.org/) (>= 2.2.2)
372
- * [RDF.rb](https://rubygems.org/gems/rdf) (~> 3.0)
373
- * [SPARQL::Client](https://rubygems.org/gems/sparql-client) (~> 3.0)
374
- * [SXP](https://rubygems.org/gems/sxp) (~> 1.0)
375
- * [Builder](https://rubygems.org/gems/builder) (>= 3.0.0)
376
- * [JSON](https://rubygems.org/gems/json) (>= 1.8.2)
377
- * Soft dependency on [Linked Data][] (>= 3.0)
378
- * Soft dependency on [Nokogiri](https://rubygems.org/gems/nokogiri) (>= 1.7)
381
+ * [Ruby](https://ruby-lang.org/) (>= 2.6)
382
+ * [RDF.rb](https://rubygems.org/gems/rdf) (~> 3.2)
383
+ * [SPARQL::Client](https://rubygems.org/gems/sparql-client) (~> 3.1)
384
+ * [SXP](https://rubygems.org/gems/sxp) (~> 1.2)
385
+ * [Builder](https://rubygems.org/gems/builder) (~> 3.2)
386
+ * [JSON](https://rubygems.org/gems/json) (~> 2.6)
387
+ * Soft dependency on [Linked Data][] (>= 3.1)
388
+ * Soft dependency on [Nokogiri](https://rubygems.org/gems/nokogiri) (~> 1.12)
379
389
  Falls back to REXML for XML parsing Builder for XML serializing. Nokogiri is much more efficient
380
- * Soft dependency on [Equivalent XML](https://rubygems.org/gems/equivalent-xml) (>= 0.3.0)
390
+ * Soft dependency on [Equivalent XML](https://rubygems.org/gems/equivalent-xml) (>= 0.6)
381
391
  Equivalent XML performs more efficient comparisons of XML Literals when Nokogiri is included
382
- * Soft dependency on [Rack][] (>= 2.0)
383
- * Soft dependency on [Sinatra][] (>= 2.0)
392
+ * Soft dependency on [Rack][] (~> 2.2)
393
+ * Soft dependency on [Sinatra][] (~> 2.1)
384
394
 
385
395
  ## Installation
386
396
 
@@ -450,7 +460,6 @@ A copy of the [SPARQL 1.0 tests][] and [SPARQL 1.1 tests][] are also included in
450
460
  [RDF.rb]: https://rubydoc.info/github/ruby-rdf/rdf
451
461
  [RDF-star]: https://w3c.github.io/rdf-star/rdf-star-cg-spec.html
452
462
  [SPARQL-star]: https://w3c.github.io/rdf-star/rdf-star-cg-spec.html#sparql-query-language
453
- [Backports]: https://rubygems.org/gems/backports
454
463
  [Linked Data]: https://rubygems.org/gems/linkeddata
455
464
  [SPARQL doc]: https://rubydoc.info/github/ruby-rdf/sparql/frames
456
465
  [SPARQL XML]: https://www.w3.org/TR/rdf-sparql-XMLres/
data/VERSION CHANGED
@@ -1 +1 @@
1
- 3.1.6
1
+ 3.2.1
data/bin/sparql CHANGED
@@ -1,6 +1,7 @@
1
1
  #!/usr/bin/env ruby
2
2
  require 'rubygems'
3
3
  $:.unshift("../../lib", __FILE__)
4
+ require 'logger'
4
5
  require 'sparql'
5
6
  begin
6
7
  require 'linkeddata'
@@ -44,9 +45,18 @@ def run(input, **options)
44
45
  SPARQL::Grammar.parse(input, **options)
45
46
  end
46
47
 
47
- puts ("\nSSE:\n" + query.to_sse) if options[:debug] || options[:to_sse]
48
+ puts ("\nSSE:\n" + query.to_sse) if options[:debug]
48
49
 
49
- unless options[:to_sse]
50
+ if options[:parse_only]
51
+ case options[:format]
52
+ when :sparql
53
+ puts ("\nSPARQL:\n" + query.to_sparql)
54
+ when nil, :sse
55
+ puts ("\nSSE:\n" + query.to_sse)
56
+ else
57
+ $stderr.puts "Unknown output format for parsing: #{options[:format]}. Use 'sse' or 'sparql'"
58
+ end
59
+ else
50
60
  res = query.execute(options[:dataset], logger: options[:logger])
51
61
  display_results(res, **options)
52
62
  end
@@ -97,7 +107,7 @@ def usage
97
107
  puts " --dataset: File containing RDF graph or dataset"
98
108
  puts " --debug: Display detailed debug output"
99
109
  puts " --execute,-e: Use option argument as the SPARQL input if no query-file given"
100
- puts " --format: Output format for results"
110
+ puts " --format: Output format for results (json, xml, csv, tsv, html, sparql, sse, or another RDF format)"
101
111
  puts " --port,-p Port on which to run server; defaults to 9292"
102
112
  puts " --sse: Query input is in SSE format"
103
113
  puts " --update: Process query as a SPARQL Update"
@@ -150,7 +160,7 @@ end
150
160
 
151
161
  case cmd
152
162
  when 'execute', 'parse'
153
- options[:to_sse] = true if cmd == 'parse'
163
+ options[:parse_only] = true if cmd == 'parse'
154
164
  input ||= ARGV.empty? ? $stdin.read : RDF::Util::File.open_file(ARGV.first).read
155
165
  run(input, **options)
156
166
  when 'query'
@@ -44,7 +44,7 @@ module SPARQL; module Algebra
44
44
  # Enumerable yielding evaluated operands
45
45
  # @return [RDF::Term]
46
46
  # @abstract
47
- def apply(enum)
47
+ def apply(enum, **options)
48
48
  raise NotImplementedError, "#{self.class}#apply(#{operands.map(&:class).join(', ')})"
49
49
  end
50
50
 
@@ -15,16 +15,16 @@ module SPARQL; module Algebra
15
15
  # @abstract
16
16
  def evaluate(bindings, **options)
17
17
  args = operands.map { |operand| operand.evaluate(bindings, depth: options[:depth].to_i + 1, **options) }
18
- options[:memoize] ? memoize(*args) : apply(*args)
18
+ options[:memoize] ? memoize(*args, **options) : apply(*args, **options)
19
19
  end
20
20
 
21
21
  ##
22
22
  # @param [Array<RDF::Term>] operands
23
23
  # evaluated operands
24
24
  # @return [RDF::Term] the memoized result
25
- def memoize(*operands)
25
+ def memoize(*operands, **options)
26
26
  @cache ||= RDF::Util::Cache.new(options[:memoize].is_a?(Integer) ? options[:memoize] : -1)
27
- @cache[operands] ||= apply(*operands)
27
+ @cache[operands] ||= apply(*operands, **options)
28
28
  end
29
29
 
30
30
  ##
@@ -32,7 +32,7 @@ module SPARQL; module Algebra
32
32
  # evaluated operands
33
33
  # @return [RDF::Term]
34
34
  # @abstract
35
- def apply(*operands)
35
+ def apply(*operands, **options)
36
36
  raise NotImplementedError, "#{self.class}#apply(#{operands.map(&:class).join(', ')})"
37
37
  end
38
38
 
@@ -66,9 +66,11 @@ module SPARQL; module Algebra
66
66
  #
67
67
  # @param [Array] sse
68
68
  # a SPARQL S-Expression (SSE) form
69
+ # @param [Hash{Symbol => Object}] options
70
+ # any additional options (see {Operator#initialize})
69
71
  # @return [Expression]
70
- def self.for(*sse)
71
- self.new(sse)
72
+ def self.for(*sse, **options)
73
+ self.new(sse, **options)
72
74
  end
73
75
  class << self; alias_method :[], :for; end
74
76
 
@@ -86,6 +88,13 @@ module SPARQL; module Algebra
86
88
  raise ArgumentError, "invalid SPARQL::Algebra::Expression form: #{sse.inspect}" unless sse.is_a?(Array)
87
89
 
88
90
  operator = Operator.for(sse.first, sse.length - 1)
91
+
92
+ # If we don't find an operator, and sse.first is an extension IRI, use a function call
93
+ if !operator && sse.first.is_a?(RDF::URI) && self.extension?(sse.first)
94
+ operator = Operator.for(:function_call, sse.length)
95
+ sse.unshift(:function_call)
96
+ end
97
+
89
98
  unless operator
90
99
  return case sse.first
91
100
  when Array
@@ -115,11 +124,16 @@ module SPARQL; module Algebra
115
124
  end
116
125
 
117
126
  debug(options) {"#{operator.inspect}(#{operands.map(&:inspect).join(',')})"}
127
+ logger = options[:logger]
118
128
  options.delete_if {|k, v| [:debug, :logger, :depth, :prefixes, :base_uri, :update, :validate].include?(k) }
119
129
  begin
120
130
  operator.new(*operands, **options)
121
131
  rescue ArgumentError => e
122
- error(options) {"Operator=#{operator.inspect}: #{e}"}
132
+ if logger
133
+ logger.error("Operator=#{operator.inspect}: #{e}")
134
+ else
135
+ raise "Operator=#{operator.inspect}: #{e}"
136
+ end
123
137
  end
124
138
  end
125
139
 
@@ -163,6 +177,17 @@ module SPARQL; module Algebra
163
177
  @extensions ||= {}
164
178
  end
165
179
 
180
+ ##
181
+ # Is an extension function available?
182
+ #
183
+ # It's either a registered extension, or an XSD casting function
184
+ #
185
+ # @param [RDF::URI] function
186
+ # @return [Boolean]
187
+ def self.extension?(function)
188
+ function.to_s.start_with?(RDF::XSD.to_s) || self.extensions[function]
189
+ end
190
+
166
191
  ##
167
192
  # Invoke an extension function.
168
193
  #
@@ -43,6 +43,15 @@ class Object
43
43
  def deep_dup
44
44
  dup
45
45
  end
46
+
47
+ ##
48
+ #
49
+ # Returns a partial SPARQL grammar for this term.
50
+ #
51
+ # @return [String]
52
+ def to_sparql(**options)
53
+ to_sxp(**options)
54
+ end
46
55
  end
47
56
 
48
57
  ##
@@ -57,20 +66,14 @@ class Array
57
66
  end
58
67
 
59
68
  ##
60
- # Evaluates the array using the given variable `bindings`.
61
69
  #
62
- # In this case, the Array has two elements, the first of which is
63
- # an XSD datatype, and the second is the expression to be evaluated.
64
- # The result is cast as a literal of the appropriate type
70
+ # Returns a partial SPARQL grammar for this array.
65
71
  #
66
- # @param [RDF::Query::Solution] bindings
67
- # a query solution containing zero or more variable bindings
68
- # @param [Hash{Symbol => Object}] options ({})
69
- # options passed from query
70
- # @return [RDF::Term]
71
- # @see SPARQL::Algebra::Expression.evaluate
72
- def evaluate(bindings, **options)
73
- SPARQL::Algebra::Expression.extension(*self.map {|o| o.evaluate(bindings, **options)})
72
+ # @param [String] delimiter (" ")
73
+ # If the first element is an IRI, treat it as an extension function
74
+ # @return [String]
75
+ def to_sparql(delimiter: " ", **options)
76
+ map {|e| e.to_sparql(**options)}.join(delimiter)
74
77
  end
75
78
 
76
79
  ##
@@ -216,15 +219,6 @@ end
216
219
  ##
217
220
  # Extensions for Ruby's `Hash` class.
218
221
  class Hash
219
- ##
220
- # Returns the SXP representation of this object, defaults to `self`.
221
- #
222
- # @return [String]
223
- def to_sxp_bin
224
- to_a.to_sxp_bin
225
- end
226
- def to_sxp; to_sxp_bin; end
227
-
228
222
  ##
229
223
  # A duplicate of this hash.
230
224
  #
@@ -278,24 +272,19 @@ module RDF::Term
278
272
  # @see SPARQL::Algebra::Expression#optimize
279
273
  def optimize(**options)
280
274
  optimized = self.deep_dup
281
- optimized.lexical = nil if optimized.respond_to?(:lexical=)
282
- optimized
275
+ #optimized.lexical = nil if optimized.respond_to?(:lexical=)
276
+ #optimized
283
277
  end
284
- end # RDF::Term
285
278
 
286
- class RDF::Literal::Double
287
279
  ##
288
- # Returns the SXP representation of this object.
280
+ #
281
+ # Returns a partial SPARQL grammar for this term.
289
282
  #
290
283
  # @return [String]
291
- def to_sxp
292
- case
293
- when nan? then 'nan.0'
294
- when infinite? then (infinite? > 0 ? '+inf.0' : '-inf.0')
295
- else canonicalize.to_s.downcase
296
- end
284
+ def to_sparql(**options)
285
+ to_sxp(**options)
297
286
  end
298
- end
287
+ end # RDF::Term
299
288
 
300
289
  # Override RDF::Queryable to execute against SPARQL::Algebra::Query elements as well as RDF::Query and RDF::Pattern
301
290
  module RDF::Queryable
@@ -343,6 +332,15 @@ module RDF::Queryable
343
332
  query_without_sparql(pattern, **options, &block)
344
333
  end
345
334
  end
335
+
336
+ ##
337
+ #
338
+ # Returns a partial SPARQL grammar for this term.
339
+ #
340
+ # @return [String]
341
+ def to_sparql(**options)
342
+ raise NotImplementedError, "SPARQL::Algebra '#{first}' operator not implemented"
343
+ end
346
344
  end
347
345
 
348
346
  class RDF::Statement
@@ -361,9 +359,31 @@ class RDF::Statement
361
359
  ##
362
360
  # Returns an S-Expression (SXP) representation
363
361
  #
362
+ # @param [Hash{Symbol => RDF::URI}] prefixes (nil)
363
+ # @param [RDF::URI] base_uri (nil)
364
364
  # @return [String]
365
- def to_sxp
366
- to_sxp_bin.to_sxp
365
+ def to_sxp(prefixes: nil, base_uri: nil)
366
+ to_sxp_bin.to_sxp(prefixes: prefixes, base_uri: base_uri)
367
+ end
368
+
369
+ ##
370
+ #
371
+ # Returns a partial SPARQL grammar for this term.
372
+ #
373
+ # @param [Boolean] as_statement (false) serialize as < ... >, otherwise TRIPLE(...)
374
+ # @return [String]
375
+ def to_sparql(as_statement: false, **options)
376
+ if as_statement
377
+ to_triple.map do |term|
378
+ if term.is_a?(::RDF::Statement)
379
+ "<<" + term.to_sparql(as_statement: true, **options) + ">>"
380
+ else
381
+ term.to_sparql(**options)
382
+ end
383
+ end.join(" ")
384
+ else
385
+ "TRIPLE(#{to_triple.to_sparql(as_statement: true, **options)})"
386
+ end
367
387
  end
368
388
 
369
389
  ##
@@ -411,6 +431,38 @@ class RDF::Query
411
431
  end
412
432
  end
413
433
 
434
+ ##
435
+ #
436
+ # Returns a partial SPARQL grammar for this query.
437
+ #
438
+ # @param [Boolean] top_level (true)
439
+ # Treat this as a top-level, generating SELECT ... WHERE {}
440
+ # @param [Array<Operator>] filter_ops ([])
441
+ # Filter Operations
442
+ # @return [String]
443
+ def to_sparql(top_level: true, filter_ops: [], **options)
444
+ str = @patterns.map { |e| e.to_sparql(as_statement: true, top_level: false, **options) }.join(". \n")
445
+ str = "GRAPH #{graph_name.to_sparql(**options)} {\n#{str}\n}\n" if graph_name
446
+ if top_level
447
+ SPARQL::Algebra::Operator.to_sparql(str, filter_ops: filter_ops, **options)
448
+ else
449
+ # Filters
450
+ filter_ops.each do |op|
451
+ str << "\nFILTER (#{op.to_sparql(**options)}) ."
452
+ end
453
+
454
+ # Extensons
455
+ extensions = options.fetch(:extensions, [])
456
+ extensions.each do |as, expression|
457
+ v = expression.to_sparql(as_statement: true, **options)
458
+ v = "<< #{v} >>" if expression.is_a?(RDF::Statement)
459
+ str << "\nBIND (" << v << " AS " << as.to_sparql(**options) << ") ."
460
+ end
461
+ str = "{#{str}}" unless filter_ops.empty? && extensions.empty?
462
+ str
463
+ end
464
+ end
465
+
414
466
  ##
415
467
  # Binds the pattern to a solution, making it no longer variable if all variables are resolved to bound variables
416
468
  #
@@ -462,11 +514,11 @@ class RDF::Query
462
514
  def optimize!(**options)
463
515
  @patterns = @patterns.map do |pattern|
464
516
  components = pattern.to_quad.map do |term|
465
- if term.respond_to?(:lexical=)
466
- term.dup.instance_eval {@lexical = nil; self}
467
- else
517
+ #if term.respond_to?(:lexical=)
518
+ # term.dup.instance_eval {@lexical = nil; self}
519
+ #else
468
520
  term
469
- end
521
+ #end
470
522
  end
471
523
  RDF::Query::Pattern.from(components, **pattern.options)
472
524
  end
@@ -530,11 +582,15 @@ class RDF::Query::Variable
530
582
  self
531
583
  end
532
584
 
533
- # Display variable as SXP
534
- # @return [Array]
535
- def to_sxp
536
- prefix = distinguished? ? (existential? ? '$' : '?') : (existential? ? '$$' : '??')
537
- unbound? ? "#{prefix}#{name}".to_sym.to_sxp : ["#{prefix}#{name}".to_sym, value].to_sxp
585
+ ##
586
+ #
587
+ # Returns a partial SPARQL grammar for this term.
588
+ #
589
+ # The Non-distinguished form (`??xxx`) is not part of the grammar, so replace with a blank-node
590
+ #
591
+ # @return [String]
592
+ def to_sparql(**options)
593
+ self.distinguished? ? super : "_:_nd#{self.name}"
538
594
  end
539
595
  end # RDF::Query::Variable
540
596
 
@@ -576,5 +632,13 @@ class RDF::Query::Solution
576
632
  def to_sxp_bin
577
633
  to_a.to_sxp_bin
578
634
  end
579
- def to_sxp; to_sxp_bin; end
635
+
636
+ # Transform Solution into an SXP
637
+ #
638
+ # @param [Hash{Symbol => RDF::URI}] prefixes (nil)
639
+ # @param [RDF::URI] base_uri (nil)
640
+ # @return [String]
641
+ def to_sxp(prefixes: nil, base_uri: nil)
642
+ to_sxp_bin.to_sxp(prefixes: prefixes, base_uri: base_uri)
643
+ end
580
644
  end # RDF::Query::Solution
@@ -3,8 +3,19 @@ module SPARQL; module Algebra
3
3
  ##
4
4
  # The SPARQL logical `abs` operator.
5
5
  #
6
- # @example
7
- # (abs ?x)
6
+ # [121] BuiltInCall ::= ... | 'ABS' '(' Expression ')'
7
+ #
8
+ # @example SPARQL Grammar
9
+ # PREFIX : <http://example.org/>
10
+ # SELECT * WHERE {
11
+ # ?s :num ?num
12
+ # FILTER(ABS(?num) >= 2)
13
+ # }
14
+ #
15
+ # @example SSE
16
+ # (prefix ((: <http://example.org/>))
17
+ # (filter (>= (abs ?num) 2)
18
+ # (bgp (triple ?s :num ?num))))
8
19
  #
9
20
  # @see https://www.w3.org/TR/sparql11-query/#func-abs
10
21
  # @see https://www.w3.org/TR/xpath-functions/#func-abs
@@ -20,12 +31,21 @@ module SPARQL; module Algebra
20
31
  # the operand
21
32
  # @return [RDF::Literal] literal of same type
22
33
  # @raise [TypeError] if the operand is not a numeric value
23
- def apply(operand)
34
+ def apply(operand, **options)
24
35
  case operand
25
36
  when RDF::Literal::Numeric then operand.abs
26
37
  else raise TypeError, "expected an RDF::Literal::Numeric, but got #{operand.inspect}"
27
38
  end
28
39
  end
40
+
41
+ ##
42
+ #
43
+ # Returns a partial SPARQL grammar for this operator.
44
+ #
45
+ # @return [String]
46
+ def to_sparql(**options)
47
+ "ABS(#{operands.first.to_sparql(**options)})"
48
+ end
29
49
  end # Abs
30
50
  end # Operator
31
51
  end; end # SPARQL::Algebra
@@ -6,8 +6,15 @@ module SPARQL; module Algebra
6
6
  #
7
7
  # The ADD operation is a shortcut for inserting all data from an input graph into a destination graph. Data from the input graph is not affected, and initial data from the destination graph, if any, is kept intact.
8
8
  #
9
- # @example
10
- # (add default <a>)
9
+ # [35] Add ::= "ADD" "SILENT"? GraphOrDefault "TO" GraphOrDefault
10
+ #
11
+ # @example SPARQL Update
12
+ # PREFIX : <http://example.org/>
13
+ # ADD DEFAULT TO :g1
14
+ #
15
+ # @example SSE
16
+ # (prefix ((: <http://example.org/>))
17
+ # (update (add default :g1)))
11
18
  #
12
19
  # @see https://www.w3.org/TR/sparql11-update/#add
13
20
  class Add < Operator
@@ -51,6 +58,18 @@ module SPARQL; module Algebra
51
58
  end
52
59
  queryable
53
60
  end
61
+
62
+ ##
63
+ #
64
+ # Returns a partial SPARQL grammar for this operator.
65
+ #
66
+ # @return [String]
67
+ def to_sparql(**options)
68
+ *args, last = operands.dup
69
+ args += [:TO, last]
70
+
71
+ "ADD " + args.to_sparql(**options)
72
+ end
54
73
  end # Add
55
74
  end # Operator
56
75
  end; end # SPARQL::Algebra
@@ -7,8 +7,23 @@ module SPARQL; module Algebra
7
7
  #
8
8
  # eval(Path(X, alt(P,Q), Y)) = Union(eval(Path(X, P, Y)), eval(Path(X, Q, Y)))
9
9
  #
10
- # @example
11
- # (alt a b)
10
+ # [89] PathAlternative ::= PathSequence ( '|' PathSequence )*
11
+ #
12
+ # @example SPARQL Query
13
+ # PREFIX : <http://www.example.org/>
14
+ # SELECT ?t
15
+ # WHERE {
16
+ # :a :p1|:p2/:p3|:p4 ?t
17
+ # }
18
+ #
19
+ # @example SSE
20
+ # (prefix ((: <http://www.example.org/>))
21
+ # (project (?t)
22
+ # (path :a
23
+ # (alt
24
+ # (alt :p1 (seq :p2 :p3))
25
+ # :p4)
26
+ # ?t)))
12
27
  #
13
28
  # @see https://www.w3.org/TR/sparql11-query/#defn_evalPP_alternative
14
29
  class Alt < Operator::Binary
@@ -57,6 +72,15 @@ module SPARQL; module Algebra
57
72
  query = Union.new(qa, qb)
58
73
  queryable.query(query, depth: options[:depth].to_i + 1, **options, &block)
59
74
  end
75
+
76
+ ##
77
+ #
78
+ # Returns a partial SPARQL grammar for this operator.
79
+ #
80
+ # @return [String]
81
+ def to_sparql(**options)
82
+ "(#{operands.first.to_sparql(**options)}|#{operands.last.to_sparql(**options)})"
83
+ end
60
84
  end # Alt
61
85
  end # Operator
62
86
  end; end # SPARQL::Algebra
@@ -3,9 +3,22 @@ module SPARQL; module Algebra
3
3
  ##
4
4
  # The SPARQL logical `and` operator.
5
5
  #
6
- # @example
7
- # (&& ?x ?y)
8
- # (and ?x ?y)
6
+ # [112] ConditionalAndExpression::= ValueLogical ( '&&' ValueLogical )*
7
+ #
8
+ # @example SPARQL Grammar
9
+ # PREFIX xsd: <http://www.w3.org/2001/XMLSchema#>
10
+ # PREFIX : <http://example.org/ns#>
11
+ # SELECT ?a
12
+ # WHERE { ?a :p ?v .
13
+ # FILTER ("true"^^xsd:boolean && ?v) .
14
+ # }
15
+ #
16
+ # @example SSE
17
+ # (prefix
18
+ # ((xsd: <http://www.w3.org/2001/XMLSchema#>) (: <http://example.org/ns#>))
19
+ # (project (?a)
20
+ # (filter (&& true ?v)
21
+ # (bgp (triple ?a :p ?v)))))
9
22
  #
10
23
  # @see https://www.w3.org/TR/sparql11-query/#func-logical-and
11
24
  # @see https://www.w3.org/TR/sparql11-query/#evaluation
@@ -60,6 +73,15 @@ module SPARQL; module Algebra
60
73
  else RDF::Literal(left && right)
61
74
  end
62
75
  end
76
+
77
+ ##
78
+ #
79
+ # Returns a partial SPARQL grammar for this operator.
80
+ #
81
+ # @return [String]
82
+ def to_sparql(**options)
83
+ "(#{operands.first.to_sparql(**options)} && #{operands.last.to_sparql(**options)})"
84
+ end
63
85
  end # And
64
86
  end # Operator
65
87
  end; end # SPARQL::Algebra