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,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
|