dolly 1.1.7 → 3.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +35 -0
- data/lib/dolly.rb +1 -23
- 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 +26 -69
- data/lib/dolly/configuration.rb +35 -10
- data/lib/dolly/connection.rb +91 -22
- data/lib/dolly/depracated_database.rb +24 -0
- data/lib/dolly/document.rb +32 -206
- data/lib/dolly/document_creation.rb +20 -0
- data/lib/dolly/document_state.rb +65 -0
- data/lib/dolly/document_type.rb +28 -0
- data/lib/dolly/exceptions.rb +21 -0
- data/lib/dolly/identity_properties.rb +29 -0
- data/lib/dolly/properties.rb +31 -0
- data/lib/dolly/property.rb +58 -47
- data/lib/dolly/property_manager.rb +47 -0
- data/lib/dolly/property_set.rb +18 -0
- data/lib/dolly/query.rb +39 -67
- 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 → railties}/railtie.rb +2 -1
- data/lib/refinements/string_refinements.rb +28 -0
- data/lib/tasks/db.rake +4 -3
- data/test/bulk_document_test.rb +8 -5
- data/test/document_test.rb +137 -53
- data/test/dummy/config/initializers/filter_parameter_logging.rb +4 -0
- data/test/dummy/log/test.log +46417 -46858
- data/test/test_helper.rb +14 -20
- metadata +42 -145
- 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.ru +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/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
data/lib/dolly/property.rb
CHANGED
@@ -1,85 +1,96 @@
|
|
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
|
-
|
16
|
+
def cast_value(value)
|
17
|
+
return set_default if value.nil?
|
18
|
+
return value unless class_name
|
19
|
+
return self_klass.new(value) unless respond_to?(klass_sym)
|
20
|
+
send(klass_sym, value)
|
21
|
+
end
|
24
22
|
|
25
|
-
|
23
|
+
def boolean?
|
24
|
+
[TrueClass, FalseClass].include?(class_name)
|
25
|
+
end
|
26
26
|
|
27
|
-
|
27
|
+
def string_value(value)
|
28
|
+
value.to_s
|
28
29
|
end
|
29
30
|
|
30
|
-
def
|
31
|
-
|
31
|
+
def hash_value(value)
|
32
|
+
value.to_h
|
32
33
|
end
|
33
34
|
|
34
|
-
def
|
35
|
-
|
35
|
+
def integer_value(value)
|
36
|
+
value.to_i
|
36
37
|
end
|
37
38
|
|
38
|
-
def
|
39
|
-
|
39
|
+
def float_value(value)
|
40
|
+
value.to_f
|
40
41
|
end
|
41
42
|
|
42
|
-
def
|
43
|
-
|
43
|
+
def date_value(value)
|
44
|
+
return value.to_date if value.respond_to?(:to_date)
|
45
|
+
Date.parse(value)
|
44
46
|
end
|
45
47
|
|
46
|
-
def
|
47
|
-
|
48
|
+
def time_value(value)
|
49
|
+
return value.to_time if value.respond_to?(:to_time)
|
50
|
+
DateTime.parse(value).to_time
|
48
51
|
end
|
49
52
|
|
50
|
-
def
|
51
|
-
|
53
|
+
def date_time_value(value)
|
54
|
+
return value.to_datetime if value.respond_to?(:to_datetime)
|
55
|
+
DateTime.parse(value)
|
52
56
|
end
|
53
57
|
|
54
|
-
def
|
55
|
-
|
58
|
+
def true_class_value(value)
|
59
|
+
truthy_value?(value)
|
56
60
|
end
|
57
61
|
|
58
|
-
def
|
59
|
-
|
62
|
+
def false_class_value(value)
|
63
|
+
truthy_value?(value)
|
60
64
|
end
|
61
65
|
|
62
|
-
|
63
|
-
|
66
|
+
private
|
67
|
+
|
68
|
+
def truthy_value?(value)
|
69
|
+
value =~ /true/ || value === true
|
64
70
|
end
|
65
71
|
|
66
|
-
def
|
67
|
-
|
72
|
+
def klass_sym
|
73
|
+
:"#{self_klass.name.underscore}_value"
|
68
74
|
end
|
69
75
|
|
70
|
-
def
|
71
|
-
|
76
|
+
def self_klass
|
77
|
+
return unless class_name
|
78
|
+
return class_name if class_name.is_a?(Class)
|
79
|
+
Object.const_get class_name
|
72
80
|
end
|
73
81
|
|
74
|
-
|
75
|
-
|
76
|
-
|
82
|
+
def set_default
|
83
|
+
return unless default_present?
|
84
|
+
return default unless cant_clone_default?
|
85
|
+
default.clone
|
77
86
|
end
|
78
87
|
|
79
|
-
def
|
80
|
-
|
81
|
-
@class_name.is_a?(Class)? @class_name : @class_name.constantize
|
88
|
+
def cant_clone_default?
|
89
|
+
CANT_CLONE.none? { |klass| default.is_a? klass }
|
82
90
|
end
|
83
91
|
|
92
|
+
def default_present?
|
93
|
+
!default.nil?
|
94
|
+
end
|
84
95
|
end
|
85
96
|
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
module Dolly
|
2
|
+
module PropertyManager
|
3
|
+
def build_property(attributes)
|
4
|
+
assign_identity_properties(attributes)
|
5
|
+
|
6
|
+
lambda do |property|
|
7
|
+
name = property.key.to_sym
|
8
|
+
next unless doc[name].nil?
|
9
|
+
write_attribute(name, attributes[name])
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
def update_attribute
|
14
|
+
lambda do |key, value|
|
15
|
+
raise InvalidProperty unless valid_property?(key)
|
16
|
+
write_attribute(key, value)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def write_attribute key, value
|
21
|
+
value = set_property_value(key, value)
|
22
|
+
instance_variable_set(:"@#{key}", value)
|
23
|
+
update_doc(key, value) unless value.nil?
|
24
|
+
end
|
25
|
+
|
26
|
+
def valid_property?(name)
|
27
|
+
properties.include? name
|
28
|
+
end
|
29
|
+
|
30
|
+
def update_doc(key, value)
|
31
|
+
doc[key] = value
|
32
|
+
end
|
33
|
+
|
34
|
+
def properties
|
35
|
+
self.class.properties
|
36
|
+
end
|
37
|
+
|
38
|
+
def set_property_value(key, value)
|
39
|
+
properties[key].cast_value(value)
|
40
|
+
end
|
41
|
+
|
42
|
+
def assign_identity_properties(opts = {})
|
43
|
+
id_presence = opts[:id] || opts[:_id] || opts['id'] || opts['_id']
|
44
|
+
self.id = id_presence if id_presence
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module Dolly
|
2
|
+
class PropertySet < Set
|
3
|
+
def include? key
|
4
|
+
keys.include?(key)
|
5
|
+
end
|
6
|
+
|
7
|
+
def [](key)
|
8
|
+
return detect {|property| property.key == key } if key.is_a?(Symbol)
|
9
|
+
super
|
10
|
+
end
|
11
|
+
|
12
|
+
private
|
13
|
+
|
14
|
+
def keys
|
15
|
+
map(&:key)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
data/lib/dolly/query.rb
CHANGED
@@ -1,85 +1,57 @@
|
|
1
|
-
require
|
2
|
-
require
|
3
|
-
require
|
4
|
-
require "exceptions/dolly"
|
1
|
+
require 'dolly/collection'
|
2
|
+
require 'dolly/query_arguments'
|
3
|
+
require 'dolly/document_type'
|
5
4
|
|
6
5
|
module Dolly
|
7
6
|
module Query
|
8
|
-
|
9
|
-
|
10
|
-
include Dolly::Connection
|
11
|
-
attr_accessor :properties
|
7
|
+
include QueryArguments
|
8
|
+
include DocumentType
|
12
9
|
|
13
|
-
|
10
|
+
def find *keys
|
11
|
+
query_hash = { keys: namespace_keys(keys) }
|
14
12
|
|
15
|
-
|
16
|
-
|
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
|
13
|
+
build_collection(query_hash).first_or_all&.itself ||
|
14
|
+
raise(Dolly::ResourceNotFound)
|
15
|
+
end
|
43
16
|
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
17
|
+
def safe_find *keys
|
18
|
+
find *keys
|
19
|
+
rescue Dolly::ResourceNotFound
|
20
|
+
nil
|
21
|
+
end
|
48
22
|
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
end
|
23
|
+
def all
|
24
|
+
build_collection(default_query_args)
|
25
|
+
end
|
53
26
|
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
27
|
+
def first limit = 1
|
28
|
+
query_hash = default_query_args.merge(limit: limit)
|
29
|
+
build_collection(query_hash).first_or_all(limit > 1)
|
30
|
+
end
|
58
31
|
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
def name_for_class
|
64
|
-
if name.include? '::'
|
65
|
-
name.constantize
|
66
|
-
end
|
67
|
-
end
|
32
|
+
def last limit = 1
|
33
|
+
query_hash = descending_query_args.merge(limit: limit)
|
34
|
+
build_collection(query_hash).first_or_all(limit > 1)
|
35
|
+
end
|
68
36
|
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
end
|
37
|
+
def find_with doc, view_name, opts = {}
|
38
|
+
opts = opts.each_with_object({}) { |(k, v), h| h[k] = escape_value(v) }
|
39
|
+
query_results = raw_view(doc, view_name, opts)
|
73
40
|
|
74
|
-
|
75
|
-
|
76
|
-
end
|
41
|
+
Collection.new(query_results).first_or_all
|
42
|
+
end
|
77
43
|
|
44
|
+
def raw_view doc, view_name, opts = {}
|
45
|
+
design = "_design/#{doc}/_view/#{view_name}"
|
46
|
+
connection.view(design, opts)
|
78
47
|
end
|
79
48
|
|
80
|
-
def
|
81
|
-
|
49
|
+
def build_collection(query)
|
50
|
+
Collection.new(connection.get('_all_docs', query.merge(include_docs: true)))
|
82
51
|
end
|
83
52
|
|
53
|
+
def bulk_document
|
54
|
+
BulkDocument.new(connection)
|
55
|
+
end
|
84
56
|
end
|
85
57
|
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Dolly
|
4
|
+
module QueryArguments
|
5
|
+
def last_item_in_range
|
6
|
+
URI.escape("\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
|
+
@namspace = 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
|