dynamoid 3.2.0 → 3.6.0
Sign up to get free protection for your applications and to get access to all the features.
- 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)
|