paulcarey-relaxdb 0.2.7 → 0.2.8

Sign up to get free protection for your applications and to get access to all the features.
data/README.textile CHANGED
@@ -1,5 +1,7 @@
1
1
  h3. What's New?
2
2
 
3
+ * 02/02/09 - mostly fixes and tweaks for CouchDB trunk (tested against revision 0.9.0a740000). This includes a couple of breaking API changes - count became limit, 409 rather than 412 is returned on document update conflict, and '/' in design docs is treated differently.
4
+
3
5
  * Potentially breaking change. Skipping validations is now done by adding attribute symbols to an object's list rather than passing them to @save@. For example @my_obj.validation_skip_list << :foo@. This offers per object granularity over validations when working with bulk_save.
4
6
 
5
7
  * Potentially breaking change. @load@ now returns an array if passed an array of size one. Previously it would have returned a single object.
@@ -96,7 +98,7 @@ h3. Exploring models
96
98
  paul.ratings.size # 0
97
99
 
98
100
  # Simple views are auto created
99
- Rating.all.sorted_by(:thumbs_up) { |q| q.key(2).count(1) } # query params map directly to CouchDB
101
+ Rating.all.sorted_by(:thumbs_up) { |q| q.key(2).limit(1) } # query params map directly to CouchDB
100
102
  </code>
101
103
  </pre>
102
104
 
@@ -110,7 +112,7 @@ h3. Paginating models
110
112
  u_id = @user._id
111
113
 
112
114
  @posts = Post.paginate_by(page_params, :writer_id, :created_at) do |p|
113
- p.startkey([u_id, {}]).endkey([u_id]).descending(true).count(5)
115
+ p.startkey([u_id, {}]).endkey([u_id]).descending(true).limit(5)
114
116
  end
115
117
  render
116
118
  end
@@ -132,7 +134,7 @@ h3. Paginating over your own views
132
134
  <code>
133
135
 
134
136
  RelaxDB.paginate_view(page_params, "Letter", "by_letter_and_number", :letter, :number) do |p|
135
- p.startkey(["b"]).endkey(["b", {}]).count(2)
137
+ p.startkey(["b"]).endkey(["b", {}]).limit(2)
136
138
  end
137
139
 
138
140
  </code>
data/Rakefile CHANGED
@@ -4,7 +4,7 @@ require 'spec/rake/spectask'
4
4
 
5
5
  PLUGIN = "relaxdb"
6
6
  NAME = "relaxdb"
7
- GEM_VERSION = "0.2.7"
7
+ GEM_VERSION = "0.2.8"
8
8
  AUTHOR = "Paul Carey"
9
9
  EMAIL = "paul.p.carey@gmail.com"
10
10
  HOMEPAGE = "http://github.com/paulcarey/relaxdb/"
@@ -29,7 +29,7 @@ module RelaxDB
29
29
 
30
30
  def save
31
31
  database = RelaxDB.db
32
- resp = database.put(::CGI::escape(@data["_id"]), @data.to_json)
32
+ resp = database.put(@data["_id"], @data.to_json)
33
33
  @data["_rev"] = JSON.parse(resp.body)["rev"]
34
34
  self
35
35
  end
@@ -37,16 +37,16 @@ module RelaxDB
37
37
  def self.get(client_class)
38
38
  begin
39
39
  database = RelaxDB.db
40
- resp = database.get(::CGI::escape("_design/#{client_class}"))
40
+ resp = database.get("_design/#{client_class}")
41
41
  DesignDocument.new(client_class, JSON.parse(resp.body))
42
- rescue => e
42
+ rescue HTTP_404
43
43
  DesignDocument.new(client_class, {"_id" => "_design/#{client_class}"} )
44
44
  end
45
45
  end
46
46
 
47
47
  def destroy!
48
48
  # Implicitly prevent the object from being resaved by failing to update its revision
49
- RelaxDB.db.delete("#{::CGI::escape(@data["_id"])}?rev=#{@data["_rev"]}")
49
+ RelaxDB.db.delete("#{@data["_id"]}?rev=#{@data["_rev"]}")
50
50
  self
51
51
  end
52
52
 
@@ -116,16 +116,15 @@ module RelaxDB
116
116
  property :_id
117
117
  property :_rev
118
118
 
119
- def initialize(set_via_writers={}, hash=nil)
120
- hash, set_via_writers = set_via_writers, true if set_via_writers.is_a?(Hash)
121
-
122
- # The default _id will be overwritten if loaded from CouchDB
123
- self._id = UuidGenerator.uuid
119
+ def initialize(hash={})
120
+ unless hash["_id"]
121
+ self._id = UuidGenerator.uuid
122
+ end
124
123
 
125
124
  @errors = Errors.new
126
125
  @validation_skip_list = []
127
126
 
128
- # Set default properties if this object has not known CouchDB
127
+ # Set default properties if this object isn't being loaded from CouchDB
129
128
  unless hash["_rev"]
130
129
  properties.each do |prop|
131
130
  if methods.include?("set_default_#{prop}")
@@ -133,10 +132,10 @@ module RelaxDB
133
132
  end
134
133
  end
135
134
  end
136
-
137
- # Maybe use the presence of _rev in hash to determine this rather than
138
- # exposing the implementation detail to clients that choose to override?
139
- set_via_writers ? set_attributes(hash) : set_raw_attributes(hash)
135
+
136
+ @set_derived_props = hash["_rev"] ? false : true
137
+ set_attributes(hash)
138
+ @set_derived_props = true
140
139
  end
141
140
 
142
141
  def set_attributes(data)
@@ -154,37 +153,7 @@ module RelaxDB
154
153
  send("#{key}=".to_sym, val) if methods.include? "#{key}="
155
154
  end
156
155
  end
157
-
158
- # Set the raw attribute values rather than setting via the associated writers
159
- # The associated writers may invoke validation functions or set derived values
160
- # Such behaviour is unwanted when loading from CouchDB and potentially under
161
- # other circumstances
162
- def set_raw_attributes(data)
163
- data.each do |key, val|
164
- if [/_at$/, /_on$/, /_date$/].inject(nil) { |i, r| i ||= (key =~ r) }
165
- val = Time.parse(val).utc rescue val
166
- end
167
-
168
- if methods.include? "#{key}="
169
- key = key.to_sym
170
- if properties.include? key
171
- instance_variable_set("@#{key}".to_sym, val)
172
- elsif self.class.has_one_rels.include? key
173
- create_or_get_proxy(HasOneProxy, key).target = val
174
- else
175
- # belongs_to
176
- if key.to_s =~ /_id$/
177
- instance_variable_set("@#{key}".to_sym, val)
178
- else
179
- create_or_get_proxy(BelongsToProxy, key).target = val
180
- end
181
- end
182
- end
183
-
184
- end
185
-
186
- end
187
-
156
+
188
157
  def inspect
189
158
  s = "#<#{self.class}:#{self.object_id}"
190
159
  properties.each do |prop|
@@ -229,7 +198,7 @@ module RelaxDB
229
198
  begin
230
199
  resp = RelaxDB.db.put(_id, to_json)
231
200
  self._rev = JSON.parse(resp.body)["rev"]
232
- rescue HTTP_412
201
+ rescue HTTP_409
233
202
  on_update_conflict
234
203
  @update_conflict = true
235
204
  return false
@@ -367,16 +336,21 @@ module RelaxDB
367
336
  @references_many_rels ||= []
368
337
  @references_many_rels << relationship
369
338
 
339
+ id_arr_sym = "@#{relationship}".to_sym
340
+
370
341
  define_method(relationship) do
371
- array_sym = "@#{relationship}".to_sym
372
- instance_variable_set(array_sym, []) unless instance_variable_defined? array_sym
373
-
374
- create_or_get_proxy(RelaxDB::ReferencesManyProxy, relationship, opts)
342
+ instance_variable_set(id_arr_sym, []) unless instance_variable_defined? id_arr_sym
343
+ create_or_get_proxy(ReferencesManyProxy, relationship, opts)
344
+ end
345
+
346
+ define_method("#{relationship}_ids") do
347
+ instance_variable_set(id_arr_sym, []) unless instance_variable_defined? id_arr_sym
348
+ instance_variable_get(id_arr_sym)
375
349
  end
376
350
 
377
351
  define_method("#{relationship}=") do |val|
378
- # Sharp edge - do not invoke this method
379
- instance_variable_set("@#{relationship}".to_sym, val)
352
+ # Don't invoke this method unless you know what you're doing
353
+ instance_variable_set(id_arr_sym, val)
380
354
  end
381
355
  end
382
356
 
@@ -394,7 +368,7 @@ module RelaxDB
394
368
 
395
369
  define_method("#{relationship}=") do |children|
396
370
  create_or_get_proxy(HasManyProxy, relationship, opts).children = children
397
- write_derived_props(relationship)
371
+ write_derived_props(relationship) if @set_derived_props
398
372
  children
399
373
  end
400
374
  end
@@ -414,7 +388,7 @@ module RelaxDB
414
388
 
415
389
  define_method("#{relationship}=") do |new_target|
416
390
  create_or_get_proxy(HasOneProxy, relationship).target = new_target
417
- write_derived_props(relationship)
391
+ write_derived_props(relationship) if @set_derived_props
418
392
  new_target
419
393
  end
420
394
  end
@@ -433,13 +407,13 @@ module RelaxDB
433
407
 
434
408
  define_method("#{relationship}=") do |new_target|
435
409
  create_or_get_proxy(BelongsToProxy, relationship).target = new_target
436
- write_derived_props(relationship)
410
+ write_derived_props(relationship) if @set_derived_props
437
411
  end
438
412
 
439
413
  # Allows all writers to be invoked from the hash passed to initialize
440
414
  define_method("#{relationship}_id=") do |id|
441
415
  instance_variable_set("@#{relationship}_id".to_sym, id)
442
- write_derived_props(relationship)
416
+ write_derived_props(relationship) if @set_derived_props
443
417
  id
444
418
  end
445
419
 
@@ -2,7 +2,7 @@ module RelaxDB
2
2
 
3
3
  class PaginateParams
4
4
 
5
- @@params = %w(key startkey startkey_docid endkey endkey_docid count update descending group reduce include_docs)
5
+ @@params = %w(key startkey startkey_docid endkey endkey_docid limit update descending group reduce include_docs)
6
6
 
7
7
  @@params.each do |param|
8
8
  define_method(param.to_sym) do |*val|
@@ -69,7 +69,7 @@ module RelaxDB
69
69
  else
70
70
  query.startkey(@orig_paginate_params.startkey).descending(@orig_paginate_params.descending)
71
71
  end
72
- query.reduce(false).count(1)
72
+ query.reduce(false).limit(1)
73
73
  RelaxDB.retrieve(query.view_path).offset
74
74
  end
75
75
 
data/lib/relaxdb/query.rb CHANGED
@@ -3,7 +3,7 @@ module RelaxDB
3
3
  # A Query is used to build the query string made against a view
4
4
  # All parameter values are first JSON encoded and then URL encoded
5
5
  # Nil values are set to the empty string
6
- # All parameter calls return self so calls may be chained => q.startkey("foo").endkey("bar").count(2)
6
+ # All parameter calls return self so calls may be chained => q.startkey("foo").endkey("bar").limit(2)
7
7
 
8
8
  #
9
9
  # The query object is currently inconsistent with the RelaxDB object idiom. Consider
@@ -17,7 +17,7 @@ module RelaxDB
17
17
  class Query
18
18
 
19
19
  # keys is not included in the standard param as it is significantly different from the others
20
- @@params = %w(key startkey startkey_docid endkey endkey_docid count update descending skip group group_level reduce include_docs)
20
+ @@params = %w(key startkey startkey_docid endkey endkey_docid limit update descending skip group group_level reduce include_docs)
21
21
 
22
22
  @@params.each do |param|
23
23
  define_method(param.to_sym) do |*val|
@@ -10,6 +10,8 @@ module RelaxDB
10
10
 
11
11
  @target_class = opts[:class]
12
12
  @relationship_as_viewed_by_target = opts[:known_as].to_s
13
+
14
+ @peers = resolve
13
15
  end
14
16
 
15
17
  def <<(obj, reciprocal_invocation=false)
@@ -30,7 +32,6 @@ module RelaxDB
30
32
  end
31
33
 
32
34
  def clear
33
- resolve
34
35
  @peers.each do |peer|
35
36
  peer.send(@relationship_as_viewed_by_target).send(:delete_from_self, @client)
36
37
  end
@@ -53,7 +54,7 @@ module RelaxDB
53
54
  end
54
55
 
55
56
  def delete_from_self(obj)
56
- @peers.delete(obj) if @peers
57
+ @peers.delete(obj)
57
58
  peer_ids.delete(obj._id)
58
59
  end
59
60
 
@@ -66,12 +67,10 @@ module RelaxDB
66
67
  end
67
68
 
68
69
  def [](*args)
69
- resolve
70
70
  @peers[*args]
71
71
  end
72
72
 
73
73
  def each(&blk)
74
- resolve
75
74
  @peers.each(&blk)
76
75
  end
77
76
 
@@ -87,7 +86,7 @@ module RelaxDB
87
86
 
88
87
  private
89
88
 
90
- # Resolves the actual ids into real objects via a single GET to CouchDB. Called internally by each
89
+ # Resolves the actual ids into real objects via a single GET to CouchDB
91
90
  def resolve
92
91
  design_doc = @client.class
93
92
  view_name = @relationship
@@ -58,7 +58,7 @@ module RelaxDB
58
58
  obj._rev = new_rev["rev"]
59
59
  obj.post_save
60
60
  end
61
- rescue HTTP_412
61
+ rescue HTTP_409
62
62
  raise UpdateConflict, objs
63
63
  end
64
64
 
@@ -74,6 +74,8 @@ module RelaxDB
74
74
  end
75
75
 
76
76
  def load(ids)
77
+ # RelaxDB.logger.debug(caller.inject("#{db.name}/#{ids}\n") { |a, i| a += "#{i}\n" })
78
+
77
79
  if ids.is_a? Array
78
80
  resp = db.post("_all_docs?include_docs=true", {:keys => ids}.to_json)
79
81
  data = JSON.parse(resp.body)
@@ -174,7 +176,7 @@ module RelaxDB
174
176
  klass = data.delete("class")
175
177
  if klass
176
178
  k = Module.const_get(klass)
177
- k.new(false, data)
179
+ k.new(data)
178
180
  else
179
181
  # data is not of a known class
180
182
  ViewObject.create(data)
@@ -0,0 +1,11 @@
1
+ module RelaxDB
2
+
3
+ module Validators
4
+
5
+ def validator_required(att, o)
6
+ !att.blank?
7
+ end
8
+
9
+ end
10
+
11
+ end
data/lib/relaxdb/views.rb CHANGED
@@ -27,12 +27,12 @@ module RelaxDB
27
27
  def self.has_n(target_class, relationship_to_client)
28
28
  template = <<-MAP_FUNC
29
29
  function(doc) {
30
- if(doc.class == "${target_class}")
30
+ if(doc.class == "${target_class}" && doc.${relationship_to_client}_id)
31
31
  emit(doc.${relationship_to_client}_id, doc);
32
32
  }
33
33
  MAP_FUNC
34
34
  template.sub!("${target_class}", target_class)
35
- template.sub("${relationship_to_client}", relationship_to_client)
35
+ template.gsub("${relationship_to_client}", relationship_to_client)
36
36
  end
37
37
 
38
38
  def self.has_many_through(target_class, peers)
@@ -75,6 +75,27 @@ describe RelaxDB::BelongsToProxy do
75
75
  r.photo.rating.should == r
76
76
  end
77
77
 
78
+ it "may be used reciprocally" do
79
+ C1 = Class.new(RelaxDB::Document) do
80
+ belongs_to :c2
81
+ end
82
+ C2 = Class.new(RelaxDB::Document) do
83
+ belongs_to :c1
84
+ end
85
+ i1, i2 = C1.new, C2.new
86
+
87
+ i1.c2 = i2
88
+ i1.save!
89
+ i2.c1 = i1
90
+ i2.save!
91
+
92
+ i1 = RelaxDB.load i1._id
93
+ i1.c2.should == i2
94
+
95
+ i2 = RelaxDB.load i2._id
96
+ i2.c1.should == i1
97
+ end
98
+
78
99
  describe "validator" do
79
100
 
80
101
  it "should be passed the _id and object" do
@@ -80,6 +80,18 @@ describe RelaxDB::Document, "derived properties" do
80
80
  i.event_name.should == "bar"
81
81
  end
82
82
 
83
+ it "should contintue to be derived post load" do
84
+ e = DpEvent.new(:name => "shindig").save!
85
+ i = DpInvite.new(:event => e).save!
86
+
87
+ i = RelaxDB.load i._id
88
+ i.event_name.should == "shindig"
89
+
90
+ e = DpEvent.new(:name => "gidnihs").save!
91
+ i.event = e
92
+ i.event_name.should == "gidnihs"
93
+ end
94
+
83
95
  describe "multiple properties" do
84
96
 
85
97
  it "should be derivable from the same source" do
@@ -16,7 +16,7 @@ describe RelaxDB::DesignDocument do
16
16
 
17
17
  it "should create a corresponding document in CouchDB" do
18
18
  RelaxDB::DesignDocument.get("foo").save
19
- RelaxDB.load("_design%2Ffoo").should_not be_nil
19
+ RelaxDB.load("_design/foo").should_not be_nil
20
20
  end
21
21
 
22
22
  end
@@ -26,7 +26,7 @@ describe RelaxDB::DesignDocument do
26
26
  it "should delete the corresponding document from CouchDB" do
27
27
  dd = RelaxDB::DesignDocument.get("foo").save
28
28
  dd.destroy!
29
- RelaxDB.load("_design%2Ffoo").should be_nil
29
+ RelaxDB.load("_design/foo").should be_nil
30
30
  end
31
31
 
32
32
  end
@@ -46,13 +46,13 @@ describe RelaxDB::Document do
46
46
 
47
47
  it "may be overridden by inheriting classes" do
48
48
  i = Initiative.new(:x => "y").save
49
- i = RelaxDB.load(i._id)
49
+ i = RelaxDB.load("y")
50
50
  i.x.should == "y"
51
51
  i.foo.should == :bar
52
52
  end
53
53
 
54
54
  end
55
-
55
+
56
56
  describe "#to_json" do
57
57
 
58
58
  it "should not output nil attributes" do
@@ -139,7 +139,8 @@ describe RelaxDB::Document do
139
139
  User.new(:items => [], :invites_received => [], :invites_sent => [])
140
140
  end
141
141
 
142
- it "should issue only a single PUT request" do
142
+ # it should issue a single POST
143
+ it "should issue no PUT requests" do
143
144
  RelaxDB.db.put_count = 0
144
145
  RelaxDB.db.get_count = 0
145
146
 
@@ -185,10 +186,10 @@ describe RelaxDB::Document do
185
186
 
186
187
  describe "user defined property writer" do
187
188
 
188
- it "may be used with caution" do
189
+ it "should not be used" do
189
190
  o = BespokeWriter.new(:val => 101).save
190
191
  o = RelaxDB.load o._id
191
- o.val.should == 91
192
+ o.val.should == 81
192
193
  end
193
194
 
194
195
  end
@@ -333,6 +334,10 @@ describe RelaxDB::Document do
333
334
  end
334
335
 
335
336
  describe "results" do
337
+
338
+ it "should be an empty array when no docs match" do
339
+ Post.all.sorted_by(:subject).should == []
340
+ end
336
341
 
337
342
  it "should be retrievable by exact criteria" do
338
343
  Post.new(:subject => "foo").save
data/spec/query_spec.rb CHANGED
@@ -29,10 +29,10 @@ describe RelaxDB::Query do
29
29
  q.view_path.should == "_view//?key=%22olympus%22"
30
30
  end
31
31
 
32
- it "should honour startkey, endkey and count" do
32
+ it "should honour startkey, endkey and limit" do
33
33
  q = RelaxDB::Query.new("", "")
34
- q.startkey(["olympus"]).endkey(["vesuvius", 3600]).count(100)
35
- q.view_path.should == "_view//?startkey=%5B%22olympus%22%5D&endkey=%5B%22vesuvius%22%2C3600%5D&count=100"
34
+ q.startkey(["olympus"]).endkey(["vesuvius", 3600]).limit(100)
35
+ q.view_path.should == "_view//?startkey=%5B%22olympus%22%5D&endkey=%5B%22vesuvius%22%2C3600%5D&limit=100"
36
36
  end
37
37
 
38
38
  it "should specify a null key if key was set to nil" do
@@ -27,7 +27,37 @@ describe RelaxDB::ReferencesManyProxy do
27
27
  t.photos.size.should == 1
28
28
  t.photos[0].should == p
29
29
  end
30
-
30
+
31
+ it "should issue only a single request to resolve the relationship" do
32
+ p, t = Photo.new, Tag.new
33
+ p.tags << t
34
+
35
+ # Create the views
36
+ p.tags.map { |t| t._id }
37
+
38
+ p = RelaxDB.load p._id
39
+ RelaxDB.db.get_count = 0
40
+ p.tags.map { |t| t._id }
41
+ p.tags.map { |t| t._id }
42
+ RelaxDB.db.get_count.should == 1
43
+ end
44
+
45
+ it "should not resolve the relationship when an object is instantiated" do
46
+ p, t = Photo.new, Tag.new
47
+ p.tags << t
48
+
49
+ RelaxDB.db.get_count = 0
50
+ p = RelaxDB.load p._id
51
+ RelaxDB.db.get_count.should == 1
52
+ end
53
+
54
+ it "should make the ids available as a property" do
55
+ p, t = Photo.new, Tag.new
56
+ p.tags << t
57
+
58
+ p.tags_ids.should == [t._id]
59
+ end
60
+
31
61
  describe "#=" do
32
62
  it "should not be invoked" do
33
63
  end
@@ -62,6 +92,17 @@ describe RelaxDB::ReferencesManyProxy do
62
92
  p.tags.size.should == 1
63
93
  t.photos.size.should == 1
64
94
  end
95
+
96
+ it "will resolve the reciprocal relationship" do
97
+ # Create the views
98
+ p, t = Photo.new, Tag.new
99
+ p.tags << t
100
+
101
+ p, t = Photo.new, Tag.new
102
+ RelaxDB.db.get_count = 0
103
+ p.tags << t
104
+ RelaxDB.db.get_count.should == 2
105
+ end
65
106
 
66
107
  end
67
108
 
@@ -81,14 +122,13 @@ describe RelaxDB::ReferencesManyProxy do
81
122
 
82
123
  describe "owner#destroy" do
83
124
 
84
- it "will not remove its membership from its peers in memory" do
85
- # Documentating behaviour, not stating that this behaviour is desired
125
+ it "should remove its membership from its peers in memory" do
86
126
  p = Photo.new
87
127
  t = Tag.new
88
128
  p.tags << t
89
129
 
90
130
  p.destroy!
91
- t.photos.size.should == 1
131
+ t.photos.size.should == 0
92
132
  end
93
133
 
94
134
  it "should remove its membership from its peers in CouchDB" do
@@ -103,7 +143,7 @@ describe RelaxDB::ReferencesManyProxy do
103
143
  end
104
144
 
105
145
  # Leaving this test as a reminder of problems with all.destroy and a self referential
106
- # references_many until references_many is removed
146
+ # references_many
107
147
  #
108
148
  # This test more complex than it needs to be to prove the point
109
149
  # It also serves as a proof of a self referential references_many, but there are better places for that
data/spec/spec_models.rb CHANGED
@@ -11,8 +11,9 @@ unless @spec_models_loaded
11
11
  class Initiative < RelaxDB::Document
12
12
  property :x
13
13
  attr_reader :foo
14
- def initialize(*data)
15
- super *data
14
+ def initialize(data)
15
+ data[:_id] = data[:x]
16
+ super data
16
17
  @foo = :bar
17
18
  end
18
19
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: paulcarey-relaxdb
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.7
4
+ version: 0.2.8
5
5
  platform: ruby
6
6
  authors:
7
7
  - Paul Carey
@@ -9,7 +9,7 @@ autorequire: relaxdb
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2009-01-18 00:00:00 -08:00
12
+ date: 2009-02-02 00:00:00 -08:00
13
13
  default_executable:
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
@@ -68,7 +68,7 @@ files:
68
68
  - lib/relaxdb/server.rb
69
69
  - lib/relaxdb/sorted_by_view.rb
70
70
  - lib/relaxdb/uuid_generator.rb
71
- - lib/relaxdb/validators
71
+ - lib/relaxdb/validators.rb
72
72
  - lib/relaxdb/view_object.rb
73
73
  - lib/relaxdb/view_result.rb
74
74
  - lib/relaxdb/view_uploader.rb