aws-record 2.1.0 → 2.1.1

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 1183f72d5c4a9eb76cce79e3dc780651d33840a8
4
- data.tar.gz: 9b003057c87a84aca97b35e1bbeb2c92f873cb53
3
+ metadata.gz: 3d5eae4de88bc967f473b49bf9294047a6ee6821
4
+ data.tar.gz: 5c2e4404ad3b47f909d572b546f3cd70a8e0e93d
5
5
  SHA512:
6
- metadata.gz: 641f8d63bd27d4c77725cf09c67260e7ea46d11b1502778c180fdb356fd987ae4ded2267428f4466bcf8412aefcf57135a3ea56383fe017af076e67573af6daa
7
- data.tar.gz: 6cd6d4756195610a012767c3f7a9b5a7818ab931a5c0b78ab47b8a895963a7378d90e38ee829f45399826e1648a7b78391b61d9be0fe70155933635625c3f0e6
6
+ metadata.gz: c261673f84aa256222fdd9c17f715ab9161c1a1a1fd23978b494c62627312d12dd314d824321ef43296f87fe92be35ab135de104b6094bb753b746fe3e7235f6
7
+ data.tar.gz: 7742ea625d83be44c72602f0d55b05f7614f87971cd69bcb402f02de0e7c55057b9870a77b43b0d2adfe02f428565b7be7e770317ba9220bc8b2386528306750
data/lib/aws-record.rb CHANGED
@@ -34,6 +34,7 @@ require_relative 'aws-record/record/marshalers/float_marshaler'
34
34
  require_relative 'aws-record/record/marshalers/date_marshaler'
35
35
  require_relative 'aws-record/record/marshalers/date_time_marshaler'
36
36
  require_relative 'aws-record/record/marshalers/time_marshaler'
37
+ require_relative 'aws-record/record/marshalers/epoch_time_marshaler'
37
38
  require_relative 'aws-record/record/marshalers/list_marshaler'
38
39
  require_relative 'aws-record/record/marshalers/map_marshaler'
39
40
  require_relative 'aws-record/record/marshalers/string_set_marshaler'
@@ -240,6 +240,28 @@ module Aws
240
240
  attr(name, Marshalers::TimeMarshaler.new(opts), opts)
241
241
  end
242
242
 
243
+ # Define a time-type attribute for your model which persists as
244
+ # epoch-seconds.
245
+ #
246
+ # @param [Symbol] name Name of this attribute. It should be a name
247
+ # that is safe to use as a method.
248
+ # @param [Hash] opts
249
+ # @option opts [Boolean] :hash_key Set to true if this attribute is
250
+ # the hash key for the table.
251
+ # @option opts [Boolean] :range_key Set to true if this attribute is
252
+ # the range key for the table.
253
+ # @option opts [Boolean] :persist_nil Optional attribute used to
254
+ # indicate whether nil values should be persisted. If true, explicitly
255
+ # set nil values will be saved to DynamoDB as a "null" type. If false,
256
+ # nil values will be ignored and not persisted. By default, is false.
257
+ # @option opts [Object] :default_value Optional attribute used to
258
+ # define a "default value" to be used if the attribute's value on an
259
+ # item is nil or not set at persistence time.
260
+ def epoch_time_attr(name, opts = {})
261
+ opts[:dynamodb_type] = "N"
262
+ attr(name, Marshalers::EpochTimeMarshaler.new(opts), opts)
263
+ end
264
+
243
265
  # Define a list-type attribute for your model.
244
266
  #
245
267
  # Lists do not have to be homogeneous, but they do have to be types that
@@ -0,0 +1,66 @@
1
+ # Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License"). You may not
4
+ # use this file except in compliance with the License. A copy of the License is
5
+ # located at
6
+ #
7
+ # http://aws.amazon.com/apache2.0/
8
+ #
9
+ # or in the "license" file accompanying this file. This file is distributed on
10
+ # an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
11
+ # or implied. See the License for the specific language governing permissions
12
+ # and limitations under the License.
13
+
14
+ require 'time'
15
+
16
+ module Aws
17
+ module Record
18
+ module Marshalers
19
+
20
+ class EpochTimeMarshaler
21
+ def initialize(opts = {})
22
+ @use_local_time = opts[:use_local_time] ? true : false
23
+ end
24
+
25
+ def type_cast(raw_value)
26
+ value = _format(raw_value)
27
+ if !@use_local_time && value.is_a?(::Time)
28
+ value.utc
29
+ else
30
+ value
31
+ end
32
+ end
33
+
34
+ def serialize(raw_value)
35
+ time = type_cast(raw_value)
36
+ if time.nil?
37
+ nil
38
+ elsif time.is_a?(::Time)
39
+ time.to_i
40
+ else
41
+ msg = "expected a Time value or nil, got #{time.class}"
42
+ raise ArgumentError, msg
43
+ end
44
+ end
45
+
46
+ private
47
+
48
+ def _format(raw_value)
49
+ case raw_value
50
+ when nil
51
+ nil
52
+ when ''
53
+ nil
54
+ when ::Time
55
+ raw_value
56
+ when Integer # timestamp
57
+ ::Time.at(raw_value)
58
+ else # Date, DateTime, or String
59
+ ::Time.parse(raw_value.to_s)
60
+ end
61
+ end
62
+ end
63
+
64
+ end
65
+ end
66
+ end
@@ -74,6 +74,19 @@ module Aws
74
74
  # end
75
75
  # end
76
76
  #
77
+ # @example A model with a Time to Live attribute
78
+ # class ExpiringTokens
79
+ # string_attr :token_uuid, hash_key: true
80
+ # epoch_time_attr :ttl
81
+ # end
82
+ #
83
+ # table_config = Aws::Record::TableConfig.define do |t|
84
+ # t.model_class ExpiringTokens
85
+ # t.read_capacity_units 10
86
+ # t.write_capacity_units 1
87
+ # t.ttl_attribute :ttl
88
+ # end
89
+ #
77
90
  class TableConfig
78
91
 
79
92
  attr_accessor :client
@@ -92,6 +105,8 @@ module Aws
92
105
  # index.
93
106
  # * +#write_capacity_units+ Sets the write capacity units for the
94
107
  # index.
108
+ # * +#ttl_attribute+ Sets the attribute ID to be used as the TTL
109
+ # attribute, and if present, TTL will be enabled for the table.
95
110
  #
96
111
  # @example Defining a migration with a GSI.
97
112
  # class Forum
@@ -170,6 +185,16 @@ module Aws
170
185
  @client = Aws::DynamoDB::Client.new(@client_options)
171
186
  end
172
187
 
188
+ # @api private
189
+ def ttl_attribute(attribute_symbol)
190
+ attribute = @model_class.attributes.attribute_for(attribute_symbol)
191
+ if attribute
192
+ @ttl_attribute = attribute.database_name
193
+ else
194
+ raise ArgumentError, "Invalid attribute #{attribute_symbol} for #{@model_class}"
195
+ end
196
+ end
197
+
173
198
  # Performs a migration, if needed, against the remote table. If
174
199
  # +#compatible?+ would return true, the remote table already has the same
175
200
  # throughput, key schema, attribute definitions, and global secondary
@@ -210,6 +235,22 @@ module Aws
210
235
  @client.create_table(_create_table_opts)
211
236
  @client.wait_until(:table_exists, table_name: @model_class.table_name)
212
237
  end
238
+ # At this stage, we have a table and need to check for after-effects to
239
+ # apply.
240
+ # First up is TTL attribute. Since this migration is not exact match,
241
+ # we will only alter TTL status if we have a TTL attribute defined. We
242
+ # may someday support explicit TTL deletion, but we do not yet do this.
243
+ if @ttl_attribute
244
+ if !_ttl_compatibility_check
245
+ client.update_time_to_live(
246
+ table_name: @model_class.table_name,
247
+ time_to_live_specification: {
248
+ enabled: true,
249
+ attribute_name: @ttl_attribute
250
+ }
251
+ )
252
+ end # Else TTL is compatible and we are done.
253
+ end # Else our work is done.
213
254
  end
214
255
 
215
256
  # Checks the remote table for compatibility. Similar to +#exact_match?+,
@@ -224,7 +265,7 @@ module Aws
224
265
  def compatible?
225
266
  begin
226
267
  resp = @client.describe_table(table_name: @model_class.table_name)
227
- _compatible_check(resp)
268
+ _compatible_check(resp) && _ttl_compatibility_check
228
269
  rescue DynamoDB::Errors::ResourceNotFoundException
229
270
  false
230
271
  end
@@ -242,13 +283,41 @@ module Aws
242
283
  _throughput_equal(resp) &&
243
284
  _keys_equal(resp) &&
244
285
  _ad_equal(resp) &&
245
- _gsi_equal(resp)
286
+ _gsi_equal(resp) &&
287
+ _ttl_match_check
246
288
  rescue DynamoDB::Errors::ResourceNotFoundException
247
289
  false
248
290
  end
249
291
  end
250
292
 
251
293
  private
294
+ def _ttl_compatibility_check
295
+ if @ttl_attribute
296
+ ttl_status = @client.describe_time_to_live(
297
+ table_name: @model_class.table_name
298
+ )
299
+ desc = ttl_status.time_to_live_description
300
+ ["ENABLED", "ENABLING"].include?(desc.time_to_live_status) &&
301
+ desc.attribute_name == @ttl_attribute
302
+ else
303
+ true
304
+ end
305
+ end
306
+
307
+ def _ttl_match_check
308
+ ttl_status = @client.describe_time_to_live(
309
+ table_name: @model_class.table_name
310
+ )
311
+ desc = ttl_status.time_to_live_description
312
+ if @ttl_attribute
313
+ ["ENABLED", "ENABLING"].include?(desc.time_to_live_status) &&
314
+ desc.attribute_name == @ttl_attribute
315
+ else
316
+ !["ENABLED", "ENABLING"].include?(desc.time_to_live_status) ||
317
+ desc.attribute_name == nil
318
+ end
319
+ end
320
+
252
321
  def _compatible_check(resp)
253
322
  _throughput_equal(resp) &&
254
323
  _keys_equal(resp) &&
@@ -13,6 +13,6 @@
13
13
 
14
14
  module Aws
15
15
  module Record
16
- VERSION = '2.1.0'
16
+ VERSION = '2.1.1'
17
17
  end
18
18
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: aws-record
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.1.0
4
+ version: 2.1.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Amazon Web Services
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2018-06-25 00:00:00.000000000 Z
11
+ date: 2018-07-10 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: aws-sdk-dynamodb
@@ -44,6 +44,7 @@ files:
44
44
  - lib/aws-record/record/marshalers/boolean_marshaler.rb
45
45
  - lib/aws-record/record/marshalers/date_marshaler.rb
46
46
  - lib/aws-record/record/marshalers/date_time_marshaler.rb
47
+ - lib/aws-record/record/marshalers/epoch_time_marshaler.rb
47
48
  - lib/aws-record/record/marshalers/float_marshaler.rb
48
49
  - lib/aws-record/record/marshalers/integer_marshaler.rb
49
50
  - lib/aws-record/record/marshalers/list_marshaler.rb