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.
@@ -1,14 +1,6 @@
1
1
  require File.dirname(__FILE__) + '/example_helper.rb'
2
2
 
3
- class Parents
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
- # invert relationships
20
- child_parents = parent_children.inject({}) do |build, (p,cs)|
21
- cs.each do |c|
22
- build[c] ? build[c] << p : build[c] = [p]
23
- end
24
- build
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
- # store data and relationships
22
+ # Store data and relationships
28
23
  parent_children.each do |pname,cnames|
29
- p = Parents.new(:name => pname).post
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
- # retrieve parents
44
- parents = parent_children.keys.map {|p| Parents.get(p)}
45
- p0,p1,p2,p3 = parents
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
- # retrieve parent children
54
- p0c,p1c,p2c,p3c = parents.map {|p| p.query(Child,'child')}
55
- puts p2c[0].name # => 'c2' (could be 'c3')
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
- # retrieve children parents
58
- c0p,c1p,c2p,c3p = children.map {|c| c.query(Parents,'parent')}
59
- puts c3p[0].name # => 'p2'
60
- puts c3p[1].name # => 'p3'
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
- # retrieve children siblings
63
- c0s,c1s,c2s,c3s = children.map do |c|
64
- c.query(Parents,'parent',Child,'child').delete_if{|s| s.eql?(c)}
65
- end
66
- puts c3s[0].name # => 'c2'
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
- # who is c3's step-sibling's other parent?
69
- c3sp = c3.query(Parents,'parent',Child,'child',Parents,'parent')
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[0].name # => "p1"
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
- # add sibling links
63
+ # Add sibling links using existing links (say, for convenience)
78
64
  children.each do |c|
79
- siblings = c.query(Parents,'parent',Child,'child').delete_if{|s| s.eql?(c)}
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
- # do any odd parents have normal children?
101
- op = parents.inject([]) do |build,parent|
102
- build << parent.query(Child,'normal',Parents,'odd')
103
- build.flatten.uniq
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
- # clean-up by deleting everybody
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
- # jattr_accessor :name, :age
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 = 'application/json'
48
+ APP_JSON = 'application/json'
49
49
  APP_JSON.freeze
50
50
 
51
- RETURN_BODY = 'returnbody'
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
- VALID_PARAMS = [:reads,:writes,:durable_writes,:deletes]
63
- VALID_PARAMS.freeze
64
- VALID_OPTS = Array.new(VALID_PARAMS) << :proxy
65
- VALID_OPTS.freeze
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
- KEYS = 'keys'
68
- KEYS.freeze
69
- SCHEMA = 'schema'
70
- SCHEMA.freeze
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 resonding nodes that must perform a durable write to the persistence layer.
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,VALID_OPTS,JiakClientException)
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 ones. This
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,VALID_PARAMS,JiakClientException)
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,VALID_PARAMS,JiakClientException)
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>reades</code> parameters. The
238
- # <code>reads</code> parameter only takes effect if the JiakObject is being
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,[:return,:reads,:writes,:durable_writes],
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,[:reads],JiakClientException)
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,[:deletes],JiakClientException)
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>jattr_reader,jattr_writer</code>, and
11
- # <code>jattr_accessor</code> are used to declare the Jiak readable and
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
- # jattr_accessor :foo, :bar
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
- # jattr_reader :f1,...,:fn
57
+ # attr_reader :f1,...,:fn
58
58
  #
59
59
  # Add read accessible fields.
60
- def jattr_reader(*fields)
60
+ def attr_reader(*fields)
61
61
  readable *fields
62
62
  nil
63
63
  end
64
- alias :jattr :jattr_reader
64
+ alias :attr :attr_reader
65
65
 
66
66
  # :call-seq:
67
- # jattr_writer :f1,...,:fn
67
+ # attr_writer :f1,...,:fn
68
68
  #
69
69
  # Add write accessible fields.
70
- def jattr_writer(*fields)
70
+ def attr_writer(*fields)
71
71
  writable *fields
72
72
  nil
73
73
  end
74
74
 
75
75
  # :call-seq:
76
- # jattr_accessor :f1,...,:fn
76
+ # attr_accessor :f1,...,:fn
77
77
  #
78
78
  # Add read/write accessible fields.
79
- def jattr_accessor(*fields)
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>jattr_*</code> methods which implicitly override this
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>jattr_*</code> methods which implicitly provide an implicit
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 jattr_* methods to specify attributes
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
- jattr_accessor *args[0]
31
+ attr_accessor *args[0]
32
32
  when JiakSchema
33
- jattr_reader *args[0].read_mask
34
- jattr_writer *args[0].write_mask
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
- jattr_accessor *args
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 in Jiak. Links are
4
- # established using a JiakLink and queried using a QueryLink. The structures
5
- # are very similar but significantly different.
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(['children','odd','_'])
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 (erlang) wildcard character (atom)
23
+ # Jiak wildcard character (erlang atom)
18
24
  ANY = '_'
25
+ ANY.freeze
19
26
 
20
27
  # :call-seq:
21
28
  # QueryLink.new(*args) -> QueryLink