riakrest 0.1.2 → 0.1.5
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 +6 -0
- data/README.rdoc +35 -25
- data/VERSION +1 -1
- data/examples/auto_manage_data.rb +51 -0
- data/examples/auto_update_links.rb +31 -14
- data/examples/basic_client.rb +33 -10
- data/examples/basic_resource.rb +29 -12
- data/examples/basic_resource_pov.rb +65 -0
- data/examples/buoy.rb +102 -0
- data/examples/buoy_pov.rb +46 -0
- data/examples/example_helper.rb +1 -0
- data/examples/linked_resources.rb +38 -70
- data/lib/riakrest/core/jiak_client.rb +56 -31
- data/lib/riakrest/core/jiak_data.rb +24 -14
- data/lib/riakrest/core/jiak_data_fields.rb +4 -4
- data/lib/riakrest/core/query_link.rb +13 -6
- data/lib/riakrest/resource/jiak_resource.rb +85 -71
- data/lib/riakrest/resource/jiak_resource_pov.rb +279 -0
- data/lib/riakrest.rb +3 -2
- data/spec/core/jiak_client_spec.rb +20 -5
- data/spec/resource/jiak_resource_spec.rb +111 -119
- metadata +11 -4
- data/examples/auto_update_data.rb +0 -38
@@ -1,14 +1,6 @@
|
|
1
1
|
require File.dirname(__FILE__) + '/example_helper.rb'
|
2
2
|
|
3
|
-
|
4
|
-
include JiakResource
|
5
|
-
server SERVER_URI
|
6
|
-
jattr_accessor :name
|
7
|
-
keygen { name }
|
8
|
-
end
|
9
|
-
(Child = Parents.dup).group 'children'
|
10
|
-
|
11
|
-
# relationships
|
3
|
+
# The parent-child relationships
|
12
4
|
parent_children = {
|
13
5
|
'p0' => ['c0'],
|
14
6
|
'p1' => ['c0','c1','c2'],
|
@@ -16,17 +8,20 @@ parent_children = {
|
|
16
8
|
'p3' => ['c3']
|
17
9
|
}
|
18
10
|
|
19
|
-
#
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
11
|
+
# Simple resource classes. Parent group (Jiak bucket name) defaults to
|
12
|
+
# lowercase of class name, so Child class just like Parent, but grouped by
|
13
|
+
# 'child' rather than 'parent'.
|
14
|
+
class Parent
|
15
|
+
include JiakResource
|
16
|
+
server SERVER_URI
|
17
|
+
attr_accessor :name
|
18
|
+
keygen { name }
|
25
19
|
end
|
20
|
+
(Child = Parent.dup).group 'child'
|
26
21
|
|
27
|
-
#
|
22
|
+
# Store data and relationships
|
28
23
|
parent_children.each do |pname,cnames|
|
29
|
-
p =
|
24
|
+
p = Parent.new(:name => pname).post
|
30
25
|
cnames.each do |cname|
|
31
26
|
begin
|
32
27
|
c = Child.get(cname)
|
@@ -40,70 +35,43 @@ parent_children.each do |pname,cnames|
|
|
40
35
|
p.update
|
41
36
|
end
|
42
37
|
|
43
|
-
#
|
44
|
-
parents
|
45
|
-
|
46
|
-
puts p1.name # => 'p1'
|
47
|
-
|
48
|
-
# retrieve children
|
49
|
-
children = child_parents.keys.map {|c| Child.get(c)}
|
50
|
-
c0,c1,c2,c3 = children
|
51
|
-
puts c1.name # => 'c1'
|
38
|
+
# Retrieve parents and children objects for future reference
|
39
|
+
parents = parent_children.keys.map {|p| Parent.get(p)}
|
40
|
+
children = parent_children.values.flatten.uniq.map {|c| Child.get(c)}
|
52
41
|
|
53
|
-
#
|
54
|
-
|
55
|
-
puts
|
42
|
+
# Retrieve parent-1 children by query
|
43
|
+
p1c = parents[1].query([Child,'child'])
|
44
|
+
puts " 3 children? #{p1c.size == 3}" # => true
|
45
|
+
puts " Including c2? #{p1c.include?(children[2])}" # => true
|
56
46
|
|
57
|
-
#
|
58
|
-
|
59
|
-
puts c3p
|
60
|
-
puts c3p[
|
47
|
+
# Retrieve child-3 parents by query
|
48
|
+
c3p = children[3].query([Parent,'parent'])
|
49
|
+
puts " 2 parents? #{c3p.size == 2}" # => true
|
50
|
+
puts " Including p2? #{c3p.include?(parents[2])}" # => true
|
61
51
|
|
62
|
-
#
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
puts
|
52
|
+
# Retrieve child-2 siblings by multi-step query
|
53
|
+
c2s = children[2].query([Parent,'parent',Child,'child'])
|
54
|
+
c2s.delete_if{|s| s.eql?(children[2])}
|
55
|
+
puts " 3 siblings? #{c2s.size == 3}" # => true
|
56
|
+
puts " Including c0? #{c2s.include?(children[0])}" # => true
|
67
57
|
|
68
|
-
#
|
69
|
-
c3sp =
|
58
|
+
# Who is c3's step-sibling's other parent?
|
59
|
+
c3sp = children[3].query([Parent,'parent',Child,'child',Parent,'parent'])
|
70
60
|
c3p.each {|p| c3sp.delete_if{|sp| p.eql?(sp)}}
|
71
|
-
puts c3sp[
|
72
|
-
|
73
|
-
# turn on auto-update at class level
|
74
|
-
Parents.auto_update true
|
75
|
-
Child.auto_update true
|
61
|
+
puts " Parent p1? #{c3sp.include?(parents[1])}" # => true
|
76
62
|
|
77
|
-
#
|
63
|
+
# Add sibling links using existing links (say, for convenience)
|
78
64
|
children.each do |c|
|
79
|
-
siblings = c.query(
|
65
|
+
siblings = c.query([Parent,'parent',Child,'child']).delete_if{|s| s.eql?(c)}
|
80
66
|
siblings.each {|s| c.link(s,'sibling')}
|
81
67
|
c.update
|
82
68
|
end
|
83
|
-
puts c1.query(Child,'sibling').size # => 2
|
84
|
-
|
85
|
-
# some folks are odd, and others are normal
|
86
|
-
parent_children.keys.each do |p|
|
87
|
-
parent = Parents.get(p)
|
88
|
-
p_children = parent.query(Child,'child')
|
89
|
-
p_children.each do |child|
|
90
|
-
child.link(parent, p[1].to_i.odd? ? 'odd' : 'normal')
|
91
|
-
child.update
|
92
|
-
parent.link(child, child.name[1].to_i.odd? ? 'odd' : 'normal')
|
93
|
-
end
|
94
|
-
parent.update
|
95
|
-
end
|
96
|
-
# refresh parents and children variables
|
97
|
-
parents.each {|p| p.refresh}
|
98
|
-
children.each {|c| c.refresh}
|
99
69
|
|
100
|
-
#
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
end
|
105
|
-
puts op[0].name # => 'p1'
|
70
|
+
# Retrieve child-2 siblings using new links
|
71
|
+
c2s = children[2].query([Child,'sibling'])
|
72
|
+
puts " 3 siblings? #{c2s.size == 3}" # => true
|
73
|
+
puts " Including c0? #{c2s.include?(children[0])}" # => true
|
106
74
|
|
107
|
-
#
|
75
|
+
# Clean-up by deleting all parents and children
|
108
76
|
parents.each {|p| p.delete}
|
109
77
|
children.each {|c| c.delete}
|
@@ -12,7 +12,7 @@ module RiakRest
|
|
12
12
|
#
|
13
13
|
# class PeopleData
|
14
14
|
# include JiakData
|
15
|
-
#
|
15
|
+
# attr_accessor :name, :age
|
16
16
|
# end
|
17
17
|
#
|
18
18
|
# client = JiakClient.new("http://localhost:8002/jiak")
|
@@ -45,29 +45,41 @@ module RiakRest
|
|
45
45
|
attr_accessor :server, :proxy, :params
|
46
46
|
|
47
47
|
# :stopdoc:
|
48
|
-
APP_JSON
|
48
|
+
APP_JSON = 'application/json'
|
49
49
|
APP_JSON.freeze
|
50
50
|
|
51
|
-
|
51
|
+
KEYS = 'keys'
|
52
|
+
SCHEMA = 'schema'
|
53
|
+
KEYS.freeze
|
54
|
+
SCHEMA.freeze
|
55
|
+
|
56
|
+
RETURN_BODY = 'returnbody'
|
57
|
+
READS = 'r'
|
58
|
+
WRITES = 'w'
|
59
|
+
DURABLE_WRITES = 'dw'
|
60
|
+
DELETES = 'rw'
|
61
|
+
COPY = 'copy'
|
62
|
+
READ = 'read'
|
63
|
+
|
52
64
|
RETURN_BODY.freeze
|
53
|
-
READS = 'r'
|
54
65
|
READS.freeze
|
55
|
-
WRITES = 'w'
|
56
66
|
WRITES.freeze
|
57
|
-
DURABLE_WRITES = 'dw'
|
58
67
|
DURABLE_WRITES.freeze
|
59
|
-
DELETES = 'rw'
|
60
68
|
DELETES.freeze
|
69
|
+
COPY.freeze
|
70
|
+
READ.freeze
|
61
71
|
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
72
|
+
CLIENT_PARAMS = [:reads,:writes,:durable_writes,:deletes,:proxy]
|
73
|
+
STORE_PARAMS = [:writes,:durable_writes,:return,:reads,:copy,:read]
|
74
|
+
GET_PARAMS = [:reads,:read]
|
75
|
+
DELETE_PARAMS = [:delete]
|
76
|
+
WALK_PARAMS = [:read]
|
66
77
|
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
78
|
+
CLIENT_PARAMS.freeze
|
79
|
+
STORE_PARAMS.freeze
|
80
|
+
GET_PARAMS.freeze
|
81
|
+
DELETE_PARAMS.freeze
|
82
|
+
WALK_PARAMS.freeze
|
71
83
|
# :startdoc:
|
72
84
|
|
73
85
|
# :call-seq:
|
@@ -79,7 +91,7 @@ module RiakRest
|
|
79
91
|
# =====Valid options
|
80
92
|
# <code>:reads</code>:: Minimum number of responding nodes for successful reads.
|
81
93
|
# <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
|
94
|
+
# <code>:durable_writes</code>:: Minimum number of responding nodes that must perform a durable write to a persistence layer.
|
83
95
|
# <code>:deletes</code>:: Minimum number of responding nodes for successful delete.
|
84
96
|
# <code>:proxy</code>:: Proxy server URI
|
85
97
|
#
|
@@ -95,7 +107,7 @@ module RiakRest
|
|
95
107
|
# individual request will default to the values set in the Riak cluster.
|
96
108
|
#
|
97
109
|
def initialize(uri, opts={})
|
98
|
-
check_opts(opts,
|
110
|
+
check_opts(opts,CLIENT_PARAMS,JiakClientException)
|
99
111
|
self.server = uri
|
100
112
|
self.proxy = opts.delete(:proxy)
|
101
113
|
self.params = opts
|
@@ -143,10 +155,10 @@ module RiakRest
|
|
143
155
|
# :call-seq:
|
144
156
|
# set_params(req_params={}) -> hash
|
145
157
|
#
|
146
|
-
# Set specified request parameters without changing unspecified
|
147
|
-
# method merges the passed parameters with the current settings.
|
158
|
+
# Set specified client request parameters without changing unspecified
|
159
|
+
# ones. This method merges the passed parameters with the current settings.
|
148
160
|
def set_params(req_params={})
|
149
|
-
check_opts(req_params,
|
161
|
+
check_opts(req_params,CLIENT_PARAMS,JiakClientException)
|
150
162
|
@params.merge!(req_params)
|
151
163
|
end
|
152
164
|
|
@@ -156,7 +168,7 @@ module RiakRest
|
|
156
168
|
# Set default params for Jiak client requests.
|
157
169
|
#
|
158
170
|
def params=(req_params)
|
159
|
-
check_opts(req_params,
|
171
|
+
check_opts(req_params,CLIENT_PARAMS,JiakClientException)
|
160
172
|
@params = req_params
|
161
173
|
end
|
162
174
|
|
@@ -232,32 +244,39 @@ module RiakRest
|
|
232
244
|
# <code>:writes</code><br/>
|
233
245
|
# <code>:durable_writes</code><br/>
|
234
246
|
# <code>:reads</code><br/>
|
247
|
+
# <code>:copy</code> -- <code>true</code> to indicate the any data
|
248
|
+
# fields already stored on the server and not explicitly altered by this
|
249
|
+
# write should be copied and left unchanged. Default is
|
250
|
+
# <code>false</code><br/>.
|
251
|
+
# <code>:read</code> -- Comma separated list of fields to be returned on
|
252
|
+
# read.
|
235
253
|
#
|
236
254
|
# See JiakClient#new for description of <code>writes,
|
237
|
-
# durable_writes,</code> and <code>
|
238
|
-
# <code>reads</code> parameter only takes effect if
|
239
|
-
# returned (which involves reading the writes).
|
255
|
+
# durable_writes,</code> and <code>reads</code> parameters. The
|
256
|
+
# <code>reads</code> and <code>read</code> parameter only takes effect if
|
257
|
+
# the JiakObject is being returned (which involves reading the writes).
|
240
258
|
#
|
241
259
|
# Raise JiakClientException if object not a JiakObject or illegal options
|
242
260
|
# are passed.<br/>
|
243
261
|
# Raise JiakResourceException on RESTful HTTP errors.
|
244
262
|
#
|
245
263
|
def store(jobj,opts={})
|
246
|
-
check_opts(opts,
|
247
|
-
JiakClientException)
|
264
|
+
check_opts(opts,STORE_PARAMS,JiakClientException)
|
248
265
|
req_params = {
|
249
266
|
WRITES => opts[:writes] || @params[:writes],
|
250
267
|
DURABLE_WRITES => opts[:durable_writes] || @params[:durable_writes],
|
268
|
+
COPY => opts[:copy]
|
251
269
|
}
|
252
270
|
if(opts[:return] == :object)
|
253
271
|
req_params[RETURN_BODY] = true
|
254
272
|
req_params[READS] = opts[:reads] || @params[:reads]
|
273
|
+
req_params[READ] = opts[:read]
|
255
274
|
end
|
256
275
|
|
257
276
|
begin
|
258
277
|
uri = jiak_uri(jobj.bucket,jobj.key) << jiak_qstring(req_params)
|
259
278
|
payload = jobj.to_jiak.to_json
|
260
|
-
headers = {
|
279
|
+
headers = {
|
261
280
|
:content_type => APP_JSON,
|
262
281
|
:accept => APP_JSON }
|
263
282
|
# Decision tree:
|
@@ -316,9 +335,10 @@ module RiakRest
|
|
316
335
|
unless bucket.is_a?(JiakBucket)
|
317
336
|
raise JiakClientException, "Bucket must be a JiakBucket."
|
318
337
|
end
|
319
|
-
check_opts(opts,
|
338
|
+
check_opts(opts,GET_PARAMS,JiakClientException)
|
320
339
|
req_params = {
|
321
|
-
READS => opts[:reads] || @params[:reads]
|
340
|
+
READS => opts[:reads] || @params[:reads],
|
341
|
+
READ => opts[:read]
|
322
342
|
}
|
323
343
|
|
324
344
|
begin
|
@@ -345,7 +365,7 @@ module RiakRest
|
|
345
365
|
# Raise JiakResourceException on RESTful HTTP errors.
|
346
366
|
#
|
347
367
|
def delete(bucket,key,opts={})
|
348
|
-
check_opts(opts,
|
368
|
+
check_opts(opts,DELETE_PARAMS,JiakClientException)
|
349
369
|
begin
|
350
370
|
req_params = {DELETES => opts[:deletes] || @params[:deletes]}
|
351
371
|
uri = jiak_uri(bucket,key) << jiak_qstring(req_params)
|
@@ -383,7 +403,11 @@ module RiakRest
|
|
383
403
|
# JiakObject array.
|
384
404
|
#
|
385
405
|
# See QueryLink for a description of the <code>query</code> structure.
|
386
|
-
def walk(bucket,key,query,data_class)
|
406
|
+
def walk(bucket,key,query,data_class,opts={})
|
407
|
+
check_opts(opts,WALK_PARAMS,JiakClientException)
|
408
|
+
req_params = {
|
409
|
+
READ => opts[:read]
|
410
|
+
}
|
387
411
|
begin
|
388
412
|
start = jiak_uri(bucket,key)
|
389
413
|
case query
|
@@ -395,6 +419,7 @@ module RiakRest
|
|
395
419
|
raise QueryLinkException, 'failed: query must be '+
|
396
420
|
'a QueryLink or an Array of QueryLink objects'
|
397
421
|
end
|
422
|
+
uri << jiak_qstring(req_params)
|
398
423
|
resp = RestClient.get(uri, :accept => APP_JSON)
|
399
424
|
JSON.parse(resp)['results'][0].map do |jiak|
|
400
425
|
JiakObject.jiak_create(jiak,data_class)
|
@@ -7,8 +7,8 @@ module RiakRest
|
|
7
7
|
# user-data instances, rather it facilitates creating the class used to
|
8
8
|
# create user-data instances.
|
9
9
|
#
|
10
|
-
# The class methods <code>
|
11
|
-
# <code>
|
10
|
+
# The class methods <code>attr_reader,attr_writer</code>, and
|
11
|
+
# <code>attr_accessor</code> are used to declare the Jiak readable and
|
12
12
|
# writable fields for a JiakData. The method <code>keygen</code> is used
|
13
13
|
# to specify a block for generating the key for a data instance. By default,
|
14
14
|
# JiakData generates an empty key which is interpreted by the Jiak server as
|
@@ -16,7 +16,7 @@ module RiakRest
|
|
16
16
|
# ====Example
|
17
17
|
# class FooBar
|
18
18
|
# include JiakData
|
19
|
-
#
|
19
|
+
# attr_accessor :foo, :bar
|
20
20
|
# keygen { foo.downcase }
|
21
21
|
# end
|
22
22
|
#
|
@@ -54,29 +54,29 @@ module RiakRest
|
|
54
54
|
module ClassMethods
|
55
55
|
|
56
56
|
# :call-seq:
|
57
|
-
#
|
57
|
+
# attr_reader :f1,...,:fn
|
58
58
|
#
|
59
59
|
# Add read accessible fields.
|
60
|
-
def
|
60
|
+
def attr_reader(*fields)
|
61
61
|
readable *fields
|
62
62
|
nil
|
63
63
|
end
|
64
|
-
alias :
|
64
|
+
alias :attr :attr_reader
|
65
65
|
|
66
66
|
# :call-seq:
|
67
|
-
#
|
67
|
+
# attr_writer :f1,...,:fn
|
68
68
|
#
|
69
69
|
# Add write accessible fields.
|
70
|
-
def
|
70
|
+
def attr_writer(*fields)
|
71
71
|
writable *fields
|
72
72
|
nil
|
73
73
|
end
|
74
74
|
|
75
75
|
# :call-seq:
|
76
|
-
#
|
76
|
+
# attr_accessor :f1,...,:fn
|
77
77
|
#
|
78
78
|
# Add read/write accessible fields.
|
79
|
-
def
|
79
|
+
def attr_accessor(*fields)
|
80
80
|
readable *fields
|
81
81
|
writable *fields
|
82
82
|
end
|
@@ -147,7 +147,17 @@ module RiakRest
|
|
147
147
|
prev_allowed = @schema.allowed_fields
|
148
148
|
added_fields = @schema.send(method,*fields)
|
149
149
|
added_allowed = @schema.allowed_fields - prev_allowed
|
150
|
-
added_allowed.each {|field| attr_accessor field}
|
150
|
+
# added_allowed.each {|field| attr_accessor field}
|
151
|
+
added_allowed.each do |field|
|
152
|
+
class_eval <<-EOH
|
153
|
+
def #{field}
|
154
|
+
@#{field}
|
155
|
+
end
|
156
|
+
def #{field}=(val)
|
157
|
+
@#{field} = val
|
158
|
+
end
|
159
|
+
EOH
|
160
|
+
end
|
151
161
|
added_fields
|
152
162
|
end
|
153
163
|
private :expand_schema
|
@@ -178,7 +188,7 @@ module RiakRest
|
|
178
188
|
# structured Jiak interaction. See JiakSchema for read mask discussion.
|
179
189
|
#
|
180
190
|
# User-defined data classes must either override this method explicitly
|
181
|
-
# or use the <code>
|
191
|
+
# or use the <code>attr_*</code> methods which implicitly override this
|
182
192
|
# method. The method is automatically called to marshall data from
|
183
193
|
# Jiak. You do not call this method explicitly.
|
184
194
|
#
|
@@ -242,11 +252,11 @@ module RiakRest
|
|
242
252
|
# for shema discussion.
|
243
253
|
#
|
244
254
|
# User-defined data classes must either override this method explicitly or
|
245
|
-
# use the <code>
|
255
|
+
# use the <code>attr_*</code> methods which implicitly provide an implicit
|
246
256
|
# override. The method is automatically called to marshall data to
|
247
257
|
# Jiak. You do not call this method explicitly.
|
248
258
|
|
249
|
-
# Data classes that do not used the
|
259
|
+
# Data classes that do not used the attr_* methods to specify attributes
|
250
260
|
# must override this method.
|
251
261
|
#
|
252
262
|
# ====Example
|
@@ -28,15 +28,15 @@ module RiakRest
|
|
28
28
|
if(args.size == 1)
|
29
29
|
case args[0]
|
30
30
|
when Symbol, Array
|
31
|
-
|
31
|
+
attr_accessor *args[0]
|
32
32
|
when JiakSchema
|
33
|
-
|
34
|
-
|
33
|
+
attr_reader *args[0].read_mask
|
34
|
+
attr_writer *args[0].write_mask
|
35
35
|
allow *args[0].allowed_fields
|
36
36
|
require *args[0].required_fields
|
37
37
|
end
|
38
38
|
else
|
39
|
-
|
39
|
+
attr_accessor *args
|
40
40
|
end
|
41
41
|
|
42
42
|
# :call-seq:
|
@@ -1,21 +1,28 @@
|
|
1
1
|
module RiakRest
|
2
2
|
|
3
|
-
# Represents a link used to query linked objects
|
4
|
-
# established using a JiakLink and queried
|
5
|
-
# are very similar but significantly
|
3
|
+
# Represents a link used to query linked objects using Jiak's link/step
|
4
|
+
# map-reduce facility. Links are established using a JiakLink and queried
|
5
|
+
# using a QueryLink. The structures are very similar but significantly
|
6
|
+
# different. A JiakLink is [bucket,key,tag] and a QueryLink is
|
7
|
+
# [bucket,tag,acc]. The accumulator field of a QueryLink allows for
|
8
|
+
# accumulating intermediate link/step results. Since RiakRest auto-inflates
|
9
|
+
# data returned via Jiak link/step processing, the accumulation of
|
10
|
+
# intermediate results is not supported by RiakRest. The setting of the
|
11
|
+
# <code>acc</code> is implemented for future consideration but should not be
|
12
|
+
# used.
|
6
13
|
#
|
7
14
|
# ===Usage
|
8
15
|
# <code>
|
9
16
|
# link = QueryLink.new('people','parent')
|
10
|
-
# link = QueryLink.new(
|
11
|
-
# link = QueryLink.new('blogs',nil,QueryLink::ANY)
|
17
|
+
# link = QueryLink.new('blogs',nil)
|
12
18
|
# </code>
|
13
19
|
class QueryLink
|
14
20
|
|
15
21
|
attr_accessor :bucket, :tag, :acc
|
16
22
|
|
17
|
-
# Jiak
|
23
|
+
# Jiak wildcard character (erlang atom)
|
18
24
|
ANY = '_'
|
25
|
+
ANY.freeze
|
19
26
|
|
20
27
|
# :call-seq:
|
21
28
|
# QueryLink.new(*args) -> QueryLink
|