dolly 0.4.0 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
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|