topfunky-couchrest 0.9.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (40) hide show
  1. data/LICENSE +176 -0
  2. data/README.rdoc +51 -0
  3. data/Rakefile +87 -0
  4. data/THANKS +15 -0
  5. data/bin/couchdir +20 -0
  6. data/bin/couchview +48 -0
  7. data/examples/word_count/markov +38 -0
  8. data/examples/word_count/views/books/chunked-map.js +3 -0
  9. data/examples/word_count/views/books/united-map.js +1 -0
  10. data/examples/word_count/views/markov/chain-map.js +6 -0
  11. data/examples/word_count/views/markov/chain-reduce.js +7 -0
  12. data/examples/word_count/views/word_count/count-map.js +6 -0
  13. data/examples/word_count/views/word_count/count-reduce.js +3 -0
  14. data/examples/word_count/word_count.rb +67 -0
  15. data/examples/word_count/word_count_query.rb +39 -0
  16. data/lib/couchrest.rb +92 -0
  17. data/lib/couchrest/commands/generate.rb +71 -0
  18. data/lib/couchrest/commands/push.rb +99 -0
  19. data/lib/couchrest/core/database.rb +105 -0
  20. data/lib/couchrest/core/server.rb +49 -0
  21. data/lib/couchrest/helper/file_manager.rb +223 -0
  22. data/lib/couchrest/helper/pager.rb +103 -0
  23. data/lib/couchrest/helper/streamer.rb +29 -0
  24. data/lib/couchrest/monkeypatches.rb +22 -0
  25. data/spec/couchrest_spec.rb +92 -0
  26. data/spec/database_spec.rb +429 -0
  27. data/spec/file_manager_spec.rb +116 -0
  28. data/spec/fixtures/attachments/test.html +11 -0
  29. data/spec/fixtures/views/lib.js +3 -0
  30. data/spec/fixtures/views/test_view/lib.js +3 -0
  31. data/spec/fixtures/views/test_view/only-map.js +4 -0
  32. data/spec/fixtures/views/test_view/test-map.js +3 -0
  33. data/spec/fixtures/views/test_view/test-reduce.js +3 -0
  34. data/spec/pager_spec.rb +122 -0
  35. data/spec/spec.opts +6 -0
  36. data/spec/spec_helper.rb +4 -0
  37. data/spec/streamer_spec.rb +23 -0
  38. data/utils/remap.rb +27 -0
  39. data/utils/subset.rb +30 -0
  40. metadata +124 -0
@@ -0,0 +1,429 @@
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 count" do
33
+ rs = @db.temp_view(@temp_view,{:count => 1})
34
+ rs['rows'].length.should == 1
35
+ end
36
+ end
37
+
38
+ describe "map/reduce query with _temp_view in Javascript" do
39
+ before(:each) do
40
+ @db.bulk_save([
41
+ {"beverage" => "beer", :count => 4},
42
+ {"beverage" => "beer", :count => 2},
43
+ {"beverage" => "tea", :count => 3}
44
+ ])
45
+ end
46
+ it "should return the result of the temporary function" do
47
+ rs = @db.temp_view(:map => "function(doc){emit(doc.beverage, doc.count)}", :reduce => "function(beverage,counts){return sum(counts)}")
48
+ # rs.should == 'x'
49
+ rs['rows'][0]['value'].should == 9
50
+ end
51
+ end
52
+
53
+ describe "saving a view" do
54
+ before(:each) do
55
+ @view = {'test' => {'map' => 'function(doc) {
56
+ if (doc.word && !/\W/.test(doc.word)) {
57
+ emit(doc.word,null);
58
+ }
59
+ }'}}
60
+ @db.save({
61
+ "_id" => "_design/test",
62
+ :views => @view
63
+ })
64
+ end
65
+ it "should work properly" do
66
+ @db.bulk_save([
67
+ {"word" => "once"},
68
+ {"word" => "and again"}
69
+ ])
70
+ @db.view('test/test')['total_rows'].should == 1
71
+ end
72
+ it "should round trip" do
73
+ @db.get("_design/test")['views'].should == @view
74
+ end
75
+ end
76
+
77
+ describe "select from an existing view" do
78
+ before(:each) do
79
+ r = @db.save({
80
+ "_id" => "_design/first",
81
+ :views => {
82
+ :test => {
83
+ :map => "function(doc){for(var w in doc){ if(!w.match(/^_/))emit(w,doc[w])}}"
84
+ }
85
+ }
86
+ })
87
+ @db.bulk_save([
88
+ {"wild" => "and random"},
89
+ {"mild" => "yet local"},
90
+ {"another" => ["set","of","keys"]}
91
+ ])
92
+ end
93
+ it "should have the view" do
94
+ @db.get('_design/first')['views']['test']['map'].should include("for(var w in doc)")
95
+ end
96
+ it "should list from the view" do
97
+ rs = @db.view('first/test')
98
+ rs['rows'].select{|r|r['key'] == 'wild' && r['value'] == 'and random'}.length.should == 1
99
+ end
100
+ it "should work with a range" do
101
+ rs = @db.view('first/test',{:startkey => "b", :endkey => "z"})
102
+ rs['rows'].length.should == 2
103
+ end
104
+ it "should work with a key" do
105
+ rs = @db.view('first/test',{:key => "wild"})
106
+ rs['rows'].length.should == 1
107
+ end
108
+ it "should work with a count" do
109
+ rs = @db.view('first/test',{:count => 1})
110
+ rs['rows'].length.should == 1
111
+ end
112
+ end
113
+
114
+ describe "GET (document by id) when the doc exists" do
115
+ before(:each) do
116
+ @r = @db.save({'lemons' => 'from texas', 'and' => 'spain'})
117
+ @docid = "http://example.com/stuff.cgi?things=and%20stuff"
118
+ @db.save({'_id' => @docid, 'will-exist' => 'here'})
119
+ end
120
+ it "should get the document" do
121
+ doc = @db.get(@r['id'])
122
+ doc['lemons'].should == 'from texas'
123
+ end
124
+ it "should work with a funky id" do
125
+ @db.get(@docid)['will-exist'].should == 'here'
126
+ end
127
+ end
128
+
129
+ describe "POST (adding bulk documents)" do
130
+ it "should add them without ids" do
131
+ rs = @db.bulk_save([
132
+ {"wild" => "and random"},
133
+ {"mild" => "yet local"},
134
+ {"another" => ["set","of","keys"]}
135
+ ])
136
+ rs['new_revs'].each do |r|
137
+ @db.get(r['id'])
138
+ end
139
+ end
140
+
141
+ it "should use uuids when ids aren't provided" do
142
+ @db.server.stub!(:next_uuid).and_return('asdf6sgadkfhgsdfusdf')
143
+
144
+ docs = [{'key' => 'value'}, {'_id' => 'totally-uniq'}]
145
+ id_docs = [{'key' => 'value', '_id' => 'asdf6sgadkfhgsdfusdf'}, {'_id' => 'totally-uniq'}]
146
+ CouchRest.should_receive(:post).with("http://localhost:5984/couchrest-test/_bulk_docs", {:docs => id_docs})
147
+
148
+ @db.bulk_save(docs)
149
+ end
150
+
151
+ it "should add them with uniq ids" do
152
+ rs = @db.bulk_save([
153
+ {"_id" => "oneB", "wild" => "and random"},
154
+ {"_id" => "twoB", "mild" => "yet local"},
155
+ {"another" => ["set","of","keys"]}
156
+ ])
157
+ rs['new_revs'].each do |r|
158
+ @db.get(r['id'])
159
+ end
160
+ end
161
+
162
+ it "in the case of an id conflict should not insert anything" do
163
+ @r = @db.save({'lemons' => 'from texas', 'and' => 'how', "_id" => "oneB"})
164
+
165
+ lambda do
166
+ rs = @db.bulk_save([
167
+ {"_id" => "oneB", "wild" => "and random"},
168
+ {"_id" => "twoB", "mild" => "yet local"},
169
+ {"another" => ["set","of","keys"]}
170
+ ])
171
+ end.should raise_error(RestClient::RequestFailed)
172
+
173
+ lambda do
174
+ @db.get('twoB')
175
+ end.should raise_error(RestClient::ResourceNotFound)
176
+ end
177
+ it "should raise an error that is useful for recovery" do
178
+ @r = @db.save({"_id" => "taken", "field" => "stuff"})
179
+ begin
180
+ rs = @db.bulk_save([
181
+ {"_id" => "taken", "wild" => "and random"},
182
+ {"_id" => "free", "mild" => "yet local"},
183
+ {"another" => ["set","of","keys"]}
184
+ ])
185
+ rescue RestClient::RequestFailed => e
186
+ # soon CouchDB will provide _which_ docs conflicted
187
+ JSON.parse(e.response.body)['error'].should == 'conflict'
188
+ end
189
+ end
190
+ end
191
+
192
+ describe "new document without an id" do
193
+ it "should start empty" do
194
+ @db.documents["total_rows"].should == 0
195
+ end
196
+ it "should create the document and return the id" do
197
+ r = @db.save({'lemons' => 'from texas', 'and' => 'spain'})
198
+ r2 = @db.get(r['id'])
199
+ r2["lemons"].should == "from texas"
200
+ end
201
+ it "should use PUT with UUIDs" do
202
+ CouchRest.should_receive(:put)
203
+ r = @db.save({'just' => ['another document']})
204
+ end
205
+
206
+ end
207
+
208
+ describe "PUT document with attachment" do
209
+ before(:each) do
210
+ @attach = "<html><head><title>My Doc</title></head><body><p>Has words.</p></body></html>"
211
+ @doc = {
212
+ "_id" => "mydocwithattachment",
213
+ "field" => ["some value"],
214
+ "_attachments" => {
215
+ "test.html" => {
216
+ "type" => "text/html",
217
+ "data" => @attach
218
+ }
219
+ }
220
+ }
221
+ @db.save(@doc)
222
+ end
223
+ it "should save and be indicated" do
224
+ doc = @db.get("mydocwithattachment")
225
+ doc['_attachments']['test.html']['length'].should == @attach.length
226
+ end
227
+ it "should be there" do
228
+ attachment = @db.fetch_attachment("mydocwithattachment","test.html")
229
+ attachment.should == @attach
230
+ end
231
+ end
232
+
233
+ describe "PUT document with attachment stub" do
234
+ before(:each) do
235
+ @attach = "<html><head><title>My Doc</title></head><body><p>Has words.</p></body></html>"
236
+ doc = {
237
+ '_id' => 'mydocwithattachment',
238
+ 'field' => ['some_value'],
239
+ '_attachments' => {
240
+ 'test.html' => {
241
+ 'type' => 'text/html', 'data' => @attach
242
+ }
243
+ }
244
+ }
245
+ @db.save(doc)
246
+ doc = @db.get('mydocwithattachment')
247
+ doc['field'] << 'another value'
248
+ @db.save(doc)
249
+ end
250
+
251
+ it 'should be there' do
252
+ attachment = @db.fetch_attachment('mydocwithattachment', 'test.html')
253
+ attachment.should == @attach
254
+ end
255
+ end
256
+
257
+ describe "PUT document with multiple attachments" do
258
+ before(:each) do
259
+ @attach = "<html><head><title>My Doc</title></head><body><p>Has words.</p></body></html>"
260
+ @attach2 = "<html><head><title>Other Doc</title></head><body><p>Has more words.</p></body></html>"
261
+ @doc = {
262
+ "_id" => "mydocwithattachment",
263
+ "field" => ["some value"],
264
+ "_attachments" => {
265
+ "test.html" => {
266
+ "type" => "text/html",
267
+ "data" => @attach
268
+ },
269
+ "other.html" => {
270
+ "type" => "text/html",
271
+ "data" => @attach2
272
+ }
273
+ }
274
+ }
275
+ @db.save(@doc)
276
+ end
277
+ it "should save and be indicated" do
278
+ doc = @db.get("mydocwithattachment")
279
+ doc['_attachments']['test.html']['length'].should == @attach.length
280
+ doc['_attachments']['other.html']['length'].should == @attach2.length
281
+ end
282
+ it "should be there" do
283
+ attachment = @db.fetch_attachment("mydocwithattachment","test.html")
284
+ attachment.should == @attach
285
+ end
286
+ it "should be there" do
287
+ attachment = @db.fetch_attachment("mydocwithattachment","other.html")
288
+ attachment.should == @attach2
289
+ end
290
+ end
291
+
292
+ describe "POST document with attachment (with funky name)" do
293
+ before(:each) do
294
+ @attach = "<html><head><title>My Funky Doc</title></head><body><p>Has words.</p></body></html>"
295
+ @doc = {
296
+ "field" => ["some other value"],
297
+ "_attachments" => {
298
+ "http://example.com/stuff.cgi?things=and%20stuff" => {
299
+ "type" => "text/html",
300
+ "data" => @attach
301
+ }
302
+ }
303
+ }
304
+ @docid = @db.save(@doc)['id']
305
+ end
306
+ it "should save and be indicated" do
307
+ doc = @db.get(@docid)
308
+ doc['_attachments']['http://example.com/stuff.cgi?things=and%20stuff']['length'].should == @attach.length
309
+ end
310
+ it "should be there" do
311
+ attachment = @db.fetch_attachment(@docid,"http://example.com/stuff.cgi?things=and%20stuff")
312
+ attachment.should == @attach
313
+ end
314
+ end
315
+
316
+ describe "PUT (new document with url id)" do
317
+ it "should create the document" do
318
+ @docid = "http://example.com/stuff.cgi?things=and%20stuff"
319
+ @db.save({'_id' => @docid, 'will-exist' => 'here'})
320
+ lambda{@db.save({'_id' => @docid})}.should raise_error(RestClient::Request::RequestFailed)
321
+ @db.get(@docid)['will-exist'].should == 'here'
322
+ end
323
+ end
324
+
325
+ describe "PUT (new document with id)" do
326
+ it "should start without the document" do
327
+ # r = @db.save({'lemons' => 'from texas', 'and' => 'spain'})
328
+ @db.documents['rows'].each do |doc|
329
+ doc['id'].should_not == 'my-doc'
330
+ end
331
+ # should_not include({'_id' => 'my-doc'})
332
+ # this needs to be a loop over docs on content with the post
333
+ # or instead make it return something with a fancy <=> method
334
+ end
335
+ it "should create the document" do
336
+ @db.save({'_id' => 'my-doc', 'will-exist' => 'here'})
337
+ lambda{@db.save({'_id' => 'my-doc'})}.should raise_error(RestClient::Request::RequestFailed)
338
+ end
339
+ end
340
+
341
+ describe "PUT (existing document with rev)" do
342
+ before(:each) do
343
+ @db.save({'_id' => 'my-doc', 'will-exist' => 'here'})
344
+ @doc = @db.get('my-doc')
345
+ @docid = "http://example.com/stuff.cgi?things=and%20stuff"
346
+ @db.save({'_id' => @docid, 'now' => 'save'})
347
+ end
348
+ it "should start with the document" do
349
+ @doc['will-exist'].should == 'here'
350
+ @db.get(@docid)['now'].should == 'save'
351
+ end
352
+ it "should save with url id" do
353
+ doc = @db.get(@docid)
354
+ doc['yaml'] = ['json', 'word.']
355
+ @db.save doc
356
+ @db.get(@docid)['yaml'].should == ['json', 'word.']
357
+ end
358
+ it "should fail to resave without the rev" do
359
+ @doc['them-keys'] = 'huge'
360
+ @doc['_rev'] = 'wrong'
361
+ # @db.save(@doc)
362
+ lambda {@db.save(@doc)}.should raise_error
363
+ end
364
+ it "should update the document" do
365
+ @doc['them-keys'] = 'huge'
366
+ @db.save(@doc)
367
+ now = @db.get('my-doc')
368
+ now['them-keys'].should == 'huge'
369
+ end
370
+ end
371
+
372
+ describe "DELETE existing document" do
373
+ before(:each) do
374
+ @r = @db.save({'lemons' => 'from texas', 'and' => 'spain'})
375
+ @docid = "http://example.com/stuff.cgi?things=and%20stuff"
376
+ @db.save({'_id' => @docid, 'will-exist' => 'here'})
377
+ end
378
+ it "should work" do
379
+ doc = @db.get(@r['id'])
380
+ doc['and'].should == 'spain'
381
+ @db.delete doc
382
+ lambda{@db.get @r['id']}.should raise_error
383
+ end
384
+ it "should work with uri id" do
385
+ doc = @db.get(@docid)
386
+ @db.delete doc
387
+ lambda{@db.get @docid}.should raise_error
388
+ end
389
+ end
390
+
391
+ it "should list documents" do
392
+ 5.times do
393
+ @db.save({'another' => 'doc', 'will-exist' => 'anywhere'})
394
+ end
395
+ ds = @db.documents
396
+ ds['rows'].should be_an_instance_of(Array)
397
+ ds['rows'][0]['id'].should_not be_nil
398
+ ds['total_rows'].should == 5
399
+ end
400
+
401
+ it "should list documents with keys and such" do
402
+ 9.times do |i|
403
+ @db.save({'_id' => "doc#{i}",'another' => 'doc', 'will-exist' => 'here'})
404
+ end
405
+ ds = @db.documents
406
+ ds['rows'].should be_an_instance_of(Array)
407
+ ds['rows'][0]['id'].should == "doc0"
408
+ ds['total_rows'].should == 9
409
+ ds = @db.documents(:startkey => 'doc0', :endkey => 'doc3')
410
+ ds['rows'].length.should == 4
411
+ ds = @db.documents(:key => 'doc0')
412
+ ds['rows'].length.should == 1
413
+ end
414
+
415
+ describe "deleting a database" do
416
+ it "should start with the test database" do
417
+ @cr.databases.should include('couchrest-test')
418
+ end
419
+ it "should delete the database" do
420
+ db = @cr.database('couchrest-test')
421
+ # r =
422
+ db.delete!
423
+ # r['ok'].should == true
424
+ @cr.databases.should_not include('couchrest-test')
425
+ end
426
+ end
427
+
428
+
429
+ end
@@ -0,0 +1,116 @@
1
+ require File.dirname(__FILE__) + '/spec_helper'
2
+
3
+ describe CouchRest::FileManager do
4
+ before(:all) 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
+ it "should initialize" do
11
+ @fm = CouchRest::FileManager.new(TESTDB)
12
+ @fm.should_not be_nil
13
+ end
14
+ it "should require a db name" do
15
+ lambda{CouchRest::FileManager.new}.should raise_error
16
+ end
17
+ it "should accept a db name" do
18
+ @fm = CouchRest::FileManager.new(TESTDB, 'http://localhost')
19
+ @fm.db.name.should == TESTDB
20
+ end
21
+ it "should default to localhost couchdb" do
22
+ @fm = CouchRest::FileManager.new(TESTDB)
23
+ @fm.db.host.should == 'http://localhost:5984'
24
+ end
25
+ end
26
+
27
+ describe CouchRest::FileManager, "pushing views" do
28
+ before(:all) do
29
+ @cr = CouchRest.new(COUCHHOST)
30
+ @db = @cr.database(TESTDB)
31
+ @db.delete! rescue nil
32
+ @db = @cr.create_db(TESTDB) rescue nil
33
+
34
+ @fm = CouchRest::FileManager.new(TESTDB, COUCHHOST)
35
+ @view_dir = File.dirname(__FILE__) + '/fixtures/views'
36
+ ds = @fm.push_views(@view_dir)
37
+ @design = @db.get("_design/test_view")
38
+ end
39
+ it "should create a design document for each folder" do
40
+ @design["views"].should_not be_nil
41
+ end
42
+ it "should push a map and reduce view" do
43
+ @design["views"]["test-map"].should_not be_nil
44
+ @design["views"]["test-reduce"].should_not be_nil
45
+ end
46
+ it "should push a map only view" do
47
+ @design["views"]["only-map"].should_not be_nil
48
+ @design["views"]["only-reduce"].should be_nil
49
+ end
50
+ it "should include library files" do
51
+ @design["views"]["only-map"]["map"].should include("globalLib")
52
+ @design["views"]["only-map"]["map"].should include("justThisView")
53
+ end
54
+ it "should not create extra design docs" do
55
+ docs = @db.documents(:startkey => '_design', :endkey => '_design/ZZZZZZ')
56
+ docs['total_rows'].should == 1
57
+ end
58
+ end
59
+
60
+ describe CouchRest::FileManager, "pushing a directory with id" do
61
+ before(:all) do
62
+ @cr = CouchRest.new(COUCHHOST)
63
+ @db = @cr.database(TESTDB)
64
+ @db.delete! rescue nil
65
+ @db = @cr.create_db(TESTDB) rescue nil
66
+
67
+ @fm = CouchRest::FileManager.new(TESTDB, COUCHHOST)
68
+ @push_dir = File.dirname(__FILE__) + '/fixtures/attachments'
69
+ ds = @fm.push_directory(@push_dir, 'attached')
70
+ end
71
+ it "should create a document for the folder" do
72
+ @db.get("attached")
73
+ end
74
+ it "should make attachments" do
75
+ doc = @db.get("attached")
76
+ doc["_attachments"]["test.html"].should_not be_nil
77
+ end
78
+ it "should set the content type" do
79
+ doc = @db.get("attached")
80
+ doc["_attachments"]["test.html"]["content_type"].should == "text/html"
81
+ end
82
+ end
83
+
84
+ describe CouchRest::FileManager, "pushing a directory without id" do
85
+ before(:all) do
86
+ @cr = CouchRest.new(COUCHHOST)
87
+ @db = @cr.database(TESTDB)
88
+ @db.delete! rescue nil
89
+ @db = @cr.create_db(TESTDB) rescue nil
90
+
91
+ @fm = CouchRest::FileManager.new(TESTDB, COUCHHOST)
92
+ @push_dir = File.dirname(__FILE__) + '/fixtures/attachments'
93
+ ds = @fm.push_directory(@push_dir)
94
+ end
95
+ it "should use the dirname" do
96
+ doc = @db.get("attachments")
97
+ doc["_attachments"]["test.html"].should_not be_nil
98
+ end
99
+ end
100
+
101
+ describe CouchRest::FileManager, "pushing a directory/ without id" do
102
+ before(:all) do
103
+ @cr = CouchRest.new(COUCHHOST)
104
+ @db = @cr.database(TESTDB)
105
+ @db.delete! rescue nil
106
+ @db = @cr.create_db(TESTDB) rescue nil
107
+
108
+ @fm = CouchRest::FileManager.new(TESTDB, COUCHHOST)
109
+ @push_dir = File.dirname(__FILE__) + '/fixtures/attachments/'
110
+ ds = @fm.push_directory(@push_dir)
111
+ end
112
+ it "should use the dirname" do
113
+ doc = @db.get("attachments")
114
+ doc["_attachments"]["test.html"].should_not be_nil
115
+ end
116
+ end