dynamoid 3.3.0 → 3.7.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.
Files changed (82) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +104 -1
  3. data/README.md +146 -52
  4. data/lib/dynamoid.rb +1 -0
  5. data/lib/dynamoid/adapter.rb +20 -7
  6. data/lib/dynamoid/adapter_plugin/aws_sdk_v3.rb +70 -37
  7. data/lib/dynamoid/adapter_plugin/aws_sdk_v3/batch_get_item.rb +3 -0
  8. data/lib/dynamoid/adapter_plugin/aws_sdk_v3/create_table.rb +20 -12
  9. data/lib/dynamoid/adapter_plugin/aws_sdk_v3/item_updater.rb +5 -4
  10. data/lib/dynamoid/adapter_plugin/aws_sdk_v3/middleware/backoff.rb +2 -2
  11. data/lib/dynamoid/adapter_plugin/aws_sdk_v3/middleware/limit.rb +2 -3
  12. data/lib/dynamoid/adapter_plugin/aws_sdk_v3/middleware/start_key.rb +2 -2
  13. data/lib/dynamoid/adapter_plugin/aws_sdk_v3/query.rb +4 -2
  14. data/lib/dynamoid/adapter_plugin/aws_sdk_v3/scan.rb +4 -2
  15. data/lib/dynamoid/adapter_plugin/aws_sdk_v3/table.rb +1 -0
  16. data/lib/dynamoid/adapter_plugin/aws_sdk_v3/until_past_table_status.rb +2 -1
  17. data/lib/dynamoid/application_time_zone.rb +1 -0
  18. data/lib/dynamoid/associations.rb +182 -19
  19. data/lib/dynamoid/associations/association.rb +10 -2
  20. data/lib/dynamoid/associations/belongs_to.rb +2 -1
  21. data/lib/dynamoid/associations/has_and_belongs_to_many.rb +2 -1
  22. data/lib/dynamoid/associations/has_many.rb +2 -1
  23. data/lib/dynamoid/associations/has_one.rb +2 -1
  24. data/lib/dynamoid/associations/many_association.rb +68 -23
  25. data/lib/dynamoid/associations/single_association.rb +31 -4
  26. data/lib/dynamoid/components.rb +2 -0
  27. data/lib/dynamoid/config.rb +15 -3
  28. data/lib/dynamoid/config/backoff_strategies/constant_backoff.rb +1 -0
  29. data/lib/dynamoid/config/backoff_strategies/exponential_backoff.rb +1 -0
  30. data/lib/dynamoid/config/options.rb +1 -0
  31. data/lib/dynamoid/criteria.rb +9 -1
  32. data/lib/dynamoid/criteria/chain.rb +421 -46
  33. data/lib/dynamoid/criteria/ignored_conditions_detector.rb +3 -3
  34. data/lib/dynamoid/criteria/key_fields_detector.rb +31 -10
  35. data/lib/dynamoid/criteria/nonexistent_fields_detector.rb +3 -2
  36. data/lib/dynamoid/criteria/overwritten_conditions_detector.rb +1 -1
  37. data/lib/dynamoid/dirty.rb +119 -64
  38. data/lib/dynamoid/document.rb +133 -46
  39. data/lib/dynamoid/dumping.rb +9 -0
  40. data/lib/dynamoid/dynamodb_time_zone.rb +1 -0
  41. data/lib/dynamoid/errors.rb +2 -0
  42. data/lib/dynamoid/fields.rb +251 -39
  43. data/lib/dynamoid/fields/declare.rb +86 -0
  44. data/lib/dynamoid/finders.rb +69 -32
  45. data/lib/dynamoid/identity_map.rb +6 -0
  46. data/lib/dynamoid/indexes.rb +86 -17
  47. data/lib/dynamoid/loadable.rb +2 -2
  48. data/lib/dynamoid/log/formatter.rb +26 -0
  49. data/lib/dynamoid/middleware/identity_map.rb +1 -0
  50. data/lib/dynamoid/persistence.rb +502 -104
  51. data/lib/dynamoid/persistence/import.rb +2 -1
  52. data/lib/dynamoid/persistence/save.rb +1 -0
  53. data/lib/dynamoid/persistence/update_fields.rb +5 -2
  54. data/lib/dynamoid/persistence/update_validations.rb +18 -0
  55. data/lib/dynamoid/persistence/upsert.rb +5 -3
  56. data/lib/dynamoid/primary_key_type_mapping.rb +1 -0
  57. data/lib/dynamoid/railtie.rb +1 -0
  58. data/lib/dynamoid/tasks.rb +3 -1
  59. data/lib/dynamoid/tasks/database.rb +1 -0
  60. data/lib/dynamoid/type_casting.rb +12 -2
  61. data/lib/dynamoid/undumping.rb +8 -0
  62. data/lib/dynamoid/validations.rb +6 -1
  63. data/lib/dynamoid/version.rb +1 -1
  64. metadata +48 -75
  65. data/.coveralls.yml +0 -1
  66. data/.document +0 -5
  67. data/.gitignore +0 -74
  68. data/.rspec +0 -2
  69. data/.rubocop.yml +0 -71
  70. data/.rubocop_todo.yml +0 -55
  71. data/.travis.yml +0 -44
  72. data/Appraisals +0 -22
  73. data/Gemfile +0 -8
  74. data/Rakefile +0 -46
  75. data/Vagrantfile +0 -29
  76. data/docker-compose.yml +0 -7
  77. data/dynamoid.gemspec +0 -57
  78. data/gemfiles/rails_4_2.gemfile +0 -9
  79. data/gemfiles/rails_5_0.gemfile +0 -8
  80. data/gemfiles/rails_5_1.gemfile +0 -8
  81. data/gemfiles/rails_5_2.gemfile +0 -8
  82. data/gemfiles/rails_6_0.gemfile +0 -8
@@ -5,6 +5,7 @@ require_relative 'middleware/limit'
5
5
  require_relative 'middleware/start_key'
6
6
 
7
7
  module Dynamoid
8
+ # @private
8
9
  module AdapterPlugin
9
10
  class AwsSdkV3
10
11
  class Scan
@@ -21,8 +22,8 @@ module Dynamoid
21
22
  request = build_request
22
23
 
23
24
  Enumerator.new do |yielder|
24
- api_call = -> (request) do
25
- client.scan(request).tap do |response|
25
+ api_call = lambda do |req|
26
+ client.scan(req).tap do |response|
26
27
  yielder << response
27
28
  end
28
29
  end
@@ -85,6 +86,7 @@ module Dynamoid
85
86
 
86
87
  def attributes_to_get
87
88
  return if options[:project].nil?
89
+
88
90
  options[:project].map(&:to_s)
89
91
  end
90
92
  end
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Dynamoid
4
+ # @private
4
5
  module AdapterPlugin
5
6
  class AwsSdkV3
6
7
  # Represents a table. Exposes data from the "DescribeTable" API call, and also
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Dynamoid
4
+ # @private
4
5
  module AdapterPlugin
5
6
  class AwsSdkV3
6
7
  class UntilPastTableStatus
@@ -32,7 +33,7 @@ module Dynamoid
32
33
  # See: http://docs.aws.amazon.com/sdkforruby/api/Aws/DynamoDB/Client.html#describe_table-instance_method
33
34
  rescue Aws::DynamoDB::Errors::ResourceNotFoundException => e
34
35
  case status
35
- when :creating then
36
+ when :creating
36
37
  if counter >= Dynamoid::Config.sync_retry_max_times
37
38
  Dynamoid.logger.warn "Waiting on table metadata for #{table_name} (check #{counter})"
38
39
  retry # start over at first line of begin, does not reset counter
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Dynamoid
4
+ # @private
4
5
  module ApplicationTimeZone
5
6
  def self.at(value)
6
7
  case Dynamoid::Config.application_timezone
@@ -25,12 +25,55 @@ module Dynamoid
25
25
  end
26
26
 
27
27
  module ClassMethods
28
- # create a has_many association for this document.
28
+ # Declare a +has_many+ association for this document.
29
29
  #
30
- # @param [Symbol] name the name of the association
31
- # @param [Hash] options options to pass to the association constructor
30
+ # class Category
31
+ # include Dynamoid::Document
32
+ #
33
+ # has_many :posts
34
+ # end
35
+ #
36
+ # Association is an enumerable collection and supports following addition
37
+ # operations:
38
+ #
39
+ # * +create+
40
+ # * +create!+
41
+ # * +destroy_all+
42
+ # * +delete_all+
43
+ # * +delete+
44
+ # * +<<+
45
+ # * +where+
46
+ # * +all+
47
+ # * +empty?+
48
+ # * +size+
49
+ #
50
+ # When a name of an associated class doesn't match an association name a
51
+ # class name should be specified explicitly either with +class+ or
52
+ # +class_name+ option:
53
+ #
54
+ # has_many :labels, class: Tag
55
+ # has_many :labels, class_name: 'Tag'
56
+ #
57
+ # When associated class has own +belongs_to+ association to
58
+ # the current class and the name doesn't match a name of the current
59
+ # class this name can be specified with +inverse_of+ option:
60
+ #
61
+ # class Post
62
+ # include Dynamoid::Document
63
+ #
64
+ # belongs_to :item, class_name: 'Tag'
65
+ # end
66
+ #
67
+ # class Tag
68
+ # include Dynamoid::Document
69
+ #
70
+ # has_many :posts, inverse_of: :item
71
+ # end
72
+ #
73
+ # @param name [Symbol] the name of the association
74
+ # @param options [Hash] options to pass to the association constructor
32
75
  # @option options [Class] :class the target class of the has_many association; that is, the belongs_to class
33
- # @option options [Symbol] :class_name the name of the target class of the association; that is, the name of the belongs_to class
76
+ # @option options [String] :class_name the name of the target class of the association; that is, the name of the belongs_to class
34
77
  # @option options [Symbol] :inverse_of the name of the association on the target class; that is, if the class has a belongs_to association, the name of that association
35
78
  #
36
79
  # @since 0.2.0
@@ -38,12 +81,47 @@ module Dynamoid
38
81
  association(:has_many, name, options)
39
82
  end
40
83
 
41
- # create a has_one association for this document.
84
+ # Declare a +has_one+ association for this document.
85
+ #
86
+ # class Image
87
+ # include Dynamoid::Document
42
88
  #
43
- # @param [Symbol] name the name of the association
44
- # @param [Hash] options options to pass to the association constructor
89
+ # has_one :post
90
+ # end
91
+ #
92
+ # Association supports following operations:
93
+ #
94
+ # * +create+
95
+ # * +create!+
96
+ # * +delete+
97
+ #
98
+ # When a name of an associated class doesn't match an association name a
99
+ # class name should be specified explicitly either with +class+ or
100
+ # +class_name+ option:
101
+ #
102
+ # has_one :item, class: Post
103
+ # has_one :item, class_name: 'Post'
104
+ #
105
+ # When associated class has own +belong_to+ association to the current
106
+ # class and the name doesn't match a name of the current class this name
107
+ # can be specified with +inverse_of+ option:
108
+ #
109
+ # class Post
110
+ # include Dynamoid::Document
111
+ #
112
+ # belongs_to :logo, class_name: 'Image'
113
+ # end
114
+ #
115
+ # class Image
116
+ # include Dynamoid::Document
117
+ #
118
+ # has_one :post, inverse_of: :logo
119
+ # end
120
+ #
121
+ # @param name [Symbol] the name of the association
122
+ # @param options [Hash] options to pass to the association constructor
45
123
  # @option options [Class] :class the target class of the has_one association; that is, the belongs_to class
46
- # @option options [Symbol] :class_name the name of the target class of the association; that is, the name of the belongs_to class
124
+ # @option options [String] :class_name the name of the target class of the association; that is, the name of the belongs_to class
47
125
  # @option options [Symbol] :inverse_of the name of the association on the target class; that is, if the class has a belongs_to association, the name of that association
48
126
  #
49
127
  # @since 0.2.0
@@ -51,25 +129,110 @@ module Dynamoid
51
129
  association(:has_one, name, options)
52
130
  end
53
131
 
54
- # create a belongs_to association for this document.
132
+ # Declare a +belongs_to+ association for this document.
133
+ #
134
+ # class Post
135
+ # include Dynamoid::Document
55
136
  #
56
- # @param [Symbol] name the name of the association
57
- # @param [Hash] options options to pass to the association constructor
137
+ # belongs_to :categories
138
+ # end
139
+ #
140
+ # Association supports following operations:
141
+ #
142
+ # * +create+
143
+ # * +create!+
144
+ # * +delete+
145
+ #
146
+ # When a name of an associated class doesn't match an association name a
147
+ # class name should be specified explicitly either with +class+ or
148
+ # +class_name+ option:
149
+ #
150
+ # belongs_to :item, class: Post
151
+ # belongs_to :item, class_name: 'Post'
152
+ #
153
+ # When associated class has own +has_many+ or +has_one+ association to
154
+ # the current class and the name doesn't match a name of the current
155
+ # class this name can be specified with +inverse_of+ option:
156
+ #
157
+ # class Category
158
+ # include Dynamoid::Document
159
+ #
160
+ # has_many :items, class_name: 'Post'
161
+ # end
162
+ #
163
+ # class Post
164
+ # include Dynamoid::Document
165
+ #
166
+ # belongs_to :categories, inverse_of: :items
167
+ # end
168
+ #
169
+ # By default a hash key attribute name is +id+. If an associated class
170
+ # uses another name for a hash key attribute it should be specified in
171
+ # the +belongs_to+ association:
172
+ #
173
+ # belongs_to :categories, foreign_key: :uuid
174
+ #
175
+ # @param name [Symbol] the name of the association
176
+ # @param options [Hash] options to pass to the association constructor
58
177
  # @option options [Class] :class the target class of the has_one association; that is, the has_many or has_one class
59
- # @option options [Symbol] :class_name the name of the target class of the association; that is, the name of the has_many or has_one class
178
+ # @option options [String] :class_name the name of the target class of the association; that is, the name of the has_many or has_one class
60
179
  # @option options [Symbol] :inverse_of the name of the association on the target class; that is, if the class has a has_many or has_one association, the name of that association
180
+ # @option options [Symbol] :foreign_key the name of a hash key attribute in the target class
61
181
  #
62
182
  # @since 0.2.0
63
183
  def belongs_to(name, options = {})
64
184
  association(:belongs_to, name, options)
65
185
  end
66
186
 
67
- # create a has_and_belongs_to_many association for this document.
187
+ # Declare a +has_and_belongs_to_many+ association for this document.
188
+ #
189
+ # class Post
190
+ # include Dynamoid::Document
191
+ #
192
+ # has_and_belongs_to_many :tags
193
+ # end
194
+ #
195
+ # Association is an enumerable collection and supports following addition
196
+ # operations:
197
+ #
198
+ # * +create+
199
+ # * +create!+
200
+ # * +destroy_all+
201
+ # * +delete_all+
202
+ # * +delete+
203
+ # * +<<+
204
+ # * +where+
205
+ # * +all+
206
+ # * +empty?+
207
+ # * +size+
208
+ #
209
+ # When a name of an associated class doesn't match an association name a
210
+ # class name should be specified explicitly either with +class+ or
211
+ # +class_name+ option:
212
+ #
213
+ # has_and_belongs_to_many :labels, class: Tag
214
+ # has_and_belongs_to_many :labels, class_name: 'Tag'
215
+ #
216
+ # When associated class has own +has_and_belongs_to_many+ association to
217
+ # the current class and the name doesn't match a name of the current
218
+ # class this name can be specified with +inverse_of+ option:
219
+ #
220
+ # class Tag
221
+ # include Dynamoid::Document
222
+ #
223
+ # has_and_belongs_to_many :items, class_name: 'Post'
224
+ # end
225
+ #
226
+ # class Post
227
+ # include Dynamoid::Document
228
+ #
229
+ # has_and_belongs_to_many :tags, inverse_of: :items
230
+ # end
68
231
  #
69
- # @param [Symbol] name the name of the association
70
- # @param [Hash] options options to pass to the association constructor
232
+ # @param name [Symbol] the name of the association
233
+ # @param options [Hash] options to pass to the association constructor
71
234
  # @option options [Class] :class the target class of the has_and_belongs_to_many association; that is, the belongs_to class
72
- # @option options [Symbol] :class_name the name of the target class of the association; that is, the name of the belongs_to class
235
+ # @option options [String] :class_name the name of the target class of the association; that is, the name of the belongs_to class
73
236
  # @option options [Symbol] :inverse_of the name of the association on the target class; that is, if the class has a belongs_to association, the name of that association
74
237
  #
75
238
  # @since 0.2.0
@@ -81,9 +244,9 @@ module Dynamoid
81
244
 
82
245
  # create getters and setters for an association.
83
246
  #
84
- # @param [Symbol] symbol the type (:has_one, :has_many, :has_and_belongs_to_many, :belongs_to) of the association
85
- # @param [Symbol] name the name of the association
86
- # @param [Hash] options options to pass to the association constructor; see above for all valid options
247
+ # @param type [Symbol] the type (:has_one, :has_many, :has_and_belongs_to_many, :belongs_to) of the association
248
+ # @param name [Symbol] the name of the association
249
+ # @param options [Hash] options to pass to the association constructor; see above for all valid options
87
250
  #
88
251
  # @since 0.2.0
89
252
  def association(type, name, options = {})
@@ -1,10 +1,12 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- module Dynamoid #:nodoc:
3
+ module Dynamoid
4
4
  # The base association module which all associations include. Every association has two very important components: the source and
5
5
  # the target. The source is the object which is calling the association information. It always has the target_ids inside of an attribute on itself.
6
6
  # The target is the object which is referencing by this association.
7
+ # @private
7
8
  module Associations
9
+ # @private
8
10
  module Association
9
11
  attr_accessor :name, :options, :source, :loaded
10
12
 
@@ -56,6 +58,12 @@ module Dynamoid #:nodoc:
56
58
  :set
57
59
  end
58
60
 
61
+ def disassociate_source
62
+ Array(target).each do |target_entry|
63
+ target_entry.send(target_association).disassociate(source.hash_key) if target_entry && target_association
64
+ end
65
+ end
66
+
59
67
  private
60
68
 
61
69
  # The target class name, either inferred through the association's name or specified in options.
@@ -116,7 +124,7 @@ module Dynamoid #:nodoc:
116
124
 
117
125
  # 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.
118
126
  #
119
- # @param [Hash] attribute hash for the new object
127
+ # @param attributes [Hash] attribute values for the new object
120
128
  #
121
129
  # @return [Dynamoid::Document] the newly-created object
122
130
  #
@@ -1,9 +1,10 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- module Dynamoid #:nodoc:
3
+ module Dynamoid
4
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
+ # @private
7
8
  class BelongsTo
8
9
  include SingleAssociation
9
10
 
@@ -1,8 +1,9 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- module Dynamoid #:nodoc:
3
+ module Dynamoid
4
4
  # The has and belongs to many association.
5
5
  module Associations
6
+ # @private
6
7
  class HasAndBelongsToMany
7
8
  include ManyAssociation
8
9
 
@@ -1,8 +1,9 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- module Dynamoid #:nodoc:
3
+ module Dynamoid
4
4
  # The has_many association.
5
5
  module Associations
6
+ # @private
6
7
  class HasMany
7
8
  include ManyAssociation
8
9
 
@@ -1,8 +1,9 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- module Dynamoid #:nodoc:
3
+ module Dynamoid
4
4
  # The HasOne association.
5
5
  module Associations
6
+ # @private
6
7
  class HasOne
7
8
  include Association
8
9
  include SingleAssociation
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- module Dynamoid #:nodoc:
3
+ module Dynamoid
4
4
  module Associations
5
5
  module ManyAssociation
6
6
  include Association
@@ -13,6 +13,8 @@ module Dynamoid #:nodoc:
13
13
  end
14
14
 
15
15
  include Enumerable
16
+
17
+ # @private
16
18
  # Delegate methods to the records the association represents.
17
19
  delegate :first, :last, :empty?, :size, :class, to: :records
18
20
 
@@ -20,11 +22,15 @@ module Dynamoid #:nodoc:
20
22
  #
21
23
  # @return the association records; depending on which association this is, either a single instance or an array
22
24
  #
25
+ # @private
23
26
  # @since 0.2.0
24
27
  def find_target
25
- Array(target_class.find(source_ids.to_a))
28
+ return [] if source_ids.empty?
29
+
30
+ Array(target_class.find(source_ids.to_a, raise_error: false))
26
31
  end
27
32
 
33
+ # @private
28
34
  def records
29
35
  if query.empty?
30
36
  target
@@ -43,13 +49,20 @@ module Dynamoid #:nodoc:
43
49
  records.include?(object)
44
50
  end
45
51
 
46
- # Deletes an object or array of objects from the association. This removes their records from the association field on the source,
47
- # and attempts to remove the source from the target association if it is detected to exist.
52
+ # Delete an object or array of objects from the association.
48
53
  #
49
- # @param [Dynamoid::Document] object the object (or array of objects) to remove from the association
54
+ # tag.posts.delete(post)
55
+ # tag.posts.delete([post1, post2, post3])
50
56
  #
51
- # @return [Dynamoid::Document] the deleted object
57
+ # This removes their records from the association field on the source,
58
+ # and attempts to remove the source from the target association if it is
59
+ # detected to exist.
52
60
  #
61
+ # It saves both models immediately - the source model and the target one
62
+ # so any not saved changes will be saved as well.
63
+ #
64
+ # @param object [Dynamoid::Document|Array] model (or array of models) to remove from the association
65
+ # @return [Dynamoid::Document|Array] the deleted model
53
66
  # @since 0.2.0
54
67
  def delete(object)
55
68
  disassociate(Array(object).collect(&:hash_key))
@@ -59,13 +72,19 @@ module Dynamoid #:nodoc:
59
72
  object
60
73
  end
61
74
 
62
- # Add an object or array of objects to an association. This preserves the current records in the association (if any)
63
- # and adds the object to the target association if it is detected to exist.
75
+ # Add an object or array of objects to an association.
64
76
  #
65
- # @param [Dynamoid::Document] object the object (or array of objects) to add to the association
77
+ # tag.posts << post
78
+ # tag.posts << [post1, post2, post3]
66
79
  #
67
- # @return [Dynamoid::Document] the added object
80
+ # This preserves the current records in the association (if any) and adds
81
+ # the object to the target association if it is detected to exist.
68
82
  #
83
+ # It saves both models immediately - the source model and the target one
84
+ # so any not saved changes will be saved as well.
85
+ #
86
+ # @param object [Dynamoid::Document|Array] model (or array of models) to add to the association
87
+ # @return [Dynamoid::Document] the added model
69
88
  # @since 0.2.0
70
89
  def <<(object)
71
90
  associate(Array(object).collect(&:hash_key))
@@ -82,8 +101,9 @@ module Dynamoid #:nodoc:
82
101
  #
83
102
  # @param [Dynamoid::Document] object the object (or array of objects) to add to the association
84
103
  #
85
- # @return [Dynamoid::Document] the added object
104
+ # @return [Dynamoid::Document|Array] the added object
86
105
  #
106
+ # @private
87
107
  # @since 0.2.0
88
108
  def setter(object)
89
109
  target.each { |o| delete(o) }
@@ -91,23 +111,37 @@ module Dynamoid #:nodoc:
91
111
  object
92
112
  end
93
113
 
94
- # Create a new instance of the target class and add it directly to the association. If the create fails an exception will be raised.
114
+ # Create a new instance of the target class, persist it and add directly
115
+ # to the association.
95
116
  #
96
- # @param [Hash] attribute hash for the new object
117
+ # tag.posts.create!(title: 'foo')
97
118
  #
98
- # @return [Dynamoid::Document] the newly-created object
119
+ # Several models can be created at once when an array of attributes
120
+ # specified:
121
+ #
122
+ # tag.posts.create!([{ title: 'foo' }, {title: 'bar'} ])
99
123
  #
124
+ # If the creation fails an exception will be raised.
125
+ #
126
+ # @param attributes [Hash] attribute values for the new object
127
+ # @return [Dynamoid::Document|Array] the newly-created object
100
128
  # @since 0.2.0
101
129
  def create!(attributes = {})
102
130
  self << target_class.create!(attributes)
103
131
  end
104
132
 
105
- # Create a new instance of the target class and add it directly to the association.
133
+ # Create a new instance of the target class, persist it and add directly
134
+ # to the association.
106
135
  #
107
- # @param [Hash] attribute hash for the new object
136
+ # tag.posts.create(title: 'foo')
108
137
  #
109
- # @return [Dynamoid::Document] the newly-created object
138
+ # Several models can be created at once when an array of attributes
139
+ # specified:
110
140
  #
141
+ # tag.posts.create([{ title: 'foo' }, {title: 'bar'} ])
142
+ #
143
+ # @param attributes [Hash] attribute values for the new object
144
+ # @return [Dynamoid::Document|Array] the newly-created object
111
145
  # @since 0.2.0
112
146
  def create(attributes = {})
113
147
  self << target_class.create(attributes)
@@ -115,16 +149,18 @@ module Dynamoid #:nodoc:
115
149
 
116
150
  # Create a new instance of the target class and add it directly to the association. If the create fails an exception will be raised.
117
151
  #
118
- # @param [Hash] attribute hash for the new object
119
- #
120
152
  # @return [Dynamoid::Document] the newly-created object
121
153
  #
154
+ # @private
122
155
  # @since 0.2.0
123
156
  def each(&block)
124
157
  records.each(&block)
125
158
  end
126
159
 
127
- # Destroys all members of the association and removes them from the association.
160
+ # Destroys all members of the association and removes them from the
161
+ # association.
162
+ #
163
+ # tag.posts.destroy_all
128
164
  #
129
165
  # @since 0.2.0
130
166
  def destroy_all
@@ -133,7 +169,10 @@ module Dynamoid #:nodoc:
133
169
  objs.each(&:destroy)
134
170
  end
135
171
 
136
- # Deletes all members of the association and removes them from the association.
172
+ # Deletes all members of the association and removes them from the
173
+ # association.
174
+ #
175
+ # tag.posts.delete_all
137
176
  #
138
177
  # @since 0.2.0
139
178
  def delete_all
@@ -144,10 +183,13 @@ module Dynamoid #:nodoc:
144
183
 
145
184
  # Naive association filtering.
146
185
  #
147
- # @param [Hash] A hash of attributes; each must match every returned object's attribute exactly.
186
+ # tag.posts.where(title: 'foo')
148
187
  #
149
- # @return [Dynamoid::Association] the association this method was called on (for chaining purposes)
188
+ # It loads lazily all the associated models and checks provided
189
+ # conditions. That's why only equality conditions can be specified.
150
190
  #
191
+ # @param args [Hash] A hash of attributes; each must match every returned object's attribute exactly.
192
+ # @return [Dynamoid::Association] the association this method was called on (for chaining purposes)
151
193
  # @since 0.2.0
152
194
  def where(args)
153
195
  filtered = clone
@@ -167,6 +209,7 @@ module Dynamoid #:nodoc:
167
209
 
168
210
  # Delegate methods we don't find directly to the records array.
169
211
  #
212
+ # @private
170
213
  # @since 0.2.0
171
214
  def method_missing(method, *args)
172
215
  if records.respond_to?(method)
@@ -176,10 +219,12 @@ module Dynamoid #:nodoc:
176
219
  end
177
220
  end
178
221
 
222
+ # @private
179
223
  def associate(hash_key)
180
224
  source.update_attribute(source_attribute, source_ids.merge(Array(hash_key)))
181
225
  end
182
226
 
227
+ # @private
183
228
  def disassociate(hash_key)
184
229
  source.update_attribute(source_attribute, source_ids - Array(hash_key))
185
230
  end