jrun-couchrest 0.2.1

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