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 +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|
|