dynamoid 3.2.0 → 3.6.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/CHANGELOG.md +111 -1
- data/README.md +580 -241
- data/lib/dynamoid.rb +2 -0
- data/lib/dynamoid/adapter.rb +15 -15
- data/lib/dynamoid/adapter_plugin/aws_sdk_v3.rb +82 -102
- data/lib/dynamoid/adapter_plugin/aws_sdk_v3/batch_get_item.rb +108 -0
- data/lib/dynamoid/adapter_plugin/aws_sdk_v3/create_table.rb +29 -16
- data/lib/dynamoid/adapter_plugin/aws_sdk_v3/item_updater.rb +3 -2
- data/lib/dynamoid/adapter_plugin/aws_sdk_v3/middleware/backoff.rb +2 -2
- data/lib/dynamoid/adapter_plugin/aws_sdk_v3/middleware/limit.rb +2 -3
- data/lib/dynamoid/adapter_plugin/aws_sdk_v3/middleware/start_key.rb +2 -2
- data/lib/dynamoid/adapter_plugin/aws_sdk_v3/query.rb +15 -6
- data/lib/dynamoid/adapter_plugin/aws_sdk_v3/scan.rb +15 -5
- data/lib/dynamoid/adapter_plugin/aws_sdk_v3/table.rb +1 -0
- data/lib/dynamoid/adapter_plugin/aws_sdk_v3/until_past_table_status.rb +5 -3
- data/lib/dynamoid/application_time_zone.rb +1 -0
- data/lib/dynamoid/associations.rb +182 -19
- data/lib/dynamoid/associations/association.rb +4 -2
- data/lib/dynamoid/associations/belongs_to.rb +2 -1
- data/lib/dynamoid/associations/has_and_belongs_to_many.rb +2 -1
- data/lib/dynamoid/associations/has_many.rb +2 -1
- data/lib/dynamoid/associations/has_one.rb +2 -1
- data/lib/dynamoid/associations/many_association.rb +65 -22
- data/lib/dynamoid/associations/single_association.rb +28 -1
- data/lib/dynamoid/components.rb +8 -3
- data/lib/dynamoid/config.rb +16 -3
- data/lib/dynamoid/config/backoff_strategies/constant_backoff.rb +1 -0
- data/lib/dynamoid/config/backoff_strategies/exponential_backoff.rb +1 -0
- data/lib/dynamoid/config/options.rb +1 -0
- data/lib/dynamoid/criteria.rb +2 -1
- data/lib/dynamoid/criteria/chain.rb +418 -46
- data/lib/dynamoid/criteria/ignored_conditions_detector.rb +3 -3
- data/lib/dynamoid/criteria/key_fields_detector.rb +109 -32
- data/lib/dynamoid/criteria/nonexistent_fields_detector.rb +3 -2
- data/lib/dynamoid/criteria/overwritten_conditions_detector.rb +1 -1
- data/lib/dynamoid/dirty.rb +239 -32
- data/lib/dynamoid/document.rb +130 -251
- data/lib/dynamoid/dumping.rb +9 -0
- data/lib/dynamoid/dynamodb_time_zone.rb +1 -0
- data/lib/dynamoid/fields.rb +246 -20
- data/lib/dynamoid/finders.rb +69 -32
- data/lib/dynamoid/identity_map.rb +6 -0
- data/lib/dynamoid/indexes.rb +76 -17
- data/lib/dynamoid/loadable.rb +31 -0
- data/lib/dynamoid/log/formatter.rb +26 -0
- data/lib/dynamoid/middleware/identity_map.rb +1 -0
- data/lib/dynamoid/persistence.rb +592 -122
- data/lib/dynamoid/persistence/import.rb +73 -0
- data/lib/dynamoid/persistence/save.rb +64 -0
- data/lib/dynamoid/persistence/update_fields.rb +63 -0
- data/lib/dynamoid/persistence/upsert.rb +60 -0
- data/lib/dynamoid/primary_key_type_mapping.rb +1 -0
- data/lib/dynamoid/railtie.rb +1 -0
- data/lib/dynamoid/tasks.rb +3 -1
- data/lib/dynamoid/tasks/database.rb +1 -0
- data/lib/dynamoid/type_casting.rb +12 -2
- data/lib/dynamoid/undumping.rb +8 -0
- data/lib/dynamoid/validations.rb +2 -0
- data/lib/dynamoid/version.rb +1 -1
- metadata +49 -71
- data/.coveralls.yml +0 -1
- data/.document +0 -5
- data/.gitignore +0 -74
- data/.rspec +0 -2
- data/.rubocop.yml +0 -71
- data/.rubocop_todo.yml +0 -55
- data/.travis.yml +0 -41
- data/Appraisals +0 -28
- data/Gemfile +0 -8
- data/Rakefile +0 -46
- data/Vagrantfile +0 -29
- data/docker-compose.yml +0 -7
- data/dynamoid.gemspec +0 -57
- data/gemfiles/rails_4_2.gemfile +0 -11
- data/gemfiles/rails_5_0.gemfile +0 -10
- data/gemfiles/rails_5_1.gemfile +0 -10
- data/gemfiles/rails_5_2.gemfile +0 -10
data/lib/dynamoid/document.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
module Dynamoid
|
3
|
+
module Dynamoid
|
4
4
|
# This is the base module for all domain objects that need to be persisted to
|
5
5
|
# the database as documents.
|
6
6
|
module Document
|
@@ -17,28 +17,19 @@ module Dynamoid #:nodoc:
|
|
17
17
|
end
|
18
18
|
|
19
19
|
module ClassMethods
|
20
|
-
#
|
21
|
-
# write capacity.
|
22
|
-
#
|
23
|
-
# @param [Hash] options options to pass for this table
|
24
|
-
# @option options [Symbol] :name the name for the table; this still gets namespaced
|
25
|
-
# @option options [Symbol] :id id column for the table
|
26
|
-
# @option options [Integer] :read_capacity set the read capacity for the table; does not work on existing tables
|
27
|
-
# @option options [Integer] :write_capacity set the write capacity for the table; does not work on existing tables
|
28
|
-
#
|
29
|
-
# @since 0.4.0
|
20
|
+
# @private
|
30
21
|
def table(options = {})
|
31
22
|
self.options = options
|
32
23
|
super if defined? super
|
33
24
|
end
|
34
25
|
|
35
26
|
def attr_readonly(*read_only_attributes)
|
36
|
-
ActiveSupport::Deprecation.warn('[Dynamoid] .attr_readonly is deprecated! Call .find instead of')
|
37
27
|
self.read_only_attributes.concat read_only_attributes.map(&:to_s)
|
38
28
|
end
|
39
29
|
|
40
|
-
# Returns the
|
30
|
+
# Returns the read capacity for this table.
|
41
31
|
#
|
32
|
+
# @return [Integer] read capacity units
|
42
33
|
# @since 0.4.0
|
43
34
|
def read_capacity
|
44
35
|
options[:read_capacity] || Dynamoid::Config.read_capacity
|
@@ -46,91 +37,121 @@ module Dynamoid #:nodoc:
|
|
46
37
|
|
47
38
|
# Returns the write_capacity for this table.
|
48
39
|
#
|
40
|
+
# @return [Integer] write capacity units
|
49
41
|
# @since 0.4.0
|
50
42
|
def write_capacity
|
51
43
|
options[:write_capacity] || Dynamoid::Config.write_capacity
|
52
44
|
end
|
53
45
|
|
46
|
+
# Returns the billing (capacity) mode for this table.
|
47
|
+
#
|
48
|
+
# Could be either +provisioned+ or +on_demand+.
|
49
|
+
#
|
50
|
+
# @return [Symbol]
|
51
|
+
def capacity_mode
|
52
|
+
options[:capacity_mode] || Dynamoid::Config.capacity_mode
|
53
|
+
end
|
54
|
+
|
54
55
|
# Returns the field name used to support STI for this table.
|
56
|
+
#
|
57
|
+
# Default field name is +type+ but it can be overrided in the +table+
|
58
|
+
# method call.
|
59
|
+
#
|
60
|
+
# User.inheritance_field # => :type
|
55
61
|
def inheritance_field
|
56
62
|
options[:inheritance_field] || :type
|
57
63
|
end
|
58
64
|
|
59
|
-
# Returns the
|
65
|
+
# Returns the hash key field name for this class.
|
60
66
|
#
|
67
|
+
# By default +id+ field is used. But it can be overriden in the +table+
|
68
|
+
# method call.
|
69
|
+
#
|
70
|
+
# User.hash_key # => :id
|
71
|
+
#
|
72
|
+
# @return [Symbol] a hash key name
|
61
73
|
# @since 0.4.0
|
62
74
|
def hash_key
|
63
75
|
options[:key] || :id
|
64
76
|
end
|
65
77
|
|
66
|
-
#
|
78
|
+
# Return the count of items for this class.
|
79
|
+
#
|
80
|
+
# It returns aproximate value based on DynamoDB statistic. DynamoDB
|
81
|
+
# updates it periodicaly so the value can be no accurate.
|
67
82
|
#
|
83
|
+
# It's a reletivly cheap operation and doesn't read all the items in a
|
84
|
+
# table. It makes just one HTTP request to DynamoDB.
|
85
|
+
#
|
86
|
+
# @return [Integer] items count in a table
|
68
87
|
# @since 0.6.1
|
69
88
|
def count
|
70
89
|
Dynamoid.adapter.count(table_name)
|
71
90
|
end
|
72
91
|
|
73
|
-
# Initialize a new object
|
92
|
+
# Initialize a new object.
|
74
93
|
#
|
75
|
-
#
|
94
|
+
# User.build(name: 'A')
|
76
95
|
#
|
77
|
-
#
|
96
|
+
# Initialize an object and pass it into a block to set other attributes.
|
78
97
|
#
|
79
|
-
#
|
80
|
-
|
81
|
-
|
82
|
-
attrs.map { |attr| create(attr) }
|
83
|
-
else
|
84
|
-
build(attrs).tap(&:save)
|
85
|
-
end
|
86
|
-
end
|
87
|
-
|
88
|
-
# Initialize a new object and immediately save it to the database. Raise an exception if persistence failed.
|
98
|
+
# User.build(name: 'A') do |u|
|
99
|
+
# u.age = 21
|
100
|
+
# end
|
89
101
|
#
|
90
|
-
#
|
102
|
+
# The only difference between +build+ and +new+ methods is that +build+
|
103
|
+
# supports STI (Single table inheritance) and looks at the inheritance
|
104
|
+
# field. So it can build a model of actual class. For instance:
|
91
105
|
#
|
92
|
-
#
|
106
|
+
# class Employee
|
107
|
+
# include Dynamoid::Document
|
93
108
|
#
|
94
|
-
#
|
95
|
-
|
96
|
-
|
97
|
-
attrs.map { |attr| create!(attr) }
|
98
|
-
else
|
99
|
-
build(attrs).tap(&:save!)
|
100
|
-
end
|
101
|
-
end
|
102
|
-
|
103
|
-
# Initialize a new object.
|
109
|
+
# field :type
|
110
|
+
# field :name
|
111
|
+
# end
|
104
112
|
#
|
105
|
-
#
|
113
|
+
# class Manager < Employee
|
114
|
+
# end
|
106
115
|
#
|
107
|
-
#
|
116
|
+
# Employee.build(name: 'Alice', type: 'Manager') # => #<Manager:0x00007f945756e3f0 ...>
|
108
117
|
#
|
118
|
+
# @param attrs [Hash] Attributes with which to create the document
|
119
|
+
# @param block [Proc] Block to process a document after initialization
|
120
|
+
# @return [Dynamoid::Document] the new document
|
109
121
|
# @since 0.2.0
|
110
|
-
def build(attrs = {})
|
111
|
-
choose_right_class(attrs).new(attrs)
|
122
|
+
def build(attrs = {}, &block)
|
123
|
+
choose_right_class(attrs).new(attrs, &block)
|
112
124
|
end
|
113
125
|
|
114
|
-
# Does this
|
126
|
+
# Does this model exist in a table?
|
115
127
|
#
|
116
|
-
#
|
117
|
-
# Multiple keys and single compound primary key should be passed only as Array explicitily.
|
128
|
+
# User.exists?('713') # => true
|
118
129
|
#
|
119
|
-
#
|
130
|
+
# If a range key is declared it should be specified in the following way:
|
120
131
|
#
|
121
|
-
#
|
132
|
+
# User.exists?([['713', 'range-key-value']]) # => true
|
122
133
|
#
|
123
|
-
#
|
134
|
+
# It's possible to check existence of several models at once:
|
124
135
|
#
|
125
|
-
#
|
136
|
+
# User.exists?(['713', '714', '715'])
|
126
137
|
#
|
127
|
-
#
|
128
|
-
# Post.exist?([713, 210])
|
138
|
+
# Or in case when a range key is declared:
|
129
139
|
#
|
130
|
-
#
|
140
|
+
# User.exists?(
|
141
|
+
# [
|
142
|
+
# ['713', 'range-key-value-1'],
|
143
|
+
# ['714', 'range-key-value-2'],
|
144
|
+
# ['715', 'range-key-value-3']
|
145
|
+
# ]
|
146
|
+
# )
|
131
147
|
#
|
132
|
-
#
|
148
|
+
# It's also possible to specify models not with primary key but with
|
149
|
+
# conditions on the attributes (in the +where+ method style):
|
133
150
|
#
|
151
|
+
# User.exists?(age: 20, 'created_at.gt': Time.now - 1.day)
|
152
|
+
#
|
153
|
+
# @param id_or_conditions [String|Array[String]|Array[Array]|Hash] the primary id of the model, a list of primary ids or a hash with the options to filter from.
|
154
|
+
# @return [true|false]
|
134
155
|
# @since 0.2.0
|
135
156
|
def exists?(id_or_conditions = {})
|
136
157
|
case id_or_conditions
|
@@ -145,165 +166,12 @@ module Dynamoid #:nodoc:
|
|
145
166
|
end
|
146
167
|
end
|
147
168
|
|
148
|
-
#
|
149
|
-
# Instantiates document and saves changes. Runs validations and callbacks.
|
150
|
-
#
|
151
|
-
# @param [Scalar value] partition key
|
152
|
-
# @param [Scalar value] sort key, optional
|
153
|
-
# @param [Hash] attributes
|
154
|
-
#
|
155
|
-
# @return [Dynamoid::Doument] updated document
|
156
|
-
#
|
157
|
-
# @example Update document
|
158
|
-
# Post.update(101, read: true)
|
159
|
-
def update(hash_key, range_key_value = nil, attrs)
|
160
|
-
model = find(hash_key, range_key: range_key_value, consistent_read: true)
|
161
|
-
model.update_attributes(attrs)
|
162
|
-
model
|
163
|
-
end
|
164
|
-
|
165
|
-
# Update document.
|
166
|
-
# Uses efficient low-level `UpdateItem` API call.
|
167
|
-
# Changes attibutes and loads new document version with one API call.
|
168
|
-
# Doesn't run validations and callbacks. Can make conditional update.
|
169
|
-
# If a document doesn't exist or specified conditions failed - returns `nil`
|
170
|
-
#
|
171
|
-
# @param [Scalar value] partition key
|
172
|
-
# @param [Scalar value] sort key (optional)
|
173
|
-
# @param [Hash] attributes
|
174
|
-
# @param [Hash] conditions
|
175
|
-
#
|
176
|
-
# @return [Dynamoid::Document/nil] updated document
|
177
|
-
#
|
178
|
-
# @example Update document
|
179
|
-
# Post.update_fields(101, read: true)
|
180
|
-
#
|
181
|
-
# @example Update document with condition
|
182
|
-
# Post.update_fields(101, { read: true }, if: { version: 1 })
|
183
|
-
def update_fields(hash_key_value, range_key_value = nil, attrs = {}, conditions = {})
|
184
|
-
optional_params = [range_key_value, attrs, conditions].compact
|
185
|
-
if optional_params.first.is_a?(Hash)
|
186
|
-
range_key_value = nil
|
187
|
-
attrs, conditions = optional_params[0..1]
|
188
|
-
else
|
189
|
-
range_key_value = optional_params.first
|
190
|
-
attrs, conditions = optional_params[1..2]
|
191
|
-
end
|
192
|
-
|
193
|
-
options = if range_key
|
194
|
-
value_casted = TypeCasting.cast_field(range_key_value, attributes[range_key])
|
195
|
-
value_dumped = Dumping.dump_field(value_casted, attributes[range_key])
|
196
|
-
{ range_key: value_dumped }
|
197
|
-
else
|
198
|
-
{}
|
199
|
-
end
|
200
|
-
|
201
|
-
(conditions[:if_exists] ||= {})[hash_key] = hash_key_value
|
202
|
-
options[:conditions] = conditions
|
203
|
-
|
204
|
-
attrs = attrs.symbolize_keys
|
205
|
-
if Dynamoid::Config.timestamps
|
206
|
-
attrs[:updated_at] ||= DateTime.now.in_time_zone(Time.zone)
|
207
|
-
end
|
208
|
-
|
209
|
-
begin
|
210
|
-
new_attrs = Dynamoid.adapter.update_item(table_name, hash_key_value, options) do |t|
|
211
|
-
attrs.each do |k, v|
|
212
|
-
value_casted = TypeCasting.cast_field(v, attributes[k])
|
213
|
-
value_dumped = Dumping.dump_field(value_casted, attributes[k])
|
214
|
-
t.set(k => value_dumped)
|
215
|
-
end
|
216
|
-
end
|
217
|
-
attrs_undumped = Undumping.undump_attributes(new_attrs, attributes)
|
218
|
-
new(attrs_undumped)
|
219
|
-
rescue Dynamoid::Errors::ConditionalCheckFailedException
|
220
|
-
end
|
221
|
-
end
|
222
|
-
|
223
|
-
# Update existing document or create new one.
|
224
|
-
# Similar to `.update_fields`. The only diffirence is creating new document.
|
225
|
-
#
|
226
|
-
# Uses efficient low-level `UpdateItem` API call.
|
227
|
-
# Changes attibutes and loads new document version with one API call.
|
228
|
-
# Doesn't run validations and callbacks. Can make conditional update.
|
229
|
-
# If specified conditions failed - returns `nil`
|
230
|
-
#
|
231
|
-
# @param [Scalar value] partition key
|
232
|
-
# @param [Scalar value] sort key (optional)
|
233
|
-
# @param [Hash] attributes
|
234
|
-
# @param [Hash] conditions
|
235
|
-
#
|
236
|
-
# @return [Dynamoid::Document/nil] updated document
|
237
|
-
#
|
238
|
-
# @example Update document
|
239
|
-
# Post.update(101, read: true)
|
240
|
-
#
|
241
|
-
# @example Update document
|
242
|
-
# Post.upsert(101, read: true)
|
243
|
-
def upsert(hash_key_value, range_key_value = nil, attrs = {}, conditions = {})
|
244
|
-
optional_params = [range_key_value, attrs, conditions].compact
|
245
|
-
if optional_params.first.is_a?(Hash)
|
246
|
-
range_key_value = nil
|
247
|
-
attrs, conditions = optional_params[0..1]
|
248
|
-
else
|
249
|
-
range_key_value = optional_params.first
|
250
|
-
attrs, conditions = optional_params[1..2]
|
251
|
-
end
|
252
|
-
|
253
|
-
options = if range_key
|
254
|
-
value_casted = TypeCasting.cast_field(range_key_value, attributes[range_key])
|
255
|
-
value_dumped = Dumping.dump_field(value_casted, attributes[range_key])
|
256
|
-
{ range_key: value_dumped }
|
257
|
-
else
|
258
|
-
{}
|
259
|
-
end
|
260
|
-
|
261
|
-
options[:conditions] = conditions
|
262
|
-
|
263
|
-
attrs = attrs.symbolize_keys
|
264
|
-
if Dynamoid::Config.timestamps
|
265
|
-
attrs[:updated_at] ||= DateTime.now.in_time_zone(Time.zone)
|
266
|
-
end
|
267
|
-
|
268
|
-
begin
|
269
|
-
new_attrs = Dynamoid.adapter.update_item(table_name, hash_key_value, options) do |t|
|
270
|
-
attrs.each do |k, v|
|
271
|
-
value_casted = TypeCasting.cast_field(v, attributes[k])
|
272
|
-
value_dumped = Dumping.dump_field(value_casted, attributes[k])
|
273
|
-
|
274
|
-
t.set(k => value_dumped)
|
275
|
-
end
|
276
|
-
end
|
277
|
-
|
278
|
-
attrs_undumped = Undumping.undump_attributes(new_attrs, attributes)
|
279
|
-
new(attrs_undumped)
|
280
|
-
rescue Dynamoid::Errors::ConditionalCheckFailedException
|
281
|
-
end
|
282
|
-
end
|
283
|
-
|
284
|
-
def inc(hash_key_value, range_key_value = nil, counters)
|
285
|
-
options = if range_key
|
286
|
-
value_casted = TypeCasting.cast_field(range_key_value, attributes[range_key])
|
287
|
-
value_dumped = Dumping.dump_field(value_casted, attributes[range_key])
|
288
|
-
{ range_key: value_dumped }
|
289
|
-
else
|
290
|
-
{}
|
291
|
-
end
|
292
|
-
|
293
|
-
Dynamoid.adapter.update_item(table_name, hash_key_value, options) do |t|
|
294
|
-
counters.each do |k, v|
|
295
|
-
value_casted = TypeCasting.cast_field(v, attributes[k])
|
296
|
-
value_dumped = Dumping.dump_field(value_casted, attributes[k])
|
297
|
-
|
298
|
-
t.add(k => value_dumped)
|
299
|
-
end
|
300
|
-
end
|
301
|
-
end
|
302
|
-
|
169
|
+
# @private
|
303
170
|
def deep_subclasses
|
304
171
|
subclasses + subclasses.map(&:deep_subclasses).flatten
|
305
172
|
end
|
306
173
|
|
174
|
+
# @private
|
307
175
|
def choose_right_class(attrs)
|
308
176
|
attrs[inheritance_field] ? attrs[inheritance_field].constantize : self
|
309
177
|
end
|
@@ -311,41 +179,50 @@ module Dynamoid #:nodoc:
|
|
311
179
|
|
312
180
|
# Initialize a new object.
|
313
181
|
#
|
314
|
-
#
|
182
|
+
# User.new(name: 'A')
|
183
|
+
#
|
184
|
+
# Initialize an object and pass it into a block to set other attributes.
|
185
|
+
#
|
186
|
+
# User.new(name: 'A') do |u|
|
187
|
+
# u.age = 21
|
188
|
+
# end
|
315
189
|
#
|
190
|
+
# @param attrs [Hash] Attributes with which to create the document
|
191
|
+
# @param block [Proc] Block to process a document after initialization
|
316
192
|
# @return [Dynamoid::Document] the new document
|
317
193
|
#
|
318
194
|
# @since 0.2.0
|
319
|
-
def initialize(attrs = {})
|
195
|
+
def initialize(attrs = {}, &block)
|
320
196
|
run_callbacks :initialize do
|
321
197
|
@new_record = true
|
322
198
|
@attributes ||= {}
|
323
199
|
@associations ||= {}
|
324
200
|
@attributes_before_type_cast ||= {}
|
325
201
|
|
326
|
-
attrs_with_defaults = {}
|
327
|
-
|
328
|
-
|
329
|
-
|
330
|
-
|
331
|
-
|
332
|
-
end
|
202
|
+
attrs_with_defaults = self.class.attributes.each_with_object({}) do |(attribute, options), res|
|
203
|
+
if attrs.key?(attribute)
|
204
|
+
res[attribute] = attrs[attribute]
|
205
|
+
elsif options.key?(:default)
|
206
|
+
res[attribute] = evaluate_default_value(options[:default])
|
207
|
+
end
|
333
208
|
end
|
334
209
|
|
335
210
|
attrs_virtual = attrs.slice(*(attrs.keys - self.class.attributes.keys))
|
336
211
|
|
337
212
|
load(attrs_with_defaults.merge(attrs_virtual))
|
338
|
-
end
|
339
|
-
end
|
340
213
|
|
341
|
-
|
342
|
-
|
343
|
-
|
214
|
+
if block
|
215
|
+
block.call(self)
|
216
|
+
end
|
344
217
|
end
|
345
218
|
end
|
346
219
|
|
347
|
-
#
|
220
|
+
# Check equality of two models.
|
221
|
+
#
|
222
|
+
# A model is equal to another model only if their primary keys (hash key
|
223
|
+
# and optionaly range key) are equal.
|
348
224
|
#
|
225
|
+
# @return [true|false]
|
349
226
|
# @since 0.2.0
|
350
227
|
def ==(other)
|
351
228
|
if self.class.identity_map_on?
|
@@ -357,54 +234,54 @@ module Dynamoid #:nodoc:
|
|
357
234
|
end
|
358
235
|
end
|
359
236
|
|
237
|
+
# Check equality of two models.
|
238
|
+
#
|
239
|
+
# Works exactly like +==+ does.
|
240
|
+
#
|
241
|
+
# @return [true|false]
|
360
242
|
def eql?(other)
|
361
243
|
self == other
|
362
244
|
end
|
363
245
|
|
364
|
-
|
365
|
-
hash_key.hash ^ range_value.hash
|
366
|
-
end
|
367
|
-
|
368
|
-
# Reload an object from the database -- if you suspect the object has changed in the datastore and you need those
|
369
|
-
# changes to be reflected immediately, you would call this method. This is a consistent read.
|
246
|
+
# Generate an Integer hash value for this model.
|
370
247
|
#
|
371
|
-
#
|
248
|
+
# Hash value is based on primary key. So models can be used safely as a
|
249
|
+
# +Hash+ keys.
|
372
250
|
#
|
373
|
-
# @
|
374
|
-
def
|
375
|
-
|
376
|
-
|
377
|
-
if self.class.range_key
|
378
|
-
options[:range_key] = range_value
|
379
|
-
end
|
380
|
-
|
381
|
-
self.attributes = self.class.find(hash_key, options).attributes
|
382
|
-
@associations.values.each(&:reset)
|
383
|
-
self
|
251
|
+
# @return [Integer]
|
252
|
+
def hash
|
253
|
+
hash_key.hash ^ range_value.hash
|
384
254
|
end
|
385
255
|
|
386
|
-
# Return
|
256
|
+
# Return a model's hash key value.
|
387
257
|
#
|
388
258
|
# @since 0.4.0
|
389
259
|
def hash_key
|
390
|
-
|
260
|
+
self[self.class.hash_key.to_sym]
|
391
261
|
end
|
392
262
|
|
393
|
-
# Assign
|
263
|
+
# Assign a model's hash key value, regardless of what it might be called to
|
264
|
+
# the object.
|
394
265
|
#
|
395
266
|
# @since 0.4.0
|
396
267
|
def hash_key=(value)
|
397
|
-
|
268
|
+
self[self.class.hash_key.to_sym] = value
|
398
269
|
end
|
399
270
|
|
271
|
+
# Return a model's range key value.
|
272
|
+
#
|
273
|
+
# Returns +nil+ if a range key isn't declared for a model.
|
400
274
|
def range_value
|
401
|
-
if
|
402
|
-
|
275
|
+
if self.class.range_key
|
276
|
+
self[self.class.range_key.to_sym]
|
403
277
|
end
|
404
278
|
end
|
405
279
|
|
280
|
+
# Assign a model's range key value.
|
406
281
|
def range_value=(value)
|
407
|
-
|
282
|
+
if self.class.range_key
|
283
|
+
self[self.class.range_key.to_sym] = value
|
284
|
+
end
|
408
285
|
end
|
409
286
|
|
410
287
|
private
|
@@ -416,7 +293,7 @@ module Dynamoid #:nodoc:
|
|
416
293
|
# Evaluates the default value given, this is used by undump
|
417
294
|
# when determining the value of the default given for a field options.
|
418
295
|
#
|
419
|
-
# @param [Object]
|
296
|
+
# @param val [Object] the attribute's default value
|
420
297
|
def evaluate_default_value(val)
|
421
298
|
if val.respond_to?(:call)
|
422
299
|
val.call
|
@@ -428,3 +305,5 @@ module Dynamoid #:nodoc:
|
|
428
305
|
end
|
429
306
|
end
|
430
307
|
end
|
308
|
+
|
309
|
+
ActiveSupport.run_load_hooks(:dynamoid, Dynamoid::Document)
|