derfred-couchrest 0.12.6

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