dynamoid 1.3.4 → 2.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.coveralls.yml +1 -0
- data/.gitignore +3 -0
- data/.travis.yml +32 -7
- data/Appraisals +7 -0
- data/CHANGELOG.md +69 -2
- data/Gemfile +2 -0
- data/README.md +108 -28
- data/Rakefile +0 -24
- data/docker-compose.yml +7 -0
- data/dynamoid.gemspec +2 -3
- data/gemfiles/rails_4_0.gemfile +2 -3
- data/gemfiles/rails_4_1.gemfile +2 -3
- data/gemfiles/rails_4_2.gemfile +2 -3
- data/gemfiles/rails_5_0.gemfile +1 -1
- data/gemfiles/rails_5_1.gemfile +7 -0
- data/lib/dynamoid.rb +31 -31
- data/lib/dynamoid/adapter.rb +5 -5
- data/lib/dynamoid/adapter_plugin/aws_sdk_v2.rb +84 -57
- data/lib/dynamoid/associations.rb +21 -12
- data/lib/dynamoid/associations/association.rb +19 -3
- data/lib/dynamoid/associations/belongs_to.rb +26 -16
- data/lib/dynamoid/associations/has_and_belongs_to_many.rb +0 -16
- data/lib/dynamoid/associations/has_many.rb +2 -17
- data/lib/dynamoid/associations/has_one.rb +0 -14
- data/lib/dynamoid/associations/many_association.rb +19 -6
- data/lib/dynamoid/associations/single_association.rb +25 -7
- data/lib/dynamoid/config.rb +18 -18
- data/lib/dynamoid/config/options.rb +1 -1
- data/lib/dynamoid/criteria/chain.rb +29 -21
- data/lib/dynamoid/dirty.rb +2 -2
- data/lib/dynamoid/document.rb +17 -5
- data/lib/dynamoid/errors.rb +4 -1
- data/lib/dynamoid/fields.rb +6 -6
- data/lib/dynamoid/finders.rb +19 -9
- data/lib/dynamoid/identity_map.rb +0 -1
- data/lib/dynamoid/indexes.rb +41 -54
- data/lib/dynamoid/persistence.rb +54 -24
- data/lib/dynamoid/railtie.rb +1 -1
- data/lib/dynamoid/validations.rb +4 -3
- data/lib/dynamoid/version.rb +1 -1
- metadata +14 -29
- data/gemfiles/rails_4_0.gemfile.lock +0 -150
- data/gemfiles/rails_4_1.gemfile.lock +0 -154
- data/gemfiles/rails_4_2.gemfile.lock +0 -175
- data/gemfiles/rails_5_0.gemfile.lock +0 -180
@@ -16,16 +16,16 @@ module Dynamoid
|
|
16
16
|
# * has_one
|
17
17
|
module Associations
|
18
18
|
extend ActiveSupport::Concern
|
19
|
-
|
19
|
+
|
20
20
|
# Create the association tracking attribute and initialize it to an empty hash.
|
21
21
|
included do
|
22
22
|
class_attribute :associations, instance_accessor: false
|
23
|
-
|
23
|
+
|
24
24
|
self.associations = {}
|
25
25
|
end
|
26
26
|
|
27
27
|
module ClassMethods
|
28
|
-
|
28
|
+
|
29
29
|
# create a has_many association for this document.
|
30
30
|
#
|
31
31
|
# @param [Symbol] name the name of the association
|
@@ -38,7 +38,7 @@ module Dynamoid
|
|
38
38
|
def has_many(name, options = {})
|
39
39
|
association(:has_many, name, options)
|
40
40
|
end
|
41
|
-
|
41
|
+
|
42
42
|
# create a has_one association for this document.
|
43
43
|
#
|
44
44
|
# @param [Symbol] name the name of the association
|
@@ -51,7 +51,7 @@ module Dynamoid
|
|
51
51
|
def has_one(name, options = {})
|
52
52
|
association(:has_one, name, options)
|
53
53
|
end
|
54
|
-
|
54
|
+
|
55
55
|
# create a belongs_to association for this document.
|
56
56
|
#
|
57
57
|
# @param [Symbol] name the name of the association
|
@@ -64,7 +64,7 @@ module Dynamoid
|
|
64
64
|
def belongs_to(name, options = {})
|
65
65
|
association(:belongs_to, name, options)
|
66
66
|
end
|
67
|
-
|
67
|
+
|
68
68
|
# create a has_and_belongs_to_many association for this document.
|
69
69
|
#
|
70
70
|
# @param [Symbol] name the name of the association
|
@@ -77,7 +77,7 @@ module Dynamoid
|
|
77
77
|
def has_and_belongs_to_many(name, options = {})
|
78
78
|
association(:has_and_belongs_to_many, name, options)
|
79
79
|
end
|
80
|
-
|
80
|
+
|
81
81
|
private
|
82
82
|
|
83
83
|
# create getters and setters for an association.
|
@@ -86,13 +86,23 @@ module Dynamoid
|
|
86
86
|
# @param [Symbol] name the name of the association
|
87
87
|
# @param [Hash] options options to pass to the association constructor; see above for all valid options
|
88
88
|
#
|
89
|
-
# @since 0.2.0
|
89
|
+
# @since 0.2.0
|
90
90
|
def association(type, name, options = {})
|
91
|
-
field
|
92
|
-
|
91
|
+
# Declare document field.
|
92
|
+
# In simple case it's equivalent to
|
93
|
+
# field "#{name}_ids".to_sym, :set
|
94
|
+
assoc = Dynamoid::Associations.const_get(type.to_s.camelcase).new(nil, name, options)
|
95
|
+
field_name = assoc.declaration_field_name
|
96
|
+
field_type = assoc.declaration_field_type
|
97
|
+
|
98
|
+
field field_name.to_sym, field_type
|
99
|
+
|
100
|
+
self.associations[name] = options.merge(type: type)
|
101
|
+
|
93
102
|
define_method(name) do
|
94
103
|
@associations[:"#{name}_ids"] ||= Dynamoid::Associations.const_get(type.to_s.camelcase).new(self, name, options)
|
95
104
|
end
|
105
|
+
|
96
106
|
define_method("#{name}=".to_sym) do |objects|
|
97
107
|
@associations[:"#{name}_ids"] ||= Dynamoid::Associations.const_get(type.to_s.camelcase).new(self, name, options)
|
98
108
|
@associations[:"#{name}_ids"].setter(objects)
|
@@ -100,7 +110,6 @@ module Dynamoid
|
|
100
110
|
end
|
101
111
|
end
|
102
112
|
|
103
|
-
|
104
113
|
end
|
105
|
-
|
114
|
+
|
106
115
|
end
|
@@ -16,6 +16,7 @@ module Dynamoid #:nodoc:
|
|
16
16
|
# @option options [Class] :class the target class of the association; that is, the class to which the association objects belong
|
17
17
|
# @option options [Symbol] :class_name the name of the target class of the association; only this or Class is necessary
|
18
18
|
# @option options [Symbol] :inverse_of the name of the association on the target class
|
19
|
+
# @option options [Symbol] :foreign_key the name of the field for belongs_to association
|
19
20
|
#
|
20
21
|
# @return [Dynamoid::Association] the actual association instance itself
|
21
22
|
#
|
@@ -48,6 +49,14 @@ module Dynamoid #:nodoc:
|
|
48
49
|
@loaded = false
|
49
50
|
end
|
50
51
|
|
52
|
+
def declaration_field_name
|
53
|
+
"#{name}_ids"
|
54
|
+
end
|
55
|
+
|
56
|
+
def declaration_field_type
|
57
|
+
:set
|
58
|
+
end
|
59
|
+
|
51
60
|
private
|
52
61
|
|
53
62
|
# The target class name, either inferred through the association's name or specified in options.
|
@@ -68,7 +77,13 @@ module Dynamoid #:nodoc:
|
|
68
77
|
#
|
69
78
|
# @since 0.2.0
|
70
79
|
def target_attribute
|
71
|
-
|
80
|
+
# In simple case it's equivalent to
|
81
|
+
# "#{target_association}_ids".to_sym if target_association
|
82
|
+
if target_association
|
83
|
+
target_options = target_class.associations[target_association]
|
84
|
+
assoc = Dynamoid::Associations.const_get(target_options[:type].to_s.camelcase).new(nil, target_association, target_options)
|
85
|
+
assoc.send(:source_attribute)
|
86
|
+
end
|
72
87
|
end
|
73
88
|
|
74
89
|
# The ids in the target association.
|
@@ -89,14 +104,15 @@ module Dynamoid #:nodoc:
|
|
89
104
|
#
|
90
105
|
# @since 0.2.0
|
91
106
|
def source_attribute
|
92
|
-
|
107
|
+
declaration_field_name.to_sym
|
93
108
|
end
|
94
109
|
|
95
110
|
# The ids in the source association.
|
96
111
|
#
|
97
112
|
# @since 0.2.0
|
98
113
|
def source_ids
|
99
|
-
|
114
|
+
# handle case when we store scalar value instead of collection (when foreign_key option is specified)
|
115
|
+
Array(source.send(source_attribute)).compact.to_set || Set.new
|
100
116
|
end
|
101
117
|
|
102
118
|
# Create a new instance of the target class without trying to add it to the association. This creates a base, that caller can update before setting or adding it.
|
@@ -1,12 +1,36 @@
|
|
1
1
|
# encoding: utf-8
|
2
2
|
module Dynamoid #:nodoc:
|
3
3
|
|
4
|
-
# The belongs_to association. For belongs_to, we reference only a single target instead of multiple records; that target is the
|
4
|
+
# The belongs_to association. For belongs_to, we reference only a single target instead of multiple records; that target is the
|
5
5
|
# object to which the association object is associated.
|
6
6
|
module Associations
|
7
7
|
class BelongsTo
|
8
8
|
include SingleAssociation
|
9
9
|
|
10
|
+
def declaration_field_name
|
11
|
+
options[:foreign_key] || "#{name}_ids"
|
12
|
+
end
|
13
|
+
|
14
|
+
def declaration_field_type
|
15
|
+
if options[:foreign_key]
|
16
|
+
target_class.attributes[target_class.hash_key][:type]
|
17
|
+
else
|
18
|
+
:set
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
# Override default implementation
|
23
|
+
# to handle case when we store id as scalar value, not as collection
|
24
|
+
def associate(hash_key)
|
25
|
+
target.send(target_association).disassociate(source.hash_key) if target && target_association
|
26
|
+
|
27
|
+
if options[:foreign_key]
|
28
|
+
source.update_attribute(source_attribute, hash_key)
|
29
|
+
else
|
30
|
+
source.update_attribute(source_attribute, Set[hash_key])
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
10
34
|
private
|
11
35
|
|
12
36
|
# Find the target association, either has_many or has_one. Uses either options[:inverse_of] or the source class name and default parsing to
|
@@ -24,21 +48,7 @@ module Dynamoid #:nodoc:
|
|
24
48
|
return has_one_key_name if target_class.associations[has_one_key_name][:type] == :has_one
|
25
49
|
end
|
26
50
|
end
|
27
|
-
|
28
|
-
# Associate a source object to this association.
|
29
|
-
#
|
30
|
-
# @since 0.2.0
|
31
|
-
def associate_target(object)
|
32
|
-
object.update_attribute(target_attribute, target_ids.merge(Array(source.hash_key)))
|
33
|
-
end
|
34
|
-
|
35
|
-
# Disassociate a source object from this association.
|
36
|
-
#
|
37
|
-
# @since 0.2.0
|
38
|
-
def disassociate_target(object)
|
39
|
-
source.update_attribute(source_attribute, target_ids - Array(source.hash_key))
|
40
|
-
end
|
41
51
|
end
|
42
52
|
end
|
43
|
-
|
53
|
+
|
44
54
|
end
|
@@ -18,22 +18,6 @@ module Dynamoid #:nodoc:
|
|
18
18
|
return nil if guess.nil? || guess[:type] != :has_and_belongs_to_many
|
19
19
|
key_name
|
20
20
|
end
|
21
|
-
|
22
|
-
# Associate a source object to this association.
|
23
|
-
#
|
24
|
-
# @since 0.2.0
|
25
|
-
def associate_target(object)
|
26
|
-
ids = object.send(target_attribute) || Set.new
|
27
|
-
object.update_attribute(target_attribute, ids.merge(Array(source.hash_key)))
|
28
|
-
end
|
29
|
-
|
30
|
-
# Disassociate a source object from this association.
|
31
|
-
#
|
32
|
-
# @since 0.2.0
|
33
|
-
def disassociate_target(object)
|
34
|
-
ids = object.send(target_attribute) || Set.new
|
35
|
-
object.update_attribute(target_attribute, ids - Array(source.hash_key))
|
36
|
-
end
|
37
21
|
end
|
38
22
|
end
|
39
23
|
|
@@ -8,7 +8,7 @@ module Dynamoid #:nodoc:
|
|
8
8
|
|
9
9
|
private
|
10
10
|
|
11
|
-
# Find the target association, always a :belongs_to association. Uses either options[:inverse_of] or the source class name
|
11
|
+
# Find the target association, always a :belongs_to association. Uses either options[:inverse_of] or the source class name
|
12
12
|
# and default parsing to return the most likely name for the target association.
|
13
13
|
#
|
14
14
|
# @since 0.2.0
|
@@ -18,22 +18,7 @@ module Dynamoid #:nodoc:
|
|
18
18
|
return nil if guess.nil? || guess[:type] != :belongs_to
|
19
19
|
key_name
|
20
20
|
end
|
21
|
-
|
22
|
-
# Associate a source object to this association.
|
23
|
-
#
|
24
|
-
# @since 0.2.0
|
25
|
-
def associate_target(object)
|
26
|
-
object.update_attribute(target_attribute, Set[source.hash_key])
|
27
|
-
end
|
28
|
-
|
29
|
-
# Disassociate a source object from this association.
|
30
|
-
#
|
31
|
-
# @since 0.2.0
|
32
|
-
def disassociate_target(object)
|
33
|
-
object.update_attribute(target_attribute, nil)
|
34
|
-
end
|
35
|
-
|
36
21
|
end
|
37
22
|
end
|
38
|
-
|
23
|
+
|
39
24
|
end
|
@@ -19,20 +19,6 @@ module Dynamoid #:nodoc:
|
|
19
19
|
return nil if guess.nil? || guess[:type] != :belongs_to
|
20
20
|
key_name
|
21
21
|
end
|
22
|
-
|
23
|
-
# Associate a source object to this association.
|
24
|
-
#
|
25
|
-
# @since 0.2.0
|
26
|
-
def associate_target(object)
|
27
|
-
object.update_attribute(target_attribute, Set[source.hash_key])
|
28
|
-
end
|
29
|
-
|
30
|
-
# Disassociate a source object from this association.
|
31
|
-
#
|
32
|
-
# @since 0.2.0
|
33
|
-
def disassociate_target(object)
|
34
|
-
source.update_attribute(source_attribute, nil)
|
35
|
-
end
|
36
22
|
end
|
37
23
|
end
|
38
24
|
|
@@ -14,7 +14,7 @@ module Dynamoid #:nodoc:
|
|
14
14
|
|
15
15
|
include Enumerable
|
16
16
|
# Delegate methods to the records the association represents.
|
17
|
-
delegate :first, :last, :empty?, :size, :class, :
|
17
|
+
delegate :first, :last, :empty?, :size, :class, to: :records
|
18
18
|
|
19
19
|
# The records associated to the source.
|
20
20
|
#
|
@@ -52,12 +52,13 @@ module Dynamoid #:nodoc:
|
|
52
52
|
#
|
53
53
|
# @since 0.2.0
|
54
54
|
def delete(object)
|
55
|
-
|
56
|
-
|
55
|
+
disassociate(Array(object).collect(&:hash_key))
|
56
|
+
if target_association
|
57
|
+
Array(object).each { |obj| obj.send(target_association).disassociate(source.hash_key) }
|
58
|
+
end
|
57
59
|
object
|
58
60
|
end
|
59
61
|
|
60
|
-
|
61
62
|
# Add an object or array of objects to an association. This preserves the current records in the association (if any)
|
62
63
|
# and adds the object to the target association if it is detected to exist.
|
63
64
|
#
|
@@ -67,8 +68,12 @@ module Dynamoid #:nodoc:
|
|
67
68
|
#
|
68
69
|
# @since 0.2.0
|
69
70
|
def <<(object)
|
70
|
-
|
71
|
-
|
71
|
+
associate(Array(object).collect(&:hash_key))
|
72
|
+
|
73
|
+
if target_association
|
74
|
+
Array(object).each { |obj| obj.send(target_association).associate(source.hash_key) }
|
75
|
+
end
|
76
|
+
|
72
77
|
object
|
73
78
|
end
|
74
79
|
|
@@ -171,6 +176,14 @@ module Dynamoid #:nodoc:
|
|
171
176
|
end
|
172
177
|
end
|
173
178
|
|
179
|
+
def associate(hash_key)
|
180
|
+
source.update_attribute(source_attribute, source_ids.merge(Array(hash_key)))
|
181
|
+
end
|
182
|
+
|
183
|
+
def disassociate(hash_key)
|
184
|
+
source.update_attribute(source_attribute, source_ids - Array(hash_key))
|
185
|
+
end
|
186
|
+
|
174
187
|
private
|
175
188
|
|
176
189
|
# If a query exists, filter all existing results based on that query.
|
@@ -5,18 +5,23 @@ module Dynamoid #:nodoc:
|
|
5
5
|
module SingleAssociation
|
6
6
|
include Association
|
7
7
|
|
8
|
-
delegate :class, :
|
8
|
+
delegate :class, to: :target
|
9
9
|
|
10
10
|
def setter(object)
|
11
|
-
|
12
|
-
|
13
|
-
|
11
|
+
if object.nil?
|
12
|
+
delete
|
13
|
+
return
|
14
|
+
end
|
15
|
+
|
16
|
+
associate(object.hash_key)
|
17
|
+
self.target = object
|
18
|
+
object.send(target_association).associate(source.hash_key) if target_association
|
14
19
|
object
|
15
20
|
end
|
16
21
|
|
17
22
|
def delete
|
18
|
-
source.
|
19
|
-
|
23
|
+
target.send(target_association).disassociate(source.hash_key) if target && target_association
|
24
|
+
disassociate
|
20
25
|
target
|
21
26
|
end
|
22
27
|
|
@@ -28,7 +33,6 @@ module Dynamoid #:nodoc:
|
|
28
33
|
setter(target_class.create(attributes))
|
29
34
|
end
|
30
35
|
|
31
|
-
|
32
36
|
# Is this object equal to the association's target?
|
33
37
|
#
|
34
38
|
# @return [Boolean] true/false
|
@@ -59,6 +63,15 @@ module Dynamoid #:nodoc:
|
|
59
63
|
target.nil?
|
60
64
|
end
|
61
65
|
|
66
|
+
def associate(hash_key)
|
67
|
+
target.send(target_association).disassociate(source.hash_key) if target && target_association
|
68
|
+
source.update_attribute(source_attribute, Set[hash_key])
|
69
|
+
end
|
70
|
+
|
71
|
+
def disassociate(hash_key=nil)
|
72
|
+
source.update_attribute(source_attribute, nil)
|
73
|
+
end
|
74
|
+
|
62
75
|
private
|
63
76
|
|
64
77
|
# Find the target of the has_one association.
|
@@ -70,6 +83,11 @@ module Dynamoid #:nodoc:
|
|
70
83
|
return if source_ids.empty?
|
71
84
|
target_class.find(source_ids.first)
|
72
85
|
end
|
86
|
+
|
87
|
+
def target=(object)
|
88
|
+
@target = object
|
89
|
+
@loaded = true
|
90
|
+
end
|
73
91
|
end
|
74
92
|
end
|
75
93
|
end
|
data/lib/dynamoid/config.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
# encoding: utf-8
|
2
|
-
require
|
3
|
-
require
|
2
|
+
require 'uri'
|
3
|
+
require 'dynamoid/config/options'
|
4
4
|
|
5
5
|
module Dynamoid
|
6
6
|
|
@@ -11,22 +11,22 @@ module Dynamoid
|
|
11
11
|
include ActiveModel::Observing if defined?(ActiveModel::Observing)
|
12
12
|
|
13
13
|
# All the default options.
|
14
|
-
option :adapter, :
|
15
|
-
option :namespace, :
|
16
|
-
option :access_key, :
|
17
|
-
option :secret_key, :
|
18
|
-
option :region, :
|
19
|
-
option :batch_size, :
|
20
|
-
option :read_capacity, :
|
21
|
-
option :write_capacity, :
|
22
|
-
option :warn_on_scan, :
|
23
|
-
option :endpoint, :
|
24
|
-
option :identity_map, :
|
25
|
-
option :timestamps, :
|
26
|
-
option :sync_retry_max_times, :
|
27
|
-
option :sync_retry_wait_seconds, :
|
28
|
-
option :convert_big_decimal, :
|
29
|
-
option :models_dir, :
|
14
|
+
option :adapter, default: 'aws_sdk_v2'
|
15
|
+
option :namespace, default: defined?(Rails) ? "dynamoid_#{Rails.application.class.parent_name}_#{Rails.env}" : 'dynamoid'
|
16
|
+
option :access_key, default: nil
|
17
|
+
option :secret_key, default: nil
|
18
|
+
option :region, default: nil
|
19
|
+
option :batch_size, default: 100
|
20
|
+
option :read_capacity, default: 100
|
21
|
+
option :write_capacity, default: 20
|
22
|
+
option :warn_on_scan, default: true
|
23
|
+
option :endpoint, default: nil
|
24
|
+
option :identity_map, default: false
|
25
|
+
option :timestamps, default: true
|
26
|
+
option :sync_retry_max_times, default: 60 # a bit over 2 minutes
|
27
|
+
option :sync_retry_wait_seconds, default: 2
|
28
|
+
option :convert_big_decimal, default: false
|
29
|
+
option :models_dir, default: 'app/models' # perhaps you keep your dynamoid models in a different directory?
|
30
30
|
option :application_timezone, default: :local # available values - :utc, :local, time zone names
|
31
31
|
|
32
32
|
# The default logger for Dynamoid: either the Rails logger or just stdout.
|