paulcarey-relaxdb 0.2.7 → 0.2.8

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/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