riakrest 0.1.0 → 0.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.
- data/History.txt +11 -0
- data/README.rdoc +1 -1
- data/Rakefile +8 -4
- data/VERSION +1 -1
- data/examples/auto_update_data.rb +2 -3
- data/examples/auto_update_links.rb +2 -3
- data/examples/basic_client.rb +2 -3
- data/examples/basic_resource.rb +2 -3
- data/examples/example_helper.rb +7 -0
- data/examples/linked_resources.rb +2 -3
- data/lib/riakrest/core/jiak_bucket.rb +2 -2
- data/lib/riakrest/core/jiak_client.rb +108 -45
- data/lib/riakrest/core/jiak_data.rb +10 -11
- data/lib/riakrest/core/jiak_object.rb +2 -1
- data/lib/riakrest/core/jiak_schema.rb +82 -38
- data/lib/riakrest/resource/jiak_resource.rb +84 -73
- data/lib/riakrest.rb +16 -9
- data/spec/core/jiak_bucket_spec.rb +3 -0
- data/spec/core/jiak_client_spec.rb +85 -15
- data/spec/core/jiak_schema_spec.rb +107 -5
- data/spec/resource/jiak_resource_spec.rb +37 -19
- data/spec/spec_helper.rb +3 -0
- metadata +35 -11
- data/examples/bucket_schemas.rb +0 -38
- data/examples/links_only_pov.rb +0 -38
- data/examples/multiple_pov.rb +0 -46
- data/examples/rest_interaction.rb +0 -51
- data/examples/ruby_json_data.rb +0 -19
data/History.txt
CHANGED
@@ -1,3 +1,14 @@
|
|
1
|
+
=== 0.1.2 2009-11-29
|
2
|
+
- Add wide open schemas.
|
3
|
+
- Add wild card schema arrays.
|
4
|
+
|
5
|
+
=== 0.1.1 2009-11-28
|
6
|
+
- Fixed several 1.8.7 issues.
|
7
|
+
- Added helper for examples and put server URI setting in helpers.
|
8
|
+
- Removed POV terminology. Riak doesn't support per-request masks (yet?).
|
9
|
+
- Added some gem dependency declarations.
|
10
|
+
- Minor refactoring.
|
11
|
+
|
1
12
|
=== 0.1.0 2009-11-16
|
2
13
|
- Renamed data/JiakDataHash to core/JiakDataFields and reworked.
|
3
14
|
- Move JiakDataHash functionality into JiakData as default implementation
|
data/README.rdoc
CHANGED
data/Rakefile
CHANGED
@@ -4,25 +4,29 @@ require 'rake'
|
|
4
4
|
begin
|
5
5
|
require 'jeweler'
|
6
6
|
rescue LoadError
|
7
|
-
puts "Jeweler (or a dependency) not available.
|
7
|
+
puts "Jeweler (or a dependency) not available."
|
8
|
+
puts " Install with: sudo gem install jeweler"
|
8
9
|
end
|
9
10
|
|
10
11
|
Jeweler::Tasks.new do |gem|
|
11
12
|
gem.name = "riakrest"
|
12
13
|
gem.summary = %Q{RiakRest provides structured, RESTful interaction with a Riak document store.}
|
13
|
-
gem.description = <<-
|
14
|
+
gem.description = <<-EOS
|
14
15
|
RiakRest provides structured, RESTful interaction with
|
15
16
|
the HTTP/JSON interface of a Riak[http://riak.basho.com] document data
|
16
17
|
store. RiakRest provides two levels of interaction: Core Client and
|
17
18
|
Resource. Core Client works at the Jiak level and exposes Jiak
|
18
19
|
internals. JiakResource is an abstraction built on top of the Core Client
|
19
20
|
that gives a true RESTful feel.
|
20
|
-
|
21
|
+
EOS
|
21
22
|
gem.authors = ["Paul Rogers"]
|
22
|
-
gem.email = "
|
23
|
+
gem.email = "riak@dingosky.com"
|
23
24
|
gem.homepage = "http://github.com/wcpr/riakrest"
|
24
25
|
gem.add_dependency('rest-client', '>= 1.0.0')
|
26
|
+
gem.add_dependency('json', '>= 1.1.9')
|
25
27
|
gem.add_development_dependency "rest-client", ">= 1.0.0"
|
28
|
+
gem.add_development_dependency "json", ">= 1.1.9"
|
29
|
+
gem.add_development_dependency "jeweler", ">= 1.4.0"
|
26
30
|
gem.add_development_dependency "rspec", ">= 1.2.9"
|
27
31
|
end
|
28
32
|
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.1.
|
1
|
+
0.1.2
|
data/examples/basic_client.rb
CHANGED
@@ -1,12 +1,11 @@
|
|
1
|
-
require '
|
2
|
-
include RiakRest
|
1
|
+
require File.dirname(__FILE__) + '/example_helper.rb'
|
3
2
|
|
4
3
|
class PeopleData
|
5
4
|
include JiakData
|
6
5
|
jattr_accessor :name, :age
|
7
6
|
end
|
8
7
|
|
9
|
-
client = JiakClient.new(
|
8
|
+
client = JiakClient.new(SERVER_URI)
|
10
9
|
bucket = JiakBucket.new('people',PeopleData)
|
11
10
|
client.set_schema(bucket)
|
12
11
|
|
data/examples/basic_resource.rb
CHANGED
@@ -102,8 +102,8 @@ module RiakRest
|
|
102
102
|
private :transform_name
|
103
103
|
|
104
104
|
def check_data_class(data_class)
|
105
|
-
unless data_class.include?(JiakData)
|
106
|
-
raise JiakBucketException, "Data class must
|
105
|
+
unless !data_class.nil? && data_class.include?(JiakData)
|
106
|
+
raise JiakBucketException, "Data class must include JiakData."
|
107
107
|
end
|
108
108
|
data_class
|
109
109
|
end
|
@@ -46,15 +46,28 @@ module RiakRest
|
|
46
46
|
|
47
47
|
# :stopdoc:
|
48
48
|
APP_JSON = 'application/json'
|
49
|
+
APP_JSON.freeze
|
50
|
+
|
49
51
|
RETURN_BODY = 'returnbody'
|
52
|
+
RETURN_BODY.freeze
|
50
53
|
READS = 'r'
|
54
|
+
READS.freeze
|
51
55
|
WRITES = 'w'
|
56
|
+
WRITES.freeze
|
52
57
|
DURABLE_WRITES = 'dw'
|
53
|
-
|
58
|
+
DURABLE_WRITES.freeze
|
59
|
+
DELETES = 'rw'
|
60
|
+
DELETES.freeze
|
61
|
+
|
62
|
+
VALID_PARAMS = [:reads,:writes,:durable_writes,:deletes]
|
63
|
+
VALID_PARAMS.freeze
|
64
|
+
VALID_OPTS = Array.new(VALID_PARAMS) << :proxy
|
65
|
+
VALID_OPTS.freeze
|
66
|
+
|
54
67
|
KEYS = 'keys'
|
68
|
+
KEYS.freeze
|
55
69
|
SCHEMA = 'schema'
|
56
|
-
|
57
|
-
VALID_OPTS = VALID_PARAMS << :proxy
|
70
|
+
SCHEMA.freeze
|
58
71
|
# :startdoc:
|
59
72
|
|
60
73
|
# :call-seq:
|
@@ -64,17 +77,22 @@ module RiakRest
|
|
64
77
|
# the specified URI. Go through a proxy if proxy option specified.
|
65
78
|
#
|
66
79
|
# =====Valid options
|
67
|
-
# <code>:reads</code>::
|
68
|
-
# <code>:writes</code>::
|
69
|
-
# <code>:durable_writes</code>::
|
70
|
-
# <code>:
|
80
|
+
# <code>:reads</code>:: Minimum number of responding nodes for successful reads.
|
81
|
+
# <code>:writes</code>:: Minimum number of responding nodes for successful writes. Writes can be buffered on the server nodes for performance.
|
82
|
+
# <code>:durable_writes</code>:: Minimum number of resonding nodes that must perform a durable write to the persistence layer.
|
83
|
+
# <code>:deletes</code>:: Minimum number of responding nodes for successful delete.
|
71
84
|
# <code>:proxy</code>:: Proxy server URI
|
72
85
|
#
|
73
|
-
#
|
74
|
-
# and <code>
|
75
|
-
# parameters
|
76
|
-
#
|
77
|
-
#
|
86
|
+
# The configuration of a Riak cluster includes server setting for the
|
87
|
+
# <code>writes, durable_writes, reads,</code> and <code>deletes</code>
|
88
|
+
# parameters. None of these request parameter are required by RiakRest, and
|
89
|
+
# their use within RiakRest is to override the Riak cluster settings,
|
90
|
+
# either at the JiakClient level or the individual request level.
|
91
|
+
#
|
92
|
+
# Settings passed to individual <code>get, store,</code> and
|
93
|
+
# <code>delete</code> requests take precendence over the setting maintained
|
94
|
+
# by a JiakClient. Any request parameter not set in JiakClient or on an
|
95
|
+
# individual request will default to the values set in the Riak cluster.
|
78
96
|
#
|
79
97
|
def initialize(uri, opts={})
|
80
98
|
check_opts(opts,VALID_OPTS,JiakClientException)
|
@@ -145,25 +163,38 @@ module RiakRest
|
|
145
163
|
# :call-seq:
|
146
164
|
# params -> hash
|
147
165
|
#
|
148
|
-
# Copy of the current parameters hash.
|
166
|
+
# Copy of the current request parameters hash.
|
149
167
|
def params
|
150
168
|
@params.dup
|
151
169
|
end
|
152
170
|
|
153
171
|
# :call-seq:
|
154
|
-
# set_schema(bucket) -> nil
|
172
|
+
# set_schema(bucket,schema=nil) -> nil
|
155
173
|
#
|
156
|
-
# Set the Jiak server schema for a bucket.
|
157
|
-
#
|
174
|
+
# Set the Jiak server schema for a bucket. If a JaikSchema is given, bucket
|
175
|
+
# must be a string; otherwise, if the schema is not given bucket must be a
|
176
|
+
# JiakBucket and the associated JiakData schema is used.
|
158
177
|
#
|
159
178
|
# Raise JiakClientException if the bucket is not a JiakBucket.
|
160
|
-
#
|
161
|
-
def set_schema(bucket)
|
162
|
-
|
163
|
-
|
179
|
+
# Raise JiakClientException if the schema is not a JiakSchema.
|
180
|
+
def set_schema(bucket,schema=nil)
|
181
|
+
if(schema.nil?)
|
182
|
+
unless bucket.is_a?(JiakBucket)
|
183
|
+
raise JiakClientException, "Bucket must be a JiakBucket."
|
184
|
+
end
|
185
|
+
bucket_name = bucket.name
|
186
|
+
schema = bucket.schema
|
187
|
+
else
|
188
|
+
unless(bucket.is_a?(String))
|
189
|
+
raise JiakClientException, "Bucket must be a string name."
|
190
|
+
end
|
191
|
+
unless(schema.is_a?(JiakSchema))
|
192
|
+
raise JiakClientException, "Schema must be a JiakSchema."
|
193
|
+
end
|
194
|
+
bucket_name = bucket
|
164
195
|
end
|
165
|
-
resp = RestClient.put(jiak_uri(
|
166
|
-
|
196
|
+
resp = RestClient.put(jiak_uri(bucket_name),
|
197
|
+
schema.to_jiak.to_json,
|
167
198
|
:content_type => APP_JSON,
|
168
199
|
:accept => APP_JSON)
|
169
200
|
end
|
@@ -171,9 +202,7 @@ module RiakRest
|
|
171
202
|
# :call-seq:
|
172
203
|
# schema(bucket) -> JiakSchema
|
173
204
|
#
|
174
|
-
# Get the data schema for a bucket on a Jiak server.
|
175
|
-
# to the Jiak server. See JiakBucket#schema for a way to get this
|
176
|
-
# information without server access.
|
205
|
+
# Get the data schema for a bucket on a Jiak server.
|
177
206
|
def schema(bucket)
|
178
207
|
JiakSchema.jiak_create(bucket_info(bucket,SCHEMA))
|
179
208
|
end
|
@@ -204,6 +233,11 @@ module RiakRest
|
|
204
233
|
# <code>:durable_writes</code><br/>
|
205
234
|
# <code>:reads</code><br/>
|
206
235
|
#
|
236
|
+
# See JiakClient#new for description of <code>writes,
|
237
|
+
# durable_writes,</code> and <code>reades</code> parameters. The
|
238
|
+
# <code>reads</code> parameter only takes effect if the JiakObject is being
|
239
|
+
# returned (which involves reading the writes).
|
240
|
+
#
|
207
241
|
# Raise JiakClientException if object not a JiakObject or illegal options
|
208
242
|
# are passed.<br/>
|
209
243
|
# Raise JiakResourceException on RESTful HTTP errors.
|
@@ -214,12 +248,14 @@ module RiakRest
|
|
214
248
|
req_params = {
|
215
249
|
WRITES => opts[:writes] || @params[:writes],
|
216
250
|
DURABLE_WRITES => opts[:durable_writes] || @params[:durable_writes],
|
217
|
-
READS => opts[:reads] || @params[:reads]
|
218
251
|
}
|
219
|
-
|
252
|
+
if(opts[:return] == :object)
|
253
|
+
req_params[RETURN_BODY] = true
|
254
|
+
req_params[READS] = opts[:reads] || @params[:reads]
|
255
|
+
end
|
220
256
|
|
221
257
|
begin
|
222
|
-
uri = jiak_uri(jobj.bucket,jobj.key
|
258
|
+
uri = jiak_uri(jobj.bucket,jobj.key) << jiak_qstring(req_params)
|
223
259
|
payload = jobj.to_jiak.to_json
|
224
260
|
headers = {
|
225
261
|
:content_type => APP_JSON,
|
@@ -270,7 +306,7 @@ module RiakRest
|
|
270
306
|
# String.
|
271
307
|
#
|
272
308
|
# =====Valid options
|
273
|
-
# <code>:reads</code>
|
309
|
+
# <code>:reads</code> --- See JiakClient#new
|
274
310
|
#
|
275
311
|
# Raise JiakClientException if bucket not a JiakBucket.<br/>
|
276
312
|
# Raise JiakResourceNotFound if resource not found on Jiak server.<br/>
|
@@ -281,10 +317,12 @@ module RiakRest
|
|
281
317
|
raise JiakClientException, "Bucket must be a JiakBucket."
|
282
318
|
end
|
283
319
|
check_opts(opts,[:reads],JiakClientException)
|
284
|
-
req_params = {
|
320
|
+
req_params = {
|
321
|
+
READS => opts[:reads] || @params[:reads]
|
322
|
+
}
|
285
323
|
|
286
324
|
begin
|
287
|
-
uri = jiak_uri(bucket,key
|
325
|
+
uri = jiak_uri(bucket,key) << jiak_qstring(req_params)
|
288
326
|
resp = RestClient.get(uri, :accept => APP_JSON)
|
289
327
|
JiakObject.jiak_create(JSON.parse(resp),bucket.data_class)
|
290
328
|
rescue RestClient::ResourceNotFound => err
|
@@ -302,16 +340,16 @@ module RiakRest
|
|
302
340
|
# Delete the JiakObject stored at the bucket/key.
|
303
341
|
#
|
304
342
|
# =====Valid options
|
305
|
-
# <code>:
|
343
|
+
# <code>:deletes</code> --- See JiakClient#new
|
306
344
|
#
|
307
345
|
# Raise JiakResourceException on RESTful HTTP errors.
|
308
346
|
#
|
309
347
|
def delete(bucket,key,opts={})
|
310
|
-
check_opts(opts,[:
|
348
|
+
check_opts(opts,[:deletes],JiakClientException)
|
311
349
|
begin
|
312
|
-
req_params = {
|
313
|
-
uri = jiak_uri(bucket,key
|
314
|
-
RestClient.delete(uri
|
350
|
+
req_params = {DELETES => opts[:deletes] || @params[:deletes]}
|
351
|
+
uri = jiak_uri(bucket,key) << jiak_qstring(req_params)
|
352
|
+
RestClient.delete(uri,:accept => APP_JSON)
|
315
353
|
true
|
316
354
|
rescue RestClient::ExceptionWithResponse => err
|
317
355
|
fail_with_response("delete", err)
|
@@ -320,6 +358,22 @@ module RiakRest
|
|
320
358
|
end
|
321
359
|
end
|
322
360
|
|
361
|
+
# :call-seq:
|
362
|
+
# exist?(bucket,key) -> true or false
|
363
|
+
#
|
364
|
+
# Return true if a resource exists at bucket/key
|
365
|
+
def exist?(bucket,key)
|
366
|
+
begin
|
367
|
+
uri = jiak_uri(bucket,key)
|
368
|
+
RestClient.head(uri,:accept => APP_JSON)
|
369
|
+
true
|
370
|
+
rescue RestClient::ResourceNotFound
|
371
|
+
false
|
372
|
+
rescue RestClient::Exception => err
|
373
|
+
fail_with_message("delete", err)
|
374
|
+
end
|
375
|
+
end
|
376
|
+
|
323
377
|
# :call-seq:
|
324
378
|
# walk(bucket,key,query,data_class) -> array
|
325
379
|
#
|
@@ -334,7 +388,7 @@ module RiakRest
|
|
334
388
|
start = jiak_uri(bucket,key)
|
335
389
|
case query
|
336
390
|
when QueryLink
|
337
|
-
uri = start
|
391
|
+
uri = "#{start}/#{query.for_uri}"
|
338
392
|
when Array
|
339
393
|
uri = query.inject(start) {|build,link| build+'/'+link.for_uri}
|
340
394
|
else
|
@@ -342,7 +396,6 @@ module RiakRest
|
|
342
396
|
'a QueryLink or an Array of QueryLink objects'
|
343
397
|
end
|
344
398
|
resp = RestClient.get(uri, :accept => APP_JSON)
|
345
|
-
# JSON.parse(resp)['results'][0]
|
346
399
|
JSON.parse(resp)['results'][0].map do |jiak|
|
347
400
|
JiakObject.jiak_create(jiak,data_class)
|
348
401
|
end
|
@@ -356,7 +409,7 @@ module RiakRest
|
|
356
409
|
# :call-seq:
|
357
410
|
# client == other -> true or false
|
358
411
|
#
|
359
|
-
# Equality
|
412
|
+
# Equality --- JiakClients are equal if they have the same URI
|
360
413
|
def ==(other)
|
361
414
|
(@server == other.server) rescue false
|
362
415
|
end
|
@@ -376,20 +429,30 @@ module RiakRest
|
|
376
429
|
end
|
377
430
|
|
378
431
|
# Build the URI for accessing the Jiak server.
|
379
|
-
def jiak_uri(bucket,key=""
|
380
|
-
|
381
|
-
uri
|
382
|
-
|
383
|
-
uri += "?#{URI.encode(qstring)}" unless qstring.empty?
|
432
|
+
def jiak_uri(bucket,key="")
|
433
|
+
bucket_name = bucket.is_a?(JiakBucket) ? bucket.name : bucket
|
434
|
+
uri = "#{@server}#{URI.encode(bucket_name)}"
|
435
|
+
uri << "/#{URI.encode(key)}" unless key.empty?
|
384
436
|
uri
|
385
437
|
end
|
386
438
|
private :jiak_uri
|
439
|
+
|
440
|
+
# Build query string. Strip keys with nil values.
|
441
|
+
def jiak_qstring(params={})
|
442
|
+
qstring = ""
|
443
|
+
params.delete_if {|k,v| v.nil?}
|
444
|
+
unless(params.empty?)
|
445
|
+
qstring << "?" << params.map{|k,v| "#{k}=#{v}"}.join('&')
|
446
|
+
end
|
447
|
+
qstring
|
448
|
+
end
|
449
|
+
private :jiak_qstring
|
387
450
|
|
388
451
|
# Get either the schema or keys for the bucket.
|
389
452
|
def bucket_info(bucket,info)
|
390
453
|
ignore = (info == SCHEMA) ? KEYS : SCHEMA
|
391
454
|
begin
|
392
|
-
uri = jiak_uri(bucket,""
|
455
|
+
uri = jiak_uri(bucket,"") << jiak_qstring({ignore => false})
|
393
456
|
JSON.parse(RestClient.get(uri, :accept => APP_JSON))[info]
|
394
457
|
rescue RestClient::ExceptionWithResponse => err
|
395
458
|
fail_with_response("get", err)
|
@@ -91,7 +91,7 @@ module RiakRest
|
|
91
91
|
#
|
92
92
|
# Raise JiakDataException if the fields include <code>jiak</code>.
|
93
93
|
def allow(*fields)
|
94
|
-
|
94
|
+
expand_schema("allow",*fields)
|
95
95
|
end
|
96
96
|
|
97
97
|
# :call-seq:
|
@@ -102,7 +102,7 @@ module RiakRest
|
|
102
102
|
#
|
103
103
|
# Returns an array of added fields.
|
104
104
|
def require(*fields)
|
105
|
-
|
105
|
+
expand_schema("require",*fields)
|
106
106
|
end
|
107
107
|
|
108
108
|
# :call-seq:
|
@@ -113,7 +113,7 @@ module RiakRest
|
|
113
113
|
#
|
114
114
|
# Returns an array of added fields.
|
115
115
|
def readable(*fields)
|
116
|
-
|
116
|
+
expand_schema("readable",*fields)
|
117
117
|
end
|
118
118
|
|
119
119
|
# :call-seq:
|
@@ -124,7 +124,7 @@ module RiakRest
|
|
124
124
|
#
|
125
125
|
# Returns an array of added fields.
|
126
126
|
def writable(*fields)
|
127
|
-
|
127
|
+
expand_schema("writable",*fields)
|
128
128
|
end
|
129
129
|
|
130
130
|
# :call-seq:
|
@@ -142,7 +142,7 @@ module RiakRest
|
|
142
142
|
|
143
143
|
# Delegates adding fields to the schema, then creates attr accessors for
|
144
144
|
# each field added.
|
145
|
-
def
|
145
|
+
def expand_schema(method,*fields)
|
146
146
|
@schema ||= JiakSchema.new
|
147
147
|
prev_allowed = @schema.allowed_fields
|
148
148
|
added_fields = @schema.send(method,*fields)
|
@@ -150,7 +150,7 @@ module RiakRest
|
|
150
150
|
added_allowed.each {|field| attr_accessor field}
|
151
151
|
added_fields
|
152
152
|
end
|
153
|
-
private :
|
153
|
+
private :expand_schema
|
154
154
|
|
155
155
|
# :call-seq:
|
156
156
|
# JiakData.schema -> JiakSchema
|
@@ -158,7 +158,6 @@ module RiakRest
|
|
158
158
|
# Get a JiakSchema representation this data.
|
159
159
|
def schema
|
160
160
|
@schema ||= JiakSchema.new
|
161
|
-
@schema.dup
|
162
161
|
end
|
163
162
|
|
164
163
|
# :call-seq:
|
@@ -200,10 +199,6 @@ module RiakRest
|
|
200
199
|
def self.included(including_class) # :nodoc:
|
201
200
|
including_class.extend(ClassMethods)
|
202
201
|
|
203
|
-
define_method(:initialize) do |hash={}|
|
204
|
-
hash.each {|k,v| instance_variable_set("@#{k}", v)}
|
205
|
-
end
|
206
|
-
|
207
202
|
define_method(:to_jiak) do
|
208
203
|
self.class.schema.write_mask.inject({}) do |build,field|
|
209
204
|
build[field] = send("#{field}")
|
@@ -235,6 +230,10 @@ module RiakRest
|
|
235
230
|
# Instance methods
|
236
231
|
# ----------------------------------------------------------------------
|
237
232
|
|
233
|
+
def initialize(hash={})
|
234
|
+
hash.each {|k,v| instance_variable_set("@#{k}", v)}
|
235
|
+
end
|
236
|
+
|
238
237
|
# :call-seq:
|
239
238
|
# to_jiak -> hash
|
240
239
|
#
|