couchrest 0.12.4 → 0.23

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.
Files changed (64) hide show
  1. data/README.md +33 -8
  2. data/Rakefile +11 -2
  3. data/examples/model/example.rb +19 -13
  4. data/lib/couchrest.rb +70 -11
  5. data/lib/couchrest/core/database.rb +121 -62
  6. data/lib/couchrest/core/design.rb +7 -17
  7. data/lib/couchrest/core/document.rb +42 -30
  8. data/lib/couchrest/core/response.rb +16 -0
  9. data/lib/couchrest/core/server.rb +47 -10
  10. data/lib/couchrest/helper/upgrade.rb +51 -0
  11. data/lib/couchrest/mixins.rb +4 -0
  12. data/lib/couchrest/mixins/attachments.rb +31 -0
  13. data/lib/couchrest/mixins/callbacks.rb +483 -0
  14. data/lib/couchrest/mixins/class_proxy.rb +108 -0
  15. data/lib/couchrest/mixins/design_doc.rb +90 -0
  16. data/lib/couchrest/mixins/document_queries.rb +44 -0
  17. data/lib/couchrest/mixins/extended_attachments.rb +68 -0
  18. data/lib/couchrest/mixins/extended_document_mixins.rb +7 -0
  19. data/lib/couchrest/mixins/properties.rb +129 -0
  20. data/lib/couchrest/mixins/validation.rb +242 -0
  21. data/lib/couchrest/mixins/views.rb +169 -0
  22. data/lib/couchrest/monkeypatches.rb +81 -6
  23. data/lib/couchrest/more/casted_model.rb +28 -0
  24. data/lib/couchrest/more/extended_document.rb +215 -0
  25. data/lib/couchrest/more/property.rb +40 -0
  26. data/lib/couchrest/support/blank.rb +42 -0
  27. data/lib/couchrest/support/class.rb +176 -0
  28. data/lib/couchrest/validation/auto_validate.rb +163 -0
  29. data/lib/couchrest/validation/contextual_validators.rb +78 -0
  30. data/lib/couchrest/validation/validation_errors.rb +118 -0
  31. data/lib/couchrest/validation/validators/absent_field_validator.rb +74 -0
  32. data/lib/couchrest/validation/validators/confirmation_validator.rb +99 -0
  33. data/lib/couchrest/validation/validators/format_validator.rb +117 -0
  34. data/lib/couchrest/validation/validators/formats/email.rb +66 -0
  35. data/lib/couchrest/validation/validators/formats/url.rb +43 -0
  36. data/lib/couchrest/validation/validators/generic_validator.rb +120 -0
  37. data/lib/couchrest/validation/validators/length_validator.rb +134 -0
  38. data/lib/couchrest/validation/validators/method_validator.rb +89 -0
  39. data/lib/couchrest/validation/validators/numeric_validator.rb +104 -0
  40. data/lib/couchrest/validation/validators/required_field_validator.rb +109 -0
  41. data/spec/couchrest/core/database_spec.rb +189 -124
  42. data/spec/couchrest/core/design_spec.rb +13 -6
  43. data/spec/couchrest/core/document_spec.rb +231 -177
  44. data/spec/couchrest/core/server_spec.rb +35 -0
  45. data/spec/couchrest/helpers/pager_spec.rb +1 -1
  46. data/spec/couchrest/more/casted_extended_doc_spec.rb +40 -0
  47. data/spec/couchrest/more/casted_model_spec.rb +98 -0
  48. data/spec/couchrest/more/extended_doc_attachment_spec.rb +130 -0
  49. data/spec/couchrest/more/extended_doc_spec.rb +509 -0
  50. data/spec/couchrest/more/extended_doc_subclass_spec.rb +98 -0
  51. data/spec/couchrest/more/extended_doc_view_spec.rb +355 -0
  52. data/spec/couchrest/more/property_spec.rb +136 -0
  53. data/spec/fixtures/more/article.rb +34 -0
  54. data/spec/fixtures/more/card.rb +20 -0
  55. data/spec/fixtures/more/course.rb +14 -0
  56. data/spec/fixtures/more/event.rb +6 -0
  57. data/spec/fixtures/more/invoice.rb +17 -0
  58. data/spec/fixtures/more/person.rb +8 -0
  59. data/spec/fixtures/more/question.rb +6 -0
  60. data/spec/fixtures/more/service.rb +12 -0
  61. data/spec/spec_helper.rb +13 -7
  62. metadata +58 -4
  63. data/lib/couchrest/core/model.rb +0 -613
  64. data/spec/couchrest/core/model_spec.rb +0 -855
@@ -14,7 +14,7 @@ describe CouchRest::Design do
14
14
  describe "with an unsaved view" do
15
15
  before(:each) do
16
16
  @des = CouchRest::Design.new
17
- method = @des.view_by :name
17
+ @des.view_by :name
18
18
  end
19
19
  it "should accept a name" do
20
20
  @des.name = "mytest"
@@ -31,7 +31,7 @@ describe CouchRest::Design do
31
31
  describe "saving" do
32
32
  before(:each) do
33
33
  @des = CouchRest::Design.new
34
- method = @des.view_by :name
34
+ @des.view_by :name
35
35
  @des.database = reset_test_db!
36
36
  end
37
37
  it "should fail without a name" do
@@ -49,7 +49,7 @@ describe CouchRest::Design do
49
49
  @db.bulk_save([{"name" => "x"},{"name" => "y"}])
50
50
  @des = CouchRest::Design.new
51
51
  @des.database = @db
52
- method = @des.view_by :name
52
+ @des.view_by :name
53
53
  end
54
54
  it "should by queryable when it's saved" do
55
55
  @des.name = "mydesign"
@@ -57,12 +57,19 @@ describe CouchRest::Design do
57
57
  res = @des.view :by_name
58
58
  res["rows"][0]["key"].should == "x"
59
59
  end
60
+ it "should be queryable on specified database" do
61
+ @des.name = "mydesign"
62
+ @des.save
63
+ @des.database = nil
64
+ res = @des.view_on @db, :by_name
65
+ res["rows"][0]["key"].should == "x"
66
+ end
60
67
  end
61
68
 
62
69
  describe "from a saved document" do
63
70
  before(:each) do
64
71
  @db = reset_test_db!
65
- @db.save({
72
+ @db.save_doc({
66
73
  "_id" => "_design/test",
67
74
  "views" => {
68
75
  "by_name" => {
@@ -92,7 +99,7 @@ describe CouchRest::Design do
92
99
  @db = reset_test_db!
93
100
  @des = CouchRest::Design.new
94
101
  @des.name = "test"
95
- method = @des.view_by :name, :descending => true
102
+ @des.view_by :name, :descending => true
96
103
  @des.database = @db
97
104
  @des.save
98
105
  @db.bulk_save([{"name" => "a"},{"name" => "z"}])
@@ -116,7 +123,7 @@ describe CouchRest::Design do
116
123
  @db = reset_test_db!
117
124
  @des = CouchRest::Design.new
118
125
  @des.name = "test"
119
- method = @des.view_by :name, :age
126
+ @des.view_by :name, :age
120
127
  @des.database = @db
121
128
  @des.save
122
129
  @db.bulk_save([{"name" => "a", "age" => 2},
@@ -1,213 +1,267 @@
1
1
  require File.dirname(__FILE__) + '/../../spec_helper'
2
2
 
3
- describe CouchRest::Document, "[]=" do
4
- before(:each) do
5
- @doc = CouchRest::Document.new
6
- end
7
- it "should work" do
8
- @doc["enamel"].should == nil
9
- @doc["enamel"] = "Strong"
10
- @doc["enamel"].should == "Strong"
11
- end
12
- it "[]= should convert to string" do
13
- @doc["enamel"].should == nil
14
- @doc[:enamel] = "Strong"
15
- @doc["enamel"].should == "Strong"
16
- end
17
- it "should read as a string" do
18
- @doc[:enamel] = "Strong"
19
- @doc[:enamel].should == "Strong"
20
- end
21
- end
3
+ class Video < CouchRest::Document; end
22
4
 
23
- describe CouchRest::Document, "new" do
24
- before(:each) do
25
- @doc = CouchRest::Document.new("key" => [1,2,3], :more => "values")
26
- end
27
- it "should create itself from a Hash" do
28
- @doc["key"].should == [1,2,3]
29
- @doc["more"].should == "values"
30
- end
31
- it "should not have rev and id" do
32
- @doc.rev.should be_nil
33
- @doc.id.should be_nil
34
- end
35
- it "should freak out when saving without a database" do
36
- lambda{@doc.save}.should raise_error(ArgumentError)
37
- end
38
- end
39
-
40
- # move to database spec
41
- describe CouchRest::Document, "saving using a database" do
5
+ describe CouchRest::Document do
6
+
42
7
  before(:all) do
43
- @doc = CouchRest::Document.new("key" => [1,2,3], :more => "values")
44
- @db = reset_test_db!
45
- @resp = @db.save(@doc)
46
- end
47
- it "should apply the database" do
48
- @doc.database.should == @db
49
- end
50
- it "should get id and rev" do
51
- @doc.id.should == @resp["id"]
52
- @doc.rev.should == @resp["rev"]
8
+ @couch = CouchRest.new
9
+ @db = @couch.database!(TESTDB)
53
10
  end
54
- end
55
11
 
56
- describe CouchRest::Document, "bulk saving" do
57
- before :all do
58
- @db = reset_test_db!
12
+ describe "[]=" do
13
+ before(:each) do
14
+ @doc = CouchRest::Document.new
15
+ end
16
+ it "should work" do
17
+ @doc["enamel"].should == nil
18
+ @doc["enamel"] = "Strong"
19
+ @doc["enamel"].should == "Strong"
20
+ end
21
+ it "[]= should convert to string" do
22
+ @doc["enamel"].should == nil
23
+ @doc[:enamel] = "Strong"
24
+ @doc["enamel"].should == "Strong"
25
+ end
26
+ it "should read as a string" do
27
+ @doc[:enamel] = "Strong"
28
+ @doc[:enamel].should == "Strong"
29
+ end
59
30
  end
60
31
 
61
- it "should use the document bulk save cache" do
62
- doc = CouchRest::Document.new({"_id" => "bulkdoc", "val" => 3})
63
- doc.database = @db
64
- doc.save(true)
65
- lambda { doc.database.get(doc["_id"]) }.should raise_error(RestClient::ResourceNotFound)
66
- doc.database.bulk_save
67
- doc.database.get(doc["_id"])["val"].should == doc["val"]
32
+ describe "default database" do
33
+ before(:each) do
34
+ Video.use_database nil
35
+ end
36
+ it "should be set using use_database on the model" do
37
+ Video.new.database.should be_nil
38
+ Video.use_database @db
39
+ Video.new.database.should == @db
40
+ Video.use_database nil
41
+ end
42
+
43
+ it "should be overwritten by instance" do
44
+ db = @couch.database('test')
45
+ article = Video.new
46
+ article.database.should be_nil
47
+ article.database = db
48
+ article.database.should_not be_nil
49
+ article.database.should == db
50
+ end
68
51
  end
69
- end
70
52
 
71
- describe "getting from a database" do
72
- before(:all) do
73
- @db = reset_test_db!
74
- @resp = @db.save({
75
- "key" => "value"
76
- })
77
- @doc = @db.get @resp['id']
78
- end
79
- it "should return a document" do
80
- @doc.should be_an_instance_of(CouchRest::Document)
81
- end
82
- it "should have a database" do
83
- @doc.database.should == @db
84
- end
85
- it "should be saveable and resavable" do
86
- @doc["more"] = "keys"
87
- @doc.save
88
- @db.get(@resp['id'])["more"].should == "keys"
89
- @doc["more"] = "these keys"
90
- @doc.save
91
- @db.get(@resp['id'])["more"].should == "these keys"
53
+ describe "new" do
54
+ before(:each) do
55
+ @doc = CouchRest::Document.new("key" => [1,2,3], :more => "values")
56
+ end
57
+ it "should create itself from a Hash" do
58
+ @doc["key"].should == [1,2,3]
59
+ @doc["more"].should == "values"
60
+ end
61
+ it "should not have rev and id" do
62
+ @doc.rev.should be_nil
63
+ @doc.id.should be_nil
64
+ end
65
+
66
+ it "should freak out when saving without a database" do
67
+ lambda{@doc.save}.should raise_error(ArgumentError)
68
+ end
69
+
92
70
  end
93
- end
94
71
 
95
- describe "destroying a document from a db" do
96
- before(:all) do
97
- @db = reset_test_db!
98
- @resp = @db.save({
99
- "key" => "value"
100
- })
101
- @doc = @db.get @resp['id']
102
- end
103
- it "should make it disappear" do
104
- @doc.destroy
105
- lambda{@db.get @resp['id']}.should raise_error
106
- end
107
- it "should error when there's no db" do
108
- @doc = CouchRest::Document.new("key" => [1,2,3], :more => "values")
109
- lambda{@doc.destroy}.should raise_error(ArgumentError)
72
+ # move to database spec
73
+ describe "saving using a database" do
74
+ before(:all) do
75
+ @doc = CouchRest::Document.new("key" => [1,2,3], :more => "values")
76
+ @db = reset_test_db!
77
+ @resp = @db.save_doc(@doc)
78
+ end
79
+ it "should apply the database" do
80
+ @doc.database.should == @db
81
+ end
82
+ it "should get id and rev" do
83
+ @doc.id.should == @resp["id"]
84
+ @doc.rev.should == @resp["rev"]
85
+ end
110
86
  end
111
- end
112
87
 
88
+ describe "bulk saving" do
89
+ before :all do
90
+ @db = reset_test_db!
91
+ end
113
92
 
114
- describe "destroying a document from a db using bulk save" do
115
- before(:all) do
116
- @db = reset_test_db!
117
- @resp = @db.save({
118
- "key" => "value"
119
- })
120
- @doc = @db.get @resp['id']
93
+ it "should use the document bulk save cache" do
94
+ doc = CouchRest::Document.new({"_id" => "bulkdoc", "val" => 3})
95
+ doc.database = @db
96
+ doc.save(true)
97
+ lambda { doc.database.get(doc["_id"]) }.should raise_error(RestClient::ResourceNotFound)
98
+ doc.database.bulk_save
99
+ doc.database.get(doc["_id"])["val"].should == doc["val"]
100
+ end
121
101
  end
122
- it "should defer actual deletion" do
123
- @doc.destroy(true)
124
- @doc['_id'].should == nil
125
- @doc['_rev'].should == nil
126
- lambda{@db.get @resp['id']}.should_not raise_error
127
- @db.bulk_save
128
- lambda{@db.get @resp['id']}.should raise_error
102
+
103
+ describe "getting from a database" do
104
+ before(:all) do
105
+ @db = reset_test_db!
106
+ @resp = @db.save_doc({
107
+ "key" => "value"
108
+ })
109
+ @doc = @db.get @resp['id']
110
+ end
111
+ it "should return a document" do
112
+ @doc.should be_an_instance_of(CouchRest::Document)
113
+ end
114
+ it "should have a database" do
115
+ @doc.database.should == @db
116
+ end
117
+ it "should be saveable and resavable" do
118
+ @doc["more"] = "keys"
119
+ @doc.save
120
+ @db.get(@resp['id'])["more"].should == "keys"
121
+ @doc["more"] = "these keys"
122
+ @doc.save
123
+ @db.get(@resp['id'])["more"].should == "these keys"
124
+ end
129
125
  end
130
- end
131
126
 
132
- describe "copying a document" do
133
- before :each do
134
- @db = reset_test_db!
135
- @resp = @db.save({'key' => 'value'})
136
- @docid = 'new-location'
137
- @doc = @db.get(@resp['id'])
127
+ describe "destroying a document from a db" do
128
+ before(:all) do
129
+ @db = reset_test_db!
130
+ @resp = @db.save_doc({
131
+ "key" => "value"
132
+ })
133
+ @doc = @db.get @resp['id']
134
+ end
135
+ it "should make it disappear" do
136
+ @doc.destroy
137
+ lambda{@db.get @resp['id']}.should raise_error
138
+ end
139
+ it "should error when there's no db" do
140
+ @doc = CouchRest::Document.new("key" => [1,2,3], :more => "values")
141
+ lambda{@doc.destroy}.should raise_error(ArgumentError)
142
+ end
138
143
  end
139
- describe "to a new location" do
140
- it "should work" do
141
- @doc.copy @docid
142
- newdoc = @db.get(@docid)
143
- newdoc['key'].should == 'value'
144
+
145
+
146
+ describe "destroying a document from a db using bulk save" do
147
+ before(:all) do
148
+ @db = reset_test_db!
149
+ @resp = @db.save_doc({
150
+ "key" => "value"
151
+ })
152
+ @doc = @db.get @resp['id']
144
153
  end
145
- it "should fail without a database" do
146
- lambda{CouchRest::Document.new({"not"=>"a real doc"}).copy}.should raise_error(ArgumentError)
154
+ it "should defer actual deletion" do
155
+ @doc.destroy(true)
156
+ @doc['_id'].should == nil
157
+ @doc['_rev'].should == nil
158
+ lambda{@db.get @resp['id']}.should_not raise_error
159
+ @db.bulk_save
160
+ lambda{@db.get @resp['id']}.should raise_error
147
161
  end
148
162
  end
149
- describe "to an existing location" do
163
+
164
+ describe "copying a document" do
150
165
  before :each do
151
- @db.save({'_id' => @docid, 'will-exist' => 'here'})
166
+ @db = reset_test_db!
167
+ @resp = @db.save_doc({'key' => 'value'})
168
+ @docid = 'new-location'
169
+ @doc = @db.get(@resp['id'])
152
170
  end
153
- it "should fail without a rev" do
154
- lambda{@doc.copy @docid}.should raise_error(RestClient::RequestFailed)
171
+ describe "to a new location" do
172
+ it "should work" do
173
+ @doc.copy @docid
174
+ newdoc = @db.get(@docid)
175
+ newdoc['key'].should == 'value'
176
+ end
177
+ it "should fail without a database" do
178
+ lambda{CouchRest::Document.new({"not"=>"a real doc"}).copy}.should raise_error(ArgumentError)
179
+ end
155
180
  end
156
- it "should succeed with a rev" do
157
- @to_be_overwritten = @db.get(@docid)
158
- @doc.copy "#{@docid}?rev=#{@to_be_overwritten['_rev']}"
159
- newdoc = @db.get(@docid)
160
- newdoc['key'].should == 'value'
161
- end
162
- it "should succeed given the doc to overwrite" do
163
- @to_be_overwritten = @db.get(@docid)
164
- @doc.copy @to_be_overwritten
165
- newdoc = @db.get(@docid)
166
- newdoc['key'].should == 'value'
181
+ describe "to an existing location" do
182
+ before :each do
183
+ @db.save_doc({'_id' => @docid, 'will-exist' => 'here'})
184
+ end
185
+ it "should fail without a rev" do
186
+ lambda{@doc.copy @docid}.should raise_error(RestClient::RequestFailed)
187
+ end
188
+ it "should succeed with a rev" do
189
+ @to_be_overwritten = @db.get(@docid)
190
+ @doc.copy "#{@docid}?rev=#{@to_be_overwritten['_rev']}"
191
+ newdoc = @db.get(@docid)
192
+ newdoc['key'].should == 'value'
193
+ end
194
+ it "should succeed given the doc to overwrite" do
195
+ @to_be_overwritten = @db.get(@docid)
196
+ @doc.copy @to_be_overwritten
197
+ newdoc = @db.get(@docid)
198
+ newdoc['key'].should == 'value'
199
+ end
167
200
  end
168
201
  end
169
202
  end
170
203
 
171
- describe "MOVE existing document" do
172
- before :each do
204
+ describe "dealing with attachments" do
205
+ before do
173
206
  @db = reset_test_db!
174
- @resp = @db.save({'key' => 'value'})
175
- @docid = 'new-location'
176
- @doc = @db.get(@resp['id'])
207
+ @attach = "<html><head><title>My Doc</title></head><body><p>Has words.</p></body></html>"
208
+ response = @db.save_doc({'key' => 'value'})
209
+ @doc = @db.get(response['id'])
177
210
  end
178
- describe "to a new location" do
179
- it "should work" do
180
- @doc.move @docid
181
- newdoc = @db.get(@docid)
182
- newdoc['key'].should == 'value'
183
- lambda {@db.get(@resp['id'])}.should raise_error(RestClient::ResourceNotFound)
211
+
212
+ def append_attachment(name='test.html', attach=@attach)
213
+ @doc['_attachments'] ||= {}
214
+ @doc['_attachments'][name] = {
215
+ 'type' => 'text/html',
216
+ 'data' => attach
217
+ }
218
+ @doc.save
219
+ @rev = @doc['_rev']
220
+ end
221
+
222
+ describe "PUTing an attachment directly to the doc" do
223
+ before do
224
+ @doc.put_attachment('test.html', @attach)
184
225
  end
185
- it "should fail without a database" do
186
- lambda{CouchRest::Document.new({"not"=>"a real doc"}).move}.should raise_error(ArgumentError)
187
- lambda{CouchRest::Document.new({"_id"=>"not a real doc"}).move}.should raise_error(ArgumentError)
226
+
227
+ it "is there" do
228
+ @db.fetch_attachment(@doc, 'test.html').should == @attach
229
+ end
230
+
231
+ it "updates the revision" do
232
+ @doc['_rev'].should_not == @rev
233
+ end
234
+
235
+ it "updates attachments" do
236
+ @attach2 = "<html><head><title>My Doc</title></head><body><p>Is Different.</p></body></html>"
237
+ @doc.put_attachment('test.html', @attach2)
238
+ @db.fetch_attachment(@doc, 'test.html').should == @attach2
188
239
  end
189
240
  end
190
- describe "to an existing location" do
191
- before :each do
192
- @db.save({'_id' => @docid, 'will-exist' => 'here'})
193
- end
194
- it "should fail without a rev" do
195
- lambda{@doc.move @docid}.should raise_error(RestClient::RequestFailed)
196
- lambda{@db.get(@resp['id'])}.should_not raise_error
197
- end
198
- it "should succeed with a rev" do
199
- @to_be_overwritten = @db.get(@docid)
200
- @doc.move "#{@docid}?rev=#{@to_be_overwritten['_rev']}"
201
- newdoc = @db.get(@docid)
202
- newdoc['key'].should == 'value'
203
- lambda {@db.get(@resp['id'])}.should raise_error(RestClient::ResourceNotFound)
204
- end
205
- it "should succeed given the doc to overwrite" do
206
- @to_be_overwritten = @db.get(@docid)
207
- @doc.move @to_be_overwritten
208
- newdoc = @db.get(@docid)
209
- newdoc['key'].should == 'value'
210
- lambda {@db.get(@resp['id'])}.should raise_error(RestClient::ResourceNotFound)
241
+
242
+ describe "fetching an attachment from a doc directly" do
243
+ before do
244
+ append_attachment
245
+ end
246
+
247
+ it "pulls the attachment" do
248
+ @doc.fetch_attachment('test.html').should == @attach
211
249
  end
212
250
  end
213
- end
251
+
252
+ describe "deleting an attachment from a doc directly" do
253
+ before do
254
+ append_attachment
255
+ @doc.delete_attachment('test.html')
256
+ end
257
+
258
+ it "removes it" do
259
+ lambda { @db.fetch_attachment(@doc, 'test.html').should }.should raise_error(RestClient::ResourceNotFound)
260
+ end
261
+
262
+ it "updates the revision" do
263
+ @doc['_rev'].should_not == @rev
264
+ end
265
+ end
266
+
267
+ end