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 +4 -4
- data/lib/dolly/bulk_document.rb +85 -0
- data/lib/dolly/bulk_error.rb +16 -0
- data/lib/dolly/collection.rb +15 -7
- data/lib/dolly/connection.rb +9 -0
- data/lib/dolly/document.rb +18 -6
- data/lib/dolly/interpreter.rb +5 -0
- data/lib/dolly/query.rb +7 -3
- data/lib/dolly/request.rb +7 -1
- data/lib/dolly/version.rb +1 -1
- data/test/bulk_document_test.rb +44 -0
- data/test/document_test.rb +27 -0
- data/test/dummy/log/test.log +11913 -0
- metadata +7 -19
- data/lib/dolly/representations/collection_representation.rb +0 -20
- data/lib/dolly/representations/document_representation.rb +0 -22
- data/lib/dolly/representations/tools.rb +0 -16
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 94c8771287f56c3dc8037d0847c45cde37301bf1
|
4
|
+
data.tar.gz: 60819593da81aa2312205e940753e8358c72d65d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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
|
data/lib/dolly/collection.rb
CHANGED
@@ -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
|
-
|
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
|
data/lib/dolly/connection.rb
CHANGED
@@ -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
|
data/lib/dolly/document.rb
CHANGED
@@ -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
|
-
|
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
|
-
|
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
|
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
|
-
|
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
@@ -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
|
data/test/document_test.rb
CHANGED
@@ -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|
|