dolly 1.1.7 → 3.1.1
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 +5 -5
- data/README.md +78 -0
- data/lib/dolly/attachment.rb +29 -0
- data/lib/dolly/bulk_document.rb +27 -26
- data/lib/dolly/class_methods_delegation.rb +15 -0
- data/lib/dolly/collection.rb +32 -65
- data/lib/dolly/configuration.rb +35 -10
- data/lib/dolly/connection.rb +93 -22
- data/lib/dolly/depracated_database.rb +24 -0
- data/lib/dolly/document.rb +61 -208
- data/lib/dolly/document_creation.rb +27 -0
- data/lib/dolly/document_state.rb +66 -0
- data/lib/dolly/document_type.rb +47 -0
- data/lib/dolly/exceptions.rb +32 -0
- data/lib/dolly/framework_helper.rb +7 -0
- data/lib/dolly/identity_properties.rb +29 -0
- data/lib/dolly/mango.rb +156 -0
- data/lib/dolly/mango_index.rb +73 -0
- data/lib/dolly/properties.rb +36 -0
- data/lib/dolly/property.rb +76 -46
- data/lib/dolly/property_manager.rb +53 -0
- data/lib/dolly/property_set.rb +23 -0
- data/lib/dolly/query.rb +63 -75
- data/lib/dolly/query_arguments.rb +35 -0
- data/lib/dolly/request.rb +12 -107
- data/lib/dolly/request_header.rb +26 -0
- data/lib/dolly/timestamp.rb +24 -0
- data/lib/dolly/version.rb +1 -1
- data/lib/dolly/view_query.rb +21 -0
- data/lib/dolly.rb +2 -23
- data/lib/{dolly → railties}/railtie.rb +2 -1
- data/lib/refinements/hash_refinements.rb +27 -0
- data/lib/refinements/string_refinements.rb +28 -0
- data/lib/tasks/db.rake +27 -4
- data/test/bulk_document_test.rb +8 -5
- data/test/document_test.rb +130 -95
- data/test/document_type_test.rb +28 -0
- data/test/dummy/config/initializers/filter_parameter_logging.rb +4 -0
- data/test/dummy/log/test.log +46417 -46858
- data/test/inheritance_test.rb +23 -0
- data/test/mango_index_test.rb +64 -0
- data/test/mango_test.rb +273 -0
- data/test/property_manager_test.rb +18 -0
- data/test/test_helper.rb +63 -18
- data/test/view_query_test.rb +27 -0
- metadata +67 -140
- data/Rakefile +0 -11
- data/lib/dolly/bulk_error.rb +0 -16
- data/lib/dolly/db_config.rb +0 -20
- data/lib/dolly/interpreter.rb +0 -5
- data/lib/dolly/logger.rb +0 -9
- data/lib/dolly/name_space.rb +0 -28
- data/lib/dolly/timestamps.rb +0 -21
- data/lib/exceptions/dolly.rb +0 -47
- data/test/collection_test.rb +0 -59
- data/test/configuration_test.rb +0 -9
- data/test/dummy/README.rdoc +0 -28
- data/test/dummy/Rakefile +0 -6
- data/test/dummy/app/assets/javascripts/application.js +0 -13
- data/test/dummy/app/assets/stylesheets/application.css +0 -13
- data/test/dummy/app/controllers/application_controller.rb +0 -5
- data/test/dummy/app/helpers/application_helper.rb +0 -2
- data/test/dummy/app/views/layouts/application.html.erb +0 -14
- data/test/dummy/bin/bundle +0 -3
- data/test/dummy/bin/rails +0 -4
- data/test/dummy/bin/rake +0 -4
- data/test/dummy/config/application.rb +0 -27
- data/test/dummy/config/boot.rb +0 -5
- data/test/dummy/config/couchdb.yml +0 -13
- data/test/dummy/config/environment.rb +0 -5
- data/test/dummy/config/environments/development.rb +0 -29
- data/test/dummy/config/environments/production.rb +0 -80
- data/test/dummy/config/environments/test.rb +0 -36
- data/test/dummy/config/initializers/backtrace_silencers.rb +0 -7
- data/test/dummy/config/initializers/inflections.rb +0 -16
- data/test/dummy/config/initializers/mime_types.rb +0 -5
- data/test/dummy/config/initializers/secret_token.rb +0 -12
- data/test/dummy/config/initializers/session_store.rb +0 -3
- data/test/dummy/config/initializers/wrap_parameters.rb +0 -14
- data/test/dummy/config/locales/en.yml +0 -23
- data/test/dummy/config/routes.rb +0 -56
- data/test/dummy/config.ru +0 -4
- data/test/dummy/lib/couch_rest_adapter/railtie.rb +0 -10
- data/test/dummy/public/404.html +0 -58
- data/test/dummy/public/422.html +0 -58
- data/test/dummy/public/500.html +0 -57
- data/test/dummy/public/favicon.ico +0 -0
- data/test/factories/factories.rb +0 -8
- data/test/request_test.rb +0 -25
@@ -0,0 +1,73 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'forwardable'
|
4
|
+
require 'dolly/document'
|
5
|
+
|
6
|
+
module Dolly
|
7
|
+
class MangoIndex
|
8
|
+
class << self
|
9
|
+
extend Forwardable
|
10
|
+
|
11
|
+
ALL_DOCS = '_all_docs'
|
12
|
+
DESIGN = '_index'
|
13
|
+
ROWS_KEY = :rows
|
14
|
+
DESIGN_PREFIX = '_design/'
|
15
|
+
|
16
|
+
def_delegators :connection, :get, :post
|
17
|
+
|
18
|
+
def all
|
19
|
+
get(DESIGN)[:indexes]
|
20
|
+
end
|
21
|
+
|
22
|
+
def create(name, fields, type = 'json')
|
23
|
+
post(DESIGN, build_index_structure(name, fields, type))
|
24
|
+
end
|
25
|
+
|
26
|
+
def create_in_database(database, name, fields, type = 'json')
|
27
|
+
connection_for_database(database).post(DESIGN, build_index_structure(name, fields, type))
|
28
|
+
end
|
29
|
+
|
30
|
+
def find_by_fields(fields)
|
31
|
+
rows = get(ALL_DOCS, key: key_from_fields(fields))[ROWS_KEY]
|
32
|
+
(rows && rows.any?)
|
33
|
+
end
|
34
|
+
|
35
|
+
def delete_all
|
36
|
+
all.each do |index_doc|
|
37
|
+
next if index_doc[:ddoc].nil?
|
38
|
+
delete(index_doc)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def delete(index_doc)
|
43
|
+
resource = "#{DESIGN}/#{index_doc[:ddoc]}/json/#{index_doc[:name]}"
|
44
|
+
connection.delete(resource, escape: false)
|
45
|
+
end
|
46
|
+
|
47
|
+
private
|
48
|
+
|
49
|
+
def connection_for_database(database)
|
50
|
+
Dolly::Connection.new(database.to_sym, Rails.env || :development)
|
51
|
+
end
|
52
|
+
|
53
|
+
def connection
|
54
|
+
@connection ||= Dolly::Document.connection
|
55
|
+
end
|
56
|
+
|
57
|
+
def build_index_structure(name, fields, type)
|
58
|
+
{
|
59
|
+
ddoc: key_from_fields(fields).gsub(DESIGN_PREFIX, ''),
|
60
|
+
index: {
|
61
|
+
fields: fields
|
62
|
+
},
|
63
|
+
name: name,
|
64
|
+
type: type
|
65
|
+
}
|
66
|
+
end
|
67
|
+
|
68
|
+
def key_from_fields(fields)
|
69
|
+
"#{DESIGN_PREFIX}index_#{fields.join('_')}"
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
require 'dolly/property_set'
|
2
|
+
require 'dolly/property'
|
3
|
+
|
4
|
+
module Dolly
|
5
|
+
module Properties
|
6
|
+
SPECIAL_KEYS = %i[_id _rev]
|
7
|
+
|
8
|
+
def property *opts, class_name: nil, default: nil
|
9
|
+
opts.each do |opt|
|
10
|
+
|
11
|
+
properties << (prop = Property.new(opt, class_name, default))
|
12
|
+
send(:attr_reader, opt)
|
13
|
+
|
14
|
+
define_method(:"#{opt}=") { |value| write_attribute(opt, value) }
|
15
|
+
define_method(:"#{opt}?") { send(opt) } if prop.boolean?
|
16
|
+
define_method(:"[]") {|name| send(name) }
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def properties
|
21
|
+
@properties ||= PropertySet.new
|
22
|
+
end
|
23
|
+
|
24
|
+
def all_property_keys
|
25
|
+
properties.map(&:key) + SPECIAL_KEYS
|
26
|
+
end
|
27
|
+
|
28
|
+
def property_keys
|
29
|
+
all_property_keys - SPECIAL_KEYS
|
30
|
+
end
|
31
|
+
|
32
|
+
def property_clean_doc(doc)
|
33
|
+
doc.reject { |key, _value| property_keys.exclude?(key.to_sym) }
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
data/lib/dolly/property.rb
CHANGED
@@ -1,85 +1,115 @@
|
|
1
|
+
require 'refinements/string_refinements'
|
2
|
+
|
1
3
|
module Dolly
|
2
4
|
class Property
|
3
|
-
|
4
|
-
|
5
|
-
attr_reader :class_name, :default
|
5
|
+
attr_reader :key, :class_name, :default
|
6
|
+
CANT_CLONE = [NilClass, TrueClass, FalseClass, Integer]
|
6
7
|
|
7
|
-
|
8
|
+
using StringRefinements
|
8
9
|
|
9
|
-
def initialize
|
10
|
-
@
|
11
|
-
@
|
12
|
-
@
|
13
|
-
@default = @default.clone if @default && CANT_CLONE.none? { |klass| @default.is_a? klass }
|
14
|
-
@value = @default if @default
|
15
|
-
warn 'There are some unprocessed options!' if opts.present?
|
10
|
+
def initialize(key, class_name, default = nil)
|
11
|
+
@key = key
|
12
|
+
@default = default
|
13
|
+
@class_name = class_name
|
16
14
|
end
|
17
15
|
|
18
|
-
def value
|
19
|
-
|
20
|
-
return
|
21
|
-
return
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
return self_klass.new @value unless self.respond_to?(klass_sym)
|
16
|
+
def cast_value(value)
|
17
|
+
return set_default if value.nil?
|
18
|
+
return value unless class_name
|
19
|
+
return custom_class(value) unless respond_to?(klass_sym)
|
20
|
+
send(klass_sym, value)
|
21
|
+
end
|
26
22
|
|
27
|
-
|
23
|
+
def custom_class(value)
|
24
|
+
value = value.is_a?(Hash) ? value.symbolize_keys : value
|
25
|
+
self_klass.new(value)
|
28
26
|
end
|
29
27
|
|
30
|
-
def
|
31
|
-
|
28
|
+
def boolean?
|
29
|
+
[TrueClass, FalseClass].include?(class_name)
|
32
30
|
end
|
33
31
|
|
34
|
-
def
|
35
|
-
|
32
|
+
def string_value(value)
|
33
|
+
value.to_s
|
36
34
|
end
|
37
35
|
|
38
|
-
def
|
39
|
-
|
36
|
+
def hash_value(value)
|
37
|
+
value.to_h
|
40
38
|
end
|
41
39
|
|
42
|
-
def
|
43
|
-
|
40
|
+
def hash_with_indifferent_access_value(value)
|
41
|
+
if defined?(Rails)
|
42
|
+
value.to_h.with_indifferent_access
|
43
|
+
else
|
44
|
+
value.to_h
|
45
|
+
end
|
44
46
|
end
|
45
47
|
|
46
|
-
def
|
47
|
-
|
48
|
+
def integer_value(value)
|
49
|
+
value.to_i
|
48
50
|
end
|
49
51
|
|
50
|
-
def
|
51
|
-
|
52
|
+
def float_value(value)
|
53
|
+
value.to_f
|
52
54
|
end
|
53
55
|
|
54
|
-
def
|
55
|
-
|
56
|
+
def date_value(value)
|
57
|
+
return value.to_date if value.respond_to?(:to_date)
|
58
|
+
Date.parse(value)
|
56
59
|
end
|
57
60
|
|
58
|
-
def
|
59
|
-
|
61
|
+
def time_value(value)
|
62
|
+
return value.to_time if value.respond_to?(:to_time)
|
63
|
+
DateTime.parse(value).to_time
|
60
64
|
end
|
61
65
|
|
62
|
-
def
|
63
|
-
|
66
|
+
def date_time_value(value)
|
67
|
+
return value.to_datetime if value.respond_to?(:to_datetime)
|
68
|
+
DateTime.parse(value)
|
64
69
|
end
|
65
70
|
|
66
|
-
def
|
67
|
-
truthy_value?
|
71
|
+
def true_class_value(value)
|
72
|
+
truthy_value?(value)
|
68
73
|
end
|
69
74
|
|
70
|
-
def
|
71
|
-
|
75
|
+
def false_class_value(value)
|
76
|
+
truthy_value?(value)
|
72
77
|
end
|
73
78
|
|
74
79
|
private
|
75
|
-
|
76
|
-
|
80
|
+
|
81
|
+
def truthy_value?(value)
|
82
|
+
value =~ /true/ || value === true
|
83
|
+
end
|
84
|
+
|
85
|
+
def klass_sym
|
86
|
+
klass_name = self_klass.
|
87
|
+
name.
|
88
|
+
split('::').
|
89
|
+
last.
|
90
|
+
underscore
|
91
|
+
|
92
|
+
:"#{klass_name}_value"
|
77
93
|
end
|
78
94
|
|
79
95
|
def self_klass
|
80
|
-
return unless
|
81
|
-
|
96
|
+
return unless class_name
|
97
|
+
return class_name if class_name.is_a?(Class)
|
98
|
+
Object.const_get class_name
|
99
|
+
end
|
100
|
+
|
101
|
+
def set_default
|
102
|
+
return unless default_present?
|
103
|
+
return default unless cant_clone_default?
|
104
|
+
default.clone
|
82
105
|
end
|
83
106
|
|
107
|
+
def cant_clone_default?
|
108
|
+
CANT_CLONE.none? { |klass| default.is_a? klass }
|
109
|
+
end
|
110
|
+
|
111
|
+
def default_present?
|
112
|
+
!default.nil?
|
113
|
+
end
|
84
114
|
end
|
85
115
|
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
module Dolly
|
2
|
+
module PropertyManager
|
3
|
+
def build_property(attributes)
|
4
|
+
assign_identity_properties(attributes)
|
5
|
+
assign_rev_properties(attributes)
|
6
|
+
|
7
|
+
lambda do |property|
|
8
|
+
name = property.key
|
9
|
+
next unless doc[name].nil?
|
10
|
+
write_attribute(name, attributes[name])
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
def update_attribute
|
15
|
+
lambda do |key, value|
|
16
|
+
raise InvalidProperty unless valid_property?(key)
|
17
|
+
write_attribute(key, value)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def write_attribute(key, value)
|
22
|
+
casted_value = set_property_value(key, value)
|
23
|
+
instance_variable_set(:"@#{key}", casted_value)
|
24
|
+
update_doc(key, casted_value)
|
25
|
+
end
|
26
|
+
|
27
|
+
def valid_property?(name)
|
28
|
+
properties.include?(name)
|
29
|
+
end
|
30
|
+
|
31
|
+
def update_doc(key, value)
|
32
|
+
doc[key] = value
|
33
|
+
end
|
34
|
+
|
35
|
+
def properties
|
36
|
+
self.class.properties
|
37
|
+
end
|
38
|
+
|
39
|
+
def set_property_value(key, value)
|
40
|
+
properties[key].cast_value(value)
|
41
|
+
end
|
42
|
+
|
43
|
+
def assign_identity_properties(opts = {})
|
44
|
+
id_presence = opts[:id] || opts[:_id] || opts['id'] || opts['_id']
|
45
|
+
self.id = id_presence if id_presence
|
46
|
+
end
|
47
|
+
|
48
|
+
def assign_rev_properties(opts = {})
|
49
|
+
rev_presence = opts[:rev] || opts [:_rev] || opts['rev'] || opts['_rev']
|
50
|
+
self.rev = rev_presence if rev_presence
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module Dolly
|
2
|
+
class PropertySet < Set
|
3
|
+
def include? key
|
4
|
+
keys.include?(key)
|
5
|
+
end
|
6
|
+
|
7
|
+
def <<(property)
|
8
|
+
return if include?(property.key)
|
9
|
+
super(property)
|
10
|
+
end
|
11
|
+
|
12
|
+
def [](key)
|
13
|
+
return detect {|property| property.key == key } if key.is_a?(Symbol)
|
14
|
+
super
|
15
|
+
end
|
16
|
+
|
17
|
+
private
|
18
|
+
|
19
|
+
def keys
|
20
|
+
map(&:key)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
data/lib/dolly/query.rb
CHANGED
@@ -1,85 +1,73 @@
|
|
1
|
-
require
|
2
|
-
require
|
3
|
-
require
|
4
|
-
require
|
1
|
+
require 'dolly/collection'
|
2
|
+
require 'dolly/query_arguments'
|
3
|
+
require 'dolly/document_type'
|
4
|
+
require 'refinements/string_refinements'
|
5
5
|
|
6
6
|
module Dolly
|
7
7
|
module Query
|
8
|
-
|
9
|
-
|
10
|
-
include Dolly::Connection
|
11
|
-
attr_accessor :properties
|
12
|
-
|
13
|
-
DESIGN_DOC = "dolly"
|
14
|
-
|
15
|
-
def find *keys
|
16
|
-
query_hash = { keys: keys.map{|key| namespace key} }
|
17
|
-
|
18
|
-
if keys.count > 1
|
19
|
-
build_collection( query_hash )
|
20
|
-
else
|
21
|
-
self.new.from_json( database.all_docs(query_hash).parsed_response )
|
22
|
-
end
|
23
|
-
rescue NoMethodError => err
|
24
|
-
if err.message == "undefined method `[]' for nil:NilClass"
|
25
|
-
raise Dolly::ResourceNotFound
|
26
|
-
else
|
27
|
-
raise
|
28
|
-
end
|
29
|
-
end
|
30
|
-
|
31
|
-
def default_query_args
|
32
|
-
{startkey: "#{name_paramitized}/", endkey: "#{name_paramitized}/\ufff0"}
|
33
|
-
end
|
34
|
-
|
35
|
-
def all
|
36
|
-
build_collection default_query_args
|
37
|
-
end
|
38
|
-
|
39
|
-
def first limit = 1
|
40
|
-
res = build_collection default_query_args.merge( limit: 1)
|
41
|
-
limit == 1 ? res.first : res
|
42
|
-
end
|
43
|
-
|
44
|
-
def last limit = 1
|
45
|
-
res = build_collection({startkey: default_query_args[:endkey], endkey: default_query_args[:startkey], limit: limit, descending: true})
|
46
|
-
limit == 1 ? res.first : res
|
47
|
-
end
|
48
|
-
|
49
|
-
def build_collection q
|
50
|
-
res = database.all_docs(q)
|
51
|
-
Collection.new res.parsed_response, name_for_class
|
52
|
-
end
|
53
|
-
|
54
|
-
def find_with doc, view_name, opts = {}
|
55
|
-
res = view "_design/#{doc}/_view/#{view_name}", opts
|
56
|
-
Collection.new res.parsed_response, name_for_class
|
57
|
-
end
|
58
|
-
|
59
|
-
#TODO: new implementation for collection returning
|
60
|
-
# multiple types is failling when the class has a namespace
|
61
|
-
# as the namespace does not exists on the doc id
|
62
|
-
# we need to reimplement this through a references class method.
|
63
|
-
def name_for_class
|
64
|
-
if name.include? '::'
|
65
|
-
name.constantize
|
66
|
-
end
|
67
|
-
end
|
68
|
-
|
69
|
-
def view doc, options = {}
|
70
|
-
options.merge! include_docs: true
|
71
|
-
database.get doc, options
|
72
|
-
end
|
73
|
-
|
74
|
-
def raw_view doc, view, opts = {}
|
75
|
-
JSON.parse database.get "_design/#{doc}/_view/#{view}", opts
|
76
|
-
end
|
8
|
+
include QueryArguments
|
9
|
+
include DocumentType
|
77
10
|
|
11
|
+
using StringRefinements
|
12
|
+
|
13
|
+
def find *keys
|
14
|
+
query_hash = { keys: namespace_keys(keys) }
|
15
|
+
|
16
|
+
build_collection(query_hash).first_or_all&.itself ||
|
17
|
+
raise(Dolly::ResourceNotFound)
|
18
|
+
end
|
19
|
+
|
20
|
+
def bulk_find(*keys_to_find)
|
21
|
+
data = {
|
22
|
+
query: { include_docs: true },
|
23
|
+
keys: keys_to_find.map { |key| namespace_key(key) }
|
24
|
+
}
|
25
|
+
|
26
|
+
res = connection.post('_all_docs', data)
|
27
|
+
Collection.new(rows: res, options: { doc_type: self.class_name })
|
28
|
+
end
|
29
|
+
|
30
|
+
def find_all(*keys)
|
31
|
+
query_hash = { keys: namespace_keys(keys) }
|
32
|
+
return [] if query_hash[:keys].none?
|
33
|
+
|
34
|
+
keys_to_find_counter = query_hash[:keys].length
|
35
|
+
build_collection(query_hash).first_or_all(true)&.itself
|
36
|
+
end
|
37
|
+
|
38
|
+
def safe_find *keys
|
39
|
+
find *keys
|
40
|
+
rescue Dolly::ResourceNotFound
|
41
|
+
nil
|
78
42
|
end
|
79
43
|
|
80
|
-
def
|
81
|
-
|
44
|
+
def all
|
45
|
+
build_collection(default_query_args)
|
82
46
|
end
|
83
47
|
|
48
|
+
def first limit = 1
|
49
|
+
query_hash = default_query_args.merge(limit: limit)
|
50
|
+
build_collection(query_hash).first_or_all(limit > 1)
|
51
|
+
end
|
52
|
+
|
53
|
+
def last limit = 1
|
54
|
+
query_hash = descending_query_args.merge(limit: limit)
|
55
|
+
build_collection(query_hash).first_or_all(limit > 1)
|
56
|
+
end
|
57
|
+
|
58
|
+
def find_with doc, view_name, opts = {}
|
59
|
+
opts = opts.each_with_object({}) { |(k, v), h| h[k] = v }
|
60
|
+
query_results = raw_view(doc, view_name, opts)
|
61
|
+
|
62
|
+
Collection.new({ rows: query_results, options: {} }).first_or_all
|
63
|
+
end
|
64
|
+
|
65
|
+
def build_collection(query)
|
66
|
+
Collection.new({ rows: connection.get('_all_docs', query.merge(include_docs: true)), options: { doc_type: self.class_name }})
|
67
|
+
end
|
68
|
+
|
69
|
+
def bulk_document
|
70
|
+
BulkDocument.new(connection)
|
71
|
+
end
|
84
72
|
end
|
85
73
|
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Dolly
|
4
|
+
module QueryArguments
|
5
|
+
def last_item_in_range
|
6
|
+
"\ufff0"
|
7
|
+
end
|
8
|
+
|
9
|
+
def default_query_args
|
10
|
+
{
|
11
|
+
startkey: "#{name_paramitized}/",
|
12
|
+
endkey: "#{name_paramitized}/#{last_item_in_range}"
|
13
|
+
}
|
14
|
+
end
|
15
|
+
|
16
|
+
def descending_query_args
|
17
|
+
{
|
18
|
+
startkey: default_query_args[:endkey],
|
19
|
+
endkey: default_query_args[:startkey],
|
20
|
+
descending: true
|
21
|
+
}
|
22
|
+
end
|
23
|
+
|
24
|
+
def escape_value(value)
|
25
|
+
return value if value.is_a? Numeric
|
26
|
+
return escape_values(value) if value.is_a? Array
|
27
|
+
return CGI.escape(value) if value.is_a? String
|
28
|
+
value
|
29
|
+
end
|
30
|
+
|
31
|
+
def escape_values *values
|
32
|
+
values.flatten.map { |value| escape_value(value) }
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
data/lib/dolly/request.rb
CHANGED
@@ -1,119 +1,24 @@
|
|
1
|
-
require "httparty"
|
2
|
-
require "dolly/bulk_document"
|
3
|
-
|
4
1
|
module Dolly
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
REQUIRED_KEYS = %w/host port name/.freeze
|
9
|
-
|
10
|
-
attr_accessor :database_name, :host, :port, :bulk_document
|
11
|
-
|
12
|
-
def initialize options = {}
|
13
|
-
REQUIRED_KEYS.each do |key|
|
14
|
-
raise Dolly::MissingRequestConfigSettings.new(key) unless options[key]
|
15
|
-
end
|
16
|
-
|
17
|
-
@host = options["host"]
|
18
|
-
@port = options["port"]
|
19
|
-
@database_name = options["name"]
|
20
|
-
@username = options["username"]
|
21
|
-
@password = options["password"]
|
22
|
-
@protocol = options["protocol"]
|
23
|
-
|
24
|
-
@bulk_document = Dolly::BulkDocument.new []
|
25
|
-
self.class.base_uri "#{protocol}://#{host}:#{port}"
|
26
|
-
end
|
27
|
-
|
28
|
-
def get resource, data = nil
|
29
|
-
q = {query: values_to_json(data)} if data
|
30
|
-
request :get, full_path(resource), q
|
31
|
-
end
|
32
|
-
|
33
|
-
def stats
|
34
|
-
request :get, "/#{database_name}"
|
35
|
-
end
|
36
|
-
|
37
|
-
def put resource, data
|
38
|
-
request :put, full_path(resource), {body: data}
|
39
|
-
end
|
40
|
-
|
41
|
-
def post resource, data
|
42
|
-
request :post, full_path(resource), {body: data}
|
43
|
-
end
|
44
|
-
|
45
|
-
def delete resource
|
46
|
-
request :delete, full_path(resource), {}
|
2
|
+
module Request
|
3
|
+
def set_namespace name
|
4
|
+
@namespace = name
|
47
5
|
end
|
48
6
|
|
49
|
-
def
|
50
|
-
|
51
|
-
request :put, attachment_path(resource, attachment_name), {body: data, headers: headers}
|
7
|
+
def set_app_env env
|
8
|
+
@app_env = env
|
52
9
|
end
|
53
10
|
|
54
|
-
def
|
55
|
-
@
|
11
|
+
def connection
|
12
|
+
@connection ||= Connection.new(namespace, app_env)
|
56
13
|
end
|
57
14
|
|
58
|
-
def
|
59
|
-
|
15
|
+
def namespace
|
16
|
+
@namespace ||= :default
|
60
17
|
end
|
61
18
|
|
62
|
-
def
|
63
|
-
|
64
|
-
|
65
|
-
end
|
66
|
-
|
67
|
-
def request method, resource, data = nil
|
68
|
-
data ||= {}
|
69
|
-
data.merge!(basic_auth: auth_info) if auth_info.present?
|
70
|
-
headers = { 'Content-Type' => 'application/json' }
|
71
|
-
headers.merge! data[:headers] if data[:headers]
|
72
|
-
response = self.class.send method, resource, data.merge(headers: headers)
|
73
|
-
log_request(resource, response.code) if Dolly.log_requests?
|
74
|
-
if response.code == 404
|
75
|
-
raise Dolly::ResourceNotFound
|
76
|
-
elsif (400..600).include? response.code
|
77
|
-
raise Dolly::ServerError.new( response )
|
78
|
-
else
|
79
|
-
response
|
80
|
-
end
|
81
|
-
end
|
82
|
-
|
83
|
-
private
|
84
|
-
def tools path, opts = nil
|
85
|
-
data = {}
|
86
|
-
q = "?#{CGI.unescape(opts.to_query)}" unless opts.blank?
|
87
|
-
data.merge!(basic_auth: auth_info) if auth_info.present?
|
88
|
-
JSON::parse self.class.get("/#{path}#{q}", data)
|
89
|
-
end
|
90
|
-
|
91
|
-
def auth_info
|
92
|
-
return nil unless @username.present?
|
93
|
-
{username: @username, password: @password}
|
94
|
-
end
|
95
|
-
|
96
|
-
def values_to_json hash
|
97
|
-
hash.reduce({}){|h, v| h[v.first] = v.last.to_json; h}
|
98
|
-
end
|
99
|
-
|
100
|
-
def full_path resource
|
101
|
-
"/#{database_name}/#{resource}"
|
102
|
-
end
|
103
|
-
|
104
|
-
def attachment_path resource, attachment_name
|
105
|
-
"#{full_path(resource)}/#{attachment_name}"
|
106
|
-
end
|
107
|
-
|
108
|
-
def log_request resource, response_code
|
109
|
-
log_value = ->(resource, response_code) { "Query: #{resource}, Response Code: #{response_code}" }
|
110
|
-
case response_code
|
111
|
-
when 200..399
|
112
|
-
Dolly.logger.info log_value[resource, response_code]
|
113
|
-
when 400..600
|
114
|
-
Dolly.logger.warn log_value[resource, response_code]
|
115
|
-
end
|
19
|
+
def app_env
|
20
|
+
return Rails.env if defined? Rails.env
|
21
|
+
@app_env ||= :development
|
116
22
|
end
|
117
23
|
end
|
118
|
-
|
119
24
|
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
require 'forwardable'
|
2
|
+
|
3
|
+
module Dolly
|
4
|
+
class HeaderRequest
|
5
|
+
extend Forwardable
|
6
|
+
|
7
|
+
CONTENT_TYPE_KEY = 'Content-Type'
|
8
|
+
JSON_CONTENT = 'application/json'
|
9
|
+
|
10
|
+
def_delegators :@collection, :[], :[]=, :keys, :each, :present?, :merge!
|
11
|
+
|
12
|
+
def initialize hash = nil
|
13
|
+
@collection = hash || default_value
|
14
|
+
end
|
15
|
+
|
16
|
+
def json?
|
17
|
+
@collection[CONTENT_TYPE_KEY] == JSON_CONTENT
|
18
|
+
end
|
19
|
+
|
20
|
+
private
|
21
|
+
|
22
|
+
def default_value
|
23
|
+
{ CONTENT_TYPE_KEY => JSON_CONTENT }
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|