couch-db 0.11.1 → 1.0.0

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.
@@ -1,410 +1,413 @@
1
- require 'couch/db/version'
2
- require 'net/http'
3
- require 'json'
4
- require 'objspace'
5
- require 'openssl'
6
-
7
- class Hash
8
- def include_symbol_or_string?(param)
9
- if param.is_a? Symbol or param.is_a? String
10
- include? param.to_sym or include? param.to_s
11
- else
12
- false
13
- end
14
- end
15
- end
16
-
17
- module Couch
18
- module BasicRequest
19
- def create_postfix(query_params, default='')
20
- if query_params
21
- params_a = []
22
- query_params.each do |key, value|
23
- params_a << "#{key}=#{value}"
24
- end
25
- postfix = "?#{params_a.join('&')}"
26
- else
27
- postfix = default
28
- end
29
- postfix
30
- end
31
-
32
- module Get
33
- # Returns parsed doc from database
34
- def get_doc(database, id)
35
- res = get("/#{database}/#{CGI.escape(id)}")
36
- JSON.parse(res.body)
37
- end
38
-
39
- def get_attachment_str(db, id, attachment)
40
- uri = URI::encode "/#{db}/#{id}/#{attachment}"
41
- get(uri).body
42
- end
43
- end
44
-
45
- module Head
46
- # Returns revision for given document
47
- def get_rev(database, id)
48
- res = head("/#{database}/#{CGI.escape(id)}")
49
- if res.code == '200'
50
- res['etag'].gsub(/^"|"$/, '')
51
- else
52
- nil
53
- end
54
- end
55
- end
56
- end
57
-
58
- # Bulk requests; use methods from Couch::BasicRequest
59
- module BulkRequest
60
- module Get
61
- # Returns an array of the full documents for given database, possibly filtered with given parameters.
62
- # We recommend you use all_docs instead.
63
- #
64
- # Note that the 'include_docs' parameter must be set to true for this.
65
- def get_all_docs(database, params)
66
- # unless params.include_symbol_or_string? :include_docs
67
- # params.merge!({:include_docs => true})
68
- # end
69
- postfix = create_postfix(params)
70
- uri = URI::encode "/#{database}/_all_docs#{postfix}"
71
- res = get(uri)
72
- JSON.parse(res.body)['rows']
73
- end
74
-
75
-
76
- # If a block is given, performs the block for each +limit+-sized slice of _all_docs.
77
- # If no block is given, returns all docs by appending +limit+-sized slices of _all_docs.
78
- #
79
- # This method assumes your docs don't have the high-value Unicode character \ufff0. If it does, then behaviour is undefined. The reason why we use the startkey parameter instead of skip is that startkey is faster.
80
- def all_docs(db, limit=750, opts={}, &block)
81
- all_docs = []
82
- start_key = nil
83
- loop do
84
- opts = opts.merge({limit: limit})
85
- if start_key
86
- opts[:startkey]=start_key
87
- end
88
- docs = (lambda { |options| get_all_docs(db, options) }).call(opts)
89
- if docs.length <= 0
90
- break
91
- else
92
- if block
93
- block.call(docs)
94
- else
95
- all_docs < docs
96
- end
97
- start_key ="\"#{docs.last['_id']}\\ufff0\""
98
- end
99
- end
100
- all_docs.flatten
101
- end
102
-
103
- # Returns an array of all rows for given view.
104
- #
105
- # We recommend you use rows_for_view instead.
106
- def get_rows_for_view(database, design_doc, view, query_params=nil)
107
- postfix = create_postfix(query_params)
108
- uri = URI::encode "/#{database}/_design/#{design_doc}/_view/#{view}#{postfix}"
109
- res = get(uri)
110
- JSON.parse(res.body.force_encoding('utf-8'))['rows']
111
- end
112
-
113
- # If a block is given, performs the block for each +limit+-sized slice of rows for the given view.
114
- # If no block is given, returns all rows by appending +limit+-sized slices of the given view.
115
- def rows_for_view(db, design_doc, view, limit=500, opts={}, &block)
116
- get_all_views(lambda { |options| get_rows_for_view(db, design_doc, view, options) }, limit, opts, block)
117
- end
118
-
119
-
120
- # Returns an array of all ids in the database
121
- def get_all_ids(database, params)
122
- ids=[]
123
- postfix = create_postfix(params)
124
-
125
- uri = URI::encode "/#{database}/_all_docs#{postfix}"
126
- res = get(uri)
127
- result = JSON.parse(res.body)
128
- result['rows'].each do |row|
129
- if row['error']
130
- puts "#{row['key']}: #{row['error']}"
131
- puts "#{row['reason']}"
132
- else
133
- ids << row['id']
134
- end
135
- end
136
- ids
137
- end
138
-
139
- # Returns an array of all ids in the database
140
- def all_ids(db, limit=500, opts={}, &block)
141
- all_docs = []
142
- start_key = nil
143
- loop do
144
- opts = opts.merge({limit: limit})
145
- if start_key
146
- opts[:startkey]=start_key
147
- end
148
- docs = (lambda { |options| get_all_ids(db, options) }).call(opts)
149
- if docs.length <= 0
150
- break
151
- else
152
- if block
153
- block.call(docs)
154
- else
155
- all_docs < docs
156
- end
157
- start_key ="\"#{docs.last}\\ufff0\""
158
- end
159
- end
160
- all_docs.flatten
161
- end
162
-
163
- # Returns an array of the full documents for given view, possibly filtered with given parameters. Note that the 'include_docs' parameter must be set to true for this.
164
- #
165
- # Also consider using `docs_for_view`
166
- def get_docs_for_view(db, design_doc, view, params={})
167
- params.merge!({:include_docs => true})
168
- rows = get_rows_for_view(db, design_doc, view, params)
169
- docs = []
170
- rows.each do |row|
171
- docs << row['doc']
172
- end
173
- docs
174
- end
175
-
176
- # If a block is given, performs the block for each +limit+-sized slice of documents for the given view.
177
- # If no block is given, returns all docs by appending +limit+-sized slices of the given view.
178
- def docs_for_view(db, design_doc, view, limit=750, opts={}, &block)
179
- get_all_views(lambda { |options| get_docs_for_view(db, design_doc, view, options) }, limit, opts, block)
180
- end
181
-
182
- private
183
-
184
- def get_all_views(next_results, limit, opts, block)
185
- all = []
186
- offset = 0
187
- loop do
188
- opts = opts.merge({
189
- limit: limit,
190
- skip: offset,
191
- })
192
- docs = next_results.call(opts)
193
- if docs.length <= 0
194
- break
195
- else
196
- if block
197
- block.call(docs)
198
- else
199
- all < docs
200
- end
201
- offset += limit
202
- end
203
- end
204
- all.flatten
205
- end
206
-
207
- end
208
-
209
- module Delete
210
- def bulk_delete(database, docs)
211
- docs.each do |doc|
212
- doc[:_deleted]=true
213
- end
214
- json = {:docs => docs}.to_json
215
- post("/#{database}/_bulk_docs", json)
216
- end
217
- end
218
-
219
- module Post
220
- # Flushes the given hashes to CouchDB
221
- def post_bulk(database, docs)
222
- body = {:docs => docs}.to_json #.force_encoding('utf-8')
223
- post("/#{database}/_bulk_docs", body)
224
- end
225
-
226
- def post_bulk_throttled(db, docs, &block)
227
- # puts "Flushing #{docs.length} docs"
228
- bulk = []
229
- docs.each do |doc|
230
- bulk << doc
231
- if bulk.to_json.bytesize/1024/1024 > options[:flush_size_mb] or bulk.length >= options[:max_array_length]
232
- handle_bulk_flush(bulk, db, block)
233
- end
234
- end
235
- if bulk.length > 0
236
- handle_bulk_flush(bulk, db, block)
237
- end
238
- end
239
-
240
-
241
- def post_bulk_if_big_enough(db, docs)
242
- flush = (docs.to_json.bytesize / 1024 >= (options[:flush_size_mb]*1024) or docs.length >= options[:max_array_length])
243
- if flush
244
- post_bulk_throttled(db, docs)
245
- docs.clear
246
- end
247
- flush
248
- end
249
-
250
- private
251
-
252
- def handle_bulk_flush(bulk, db, block)
253
- res = post_bulk(db, bulk)
254
- error_count=0
255
- if res.body
256
- begin
257
- JSON.parse(res.body).each do |d|
258
- error_count+=1 if d['error']
259
- end
260
- end
261
- end
262
- if error_count > 0
263
- puts "Bulk request completed with #{error_count} errors"
264
- end
265
- if block
266
- block.call(res)
267
- end
268
- bulk.clear
269
- end
270
- end
271
- end
272
-
273
- class Server
274
- attr_accessor :options
275
-
276
- def initialize(url, options)
277
- if url.is_a? String
278
- url = URI(url)
279
- end
280
- @couch_url = url
281
- @options = options
282
- @options[:couch_url] = @couch_url
283
- @options[:use_ssl] ||= true
284
- @options[:max_array_length] ||= 250
285
- @options[:flush_size_mb] ||= 10
286
- @options[:open_timeout] ||= 5*30
287
- @options[:read_timeout] ||= 5*30
288
- @options[:fail_silent] ||= false
289
- end
290
-
291
- def delete(uri)
292
- Request.new(Net::HTTP::Delete.new(uri), nil,
293
- @options
294
- ).perform
295
- end
296
-
297
- def new_delete(uri)
298
- Request.new(Net::HTTP::Delete.new(uri)).couch_url(@couch_url)
299
- end
300
-
301
- def head(uri)
302
- Request.new(Net::HTTP::Head.new(uri), nil,
303
- @options
304
- ).perform
305
- end
306
-
307
- def new_head(uri)
308
- Request.new(Net::HTTP::Head.new(uri)).couch_url(@couch_url)
309
- end
310
-
311
- def get(uri)
312
- Request.new(
313
- Net::HTTP::Get.new(uri), nil,
314
- @options
315
- ).perform
316
- end
317
-
318
- def new_get(uri)
319
- Request.new(Net::HTTP::Get.new(uri)).couch_url(@couch_url)
320
- end
321
-
322
- def put(uri, json)
323
- Request.new(Net::HTTP::Put.new(uri), json,
324
- @options
325
- ).perform
326
- end
327
-
328
- def new_put(uri)
329
- Request.new(Net::HTTP::Put.new(uri)).couch_url(@couch_url)
330
- end
331
-
332
- def post(uri, json)
333
- Request.new(Net::HTTP::Post.new(uri), json,
334
- @options
335
- ).perform
336
- end
337
-
338
- def new_post(uri)
339
- Request.new(Net::HTTP::Post.new(uri)).couch_url(@couch_url)
340
- end
341
-
342
- class Request
343
- def initialize(req, json=nil, opts={open_timeout: 5*30, read_timeout: 5*30, fail_silent: false})
344
- @req=req
345
- @json = json
346
- @options = opts
347
- end
348
-
349
- def json(json)
350
- @json = json
351
- self
352
- end
353
-
354
- def couch_url(couch_url)
355
- @options.merge!({couch_url: couch_url})
356
- self
357
- end
358
-
359
- def open_timeout(open_timeout)
360
- @options.merge!({open_timeout: open_timeout})
361
- self
362
- end
363
-
364
- def read_timeout(read_timeout)
365
- @options.merge!({read_timeout: read_timeout})
366
- self
367
- end
368
-
369
- def fail_silent(fail_silent)
370
- @options.merge!({fail_silent: fail_silent})
371
- self
372
- end
373
-
374
- def perform
375
- @req.basic_auth @options[:name], @options[:password]
376
-
377
- if @json
378
- @req['Content-Type'] = 'application/json;charset=utf-8'
379
- @req.body = @json
380
- end
381
-
382
- res = Net::HTTP.start(@options[:couch_url].host, @options[:couch_url].port,
383
- :use_ssl => @options[:couch_url].scheme =='https') do |http|
384
- http.open_timeout = @options[:open_timeout]
385
- http.read_timeout = @options[:read_timeout]
386
- http.request(@req)
387
- end
388
-
389
- unless @options[:fail_silent] or res.kind_of?(Net::HTTPSuccess)
390
- # puts "CouchDb responsed with error code #{res.code}"
391
- handle_error(@req, res)
392
- end
393
- res
394
- end
395
-
396
- def handle_error(req, res)
397
- raise RuntimeError.new("#{res.code}:#{res.message}\nMETHOD:#{req.method}\nURI:#{req.path}\n#{res.body}")
398
- end
399
- end
400
-
401
- include BasicRequest
402
- include BasicRequest::Head
403
- include BasicRequest::Get
404
- include BulkRequest::Get
405
- include BulkRequest::Delete
406
- include BulkRequest::Post
407
-
408
- private
409
- end
410
- end
1
+ require 'couch/db/version'
2
+ require 'net/http'
3
+ require 'json'
4
+ require 'objspace'
5
+ require 'openssl'
6
+
7
+ class Hash
8
+ def include_symbol_or_string?(param)
9
+ if param.is_a? Symbol or param.is_a? String
10
+ include? param.to_sym or include? param.to_s
11
+ else
12
+ false
13
+ end
14
+ end
15
+ end
16
+
17
+ module Couch
18
+ module BasicRequest
19
+ def create_postfix(query_params, default='')
20
+ if query_params
21
+ params_a = []
22
+ query_params.each do |key, value|
23
+ params_a << "#{key}=#{value}"
24
+ end
25
+ postfix = "?#{params_a.join('&')}"
26
+ else
27
+ postfix = default
28
+ end
29
+ postfix
30
+ end
31
+
32
+ module Get
33
+ # Returns parsed doc from database
34
+ def get_doc(database, id, params={})
35
+ res = get("/#{database}/#{CGI.escape(id)}#{create_postfix(params)}")
36
+ JSON.parse(res.body)
37
+ end
38
+
39
+ def get_attachment_str(db, id, attachment)
40
+ uri = URI::encode "/#{db}/#{id}/#{attachment}"
41
+ get(uri).body
42
+ end
43
+ end
44
+
45
+ module Head
46
+ # Returns revision for given document
47
+ def get_rev(database, id)
48
+ res = head("/#{database}/#{CGI.escape(id)}")
49
+ if res.code == '200'
50
+ res['etag'].gsub(/^"|"$/, '')
51
+ else
52
+ nil
53
+ end
54
+ end
55
+ end
56
+ end
57
+
58
+ # Bulk requests; use methods from Couch::BasicRequest
59
+ module BulkRequest
60
+ module Get
61
+ # Returns an array of the full documents for given database, possibly filtered with given parameters.
62
+ # We recommend you use all_docs instead.
63
+ #
64
+ # Note that the 'include_docs' parameter must be set to true for this.
65
+ def get_all_docs(database, params)
66
+ # unless params.include_symbol_or_string? :include_docs
67
+ # params.merge!({:include_docs => true})
68
+ # end
69
+ postfix = create_postfix(params)
70
+ uri = URI::encode "/#{database}/_all_docs#{postfix}"
71
+ res = get(uri)
72
+ JSON.parse(res.body)['rows']
73
+ end
74
+
75
+
76
+ # If a block is given, performs the block for each +limit+-sized slice of _all_docs.
77
+ # If no block is given, returns all docs by appending +limit+-sized slices of _all_docs.
78
+ #
79
+ # This method assumes your docs don't have the high-value Unicode character \ufff0. If it does, then behaviour is undefined. The reason why we use the startkey parameter instead of skip is that startkey is faster.
80
+ def all_docs(db, limit=750, opts={}, &block)
81
+ all_docs = []
82
+ start_key = nil
83
+ loop do
84
+ opts = opts.merge({limit: limit})
85
+ if start_key
86
+ opts[:startkey]=start_key
87
+ end
88
+ docs = (lambda { |options| get_all_docs(db, options) }).call(opts)
89
+ if docs.length <= 0
90
+ break
91
+ else
92
+ if block
93
+ block.call(docs)
94
+ else
95
+ all_docs < docs
96
+ end
97
+ start_key ="\"#{docs.last['_id']}\\ufff0\""
98
+ end
99
+ end
100
+ all_docs.flatten
101
+ end
102
+
103
+ # Returns an array of all rows for given view.
104
+ #
105
+ # We recommend you use rows_for_view instead.
106
+ def get_rows_for_view(database, design_doc, view, query_params=nil)
107
+ postfix = create_postfix(query_params)
108
+ uri = URI::encode "/#{database}/_design/#{design_doc}/_view/#{view}#{postfix}"
109
+ res = get(uri)
110
+ JSON.parse(res.body.force_encoding('utf-8'))['rows']
111
+ end
112
+
113
+ # If a block is given, performs the block for each +limit+-sized slice of rows for the given view.
114
+ # If no block is given, returns all rows by appending +limit+-sized slices of the given view.
115
+ def rows_for_view(db, design_doc, view, limit=500, opts={}, &block)
116
+ get_all_views(lambda { |options| get_rows_for_view(db, design_doc, view, options) }, limit, opts, block)
117
+ end
118
+
119
+
120
+ # Returns an array of all ids in the database
121
+ def get_all_ids(database, params)
122
+ ids=[]
123
+ postfix = create_postfix(params)
124
+
125
+ uri = URI::encode "/#{database}/_all_docs#{postfix}"
126
+ res = get(uri)
127
+ result = JSON.parse(res.body)
128
+ result['rows'].each do |row|
129
+ if row['error']
130
+ puts "#{row['key']}: #{row['error']}"
131
+ puts "#{row['reason']}"
132
+ else
133
+ ids << row['id']
134
+ end
135
+ end
136
+ ids
137
+ end
138
+
139
+ # Returns an array of all ids in the database
140
+ def all_ids(db, limit=500, opts={}, &block)
141
+ all_docs = []
142
+ start_key = nil
143
+ loop do
144
+ opts = opts.merge({limit: limit})
145
+ if start_key
146
+ opts[:startkey]=start_key
147
+ end
148
+ docs = (lambda { |options| get_all_ids(db, options) }).call(opts)
149
+ if docs.length <= 0
150
+ break
151
+ else
152
+ if block
153
+ block.call(docs)
154
+ else
155
+ all_docs < docs
156
+ end
157
+ start_key ="\"#{docs.last}\\ufff0\""
158
+ end
159
+ end
160
+ all_docs.flatten
161
+ end
162
+
163
+ # Returns an array of the full documents for given view, possibly filtered with given parameters. Note that the 'include_docs' parameter must be set to true for this.
164
+ #
165
+ # Also consider using `docs_for_view`
166
+ def get_docs_for_view(db, design_doc, view, params={})
167
+ params.merge!({:include_docs => true})
168
+ rows = get_rows_for_view(db, design_doc, view, params)
169
+ docs = []
170
+ rows.each do |row|
171
+ docs << row['doc']
172
+ end
173
+ docs
174
+ end
175
+
176
+ # If a block is given, performs the block for each +limit+-sized slice of documents for the given view.
177
+ # If no block is given, returns all docs by appending +limit+-sized slices of the given view.
178
+ def docs_for_view(db, design_doc, view, limit=750, opts={}, &block)
179
+ get_all_views(lambda { |options| get_docs_for_view(db, design_doc, view, options) }, limit, opts, block)
180
+ end
181
+
182
+ private
183
+
184
+ def get_all_views(next_results, limit, opts, block)
185
+ all = []
186
+ offset = 0
187
+ loop do
188
+ opts = opts.merge({
189
+ limit: limit,
190
+ skip: offset,
191
+ })
192
+ docs = next_results.call(opts)
193
+ if docs.length <= 0
194
+ break
195
+ else
196
+ if block
197
+ block.call(docs)
198
+ else
199
+ all < docs
200
+ end
201
+ offset += limit
202
+ end
203
+ end
204
+ all.flatten
205
+ end
206
+
207
+ end
208
+
209
+ module Delete
210
+ def bulk_delete(database, docs)
211
+ docs.each do |doc|
212
+ doc[:_deleted]=true
213
+ end
214
+ json = {:docs => docs}.to_json
215
+ post("/#{database}/_bulk_docs", json)
216
+ end
217
+ end
218
+
219
+ module Post
220
+ # Flushes the given hashes to CouchDB
221
+ def post_bulk(database, docs)
222
+ body = {:docs => docs}.to_json #.force_encoding('utf-8')
223
+ post("/#{database}/_bulk_docs", body)
224
+ end
225
+
226
+ def post_bulk_throttled(db, docs, &block)
227
+ # puts "Flushing #{docs.length} docs"
228
+ bulk = []
229
+ docs.each do |doc|
230
+ bulk << doc
231
+ if bulk.to_json.bytesize/1024/1024 > options[:flush_size_mb] or bulk.length >= options[:max_array_length]
232
+ handle_bulk_flush(bulk, db, block)
233
+ end
234
+ end
235
+ if bulk.length > 0
236
+ handle_bulk_flush(bulk, db, block)
237
+ end
238
+ end
239
+
240
+
241
+ def post_bulk_if_big_enough(db, docs)
242
+ flush = (docs.to_json.bytesize / 1024 >= (options[:flush_size_mb]*1024) or docs.length >= options[:max_array_length])
243
+ if flush
244
+ post_bulk_throttled(db, docs)
245
+ docs.clear
246
+ end
247
+ flush
248
+ end
249
+
250
+ private
251
+
252
+ def handle_bulk_flush(bulk, db, block)
253
+ res = post_bulk(db, bulk)
254
+ error_count=0
255
+ if res.body
256
+ begin
257
+ JSON.parse(res.body).each do |d|
258
+ error_count+=1 if d['error']
259
+ end
260
+ end
261
+ end
262
+ if error_count > 0
263
+ puts "Bulk request completed with #{error_count} errors"
264
+ end
265
+ if block
266
+ block.call(res)
267
+ end
268
+ bulk.clear
269
+ end
270
+ end
271
+ end
272
+
273
+ class Server
274
+ attr_accessor :options
275
+
276
+ def initialize(url, options)
277
+ if url.is_a? String
278
+ url = URI(url)
279
+ end
280
+ @couch_url = url
281
+ @options = options
282
+ @options[:couch_url] = @couch_url
283
+ @options[:use_ssl] ||= true
284
+ @options[:max_array_length] ||= 250
285
+ @options[:flush_size_mb] ||= 10
286
+ @options[:open_timeout] ||= 5*30
287
+ @options[:read_timeout] ||= 5*30
288
+ @options[:fail_silent] ||= false
289
+ end
290
+
291
+ def delete(uri)
292
+ Request.new(Net::HTTP::Delete.new(uri), nil,
293
+ @options
294
+ ).perform
295
+ end
296
+
297
+ def new_delete(uri)
298
+ Request.new(Net::HTTP::Delete.new(uri)).couch_url(@couch_url)
299
+ end
300
+
301
+ def head(uri)
302
+ Request.new(Net::HTTP::Head.new(uri), nil,
303
+ @options
304
+ ).perform
305
+ end
306
+
307
+ def new_head(uri)
308
+ Request.new(Net::HTTP::Head.new(uri)).couch_url(@couch_url)
309
+ end
310
+
311
+ def get(uri)
312
+ Request.new(
313
+ Net::HTTP::Get.new(uri), nil,
314
+ @options
315
+ ).perform
316
+ end
317
+
318
+ def new_get(uri)
319
+ Request.new(Net::HTTP::Get.new(uri)).couch_url(@couch_url)
320
+ end
321
+
322
+ def put(uri, json)
323
+ Request.new(Net::HTTP::Put.new(uri), json,
324
+ @options
325
+ ).perform
326
+ end
327
+
328
+ def new_put(uri)
329
+ Request.new(Net::HTTP::Put.new(uri)).couch_url(@couch_url)
330
+ end
331
+
332
+ def post(uri, json)
333
+ Request.new(Net::HTTP::Post.new(uri), json,
334
+ @options
335
+ ).perform
336
+ end
337
+
338
+ def new_post(uri)
339
+ Request.new(Net::HTTP::Post.new(uri)).couch_url(@couch_url)
340
+ end
341
+
342
+ class Request
343
+ def initialize(req, json=nil, opts={open_timeout: 5*30, read_timeout: 5*30, fail_silent: false})
344
+ @req=req
345
+ @json = json
346
+ @options = opts
347
+ end
348
+
349
+ def json(json)
350
+ @json = json
351
+ self
352
+ end
353
+
354
+ def couch_url(couch_url)
355
+ @options.merge!({couch_url: couch_url})
356
+ self
357
+ end
358
+
359
+ def open_timeout(open_timeout)
360
+ @options.merge!({open_timeout: open_timeout})
361
+ self
362
+ end
363
+
364
+ def read_timeout(read_timeout)
365
+ @options.merge!({read_timeout: read_timeout})
366
+ self
367
+ end
368
+
369
+ def fail_silent(fail_silent)
370
+ @options.merge!({fail_silent: fail_silent})
371
+ self
372
+ end
373
+
374
+ def perform
375
+ @req.basic_auth @options[:name], @options[:password]
376
+
377
+ if @json
378
+ @req['Content-Type'] = 'application/json;charset=utf-8'
379
+ @req.body = @json
380
+ end
381
+
382
+ res = Net::HTTP.start(
383
+ @options[:couch_url].host,
384
+ @options[:couch_url].port,
385
+ {:use_ssl => @options[:couch_url].scheme =='https'}
386
+ ) do |http|
387
+ http.open_timeout = @options[:open_timeout]
388
+ http.read_timeout = @options[:read_timeout]
389
+ http.request(@req)
390
+ end
391
+
392
+ unless @options[:fail_silent] or res.kind_of?(Net::HTTPSuccess)
393
+ # puts "CouchDb responsed with error code #{res.code}"
394
+ handle_error(@req, res)
395
+ end
396
+ res
397
+ end
398
+
399
+ def handle_error(req, res)
400
+ raise RuntimeError.new("#{res.code}:#{res.message}\nMETHOD:#{req.method}\nURI:#{req.path}\n#{res.body}")
401
+ end
402
+ end
403
+
404
+ include BasicRequest
405
+ include BasicRequest::Head
406
+ include BasicRequest::Get
407
+ include BulkRequest::Get
408
+ include BulkRequest::Delete
409
+ include BulkRequest::Post
410
+
411
+ private
412
+ end
413
+ end