brianmario-couchrest 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 (92) hide show
  1. data/LICENSE +176 -0
  2. data/README.md +95 -0
  3. data/Rakefile +75 -0
  4. data/THANKS.md +18 -0
  5. data/examples/model/example.rb +144 -0
  6. data/examples/word_count/markov +38 -0
  7. data/examples/word_count/views/books/chunked-map.js +3 -0
  8. data/examples/word_count/views/books/united-map.js +1 -0
  9. data/examples/word_count/views/markov/chain-map.js +6 -0
  10. data/examples/word_count/views/markov/chain-reduce.js +7 -0
  11. data/examples/word_count/views/word_count/count-map.js +6 -0
  12. data/examples/word_count/views/word_count/count-reduce.js +3 -0
  13. data/examples/word_count/word_count.rb +46 -0
  14. data/examples/word_count/word_count_query.rb +40 -0
  15. data/examples/word_count/word_count_views.rb +26 -0
  16. data/lib/couchrest.rb +198 -0
  17. data/lib/couchrest/commands/generate.rb +71 -0
  18. data/lib/couchrest/commands/push.rb +103 -0
  19. data/lib/couchrest/core/database.rb +303 -0
  20. data/lib/couchrest/core/design.rb +79 -0
  21. data/lib/couchrest/core/document.rb +87 -0
  22. data/lib/couchrest/core/response.rb +16 -0
  23. data/lib/couchrest/core/server.rb +88 -0
  24. data/lib/couchrest/core/view.rb +4 -0
  25. data/lib/couchrest/helper/pager.rb +103 -0
  26. data/lib/couchrest/helper/streamer.rb +44 -0
  27. data/lib/couchrest/helper/upgrade.rb +51 -0
  28. data/lib/couchrest/mixins.rb +4 -0
  29. data/lib/couchrest/mixins/attachments.rb +31 -0
  30. data/lib/couchrest/mixins/callbacks.rb +483 -0
  31. data/lib/couchrest/mixins/class_proxy.rb +108 -0
  32. data/lib/couchrest/mixins/design_doc.rb +90 -0
  33. data/lib/couchrest/mixins/document_queries.rb +44 -0
  34. data/lib/couchrest/mixins/extended_attachments.rb +68 -0
  35. data/lib/couchrest/mixins/extended_document_mixins.rb +7 -0
  36. data/lib/couchrest/mixins/properties.rb +129 -0
  37. data/lib/couchrest/mixins/validation.rb +242 -0
  38. data/lib/couchrest/mixins/views.rb +169 -0
  39. data/lib/couchrest/monkeypatches.rb +113 -0
  40. data/lib/couchrest/more/casted_model.rb +28 -0
  41. data/lib/couchrest/more/extended_document.rb +215 -0
  42. data/lib/couchrest/more/property.rb +40 -0
  43. data/lib/couchrest/support/blank.rb +42 -0
  44. data/lib/couchrest/support/class.rb +176 -0
  45. data/lib/couchrest/validation/auto_validate.rb +163 -0
  46. data/lib/couchrest/validation/contextual_validators.rb +78 -0
  47. data/lib/couchrest/validation/validation_errors.rb +118 -0
  48. data/lib/couchrest/validation/validators/absent_field_validator.rb +74 -0
  49. data/lib/couchrest/validation/validators/confirmation_validator.rb +99 -0
  50. data/lib/couchrest/validation/validators/format_validator.rb +117 -0
  51. data/lib/couchrest/validation/validators/formats/email.rb +66 -0
  52. data/lib/couchrest/validation/validators/formats/url.rb +43 -0
  53. data/lib/couchrest/validation/validators/generic_validator.rb +120 -0
  54. data/lib/couchrest/validation/validators/length_validator.rb +134 -0
  55. data/lib/couchrest/validation/validators/method_validator.rb +89 -0
  56. data/lib/couchrest/validation/validators/numeric_validator.rb +104 -0
  57. data/lib/couchrest/validation/validators/required_field_validator.rb +109 -0
  58. data/spec/couchrest/core/couchrest_spec.rb +201 -0
  59. data/spec/couchrest/core/database_spec.rb +699 -0
  60. data/spec/couchrest/core/design_spec.rb +138 -0
  61. data/spec/couchrest/core/document_spec.rb +267 -0
  62. data/spec/couchrest/core/server_spec.rb +35 -0
  63. data/spec/couchrest/helpers/pager_spec.rb +122 -0
  64. data/spec/couchrest/helpers/streamer_spec.rb +23 -0
  65. data/spec/couchrest/more/casted_extended_doc_spec.rb +40 -0
  66. data/spec/couchrest/more/casted_model_spec.rb +98 -0
  67. data/spec/couchrest/more/extended_doc_attachment_spec.rb +130 -0
  68. data/spec/couchrest/more/extended_doc_spec.rb +509 -0
  69. data/spec/couchrest/more/extended_doc_subclass_spec.rb +98 -0
  70. data/spec/couchrest/more/extended_doc_view_spec.rb +355 -0
  71. data/spec/couchrest/more/property_spec.rb +136 -0
  72. data/spec/fixtures/attachments/README +3 -0
  73. data/spec/fixtures/attachments/couchdb.png +0 -0
  74. data/spec/fixtures/attachments/test.html +11 -0
  75. data/spec/fixtures/more/article.rb +34 -0
  76. data/spec/fixtures/more/card.rb +20 -0
  77. data/spec/fixtures/more/course.rb +14 -0
  78. data/spec/fixtures/more/event.rb +6 -0
  79. data/spec/fixtures/more/invoice.rb +17 -0
  80. data/spec/fixtures/more/person.rb +8 -0
  81. data/spec/fixtures/more/question.rb +6 -0
  82. data/spec/fixtures/more/service.rb +12 -0
  83. data/spec/fixtures/views/lib.js +3 -0
  84. data/spec/fixtures/views/test_view/lib.js +3 -0
  85. data/spec/fixtures/views/test_view/only-map.js +4 -0
  86. data/spec/fixtures/views/test_view/test-map.js +3 -0
  87. data/spec/fixtures/views/test_view/test-reduce.js +3 -0
  88. data/spec/spec.opts +6 -0
  89. data/spec/spec_helper.rb +26 -0
  90. data/utils/remap.rb +27 -0
  91. data/utils/subset.rb +30 -0
  92. metadata +200 -0
@@ -0,0 +1,699 @@
1
+ require File.dirname(__FILE__) + '/../../spec_helper'
2
+
3
+ describe CouchRest::Database do
4
+ before(:each) do
5
+ @cr = CouchRest.new(COUCHHOST)
6
+ @db = @cr.database(TESTDB)
7
+ @db.delete! rescue nil
8
+ @db = @cr.create_db(TESTDB) rescue nil
9
+ end
10
+
11
+ describe "database name including slash" do
12
+ it "should escape the name in the URI" do
13
+ db = @cr.database("foo/bar")
14
+ db.name.should == "foo/bar"
15
+ db.uri.should == "#{COUCHHOST}/foo%2Fbar"
16
+ end
17
+ end
18
+
19
+ describe "map query with _temp_view in Javascript" do
20
+ before(:each) do
21
+ @db.bulk_save([
22
+ {"wild" => "and random"},
23
+ {"mild" => "yet local"},
24
+ {"another" => ["set","of","keys"]}
25
+ ])
26
+ @temp_view = {:map => "function(doc){for(var w in doc){ if(!w.match(/^_/))emit(w,doc[w])}}"}
27
+ end
28
+ it "should return the result of the temporary function" do
29
+ rs = @db.temp_view(@temp_view)
30
+ rs['rows'].select{|r|r['key'] == 'wild' && r['value'] == 'and random'}.length.should == 1
31
+ end
32
+ it "should work with a range" do
33
+ rs = @db.temp_view(@temp_view, :startkey => "b", :endkey => "z")
34
+ rs['rows'].length.should == 2
35
+ end
36
+ it "should work with a key" do
37
+ rs = @db.temp_view(@temp_view, :key => "wild")
38
+ rs['rows'].length.should == 1
39
+ end
40
+ it "should work with a limit" do
41
+ rs = @db.temp_view(@temp_view, :limit => 1)
42
+ rs['rows'].length.should == 1
43
+ end
44
+ it "should work with multi-keys" do
45
+ rs = @db.temp_view(@temp_view, :keys => ["another", "wild"])
46
+ rs['rows'].length.should == 2
47
+ end
48
+ end
49
+
50
+ describe "map/reduce query with _temp_view in Javascript" do
51
+ before(:each) do
52
+ @db.bulk_save([
53
+ {"beverage" => "beer", :count => 4},
54
+ {"beverage" => "beer", :count => 2},
55
+ {"beverage" => "tea", :count => 3}
56
+ ])
57
+ end
58
+ it "should return the result of the temporary function" do
59
+ rs = @db.temp_view(:map => "function(doc){emit(doc.beverage, doc.count)}", :reduce => "function(beverage,counts){return sum(counts)}")
60
+ # rs.should == 'x'
61
+ rs['rows'][0]['value'].should == 9
62
+ end
63
+ end
64
+
65
+ describe "saving a view" do
66
+ before(:each) do
67
+ @view = {'test' => {'map' => 'function(doc) {
68
+ if (doc.word && !/\W/.test(doc.word)) {
69
+ emit(doc.word,null);
70
+ }
71
+ }'}}
72
+ @db.save_doc({
73
+ "_id" => "_design/test",
74
+ :views => @view
75
+ })
76
+ end
77
+ it "should work properly" do
78
+ @db.bulk_save([
79
+ {"word" => "once"},
80
+ {"word" => "and again"}
81
+ ])
82
+ @db.view('test/test')['total_rows'].should == 1
83
+ end
84
+ it "should round trip" do
85
+ @db.get("_design/test")['views'].should == @view
86
+ end
87
+ end
88
+
89
+ describe "select from an existing view" do
90
+ before(:each) do
91
+ r = @db.save_doc({
92
+ "_id" => "_design/first",
93
+ :views => {
94
+ :test => {
95
+ :map => "function(doc){for(var w in doc){ if(!w.match(/^_/))emit(w,doc[w])}}"
96
+ }
97
+ }
98
+ })
99
+ @db.bulk_save([
100
+ {"wild" => "and random"},
101
+ {"mild" => "yet local"},
102
+ {"another" => ["set","of","keys"]}
103
+ ])
104
+ end
105
+ it "should have the view" do
106
+ @db.get('_design/first')['views']['test']['map'].should include("for(var w in doc)")
107
+ end
108
+ it "should list from the view" do
109
+ rs = @db.view('first/test')
110
+ rs['rows'].select{|r|r['key'] == 'wild' && r['value'] == 'and random'}.length.should == 1
111
+ end
112
+ it "should work with a range" do
113
+ rs = @db.view('first/test', :startkey => "b", :endkey => "z")
114
+ rs['rows'].length.should == 2
115
+ end
116
+ it "should work with a key" do
117
+ rs = @db.view('first/test', :key => "wild")
118
+ rs['rows'].length.should == 1
119
+ end
120
+ it "should work with a limit" do
121
+ rs = @db.view('first/test', :limit => 1)
122
+ rs['rows'].length.should == 1
123
+ end
124
+ it "should work with multi-keys" do
125
+ rs = @db.view('first/test', :keys => ["another", "wild"])
126
+ rs['rows'].length.should == 2
127
+ end
128
+ it "should accept a block" do
129
+ rows = []
130
+ rs = @db.view('first/test', :include_docs => true) do |row|
131
+ rows << row
132
+ end
133
+ rows.length.should == 4
134
+ rs["total_rows"].should == 3
135
+ end
136
+ end
137
+
138
+ describe "GET (document by id) when the doc exists" do
139
+ before(:each) do
140
+ @r = @db.save_doc({'lemons' => 'from texas', 'and' => 'spain'})
141
+ @docid = "http://example.com/stuff.cgi?things=and%20stuff"
142
+ @db.save_doc({'_id' => @docid, 'will-exist' => 'here'})
143
+ end
144
+ it "should get the document" do
145
+ doc = @db.get(@r['id'])
146
+ doc['lemons'].should == 'from texas'
147
+ end
148
+ it "should work with a funky id" do
149
+ @db.get(@docid)['will-exist'].should == 'here'
150
+ end
151
+ end
152
+
153
+ describe "POST (adding bulk documents)" do
154
+ it "should add them without ids" do
155
+ rs = @db.bulk_save([
156
+ {"wild" => "and random"},
157
+ {"mild" => "yet local"},
158
+ {"another" => ["set","of","keys"]}
159
+ ])
160
+ rs.each do |r|
161
+ @db.get(r['id']).rev.should == r["rev"]
162
+ end
163
+ end
164
+
165
+ it "should use uuids when ids aren't provided" do
166
+ @db.server.stub!(:next_uuid).and_return('asdf6sgadkfhgsdfusdf')
167
+
168
+ docs = [{'key' => 'value'}, {'_id' => 'totally-uniq'}]
169
+ id_docs = [{'key' => 'value', '_id' => 'asdf6sgadkfhgsdfusdf'}, {'_id' => 'totally-uniq'}]
170
+ CouchRest.should_receive(:post).with("http://127.0.0.1:5984/couchrest-test/_bulk_docs", {:docs => id_docs})
171
+
172
+ @db.bulk_save(docs)
173
+ end
174
+
175
+ it "should add them with uniq ids" do
176
+ rs = @db.bulk_save([
177
+ {"_id" => "oneB", "wild" => "and random"},
178
+ {"_id" => "twoB", "mild" => "yet local"},
179
+ {"another" => ["set","of","keys"]}
180
+ ])
181
+ rs.each do |r|
182
+ @db.get(r['id']).rev.should == r["rev"]
183
+ end
184
+ end
185
+
186
+ it "should empty the bulk save cache if no documents are given" do
187
+ @db.save_doc({"_id" => "bulk_cache_1", "val" => "test"}, true)
188
+ lambda do
189
+ @db.get('bulk_cache_1')
190
+ end.should raise_error(RestClient::ResourceNotFound)
191
+ @db.bulk_save
192
+ @db.get("bulk_cache_1")["val"].should == "test"
193
+ end
194
+
195
+ it "should raise an error that is useful for recovery" do
196
+ @r = @db.save_doc({"_id" => "taken", "field" => "stuff"})
197
+ begin
198
+ rs = @db.bulk_save([
199
+ {"_id" => "taken", "wild" => "and random"},
200
+ {"_id" => "free", "mild" => "yet local"},
201
+ {"another" => ["set","of","keys"]}
202
+ ])
203
+ rescue RestClient::RequestFailed => e
204
+ # soon CouchDB will provide _which_ docs conflicted
205
+ Yajl::Parser.parse(e.response.body)['error'].should == 'conflict'
206
+ end
207
+ end
208
+ end
209
+
210
+ describe "new document without an id" do
211
+ it "should start empty" do
212
+ @db.documents["total_rows"].should == 0
213
+ end
214
+ it "should create the document and return the id" do
215
+ r = @db.save_doc({'lemons' => 'from texas', 'and' => 'spain'})
216
+ r2 = @db.get(r['id'])
217
+ r2["lemons"].should == "from texas"
218
+ end
219
+ it "should use PUT with UUIDs" do
220
+ CouchRest.should_receive(:put).and_return({"ok" => true, "id" => "100", "rev" => "55"})
221
+ r = @db.save_doc({'just' => ['another document']})
222
+ end
223
+
224
+ end
225
+
226
+ describe "fetch_attachment" do
227
+ before do
228
+ @attach = "<html><head><title>My Doc</title></head><body><p>Has words.</p></body></html>"
229
+ @doc = {
230
+ "_id" => "mydocwithattachment",
231
+ "field" => ["some value"],
232
+ "_attachments" => {
233
+ "test.html" => {
234
+ "type" => "text/html",
235
+ "data" => @attach
236
+ }
237
+ }
238
+ }
239
+ @db.save_doc(@doc)
240
+ end
241
+
242
+ # Depreacated
243
+ # it "should get the attachment with the doc's _id" do
244
+ # @db.fetch_attachment("mydocwithattachment", "test.html").should == @attach
245
+ # end
246
+
247
+ it "should get the attachment with the doc itself" do
248
+ @db.fetch_attachment(@db.get('mydocwithattachment'), 'test.html').should == @attach
249
+ end
250
+ end
251
+
252
+ describe "PUT attachment from file" do
253
+ before(:each) do
254
+ filename = FIXTURE_PATH + '/attachments/couchdb.png'
255
+ @file = File.open(filename)
256
+ end
257
+ after(:each) do
258
+ @file.close
259
+ end
260
+ it "should save the attachment to a new doc" do
261
+ r = @db.put_attachment({'_id' => 'attach-this'}, 'couchdb.png', image = @file.read, {:content_type => 'image/png'})
262
+ r['ok'].should == true
263
+ doc = @db.get("attach-this")
264
+ attachment = @db.fetch_attachment(doc,"couchdb.png")
265
+ attachment.should == image
266
+ end
267
+ end
268
+
269
+ describe "PUT document with attachment" do
270
+ before(:each) do
271
+ @attach = "<html><head><title>My Doc</title></head><body><p>Has words.</p></body></html>"
272
+ doc = {
273
+ "_id" => "mydocwithattachment",
274
+ "field" => ["some value"],
275
+ "_attachments" => {
276
+ "test.html" => {
277
+ "type" => "text/html",
278
+ "data" => @attach
279
+ }
280
+ }
281
+ }
282
+ @db.save_doc(doc)
283
+ @doc = @db.get("mydocwithattachment")
284
+ end
285
+ it "should save and be indicated" do
286
+ @doc['_attachments']['test.html']['length'].should == @attach.length
287
+ end
288
+ it "should be there" do
289
+ attachment = @db.fetch_attachment(@doc,"test.html")
290
+ attachment.should == @attach
291
+ end
292
+ end
293
+
294
+ describe "PUT document with attachment stub" do
295
+ before(:each) do
296
+ @attach = "<html><head><title>My Doc</title></head><body><p>Has words.</p></body></html>"
297
+ doc = {
298
+ '_id' => 'mydocwithattachment',
299
+ 'field' => ['some_value'],
300
+ '_attachments' => {
301
+ 'test.html' => {
302
+ 'type' => 'text/html', 'data' => @attach
303
+ }
304
+ }
305
+ }
306
+ @db.save_doc(doc)
307
+ doc['_rev'].should_not be_nil
308
+ doc['field'] << 'another value'
309
+ @db.save_doc(doc)["ok"].should be_true
310
+ end
311
+
312
+ it 'should be there' do
313
+ doc = @db.get('mydocwithattachment')
314
+ attachment = @db.fetch_attachment(doc, 'test.html')
315
+ Base64.decode64(attachment).should == @attach
316
+ end
317
+ end
318
+
319
+ describe "PUT document with multiple attachments" do
320
+ before(:each) do
321
+ @attach = "<html><head><title>My Doc</title></head><body><p>Has words.</p></body></html>"
322
+ @attach2 = "<html><head><title>Other Doc</title></head><body><p>Has more words.</p></body></html>"
323
+ @doc = {
324
+ "_id" => "mydocwithattachment",
325
+ "field" => ["some value"],
326
+ "_attachments" => {
327
+ "test.html" => {
328
+ "type" => "text/html",
329
+ "data" => @attach
330
+ },
331
+ "other.html" => {
332
+ "type" => "text/html",
333
+ "data" => @attach2
334
+ }
335
+ }
336
+ }
337
+ @db.save_doc(@doc)
338
+ @doc = @db.get("mydocwithattachment")
339
+ end
340
+ it "should save and be indicated" do
341
+ @doc['_attachments']['test.html']['length'].should == @attach.length
342
+ @doc['_attachments']['other.html']['length'].should == @attach2.length
343
+ end
344
+ it "should be there" do
345
+ attachment = @db.fetch_attachment(@doc,"test.html")
346
+ attachment.should == @attach
347
+ end
348
+ it "should be there" do
349
+ attachment = @db.fetch_attachment(@doc,"other.html")
350
+ attachment.should == @attach2
351
+ end
352
+ end
353
+
354
+ describe "DELETE an attachment directly from the database" do
355
+ before(:each) do
356
+ doc = {
357
+ '_id' => 'mydocwithattachment',
358
+ '_attachments' => {
359
+ 'test.html' => {
360
+ 'type' => 'text/html',
361
+ 'data' => "<html><head><title>My Doc</title></head><body><p>Has words.</p></body></html>"
362
+ }
363
+ }
364
+ }
365
+ @db.save_doc(doc)
366
+ @doc = @db.get('mydocwithattachment')
367
+ end
368
+ it "should delete the attachment" do
369
+ lambda { @db.fetch_attachment(@doc,'test.html') }.should_not raise_error
370
+ @db.delete_attachment(@doc, "test.html")
371
+ lambda { @db.fetch_attachment(@doc,'test.html') }.should raise_error(RestClient::ResourceNotFound)
372
+ end
373
+ end
374
+
375
+ describe "POST document with attachment (with funky name)" do
376
+ before(:each) do
377
+ @attach = "<html><head><title>My Funky Doc</title></head><body><p>Has words.</p></body></html>"
378
+ @doc = {
379
+ "field" => ["some other value"],
380
+ "_attachments" => {
381
+ "http://example.com/stuff.cgi?things=and%20stuff" => {
382
+ "type" => "text/html",
383
+ "data" => @attach
384
+ }
385
+ }
386
+ }
387
+ @docid = @db.save_doc(@doc)['id']
388
+ end
389
+ it "should save and be indicated" do
390
+ doc = @db.get(@docid)
391
+ doc['_attachments']['http://example.com/stuff.cgi?things=and%20stuff']['length'].should == @attach.length
392
+ end
393
+ it "should be there" do
394
+ doc = @db.get(@docid)
395
+ attachment = @db.fetch_attachment(doc,"http://example.com/stuff.cgi?things=and%20stuff")
396
+ attachment.should == @attach
397
+ end
398
+ end
399
+
400
+ describe "PUT (new document with url id)" do
401
+ it "should create the document" do
402
+ @docid = "http://example.com/stuff.cgi?things=and%20stuff"
403
+ @db.save_doc({'_id' => @docid, 'will-exist' => 'here'})
404
+ lambda{@db.save_doc({'_id' => @docid})}.should raise_error(RestClient::Request::RequestFailed)
405
+ @db.get(@docid)['will-exist'].should == 'here'
406
+ end
407
+ end
408
+
409
+ describe "PUT (new document with id)" do
410
+ it "should start without the document" do
411
+ # r = @db.save_doc({'lemons' => 'from texas', 'and' => 'spain'})
412
+ @db.documents['rows'].each do |doc|
413
+ doc['id'].should_not == 'my-doc'
414
+ end
415
+ # should_not include({'_id' => 'my-doc'})
416
+ # this needs to be a loop over docs on content with the post
417
+ # or instead make it return something with a fancy <=> method
418
+ end
419
+ it "should create the document" do
420
+ @db.save_doc({'_id' => 'my-doc', 'will-exist' => 'here'})
421
+ lambda{@db.save_doc({'_id' => 'my-doc'})}.should raise_error(RestClient::Request::RequestFailed)
422
+ end
423
+ end
424
+
425
+ describe "PUT (existing document with rev)" do
426
+ before(:each) do
427
+ @db.save_doc({'_id' => 'my-doc', 'will-exist' => 'here'})
428
+ @doc = @db.get('my-doc')
429
+ @docid = "http://example.com/stuff.cgi?things=and%20stuff"
430
+ @db.save_doc({'_id' => @docid, 'now' => 'save'})
431
+ end
432
+ it "should start with the document" do
433
+ @doc['will-exist'].should == 'here'
434
+ @db.get(@docid)['now'].should == 'save'
435
+ end
436
+ it "should save with url id" do
437
+ doc = @db.get(@docid)
438
+ doc['yaml'] = ['json', 'word.']
439
+ @db.save_doc doc
440
+ @db.get(@docid)['yaml'].should == ['json', 'word.']
441
+ end
442
+ it "should fail to resave without the rev" do
443
+ @doc['them-keys'] = 'huge'
444
+ @doc['_rev'] = 'wrong'
445
+ # @db.save_doc(@doc)
446
+ lambda {@db.save_doc(@doc)}.should raise_error
447
+ end
448
+ it "should update the document" do
449
+ @doc['them-keys'] = 'huge'
450
+ @db.save_doc(@doc)
451
+ now = @db.get('my-doc')
452
+ now['them-keys'].should == 'huge'
453
+ end
454
+ end
455
+
456
+ describe "cached bulk save" do
457
+ it "stores documents in a database-specific cache" do
458
+ td = {"_id" => "btd1", "val" => "test"}
459
+ @db.save_doc(td, true)
460
+ @db.instance_variable_get("@bulk_save_cache").should == [td]
461
+
462
+ end
463
+
464
+ it "doesn't save to the database until the configured cache size is exceded" do
465
+ @db.bulk_save_cache_limit = 3
466
+ td1 = {"_id" => "td1", "val" => true}
467
+ td2 = {"_id" => "td2", "val" => 4}
468
+ @db.save_doc(td1, true)
469
+ @db.save_doc(td2, true)
470
+ lambda do
471
+ @db.get(td1["_id"])
472
+ end.should raise_error(RestClient::ResourceNotFound)
473
+ lambda do
474
+ @db.get(td2["_id"])
475
+ end.should raise_error(RestClient::ResourceNotFound)
476
+ td3 = {"_id" => "td3", "val" => "foo"}
477
+ @db.save_doc(td3, true)
478
+ @db.get(td1["_id"])["val"].should == td1["val"]
479
+ @db.get(td2["_id"])["val"].should == td2["val"]
480
+ @db.get(td3["_id"])["val"].should == td3["val"]
481
+ end
482
+
483
+ it "clears the bulk save cache the first time a non bulk save is requested" do
484
+ td1 = {"_id" => "blah", "val" => true}
485
+ td2 = {"_id" => "steve", "val" => 3}
486
+ @db.bulk_save_cache_limit = 50
487
+ @db.save_doc(td1, true)
488
+ lambda do
489
+ @db.get(td1["_id"])
490
+ end.should raise_error(RestClient::ResourceNotFound)
491
+ @db.save_doc(td2)
492
+ @db.get(td1["_id"])["val"].should == td1["val"]
493
+ @db.get(td2["_id"])["val"].should == td2["val"]
494
+ end
495
+ end
496
+
497
+ describe "DELETE existing document" do
498
+ before(:each) do
499
+ @r = @db.save_doc({'lemons' => 'from texas', 'and' => 'spain'})
500
+ @docid = "http://example.com/stuff.cgi?things=and%20stuff"
501
+ @db.save_doc({'_id' => @docid, 'will-exist' => 'here'})
502
+ end
503
+ it "should work" do
504
+ doc = @db.get(@r['id'])
505
+ doc['and'].should == 'spain'
506
+ @db.delete_doc doc
507
+ lambda{@db.get @r['id']}.should raise_error
508
+ end
509
+ it "should work with uri id" do
510
+ doc = @db.get(@docid)
511
+ @db.delete_doc doc
512
+ lambda{@db.get @docid}.should raise_error
513
+ end
514
+ it "should fail without an _id" do
515
+ lambda{@db.delete_doc({"not"=>"a real doc"})}.should raise_error(ArgumentError)
516
+ end
517
+ it "should defer actual deletion when using bulk save" do
518
+ doc = @db.get(@docid)
519
+ @db.delete_doc doc, true
520
+ lambda{@db.get @docid}.should_not raise_error
521
+ @db.bulk_save
522
+ lambda{@db.get @docid}.should raise_error
523
+ end
524
+
525
+ end
526
+
527
+ describe "COPY existing document" do
528
+ before :each do
529
+ @r = @db.save_doc({'artist' => 'Zappa', 'title' => 'Muffin Man'})
530
+ @docid = 'tracks/zappa/muffin-man'
531
+ @doc = @db.get(@r['id'])
532
+ end
533
+ describe "to a new location" do
534
+ it "should work" do
535
+ @db.copy_doc @doc, @docid
536
+ newdoc = @db.get(@docid)
537
+ newdoc['artist'].should == 'Zappa'
538
+ end
539
+ it "should fail without an _id" do
540
+ lambda{@db.copy({"not"=>"a real doc"})}.should raise_error(ArgumentError)
541
+ end
542
+ end
543
+ describe "to an existing location" do
544
+ before :each do
545
+ @db.save_doc({'_id' => @docid, 'will-exist' => 'here'})
546
+ end
547
+ it "should fail without a rev" do
548
+ lambda{@db.copy_doc @doc, @docid}.should raise_error(RestClient::RequestFailed)
549
+ end
550
+ it "should succeed with a rev" do
551
+ @to_be_overwritten = @db.get(@docid)
552
+ @db.copy_doc @doc, "#{@docid}?rev=#{@to_be_overwritten['_rev']}"
553
+ newdoc = @db.get(@docid)
554
+ newdoc['artist'].should == 'Zappa'
555
+ end
556
+ it "should succeed given the doc to overwrite" do
557
+ @to_be_overwritten = @db.get(@docid)
558
+ @db.copy_doc @doc, @to_be_overwritten
559
+ newdoc = @db.get(@docid)
560
+ newdoc['artist'].should == 'Zappa'
561
+ end
562
+ end
563
+ end
564
+
565
+
566
+ it "should list documents" do
567
+ 5.times do
568
+ @db.save_doc({'another' => 'doc', 'will-exist' => 'anywhere'})
569
+ end
570
+ ds = @db.documents
571
+ ds['rows'].should be_an_instance_of(Array)
572
+ ds['rows'][0]['id'].should_not be_nil
573
+ ds['total_rows'].should == 5
574
+ end
575
+
576
+ describe "documents / _all_docs" do
577
+ before(:each) do
578
+ 9.times do |i|
579
+ @db.save_doc({'_id' => "doc#{i}",'another' => 'doc', 'will-exist' => 'here'})
580
+ end
581
+ end
582
+ it "should list documents with keys and such" do
583
+ ds = @db.documents
584
+ ds['rows'].should be_an_instance_of(Array)
585
+ ds['rows'][0]['id'].should == "doc0"
586
+ ds['total_rows'].should == 9
587
+ end
588
+ it "should take query params" do
589
+ ds = @db.documents(:startkey => 'doc0', :endkey => 'doc3')
590
+ ds['rows'].length.should == 4
591
+ ds = @db.documents(:key => 'doc0')
592
+ ds['rows'].length.should == 1
593
+ end
594
+ it "should work with multi-key" do
595
+ rs = @db.documents :keys => ["doc0", "doc7"]
596
+ rs['rows'].length.should == 2
597
+ end
598
+ it "should work with include_docs" do
599
+ ds = @db.documents(:startkey => 'doc0', :endkey => 'doc3', :include_docs => true)
600
+ ds['rows'][0]['doc']['another'].should == "doc"
601
+ end
602
+ it "should have the bulk_load macro" do
603
+ rs = @db.bulk_load ["doc0", "doc7"]
604
+ rs['rows'].length.should == 2
605
+ ds['rows'][0]['doc']['another'].should == "doc"
606
+ end
607
+ end
608
+
609
+
610
+ describe "compacting a database" do
611
+ it "should compact the database" do
612
+ db = @cr.database('couchrest-test')
613
+ # r =
614
+ db.compact!
615
+ # r['ok'].should == true
616
+ end
617
+ end
618
+
619
+ describe "deleting a database" do
620
+ it "should start with the test database" do
621
+ @cr.databases.should include('couchrest-test')
622
+ end
623
+ it "should delete the database" do
624
+ db = @cr.database('couchrest-test')
625
+ # r =
626
+ db.delete!
627
+ # r['ok'].should == true
628
+ @cr.databases.should_not include('couchrest-test')
629
+ end
630
+ end
631
+
632
+ describe "replicating a database" do
633
+ before do
634
+ @db.save_doc({'_id' => 'test_doc', 'some-value' => 'foo'})
635
+ @other_db = @cr.database 'couchrest-test-replication'
636
+ @other_db.delete! rescue nil
637
+ @other_db = @cr.create_db 'couchrest-test-replication'
638
+ end
639
+
640
+ describe "via pulling" do
641
+ before do
642
+ @other_db.replicate_from @db
643
+ end
644
+
645
+ it "contains the document from the original database" do
646
+ doc = @other_db.get('test_doc')
647
+ doc['some-value'].should == 'foo'
648
+ end
649
+ end
650
+
651
+ describe "via pushing" do
652
+ before do
653
+ @db.replicate_to @other_db
654
+ end
655
+
656
+ it "copies the document to the other database" do
657
+ doc = @other_db.get('test_doc')
658
+ doc['some-value'].should == 'foo'
659
+ end
660
+ end
661
+ end
662
+
663
+ describe "creating a database" do
664
+ before(:each) do
665
+ @db = @cr.database('couchrest-test-db_to_create')
666
+ @db.delete! if @cr.databases.include?('couchrest-test-db_to_create')
667
+ end
668
+
669
+ it "should just work fine" do
670
+ @cr.databases.should_not include('couchrest-test-db_to_create')
671
+ @db.create!
672
+ @cr.databases.should include('couchrest-test-db_to_create')
673
+ end
674
+ end
675
+
676
+ describe "recreating a database" do
677
+ before(:each) do
678
+ @db = @cr.database('couchrest-test-db_to_create')
679
+ @db2 = @cr.database('couchrest-test-db_to_recreate')
680
+ @cr.databases.include?(@db.name) ? nil : @db.create!
681
+ @cr.databases.include?(@db2.name) ? @db2.delete! : nil
682
+ end
683
+
684
+ it "should drop and recreate a database" do
685
+ @cr.databases.should include(@db.name)
686
+ @db.recreate!
687
+ @cr.databases.should include(@db.name)
688
+ end
689
+
690
+ it "should recreate a db even tho it doesn't exist" do
691
+ @cr.databases.should_not include(@db2.name)
692
+ @db2.recreate!
693
+ @cr.databases.should include(@db2.name)
694
+ end
695
+
696
+ end
697
+
698
+
699
+ end