dolly 0.4.0 → 0.5.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: c8e886107b3a3b884726d4a2497e2e4cd47690bf
4
- data.tar.gz: 9fd518c6a9b2c06ca14fbad305bb1afb2d9a8a49
3
+ metadata.gz: 94c8771287f56c3dc8037d0847c45cde37301bf1
4
+ data.tar.gz: 60819593da81aa2312205e940753e8358c72d65d
5
5
  SHA512:
6
- metadata.gz: 7dbe2cc21c9cd20c9f5011fb17ddc3f64856298645ce33c25f0408ba76aa684a68351c270ca76ab29a1a797bb3a4f333afa43570531d7a205616b7e837c09193
7
- data.tar.gz: 11c1a0face5e9722e294c6d2ae093997fad57826c8be1e22915448edffd21ca86696362d805bf3ca451719becc1e41228f7873256e4c78821393c385a78b0f5a
6
+ metadata.gz: 384b3d6789af88ba43e1a3f2f7e05d863f8095625f2f3b0637b497366174361ce434bc42595257d60fca3d8e8f1b2a5bad6123b46c45f346b91b1708c2d55c21
7
+ data.tar.gz: 0bf4f41521a7755687d6bae67020111f2677d9d8297c0bd72c97a1a8b4dd100cd87e51bf251ec5ee6ba63e84cead812c5fc8ac1666ed7e42f08ecc2eca3dfd20
@@ -0,0 +1,85 @@
1
+ require 'dolly/bulk_error'
2
+
3
+ module Dolly
4
+ class BulkDocument
5
+ include Enumerable
6
+ extend Forwardable
7
+
8
+ DOC_NAME = "_bulk_docs".freeze
9
+
10
+ attr_reader :payload, :database
11
+ attr_accessor :errors, :response
12
+
13
+ def_delegators :docs, :[], :<<
14
+
15
+ def initialize database, ary = []
16
+ @database = database
17
+ @payload = Hash.new
18
+ self.payload[:docs] = ary
19
+ end
20
+
21
+ def docs
22
+ self.payload[:docs]
23
+ end
24
+
25
+ def save
26
+ return if docs.empty?
27
+ self.response = JSON::parse self.database.post(DOC_NAME, json_payload)
28
+ build_errors
29
+ update_revs
30
+ end
31
+
32
+ def delete
33
+ return if docs.empty?
34
+ JSON::parse database.post DOC_NAME, json_payload("_deleted" => true)
35
+ end
36
+
37
+ def clear
38
+ self.payload[:docs] = []
39
+ self.response = []
40
+ self.errors = []
41
+ end
42
+
43
+ def with_errors?
44
+ response_errors.present?
45
+ end
46
+
47
+ private
48
+ def update_revs
49
+ self.response.each do |doc|
50
+ next if doc['error']
51
+ item = self.payload[:docs].detect{|d| d.id == doc['id']}
52
+ if item.nil?
53
+ self.errors << BulkError.new({"error" => "Document saved but not local rev updated.", "reason" => "Document with id #{doc['id']} on bulk doc was not found in payload.", "obj" => nil})
54
+ next
55
+ end
56
+ item.doc['_rev'] = doc['rev']
57
+ self.payload[:docs].delete item
58
+ end
59
+ clean_response
60
+ end
61
+
62
+ def clean_response
63
+ self.response.delete_if {|doc| !doc['error'] }
64
+ end
65
+
66
+ def build_errors
67
+ self.errors = response_errors.map do |err|
68
+ obj = self.payload[:docs].detect{|d| d.id == err['id']} if err['id']
69
+ BulkError.new err.merge!("obj" => obj)
70
+ end
71
+ end
72
+
73
+ def bare_docs
74
+ self.payload[:docs].map(&:doc)
75
+ end
76
+
77
+ def json_payload opts = {}
78
+ {docs: bare_docs.map{|d| d.merge(opts)} }.to_json
79
+ end
80
+
81
+ def response_errors
82
+ self.response.select{|d| d['error']}
83
+ end
84
+ end
85
+ end
@@ -0,0 +1,16 @@
1
+ module Dolly
2
+ class BulkError
3
+ attr_accessor :obj, :name, :message
4
+
5
+ def initialize options = {}
6
+ self.obj = options['obj']
7
+ self.name = options['error']
8
+ self.message = options['reason']
9
+ end
10
+
11
+ def to_s
12
+ message
13
+ end
14
+
15
+ end
16
+ end
@@ -1,5 +1,3 @@
1
- require 'dolly/representations/collection_representation'
2
-
3
1
  module Dolly
4
2
  class Collection
5
3
  extend Forwardable
@@ -44,8 +42,22 @@ module Dolly
44
42
  length
45
43
  end
46
44
 
45
+ def rows= ary
46
+ ary.each do |r|
47
+ next unless r['doc']
48
+ properties = r['doc']
49
+ id = properties.delete '_id'
50
+ rev = properties.delete '_rev' if properties['_rev']
51
+ document = docs_class.new properties
52
+ document.doc = properties.merge({'_id' => id, '_rev' => rev})
53
+ @set << document
54
+ end
55
+ @rows = ary
56
+ end
57
+
47
58
  def load
48
- @set = self.extend(representation).from_json(json).rows
59
+ parsed = JSON::parse json
60
+ self.rows = parsed['rows']
49
61
  end
50
62
 
51
63
  def to_json options = {}
@@ -54,10 +66,6 @@ module Dolly
54
66
  end
55
67
 
56
68
  private
57
- def representation
58
- Representations::CollectionRepresentation.config(docs_class)
59
- end
60
-
61
69
  def docs_class
62
70
  @docs_class
63
71
  end
@@ -1,6 +1,7 @@
1
1
  require "dolly/request"
2
2
  require "dolly/name_space"
3
3
  require "dolly/db_config"
4
+ require "dolly/bulk_document"
4
5
 
5
6
  module Dolly
6
7
  module Connection
@@ -13,6 +14,14 @@ module Dolly
13
14
  @database ||= Request.new(env)
14
15
  end
15
16
 
17
+ def bulk_document
18
+ @bulk_document ||= BulkDocument.new(database)
19
+ end
20
+
21
+ def bulk_save
22
+ bulk_document.save
23
+ end
24
+
16
25
  def database_name value
17
26
  @@database_name ||= value
18
27
  end
@@ -22,6 +22,7 @@ module Dolly
22
22
  end
23
23
 
24
24
  def save
25
+ self.doc['_id'] = self.class.next_id if self.doc['_id'].blank?
25
26
  response = database.put(id_as_resource, self.doc.to_json)
26
27
  obj = JSON::parse response.parsed_response
27
28
  doc['_rev'] = obj['rev'] if obj['rev']
@@ -33,7 +34,15 @@ module Dolly
33
34
  save
34
35
  end
35
36
 
37
+ def destroy soft = false
38
+ #TODO: Add soft delete support
39
+ q = id_as_resource + "?rev=#{rev}"
40
+ response = database.delete(q)
41
+ JSON::parse response.parsed_response
42
+ end
43
+
36
44
  def rows= col
45
+ raise Dolly::ResourceNotFound if col.empty?
37
46
  col.each{ |r| @doc = r['doc'] }
38
47
  _properties.each do |p|
39
48
  self.send "#{p.name}=", doc[p.name]
@@ -42,7 +51,9 @@ module Dolly
42
51
  end
43
52
 
44
53
  def from_json string
45
- self.class.new.extend(representation).from_json( string )
54
+ parsed = JSON::parse( string )
55
+ self.rows = parsed['rows']
56
+ self
46
57
  end
47
58
 
48
59
  def database
@@ -53,10 +64,6 @@ module Dolly
53
64
  CGI::escape id
54
65
  end
55
66
 
56
- def representation
57
- Representations::DocumentRepresentation.config(self.properties)
58
- end
59
-
60
67
  def self.create options = {}
61
68
  obj = new options
62
69
  obj.save
@@ -95,7 +102,12 @@ module Dolly
95
102
  end
96
103
 
97
104
  def init_properties options = {}
98
- options.each{|k, v| send(:"#{k}=", v)}
105
+ #TODO: right now not listed properties will be ignored
106
+ options.each do |k, v|
107
+ next unless respond_to? :"#{k}="
108
+ send(:"#{k}=", v)
109
+ end
110
+ self.doc ||= {}
99
111
  end
100
112
  end
101
113
  end
@@ -0,0 +1,5 @@
1
+ module Dolly
2
+ module Interpreter
3
+
4
+ end
5
+ end
data/lib/dolly/query.rb CHANGED
@@ -1,7 +1,5 @@
1
1
  require "dolly/connection"
2
2
  require "dolly/collection"
3
- require "dolly/representations/document_representation"
4
- require "dolly/representations/collection_representation"
5
3
  require "dolly/name_space"
6
4
  require "exceptions/dolly"
7
5
 
@@ -40,7 +38,13 @@ module Dolly
40
38
  end
41
39
 
42
40
  def build_collection q
43
- Collection.new default_view(q).parsed_response, name.constantize
41
+ res = default_view(q)
42
+ Collection.new res.parsed_response, name.constantize
43
+ end
44
+
45
+ def find_with doc, view_name, opts = {}
46
+ res = view "_design/#{doc}/_view/#{view_name}", opts
47
+ Collection.new res.parsed_response, name.constantize
44
48
  end
45
49
 
46
50
  def default_view options = {}
data/lib/dolly/request.rb CHANGED
@@ -1,4 +1,5 @@
1
1
  require "httparty"
2
+ require "dolly/bulk_document"
2
3
 
3
4
  module Dolly
4
5
 
@@ -7,7 +8,7 @@ module Dolly
7
8
  DEFAULT_HOST = 'localhost'
8
9
  DEFAULT_PORT = '5984'
9
10
 
10
- attr_accessor :database_name, :host, :port
11
+ attr_accessor :database_name, :host, :port, :bulk_document
11
12
 
12
13
  def initialize options = {}
13
14
  @host = options["host"] || DEFAULT_HOST
@@ -17,6 +18,7 @@ module Dolly
17
18
  @username = options["username"]
18
19
  @password = options["password"]
19
20
 
21
+ @bulk_document = Dolly::BulkDocument.new []
20
22
  self.class.base_uri "#{protocol}://#{auth_info}#{host}:#{port}"
21
23
  end
22
24
 
@@ -29,6 +31,10 @@ module Dolly
29
31
  request :put, resource, {body: data}
30
32
  end
31
33
 
34
+ def post resource, data
35
+ request :post, resource, {body: data}
36
+ end
37
+
32
38
  def delete resource
33
39
  request :delete, resource, {}
34
40
  end
data/lib/dolly/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Dolly
2
- VERSION = "0.4.0"
2
+ VERSION = "0.5.0"
3
3
  end
@@ -0,0 +1,44 @@
1
+ require 'test_helper'
2
+
3
+ class Doc < Dolly::Document
4
+ property :name
5
+ end
6
+
7
+ class BulkDocumentTest < ActiveSupport::TestCase
8
+
9
+ setup do
10
+ @doc = Dolly::Document.bulk_document
11
+ @req = "http://localhost:5984/test/_bulk_docs"
12
+ end
13
+
14
+ teardown do
15
+ @doc.clear
16
+ end
17
+
18
+ test 'bulk document intialize with empty payload' do
19
+ assert_equal [], @doc.docs
20
+ end
21
+
22
+ test 'adding document to bulk_doc' do
23
+ d = Doc.new
24
+ @doc << d
25
+ assert @doc.docs.include?(d)
26
+ end
27
+
28
+ test 'save document will remove docs from payload' do
29
+ docs = 3.times.map{ Doc.new name: "a" }
30
+ docs.each do |d|
31
+ d.doc['_id'] = "foo_bar/#{SecureRandom.uuid}"
32
+ @doc << d
33
+ end
34
+
35
+ res = docs.map{|d| {ok: true, id: d.id, rev: "2-#{SecureRandom.uuid}"} }.to_json
36
+ FakeWeb.register_uri :post, @req, body: res
37
+
38
+ @doc.save
39
+
40
+ assert_equal [], @doc.errors
41
+ assert_equal [], @doc.docs
42
+ end
43
+
44
+ end
@@ -173,6 +173,33 @@ class DocumentTest < ActiveSupport::TestCase
173
173
  assert last_2.kind_of?(Dolly::Collection)
174
174
  end
175
175
 
176
+ test 'delete method on document' do
177
+ resp = {ok: true, id: "foo_bar/1", rev: "FF0000"}
178
+ FakeWeb.register_uri :delete, /http:\/\/localhost:5984\/test\/foo_bar%2F[^\?]+\?rev=.+/, body: resp.to_json
179
+ doc = FooBar.find "1"
180
+ doc.destroy
181
+ end
182
+
183
+ test 'soft delete on document' do
184
+ skip "delete should be able to do soft deletion."
185
+ end
186
+
187
+ test 'query custom view' do
188
+ FakeWeb.register_uri :get, "http://localhost:5984/test/_design/test/_view/custom_view?key=1&include_docs=true", body: @multi_resp.to_json
189
+ f = FooBar.find_with "test", "custom_view", key: 1
190
+ assert_equal 2, f.count
191
+ f.each{ |d| assert d.kind_of?(FooBar) }
192
+ end
193
+
194
+ test 'new document have id' do
195
+ foo = FooBar.new
196
+ assert_equal 0, (foo.id =~ /^foo_bar\/[abcdef0-9]+/i)
197
+ end
198
+
199
+ test 'Dolly::Document have bulk_document instance' do
200
+ assert Dolly::Document.bulk_document.kind_of?(Dolly::BulkDocument)
201
+ end
202
+
176
203
  private
177
204
  def build_view_response properties
178
205
  rows = properties.map.with_index do |v, i|