sparql-client 2.2.1 → 3.1.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,4 +1,6 @@
1
- module SPARQL; class Client
1
+ require 'delegate'
2
+
3
+ class SPARQL::Client
2
4
  ##
3
5
  # A SPARQL query builder.
4
6
  #
@@ -10,19 +12,13 @@ module SPARQL; class Client
10
12
  # The form of the query.
11
13
  #
12
14
  # @return [:select, :ask, :construct, :describe]
13
- # @see http://www.w3.org/TR/sparql11-query/#QueryForms
15
+ # @see https://www.w3.org/TR/sparql11-query/#QueryForms
14
16
  attr_reader :form
15
17
 
16
18
  ##
17
19
  # @return [Hash{Symbol => Object}]
18
20
  attr_reader :options
19
21
 
20
- ##
21
- # Values returned from previous query.
22
- #
23
- # @return [Array<[key, RDF::Value]>]
24
- attr_reader :values
25
-
26
22
  ##
27
23
  # Creates a boolean `ASK` query.
28
24
  #
@@ -31,34 +27,33 @@ module SPARQL; class Client
31
27
  #
32
28
  # @param [Hash{Symbol => Object}] options (see {#initialize})
33
29
  # @return [Query]
34
- # @see http://www.w3.org/TR/sparql11-query/#ask
35
- def self.ask(options = {})
36
- self.new(:ask, options)
30
+ # @see https://www.w3.org/TR/sparql11-query/#ask
31
+ def self.ask(**options)
32
+ self.new(:ask, **options)
37
33
  end
38
34
 
39
35
  ##
40
36
  # Creates a tuple `SELECT` query.
41
37
  #
42
- # @example SELECT * WHERE { ?s ?p ?o . }
38
+ # @example `SELECT * WHERE { ?s ?p ?o . }`
43
39
  # Query.select.where([:s, :p, :o])
44
40
  #
45
- # @example SELECT ?s WHERE {?s ?p ?o .}
41
+ # @example `SELECT ?s WHERE {?s ?p ?o .}`
46
42
  # Query.select(:s).where([:s, :p, :o])
47
43
  #
48
- # @example SELECT COUNT(?uri as ?c) WHERE {?uri a owl:Class}
44
+ # @example `SELECT COUNT(?uri as ?c) WHERE {?uri a owl:Class}`
49
45
  # Query.select(count: {uri: :c}).where([:uri, RDF.type, RDF::OWL.Class])
50
46
  #
51
47
  # @param [Array<Symbol>] variables
52
48
  # @return [Query]
53
49
  #
54
- # @overload self.select(*variables, options)
50
+ # @overload self.select(*variables, **options)
55
51
  # @param [Array<Symbol>] variables
56
52
  # @param [Hash{Symbol => Object}] options (see {#initialize})
57
53
  # @return [Query]
58
- # @see http://www.w3.org/TR/sparql11-query/#select
59
- def self.select(*variables)
60
- options = variables.last.is_a?(Hash) ? variables.pop : {}
61
- self.new(:select, options).select(*variables)
54
+ # @see https://www.w3.org/TR/sparql11-query/#select
55
+ def self.select(*variables, **options)
56
+ self.new(:select, **options).select(*variables)
62
57
  end
63
58
 
64
59
  ##
@@ -70,14 +65,13 @@ module SPARQL; class Client
70
65
  # @param [Array<Symbol, RDF::URI>] variables
71
66
  # @return [Query]
72
67
  #
73
- # @overload self.describe(*variables, options)
68
+ # @overload self.describe(*variables, **options)
74
69
  # @param [Array<Symbol, RDF::URI>] variables
75
70
  # @param [Hash{Symbol => Object}] options (see {#initialize})
76
71
  # @return [Query]
77
- # @see http://www.w3.org/TR/sparql11-query/#describe
78
- def self.describe(*variables)
79
- options = variables.last.is_a?(Hash) ? variables.pop : {}
80
- self.new(:describe, options).describe(*variables)
72
+ # @see https://www.w3.org/TR/sparql11-query/#describe
73
+ def self.describe(*variables, **options)
74
+ self.new(:describe, **options).describe(*variables)
81
75
  end
82
76
 
83
77
  ##
@@ -89,19 +83,18 @@ module SPARQL; class Client
89
83
  # @param [Array<RDF::Query::Pattern, Array>] patterns
90
84
  # @return [Query]
91
85
  #
92
- # @overload self.construct(*variables, options)
86
+ # @overload self.construct(*variables, **options)
93
87
  # @param [Array<RDF::Query::Pattern, Array>] patterns
94
88
  # @param [Hash{Symbol => Object}] options (see {#initialize})
95
89
  # @return [Query]
96
- # @see http://www.w3.org/TR/sparql11-query/#construct
97
- def self.construct(*patterns)
98
- options = patterns.last.is_a?(Hash) ? patterns.pop : {}
99
- self.new(:construct, options).construct(*patterns) # FIXME
90
+ # @see https://www.w3.org/TR/sparql11-query/#construct
91
+ def self.construct(*patterns, **options)
92
+ self.new(:construct, **options).construct(*patterns) # FIXME
100
93
  end
101
94
 
102
95
  ##
103
96
  # @param [Symbol, #to_s] form
104
- # @overload self.construct(*variables, options)
97
+ # @overload self.construct(*variables, **options)
105
98
  # @param [Symbol, #to_s] form
106
99
  # @param [Hash{Symbol => Object}] options (see {Client#initialize})
107
100
  # @option options [Hash{Symbol => Symbol}] :count
@@ -110,10 +103,10 @@ module SPARQL; class Client
110
103
  #
111
104
  # @yield [query]
112
105
  # @yieldparam [Query]
113
- def initialize(form = :ask, options = {}, &block)
106
+ def initialize(form = :ask, **options, &block)
114
107
  @subqueries = []
115
108
  @form = form.respond_to?(:to_sym) ? form.to_sym : form.to_s.to_sym
116
- super([], options, &block)
109
+ super([], **options, &block)
117
110
  end
118
111
 
119
112
  ##
@@ -121,27 +114,31 @@ module SPARQL; class Client
121
114
  # query.ask.where([:s, :p, :o])
122
115
  #
123
116
  # @return [Query]
124
- # @see http://www.w3.org/TR/sparql11-query/#ask
117
+ # @see https://www.w3.org/TR/sparql11-query/#ask
125
118
  def ask
126
119
  @form = :ask
127
120
  self
128
121
  end
129
122
 
130
123
  ##
131
- # @example SELECT * WHERE { ?s ?p ?o . }
124
+ # @example `SELECT * WHERE { ?s ?p ?o . }`
132
125
  # query.select.where([:s, :p, :o])
133
126
  #
134
- # @example SELECT ?s WHERE {?s ?p ?o .}
127
+ # @example `SELECT ?s WHERE {?s ?p ?o .}`
135
128
  # query.select(:s).where([:s, :p, :o])
136
129
  #
137
- # @example SELECT COUNT(?uri as ?c) WHERE {?uri a owl:Class}
130
+ # @example `SELECT COUNT(?uri as ?c) WHERE {?uri a owl:Class}`
138
131
  # query.select(count: {uri: :c}).where([:uri, RDF.type, RDF::OWL.Class])
139
132
  #
140
- # @param [Array<Symbol>] variables
133
+ # @param [Array<Symbol>, Hash{Symbol => RDF::Query::Variable}] variables
141
134
  # @return [Query]
142
- # @see http://www.w3.org/TR/sparql11-query/#select
135
+ # @see https://www.w3.org/TR/sparql11-query/#select
143
136
  def select(*variables)
144
- @values = variables.map { |var| [var, RDF::Query::Variable.new(var)] }
137
+ @values = if variables.length == 1 && variables.first.is_a?(Hash)
138
+ variables.to_a
139
+ else
140
+ variables.map { |var| [var, RDF::Query::Variable.new(var)] }
141
+ end
145
142
  self
146
143
  end
147
144
 
@@ -151,7 +148,7 @@ module SPARQL; class Client
151
148
  #
152
149
  # @param [Array<Symbol>] variables
153
150
  # @return [Query]
154
- # @see http://www.w3.org/TR/sparql11-query/#describe
151
+ # @see https://www.w3.org/TR/sparql11-query/#describe
155
152
  def describe(*variables)
156
153
  @values = variables.map { |var|
157
154
  [var, var.is_a?(RDF::URI) ? var : RDF::Query::Variable.new(var)]
@@ -165,7 +162,7 @@ module SPARQL; class Client
165
162
  #
166
163
  # @param [Array<RDF::Query::Pattern, Array>] patterns
167
164
  # @return [Query]
168
- # @see http://www.w3.org/TR/sparql11-query/#construct
165
+ # @see https://www.w3.org/TR/sparql11-query/#construct
169
166
  def construct(*patterns)
170
167
  options[:template] = build_patterns(patterns)
171
168
  self
@@ -177,7 +174,7 @@ module SPARQL; class Client
177
174
  #
178
175
  # @param [RDF::URI] uri
179
176
  # @return [Query]
180
- # @see http://www.w3.org/TR/sparql11-query/#specifyingDataset
177
+ # @see https://www.w3.org/TR/sparql11-query/#specifyingDataset
181
178
  def from(uri)
182
179
  options[:from] = uri
183
180
  self
@@ -210,7 +207,7 @@ module SPARQL; class Client
210
207
  # Yield form with or without argument; without an argument, evaluates within the query.
211
208
  # @yieldparam [SPARQL::Client::Query] query Actually a delegator to query. Methods other than `#select` are evaluated against `self`. For `#select`, a new Query is created, and the result added as a subquery.
212
209
  # @return [Query]
213
- # @see http://www.w3.org/TR/sparql11-query/#GraphPattern
210
+ # @see https://www.w3.org/TR/sparql11-query/#GraphPattern
214
211
  def where(*patterns_queries, &block)
215
212
  subqueries, patterns = patterns_queries.partition {|pq| pq.is_a? SPARQL::Client::Query}
216
213
  @patterns += build_patterns(patterns)
@@ -246,11 +243,11 @@ module SPARQL; class Client
246
243
  # query.select.where([:s, :p, :o]).order_by(:o, :p)
247
244
  #
248
245
  # @example SELECT * WHERE { ?s ?p ?o . } ORDER BY ASC(?o) DESC(?p)
249
- # query.select.where([:s, :p, :o]).order_by(:o => :asc, :p => :desc)
246
+ # query.select.where([:s, :p, :o]).order_by(o: :asc, p: :desc)
250
247
  #
251
248
  # @param [Array<Symbol, String>] variables
252
249
  # @return [Query]
253
- # @see http://www.w3.org/TR/sparql11-query/#modOrderBy
250
+ # @see https://www.w3.org/TR/sparql11-query/#modOrderBy
254
251
  def order(*variables)
255
252
  options[:order_by] = variables
256
253
  self
@@ -265,7 +262,7 @@ module SPARQL; class Client
265
262
  #
266
263
  # @param [Array<Symbol, String>] var
267
264
  # @return [Query]
268
- # @see http://www.w3.org/TR/sparql11-query/#modOrderBy
265
+ # @see https://www.w3.org/TR/sparql11-query/#modOrderBy
269
266
  def asc(var)
270
267
  (options[:order_by] ||= []) << {var => :asc}
271
268
  self
@@ -278,7 +275,7 @@ module SPARQL; class Client
278
275
  #
279
276
  # @param [Array<Symbol, String>] var
280
277
  # @return [Query]
281
- # @see http://www.w3.org/TR/sparql11-query/#modOrderBy
278
+ # @see https://www.w3.org/TR/sparql11-query/#modOrderBy
282
279
  def desc(var)
283
280
  (options[:order_by] ||= []) << {var => :desc}
284
281
  self
@@ -290,7 +287,7 @@ module SPARQL; class Client
290
287
  #
291
288
  # @param [Array<Symbol, String>] variables
292
289
  # @return [Query]
293
- # @see http://www.w3.org/TR/sparql11-query/#groupby
290
+ # @see https://www.w3.org/TR/sparql11-query/#groupby
294
291
  def group(*variables)
295
292
  options[:group_by] = variables
296
293
  self
@@ -303,7 +300,7 @@ module SPARQL; class Client
303
300
  # query.select(:s).distinct.where([:s, :p, :o])
304
301
  #
305
302
  # @return [Query]
306
- # @see http://www.w3.org/TR/sparql11-query/#modDuplicates
303
+ # @see https://www.w3.org/TR/sparql11-query/#modDuplicates
307
304
  def distinct(state = true)
308
305
  options[:distinct] = state
309
306
  self
@@ -314,7 +311,7 @@ module SPARQL; class Client
314
311
  # query.select(:s).reduced.where([:s, :p, :o])
315
312
  #
316
313
  # @return [Query]
317
- # @see http://www.w3.org/TR/sparql11-query/#modDuplicates
314
+ # @see https://www.w3.org/TR/sparql11-query/#modDuplicates
318
315
  def reduced(state = true)
319
316
  options[:reduced] = state
320
317
  self
@@ -325,7 +322,7 @@ module SPARQL; class Client
325
322
  # query.select.graph(:g).where([:s, :p, :o])
326
323
  # @param [RDF::Value] graph_uri_or_var
327
324
  # @return [Query]
328
- # @see http://www.w3.org/TR/sparql11-query/#queryDataset
325
+ # @see https://www.w3.org/TR/sparql11-query/#queryDataset
329
326
  def graph(graph_uri_or_var)
330
327
  options[:graph] = case graph_uri_or_var
331
328
  when Symbol then RDF::Query::Variable.new(graph_uri_or_var)
@@ -342,7 +339,7 @@ module SPARQL; class Client
342
339
  #
343
340
  # @param [Integer, #to_i] start
344
341
  # @return [Query]
345
- # @see http://www.w3.org/TR/sparql11-query/#modOffset
342
+ # @see https://www.w3.org/TR/sparql11-query/#modOffset
346
343
  def offset(start)
347
344
  slice(start, nil)
348
345
  end
@@ -353,7 +350,7 @@ module SPARQL; class Client
353
350
  #
354
351
  # @param [Integer, #to_i] length
355
352
  # @return [Query]
356
- # @see http://www.w3.org/TR/sparql11-query/#modResultLimit
353
+ # @see https://www.w3.org/TR/sparql11-query/#modResultLimit
357
354
  def limit(length)
358
355
  slice(nil, length)
359
356
  end
@@ -372,16 +369,38 @@ module SPARQL; class Client
372
369
  end
373
370
 
374
371
  ##
375
- # @example PREFIX dc: <http://purl.org/dc/elements/1.1/> PREFIX foaf: <http://xmlns.com/foaf/0.1/> SELECT * WHERE \{ ?s ?p ?o . \}
376
- # query.select.
377
- # prefix(dc: RDF::URI("http://purl.org/dc/elements/1.1/")).
378
- # prefix(foaf: RDF::URI("http://xmlns.com/foaf/0.1/")).
379
- # where([:s, :p, :o])
372
+ # @overload prefix(prefix: uri)
373
+ # @example PREFIX dc: <http://purl.org/dc/elements/1.1/> PREFIX foaf: <http://xmlns.com/foaf/0.1/> SELECT * WHERE \{ ?s ?p ?o . \}
374
+ # query.select.
375
+ # prefix(dc: RDF::URI("http://purl.org/dc/elements/1.1/")).
376
+ # prefix(foaf: RDF::URI("http://xmlns.com/foaf/0.1/")).
377
+ # where([:s, :p, :o])
380
378
  #
381
- # @return [Query]
382
- # @see http://www.w3.org/TR/sparql11-query/#prefNames
383
- def prefix(string)
384
- (options[:prefixes] ||= []) << string
379
+ # @param [RDF::URI] uri
380
+ # @param [Symbol, String] prefix
381
+ # @return [Query]
382
+ #
383
+ # @overload prefix(string)
384
+ # @example PREFIX dc: <http://purl.org/dc/elements/1.1/> PREFIX foaf: <http://xmlns.com/foaf/0.1/> SELECT * WHERE \{ ?s ?p ?o . \}
385
+ # query.select.
386
+ # prefix("dc: <http://purl.org/dc/elements/1.1/>").
387
+ # prefix("foaf: <http://xmlns.com/foaf/0.1/>").
388
+ # where([:s, :p, :o])
389
+ #
390
+ # @param [string] string
391
+ # @return [Query]
392
+ # @see https://www.w3.org/TR/sparql11-query/#prefNames
393
+ def prefix(val)
394
+ options[:prefixes] ||= []
395
+ if val.kind_of? String
396
+ options[:prefixes] << val
397
+ elsif val.kind_of? Hash
398
+ val.each do |k, v|
399
+ options[:prefixes] << "#{k}: <#{v}>"
400
+ end
401
+ else
402
+ raise ArgumentError, "prefix must be a kind of String or a Hash"
403
+ end
385
404
  self
386
405
  end
387
406
 
@@ -403,7 +422,7 @@ module SPARQL; class Client
403
422
  # Yield form with or without argument; without an argument, evaluates within the query.
404
423
  # @yieldparam [SPARQL::Client::Query] query used for creating filters on the optional patterns.
405
424
  # @return [Query]
406
- # @see http://www.w3.org/TR/sparql11-query/#optionals
425
+ # @see https://www.w3.org/TR/sparql11-query/#optionals
407
426
  def optional(*patterns, &block)
408
427
  (options[:optionals] ||= []) << build_patterns(patterns)
409
428
 
@@ -449,7 +468,7 @@ module SPARQL; class Client
449
468
  # Yield form with or without argument; without an argument, evaluates within the query.
450
469
  # @yieldparam [SPARQL::Client::Query] query used for adding select clauses.
451
470
  # @return [Query]
452
- # @see http://www.w3.org/TR/sparql11-query/#optionals
471
+ # @see https://www.w3.org/TR/sparql11-query/#optionals
453
472
  def union(*patterns, &block)
454
473
  options[:unions] ||= []
455
474
 
@@ -502,7 +521,7 @@ module SPARQL; class Client
502
521
  # Yield form with or without argument; without an argument, evaluates within the query.
503
522
  # @yieldparam [SPARQL::Client::Query] query used for adding select clauses.
504
523
  # @return [Query]
505
- # @see http://www.w3.org/TR/sparql11-query/#optionals
524
+ # @see https://www.w3.org/TR/sparql11-query/#optionals
506
525
  def minus(*patterns, &block)
507
526
  options[:minuses] ||= []
508
527
 
@@ -528,6 +547,71 @@ module SPARQL; class Client
528
547
  self
529
548
  end
530
549
 
550
+ ##
551
+ # Specify inline data for a query
552
+ #
553
+ # @overload values
554
+ # Values returned from previous query.
555
+ #
556
+ # @return [Array<Array(key, RDF::Value)>]
557
+ #
558
+ # @overload values(vars, *data)
559
+ # @example single variable with multiple values
560
+ # query.select
561
+ # .where([:s, RDF::URI('http://purl.org/dc/terms/title'), :title])
562
+ # .values(:title, "This title", "Another title")
563
+ #
564
+ # @example multiple variables with multiple values
565
+ # query.select
566
+ # .where([:s, RDF::URI('http://purl.org/dc/terms/title'), :title],
567
+ # [:s, RDF.type, :type])
568
+ # .values([:type, :title],
569
+ # [RDF::URI('http://pcdm.org/models#Object'), "This title"],
570
+ # [RDF::URI('http://pcdm.org/models#Collection', 'Another title'])
571
+ #
572
+ # @example multiple variables with UNDEF
573
+ # query.select
574
+ # .where([:s, RDF::URI('http://purl.org/dc/terms/title'), :title],
575
+ # [:s, RDF.type, :type])
576
+ # .values([:type, :title],
577
+ # [nil "This title"],
578
+ # [RDF::URI('http://pcdm.org/models#Collection', nil])
579
+ #
580
+ # @param [Symbol, Array<Symbol>] vars
581
+ # @param [Array<RDF::Term, String, nil>] *data
582
+ # @return [Query]
583
+ def values(*args)
584
+ return @values if args.empty?
585
+ vars, *data = *args
586
+ vars = Array(vars).map {|var| RDF::Query::Variable.new(var)}
587
+ if vars.length == 1
588
+ # data may be a in array form or simple form
589
+ if data.any? {|d| d.is_a?(Array)} && !data.all? {|d| d.is_a?(Array)}
590
+ raise ArgumentError, "values data must all be in array form or all simple"
591
+ end
592
+ data = data.map {|d| Array(d)}
593
+ end
594
+
595
+ # Each data value must be an array with the same number of entries as vars
596
+ unless data.all? {|d| d.is_a?(Array) && d.all? {|dd| dd.is_a?(RDF::Value) || dd.is_a?(String) || dd.nil?}}
597
+ raise ArgumentError, "values data must each be an array of terms, strings, or nil"
598
+ end
599
+
600
+ # Turn strings into Literals
601
+ data = data.map do |d|
602
+ d.map do |nil_literal_or_term|
603
+ case nil_literal_or_term
604
+ when nil then nil
605
+ when String then RDF::Literal(nil_literal_or_term)
606
+ when RDF::Value then nil_literal_or_term
607
+ else raise ArgumentError
608
+ end
609
+ end
610
+ end
611
+ options[:values] = [vars, *data]
612
+ self
613
+ end
614
+
531
615
  ##
532
616
  # @return expects_statements?
533
617
  def expects_statements?
@@ -646,7 +730,7 @@ module SPARQL; class Client
646
730
  buffer << 'ORDER BY'
647
731
  options[:order_by].map { |elem|
648
732
  case elem
649
- # .order_by({ :var1 => :asc, :var2 => :desc})
733
+ # .order_by({ var1: :asc, var2: :desc})
650
734
  when Hash
651
735
  elem.each { |key, val|
652
736
  # check provided values
@@ -712,6 +796,18 @@ module SPARQL; class Client
712
796
  if options[:filters]
713
797
  buffer += options[:filters].map(&:to_s)
714
798
  end
799
+ if options[:values]
800
+ vars = options[:values].first.map {|var| SPARQL::Client.serialize_value(var)}
801
+ buffer << "VALUES (#{vars.join(' ')}) {"
802
+ options[:values][1..-1].each do |data_block_value|
803
+ buffer << '('
804
+ buffer << data_block_value.map do |value|
805
+ value.nil? ? 'UNDEF' : SPARQL::Client.serialize_value(value)
806
+ end.join(' ')
807
+ buffer << ')'
808
+ end
809
+ buffer << '}'
810
+ end
715
811
  if options[:graph]
716
812
  buffer << '}' # GRAPH
717
813
  end
@@ -752,4 +848,4 @@ module SPARQL; class Client
752
848
  end
753
849
  end
754
850
  end
755
- end; end
851
+ end