dynamoid 3.5.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 +35 -4
- data/README.md +24 -18
- data/lib/dynamoid.rb +1 -0
- data/lib/dynamoid/adapter.rb +7 -4
- data/lib/dynamoid/adapter_plugin/aws_sdk_v3.rb +14 -11
- data/lib/dynamoid/adapter_plugin/aws_sdk_v3/batch_get_item.rb +1 -0
- data/lib/dynamoid/adapter_plugin/aws_sdk_v3/create_table.rb +8 -7
- data/lib/dynamoid/adapter_plugin/aws_sdk_v3/item_updater.rb +3 -2
- data/lib/dynamoid/adapter_plugin/aws_sdk_v3/middleware/backoff.rb +1 -0
- data/lib/dynamoid/adapter_plugin/aws_sdk_v3/middleware/limit.rb +1 -0
- data/lib/dynamoid/adapter_plugin/aws_sdk_v3/middleware/start_key.rb +1 -0
- data/lib/dynamoid/adapter_plugin/aws_sdk_v3/query.rb +1 -0
- data/lib/dynamoid/adapter_plugin/aws_sdk_v3/scan.rb +1 -0
- 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 +1 -0
- 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 +1 -0
- data/lib/dynamoid/config.rb +3 -2
- 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 +1 -0
- data/lib/dynamoid/criteria/chain.rb +353 -33
- data/lib/dynamoid/criteria/ignored_conditions_detector.rb +1 -0
- data/lib/dynamoid/criteria/key_fields_detector.rb +10 -1
- data/lib/dynamoid/criteria/nonexistent_fields_detector.rb +1 -0
- data/lib/dynamoid/criteria/overwritten_conditions_detector.rb +1 -0
- data/lib/dynamoid/dirty.rb +71 -16
- data/lib/dynamoid/document.rb +123 -42
- data/lib/dynamoid/dumping.rb +9 -0
- data/lib/dynamoid/dynamodb_time_zone.rb +1 -0
- data/lib/dynamoid/fields.rb +189 -16
- data/lib/dynamoid/finders.rb +65 -28
- data/lib/dynamoid/identity_map.rb +6 -0
- data/lib/dynamoid/indexes.rb +74 -15
- data/lib/dynamoid/log/formatter.rb +26 -0
- data/lib/dynamoid/middleware/identity_map.rb +1 -0
- data/lib/dynamoid/persistence.rb +452 -106
- data/lib/dynamoid/persistence/import.rb +1 -0
- data/lib/dynamoid/persistence/save.rb +1 -0
- data/lib/dynamoid/persistence/update_fields.rb +1 -0
- data/lib/dynamoid/persistence/upsert.rb +1 -0
- data/lib/dynamoid/primary_key_type_mapping.rb +1 -0
- data/lib/dynamoid/railtie.rb +1 -0
- data/lib/dynamoid/tasks/database.rb +1 -0
- data/lib/dynamoid/type_casting.rb +12 -0
- data/lib/dynamoid/undumping.rb +8 -0
- data/lib/dynamoid/validations.rb +2 -0
- data/lib/dynamoid/version.rb +1 -1
- metadata +7 -19
@@ -1,7 +1,8 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
module Dynamoid
|
3
|
+
module Dynamoid
|
4
4
|
module Criteria
|
5
|
+
# @private
|
5
6
|
class KeyFieldsDetector
|
6
7
|
class Query
|
7
8
|
def initialize(query_hash)
|
@@ -10,6 +11,10 @@ module Dynamoid #:nodoc:
|
|
10
11
|
@fields = query_hash.keys.map(&:to_s).map { |s| s.split('.').first }
|
11
12
|
end
|
12
13
|
|
14
|
+
def contain_only?(field_names)
|
15
|
+
(@fields - field_names.map(&:to_s)).blank?
|
16
|
+
end
|
17
|
+
|
13
18
|
def contain?(field_name)
|
14
19
|
@fields.include?(field_name.to_s)
|
15
20
|
end
|
@@ -26,6 +31,10 @@ module Dynamoid #:nodoc:
|
|
26
31
|
@result = find_keys_in_query
|
27
32
|
end
|
28
33
|
|
34
|
+
def non_key_present?
|
35
|
+
!@query.contain_only?([hash_key, range_key].compact)
|
36
|
+
end
|
37
|
+
|
29
38
|
def key_present?
|
30
39
|
@result.present?
|
31
40
|
end
|
data/lib/dynamoid/dirty.rb
CHANGED
@@ -22,6 +22,7 @@ module Dynamoid
|
|
22
22
|
attribute_method_affix prefix: 'restore_', suffix: '!'
|
23
23
|
end
|
24
24
|
|
25
|
+
# @private
|
25
26
|
module ClassMethods
|
26
27
|
def update_fields(*)
|
27
28
|
if model = super
|
@@ -44,6 +45,7 @@ module Dynamoid
|
|
44
45
|
end
|
45
46
|
end
|
46
47
|
|
48
|
+
# @private
|
47
49
|
def save(*)
|
48
50
|
if status = super
|
49
51
|
changes_applied
|
@@ -51,24 +53,28 @@ module Dynamoid
|
|
51
53
|
status
|
52
54
|
end
|
53
55
|
|
56
|
+
# @private
|
54
57
|
def save!(*)
|
55
58
|
super.tap do
|
56
59
|
changes_applied
|
57
60
|
end
|
58
61
|
end
|
59
62
|
|
63
|
+
# @private
|
60
64
|
def update(*)
|
61
65
|
super.tap do
|
62
66
|
clear_changes_information
|
63
67
|
end
|
64
68
|
end
|
65
69
|
|
70
|
+
# @private
|
66
71
|
def update!(*)
|
67
72
|
super.tap do
|
68
73
|
clear_changes_information
|
69
74
|
end
|
70
75
|
end
|
71
76
|
|
77
|
+
# @private
|
72
78
|
def reload(*)
|
73
79
|
super.tap do
|
74
80
|
clear_changes_information
|
@@ -78,17 +84,22 @@ module Dynamoid
|
|
78
84
|
# Returns +true+ if any attribute have unsaved changes, +false+ otherwise.
|
79
85
|
#
|
80
86
|
# person.changed? # => false
|
81
|
-
# person.name = '
|
87
|
+
# person.name = 'Bob'
|
82
88
|
# person.changed? # => true
|
89
|
+
#
|
90
|
+
# @return [true|false]
|
83
91
|
def changed?
|
84
92
|
changed_attributes.present?
|
85
93
|
end
|
86
94
|
|
87
|
-
# Returns an array with
|
95
|
+
# Returns an array with names of the attributes with unsaved changes.
|
88
96
|
#
|
97
|
+
# person = Person.new
|
89
98
|
# person.changed # => []
|
90
|
-
# person.name = '
|
99
|
+
# person.name = 'Bob'
|
91
100
|
# person.changed # => ["name"]
|
101
|
+
#
|
102
|
+
# @return [Array[String]]
|
92
103
|
def changed
|
93
104
|
changed_attributes.keys
|
94
105
|
end
|
@@ -97,18 +108,22 @@ module Dynamoid
|
|
97
108
|
# and new values like <tt>attr => [original value, new value]</tt>.
|
98
109
|
#
|
99
110
|
# person.changes # => {}
|
100
|
-
# person.name = '
|
101
|
-
# person.changes # => { "name" => ["
|
111
|
+
# person.name = 'Bob'
|
112
|
+
# person.changes # => { "name" => ["Bill", "Bob"] }
|
113
|
+
#
|
114
|
+
# @return [ActiveSupport::HashWithIndifferentAccess]
|
102
115
|
def changes
|
103
116
|
ActiveSupport::HashWithIndifferentAccess[changed.map { |attr| [attr, attribute_change(attr)] }]
|
104
117
|
end
|
105
118
|
|
106
119
|
# Returns a hash of attributes that were changed before the model was saved.
|
107
120
|
#
|
108
|
-
# person.name # => "
|
109
|
-
# person.name = '
|
121
|
+
# person.name # => "Bob"
|
122
|
+
# person.name = 'Robert'
|
110
123
|
# person.save
|
111
|
-
# person.previous_changes # => {"name" => ["
|
124
|
+
# person.previous_changes # => {"name" => ["Bob", "Robert"]}
|
125
|
+
#
|
126
|
+
# @return [ActiveSupport::HashWithIndifferentAccess]
|
112
127
|
def previous_changes
|
113
128
|
@previously_changed ||= ActiveSupport::HashWithIndifferentAccess.new
|
114
129
|
end
|
@@ -116,15 +131,28 @@ module Dynamoid
|
|
116
131
|
# Returns a hash of the attributes with unsaved changes indicating their original
|
117
132
|
# values like <tt>attr => original value</tt>.
|
118
133
|
#
|
119
|
-
# person.name # => "
|
120
|
-
# person.name = '
|
121
|
-
# person.changed_attributes # => {"name" => "
|
134
|
+
# person.name # => "Bob"
|
135
|
+
# person.name = 'Robert'
|
136
|
+
# person.changed_attributes # => {"name" => "Bob"}
|
137
|
+
#
|
138
|
+
# @return [ActiveSupport::HashWithIndifferentAccess]
|
122
139
|
def changed_attributes
|
123
140
|
@changed_attributes ||= ActiveSupport::HashWithIndifferentAccess.new
|
124
141
|
end
|
125
142
|
|
126
143
|
# Handle <tt>*_changed?</tt> for +method_missing+.
|
127
|
-
|
144
|
+
#
|
145
|
+
# person.attribute_changed?(:name) # => true
|
146
|
+
# person.attribute_changed?(:name, from: 'Alice')
|
147
|
+
# person.attribute_changed?(:name, to: 'Bob')
|
148
|
+
# person.attribute_changed?(:name, from: 'Alice', to: 'Bod')
|
149
|
+
#
|
150
|
+
# @private
|
151
|
+
# @param attr [Symbol] attribute name
|
152
|
+
# @param options [Hash] conditions on +from+ and +to+ value (optional)
|
153
|
+
# @option options [Symbol] :from previous attribute value
|
154
|
+
# @option options [Symbol] :to current attribute value
|
155
|
+
def attribute_changed?(attr, options = {})
|
128
156
|
result = changes_include?(attr)
|
129
157
|
result &&= options[:to] == __send__(attr) if options.key?(:to)
|
130
158
|
result &&= options[:from] == changed_attributes[attr] if options.key?(:from)
|
@@ -132,21 +160,48 @@ module Dynamoid
|
|
132
160
|
end
|
133
161
|
|
134
162
|
# Handle <tt>*_was</tt> for +method_missing+.
|
135
|
-
|
163
|
+
#
|
164
|
+
# person = Person.create(name: 'Alice')
|
165
|
+
# person.name = 'Bob'
|
166
|
+
# person.attribute_was(:name) # => "Alice"
|
167
|
+
#
|
168
|
+
# @private
|
169
|
+
# @param attr [Symbol] attribute name
|
170
|
+
def attribute_was(attr)
|
136
171
|
attribute_changed?(attr) ? changed_attributes[attr] : __send__(attr)
|
137
172
|
end
|
138
173
|
|
139
174
|
# Restore all previous data of the provided attributes.
|
175
|
+
#
|
176
|
+
# @param attributes [Array[Symbol]] a list of attribute names
|
140
177
|
def restore_attributes(attributes = changed)
|
141
178
|
attributes.each { |attr| restore_attribute! attr }
|
142
179
|
end
|
143
180
|
|
144
181
|
# Handles <tt>*_previously_changed?</tt> for +method_missing+.
|
145
|
-
|
182
|
+
#
|
183
|
+
# person = Person.create(name: 'Alice')
|
184
|
+
# person.name = 'Bob'
|
185
|
+
# person.save
|
186
|
+
# person.attribute_changed?(:name) # => true
|
187
|
+
#
|
188
|
+
# @private
|
189
|
+
# @param attr [Symbol] attribute name
|
190
|
+
# @return [true|false]
|
191
|
+
def attribute_previously_changed?(attr)
|
146
192
|
previous_changes_include?(attr)
|
147
193
|
end
|
148
194
|
|
149
195
|
# Handles <tt>*_previous_change</tt> for +method_missing+.
|
196
|
+
#
|
197
|
+
# person = Person.create(name: 'Alice')
|
198
|
+
# person.name = 'Bob'
|
199
|
+
# person.save
|
200
|
+
# person.attribute_previously_changed(:name) # => ["Alice", "Bob"]
|
201
|
+
#
|
202
|
+
# @private
|
203
|
+
# @param attr [Symbol]
|
204
|
+
# @return [Array]
|
150
205
|
def attribute_previous_change(attr)
|
151
206
|
previous_changes[attr] if attribute_previously_changed?(attr)
|
152
207
|
end
|
@@ -204,7 +259,7 @@ module Dynamoid
|
|
204
259
|
|
205
260
|
# This is necessary because `changed_attributes` might be overridden in
|
206
261
|
# other implemntations (e.g. in `ActiveRecord`)
|
207
|
-
alias attributes_changed_by_setter changed_attributes
|
262
|
+
alias attributes_changed_by_setter changed_attributes
|
208
263
|
|
209
264
|
# Force an attribute to have a particular "before" value
|
210
265
|
def set_attribute_was(attr, old_value)
|
@@ -212,7 +267,7 @@ module Dynamoid
|
|
212
267
|
end
|
213
268
|
|
214
269
|
# Remove changes information for the provided attributes.
|
215
|
-
def clear_attribute_changes(attributes)
|
270
|
+
def clear_attribute_changes(attributes)
|
216
271
|
attributes_changed_by_setter.except!(*attributes)
|
217
272
|
end
|
218
273
|
end
|
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,31 +37,53 @@ 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
|
|
54
46
|
# Returns the billing (capacity) mode for this table.
|
55
|
-
#
|
47
|
+
#
|
48
|
+
# Could be either +provisioned+ or +on_demand+.
|
49
|
+
#
|
50
|
+
# @return [Symbol]
|
56
51
|
def capacity_mode
|
57
52
|
options[:capacity_mode] || Dynamoid::Config.capacity_mode
|
58
53
|
end
|
59
54
|
|
60
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
|
61
61
|
def inheritance_field
|
62
62
|
options[:inheritance_field] || :type
|
63
63
|
end
|
64
64
|
|
65
|
-
# Returns the
|
65
|
+
# Returns the hash key field name for this class.
|
66
|
+
#
|
67
|
+
# By default +id+ field is used. But it can be overriden in the +table+
|
68
|
+
# method call.
|
66
69
|
#
|
70
|
+
# User.hash_key # => :id
|
71
|
+
#
|
72
|
+
# @return [Symbol] a hash key name
|
67
73
|
# @since 0.4.0
|
68
74
|
def hash_key
|
69
75
|
options[:key] || :id
|
70
76
|
end
|
71
77
|
|
72
|
-
#
|
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.
|
73
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
|
74
87
|
# @since 0.6.1
|
75
88
|
def count
|
76
89
|
Dynamoid.adapter.count(table_name)
|
@@ -78,35 +91,67 @@ module Dynamoid #:nodoc:
|
|
78
91
|
|
79
92
|
# Initialize a new object.
|
80
93
|
#
|
81
|
-
#
|
94
|
+
# User.build(name: 'A')
|
82
95
|
#
|
83
|
-
#
|
96
|
+
# Initialize an object and pass it into a block to set other attributes.
|
97
|
+
#
|
98
|
+
# User.build(name: 'A') do |u|
|
99
|
+
# u.age = 21
|
100
|
+
# end
|
101
|
+
#
|
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:
|
105
|
+
#
|
106
|
+
# class Employee
|
107
|
+
# include Dynamoid::Document
|
108
|
+
#
|
109
|
+
# field :type
|
110
|
+
# field :name
|
111
|
+
# end
|
84
112
|
#
|
113
|
+
# class Manager < Employee
|
114
|
+
# end
|
115
|
+
#
|
116
|
+
# Employee.build(name: 'Alice', type: 'Manager') # => #<Manager:0x00007f945756e3f0 ...>
|
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
|
85
121
|
# @since 0.2.0
|
86
|
-
def build(attrs = {})
|
87
|
-
choose_right_class(attrs).new(attrs)
|
122
|
+
def build(attrs = {}, &block)
|
123
|
+
choose_right_class(attrs).new(attrs, &block)
|
88
124
|
end
|
89
125
|
|
90
|
-
# Does this
|
126
|
+
# Does this model exist in a table?
|
127
|
+
#
|
128
|
+
# User.exists?('713') # => true
|
91
129
|
#
|
92
|
-
#
|
93
|
-
# Multiple keys and single compound primary key should be passed only as Array explicitily.
|
130
|
+
# If a range key is declared it should be specified in the following way:
|
94
131
|
#
|
95
|
-
#
|
132
|
+
# User.exists?([['713', 'range-key-value']]) # => true
|
96
133
|
#
|
97
|
-
#
|
134
|
+
# It's possible to check existence of several models at once:
|
98
135
|
#
|
99
|
-
#
|
136
|
+
# User.exists?(['713', '714', '715'])
|
100
137
|
#
|
101
|
-
#
|
138
|
+
# Or in case when a range key is declared:
|
102
139
|
#
|
103
|
-
#
|
104
|
-
#
|
140
|
+
# User.exists?(
|
141
|
+
# [
|
142
|
+
# ['713', 'range-key-value-1'],
|
143
|
+
# ['714', 'range-key-value-2'],
|
144
|
+
# ['715', 'range-key-value-3']
|
145
|
+
# ]
|
146
|
+
# )
|
105
147
|
#
|
106
|
-
#
|
148
|
+
# It's also possible to specify models not with primary key but with
|
149
|
+
# conditions on the attributes (in the +where+ method style):
|
107
150
|
#
|
108
|
-
#
|
151
|
+
# User.exists?(age: 20, 'created_at.gt': Time.now - 1.day)
|
109
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]
|
110
155
|
# @since 0.2.0
|
111
156
|
def exists?(id_or_conditions = {})
|
112
157
|
case id_or_conditions
|
@@ -121,10 +166,12 @@ module Dynamoid #:nodoc:
|
|
121
166
|
end
|
122
167
|
end
|
123
168
|
|
169
|
+
# @private
|
124
170
|
def deep_subclasses
|
125
171
|
subclasses + subclasses.map(&:deep_subclasses).flatten
|
126
172
|
end
|
127
173
|
|
174
|
+
# @private
|
128
175
|
def choose_right_class(attrs)
|
129
176
|
attrs[inheritance_field] ? attrs[inheritance_field].constantize : self
|
130
177
|
end
|
@@ -132,12 +179,20 @@ module Dynamoid #:nodoc:
|
|
132
179
|
|
133
180
|
# Initialize a new object.
|
134
181
|
#
|
135
|
-
#
|
182
|
+
# User.new(name: 'A')
|
136
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
|
189
|
+
#
|
190
|
+
# @param attrs [Hash] Attributes with which to create the document
|
191
|
+
# @param block [Proc] Block to process a document after initialization
|
137
192
|
# @return [Dynamoid::Document] the new document
|
138
193
|
#
|
139
194
|
# @since 0.2.0
|
140
|
-
def initialize(attrs = {})
|
195
|
+
def initialize(attrs = {}, &block)
|
141
196
|
run_callbacks :initialize do
|
142
197
|
@new_record = true
|
143
198
|
@attributes ||= {}
|
@@ -155,11 +210,19 @@ module Dynamoid #:nodoc:
|
|
155
210
|
attrs_virtual = attrs.slice(*(attrs.keys - self.class.attributes.keys))
|
156
211
|
|
157
212
|
load(attrs_with_defaults.merge(attrs_virtual))
|
213
|
+
|
214
|
+
if block
|
215
|
+
block.call(self)
|
216
|
+
end
|
158
217
|
end
|
159
218
|
end
|
160
219
|
|
161
|
-
#
|
220
|
+
# Check equality of two models.
|
162
221
|
#
|
222
|
+
# A model is equal to another model only if their primary keys (hash key
|
223
|
+
# and optionaly range key) are equal.
|
224
|
+
#
|
225
|
+
# @return [true|false]
|
163
226
|
# @since 0.2.0
|
164
227
|
def ==(other)
|
165
228
|
if self.class.identity_map_on?
|
@@ -171,36 +234,54 @@ module Dynamoid #:nodoc:
|
|
171
234
|
end
|
172
235
|
end
|
173
236
|
|
237
|
+
# Check equality of two models.
|
238
|
+
#
|
239
|
+
# Works exactly like +==+ does.
|
240
|
+
#
|
241
|
+
# @return [true|false]
|
174
242
|
def eql?(other)
|
175
243
|
self == other
|
176
244
|
end
|
177
245
|
|
246
|
+
# Generate an Integer hash value for this model.
|
247
|
+
#
|
248
|
+
# Hash value is based on primary key. So models can be used safely as a
|
249
|
+
# +Hash+ keys.
|
250
|
+
#
|
251
|
+
# @return [Integer]
|
178
252
|
def hash
|
179
253
|
hash_key.hash ^ range_value.hash
|
180
254
|
end
|
181
255
|
|
182
|
-
# Return
|
256
|
+
# Return a model's hash key value.
|
183
257
|
#
|
184
258
|
# @since 0.4.0
|
185
259
|
def hash_key
|
186
|
-
|
260
|
+
self[self.class.hash_key.to_sym]
|
187
261
|
end
|
188
262
|
|
189
|
-
# Assign
|
263
|
+
# Assign a model's hash key value, regardless of what it might be called to
|
264
|
+
# the object.
|
190
265
|
#
|
191
266
|
# @since 0.4.0
|
192
267
|
def hash_key=(value)
|
193
|
-
|
268
|
+
self[self.class.hash_key.to_sym] = value
|
194
269
|
end
|
195
270
|
|
271
|
+
# Return a model's range key value.
|
272
|
+
#
|
273
|
+
# Returns +nil+ if a range key isn't declared for a model.
|
196
274
|
def range_value
|
197
|
-
if
|
198
|
-
|
275
|
+
if self.class.range_key
|
276
|
+
self[self.class.range_key.to_sym]
|
199
277
|
end
|
200
278
|
end
|
201
279
|
|
280
|
+
# Assign a model's range key value.
|
202
281
|
def range_value=(value)
|
203
|
-
|
282
|
+
if self.class.range_key
|
283
|
+
self[self.class.range_key.to_sym] = value
|
284
|
+
end
|
204
285
|
end
|
205
286
|
|
206
287
|
private
|
@@ -212,7 +293,7 @@ module Dynamoid #:nodoc:
|
|
212
293
|
# Evaluates the default value given, this is used by undump
|
213
294
|
# when determining the value of the default given for a field options.
|
214
295
|
#
|
215
|
-
# @param [Object]
|
296
|
+
# @param val [Object] the attribute's default value
|
216
297
|
def evaluate_default_value(val)
|
217
298
|
if val.respond_to?(:call)
|
218
299
|
val.call
|