rdf-virtuoso 0.0.11
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/README.md +73 -0
- data/lib/active_rdf.rb +14 -0
- data/lib/active_rdf/association_reflection.rb +26 -0
- data/lib/active_rdf/errors.rb +9 -0
- data/lib/active_rdf/exceptions.rb +83 -0
- data/lib/active_rdf/model.rb +69 -0
- data/lib/active_rdf/persistence.rb +185 -0
- data/lib/active_rdf/reflections.rb +19 -0
- data/lib/active_rdf/version.rb +10 -0
- data/lib/rdf/virtuoso.rb +8 -0
- data/lib/rdf/virtuoso/parser.rb +42 -0
- data/lib/rdf/virtuoso/prefixes.rb +54 -0
- data/lib/rdf/virtuoso/query.rb +632 -0
- data/lib/rdf/virtuoso/repository.rb +104 -0
- data/lib/rdf/virtuoso/version.rb +5 -0
- data/spec/active_rdf/persistence_spec.rb +31 -0
- data/spec/prefixes_spec.rb +48 -0
- data/spec/query_spec.rb +278 -0
- data/spec/repository_spec.rb +21 -0
- data/spec/spec_helper.rb +12 -0
- metadata +243 -0
@@ -0,0 +1,19 @@
|
|
1
|
+
require 'active_rdf/association_reflection'
|
2
|
+
|
3
|
+
module ActiveRDF
|
4
|
+
module Reflections
|
5
|
+
# Returns a hash containing all AssociationReflection objects for the current class
|
6
|
+
# Example:
|
7
|
+
#
|
8
|
+
# Invoice.reflections
|
9
|
+
# Account.reflections
|
10
|
+
#
|
11
|
+
def reflections
|
12
|
+
read_inheritable_attribute(:reflections) || write_inheritable_attribute(:reflections, {})
|
13
|
+
end
|
14
|
+
|
15
|
+
def reflect_on_association(association)
|
16
|
+
reflections[association].is_a?(AssociationReflection) ? reflections[association] : nil
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
data/lib/rdf/virtuoso.rb
ADDED
@@ -0,0 +1,42 @@
|
|
1
|
+
module RDF
|
2
|
+
module Virtuoso
|
3
|
+
module Parser
|
4
|
+
class JSON
|
5
|
+
|
6
|
+
def self.call(response)
|
7
|
+
parse_json_bindings(response)
|
8
|
+
end
|
9
|
+
|
10
|
+
def self.parse_json_bindings(response)
|
11
|
+
case
|
12
|
+
when response['boolean']
|
13
|
+
response['boolean']
|
14
|
+
when response['results']
|
15
|
+
solutions = response['results']['bindings'].map do |row|
|
16
|
+
row = row.inject({}) do |cols, (name, value)|
|
17
|
+
cols.merge(name.to_sym => parse_json_value(value))
|
18
|
+
end
|
19
|
+
RDF::Query::Solution.new(row)
|
20
|
+
end
|
21
|
+
RDF::Query::Solutions.new(solutions)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def self.parse_json_value(value, nodes = {})
|
26
|
+
case value['type'].to_sym
|
27
|
+
when :bnode
|
28
|
+
nodes[id = value['value']] ||= RDF::Node.new(id)
|
29
|
+
when :uri
|
30
|
+
RDF::URI.new(value['value'])
|
31
|
+
when :literal
|
32
|
+
RDF::Literal.new(value['value'], :language => value['xml:lang'])
|
33
|
+
when :'typed-literal'
|
34
|
+
RDF::Literal.new(value['value'], :datatype => value['datatype'])
|
35
|
+
else nil
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
module RDF::Virtuoso
|
2
|
+
require 'uri'
|
3
|
+
|
4
|
+
class UnProcessable; end
|
5
|
+
class Prefixes
|
6
|
+
|
7
|
+
PREFIXES = {
|
8
|
+
dc: 'http://purl.org/dc/terms/',
|
9
|
+
bibo: 'http://purl.org/ontology/bibo/',
|
10
|
+
fabio: 'http://purl.org/spar/fabio/',
|
11
|
+
rev: 'http://purl.org/stuff/rev#',
|
12
|
+
foaf: 'http://xmlns.com/foaf/0.1/',
|
13
|
+
lang: 'http://lexvo.org/id/iso639-3/'
|
14
|
+
}
|
15
|
+
|
16
|
+
class << self
|
17
|
+
def parse(uri_or_array)
|
18
|
+
prefixes = case uri_or_array
|
19
|
+
when String then [uri_or_array]
|
20
|
+
when Array then uri_or_array
|
21
|
+
else return UnProcessable.new
|
22
|
+
end
|
23
|
+
result = Set.new
|
24
|
+
prefixes.each do |prefix|
|
25
|
+
uri = URI(prefix)
|
26
|
+
str = ""
|
27
|
+
str << uri.host.split('.')[-2]
|
28
|
+
/^(?<iri>.*[\/|#]).+$/ =~ uri.to_s
|
29
|
+
str << ": <%s>" % iri
|
30
|
+
result << str
|
31
|
+
end
|
32
|
+
result.to_a
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def initialize(prefixes={})
|
37
|
+
@prefixes = prefixes
|
38
|
+
end
|
39
|
+
|
40
|
+
def to_a
|
41
|
+
ary = []
|
42
|
+
@prefixes.each_pair do |key, value|
|
43
|
+
ary << "#{key}: <#{value}>"
|
44
|
+
end
|
45
|
+
ary
|
46
|
+
end
|
47
|
+
|
48
|
+
def to_s
|
49
|
+
@prefixes.inspect
|
50
|
+
end
|
51
|
+
|
52
|
+
end
|
53
|
+
|
54
|
+
end
|
@@ -0,0 +1,632 @@
|
|
1
|
+
module RDF::Virtuoso
|
2
|
+
|
3
|
+
##
|
4
|
+
# A SPARQL query builder.
|
5
|
+
#
|
6
|
+
# @example Iterating over all found solutions
|
7
|
+
# query.each_solution { |solution| puts solution.inspect }
|
8
|
+
#
|
9
|
+
class Query < RDF::Query
|
10
|
+
##
|
11
|
+
# @return [Symbol]
|
12
|
+
# @see http://www.w3.org/TR/rdf-sparql-query/#QueryForms
|
13
|
+
attr_reader :form
|
14
|
+
|
15
|
+
##
|
16
|
+
# @return [Hash{Symbol => Object}]
|
17
|
+
attr_reader :options
|
18
|
+
|
19
|
+
##
|
20
|
+
# @return [Array<[key, RDF::Value]>]
|
21
|
+
attr_reader :values
|
22
|
+
|
23
|
+
|
24
|
+
attr_reader :data_values
|
25
|
+
|
26
|
+
##
|
27
|
+
# Creates a boolean `ASK` query.
|
28
|
+
#
|
29
|
+
# @param [Hash{Symbol => Object}] options
|
30
|
+
# @return [Query]
|
31
|
+
# @see http://www.w3.org/TR/rdf-sparql-query/#ask
|
32
|
+
def self.ask(options = {})
|
33
|
+
self.new(:ask, options)
|
34
|
+
end
|
35
|
+
|
36
|
+
##
|
37
|
+
# Creates a tuple `SELECT` query.
|
38
|
+
#
|
39
|
+
# @param [Array<Symbol>] variables
|
40
|
+
# @param [Hash{Symbol => Object}] options
|
41
|
+
# @return [Query]
|
42
|
+
# @see http://www.w3.org/TR/rdf-sparql-query/#select
|
43
|
+
def self.select(*variables)
|
44
|
+
options = variables.last.is_a?(Hash) ? variables.pop : {}
|
45
|
+
self.new(:select, options).select(*variables)
|
46
|
+
end
|
47
|
+
|
48
|
+
##
|
49
|
+
# Creates a `DESCRIBE` query.
|
50
|
+
#
|
51
|
+
# @param [Array<Symbol, RDF::URI>] variables
|
52
|
+
# @param [Hash{Symbol => Object}] options
|
53
|
+
# @return [Query]
|
54
|
+
# @see http://www.w3.org/TR/rdf-sparql-query/#describe
|
55
|
+
def self.describe(*variables)
|
56
|
+
options = variables.last.is_a?(Hash) ? variables.pop : {}
|
57
|
+
self.new(:describe, options).describe(*variables)
|
58
|
+
end
|
59
|
+
|
60
|
+
##
|
61
|
+
# Creates a graph `CONSTRUCT` query.
|
62
|
+
#
|
63
|
+
# @param [Array<RDF::Query::Pattern, Array>] patterns
|
64
|
+
# @param [Hash{Symbol => Object}] options
|
65
|
+
# @return [Query]
|
66
|
+
# @see http://www.w3.org/TR/rdf-sparql-query/#construct
|
67
|
+
def self.construct(*patterns)
|
68
|
+
options = patterns.last.is_a?(Hash) ? patterns.pop : {}
|
69
|
+
self.new(:construct, options).construct(*patterns) # FIXME
|
70
|
+
end
|
71
|
+
|
72
|
+
##
|
73
|
+
# Creates an `UPDATE` query.
|
74
|
+
#
|
75
|
+
# @param [Array<RDF::Query::Pattern, Array>] patterns
|
76
|
+
# @param [Hash{Symbol => Object}] options
|
77
|
+
# @return [Query]
|
78
|
+
# @see http://www.w3.org/Submission/SPARQL-Update/
|
79
|
+
def self.insert_data(*patterns)
|
80
|
+
# options = variables.last.is_a?(Hash) ? variables.pop : {}
|
81
|
+
options = patterns.last.is_a?(Hash) ? patterns.pop : {}
|
82
|
+
self.new(:insert_data, options).insert_data(*patterns)
|
83
|
+
end
|
84
|
+
|
85
|
+
def self.insert(*patterns)
|
86
|
+
# options = variables.last.is_a?(Hash) ? variables.pop : {}
|
87
|
+
options = patterns.last.is_a?(Hash) ? patterns.pop : {}
|
88
|
+
self.new(:insert, options).insert(*patterns)
|
89
|
+
end
|
90
|
+
|
91
|
+
def self.delete_data(*patterns)
|
92
|
+
options = patterns.last.is_a?(Hash) ? patterns.pop : {}
|
93
|
+
self.new(:delete_data, options).delete_data(*patterns)
|
94
|
+
end
|
95
|
+
|
96
|
+
def self.delete(*patterns)
|
97
|
+
options = patterns.last.is_a?(Hash) ? patterns.pop : {}
|
98
|
+
self.new(:delete, options).delete(*patterns)
|
99
|
+
end
|
100
|
+
|
101
|
+
def self.create(*variables)
|
102
|
+
options = variables.last.is_a?(Hash) ? variables.pop : {}
|
103
|
+
self.new(:create, options).create(variables.first)
|
104
|
+
end
|
105
|
+
|
106
|
+
def self.drop(*variables)
|
107
|
+
options = variables.last.is_a?(Hash) ? variables.pop : {}
|
108
|
+
self.new(:drop, options).drop(variables.first)
|
109
|
+
end
|
110
|
+
|
111
|
+
def self.clear(*variables)
|
112
|
+
options = variables.last.is_a?(Hash) ? variables.pop : {}
|
113
|
+
self.new(:clear, options).clear(variables.first)
|
114
|
+
end
|
115
|
+
|
116
|
+
##
|
117
|
+
# @param [Symbol, #to_s] form
|
118
|
+
# @param [Hash{Symbol => Object}] options
|
119
|
+
# @yield [query]
|
120
|
+
# @yieldparam [Query]
|
121
|
+
def initialize(form = :ask, options = {}, &block)
|
122
|
+
@form = form.respond_to?(:to_sym) ? form.to_sym : form.to_s.to_sym
|
123
|
+
super([], options, &block)
|
124
|
+
end
|
125
|
+
|
126
|
+
##
|
127
|
+
# @return [Query]
|
128
|
+
# @see http://www.w3.org/TR/rdf-sparql-query/#ask
|
129
|
+
def ask
|
130
|
+
@form = :ask
|
131
|
+
self
|
132
|
+
end
|
133
|
+
|
134
|
+
##
|
135
|
+
# @param [Array<Symbol>] variables
|
136
|
+
# @return [Query]
|
137
|
+
# @see http://www.w3.org/TR/rdf-sparql-query/#select
|
138
|
+
def select(*variables)
|
139
|
+
@values = variables.map { |var| [var, RDF::Query::Variable.new(var)] }
|
140
|
+
self
|
141
|
+
end
|
142
|
+
|
143
|
+
##
|
144
|
+
# @param [Array<Symbol>] variables
|
145
|
+
# @return [Query]
|
146
|
+
# @see http://www.w3.org/TR/rdf-sparql-query/#describe
|
147
|
+
def describe(*variables)
|
148
|
+
@values = variables.map { |var|
|
149
|
+
[var, var.is_a?(RDF::URI) ? var : RDF::Query::Variable.new(var)]
|
150
|
+
}
|
151
|
+
self
|
152
|
+
end
|
153
|
+
|
154
|
+
##
|
155
|
+
# @param [Array<RDF::Query::Pattern, Array>] patterns
|
156
|
+
# @return [Query]
|
157
|
+
# @see http://www.w3.org/TR/rdf-sparql-query/#construct
|
158
|
+
def construct(*patterns)
|
159
|
+
new_patterns = []
|
160
|
+
patterns.each do |pattern|
|
161
|
+
new_patterns << pattern.map do |value|
|
162
|
+
if value.is_a?(Symbol)
|
163
|
+
value = RDF::Query::Variable.new(value)
|
164
|
+
elsif value.is_a?(RDF::URI)
|
165
|
+
value = value
|
166
|
+
else
|
167
|
+
value = RDF::Literal.new(value)
|
168
|
+
end
|
169
|
+
end
|
170
|
+
end
|
171
|
+
@data_values = build_patterns(new_patterns)
|
172
|
+
self
|
173
|
+
end
|
174
|
+
|
175
|
+
|
176
|
+
##
|
177
|
+
# @param [Array<RDF::Query::Pattern, Array>] patterns
|
178
|
+
# @return [Query]
|
179
|
+
# @see http://www.w3.org/Submission/SPARQL-Update/
|
180
|
+
def insert_data(*patterns)
|
181
|
+
new_patterns = []
|
182
|
+
patterns.each do |values|
|
183
|
+
new_patterns << values.map { |var| [var, var.is_a?(RDF::URI) ? var : var] }
|
184
|
+
end
|
185
|
+
@data_values = new_patterns #build_patterns(new_patterns)
|
186
|
+
self
|
187
|
+
end
|
188
|
+
|
189
|
+
def insert(*patterns)
|
190
|
+
new_patterns = []
|
191
|
+
patterns.each do |pattern|
|
192
|
+
new_patterns << pattern.map do |value|
|
193
|
+
if value.is_a?(Symbol)
|
194
|
+
value = RDF::Query::Variable.new(value)
|
195
|
+
elsif value.is_a?(RDF::URI)
|
196
|
+
value = value
|
197
|
+
else
|
198
|
+
value = RDF::Literal.new(value)
|
199
|
+
end
|
200
|
+
end
|
201
|
+
end
|
202
|
+
@data_values = build_patterns(new_patterns)
|
203
|
+
self
|
204
|
+
end
|
205
|
+
|
206
|
+
def delete_data(*patterns)
|
207
|
+
new_patterns = []
|
208
|
+
patterns.each do |values|
|
209
|
+
new_patterns << values.map { |var| [var, var.is_a?(RDF::URI) ? var : var] }
|
210
|
+
end
|
211
|
+
@data_values = new_patterns #build_patterns(new_patterns)
|
212
|
+
self
|
213
|
+
end
|
214
|
+
|
215
|
+
def delete(*patterns)
|
216
|
+
new_patterns = []
|
217
|
+
patterns.each do |pattern|
|
218
|
+
new_patterns << pattern.map do |value|
|
219
|
+
if value.is_a?(Symbol)
|
220
|
+
value = RDF::Query::Variable.new(value)
|
221
|
+
elsif value.is_a?(RDF::URI)
|
222
|
+
value = value
|
223
|
+
else
|
224
|
+
value = RDF::Literal.new(value)
|
225
|
+
end
|
226
|
+
end
|
227
|
+
end
|
228
|
+
@data_values = build_patterns(new_patterns)
|
229
|
+
self
|
230
|
+
end
|
231
|
+
|
232
|
+
# def delete(*variables)
|
233
|
+
# @values = variables.map { |var|
|
234
|
+
# [var, var.is_a?(RDF::URI) ? var : RDF::Query::Variable.new(var)]
|
235
|
+
# }
|
236
|
+
# self
|
237
|
+
# end
|
238
|
+
|
239
|
+
def create(uri)
|
240
|
+
options[:graph] = uri
|
241
|
+
self
|
242
|
+
end
|
243
|
+
|
244
|
+
def drop(uri)
|
245
|
+
options[:graph] = uri
|
246
|
+
self
|
247
|
+
end
|
248
|
+
|
249
|
+
def clear(uri)
|
250
|
+
options[:graph] = uri
|
251
|
+
self
|
252
|
+
end
|
253
|
+
|
254
|
+
# @param RDF::URI uri
|
255
|
+
# @return [Query]
|
256
|
+
# @see http://www.w3.org/TR/rdf-sparql-query/#specDataset
|
257
|
+
def from(uri)
|
258
|
+
options[:from] = uri
|
259
|
+
self
|
260
|
+
end
|
261
|
+
|
262
|
+
# @param RDF::URI uri
|
263
|
+
# @return [Query]
|
264
|
+
def graph(uri)
|
265
|
+
options[:graph] = uri
|
266
|
+
self
|
267
|
+
end
|
268
|
+
|
269
|
+
##
|
270
|
+
# @param [Array<RDF::Query::Pattern, Array>] patterns
|
271
|
+
# @return [Query]
|
272
|
+
# @see http://www.w3.org/TR/rdf-sparql-query/#GraphPattern
|
273
|
+
def where(*patterns)
|
274
|
+
@patterns += build_patterns(patterns)
|
275
|
+
self
|
276
|
+
end
|
277
|
+
|
278
|
+
alias_method :whether, :where
|
279
|
+
|
280
|
+
##
|
281
|
+
# @param [Array<Symbol, String>] variables
|
282
|
+
# @return [Query]
|
283
|
+
# @see http://www.w3.org/TR/rdf-sparql-query/#modOrderBy
|
284
|
+
def order(*variables)
|
285
|
+
options[:order_by] = variables
|
286
|
+
self
|
287
|
+
end
|
288
|
+
|
289
|
+
alias_method :order_by, :order
|
290
|
+
|
291
|
+
##
|
292
|
+
# @return [Query]
|
293
|
+
# @see http://www.w3.org/TR/rdf-sparql-query/#modDistinct
|
294
|
+
def distinct(state = true)
|
295
|
+
options[:distinct] = state
|
296
|
+
self
|
297
|
+
end
|
298
|
+
|
299
|
+
##
|
300
|
+
# @return [Query]
|
301
|
+
# @see http://www.w3.org/TR/rdf-sparql-query/#modReduced
|
302
|
+
def reduced(state = true)
|
303
|
+
options[:reduced] = state
|
304
|
+
self
|
305
|
+
end
|
306
|
+
|
307
|
+
## SPARQL 1.1 Aggregates
|
308
|
+
# @return [Query]
|
309
|
+
# @see http://www.w3.org/TR/sparql11-query/#defn_aggCount
|
310
|
+
# def count(*variables)
|
311
|
+
# options[:count] = variables
|
312
|
+
# self
|
313
|
+
# end
|
314
|
+
AGG_METHODS = %w(count min max sum avg sample group_concat group_digest)
|
315
|
+
|
316
|
+
AGG_METHODS.each do |m|
|
317
|
+
define_method m do |*variables|
|
318
|
+
options[m.to_sym] = variables
|
319
|
+
self
|
320
|
+
end
|
321
|
+
end
|
322
|
+
|
323
|
+
##
|
324
|
+
# @param [Integer, #to_i] start
|
325
|
+
# @return [Query]
|
326
|
+
# @see http://www.w3.org/TR/rdf-sparql-query/#modOffset
|
327
|
+
def offset(start)
|
328
|
+
slice(start, nil)
|
329
|
+
end
|
330
|
+
|
331
|
+
##
|
332
|
+
# @param [Integer, #to_i] length
|
333
|
+
# @return [Query]
|
334
|
+
# @see http://www.w3.org/TR/rdf-sparql-query/#modResultLimit
|
335
|
+
def limit(length)
|
336
|
+
slice(nil, length)
|
337
|
+
end
|
338
|
+
|
339
|
+
##
|
340
|
+
# @param [Integer, #to_i] start
|
341
|
+
# @param [Integer, #to_i] length
|
342
|
+
# @return [Query]
|
343
|
+
def slice(start, length)
|
344
|
+
options[:offset] = start.to_i if start
|
345
|
+
options[:limit] = length.to_i if length
|
346
|
+
self
|
347
|
+
end
|
348
|
+
|
349
|
+
##
|
350
|
+
# @return [Query]
|
351
|
+
# @see http://www.w3.org/TR/rdf-sparql-query/#prefNames
|
352
|
+
def prefix(string)
|
353
|
+
(options[:prefixes] ||= []) << string
|
354
|
+
self
|
355
|
+
end
|
356
|
+
|
357
|
+
##
|
358
|
+
# @return [Query]
|
359
|
+
# @see http://www.w3.org/TR/rdf-sparql-query/#prefNames
|
360
|
+
def prefixes(prefixes = nil)
|
361
|
+
options[:prefixes] ||= []
|
362
|
+
options[:prefixes] += prefixes.to_a
|
363
|
+
self
|
364
|
+
end
|
365
|
+
|
366
|
+
##
|
367
|
+
# @return [Query]
|
368
|
+
# @see http://www.w3.org/TR/rdf-sparql-query/#optionals
|
369
|
+
def optional(*patterns)
|
370
|
+
(options[:optionals] ||= []) << build_patterns(patterns)
|
371
|
+
self
|
372
|
+
end
|
373
|
+
|
374
|
+
##
|
375
|
+
# @return [Query]
|
376
|
+
# @see http://www.w3.org/TR/rdf-sparql-query/#minus
|
377
|
+
def minus(*patterns)
|
378
|
+
(options[:minuses] ||= []) << build_patterns(patterns)
|
379
|
+
self
|
380
|
+
end
|
381
|
+
|
382
|
+
def union(*patterns)
|
383
|
+
(options[:unions] ||= []) << build_patterns(patterns)
|
384
|
+
self
|
385
|
+
end
|
386
|
+
|
387
|
+
##
|
388
|
+
# @private
|
389
|
+
def build_patterns(patterns)
|
390
|
+
patterns.map do |pattern|
|
391
|
+
case pattern
|
392
|
+
when RDF::Query::Pattern then pattern
|
393
|
+
else RDF::Query::Pattern.new(*pattern.to_a)
|
394
|
+
end
|
395
|
+
end
|
396
|
+
end
|
397
|
+
|
398
|
+
##
|
399
|
+
# @private
|
400
|
+
def filter(string)
|
401
|
+
(options[:filters] ||= []) << string
|
402
|
+
self
|
403
|
+
end
|
404
|
+
|
405
|
+
def filters(filters = nil)
|
406
|
+
options[:filters] ||= []
|
407
|
+
options[:filters] += filters.to_a
|
408
|
+
self
|
409
|
+
end
|
410
|
+
|
411
|
+
##
|
412
|
+
# @return [Boolean]
|
413
|
+
def true?
|
414
|
+
case result
|
415
|
+
when TrueClass, FalseClass then result
|
416
|
+
when Enumerable then !result.empty?
|
417
|
+
else false
|
418
|
+
end
|
419
|
+
end
|
420
|
+
|
421
|
+
##
|
422
|
+
# @return [Boolean]
|
423
|
+
def false?
|
424
|
+
!true?
|
425
|
+
end
|
426
|
+
|
427
|
+
##
|
428
|
+
# @return [Enumerable<RDF::Query::Solution>]
|
429
|
+
def solutions
|
430
|
+
result
|
431
|
+
end
|
432
|
+
|
433
|
+
##
|
434
|
+
# @yield [statement]
|
435
|
+
# @yieldparam [RDF::Statement]
|
436
|
+
# @return [Enumerator]
|
437
|
+
def each_statement(&block)
|
438
|
+
result.each_statement(&block)
|
439
|
+
end
|
440
|
+
|
441
|
+
##
|
442
|
+
# @return [Object]
|
443
|
+
def result
|
444
|
+
@result ||= execute
|
445
|
+
end
|
446
|
+
|
447
|
+
##
|
448
|
+
# @return [Object]
|
449
|
+
def execute
|
450
|
+
#query
|
451
|
+
#raise NotImplementedError
|
452
|
+
end
|
453
|
+
|
454
|
+
##
|
455
|
+
# Returns the string representation of this query.
|
456
|
+
#
|
457
|
+
# @return [String]
|
458
|
+
def to_s
|
459
|
+
buffer = [form.to_s.gsub('_', ' ').upcase]
|
460
|
+
case form
|
461
|
+
when :select, :describe
|
462
|
+
buffer << 'DISTINCT' if options[:distinct]
|
463
|
+
buffer << 'REDUCED' if options[:reduced]
|
464
|
+
# Aggregates in select/describe
|
465
|
+
aggregates = [:count, :min, :max, :avg, :sum, :sample, :group_concat, :group_digest]
|
466
|
+
if (options.keys & aggregates).any?
|
467
|
+
(options.keys & aggregates).each do |agg|
|
468
|
+
case agg
|
469
|
+
when :sample
|
470
|
+
buffer << '(sql:' + agg.to_s.upcase
|
471
|
+
buffer << options[agg].map { |var| var.is_a?(String) ? var : "(?#{var})" }
|
472
|
+
when :group_concat, :group_digest
|
473
|
+
buffer << '(sql:' + agg.to_s.upcase
|
474
|
+
buffer << options[agg].map { |var| var.is_a?(Symbol) ? "(?#{var}" : "'#{var}'"}.join(', ')
|
475
|
+
buffer << ')'
|
476
|
+
else
|
477
|
+
buffer << '(' + agg.to_s.gsub('_', ' ').upcase
|
478
|
+
buffer << options[agg].map { |var| var.is_a?(String) ? var : "(?#{var})" }
|
479
|
+
end
|
480
|
+
|
481
|
+
buffer << 'AS ?' + agg.to_s + ')'
|
482
|
+
end
|
483
|
+
else
|
484
|
+
buffer << (values.empty? ? '*' : values.map { |v| serialize_value(v[1]) }.join(' '))
|
485
|
+
end
|
486
|
+
when :construct
|
487
|
+
buffer << '{'
|
488
|
+
buffer += serialize_patterns(@data_values)
|
489
|
+
buffer << '}'
|
490
|
+
|
491
|
+
# for virtuoso inserts
|
492
|
+
when :insert_data
|
493
|
+
buffer << "INTO GRAPH #{serialize_value(options[:graph])}" if options[:graph]
|
494
|
+
buffer << '{'
|
495
|
+
@data_values.each do |triple|
|
496
|
+
if triple.first.first.is_a?(RDF::Statement)
|
497
|
+
buffer << triple.map { |v| serialize_value(v[1])}
|
498
|
+
else
|
499
|
+
buffer << triple.map { |v| serialize_value(v[1])}.join(' ') + " ."
|
500
|
+
end
|
501
|
+
end
|
502
|
+
buffer << '}'
|
503
|
+
|
504
|
+
when :insert
|
505
|
+
buffer << "INTO GRAPH #{serialize_value(options[:graph])}" if options[:graph]
|
506
|
+
# buffer += serialize_patterns(options[:template])
|
507
|
+
# (@data_values.map { |v| puts v[1].inspect; puts 'xxx ' } )
|
508
|
+
buffer << '{'
|
509
|
+
buffer += serialize_patterns(@data_values)
|
510
|
+
buffer << '}'
|
511
|
+
|
512
|
+
when :delete_data
|
513
|
+
buffer << "FROM #{serialize_value(options[:graph])}" #if options[:graph]
|
514
|
+
buffer << '{'
|
515
|
+
@data_values.each do |triple|
|
516
|
+
if triple.first.first.is_a?(RDF::Statement)
|
517
|
+
buffer << triple.map { |v| serialize_value(v[1])}
|
518
|
+
else
|
519
|
+
buffer << triple.map { |v| serialize_value(v[1])}.join(' ') + " ."
|
520
|
+
end
|
521
|
+
end
|
522
|
+
buffer << '}'
|
523
|
+
|
524
|
+
when :delete
|
525
|
+
buffer << "FROM #{serialize_value(options[:graph])}" if options[:graph]
|
526
|
+
buffer << '{'
|
527
|
+
buffer += serialize_patterns(@data_values)
|
528
|
+
buffer << '}'
|
529
|
+
|
530
|
+
when :create, :drop
|
531
|
+
buffer << 'SILENT' if options[:silent]
|
532
|
+
buffer << "GRAPH #{serialize_value(options[:graph])}"
|
533
|
+
|
534
|
+
when :clear
|
535
|
+
buffer << "GRAPH #{serialize_value(options[:graph])}"
|
536
|
+
|
537
|
+
end
|
538
|
+
|
539
|
+
buffer << "FROM #{serialize_value(options[:from])}" if options[:from]
|
540
|
+
|
541
|
+
unless patterns.empty? && ([:describe, :insert_data, :delete_data, :create, :clear, :drop].include?(form))
|
542
|
+
buffer << 'WHERE {'
|
543
|
+
|
544
|
+
buffer << '{' if options[:unions]
|
545
|
+
|
546
|
+
buffer += serialize_patterns(patterns)
|
547
|
+
if options[:optionals]
|
548
|
+
options[:optionals].each do |patterns|
|
549
|
+
buffer << 'OPTIONAL {'
|
550
|
+
buffer += serialize_patterns(patterns)
|
551
|
+
buffer << '}'
|
552
|
+
end
|
553
|
+
end
|
554
|
+
|
555
|
+
if options[:minuses]
|
556
|
+
options[:minuses].each do |patterns|
|
557
|
+
buffer << 'MINUS {'
|
558
|
+
buffer += serialize_patterns(patterns)
|
559
|
+
buffer << '}'
|
560
|
+
end
|
561
|
+
end
|
562
|
+
|
563
|
+
if options[:filters]
|
564
|
+
buffer += options[:filters].map { |filter| "FILTER(#{filter})" }
|
565
|
+
end
|
566
|
+
buffer << '}'
|
567
|
+
|
568
|
+
if options[:unions]
|
569
|
+
options[:unions].each do |patterns|
|
570
|
+
buffer << 'UNION {'
|
571
|
+
buffer += serialize_patterns(patterns)
|
572
|
+
buffer << '}'
|
573
|
+
end
|
574
|
+
buffer << '}'
|
575
|
+
end
|
576
|
+
|
577
|
+
end
|
578
|
+
|
579
|
+
if options[:order_by]
|
580
|
+
buffer << 'ORDER BY'
|
581
|
+
buffer += options[:order_by].map { |var| var.is_a?(String) ? var : "?#{var}" }
|
582
|
+
end
|
583
|
+
|
584
|
+
buffer << "OFFSET #{options[:offset]}" if options[:offset]
|
585
|
+
buffer << "LIMIT #{options[:limit]}" if options[:limit]
|
586
|
+
options[:prefixes].reverse.each {|e| buffer.unshift("PREFIX #{e}") } if options[:prefixes]
|
587
|
+
|
588
|
+
buffer.join(' ')
|
589
|
+
end
|
590
|
+
|
591
|
+
##
|
592
|
+
# @private
|
593
|
+
def serialize_patterns(patterns)
|
594
|
+
patterns.map do |p|
|
595
|
+
p.to_triple.map { |v| serialize_value(v) }.join(' ') << " ."
|
596
|
+
end
|
597
|
+
end
|
598
|
+
|
599
|
+
##
|
600
|
+
# Outputs a developer-friendly representation of this query to `stderr`.
|
601
|
+
#
|
602
|
+
# @return [void]
|
603
|
+
def inspect!
|
604
|
+
warn(inspect)
|
605
|
+
self
|
606
|
+
end
|
607
|
+
|
608
|
+
##
|
609
|
+
# Returns a developer-friendly representation of this query.
|
610
|
+
#
|
611
|
+
# @return [String]
|
612
|
+
def inspect
|
613
|
+
sprintf("#<%s:%#0x(%s)>", self.class.name, __id__, to_s)
|
614
|
+
end
|
615
|
+
|
616
|
+
##
|
617
|
+
# Serializes an RDF::Value into a format appropriate for select, construct, and where clauses
|
618
|
+
#
|
619
|
+
# @param [RDF::Value]
|
620
|
+
# @return [String]
|
621
|
+
# @private
|
622
|
+
def serialize_value(value)
|
623
|
+
# SPARQL queries are UTF-8, but support ASCII-style Unicode escapes, so
|
624
|
+
# the N-Triples serializer is fine unless it's a variable:
|
625
|
+
case
|
626
|
+
when value.is_a?(String) then value.inspect
|
627
|
+
when value.variable? then value.to_s
|
628
|
+
else RDF::NTriples.serialize(value)
|
629
|
+
end
|
630
|
+
end
|
631
|
+
end
|
632
|
+
end
|