rdf-virtuoso 0.0.11
Sign up to get free protection for your applications and to get access to all the features.
- 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,104 @@
|
|
1
|
+
require 'api_smith'
|
2
|
+
require 'rdf'
|
3
|
+
|
4
|
+
module RDF
|
5
|
+
module Virtuoso
|
6
|
+
class Repository
|
7
|
+
include APISmith::Client
|
8
|
+
|
9
|
+
RESULT_JSON = 'application/sparql-results+json'.freeze
|
10
|
+
RESULT_XML = 'application/sparql-results+xml'.freeze
|
11
|
+
|
12
|
+
class Parser::SparqlJson < HTTParty::Parser
|
13
|
+
SupportedFormats.merge!({ RESULT_JSON => :json })
|
14
|
+
end
|
15
|
+
|
16
|
+
class ClientError < StandardError; end
|
17
|
+
class MalformedQuery < ClientError; end
|
18
|
+
class NotAuthorized < ClientError; end
|
19
|
+
class ServerError < StandardError; end
|
20
|
+
|
21
|
+
# TODO: Look at issues with HTTParty Connection reset
|
22
|
+
#persistent
|
23
|
+
maintain_method_across_redirects true
|
24
|
+
|
25
|
+
attr_reader :username, :password, :uri, :auth_method
|
26
|
+
|
27
|
+
def initialize(uri, opts={})
|
28
|
+
self.class.base_uri uri
|
29
|
+
@uri = uri
|
30
|
+
@username = opts[:username] ||= nil
|
31
|
+
@password = opts[:password] ||= nil
|
32
|
+
@auth_method = opts[:auth_method] ||= 'digest'
|
33
|
+
end
|
34
|
+
|
35
|
+
READ_METHODS = %w(select ask construct describe)
|
36
|
+
WRITE_METHODS = %w(query insert insert_data update delete delete_data create drop clear)
|
37
|
+
|
38
|
+
READ_METHODS.each do |m|
|
39
|
+
define_method m do |*args|
|
40
|
+
response = api_get *args
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
WRITE_METHODS.each do |m|
|
45
|
+
define_method m do |*args|
|
46
|
+
response = api_post *args
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
private
|
51
|
+
|
52
|
+
def check_response_errors(response)
|
53
|
+
case response.code
|
54
|
+
when 401
|
55
|
+
raise NotAuthorized.new
|
56
|
+
when 400
|
57
|
+
raise MalformedQuery.new(response.parsed_response)
|
58
|
+
when 500..599
|
59
|
+
raise ServerError.new(response.body)
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
def headers
|
64
|
+
{ 'Accept' => [RESULT_JSON, RESULT_XML].join(', ') }
|
65
|
+
end
|
66
|
+
|
67
|
+
def base_query_options
|
68
|
+
{ :format => 'json' }
|
69
|
+
end
|
70
|
+
|
71
|
+
def base_request_options
|
72
|
+
{ :headers => headers }
|
73
|
+
end
|
74
|
+
|
75
|
+
def extra_request_options
|
76
|
+
case @auth_method
|
77
|
+
when 'basic'
|
78
|
+
{ :basic_auth => auth }
|
79
|
+
when 'digest'
|
80
|
+
{ :digest_auth => auth }
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
def auth
|
85
|
+
{ :username => @username, :password => @password }
|
86
|
+
end
|
87
|
+
|
88
|
+
def api_get(query, options = {})
|
89
|
+
self.class.endpoint 'sparql'
|
90
|
+
get '/', :extra_query => { :query => query }.merge(options),
|
91
|
+
:transform => RDF::Virtuoso::Parser::JSON
|
92
|
+
end
|
93
|
+
|
94
|
+
def api_post(query, options = {})
|
95
|
+
self.class.endpoint 'sparql-auth'
|
96
|
+
post '/', :extra_body => { :query => query }.merge(options),
|
97
|
+
:extra_request => extra_request_options,
|
98
|
+
:response_container => [
|
99
|
+
"results", "bindings", 0, "callret-0", "value"]
|
100
|
+
end
|
101
|
+
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
class Resource < ActiveRDF::Model
|
4
|
+
end
|
5
|
+
|
6
|
+
describe ActiveRDF::Persistence do
|
7
|
+
|
8
|
+
let(:resource) { Resource.new }
|
9
|
+
|
10
|
+
before do
|
11
|
+
resource.stub(:id).and_return("some_unique_id")
|
12
|
+
client = double("client")
|
13
|
+
resource.stub(:connection).and_return client
|
14
|
+
end
|
15
|
+
|
16
|
+
describe :destroy do
|
17
|
+
|
18
|
+
it "formats the destroy query correctly" do
|
19
|
+
subject = resource.subject_for(resource.id)
|
20
|
+
query =
|
21
|
+
<<-q
|
22
|
+
DELETE FROM <#{resource.graph}> { <#{subject}> ?p ?o }
|
23
|
+
WHERE { <#{subject}> ?p ?o }
|
24
|
+
q
|
25
|
+
|
26
|
+
resource.connection.should_receive(:delete).with(query)
|
27
|
+
resource.destroy
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
require_relative '../lib/rdf/virtuoso/prefixes'
|
2
|
+
require 'rdf'
|
3
|
+
|
4
|
+
describe RDF::Virtuoso::Prefixes do
|
5
|
+
subject { RDF::Virtuoso::Prefixes.new(foo: 'bar', baz: 'quux') }
|
6
|
+
|
7
|
+
it "takes a hash when initialized" do
|
8
|
+
subject.should be_a RDF::Virtuoso::Prefixes
|
9
|
+
end
|
10
|
+
|
11
|
+
it "responds to to_a" do
|
12
|
+
subject.should respond_to :to_a
|
13
|
+
end
|
14
|
+
|
15
|
+
it "returns a nice array" do
|
16
|
+
subject.to_a.should == ["foo: <bar>", "baz: <quux>"]
|
17
|
+
end
|
18
|
+
|
19
|
+
it "presents itself nicely" do
|
20
|
+
subject.to_s.should == "{:foo=>\"bar\", :baz=>\"quux\"}"
|
21
|
+
end
|
22
|
+
|
23
|
+
context "when creating prefixes" do
|
24
|
+
let(:uris) { [RDF::DC.title.to_s, "http://example.org/foo/bar", "http://hash.org/foo#bar"] }
|
25
|
+
|
26
|
+
it "creates prefixes from uris" do
|
27
|
+
RDF::Virtuoso::Prefixes.parse(uris).should == [
|
28
|
+
"purl: <http://purl.org/dc/terms/>",
|
29
|
+
"example: <http://example.org/foo/>",
|
30
|
+
"hash: <http://hash.org/foo#>"
|
31
|
+
]
|
32
|
+
end
|
33
|
+
|
34
|
+
it "only creates unique prefixes from uris" do
|
35
|
+
uris << 'http://example.org/foo/baz'
|
36
|
+
RDF::Virtuoso::Prefixes.parse(uris).should == [
|
37
|
+
"purl: <http://purl.org/dc/terms/>",
|
38
|
+
"example: <http://example.org/foo/>",
|
39
|
+
"hash: <http://hash.org/foo#>"
|
40
|
+
]
|
41
|
+
end
|
42
|
+
|
43
|
+
it "returns an error object if a disallowed param is sent" do
|
44
|
+
RDF::Virtuoso::Prefixes.parse({}).should be_a RDF::Virtuoso::UnProcessable
|
45
|
+
end
|
46
|
+
|
47
|
+
end
|
48
|
+
end
|
data/spec/query_spec.rb
ADDED
@@ -0,0 +1,278 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), 'spec_helper')
|
2
|
+
|
3
|
+
describe RDF::Virtuoso::Query do
|
4
|
+
before :each do
|
5
|
+
@query = RDF::Virtuoso::Query
|
6
|
+
end
|
7
|
+
|
8
|
+
context "when building queries" do
|
9
|
+
it "should support ASK queries" do
|
10
|
+
@query.should respond_to(:ask)
|
11
|
+
end
|
12
|
+
|
13
|
+
it "should support SELECT queries" do
|
14
|
+
@query.should respond_to(:select)
|
15
|
+
end
|
16
|
+
|
17
|
+
it "should support DESCRIBE queries" do
|
18
|
+
@query.should respond_to(:describe)
|
19
|
+
end
|
20
|
+
|
21
|
+
it "should support CONSTRUCT queries" do
|
22
|
+
@query.should respond_to(:construct)
|
23
|
+
end
|
24
|
+
|
25
|
+
it "should support INSERT DATA queries" do
|
26
|
+
@query.should respond_to(:insert_data)
|
27
|
+
end
|
28
|
+
|
29
|
+
it "should support INSERT WHERE queries" do
|
30
|
+
@query.should respond_to(:insert)
|
31
|
+
end
|
32
|
+
|
33
|
+
it "should support DELETE DATA queries" do
|
34
|
+
@query.should respond_to(:delete_data)
|
35
|
+
end
|
36
|
+
|
37
|
+
it "should support DELETE WHERE queries" do
|
38
|
+
@query.should respond_to(:delete)
|
39
|
+
end
|
40
|
+
|
41
|
+
it "should support CREATE GRAPH queries" do
|
42
|
+
@query.should respond_to(:create)
|
43
|
+
end
|
44
|
+
|
45
|
+
end
|
46
|
+
|
47
|
+
|
48
|
+
context "when building update queries" do
|
49
|
+
before :each do
|
50
|
+
@graph = "http://example.org/"
|
51
|
+
@uri = RDF::Vocabulary.new "http://example.org/"
|
52
|
+
end
|
53
|
+
# TODO add support for advanced inserts (moving copying between different graphs)
|
54
|
+
it "should support INSERT DATA queries" do
|
55
|
+
@query.insert_data([@uri.ola, @uri.type, @uri.something]).graph(RDF::URI.new(@graph)).to_s.should == "INSERT DATA INTO GRAPH <#{@graph}> { <#{@graph}ola> <#{@graph}type> <#{@graph}something> . }"
|
56
|
+
@query.insert_data([@uri.ola, @uri.name, "two words"]).graph(RDF::URI.new(@graph)).to_s.should == "INSERT DATA INTO GRAPH <#{@graph}> { <#{@graph}ola> <#{@graph}name> \"two words\" . }"
|
57
|
+
end
|
58
|
+
|
59
|
+
it "should support INSERT DATA queries with arrays" do
|
60
|
+
@query.insert_data([@uri.ola, @uri.type, @uri.something],[@uri.ola, @uri.type, @uri.something_else]).graph(RDF::URI.new(@graph)).to_s.should == "INSERT DATA INTO GRAPH <#{@graph}> { <#{@graph}ola> <#{@graph}type> <#{@graph}something> . <#{@graph}ola> <#{@graph}type> <#{@graph}something_else> . }"
|
61
|
+
end
|
62
|
+
|
63
|
+
it "should support INSERT DATA queries with RDF::Statements" do
|
64
|
+
statements = [RDF::Statement.new(RDF::URI('http://test'), RDF.type, RDF::URI('http://type')), RDF::Statement.new(RDF::URI('http://test'), RDF.type, RDF::URI('http://type2'))]
|
65
|
+
@query.insert_data(statements).graph(RDF::URI.new(@graph)).to_s.should == "INSERT DATA INTO GRAPH <#{@graph}> { <http://test> <#{RDF.type}> <http://type> .\n <http://test> <#{RDF.type}> <http://type2> .\n }"
|
66
|
+
end
|
67
|
+
|
68
|
+
it "should support INSERT WHERE queries with symbols and patterns" do
|
69
|
+
@query.insert([:s, :p, :o]).graph(RDF::URI.new(@graph)).where([:s, :p, :o]).to_s.should == "INSERT INTO GRAPH <#{@graph}> { ?s ?p ?o . } WHERE { ?s ?p ?o . }"
|
70
|
+
@query.insert([:s, @uri.newtype, :o]).graph(RDF::URI.new(@graph)).where([:s, @uri.type, :o]).to_s.should == "INSERT INTO GRAPH <#{@graph}> { ?s <#{@graph}newtype> ?o . } WHERE { ?s <#{@graph}type> ?o . }"
|
71
|
+
end
|
72
|
+
|
73
|
+
it "should support DELETE DATA queries" do
|
74
|
+
@query.delete_data([@uri.ola, @uri.type, @uri.something]).graph(RDF::URI.new(@graph)).to_s.should == "DELETE DATA FROM <#{@graph}> { <#{@graph}ola> <#{@graph}type> <#{@graph}something> . }"
|
75
|
+
@query.delete_data([@uri.ola, @uri.name, RDF::Literal.new("myname")]).graph(RDF::URI.new(@graph)).to_s.should == "DELETE DATA FROM <#{@graph}> { <#{@graph}ola> <#{@graph}name> \"myname\" . }"
|
76
|
+
end
|
77
|
+
|
78
|
+
it "should support DELETE DATA queries with arrays" do
|
79
|
+
@query.delete_data([@uri.ola, @uri.type, @uri.something],[@uri.ola, @uri.type, @uri.something_else]).graph(RDF::URI.new(@graph)).to_s.should == "DELETE DATA FROM <#{@graph}> { <#{@graph}ola> <#{@graph}type> <#{@graph}something> . <#{@graph}ola> <#{@graph}type> <#{@graph}something_else> . }"
|
80
|
+
end
|
81
|
+
|
82
|
+
it "should support DELETE DATA queries with RDF::Statements" do
|
83
|
+
statements = [RDF::Statement.new(RDF::URI('http://test'), RDF.type, RDF::URI('http://type')), RDF::Statement.new(RDF::URI('http://test'), RDF.type, RDF::URI('http://type2'))]
|
84
|
+
@query.delete_data(statements).graph(RDF::URI.new(@graph)).to_s.should == "DELETE DATA FROM <#{@graph}> { <http://test> <#{RDF.type}> <http://type> .\n <http://test> <#{RDF.type}> <http://type2> .\n }"
|
85
|
+
end
|
86
|
+
|
87
|
+
it "should support DELETE WHERE queries with symbols and patterns" do
|
88
|
+
@query.delete([:s, :p, :o]).graph(RDF::URI.new(@graph)).where([:s, :p, :o]).to_s.should == "DELETE FROM <#{@graph}> { ?s ?p ?o . } WHERE { ?s ?p ?o . }"
|
89
|
+
@query.delete([:s, @uri.newtype, :o]).graph(RDF::URI.new(@graph)).where([:s, @uri.newtype, :o]).to_s.should == "DELETE FROM <#{@graph}> { ?s <#{@graph}newtype> ?o . } WHERE { ?s <#{@graph}newtype> ?o . }"
|
90
|
+
end
|
91
|
+
|
92
|
+
it "should support CREATE GRAPH queries" do
|
93
|
+
@query.create(RDF::URI.new(@graph)).to_s.should == "CREATE GRAPH <#{@graph}>"
|
94
|
+
@query.create(RDF::URI.new(@graph), :silent => true).to_s.should == "CREATE SILENT GRAPH <#{@graph}>"
|
95
|
+
end
|
96
|
+
|
97
|
+
it "should support DROP GRAPH queries" do
|
98
|
+
@query.drop(RDF::URI.new(@graph)).to_s.should == "DROP GRAPH <#{@graph}>"
|
99
|
+
@query.drop(RDF::URI.new(@graph), :silent => true).to_s.should == "DROP SILENT GRAPH <#{@graph}>"
|
100
|
+
|
101
|
+
end
|
102
|
+
|
103
|
+
end
|
104
|
+
|
105
|
+
context "when building ASK queries" do
|
106
|
+
it "should support basic graph patterns" do
|
107
|
+
@query.ask.where([:s, :p, :o]).to_s.should == "ASK WHERE { ?s ?p ?o . }"
|
108
|
+
@query.ask.whether([:s, :p, :o]).to_s.should == "ASK WHERE { ?s ?p ?o . }"
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
context "when building SELECT queries" do
|
113
|
+
it "should support basic graph patterns" do
|
114
|
+
@query.select.where([:s, :p, :o]).to_s.should == "SELECT * WHERE { ?s ?p ?o . }"
|
115
|
+
end
|
116
|
+
|
117
|
+
it "should support projection" do
|
118
|
+
@query.select(:s).where([:s, :p, :o]).to_s.should == "SELECT ?s WHERE { ?s ?p ?o . }"
|
119
|
+
@query.select(:s, :p).where([:s, :p, :o]).to_s.should == "SELECT ?s ?p WHERE { ?s ?p ?o . }"
|
120
|
+
@query.select(:s, :p, :o).where([:s, :p, :o]).to_s.should == "SELECT ?s ?p ?o WHERE { ?s ?p ?o . }"
|
121
|
+
end
|
122
|
+
|
123
|
+
it "should support SELECT with complex WHERE patterns" do
|
124
|
+
@query.select.where(
|
125
|
+
[:s, :p, :o],
|
126
|
+
[:s, RDF.type, RDF::DC.Document]
|
127
|
+
).to_s.should ==
|
128
|
+
"SELECT * WHERE { ?s ?p ?o . ?s <#{RDF.type}> <#{RDF::DC.Document}> . }"
|
129
|
+
end
|
130
|
+
|
131
|
+
it "should support string objects in SPARQL queries" do
|
132
|
+
@query.select.where([:s, :p, "dummyobject"]).to_s.should == "SELECT * WHERE { ?s ?p \"dummyobject\" . }"
|
133
|
+
end
|
134
|
+
|
135
|
+
#it "should support raw string SPARQL queries" do
|
136
|
+
# q = "SELECT * WHERE { ?s <#{RDF.type}> ?o . }"
|
137
|
+
# @query.query(q).should == "SELECT * WHERE { ?s <#{RDF.type}> ?o . }"
|
138
|
+
#end
|
139
|
+
|
140
|
+
it "should support FROM" do
|
141
|
+
uri = "http://example.org/dft.ttl"
|
142
|
+
@query.select.from(RDF::URI.new(uri)).where([:s, :p, :o]).to_s.should ==
|
143
|
+
"SELECT * FROM <#{uri}> WHERE { ?s ?p ?o . }"
|
144
|
+
end
|
145
|
+
|
146
|
+
it "should support DISTINCT" do
|
147
|
+
@query.select(:s, :distinct => true).where([:s, :p, :o]).to_s.should == "SELECT DISTINCT ?s WHERE { ?s ?p ?o . }"
|
148
|
+
@query.select(:s).distinct.where([:s, :p, :o]).to_s.should == "SELECT DISTINCT ?s WHERE { ?s ?p ?o . }"
|
149
|
+
end
|
150
|
+
|
151
|
+
it "should support REDUCED" do
|
152
|
+
@query.select(:s, :reduced => true).where([:s, :p, :o]).to_s.should == "SELECT REDUCED ?s WHERE { ?s ?p ?o . }"
|
153
|
+
@query.select(:s).reduced.where([:s, :p, :o]).to_s.should == "SELECT REDUCED ?s WHERE { ?s ?p ?o . }"
|
154
|
+
end
|
155
|
+
|
156
|
+
it "should support aggregate COUNT" do
|
157
|
+
@query.select.where([:s, :p, :o]).count(:s).to_s.should == "SELECT (COUNT (?s) AS ?count) WHERE { ?s ?p ?o . }"
|
158
|
+
@query.select.count(:s).where([:s, :p, :o]).to_s.should == "SELECT (COUNT (?s) AS ?count) WHERE { ?s ?p ?o . }"
|
159
|
+
end
|
160
|
+
|
161
|
+
it "should support aggregates SUM, MIN, MAX, AVG, SAMPLE" do
|
162
|
+
@query.select.where([:s, :p, :o]).sum(:s).to_s.should == "SELECT (SUM (?s) AS ?sum) WHERE { ?s ?p ?o . }"
|
163
|
+
@query.select.where([:s, :p, :o]).min(:s).to_s.should == "SELECT (MIN (?s) AS ?min) WHERE { ?s ?p ?o . }"
|
164
|
+
@query.select.where([:s, :p, :o]).max(:s).to_s.should == "SELECT (MAX (?s) AS ?max) WHERE { ?s ?p ?o . }"
|
165
|
+
@query.select.where([:s, :p, :o]).avg(:s).to_s.should == "SELECT (AVG (?s) AS ?avg) WHERE { ?s ?p ?o . }"
|
166
|
+
@query.select.where([:s, :p, :o]).sample(:s).to_s.should == "SELECT (sql:SAMPLE (?s) AS ?sample) WHERE { ?s ?p ?o . }"
|
167
|
+
@query.select.where([:s, :p, :o]).group_concat(:s, '_').to_s.should == "SELECT (sql:GROUP_CONCAT (?s, '_' ) AS ?group_concat) WHERE { ?s ?p ?o . }"
|
168
|
+
@query.select.where([:s, :p, :o]).group_digest(:s, '_', 1000, 1).to_s.should == "SELECT (sql:GROUP_DIGEST (?s, '_', '1000', '1' ) AS ?group_digest) WHERE { ?s ?p ?o . }"
|
169
|
+
end
|
170
|
+
|
171
|
+
it "should support ORDER BY" do
|
172
|
+
@query.select.where([:s, :p, :o]).order_by(:o).to_s.should == "SELECT * WHERE { ?s ?p ?o . } ORDER BY ?o"
|
173
|
+
@query.select.where([:s, :p, :o]).order_by('?o').to_s.should == "SELECT * WHERE { ?s ?p ?o . } ORDER BY ?o"
|
174
|
+
# @query.select.where([:s, :p, :o]).order_by(:o => :asc).to_s.should == "SELECT * WHERE { ?s ?p ?o . } ORDER BY ?o ASC"
|
175
|
+
@query.select.where([:s, :p, :o]).order_by('?o ASC').to_s.should == "SELECT * WHERE { ?s ?p ?o . } ORDER BY ?o ASC"
|
176
|
+
# @query.select.where([:s, :p, :o]).order_by(:o => :desc).to_s.should == "SELECT * WHERE { ?s ?p ?o . } ORDER BY ?o DESC"
|
177
|
+
@query.select.where([:s, :p, :o]).order_by('?o DESC').to_s.should == "SELECT * WHERE { ?s ?p ?o . } ORDER BY ?o DESC"
|
178
|
+
end
|
179
|
+
|
180
|
+
it "should support OFFSET" do
|
181
|
+
@query.select.where([:s, :p, :o]).offset(100).to_s.should == "SELECT * WHERE { ?s ?p ?o . } OFFSET 100"
|
182
|
+
end
|
183
|
+
|
184
|
+
it "should support LIMIT" do
|
185
|
+
@query.select.where([:s, :p, :o]).limit(10).to_s.should == "SELECT * WHERE { ?s ?p ?o . } LIMIT 10"
|
186
|
+
end
|
187
|
+
|
188
|
+
it "should support OFFSET with LIMIT" do
|
189
|
+
@query.select.where([:s, :p, :o]).offset(100).limit(10).to_s.should == "SELECT * WHERE { ?s ?p ?o . } OFFSET 100 LIMIT 10"
|
190
|
+
@query.select.where([:s, :p, :o]).slice(100, 10).to_s.should == "SELECT * WHERE { ?s ?p ?o . } OFFSET 100 LIMIT 10"
|
191
|
+
end
|
192
|
+
|
193
|
+
it "should support PREFIX" do
|
194
|
+
prefixes = ["dc: <http://purl.org/dc/elements/1.1/>", "foaf: <http://xmlns.com/foaf/0.1/>"]
|
195
|
+
@query.select.prefix(prefixes[0]).prefix(prefixes[1]).where([:s, :p, :o]).to_s.should ==
|
196
|
+
"PREFIX #{prefixes[0]} PREFIX #{prefixes[1]} SELECT * WHERE { ?s ?p ?o . }"
|
197
|
+
end
|
198
|
+
|
199
|
+
it "constructs PREFIXes" do
|
200
|
+
prefixes = RDF::Virtuoso::Prefixes.new dc: RDF::DC, foaf: RDF::FOAF
|
201
|
+
@query.select.prefixes(prefixes).where([:s, :p, :o]).to_s.should ==
|
202
|
+
"PREFIX dc: <#{RDF::DC}> PREFIX foaf: <#{RDF::FOAF}> SELECT * WHERE { ?s ?p ?o . }"
|
203
|
+
end
|
204
|
+
|
205
|
+
it "should support custom PREFIXes in hash array" do
|
206
|
+
prefixes = RDF::Virtuoso::Prefixes.new foo: "http://foo.com/", bar: "http://bar.net"
|
207
|
+
@query.select.prefixes(prefixes).where([:s, :p, :o]).to_s.should ==
|
208
|
+
"PREFIX foo: <http://foo.com/> PREFIX bar: <http://bar.net> SELECT * WHERE { ?s ?p ?o . }"
|
209
|
+
end
|
210
|
+
|
211
|
+
it "should support OPTIONAL" do
|
212
|
+
@query.select.where([:s, :p, :o]).optional([:s, RDF.type, :o], [:s, RDF::DC.abstract, :o]).to_s.should ==
|
213
|
+
"SELECT * WHERE { ?s ?p ?o . OPTIONAL { ?s <#{RDF.type}> ?o . ?s <#{RDF::DC.abstract}> ?o . } }"
|
214
|
+
end
|
215
|
+
|
216
|
+
it "should support multiple OPTIONALs" do
|
217
|
+
@query.select.where([:s, :p, :o]).optional([:s, RDF.type, :o]).optional([:s, RDF::DC.abstract, :o]).to_s.should ==
|
218
|
+
"SELECT * WHERE { ?s ?p ?o . OPTIONAL { ?s <#{RDF.type}> ?o . } OPTIONAL { ?s <#{RDF::DC.abstract}> ?o . } }"
|
219
|
+
end
|
220
|
+
|
221
|
+
it "should support MINUS, also with an array pattern" do
|
222
|
+
@query.select.where([:s, :p, :o]).minus([:s, RDF.type, :o], [:s, RDF::DC.abstract, :o]).to_s.should ==
|
223
|
+
"SELECT * WHERE { ?s ?p ?o . MINUS { ?s <#{RDF.type}> ?o . ?s <#{RDF::DC.abstract}> ?o . } }"
|
224
|
+
end
|
225
|
+
|
226
|
+
it "should support multiple MINUSes" do
|
227
|
+
@query.select.where([:s, :p, :o]).minus([:s, RDF.type, :o]).minus([:s, RDF::DC.abstract, :o]).to_s.should ==
|
228
|
+
"SELECT * WHERE { ?s ?p ?o . MINUS { ?s <#{RDF.type}> ?o . } MINUS { ?s <#{RDF::DC.abstract}> ?o . } }"
|
229
|
+
end
|
230
|
+
|
231
|
+
it "should support UNION" do
|
232
|
+
@query.select.where([:s, RDF::DC.abstract, :o]).union([:s, RDF.type, :o]).to_s.should ==
|
233
|
+
"SELECT * WHERE { { ?s <#{RDF::DC.abstract}> ?o . } UNION { ?s <#{RDF.type}> ?o . } }"
|
234
|
+
end
|
235
|
+
|
236
|
+
it "should support FILTER" do
|
237
|
+
@query.select.where([:s, RDF::DC.abstract, :o]).filter('lang(?text) != "nb"').to_s.should ==
|
238
|
+
"SELECT * WHERE { ?s <#{RDF::DC.abstract}> ?o . FILTER(lang(?text) != \"nb\") }"
|
239
|
+
end
|
240
|
+
|
241
|
+
it "should support multiple FILTERs" do
|
242
|
+
filters = ['lang(?text) != "nb"', 'regex(?uri, "^https")']
|
243
|
+
@query.select.where([:s, RDF::DC.abstract, :o]).filters(filters).to_s.should ==
|
244
|
+
"SELECT * WHERE { ?s <#{RDF::DC.abstract}> ?o . FILTER(lang(?text) != \"nb\") FILTER(regex(?uri, \"^https\")) }"
|
245
|
+
end
|
246
|
+
|
247
|
+
end
|
248
|
+
|
249
|
+
context "when building DESCRIBE queries" do
|
250
|
+
it "should support basic graph patterns" do
|
251
|
+
@query.describe.where([:s, :p, :o]).to_s.should == "DESCRIBE * WHERE { ?s ?p ?o . }"
|
252
|
+
end
|
253
|
+
|
254
|
+
it "should support projection" do
|
255
|
+
@query.describe(:s).where([:s, :p, :o]).to_s.should == "DESCRIBE ?s WHERE { ?s ?p ?o . }"
|
256
|
+
@query.describe(:s, :p).where([:s, :p, :o]).to_s.should == "DESCRIBE ?s ?p WHERE { ?s ?p ?o . }"
|
257
|
+
@query.describe(:s, :p, :o).where([:s, :p, :o]).to_s.should == "DESCRIBE ?s ?p ?o WHERE { ?s ?p ?o . }"
|
258
|
+
end
|
259
|
+
|
260
|
+
it "should support RDF::URI arguments" do
|
261
|
+
uris = ['http://www.bbc.co.uk/programmes/b007stmh#programme', 'http://www.bbc.co.uk/programmes/b00lg2xb#programme']
|
262
|
+
@query.describe(RDF::URI.new(uris[0]),RDF::URI.new(uris[1])).to_s.should ==
|
263
|
+
"DESCRIBE <#{uris[0]}> <#{uris[1]}>"
|
264
|
+
end
|
265
|
+
end
|
266
|
+
|
267
|
+
context "when building CONSTRUCT queries" do
|
268
|
+
it "should support basic graph patterns" do
|
269
|
+
@query.construct([:s, :p, :o]).where([:s, :p, :o]).to_s.should == "CONSTRUCT { ?s ?p ?o . } WHERE { ?s ?p ?o . }"
|
270
|
+
end
|
271
|
+
|
272
|
+
it "should support complex constructs" do
|
273
|
+
@query.construct([:s, :p, :o], [:s, :q, RDF::Literal.new("new")]).where([:s, :p, :o], [:s, :q, "old"]).to_s.should == "CONSTRUCT { ?s ?p ?o . ?s ?q \"new\" . } WHERE { ?s ?p ?o . ?s ?q \"old\" . }"
|
274
|
+
end
|
275
|
+
|
276
|
+
|
277
|
+
end
|
278
|
+
end
|