dolly 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/Rakefile +11 -0
- data/lib/dolly.rb +51 -0
- data/lib/dolly/collection.rb +57 -0
- data/lib/dolly/connection.rb +15 -0
- data/lib/dolly/document.rb +114 -0
- data/lib/dolly/property.rb +67 -0
- data/lib/dolly/representations/collection_representation.rb +15 -0
- data/lib/dolly/representations/document_representation.rb +19 -0
- data/lib/dolly/request.rb +58 -0
- data/lib/dolly/version.rb +3 -0
- data/lib/exceptions/dolly.rb +12 -0
- data/test/dolly_test.rb +147 -0
- data/test/dummy/README.rdoc +28 -0
- data/test/dummy/Rakefile +6 -0
- data/test/dummy/app/assets/javascripts/application.js +13 -0
- data/test/dummy/app/assets/stylesheets/application.css +13 -0
- data/test/dummy/app/controllers/application_controller.rb +5 -0
- data/test/dummy/app/helpers/application_helper.rb +2 -0
- data/test/dummy/app/views/layouts/application.html.erb +14 -0
- data/test/dummy/bin/bundle +3 -0
- data/test/dummy/bin/rails +4 -0
- data/test/dummy/bin/rake +4 -0
- data/test/dummy/config.ru +4 -0
- data/test/dummy/config/application.rb +27 -0
- data/test/dummy/config/boot.rb +5 -0
- data/test/dummy/config/couchdb.yml +15 -0
- data/test/dummy/config/environment.rb +5 -0
- data/test/dummy/config/environments/development.rb +29 -0
- data/test/dummy/config/environments/production.rb +80 -0
- data/test/dummy/config/environments/test.rb +36 -0
- data/test/dummy/config/initializers/backtrace_silencers.rb +7 -0
- data/test/dummy/config/initializers/filter_parameter_logging.rb +4 -0
- data/test/dummy/config/initializers/inflections.rb +16 -0
- data/test/dummy/config/initializers/mime_types.rb +5 -0
- data/test/dummy/config/initializers/secret_token.rb +12 -0
- data/test/dummy/config/initializers/session_store.rb +3 -0
- data/test/dummy/config/initializers/wrap_parameters.rb +14 -0
- data/test/dummy/config/locales/en.yml +23 -0
- data/test/dummy/config/routes.rb +56 -0
- data/test/dummy/lib/couch_rest_adapter/railtie.rb +10 -0
- data/test/dummy/log/test.log +12660 -0
- data/test/dummy/public/404.html +58 -0
- data/test/dummy/public/422.html +58 -0
- data/test/dummy/public/500.html +57 -0
- data/test/dummy/public/favicon.ico +0 -0
- data/test/factories/factories.rb +8 -0
- data/test/test_helper.rb +37 -0
- metadata +239 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: ea68df6004ba83c19215952ce9a3ce9e19169ec3
|
4
|
+
data.tar.gz: 835ecc53373d834ff7a8c05173200911490d7e4e
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 40468de07bee1d6412e8dcae7b96f06d85ab9a7c8e1c7a41158a648f922cbb08b0b9c7ac3e54b30bf98a23647597f30d1c603dafabe784db61997323f5e12a9c
|
7
|
+
data.tar.gz: 30ddf8c41e68c48645f899d145aa439f6c4bde64218f82e048ba3af8aa85dc614fe7c18eeda6973faee88345cea4932c1ad07b4d4671c068d71c5416a4aa7f18
|
data/Rakefile
ADDED
data/lib/dolly.rb
ADDED
@@ -0,0 +1,51 @@
|
|
1
|
+
require "dolly/version"
|
2
|
+
require "dolly/document"
|
3
|
+
require "dolly/property"
|
4
|
+
|
5
|
+
module Dolly
|
6
|
+
|
7
|
+
class Base
|
8
|
+
include Dolly::Document
|
9
|
+
attr_accessor :rows, :doc, :key
|
10
|
+
|
11
|
+
def rows= col
|
12
|
+
col.each{ |r| @doc = r['doc'] }
|
13
|
+
_properties.each do |p|
|
14
|
+
self.send "#{p.name}=", doc[p.name]
|
15
|
+
end
|
16
|
+
@rows = col
|
17
|
+
end
|
18
|
+
|
19
|
+
def self.property *ary
|
20
|
+
options = ary.pop if ary.last.kind_of? Hash
|
21
|
+
options ||= {}
|
22
|
+
@properties ||= []
|
23
|
+
|
24
|
+
@properties += ary.map do |name|
|
25
|
+
options.merge!({name: name})
|
26
|
+
property = Property.new(options)
|
27
|
+
|
28
|
+
define_method(name) do
|
29
|
+
property.value = @doc[name.to_s]
|
30
|
+
property.value
|
31
|
+
end
|
32
|
+
|
33
|
+
define_method("#{name}=") do |val|
|
34
|
+
@doc ||={}
|
35
|
+
@doc[name.to_s] = val
|
36
|
+
end
|
37
|
+
|
38
|
+
define_method(:"#{name}?") { send name } if property.boolean?
|
39
|
+
define_method("[]") {|n| send n.to_sym}
|
40
|
+
|
41
|
+
property
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
private
|
46
|
+
def _properties
|
47
|
+
self.class.properties
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
require 'dolly/representations/collection_representation'
|
2
|
+
|
3
|
+
module Dolly
|
4
|
+
class Collection
|
5
|
+
extend Forwardable
|
6
|
+
attr_accessor :rows
|
7
|
+
attr_writer :json, :docs_class
|
8
|
+
|
9
|
+
def_delegators :@set, :clear, :empty?, :length, :+, :-
|
10
|
+
|
11
|
+
def initialize str, docs_class
|
12
|
+
@set = Set.new
|
13
|
+
@docs_class = docs_class
|
14
|
+
@json = str
|
15
|
+
end
|
16
|
+
|
17
|
+
def map &block
|
18
|
+
load if empty?
|
19
|
+
@set.collect &block
|
20
|
+
end
|
21
|
+
|
22
|
+
def each &block
|
23
|
+
load if empty?
|
24
|
+
@set.each &block
|
25
|
+
#TODO: returning nil to avoid extra time serializing set.
|
26
|
+
nil
|
27
|
+
end
|
28
|
+
|
29
|
+
def to_a
|
30
|
+
load if empty?
|
31
|
+
@set.to_a
|
32
|
+
end
|
33
|
+
|
34
|
+
def count
|
35
|
+
load if empty?
|
36
|
+
length
|
37
|
+
end
|
38
|
+
|
39
|
+
def load
|
40
|
+
@set = self.extend(representation).from_json(json).rows
|
41
|
+
end
|
42
|
+
|
43
|
+
private
|
44
|
+
def representation
|
45
|
+
Representations::CollectionRepresentation.config(docs_class)
|
46
|
+
end
|
47
|
+
|
48
|
+
def docs_class
|
49
|
+
@docs_class
|
50
|
+
end
|
51
|
+
|
52
|
+
def json
|
53
|
+
@json
|
54
|
+
end
|
55
|
+
|
56
|
+
end
|
57
|
+
end
|
@@ -0,0 +1,114 @@
|
|
1
|
+
require "active_model/naming"
|
2
|
+
require "dolly/connection"
|
3
|
+
require "dolly/collection"
|
4
|
+
require "dolly/representations/document_representation"
|
5
|
+
require "dolly/representations/collection_representation"
|
6
|
+
require "exceptions/dolly"
|
7
|
+
|
8
|
+
module Dolly
|
9
|
+
module Document
|
10
|
+
|
11
|
+
def id
|
12
|
+
doc['_id']
|
13
|
+
end
|
14
|
+
|
15
|
+
def rev
|
16
|
+
doc['_rev']
|
17
|
+
end
|
18
|
+
|
19
|
+
def save
|
20
|
+
response = database.put(id_as_resource, self.doc.to_json)
|
21
|
+
obj = JSON::parse response.parsed_response
|
22
|
+
doc['_rev'] = obj['rev'] if obj['rev']
|
23
|
+
obj['ok']
|
24
|
+
end
|
25
|
+
|
26
|
+
def save!
|
27
|
+
#TODO: decide how to handle validations...
|
28
|
+
save
|
29
|
+
end
|
30
|
+
|
31
|
+
def from_json string
|
32
|
+
self.class.new.extend(representation).from_json( string )
|
33
|
+
end
|
34
|
+
|
35
|
+
def database
|
36
|
+
self.class.database
|
37
|
+
end
|
38
|
+
|
39
|
+
def id_as_resource
|
40
|
+
CGI::escape id
|
41
|
+
end
|
42
|
+
|
43
|
+
def representation
|
44
|
+
Representations::DocumentRepresentation.config(self.class.properties)
|
45
|
+
end
|
46
|
+
|
47
|
+
module ClassMethods
|
48
|
+
include ActiveModel::Naming
|
49
|
+
include Dolly::Connection
|
50
|
+
attr_accessor :properties
|
51
|
+
|
52
|
+
DESIGN_DOC = "dolly"
|
53
|
+
|
54
|
+
def find *ids
|
55
|
+
response = default_view(keys: ids.map{|id| namespace(id)}).parsed_response
|
56
|
+
ids.count > 1 ? Collection.new(response, name.constantize) : self.new.from_json(response)
|
57
|
+
rescue NoMethodError => err
|
58
|
+
if err.message == "undefined method `[]' for nil:NilClass"
|
59
|
+
raise Dolly::ResourceNotFound
|
60
|
+
else
|
61
|
+
raise
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
def all
|
66
|
+
Collection.new default_view.parsed_response, name.constantize
|
67
|
+
end
|
68
|
+
|
69
|
+
def default_view options = {}
|
70
|
+
view default_doc, options
|
71
|
+
end
|
72
|
+
|
73
|
+
def view doc, options = {}
|
74
|
+
options.merge! include_docs: true
|
75
|
+
database.get doc, options
|
76
|
+
end
|
77
|
+
|
78
|
+
def default_doc
|
79
|
+
"#{design_doc}/_view/#{name_paramitized}"
|
80
|
+
end
|
81
|
+
|
82
|
+
def design_doc
|
83
|
+
"_design/#{@@design_doc || DESIGN_DOC}"
|
84
|
+
end
|
85
|
+
|
86
|
+
def set_design_doc value
|
87
|
+
@@design_doc = value
|
88
|
+
end
|
89
|
+
|
90
|
+
def name_paramitized
|
91
|
+
model_name.param_key
|
92
|
+
end
|
93
|
+
|
94
|
+
def namespace id
|
95
|
+
return id if id =~ /^#{name_paramitized}/
|
96
|
+
"#{name_paramitized}/#{id}"
|
97
|
+
end
|
98
|
+
|
99
|
+
def timestamps!
|
100
|
+
%i/created_at updated_at/.each do |method|
|
101
|
+
define_method(method){ @doc[method.to_s] ||= DateTime.now }
|
102
|
+
define_method(:"[]"){|m| self.send(m.to_sym) }
|
103
|
+
define_method(:"[]="){|m, v| self.send(:"#{m}=", v) }
|
104
|
+
define_method(:"#{method}="){|val| @doc[method.to_s] = val }
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
end
|
109
|
+
|
110
|
+
def self.included(base)
|
111
|
+
base.extend ClassMethods
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
@@ -0,0 +1,67 @@
|
|
1
|
+
module Dolly
|
2
|
+
class Property
|
3
|
+
attr_writer :value
|
4
|
+
attr_accessor :name
|
5
|
+
|
6
|
+
def initialize opts = {}
|
7
|
+
@class_name = opts.delete(:class_name) if opts.present?
|
8
|
+
@name = opts.delete(:name).to_s
|
9
|
+
@default = opts.delete(:default)
|
10
|
+
warn 'There are some unprocesed options' if opts.present?
|
11
|
+
end
|
12
|
+
|
13
|
+
def value
|
14
|
+
return @default if @value.nil?
|
15
|
+
return @value unless self_klass
|
16
|
+
|
17
|
+
klass_sym = :"#{self_klass.name.underscore}_#{__method__}"
|
18
|
+
|
19
|
+
return self_klass.new @value unless self.respond_to?(klass_sym)
|
20
|
+
|
21
|
+
self.send klass_sym
|
22
|
+
end
|
23
|
+
|
24
|
+
def array_value
|
25
|
+
@value.to_a
|
26
|
+
end
|
27
|
+
|
28
|
+
def hash_value
|
29
|
+
@value.to_h
|
30
|
+
end
|
31
|
+
|
32
|
+
def string_value
|
33
|
+
@value.to_s
|
34
|
+
end
|
35
|
+
|
36
|
+
def integer_value
|
37
|
+
@value.to_i
|
38
|
+
end
|
39
|
+
|
40
|
+
def float_value
|
41
|
+
@value.to_f
|
42
|
+
end
|
43
|
+
|
44
|
+
def true_class_value
|
45
|
+
truthy_value?
|
46
|
+
end
|
47
|
+
|
48
|
+
def false_class_value
|
49
|
+
truthy_value?
|
50
|
+
end
|
51
|
+
|
52
|
+
def boolean?
|
53
|
+
self_klass == TrueClass || self_klass == FalseClass
|
54
|
+
end
|
55
|
+
|
56
|
+
private
|
57
|
+
def truthy_value?
|
58
|
+
@value =~ /true/ || @value === true
|
59
|
+
end
|
60
|
+
|
61
|
+
def self_klass
|
62
|
+
return unless @class_name
|
63
|
+
@class_name.is_a?(Class)? @class_name : @class_name.constantize
|
64
|
+
end
|
65
|
+
|
66
|
+
end
|
67
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
require 'representable/json'
|
2
|
+
|
3
|
+
module Dolly
|
4
|
+
module Representations
|
5
|
+
module CollectionRepresentation
|
6
|
+
include Representable::JSON
|
7
|
+
|
8
|
+
def self.config docs_class
|
9
|
+
self.collection :rows, extend: DocumentRepresentation, class: docs_class
|
10
|
+
self
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
@@ -0,0 +1,19 @@
|
|
1
|
+
require 'representable/json'
|
2
|
+
|
3
|
+
module Dolly
|
4
|
+
module Representations
|
5
|
+
module DocumentRepresentation
|
6
|
+
include Representable::JSON
|
7
|
+
|
8
|
+
property :rows
|
9
|
+
property :doc
|
10
|
+
|
11
|
+
def self.config properties
|
12
|
+
properties.each do |p|
|
13
|
+
self.property p.name
|
14
|
+
end
|
15
|
+
self
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
require "httparty"
|
2
|
+
|
3
|
+
module Dolly
|
4
|
+
|
5
|
+
class Request
|
6
|
+
include HTTParty
|
7
|
+
DEFAULT_HOST = 'localhost'
|
8
|
+
DEFAULT_PORT = '5984'
|
9
|
+
|
10
|
+
attr_accessor :database_name, :host, :port
|
11
|
+
|
12
|
+
def initialize options = {}
|
13
|
+
@host = options[:host] || DEFAULT_HOST
|
14
|
+
@port = options[:port] || DEFAULT_PORT
|
15
|
+
@database_name = options[:database_name]
|
16
|
+
|
17
|
+
self.class.base_uri "#{protocol}://#{host}:#{port}"
|
18
|
+
end
|
19
|
+
|
20
|
+
def get resource, data
|
21
|
+
request :get, resource, {query: values_to_json(data)}
|
22
|
+
end
|
23
|
+
|
24
|
+
def put resource, data
|
25
|
+
request :put, resource, {body: data}
|
26
|
+
end
|
27
|
+
|
28
|
+
def delete resource
|
29
|
+
request :delete, resource, {}
|
30
|
+
end
|
31
|
+
|
32
|
+
def protocol
|
33
|
+
@protocol || 'http'
|
34
|
+
end
|
35
|
+
|
36
|
+
private
|
37
|
+
def values_to_json hash
|
38
|
+
hash.reduce({}){|h, v| h[v.first] = v.last.to_json; h}
|
39
|
+
end
|
40
|
+
|
41
|
+
def full_path resource
|
42
|
+
"/#{database_name}/#{resource}"
|
43
|
+
end
|
44
|
+
|
45
|
+
def request method, resource, data = nil
|
46
|
+
headers = { 'Content-Type' => 'application/json' }
|
47
|
+
response = self.class.send method, full_path(resource), data.merge(headers: headers)
|
48
|
+
if response.code == 404
|
49
|
+
raise Dolly::ResourceNotFound
|
50
|
+
elsif (500..600).include? response.code
|
51
|
+
raise Dolly::ServerError
|
52
|
+
else
|
53
|
+
response
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
end
|
data/test/dolly_test.rb
ADDED
@@ -0,0 +1,147 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
class FooBar < Dolly::Base
|
4
|
+
database_name 'test'
|
5
|
+
set_design_doc 'test'
|
6
|
+
|
7
|
+
property :foo, :bar
|
8
|
+
property :with_default, default: 1
|
9
|
+
property :boolean, class_name: TrueClass, default: true
|
10
|
+
|
11
|
+
timestamps!
|
12
|
+
end
|
13
|
+
|
14
|
+
class DollyTest < ActiveSupport::TestCase
|
15
|
+
|
16
|
+
def setup
|
17
|
+
data = {foo: 'Foo', bar: 'Bar', type: 'foo_bar'}
|
18
|
+
all_docs = [ {foo: 'Foo B', bar: 'Bar B', type: 'foo_bar'}, {foo: 'Foo A', bar: 'Bar A', type: 'foo_bar'}]
|
19
|
+
|
20
|
+
view_resp = build_view_response [data]
|
21
|
+
empty_resp = build_view_response []
|
22
|
+
@multi_resp = build_view_response all_docs
|
23
|
+
|
24
|
+
build_request ["foo_bar/1"], view_resp
|
25
|
+
build_request ["foo_bar/2"], empty_resp
|
26
|
+
build_request ["foo_bar/1","foo_bar/2"], @multi_resp
|
27
|
+
build_request [], @multi_resp
|
28
|
+
end
|
29
|
+
|
30
|
+
test 'with timestamps!' do
|
31
|
+
later = DateTime.new 1963, 1, 1
|
32
|
+
now = DateTime.now
|
33
|
+
DateTime.stubs(:now).returns(now)
|
34
|
+
foo = FooBar.find "1"
|
35
|
+
assert_equal now, foo.created_at
|
36
|
+
assert_equal now, foo['created_at']
|
37
|
+
assert_equal now, foo.updated_at
|
38
|
+
assert foo.updated_at = later
|
39
|
+
assert_equal later, foo.updated_at
|
40
|
+
assert foo['created_at'] = later
|
41
|
+
assert_equal later, foo['created_at']
|
42
|
+
assert_equal foo['created_at'], foo.created_at
|
43
|
+
end
|
44
|
+
|
45
|
+
test 'empty find should raise error' do
|
46
|
+
assert_raise Dolly::ResourceNotFound do
|
47
|
+
FakeWeb.register_uri :get, "http://localhost:5984/test/_design/test/_view/foo_bar?keys=%5B%5D&include_docs=true", :status => ["404", "Not Found"]
|
48
|
+
foo = FooBar.find
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
test 'error on server raises Dolly::ServerError' do
|
53
|
+
assert_raise Dolly::ServerError do
|
54
|
+
FakeWeb.register_uri :get, "http://localhost:5984/test/_design/test/_view/foo_bar?keys=%5B%5D&include_docs=true", :status => ["500", "Error"]
|
55
|
+
foo = FooBar.find
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
test 'will have object with boolean? method' do
|
60
|
+
foo = FooBar.find "1"
|
61
|
+
assert_equal true, foo.boolean?
|
62
|
+
foo.boolean = false
|
63
|
+
assert_equal false, foo['boolean']
|
64
|
+
assert_equal false, foo.boolean?
|
65
|
+
end
|
66
|
+
|
67
|
+
test 'find will get a FooBar document' do
|
68
|
+
foo = FooBar.find "1"
|
69
|
+
assert_equal true, foo.kind_of?(FooBar)
|
70
|
+
end
|
71
|
+
|
72
|
+
test 'will have key properties' do
|
73
|
+
foo = FooBar.find "1"
|
74
|
+
assert_equal 'Foo', foo['foo']
|
75
|
+
assert_equal 'Bar', foo['bar']
|
76
|
+
end
|
77
|
+
|
78
|
+
test 'will have only set properties' do
|
79
|
+
foo = FooBar.find "1"
|
80
|
+
assert_equal 'Foo', foo.foo
|
81
|
+
assert_equal 'Bar', foo.bar
|
82
|
+
assert_equal false, foo.respond_to?(:type)
|
83
|
+
end
|
84
|
+
|
85
|
+
test 'with default will return default value on nil' do
|
86
|
+
foo = FooBar.find "1"
|
87
|
+
assert_equal 1, foo.with_default
|
88
|
+
end
|
89
|
+
|
90
|
+
test 'default will be avoerwriten' do
|
91
|
+
foo = FooBar.find "1"
|
92
|
+
assert_equal 1, foo.with_default
|
93
|
+
assert foo.with_default = 30
|
94
|
+
assert_equal 30, foo.with_default
|
95
|
+
end
|
96
|
+
|
97
|
+
test 'getting not found document' do
|
98
|
+
assert_raise Dolly::ResourceNotFound do
|
99
|
+
missing = FooBar.find "2"
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
test 'find with multiple ids will return Collection' do
|
104
|
+
many = FooBar.find "1", "2"
|
105
|
+
assert_equal true, many.kind_of?(Dolly::Collection)
|
106
|
+
end
|
107
|
+
|
108
|
+
test 'all will get 2 docs' do
|
109
|
+
all = FooBar.all
|
110
|
+
assert_equal 2, all.count
|
111
|
+
end
|
112
|
+
|
113
|
+
test 'all will get FooBar documents' do
|
114
|
+
all = FooBar.all
|
115
|
+
all.each{ |d| assert_equal true, d.kind_of?(FooBar) }
|
116
|
+
end
|
117
|
+
|
118
|
+
test 'multi response with right data' do
|
119
|
+
all = FooBar.all
|
120
|
+
ids = @multi_resp[:rows].map{|d| d[:id]}
|
121
|
+
foos = @multi_resp[:rows].map{|d| d[:doc][:foo]}
|
122
|
+
bars = @multi_resp[:rows].map{|d| d[:doc][:bar]}
|
123
|
+
all.each do |d|
|
124
|
+
assert foos.include?(d.foo)
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
private
|
129
|
+
def build_view_response properties
|
130
|
+
rows = properties.map.with_index do |v, i|
|
131
|
+
{
|
132
|
+
id: "foo_bar/#{i}",
|
133
|
+
key: "foo_bar",
|
134
|
+
value: 1,
|
135
|
+
doc: {_id: "foo_bar/#{i}", _rev: SecureRandom.hex}.merge!(v)
|
136
|
+
}
|
137
|
+
end
|
138
|
+
{total_rows: properties.count, offset:0, rows: rows}
|
139
|
+
end
|
140
|
+
|
141
|
+
def build_request keys, body, view_name = 'foo_bar'
|
142
|
+
base_url = "http://localhost:5984/test/_design/test/_view/foo_bar"
|
143
|
+
query = "keys=#{CGI::escape keys.to_s.gsub(' ','')}&" unless keys.blank?
|
144
|
+
FakeWeb.register_uri :get, "#{base_url}?#{query.to_s}include_docs=true", body: body.to_json
|
145
|
+
end
|
146
|
+
|
147
|
+
end
|