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
@@ -13,6 +13,7 @@ module Dynamoid
|
|
13
13
|
@identity_map ||= {}
|
14
14
|
end
|
15
15
|
|
16
|
+
# @private
|
16
17
|
def from_database(attrs = {})
|
17
18
|
return super if identity_map_off?
|
18
19
|
|
@@ -29,6 +30,7 @@ module Dynamoid
|
|
29
30
|
document
|
30
31
|
end
|
31
32
|
|
33
|
+
# @private
|
32
34
|
def find_by_id(id, options = {})
|
33
35
|
return super if identity_map_off?
|
34
36
|
|
@@ -41,6 +43,7 @@ module Dynamoid
|
|
41
43
|
identity_map[key] || super
|
42
44
|
end
|
43
45
|
|
46
|
+
# @private
|
44
47
|
def identity_map_key(attrs)
|
45
48
|
key = attrs[hash_key].to_s
|
46
49
|
key += "::#{attrs[range_key]}" if range_key
|
@@ -60,6 +63,7 @@ module Dynamoid
|
|
60
63
|
self.class.identity_map
|
61
64
|
end
|
62
65
|
|
66
|
+
# @private
|
63
67
|
def save(*args)
|
64
68
|
return super if self.class.identity_map_off?
|
65
69
|
|
@@ -69,6 +73,7 @@ module Dynamoid
|
|
69
73
|
result
|
70
74
|
end
|
71
75
|
|
76
|
+
# @private
|
72
77
|
def delete
|
73
78
|
return super if self.class.identity_map_off?
|
74
79
|
|
@@ -76,6 +81,7 @@ module Dynamoid
|
|
76
81
|
super
|
77
82
|
end
|
78
83
|
|
84
|
+
# @private
|
79
85
|
def identity_map_key
|
80
86
|
key = hash_key.to_s
|
81
87
|
key += "::#{range_value}" if self.class.range_key
|
data/lib/dynamoid/indexes.rb
CHANGED
@@ -15,19 +15,43 @@ module Dynamoid
|
|
15
15
|
# Defines a Global Secondary index on a table. Keys can be specified as
|
16
16
|
# hash-only, or hash & range.
|
17
17
|
#
|
18
|
-
#
|
19
|
-
#
|
20
|
-
#
|
21
|
-
#
|
22
|
-
#
|
18
|
+
# class Post
|
19
|
+
# include Dynamoid::Document
|
20
|
+
#
|
21
|
+
# field :category
|
22
|
+
#
|
23
|
+
# global_secondary_indexes hash_key: :category
|
24
|
+
# end
|
25
|
+
#
|
26
|
+
# The full example with all the options being specified:
|
27
|
+
#
|
28
|
+
# global_secondary_indexes hash_key: :category,
|
29
|
+
# range_key: :created_at,
|
30
|
+
# name: 'posts_category_created_at_index',
|
31
|
+
# projected_attributes: :all,
|
32
|
+
# read_capacity: 100,
|
33
|
+
# write_capacity: 20
|
34
|
+
#
|
35
|
+
# Global secondary index should be declared after fields for mentioned
|
36
|
+
# hash key and optional range key are declared (with method +field+)
|
37
|
+
#
|
38
|
+
# The only mandatory option is +hash_key+. Raises
|
39
|
+
# +Dynamoid::Errors::InvalidIndex+ exception if passed incorrect
|
40
|
+
# options.
|
41
|
+
#
|
42
|
+
# @param [Hash] options the options to pass for this table
|
43
|
+
# @option options [Symbol] name the name for the index; this still gets
|
44
|
+
# namespaced. If not specified, will use a default name.
|
45
|
+
# @option options [Symbol] hash_key the index hash key column.
|
46
|
+
# @option options [Symbol] range_key the index range key column (if
|
23
47
|
# applicable).
|
24
|
-
# @option options [Symbol, Array<Symbol>]
|
25
|
-
# attributes to project for this index. Can be
|
48
|
+
# @option options [Symbol, Array<Symbol>] projected_attributes table
|
49
|
+
# attributes to project for this index. Can be +:keys_only+, +:all+
|
26
50
|
# or an array of included fields. If not specified, defaults to
|
27
|
-
#
|
28
|
-
# @option options [Integer]
|
51
|
+
# +:keys_only+.
|
52
|
+
# @option options [Integer] read_capacity set the read capacity for the
|
29
53
|
# index; does not work on existing indexes.
|
30
|
-
# @option options [Integer]
|
54
|
+
# @option options [Integer] write_capacity set the write capacity for
|
31
55
|
# the index; does not work on existing indexes.
|
32
56
|
def global_secondary_index(options = {})
|
33
57
|
unless options.present?
|
@@ -55,14 +79,38 @@ module Dynamoid
|
|
55
79
|
# Defines a local secondary index on a table. Will use the same primary
|
56
80
|
# hash key as the table.
|
57
81
|
#
|
82
|
+
# class Comment
|
83
|
+
# include Dynamoid::Document
|
84
|
+
#
|
85
|
+
# table hash_key: :post_id
|
86
|
+
# range :created_at, :datetime
|
87
|
+
# field :author_id
|
88
|
+
#
|
89
|
+
# local_secondary_indexes hash_key: :author_id
|
90
|
+
# end
|
91
|
+
#
|
92
|
+
# The full example with all the options being specified:
|
93
|
+
#
|
94
|
+
# local_secondary_indexes range_key: :created_at,
|
95
|
+
# name: 'posts_created_at_index',
|
96
|
+
# projected_attributes: :all
|
97
|
+
#
|
98
|
+
# Local secondary index should be declared after fields for mentioned
|
99
|
+
# hash key and optional range key are declared (with method +field+) as
|
100
|
+
# well as after +table+ method call.
|
101
|
+
#
|
102
|
+
# The only mandatory option is +range_key+. Raises
|
103
|
+
# +Dynamoid::Errors::InvalidIndex+ exception if passed incorrect
|
104
|
+
# options.
|
105
|
+
#
|
58
106
|
# @param [Hash] options options to pass for this index.
|
59
|
-
# @option options [Symbol]
|
107
|
+
# @option options [Symbol] name the name for the index; this still gets
|
60
108
|
# namespaced. If not specified, a name is automatically generated.
|
61
|
-
# @option options [Symbol]
|
62
|
-
# @option options [Symbol, Array<Symbol>]
|
63
|
-
# attributes to project for this index. Can be
|
109
|
+
# @option options [Symbol] range_key the range key column for the index.
|
110
|
+
# @option options [Symbol, Array<Symbol>] projected_attributes table
|
111
|
+
# attributes to project for this index. Can be +:keys_only+, +:all+
|
64
112
|
# or an array of included fields. If not specified, defaults to
|
65
|
-
#
|
113
|
+
# +:keys_only+.
|
66
114
|
def local_secondary_index(options = {})
|
67
115
|
unless options.present?
|
68
116
|
raise Dynamoid::Errors::InvalidIndex, 'empty index definition'
|
@@ -94,6 +142,13 @@ module Dynamoid
|
|
94
142
|
self
|
95
143
|
end
|
96
144
|
|
145
|
+
# Returns an index by its hash key and optional range key.
|
146
|
+
#
|
147
|
+
# It works only for indexes without explicit name declared.
|
148
|
+
#
|
149
|
+
# @param hash [scalar] the hash key used to declare an index
|
150
|
+
# @param range [scalar] the range key used to declare an index (optional)
|
151
|
+
# @return [Dynamoid::Indexes::Index, nil] index object or nil if it isn't found
|
97
152
|
def find_index(hash, range = nil)
|
98
153
|
index = indexes[index_key(hash, range)]
|
99
154
|
index
|
@@ -150,6 +205,10 @@ module Dynamoid
|
|
150
205
|
local_secondary_indexes.merge(global_secondary_indexes)
|
151
206
|
end
|
152
207
|
|
208
|
+
# Returns an array of hash keys for all the declared Glocal Secondary
|
209
|
+
# Indexes.
|
210
|
+
#
|
211
|
+
# @return [Array[String]] array of hash keys
|
153
212
|
def indexed_hash_keys
|
154
213
|
global_secondary_indexes.map do |_name, index|
|
155
214
|
index.hash_key.to_s
|
@@ -0,0 +1,26 @@
|
|
1
|
+
module Dynamoid
|
2
|
+
module Log
|
3
|
+
module Formatter
|
4
|
+
|
5
|
+
# https://docs.aws.amazon.com/sdk-for-ruby/v3/api/Aws/Log/Formatter.html
|
6
|
+
# https://docs.aws.amazon.com/sdk-for-ruby/v2/api/Seahorse/Client/Response.html
|
7
|
+
# https://aws.amazon.com/ru/blogs/developer/logging-requests/
|
8
|
+
class Debug
|
9
|
+
def format(response)
|
10
|
+
bold = "\x1b[1m"
|
11
|
+
color = "\x1b[34m"
|
12
|
+
reset = "\x1b[0m"
|
13
|
+
|
14
|
+
[
|
15
|
+
response.context.operation.name,
|
16
|
+
"#{bold}#{color}\nRequest:\n#{reset}#{bold}",
|
17
|
+
JSON.pretty_generate(JSON.parse(response.context.http_request.body.string)),
|
18
|
+
"#{bold}#{color}\nResponse:\n#{reset}#{bold}",
|
19
|
+
JSON.pretty_generate(JSON.parse(response.context.http_response.body.string)),
|
20
|
+
reset
|
21
|
+
].join("\n")
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
data/lib/dynamoid/persistence.rb
CHANGED
@@ -19,6 +19,7 @@ module Dynamoid
|
|
19
19
|
attr_accessor :new_record
|
20
20
|
alias new_record? new_record
|
21
21
|
|
22
|
+
# @private
|
22
23
|
UNIX_EPOCH_DATE = Date.new(1970, 1, 1).freeze
|
23
24
|
|
24
25
|
module ClassMethods
|
@@ -30,13 +31,64 @@ module Dynamoid
|
|
30
31
|
|
31
32
|
# Create a table.
|
32
33
|
#
|
33
|
-
#
|
34
|
-
#
|
35
|
-
#
|
36
|
-
#
|
37
|
-
#
|
38
|
-
#
|
39
|
-
#
|
34
|
+
# Uses a configuration specified in a model class (with the +table+
|
35
|
+
# method) e.g. table name, schema (hash and range keys), global and local
|
36
|
+
# secondary indexes, billing mode and write/read capacity.
|
37
|
+
#
|
38
|
+
# For instance here
|
39
|
+
#
|
40
|
+
# class User
|
41
|
+
# include Dynamoid::Document
|
42
|
+
#
|
43
|
+
# table key: :uuid
|
44
|
+
# range :last_name
|
45
|
+
#
|
46
|
+
# field :first_name
|
47
|
+
# field :last_name
|
48
|
+
# end
|
49
|
+
#
|
50
|
+
# User.create_table
|
51
|
+
#
|
52
|
+
# +create_table+ method call will create a table +dynamoid_users+ with
|
53
|
+
# hash key +uuid+ and range key +name+, DynamoDB default billing mode and
|
54
|
+
# Dynamoid default read/write capacity units (100/20).
|
55
|
+
#
|
56
|
+
# All the configuration can be overridden with +options+ argument.
|
57
|
+
#
|
58
|
+
# User.create_table(table_name: 'users', read_capacity: 200, write_capacity: 40)
|
59
|
+
#
|
60
|
+
# Dynamoid creates a table synchronously by default. DynamoDB table
|
61
|
+
# creation is an asynchronous operation and a client should wait until a
|
62
|
+
# table status changes to +ACTIVE+ and a table becomes available. That's
|
63
|
+
# why Dynamoid is polling a table status and returns results only when a
|
64
|
+
# table becomes available.
|
65
|
+
#
|
66
|
+
# Polling is configured with +Dynamoid::Config.sync_retry_max_times+ and
|
67
|
+
# +Dynamoid::Config.sync_retry_wait_seconds+ configuration options. If
|
68
|
+
# table creation takes more time than configured waiting time then
|
69
|
+
# Dynamoid stops polling and returns +true+.
|
70
|
+
#
|
71
|
+
# In order to return back asynchronous behaviour and not to wait until a
|
72
|
+
# table is created the +sync: false+ option should be specified.
|
73
|
+
#
|
74
|
+
# User.create_table(sync: false)
|
75
|
+
#
|
76
|
+
# Subsequent method calls for the same table will be ignored.
|
77
|
+
#
|
78
|
+
# @param options [Hash]
|
79
|
+
#
|
80
|
+
# @option options [Symbol] :table_name name of the table
|
81
|
+
# @option options [Symbol] :id hash key name of the table
|
82
|
+
# @option options [Symbol] :hash_key_type Dynamoid type of the hash key - +:string+, +:integer+ or any other scalar type
|
83
|
+
# @option options [Hash] :range_key a Hash with range key name and type in format +{ <name> => <type> }+ e.g. +{ last_name: :string }+
|
84
|
+
# @option options [String] :billing_mode billing mode of a table - either +PROVISIONED+ (default) or +PAY_PER_REQUEST+ (for On-Demand Mode)
|
85
|
+
# @option options [Integer] :read_capacity read capacity units for the table; does not work on existing tables and is ignored when billing mode is +PAY_PER_REQUEST+
|
86
|
+
# @option options [Integer] :write_capacity write capacity units for the table; does not work on existing tables and is ignored when billing mode is +PAY_PER_REQUEST+
|
87
|
+
# @option options [Hash] :local_secondary_indexes
|
88
|
+
# @option options [Hash] :global_secondary_indexes
|
89
|
+
# @option options [true|false] :sync specifies should the method call be synchronous and wait until a table is completely created
|
90
|
+
#
|
91
|
+
# @return [true|false] Whether a table created successfully
|
40
92
|
# @since 0.4.0
|
41
93
|
def create_table(options = {})
|
42
94
|
range_key_hash = if range_key
|
@@ -63,11 +115,17 @@ module Dynamoid
|
|
63
115
|
end
|
64
116
|
end
|
65
117
|
|
66
|
-
# Deletes the table for the model
|
118
|
+
# Deletes the table for the model.
|
119
|
+
#
|
120
|
+
# Dynamoid deletes a table asynchronously and doesn't wait until a table
|
121
|
+
# is deleted completely.
|
122
|
+
#
|
123
|
+
# Subsequent method calls for the same table will be ignored.
|
67
124
|
def delete_table
|
68
125
|
Dynamoid.adapter.delete_table(table_name)
|
69
126
|
end
|
70
127
|
|
128
|
+
# @private
|
71
129
|
def from_database(attrs = {})
|
72
130
|
klass = choose_right_class(attrs)
|
73
131
|
attrs_undumped = Undumping.undump_attributes(attrs, klass.attributes)
|
@@ -76,70 +134,94 @@ module Dynamoid
|
|
76
134
|
|
77
135
|
# Create several models at once.
|
78
136
|
#
|
79
|
-
#
|
80
|
-
#
|
81
|
-
#
|
82
|
-
#
|
137
|
+
# users = User.import([{ name: 'a' }, { name: 'b' }])
|
138
|
+
#
|
139
|
+
# +import+ is a relatively low-level method and bypasses some
|
140
|
+
# mechanisms like callbacks and validation.
|
83
141
|
#
|
84
|
-
#
|
142
|
+
# It sets timestamp fields +created_at+ and +updated_at+ if they are
|
143
|
+
# blank. It sets a hash key field as well if it's blank. It expects that
|
144
|
+
# the hash key field is +string+ and sets a random UUID value if the field
|
145
|
+
# value is blank. All the field values are type casted to the declared
|
146
|
+
# types.
|
85
147
|
#
|
86
|
-
#
|
87
|
-
#
|
148
|
+
# It works efficiently and uses the `BatchWriteItem` operation. In order
|
149
|
+
# to cope with throttling it uses a backoff strategy if it's specified with
|
150
|
+
# `Dynamoid::Config.backoff` configuration option.
|
151
|
+
#
|
152
|
+
# Because of the nature of DynamoDB and its limits only 25 models can be
|
153
|
+
# saved at once. So multiple HTTP requests can be sent to DynamoDB.
|
154
|
+
#
|
155
|
+
# @param array_of_attributes [Array<Hash>]
|
156
|
+
# @return [Array] Created models
|
88
157
|
def import(array_of_attributes)
|
89
158
|
Import.call(self, array_of_attributes)
|
90
159
|
end
|
91
160
|
|
92
161
|
# Create a model.
|
93
162
|
#
|
94
|
-
# Initializes a new
|
95
|
-
#
|
163
|
+
# Initializes a new model and immediately saves it to DynamoDB.
|
164
|
+
#
|
165
|
+
# User.create(first_name: 'Mark', last_name: 'Tyler')
|
166
|
+
#
|
96
167
|
# Accepts both Hash and Array of Hashes and can create several models.
|
97
168
|
#
|
98
|
-
#
|
169
|
+
# User.create([{ first_name: 'Alice' }, { first_name: 'Bob' }])
|
170
|
+
#
|
171
|
+
# Creates a model and pass it into a block to set other attributes.
|
99
172
|
#
|
100
|
-
#
|
173
|
+
# User.create(first_name: 'Mark') do |u|
|
174
|
+
# u.age = 21
|
175
|
+
# end
|
101
176
|
#
|
177
|
+
# Validates model and runs callbacks.
|
178
|
+
#
|
179
|
+
# @param attrs [Hash|Array[Hash]] Attributes of the models
|
180
|
+
# @param block [Proc] Block to process a document after initialization
|
181
|
+
# @return [Dynamoid::Document] The created document
|
102
182
|
# @since 0.2.0
|
103
|
-
def create(attrs = {})
|
183
|
+
def create(attrs = {}, &block)
|
104
184
|
if attrs.is_a?(Array)
|
105
|
-
attrs.map { |attr| create(attr) }
|
185
|
+
attrs.map { |attr| create(attr, &block) }
|
106
186
|
else
|
107
|
-
build(attrs).tap(&:save)
|
187
|
+
build(attrs, &block).tap(&:save)
|
108
188
|
end
|
109
189
|
end
|
110
190
|
|
111
|
-
# Create
|
112
|
-
#
|
113
|
-
# Initializes a new object and immediately saves it to the database.
|
114
|
-
# Raises an exception if validation failed.
|
115
|
-
# Accepts both Hash and Array of Hashes and can create several models.
|
116
|
-
#
|
117
|
-
# @param [Hash|Array[Hash]] attrs Attributes with which to create the object.
|
191
|
+
# Create a model.
|
118
192
|
#
|
119
|
-
#
|
193
|
+
# Initializes a new object and immediately saves it to the Dynamoid.
|
194
|
+
# Raises an exception +Dynamoid::Errors::DocumentNotValid+ if validation
|
195
|
+
# failed. Accepts both Hash and Array of Hashes and can create several
|
196
|
+
# models.
|
120
197
|
#
|
198
|
+
# @param attrs [Hash|Array[Hash]] Attributes with which to create the object.
|
199
|
+
# @param block [Proc] Block to process a document after initialization
|
200
|
+
# @return [Dynamoid::Document] The created document
|
121
201
|
# @since 0.2.0
|
122
|
-
def create!(attrs = {})
|
202
|
+
def create!(attrs = {}, &block)
|
123
203
|
if attrs.is_a?(Array)
|
124
|
-
attrs.map { |attr| create!(attr) }
|
204
|
+
attrs.map { |attr| create!(attr, &block) }
|
125
205
|
else
|
126
|
-
build(attrs).tap(&:save!)
|
206
|
+
build(attrs, &block).tap(&:save!)
|
127
207
|
end
|
128
208
|
end
|
129
209
|
|
130
210
|
# Update document with provided attributes.
|
131
211
|
#
|
132
|
-
# Instantiates document and saves changes.
|
133
|
-
#
|
212
|
+
# Instantiates document and saves changes. Runs validations and
|
213
|
+
# callbacks. Don't save changes if validation fails.
|
134
214
|
#
|
135
|
-
#
|
136
|
-
# @param [Scalar value] sort key, optional
|
137
|
-
# @param [Hash] attributes
|
215
|
+
# User.update('1', age: 26)
|
138
216
|
#
|
139
|
-
#
|
217
|
+
# If range key is declared for a model it should be passed as well:
|
140
218
|
#
|
141
|
-
#
|
142
|
-
#
|
219
|
+
# User.update('1', 'Tylor', age: 26)
|
220
|
+
#
|
221
|
+
# @param hash_key [Scalar value] hash key
|
222
|
+
# @param range_key_value [Scalar value] range key (optional)
|
223
|
+
# @param attrs [Hash]
|
224
|
+
# @return [Dynamoid::Document] Updated document
|
143
225
|
def update(hash_key, range_key_value = nil, attrs)
|
144
226
|
model = find(hash_key, range_key: range_key_value, consistent_read: true)
|
145
227
|
model.update_attributes(attrs)
|
@@ -148,17 +230,21 @@ module Dynamoid
|
|
148
230
|
|
149
231
|
# Update document with provided attributes.
|
150
232
|
#
|
151
|
-
# Instantiates document and saves changes.
|
152
|
-
#
|
233
|
+
# Instantiates document and saves changes. Runs validations and
|
234
|
+
# callbacks.
|
235
|
+
#
|
236
|
+
# User.update!('1', age: 26)
|
153
237
|
#
|
154
|
-
#
|
155
|
-
# @param [Scalar value] sort key, optional
|
156
|
-
# @param [Hash] attributes
|
238
|
+
# If range key is declared for a model it should be passed as well:
|
157
239
|
#
|
158
|
-
#
|
240
|
+
# User.update('1', 'Tylor', age: 26)
|
159
241
|
#
|
160
|
-
#
|
161
|
-
#
|
242
|
+
# Raises +Dynamoid::Errors::DocumentNotValid+ exception if validation fails.
|
243
|
+
#
|
244
|
+
# @param hash_key [Scalar value] hash key
|
245
|
+
# @param range_key_value [Scalar value] range key (optional)
|
246
|
+
# @param attrs [Hash]
|
247
|
+
# @return [Dynamoid::Document] Updated document
|
162
248
|
def update!(hash_key, range_key_value = nil, attrs)
|
163
249
|
model = find(hash_key, range_key: range_key_value, consistent_read: true)
|
164
250
|
model.update_attributes!(attrs)
|
@@ -167,23 +253,34 @@ module Dynamoid
|
|
167
253
|
|
168
254
|
# Update document.
|
169
255
|
#
|
170
|
-
#
|
171
|
-
#
|
172
|
-
#
|
173
|
-
#
|
256
|
+
# Doesn't run validations and callbacks.
|
257
|
+
#
|
258
|
+
# User.update_fields('1', age: 26)
|
259
|
+
#
|
260
|
+
# If range key is declared for a model it should be passed as well:
|
261
|
+
#
|
262
|
+
# User.update_fields('1', 'Tylor', age: 26)
|
263
|
+
#
|
264
|
+
# Can make a conditional update so a document will be updated only if it
|
265
|
+
# meets the specified conditions. Conditions can be specified as a +Hash+
|
266
|
+
# with +:if+ key:
|
267
|
+
#
|
268
|
+
# User.update_fields('1', { age: 26 }, if: { version: 1 })
|
174
269
|
#
|
175
|
-
#
|
176
|
-
#
|
177
|
-
# @param [Hash] attributes
|
178
|
-
# @param [Hash] conditions
|
270
|
+
# Here +User+ model has an integer +version+ field and the document will
|
271
|
+
# be updated only if the +version+ attribute currently has value 1.
|
179
272
|
#
|
180
|
-
#
|
273
|
+
# If a document with specified hash and range keys doesn't exist or
|
274
|
+
# conditions were specified and failed the method call returns +nil+.
|
181
275
|
#
|
182
|
-
#
|
183
|
-
#
|
276
|
+
# +update_fields+ uses the +UpdateItem+ operation so it saves changes and
|
277
|
+
# loads an updated document back with one HTTP request.
|
184
278
|
#
|
185
|
-
# @
|
186
|
-
#
|
279
|
+
# @param hash_key_value [Scalar value] hash key
|
280
|
+
# @param range_key_value [Scalar value] range key (optional)
|
281
|
+
# @param attrs [Hash]
|
282
|
+
# @param conditions [Hash] (optional)
|
283
|
+
# @return [Dynamoid::Document|nil] Updated document
|
187
284
|
def update_fields(hash_key_value, range_key_value = nil, attrs = {}, conditions = {})
|
188
285
|
optional_params = [range_key_value, attrs, conditions].compact
|
189
286
|
if optional_params.first.is_a?(Hash)
|
@@ -201,25 +298,37 @@ module Dynamoid
|
|
201
298
|
conditions: conditions)
|
202
299
|
end
|
203
300
|
|
204
|
-
# Update existing document or create new one.
|
301
|
+
# Update an existing document or create a new one.
|
205
302
|
#
|
206
|
-
#
|
207
|
-
#
|
303
|
+
# If a document with specified hash and range keys doesn't exist it
|
304
|
+
# creates a new document with specified attributes. Doesn't run
|
305
|
+
# validations and callbacks.
|
208
306
|
#
|
209
|
-
#
|
210
|
-
# Changes attibutes and loads new document version with one API call.
|
211
|
-
# Doesn't run validations and callbacks. Can make conditional update.
|
212
|
-
# If specified conditions failed - returns `nil`.
|
307
|
+
# User.upsert('1', age: 26)
|
213
308
|
#
|
214
|
-
#
|
215
|
-
# @param [Scalar value] sort key (optional)
|
216
|
-
# @param [Hash] attributes
|
217
|
-
# @param [Hash] conditions
|
309
|
+
# If range key is declared for a model it should be passed as well:
|
218
310
|
#
|
219
|
-
#
|
311
|
+
# User.upsert('1', 'Tylor', age: 26)
|
220
312
|
#
|
221
|
-
#
|
222
|
-
#
|
313
|
+
# Can make a conditional update so a document will be updated only if it
|
314
|
+
# meets the specified conditions. Conditions can be specified as a +Hash+
|
315
|
+
# with +:if+ key:
|
316
|
+
#
|
317
|
+
# User.upsert('1', { age: 26 }, if: { version: 1 })
|
318
|
+
#
|
319
|
+
# Here +User+ model has an integer +version+ field and the document will
|
320
|
+
# be updated only if the +version+ attribute currently has value 1.
|
321
|
+
#
|
322
|
+
# If conditions were specified and failed the method call returns +nil+.
|
323
|
+
#
|
324
|
+
# +upsert+ uses the +UpdateItem+ operation so it saves changes and loads
|
325
|
+
# an updated document back with one HTTP request.
|
326
|
+
#
|
327
|
+
# @param hash_key_value [Scalar value] hash key
|
328
|
+
# @param range_key_value [Scalar value] range key (optional)
|
329
|
+
# @param attrs [Hash]
|
330
|
+
# @param conditions [Hash] (optional)
|
331
|
+
# @return [Dynamoid::Document|nil] Updated document
|
223
332
|
def upsert(hash_key_value, range_key_value = nil, attrs = {}, conditions = {})
|
224
333
|
optional_params = [range_key_value, attrs, conditions].compact
|
225
334
|
if optional_params.first.is_a?(Hash)
|
@@ -237,19 +346,27 @@ module Dynamoid
|
|
237
346
|
conditions: conditions)
|
238
347
|
end
|
239
348
|
|
240
|
-
# Increase numeric field by specified value.
|
349
|
+
# Increase a numeric field by specified value.
|
350
|
+
#
|
351
|
+
# User.inc('1', age: 2)
|
241
352
|
#
|
242
353
|
# Can update several fields at once.
|
243
|
-
# Uses efficient low-level `UpdateItem` API call.
|
244
354
|
#
|
245
|
-
#
|
246
|
-
#
|
247
|
-
#
|
355
|
+
# User.inc('1', age: 2, version: 1)
|
356
|
+
#
|
357
|
+
# If range key is declared for a model it should be passed as well:
|
248
358
|
#
|
249
|
-
#
|
359
|
+
# User.inc('1', 'Tylor', age: 2)
|
250
360
|
#
|
251
|
-
#
|
252
|
-
#
|
361
|
+
# Uses efficient low-level +UpdateItem+ operation and does only one HTTP
|
362
|
+
# request.
|
363
|
+
#
|
364
|
+
# Doesn't run validations and callbacks. Doesn't update +created_at+ and
|
365
|
+
# +updated_at+ as well.
|
366
|
+
#
|
367
|
+
# @param hash_key_value [Scalar value] hash key
|
368
|
+
# @param range_key_value [Scalar value] range key (optional)
|
369
|
+
# @param counters [Hash] value to increase by
|
253
370
|
def inc(hash_key_value, range_key_value = nil, counters)
|
254
371
|
options = if range_key
|
255
372
|
value_casted = TypeCasting.cast_field(range_key_value, attributes[range_key])
|
@@ -270,8 +387,17 @@ module Dynamoid
|
|
270
387
|
end
|
271
388
|
end
|
272
389
|
|
273
|
-
#
|
390
|
+
# Update document timestamps.
|
391
|
+
#
|
392
|
+
# Set +updated_at+ attribute to current DateTime.
|
393
|
+
#
|
394
|
+
# post.touch
|
274
395
|
#
|
396
|
+
# Can update another field in addition with the same timestamp if it's name passed as argument.
|
397
|
+
#
|
398
|
+
# user.touch(:last_login_at)
|
399
|
+
#
|
400
|
+
# @param name [Symbol] attribute name to update (optional)
|
275
401
|
def touch(name = nil)
|
276
402
|
now = DateTime.now
|
277
403
|
self.updated_at = now
|
@@ -279,15 +405,67 @@ module Dynamoid
|
|
279
405
|
save
|
280
406
|
end
|
281
407
|
|
282
|
-
# Is this object persisted in
|
408
|
+
# Is this object persisted in DynamoDB?
|
409
|
+
#
|
410
|
+
# user = User.new
|
411
|
+
# user.persisted? # => false
|
283
412
|
#
|
413
|
+
# user.save
|
414
|
+
# user.persisted? # => true
|
415
|
+
#
|
416
|
+
# @return [true|false]
|
284
417
|
# @since 0.2.0
|
285
418
|
def persisted?
|
286
419
|
!(new_record? || @destroyed)
|
287
420
|
end
|
288
421
|
|
289
|
-
#
|
422
|
+
# Create new model or persist changes.
|
423
|
+
#
|
424
|
+
# Run the validation and callbacks. Returns +true+ if saving is successful
|
425
|
+
# and +false+ otherwise.
|
426
|
+
#
|
427
|
+
# user = User.new
|
428
|
+
# user.save # => true
|
429
|
+
#
|
430
|
+
# user.age = 26
|
431
|
+
# user.save # => true
|
432
|
+
#
|
433
|
+
# Validation can be skipped with +validate: false+ option:
|
434
|
+
#
|
435
|
+
# user = User.new(age: -1)
|
436
|
+
# user.save(validate: false) # => true
|
437
|
+
#
|
438
|
+
# +save+ by default sets timestamps attributes - +created_at+ and
|
439
|
+
# +updated_at+ when creates new model and updates +updated_at+ attribute
|
440
|
+
# when update already existing one.
|
290
441
|
#
|
442
|
+
# Changing +updated_at+ attribute at updating a model can be skipped with
|
443
|
+
# +touch: false+ option:
|
444
|
+
#
|
445
|
+
# user.save(touch: false)
|
446
|
+
#
|
447
|
+
# If a model is new and hash key (+id+ by default) is not assigned yet
|
448
|
+
# it was assigned implicitly with random UUID value.
|
449
|
+
#
|
450
|
+
# If +lock_version+ attribute is declared it will be incremented. If it's blank then it will be initialized with 1.
|
451
|
+
#
|
452
|
+
# +save+ method call raises +Dynamoid::Errors::RecordNotUnique+ exception
|
453
|
+
# if primary key (hash key + optional range key) already exists in a
|
454
|
+
# table.
|
455
|
+
#
|
456
|
+
# +save+ method call raises +Dynamoid::Errors::StaleObjectError+ exception
|
457
|
+
# if there is +lock_version+ attribute and the document in a table was
|
458
|
+
# already changed concurrently and +lock_version+ was consequently
|
459
|
+
# increased.
|
460
|
+
#
|
461
|
+
# When a table is not created yet the first +save+ method call will create
|
462
|
+
# a table. It's useful in test environment to avoid explicit table
|
463
|
+
# creation.
|
464
|
+
#
|
465
|
+
# @param options [Hash] (optional)
|
466
|
+
# @option options [true|false] :validate validate a model or not - +true+ by default (optional)
|
467
|
+
# @option options [true|false] :touch update tiemstamps fields or not - +true+ by default (optional)
|
468
|
+
# @return [true|false] Whether saving successful or not
|
291
469
|
# @since 0.2.0
|
292
470
|
def save(options = {})
|
293
471
|
self.class.create_table(sync: true)
|
@@ -307,20 +485,29 @@ module Dynamoid
|
|
307
485
|
end
|
308
486
|
end
|
309
487
|
|
310
|
-
#
|
488
|
+
# Update multiple attributes at once, saving the object once the updates
|
489
|
+
# are complete. Returns +true+ if saving is successful and +false+
|
490
|
+
# otherwise.
|
311
491
|
#
|
312
|
-
#
|
492
|
+
# user.update_attributes(age: 27, last_name: 'Tylor')
|
313
493
|
#
|
494
|
+
# @param attributes [Hash] a hash of attributes to update
|
495
|
+
# @return [true|false] Whether updating successful or not
|
314
496
|
# @since 0.2.0
|
315
497
|
def update_attributes(attributes)
|
316
498
|
attributes.each { |attribute, value| write_attribute(attribute, value) }
|
317
499
|
save
|
318
500
|
end
|
319
501
|
|
320
|
-
#
|
321
|
-
#
|
502
|
+
# Update multiple attributes at once, saving the object once the updates
|
503
|
+
# are complete.
|
504
|
+
#
|
505
|
+
# user.update_attributes!(age: 27, last_name: 'Tylor')
|
322
506
|
#
|
323
|
-
#
|
507
|
+
# Raises a +Dynamoid::Errors::DocumentNotValid+ exception if some vaidation
|
508
|
+
# fails.
|
509
|
+
#
|
510
|
+
# @param attributes [Hash] a hash of attributes to update
|
324
511
|
def update_attributes!(attributes)
|
325
512
|
attributes.each { |attribute, value| write_attribute(attribute, value) }
|
326
513
|
save!
|
@@ -328,20 +515,68 @@ module Dynamoid
|
|
328
515
|
|
329
516
|
# Update a single attribute, saving the object afterwards.
|
330
517
|
#
|
331
|
-
#
|
332
|
-
#
|
518
|
+
# Returns +true+ if saving is successful and +false+ otherwise.
|
519
|
+
#
|
520
|
+
# user.update_attribute(:last_name, 'Tylor')
|
333
521
|
#
|
522
|
+
# @param attribute [Symbol] attribute name to update
|
523
|
+
# @param value [Object] the value to assign it
|
524
|
+
# @return [Dynamoid::Document] self
|
334
525
|
# @since 0.2.0
|
335
526
|
def update_attribute(attribute, value)
|
336
527
|
write_attribute(attribute, value)
|
337
528
|
save
|
338
529
|
end
|
339
530
|
|
531
|
+
# Update a model.
|
532
|
+
#
|
533
|
+
# Runs validation and callbacks. Reloads all attribute values.
|
534
|
+
#
|
535
|
+
# Accepts mandatory block in order to specify operations which will modify
|
536
|
+
# attributes. Supports following operations: +add+, +delete+ and +set+.
|
537
|
+
#
|
538
|
+
# Operation +add+ just adds a value for numeric attributes and join
|
539
|
+
# collections if attribute is a collection (one of +array+, +set+ or
|
540
|
+
# +map+).
|
541
|
+
#
|
542
|
+
# user.update do |t|
|
543
|
+
# t.add(age: 1, followers_count: 5)
|
544
|
+
# t.add(hobbies: ['skying', 'climbing'])
|
545
|
+
# end
|
546
|
+
#
|
547
|
+
# Operation +delete+ is applied to collection attribute types and
|
548
|
+
# substructs one collection from another.
|
340
549
|
#
|
341
|
-
#
|
342
|
-
#
|
550
|
+
# user.update do |t|
|
551
|
+
# t.delete(hobbies: ['skying'])
|
552
|
+
# end
|
343
553
|
#
|
554
|
+
# Operation +set+ just changes an attribute value:
|
344
555
|
#
|
556
|
+
# user.update do |t|
|
557
|
+
# t.set(age: 21)
|
558
|
+
# end
|
559
|
+
#
|
560
|
+
# All the operations works like +ADD+, +DELETE+ and +PUT+ actions supported
|
561
|
+
# by +AttributeUpdates+
|
562
|
+
# {parameter}[https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/LegacyConditionalParameters.AttributeUpdates.html]
|
563
|
+
# of +UpdateItem+ operation.
|
564
|
+
#
|
565
|
+
# Can update a model conditionaly:
|
566
|
+
#
|
567
|
+
# user.update(if: { age: 20 }) do |t|
|
568
|
+
# t.add(age: 1)
|
569
|
+
# end
|
570
|
+
#
|
571
|
+
# If a document doesn't meet conditions it raises
|
572
|
+
# +Dynamoid::Errors::StaleObjectError+ exception.
|
573
|
+
#
|
574
|
+
# It will increment the +lock_version+ attribute if a table has the column,
|
575
|
+
# but will not check it. Thus, a concurrent +save+ call will never cause an
|
576
|
+
# +update!+ to fail, but an +update!+ may cause a concurrent +save+ to
|
577
|
+
# fail.
|
578
|
+
#
|
579
|
+
# @param conditions [Hash] Conditions on model attributes to make a conditional update (optional)
|
345
580
|
def update!(conditions = {})
|
346
581
|
run_callbacks(:update) do
|
347
582
|
options = range_key ? { range_key: Dumping.dump_field(read_attribute(range_key), self.class.attributes[range_key]) } : {}
|
@@ -365,6 +600,54 @@ module Dynamoid
|
|
365
600
|
end
|
366
601
|
end
|
367
602
|
|
603
|
+
# Update a model.
|
604
|
+
#
|
605
|
+
# Runs validation and callbacks. Reloads all attribute values.
|
606
|
+
#
|
607
|
+
# Accepts mandatory block in order to specify operations which will modify
|
608
|
+
# attributes. Supports following operations: +add+, +delete+ and +set+.
|
609
|
+
#
|
610
|
+
# Operation +add+ just adds a value for numeric attributes and join
|
611
|
+
# collections if attribute is a collection (one of +array+, +set+ or
|
612
|
+
# +map+).
|
613
|
+
#
|
614
|
+
# user.update do |t|
|
615
|
+
# t.add(age: 1, followers_count: 5)
|
616
|
+
# t.add(hobbies: ['skying', 'climbing'])
|
617
|
+
# end
|
618
|
+
#
|
619
|
+
# Operation +delete+ is applied to collection attribute types and
|
620
|
+
# substructs one collection from another.
|
621
|
+
#
|
622
|
+
# user.update do |t|
|
623
|
+
# t.delete(hobbies: ['skying'])
|
624
|
+
# end
|
625
|
+
#
|
626
|
+
# Operation +set+ just changes an attribute value:
|
627
|
+
#
|
628
|
+
# user.update do |t|
|
629
|
+
# t.set(age: 21)
|
630
|
+
# end
|
631
|
+
#
|
632
|
+
# All the operations works like +ADD+, +DELETE+ and +PUT+ actions supported
|
633
|
+
# by +AttributeUpdates+
|
634
|
+
# {parameter}[https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/LegacyConditionalParameters.AttributeUpdates.html]
|
635
|
+
# of +UpdateItem+ operation.
|
636
|
+
#
|
637
|
+
# Can update a model conditionaly:
|
638
|
+
#
|
639
|
+
# user.update(if: { age: 20 }) do |t|
|
640
|
+
# t.add(age: 1)
|
641
|
+
# end
|
642
|
+
#
|
643
|
+
# If a document doesn't meet conditions it just returns +false+. Otherwise it returns +true+.
|
644
|
+
#
|
645
|
+
# It will increment the +lock_version+ attribute if a table has the column,
|
646
|
+
# but will not check it. Thus, a concurrent +save+ call will never cause an
|
647
|
+
# +update!+ to fail, but an +update!+ may cause a concurrent +save+ to
|
648
|
+
# fail.
|
649
|
+
#
|
650
|
+
# @param conditions [Hash] Conditions on model attributes to make a conditional update (optional)
|
368
651
|
def update(conditions = {}, &block)
|
369
652
|
update!(conditions, &block)
|
370
653
|
true
|
@@ -372,38 +655,86 @@ module Dynamoid
|
|
372
655
|
false
|
373
656
|
end
|
374
657
|
|
375
|
-
#
|
376
|
-
#
|
658
|
+
# Change numeric attribute value.
|
659
|
+
#
|
660
|
+
# Initializes attribute to zero if +nil+ and adds the specified value (by
|
661
|
+
# default is 1). Only makes sense for number-based attributes.
|
662
|
+
#
|
663
|
+
# user.increment(:followers_count)
|
664
|
+
# user.increment(:followers_count, 2)
|
665
|
+
#
|
666
|
+
# @param attribute [Symbol] attribute name
|
667
|
+
# @param by [Numeric] value to add (optional)
|
668
|
+
# @return [Dynamoid::Document] self
|
377
669
|
def increment(attribute, by = 1)
|
378
670
|
self[attribute] ||= 0
|
379
671
|
self[attribute] += by
|
380
672
|
self
|
381
673
|
end
|
382
674
|
|
383
|
-
#
|
384
|
-
#
|
675
|
+
# Change numeric attribute value and save a model.
|
676
|
+
#
|
677
|
+
# Initializes attribute to zero if +nil+ and adds the specified value (by
|
678
|
+
# default is 1). Only makes sense for number-based attributes.
|
679
|
+
#
|
680
|
+
# user.increment!(:followers_count)
|
681
|
+
# user.increment!(:followers_count, 2)
|
682
|
+
#
|
683
|
+
# Returns +true+ if a model was saved and +false+ otherwise.
|
684
|
+
#
|
685
|
+
# @param attribute [Symbol] attribute name
|
686
|
+
# @param by [Numeric] value to add (optional)
|
687
|
+
# @return [true|false] whether saved model successfully
|
385
688
|
def increment!(attribute, by = 1)
|
386
689
|
increment(attribute, by)
|
387
690
|
save
|
388
691
|
end
|
389
692
|
|
390
|
-
#
|
391
|
-
#
|
693
|
+
# Change numeric attribute value.
|
694
|
+
#
|
695
|
+
# Initializes attribute to zero if +nil+ and subtracts the specified value
|
696
|
+
# (by default is 1). Only makes sense for number-based attributes.
|
697
|
+
#
|
698
|
+
# user.decrement(:followers_count)
|
699
|
+
# user.decrement(:followers_count, 2)
|
700
|
+
#
|
701
|
+
# @param attribute [Symbol] attribute name
|
702
|
+
# @param by [Numeric] value to subtract (optional)
|
703
|
+
# @return [Dynamoid::Document] self
|
392
704
|
def decrement(attribute, by = 1)
|
393
705
|
self[attribute] ||= 0
|
394
706
|
self[attribute] -= by
|
395
707
|
self
|
396
708
|
end
|
397
709
|
|
398
|
-
#
|
399
|
-
#
|
710
|
+
# Change numeric attribute value and save a model.
|
711
|
+
#
|
712
|
+
# Initializes attribute to zero if +nil+ and subtracts the specified value
|
713
|
+
# (by default is 1). Only makes sense for number-based attributes.
|
714
|
+
#
|
715
|
+
# user.decrement!(:followers_count)
|
716
|
+
# user.decrement!(:followers_count, 2)
|
717
|
+
#
|
718
|
+
# Returns +true+ if a model was saved and +false+ otherwise.
|
719
|
+
#
|
720
|
+
# @param attribute [Symbol] attribute name
|
721
|
+
# @param by [Numeric] value to subtract (optional)
|
722
|
+
# @return [true|false] whether saved model successfully
|
400
723
|
def decrement!(attribute, by = 1)
|
401
724
|
decrement(attribute, by)
|
402
725
|
save
|
403
726
|
end
|
404
727
|
|
405
|
-
# Delete
|
728
|
+
# Delete a model.
|
729
|
+
#
|
730
|
+
# Runs callbacks.
|
406
731
|
#
|
732
|
+
# Supports optimistic locking with the +lock_version+ attribute and doesn't
|
733
|
+
# delete a model if it's already changed.
|
734
|
+
#
|
735
|
+
# Returns +true+ if deleted successfully and +false+ otherwise.
|
736
|
+
#
|
737
|
+
# @return [true|false] whether deleted successfully
|
407
738
|
# @since 0.2.0
|
408
739
|
def destroy
|
409
740
|
ret = run_callbacks(:destroy) do
|
@@ -415,11 +746,26 @@ module Dynamoid
|
|
415
746
|
ret == false ? false : self
|
416
747
|
end
|
417
748
|
|
749
|
+
# Delete a model.
|
750
|
+
#
|
751
|
+
# Runs callbacks.
|
752
|
+
#
|
753
|
+
# Supports optimistic locking with the +lock_version+ attribute and doesn't
|
754
|
+
# delete a model if it's already changed.
|
755
|
+
#
|
756
|
+
# Raises +Dynamoid::Errors::RecordNotDestroyed+ exception if model deleting
|
757
|
+
# failed.
|
418
758
|
def destroy!
|
419
759
|
destroy || (raise Dynamoid::Errors::RecordNotDestroyed, self)
|
420
760
|
end
|
421
761
|
|
422
|
-
# Delete
|
762
|
+
# Delete a model.
|
763
|
+
#
|
764
|
+
# Supports optimistic locking with the +lock_version+ attribute and doesn't
|
765
|
+
# delete a model if it's already changed.
|
766
|
+
#
|
767
|
+
# Raises +Dynamoid::Errors::StaleObjectError+ exception if cannot delete a
|
768
|
+
# model.
|
423
769
|
#
|
424
770
|
# @since 0.2.0
|
425
771
|
def delete
|