dynamoid 1.3.4 → 2.0.0
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 +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.
|