sparql-client 2.2.1 → 3.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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