chill 5 → 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 (2) hide show
  1. data/library/chill.rb +125 -10
  2. metadata +9 -9
@@ -57,10 +57,35 @@ module ChillDB
57
57
  return ChillDB::Document.new(@@database, hash).commit!
58
58
  end
59
59
 
60
+ # commit takes an array of documents, and does a bulk commit to the server (one single request)
61
+ # using a bulk commit is faster than calling commit! on each individual document object
62
+ def commit! *args
63
+ list(args.flatten).commit!
64
+ end
65
+
66
+ def delete! *args
67
+ list(args.flatten).delete!
68
+ end
69
+
70
+ # turn an array of documents in to a ChillDB::List
71
+ def list array = []
72
+ list = ChillDB::List.from_array array
73
+ list.database = @@database
74
+ return list
75
+ end
76
+
77
+ # all docs!
78
+ def everything
79
+ list = ChillDB::List.load(JSON.parse(@@database.http('_all_docs?include_docs=true').get.body))
80
+ list.database = @@database
81
+ return list
82
+ end
83
+
84
+ # open a resource to the server for a particular document, which you can get, post, etc to. For internal use.
60
85
  def open *args
61
86
  headers = { accept: '*/*' }
62
87
  headers.merge! args.pop if args.last.respond_to? :to_hash
63
- @@database.http(args.map { |i| URI.escape(i, /[^a-z0-9_.-]/i) }.join('/'), headers)
88
+ @@database.http(args.map { |item| URI.escape(item, /[^a-z0-9_.-]/i) }.join('/'), headers)
64
89
  end
65
90
  end
66
91
 
@@ -86,6 +111,17 @@ class ChillDB::Database
86
111
  return self
87
112
  end
88
113
 
114
+ # get info about database
115
+ def info
116
+ response = http('').get()
117
+ IndifferentHash.new.replace(JSON.parse response.body)
118
+ end
119
+
120
+ # pretty output for debugging things :)
121
+ def inspect
122
+ "#<ChillDB::Database: #{info.inspect} >"
123
+ end
124
+
89
125
  #def revs_limit; http('_revs_limit').get.body.to_i; end
90
126
  #def revs_limit=(v); http('_revs_limit').put(v.to_s); end
91
127
 
@@ -204,6 +240,7 @@ class ChillDB::Document < ChillDB::IndifferentHash
204
240
  # returns self, or if there's a more specific subclass, a subclassed version of Document
205
241
  def load lookup_revision = nil
206
242
  url = URI(URI.escape self['_id'])
243
+ lookup_revision ||= self['_rev']
207
244
  url.query = "rev=#{lookup_revision}" if lookup_revision
208
245
  response = @database.http(url).get
209
246
  return self if response.code == 404 # we can create it later
@@ -215,6 +252,7 @@ class ChillDB::Document < ChillDB::IndifferentHash
215
252
 
216
253
  # stores updates (or newly existingness) of document to origin database
217
254
  def commit!
255
+ return delete! if self['_deleted'] # just delete if we're marked for deletion
218
256
  json = JSON.generate(self)
219
257
  response = @database.http(URI.escape self['_id']).put(json);
220
258
  raise response.body unless (200..299).include? response.code
@@ -225,11 +263,17 @@ class ChillDB::Document < ChillDB::IndifferentHash
225
263
  return self
226
264
  end
227
265
 
228
- # delete this jerk
266
+ # mark this jerk for deletion! (useful for bulk commit)
267
+ def delete
268
+ self.replace('_id'=> self['_id'], '_rev'=> self['_rev'], '_deleted'=> true)
269
+ end
270
+
271
+ # delete this jerk immediately
229
272
  def delete!
230
273
  response = @database.http(URI.escape self['_id']).delete()
231
274
  response = ChillDB::IndifferentHash.new.replace JSON.parse(response.body)
232
275
  raise "Couldn't delete #{self._id}: #{response.error} - #{response.reason}" if response['error']
276
+ delete # make our contents be deleted
233
277
  return response
234
278
  end
235
279
 
@@ -249,6 +293,11 @@ class ChillDB::Document < ChillDB::IndifferentHash
249
293
  def to_param
250
294
  self['_id']
251
295
  end
296
+
297
+ # loose equality check
298
+ def == other_doc
299
+ other.is_a?(self.class) and (self['_id'] == other['_id']) and (self['_rev'] == other['_rev'])
300
+ end
252
301
  end
253
302
 
254
303
 
@@ -273,6 +322,14 @@ class ChillDB::List < Array
273
322
  return new_list
274
323
  end
275
324
 
325
+ # to make a list from a simple array (not a couchdb response...)
326
+ def self.from_array array
327
+ new_list = self.new
328
+ new_list.replace array.map do |item|
329
+ { 'id'=> item['_id'], 'key'=> item['_id'], 'value'=> item, 'doc'=> item }
330
+ end
331
+ end
332
+
276
333
  # store rows nicely in mah belleh
277
334
  def rows=(arr)
278
335
  self.replace(arr.map { |item|
@@ -342,21 +399,60 @@ class ChillDB::List < Array
342
399
  return hash
343
400
  end
344
401
 
402
+ # commit takes an array of documents, and does a bulk commit to the server (one single request)
403
+ # using a bulk commit is faster than calling commit! on each individual document object
404
+ def commit!
405
+ commit_documents! convert
406
+ end
407
+ alias_method :commit_all!, :commit!
408
+
345
409
  # remove all the documents in this list from the database
346
- def delete_all!
410
+ def delete!
411
+ # check all the entries have a _rev - if they don't they cannot be deleted!
347
412
  each do |item|
348
- raise "Some (all?) items in list do not contain _rev properties in their values" unless item['value']['_rev']
413
+ rev = item['value']['_rev'] || item['value']['rev'] || item['doc']['_rev']
414
+ raise "Some (all?) items in list do not contain _rev properties in their values" unless rev
349
415
  end
350
416
 
351
- request = { docs: map { |item|
352
- { _id: item['value']['_id'] || item['id'], _rev: item['value']['_rev'], _deleted: true }
353
- } }
417
+ # mark all documents for deletion and commit the order!
418
+ commit_documents! convert.map { |item| item.delete }
419
+ end
420
+
421
+ alias_method :delete_all!, :delete!
422
+
423
+ private
424
+ # get the list, with any non-ChillDB::Document's converted in to those
425
+ def convert
426
+ map do |item|
427
+ document = item['doc'] || item['value']
428
+ if document.is_a? ChillDB::Document
429
+ document
430
+ elsif document.respond_to? :to_hash
431
+ document['_rev'] ||= item['value']['_rev'] || item['value']['rev'] || item['doc']['_rev']
432
+ document = ChillDB::Document.new(@database, document.to_hash)
433
+ else
434
+ raise "Cannot convert #{document.inspect}"
435
+ end
436
+ end
437
+ end
438
+
439
+ # commit an array of documents to the server
440
+ def commit_documents! documents
441
+ response = @database.http('_bulk_docs').post(JSON.generate(docs: documents.to_a))
442
+ raise response.body unless (200..299).include? response.code
443
+ json = JSON.parse(response.body)
444
+ errors = []
354
445
 
355
- response = JSON.parse @database.http("_bulk_docs").post(request.to_json)
356
- raise "Error: #{response['error']} - #{response['reason']}" if response.is_a? Hash and response['error']
446
+ documents.each_index do |index|
447
+ self[index]['id'] = json[index]['id']
448
+ self[index]['value']['rev'] = json[index]['rev'] if json[index]['rev']
449
+ errors.push [self[index], json[index]] if json[index]['error']
450
+ end
357
451
 
358
- return ChillDB::IndifferentHash.new.replace response
452
+ raise errors unless errors.empty?
453
+ return self
359
454
  end
455
+
360
456
  end
361
457
 
362
458
 
@@ -437,3 +533,22 @@ end
437
533
 
438
534
 
439
535
 
536
+
537
+ class ChillDB::BulkUpdateErrors < StandardError
538
+ attr_accessor :failures
539
+
540
+ def initialize *args
541
+ @failures = args.pop
542
+ super(*args)
543
+ end
544
+
545
+ def inspect
546
+ "ChillDB::BulkUpdateError:\n" + @failures.map { |failure|
547
+ document, error = failure
548
+ " '#{document['_id']}': #{error['reason']}"
549
+ }.join('\n')
550
+ end
551
+ end
552
+
553
+
554
+
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: chill
3
3
  version: !ruby/object:Gem::Version
4
- version: '5'
4
+ version: '6'
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,11 +9,11 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2011-10-31 00:00:00.000000000Z
12
+ date: 2012-04-28 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: json
16
- requirement: &70177568025240 !ruby/object:Gem::Requirement
16
+ requirement: &70131867175840 !ruby/object:Gem::Requirement
17
17
  none: false
18
18
  requirements:
19
19
  - - ! '>='
@@ -21,10 +21,10 @@ dependencies:
21
21
  version: 1.0.0
22
22
  type: :runtime
23
23
  prerelease: false
24
- version_requirements: *70177568025240
24
+ version_requirements: *70131867175840
25
25
  - !ruby/object:Gem::Dependency
26
26
  name: rest-client
27
- requirement: &70177568024660 !ruby/object:Gem::Requirement
27
+ requirement: &70131867175340 !ruby/object:Gem::Requirement
28
28
  none: false
29
29
  requirements:
30
30
  - - ! '>='
@@ -32,10 +32,10 @@ dependencies:
32
32
  version: 1.6.7
33
33
  type: :runtime
34
34
  prerelease: false
35
- version_requirements: *70177568024660
35
+ version_requirements: *70131867175340
36
36
  - !ruby/object:Gem::Dependency
37
37
  name: uuid
38
- requirement: &70177568024180 !ruby/object:Gem::Requirement
38
+ requirement: &70131867174860 !ruby/object:Gem::Requirement
39
39
  none: false
40
40
  requirements:
41
41
  - - ! '>='
@@ -43,7 +43,7 @@ dependencies:
43
43
  version: 2.3.4
44
44
  type: :runtime
45
45
  prerelease: false
46
- version_requirements: *70177568024180
46
+ version_requirements: *70131867174860
47
47
  description: A little library to talk to a couchdb. I made it skinny, because couchdb
48
48
  is very simple. I think that's a good thing.
49
49
  email: a@creativepony.com
@@ -72,7 +72,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
72
72
  version: '0'
73
73
  requirements: []
74
74
  rubyforge_project:
75
- rubygems_version: 1.8.10
75
+ rubygems_version: 1.8.11
76
76
  signing_key:
77
77
  specification_version: 3
78
78
  summary: A tiny plug to hook ruby in to couchdb