aws-record 2.9.0 → 2.10.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 6316b0ad6349fdea29d10e1325b6044b54eb3f2696a9bd1692cc30881e5e2e02
4
- data.tar.gz: 57c1d3c37435e3bc79eac488738c08f8ac6536bfbd5f493ac221f248bdf3e8c8
3
+ metadata.gz: e1d49110ed24d748680a2fe7c1d124e5faa40c1ee224b6f20059cc3252dc8b27
4
+ data.tar.gz: 4efe9261ad7642c172e267f4cec4b614f61f42e7c57970c7561b6eb51c6ac516
5
5
  SHA512:
6
- metadata.gz: 8bdca623e0884f5cd2a704bf807be58687077e04f746e5c99a6e15ce2df4ad378afd6e3d6bdb74899d4a86521e921fd588a5fbdc5ba1c6b6c06e3daf08ad3d16
7
- data.tar.gz: 2448123077cea61bf1ab263278ce1a2209d69d9a7ed53d8f665feb8bef2c7185c447378f3c4ae70a96a16ef4d62e4d2a3ffd1769f94bc367e8cd2e0c1733c4cd
6
+ metadata.gz: 9d2d80ea4671ab80debef324a8f80b40cb41034b2a426c69d95db48d436d86f1f7c4d1c8458da363595c28de3254c0755d9956f78f3e25dcacea83d695c8cede
7
+ data.tar.gz: ae7e17fb7b3fcd56a3e5f78c92da540bcceb5d4a3ec62ac70b95cf0eaefaedb89a5845b701d5b28eba0221294c6eb1f769800756017e04a812dd1a552dfd43ce
@@ -1,15 +1,4 @@
1
- # Copyright 2015-2021 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.
1
+ # frozen_string_literal: true
13
2
 
14
3
  module Aws
15
4
  module Record
@@ -17,6 +6,28 @@ module Aws
17
6
  extend ClientConfiguration
18
7
 
19
8
  class << self
9
+ # Provides a thin wrapper to the
10
+ # {https://docs.aws.amazon.com/sdk-for-ruby/v3/api/Aws/DynamoDB/Client.html#batch_write_item-instance_method Aws::DynamoDB::Client#batch_write_item}
11
+ # method. Up to 25 +PutItem+ or +DeleteItem+ operations are supported.
12
+ # A single request may write up to 16 MB of data, with each item having a
13
+ # write limit of 400 KB.
14
+ #
15
+ # *Note*: this operation does not support dirty attribute handling,
16
+ # nor does it enforce safe write operations (i.e. update vs new record
17
+ # checks).
18
+ #
19
+ # This call may partially execute write operations. Failed operations
20
+ # are returned as {BatchWrite.unprocessed_items unprocessed_items} (i.e. the
21
+ # table fails to meet requested write capacity). Any unprocessed
22
+ # items may be retried by calling {BatchWrite.execute! .execute!}
23
+ # again. You can determine if the request needs to be retried by calling
24
+ # the {BatchWrite.complete? .complete?} method - which returns +true+
25
+ # when all operations have been completed.
26
+ #
27
+ # Please see
28
+ # {https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Programming.Errors.html#Programming.Errors.BatchOperations Batch Operations and Error Handling}
29
+ # in the DynamoDB Developer Guide for more details.
30
+ #
20
31
  # @example Usage Example
21
32
  # class Breakfast
22
33
  # include Aws::Record
@@ -38,29 +49,7 @@ module Aws
38
49
  # end
39
50
  #
40
51
  # # unprocessed items can be retried by calling Aws::Record::BatchWrite#execute!
41
- # operation.execute! unless operation.complete?
42
- #
43
- # Provides a thin wrapper to the
44
- # {https://docs.aws.amazon.com/sdk-for-ruby/v3/api/Aws/DynamoDB/Client.html#batch_write_item-instance_method Aws::DynamoDB::Client#batch_write_item}
45
- # method. Up to 25 +PutItem+ or +DeleteItem+ operations are supported.
46
- # A single rquest may write up to 16 MB of data, with each item having a
47
- # write limit of 400 KB.
48
- #
49
- # *Note*: this operation does not support dirty attribute handling,
50
- # nor does it enforce safe write operations (i.e. update vs new record
51
- # checks).
52
- #
53
- # This call may partially execute write operations. Failed operations
54
- # are returned as +Aws::Record::BatchWrite#unprocessed_items+ (i.e. the
55
- # table fails to meet requested write capacity). Any unprocessed
56
- # items may be retried by calling +Aws::Record::BatchWrite#execute!+
57
- # again. You can determine if the request needs to be retried by calling
58
- # the +Aws::Record::BatchWrite#complete?+ method - which returns +true+
59
- # when all operations have been completed.
60
- #
61
- # Please see
62
- # {https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Programming.Errors.html#Programming.Errors.BatchOperations Batch Operations and Error Handling}
63
- # in the DynamoDB Developer Guide for more details.
52
+ # operation.execute! until operation.complete?
64
53
  #
65
54
  # @param [Hash] opts the options you wish to use to create the client.
66
55
  # Note that if you include the option +:client+, all other options
@@ -76,6 +65,81 @@ module Aws
76
65
  block.call(batch)
77
66
  batch.execute!
78
67
  end
68
+
69
+ # Provides support for the
70
+ # {https://docs.aws.amazon.com/sdk-for-ruby/v3/api/Aws/DynamoDB/Client.html#batch_get_item-instance_method
71
+ # Aws::DynamoDB::Client#batch_get_item} for aws-record models.
72
+ #
73
+ # +Aws::Record::Batch+ is Enumerable and using Enumerable methods will handle
74
+ # paging through all requested keys automatically. Alternatively, a lower level
75
+ # interface is available. You can determine if there are any unprocessed keys by calling
76
+ # {BatchRead.complete? .complete?} and any unprocessed keys can be processed by
77
+ # calling {BatchRead.execute! .execute!}. You can access all processed items
78
+ # through {BatchRead.items .items}.
79
+ #
80
+ # The +batch_get_item+ supports up to 100 operations in a single call and a single
81
+ # operation can retrieve up to 16 MB of data.
82
+ #
83
+ # +Aws::Record::BatchRead+ can take more than 100 item keys. The first 100 requests
84
+ # will be processed and the remaining requests will be stored.
85
+ # When using Enumerable methods, any pending item keys will be automatically
86
+ # processed and the new items will be added to +items+.
87
+ # Alternately, use {BatchRead.execute! .execute!} to process any pending item keys.
88
+ #
89
+ # All processed operations can be accessed by {BatchRead.items items} - which is an
90
+ # array of modeled items from the response. The items will be unordered since
91
+ # DynamoDB does not return items in any particular order.
92
+ #
93
+ # If a requested item does not exist in the database, it is not returned in the response.
94
+ #
95
+ # If there is a returned item from the call and there's no reference model class
96
+ # to be found, the item will not show up under +items+.
97
+ #
98
+ # @example Usage Example
99
+ # class Lunch
100
+ # include Aws::Record
101
+ # integer_attr :id, hash_key: true
102
+ # string_attr :name, range_key: true
103
+ # end
104
+ #
105
+ # class Dessert
106
+ # include Aws::Record
107
+ # integer_attr :id, hash_key: true
108
+ # string_attr :name, range_key: true
109
+ # end
110
+ #
111
+ # # batch operations
112
+ # operation = Aws::Record::Batch.read do |db|
113
+ # db.find(Lunch, id: 1, name: 'Papaya Salad')
114
+ # db.find(Lunch, id: 2, name: 'BLT Sandwich')
115
+ # db.find(Dessert, id: 1, name: 'Apple Pie')
116
+ # end
117
+ #
118
+ # # BatchRead is enumerable and handles pagination
119
+ # operation.each { |item| item.id }
120
+ #
121
+ # # Alternatively, BatchRead provides a lower level
122
+ # # interface through: execute!, complete? and items.
123
+ # # Unprocessed items can be processed by calling:
124
+ # operation.execute! until operation.complete?
125
+ #
126
+ # @param [Hash] opts the options you wish to use to create the client.
127
+ # Note that if you include the option +:client+, all other options
128
+ # will be ignored. See the documentation for other options in the
129
+ # {https://docs.aws.amazon.com/sdk-for-ruby/v3/api/Aws/DynamoDB/Client.html#initialize-instance_method
130
+ # AWS SDK for Ruby}.
131
+ # @option opts [Aws::DynamoDB::Client] :client allows you to pass in your
132
+ # own pre-configured client.
133
+ # @return [Aws::Record::BatchRead] An instance that contains modeled items
134
+ # from the +BatchGetItem+ result and stores unprocessed keys to be
135
+ # manually processed later.
136
+ def read(opts = {}, &block)
137
+ batch = BatchRead.new(client: _build_client(opts))
138
+ block.call(batch)
139
+ batch.execute!
140
+ batch
141
+ end
142
+
79
143
  end
80
144
  end
81
145
  end
@@ -0,0 +1,186 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Aws
4
+ module Record
5
+ class BatchRead
6
+ include Enumerable
7
+
8
+ # @api private
9
+ BATCH_GET_ITEM_LIMIT = 100
10
+
11
+ # @param [Aws::DynamoDB::Client] client the DynamoDB SDK client.
12
+ def initialize(opts = {})
13
+ @client = opts[:client]
14
+ end
15
+
16
+ # Append the item keys to a batch read request.
17
+ #
18
+ # See {Batch.read} for example usage.
19
+ # @param [Aws::Record] klass a model class that includes {Aws::Record}
20
+ # @param [Hash] key attribute-value pairs for the key you wish to search for.
21
+ # @raise [Aws::Record::Errors::KeyMissing] if your option parameters
22
+ # do not include all item keys defined in the model.
23
+ # @raise [ArgumentError] if the provided item keys is a duplicate request
24
+ # in the same instance.
25
+ def find(klass, key = {})
26
+ unprocessed_key = format_unprocessed_key(klass, key)
27
+ store_unprocessed_key(klass, unprocessed_key)
28
+ store_item_class(klass, unprocessed_key)
29
+ end
30
+
31
+ # Perform a +batch_get_item+ request.
32
+ #
33
+ # This method processes the first 100 item keys and
34
+ # returns an array of new modeled items.
35
+ #
36
+ # See {Batch.read} for example usage.
37
+ # @return [Array] an array of unordered new items
38
+ def execute!
39
+ operation_keys = unprocessed_keys[0..BATCH_GET_ITEM_LIMIT - 1]
40
+ @unprocessed_keys = unprocessed_keys[BATCH_GET_ITEM_LIMIT..-1] || []
41
+
42
+ operations = build_operations(operation_keys)
43
+ result = @client.batch_get_item(request_items: operations)
44
+ new_items = build_items(result.responses)
45
+ items.concat(new_items)
46
+
47
+ unless result.unprocessed_keys.nil?
48
+ update_unprocessed_keys(result.unprocessed_keys)
49
+ end
50
+
51
+ new_items
52
+ end
53
+
54
+ # Provides an enumeration of the results from the +batch_get_item+ request
55
+ # and handles pagination.
56
+ #
57
+ # Any pending item keys will be automatically processed and be
58
+ # added to the {#items}.
59
+ #
60
+ # See {Batch.read} for example usage.
61
+ # @yieldparam [Aws::Record] item a modeled item
62
+ # @return [Enumerable<BatchRead>] an enumeration over the results of
63
+ # +batch_get_item+ request.
64
+ def each
65
+ return enum_for(:each) unless block_given?
66
+
67
+ @items.each { |item| yield item }
68
+ until complete?
69
+ new_items = execute!
70
+ new_items.each { |new_item| yield new_item }
71
+ end
72
+ end
73
+
74
+ # Indicates if all item keys have been processed.
75
+ #
76
+ # See {Batch.read} for example usage.
77
+ # @return [Boolean] +true+ if all item keys has been processed, +false+ otherwise.
78
+ def complete?
79
+ unprocessed_keys.none?
80
+ end
81
+
82
+ # Returns an array of modeled items. The items are marshaled into classes used in {#find} method.
83
+ # These items will be unordered since DynamoDB does not return items in any particular order.
84
+ #
85
+ # See {Batch.read} for example usage.
86
+ # @return [Array] an array of modeled items from the +batch_get_item+ call.
87
+ def items
88
+ @items ||= []
89
+ end
90
+
91
+ private
92
+
93
+ def unprocessed_keys
94
+ @unprocessed_keys ||= []
95
+ end
96
+
97
+ def item_classes
98
+ @item_classes ||= Hash.new { |h, k| h[k] = [] }
99
+ end
100
+
101
+ def format_unprocessed_key(klass, key)
102
+ item_key = {}
103
+ attributes = klass.attributes
104
+ klass.keys.each_value do |attr_sym|
105
+ unless key[attr_sym]
106
+ raise Errors::KeyMissing, "Missing required key #{attr_sym} in #{key}"
107
+ end
108
+
109
+ attr_name = attributes.storage_name_for(attr_sym)
110
+ item_key[attr_name] = attributes.attribute_for(attr_sym)
111
+ .serialize(key[attr_sym])
112
+ end
113
+ item_key
114
+ end
115
+
116
+ def store_unprocessed_key(klass, unprocessed_key)
117
+ unprocessed_keys << { keys: unprocessed_key, table_name: klass.table_name }
118
+ end
119
+
120
+ def store_item_class(klass, key)
121
+ if item_classes.include?(klass.table_name)
122
+ item_classes[klass.table_name].each do |item|
123
+ if item[:keys] == key && item[:class] != klass
124
+ raise ArgumentError, 'Provided item keys is a duplicate request'
125
+ end
126
+ end
127
+ end
128
+ item_classes[klass.table_name] << { keys: key, class: klass }
129
+ end
130
+
131
+ def build_operations(keys)
132
+ operations = Hash.new { |h, k| h[k] = { keys: [] } }
133
+ keys.each do |key|
134
+ operations[key[:table_name]][:keys] << key[:keys]
135
+ end
136
+ operations
137
+ end
138
+
139
+ def build_items(item_responses)
140
+ new_items = []
141
+ item_responses.each do |table, unprocessed_items|
142
+ unprocessed_items.each do |item|
143
+ item_class = find_item_class(table, item)
144
+ if item_class.nil? && @client.config.logger
145
+ @client.config.logger.warn(
146
+ 'Unexpected response from service.'\
147
+ "Received: #{item}. Skipping above item and continuing"
148
+ )
149
+ else
150
+ new_items << build_item(item, item_class)
151
+ end
152
+ end
153
+ end
154
+ new_items
155
+ end
156
+
157
+ def update_unprocessed_keys(keys)
158
+ keys.each do |table_name, table_values|
159
+ table_values.keys.each do |key|
160
+ unprocessed_keys << { keys: key, table_name: table_name }
161
+ end
162
+ end
163
+ end
164
+
165
+ def find_item_class(table, item)
166
+ selected_item = item_classes[table].find { |item_info| contains_keys?(item, item_info[:keys]) }
167
+ selected_item[:class] if selected_item
168
+ end
169
+
170
+ def contains_keys?(item, keys)
171
+ item.merge(keys) == item
172
+ end
173
+
174
+ def build_item(item, item_class)
175
+ new_item_opts = {}
176
+ item.each do |db_name, value|
177
+ name = item_class.attributes.db_to_attribute_name(db_name)
178
+ new_item_opts[name] = value
179
+ end
180
+ item = item_class.new(new_item_opts)
181
+ item.clean!
182
+ item
183
+ end
184
+ end
185
+ end
186
+ end
@@ -15,12 +15,14 @@ module Aws
15
15
  module Record
16
16
  class BatchWrite
17
17
  # @param [Aws::DynamoDB::Client] client the DynamoDB SDK client.
18
- def initialize(client:)
19
- @client = client
18
+ def initialize(opts = {})
19
+ @client = opts[:client]
20
20
  end
21
21
 
22
22
  # Append a +PutItem+ operation to a batch write request.
23
23
  #
24
+ # See {Batch.write} for example usage.
25
+ #
24
26
  # @param [Aws::Record] record a model class that includes {Aws::Record}.
25
27
  def put(record)
26
28
  table_name, params = record_put_params(record)
@@ -30,6 +32,7 @@ module Aws
30
32
 
31
33
  # Append a +DeleteItem+ operation to a batch write request.
32
34
  #
35
+ # See {Batch.write} for example usage.
33
36
  # @param [Aws::Record] record a model class that includes {Aws::Record}.
34
37
  def delete(record)
35
38
  table_name, params = record_delete_params(record)
@@ -39,6 +42,7 @@ module Aws
39
42
 
40
43
  # Perform a +batch_write_item+ request.
41
44
  #
45
+ # See {Batch.write} for example usage.
42
46
  # @return [Aws::Record::BatchWrite] an instance that provides access to
43
47
  # unprocessed items and allows for retries.
44
48
  def execute!
@@ -49,6 +53,7 @@ module Aws
49
53
 
50
54
  # Indicates if all items have been processed.
51
55
  #
56
+ # See {Batch.write} for example usage.
52
57
  # @return [Boolean] +true+ if +unprocessed_items+ is empty, +false+
53
58
  # otherwise
54
59
  def complete?
@@ -58,6 +63,7 @@ module Aws
58
63
  # Returns all +DeleteItem+ and +PutItem+ operations that have not yet been
59
64
  # processed successfully.
60
65
  #
66
+ # See {Batch.write} for example usage.
61
67
  # @return [Hash] All operations that have not yet successfully completed.
62
68
  def unprocessed_items
63
69
  operations
@@ -54,7 +54,7 @@ module Aws
54
54
  # match your search.
55
55
  #
56
56
  # @return [Array<Aws::Record>] an array of the record items found in the
57
- # first page of reponses from the query or scan call.
57
+ # first page of responses from the query or scan call.
58
58
  def page
59
59
  search_response = items
60
60
  @last_evaluated_key = search_response.last_evaluated_key
@@ -1,15 +1,4 @@
1
- # Copyright 2015-2016 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.
1
+ # frozen_string_literal: true
13
2
 
14
3
  module Aws
15
4
  module Record
@@ -514,6 +503,43 @@ module Aws
514
503
  end
515
504
  end
516
505
 
506
+
507
+ # @example Usage Example
508
+ # class MyModel
509
+ # include Aws::Record
510
+ # integer_attr :id, hash_key: true
511
+ # string_attr :name, range_key: true
512
+ # end
513
+ #
514
+ # # returns a homogenous list of items
515
+ # foo_items = MyModel.find_all(
516
+ # [
517
+ # {id: 1, name: 'n1'},
518
+ # {id: 2, name: 'n2'}
519
+ # ])
520
+ #
521
+ # Provides support for the
522
+ # {https://docs.aws.amazon.com/sdk-for-ruby/v3/api/Aws/DynamoDB/Client.html#batch_get_item-instance_method
523
+ # Aws::DynamoDB::Client#batch_get_item} for your model.
524
+ #
525
+ # This method will take a list of keys and return an instance of +Aws::Record::BatchRead+
526
+ #
527
+ # See {Batch.read} for more details.
528
+ # @param [Array] keys an array of item key hashes you wish to search for.
529
+ # @return [Aws::Record::BatchRead] An instance that contains modeled items
530
+ # from the +BatchGetItem+ result and stores unprocessed keys to be
531
+ # manually processed later.
532
+ # @raise [Aws::Record::Errors::KeyMissing] if your param hashes do not
533
+ # include all the keys defined in model.
534
+ # @raise [ArgumentError] if the provided keys are a duplicate.
535
+ def find_all(keys)
536
+ Aws::Record::Batch.read do |db|
537
+ keys.each do |key|
538
+ db.find(self, key)
539
+ end
540
+ end
541
+ end
542
+
517
543
  # @example Usage Example
518
544
  # class MyModel
519
545
  # include Aws::Record
data/lib/aws-record.rb CHANGED
@@ -1,15 +1,4 @@
1
- # Copyright 2015-2017 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.
1
+ # frozen_string_literal: true
13
2
 
14
3
  require 'aws-sdk-dynamodb'
15
4
  require_relative 'aws-record/record/client_configuration'
@@ -30,6 +19,7 @@ require_relative 'aws-record/record/table_migration'
30
19
  require_relative 'aws-record/record/version'
31
20
  require_relative 'aws-record/record/transactions'
32
21
  require_relative 'aws-record/record/buildable_search'
22
+ require_relative 'aws-record/record/batch_read'
33
23
  require_relative 'aws-record/record/batch_write'
34
24
  require_relative 'aws-record/record/batch'
35
25
  require_relative 'aws-record/record/marshalers/string_marshaler'
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.9.0
4
+ version: 2.10.0
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: 2022-11-16 00:00:00.000000000 Z
11
+ date: 2023-01-13 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: aws-sdk-dynamodb
@@ -37,6 +37,7 @@ files:
37
37
  - lib/aws-record/record/attribute.rb
38
38
  - lib/aws-record/record/attributes.rb
39
39
  - lib/aws-record/record/batch.rb
40
+ - lib/aws-record/record/batch_read.rb
40
41
  - lib/aws-record/record/batch_write.rb
41
42
  - lib/aws-record/record/buildable_search.rb
42
43
  - lib/aws-record/record/client_configuration.rb
@@ -65,7 +66,7 @@ files:
65
66
  - lib/aws-record/record/table_migration.rb
66
67
  - lib/aws-record/record/transactions.rb
67
68
  - lib/aws-record/record/version.rb
68
- homepage: http://github.com/aws/aws-sdk-ruby-record
69
+ homepage: https://github.com/aws/aws-sdk-ruby-record
69
70
  licenses:
70
71
  - Apache 2.0
71
72
  metadata: {}