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.
@@ -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,5 @@
1
+ module RDF
2
+ module Virtuoso
3
+ VERSION = "0.0.11"
4
+ end
5
+ 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
@@ -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