aws-record 2.8.0 → 2.10.0
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 +4 -4
- data/lib/aws-record/record/attributes.rb +58 -3
- data/lib/aws-record/record/batch.rb +99 -35
- data/lib/aws-record/record/batch_read.rb +186 -0
- data/lib/aws-record/record/batch_write.rb +8 -2
- data/lib/aws-record/record/client_configuration.rb +12 -2
- data/lib/aws-record/record/item_collection.rb +1 -1
- data/lib/aws-record/record/item_operations.rb +38 -12
- data/lib/aws-record/record/model_attributes.rb +7 -0
- data/lib/aws-record/record/secondary_indexes.rb +23 -0
- data/lib/aws-record/record.rb +99 -8
- data/lib/aws-record.rb +2 -12
- metadata +4 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e1d49110ed24d748680a2fe7c1d124e5faa40c1ee224b6f20059cc3252dc8b27
|
4
|
+
data.tar.gz: 4efe9261ad7642c172e267f4cec4b614f61f42e7c57970c7561b6eb51c6ac516
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9d2d80ea4671ab80debef324a8f80b40cb41034b2a426c69d95db48d436d86f1f7c4d1c8458da363595c28de3254c0755d9956f78f3e25dcacea83d695c8cede
|
7
|
+
data.tar.gz: ae7e17fb7b3fcd56a3e5f78c92da540bcceb5d4a3ec62ac70b95cf0eaefaedb89a5845b701d5b28eba0221294c6eb1f769800756017e04a812dd1a552dfd43ce
|
@@ -20,8 +20,19 @@ module Aws
|
|
20
20
|
model_attributes = ModelAttributes.new(self)
|
21
21
|
sub_class.instance_variable_set("@attributes", model_attributes)
|
22
22
|
sub_class.instance_variable_set("@keys", KeyAttributes.new(model_attributes))
|
23
|
+
if Aws::Record.extends_record?(sub_class)
|
24
|
+
inherit_attributes(sub_class)
|
25
|
+
end
|
23
26
|
end
|
24
27
|
|
28
|
+
# Base initialization method for a new item. Optionally, allows you to
|
29
|
+
# provide initial attribute values for the model. You do not need to
|
30
|
+
# provide all, or even any, attributes at item creation time.
|
31
|
+
#
|
32
|
+
# === Inheritance Support
|
33
|
+
# Child models will inherit the attributes and keys defined in the parent
|
34
|
+
# model. Child models can override attribute keys if defined in their own model.
|
35
|
+
# See examples below to see the feature in action.
|
25
36
|
# @example Usage Example
|
26
37
|
# class MyModel
|
27
38
|
# include Aws::Record
|
@@ -31,11 +42,34 @@ module Aws
|
|
31
42
|
# end
|
32
43
|
#
|
33
44
|
# item = MyModel.new(id: 1, name: "Quick Create")
|
45
|
+
# @example Child model inheriting from Parent model
|
46
|
+
# class Animal
|
47
|
+
# include Aws::Record
|
48
|
+
# string_attr :name, hash_key: true
|
49
|
+
# integer_attr :age, default_value: 1
|
50
|
+
# end
|
34
51
|
#
|
35
|
-
#
|
36
|
-
#
|
37
|
-
#
|
52
|
+
# class Cat < Animal
|
53
|
+
# include Aws::Record
|
54
|
+
# integer_attr :num_of_wiskers
|
55
|
+
# end
|
38
56
|
#
|
57
|
+
# cat = Cat.find(name: 'Foo')
|
58
|
+
# cat.age # => 1
|
59
|
+
# cat.num_of_wiskers = 200
|
60
|
+
# @example Child model overrides the hash key
|
61
|
+
# class Animal
|
62
|
+
# include Aws::Record
|
63
|
+
# string_attr :name, hash_key: true
|
64
|
+
# integer_attr :age, range_key: true
|
65
|
+
# end
|
66
|
+
#
|
67
|
+
# class Dog < Animal
|
68
|
+
# include Aws::Record
|
69
|
+
# integer_attr :id, hash_key: true
|
70
|
+
# end
|
71
|
+
#
|
72
|
+
# Dog.keys # => {:hash=>:id, :range=>:age}
|
39
73
|
# @param [Hash] attr_values Attribute symbol/value pairs for any initial
|
40
74
|
# attribute values you wish to set.
|
41
75
|
# @return [Aws::Record] An item instance for your model.
|
@@ -56,6 +90,27 @@ module Aws
|
|
56
90
|
@data.hash_copy
|
57
91
|
end
|
58
92
|
|
93
|
+
private
|
94
|
+
def self.inherit_attributes(klass)
|
95
|
+
superclass_attributes = klass.superclass.instance_variable_get("@attributes")
|
96
|
+
|
97
|
+
superclass_attributes.attributes.each do |name, attribute|
|
98
|
+
subclass_attributes = klass.instance_variable_get("@attributes")
|
99
|
+
subclass_attributes.register_superclass_attribute(name, attribute)
|
100
|
+
end
|
101
|
+
|
102
|
+
superclass_keys = klass.superclass.instance_variable_get("@keys")
|
103
|
+
subclass_keys = klass.instance_variable_get("@keys")
|
104
|
+
|
105
|
+
if superclass_keys.hash_key
|
106
|
+
subclass_keys.hash_key = superclass_keys.hash_key
|
107
|
+
end
|
108
|
+
|
109
|
+
if superclass_keys.range_key
|
110
|
+
subclass_keys.range_key = superclass_keys.range_key
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
59
114
|
module ClassMethods
|
60
115
|
|
61
116
|
# Define an attribute for your model, providing your own attribute type.
|
@@ -1,15 +1,4 @@
|
|
1
|
-
#
|
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!
|
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(
|
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
|
@@ -26,6 +26,8 @@ module Aws
|
|
26
26
|
# in doubt, call this method to ensure your client is configured the way
|
27
27
|
# you want it to be configured.
|
28
28
|
#
|
29
|
+
# *Note*: {#dynamodb_client} is inherited from a parent model when
|
30
|
+
# +configure_client+ is explicitly specified in the parent.
|
29
31
|
# @param [Hash] opts the options you wish to use to create the client.
|
30
32
|
# Note that if you include the option +:client+, all other options
|
31
33
|
# will be ignored. See the documentation for other options in the
|
@@ -33,15 +35,23 @@ module Aws
|
|
33
35
|
# @option opts [Aws::DynamoDB::Client] :client allows you to pass in your
|
34
36
|
# own pre-configured client.
|
35
37
|
def configure_client(opts = {})
|
36
|
-
|
38
|
+
if self.class != Module && Aws::Record.extends_record?(self) && opts.empty? &&
|
39
|
+
self.superclass.instance_variable_get('@dynamodb_client')
|
40
|
+
@dynamodb_client = self.superclass.instance_variable_get('@dynamodb_client')
|
41
|
+
else
|
42
|
+
@dynamodb_client = _build_client(opts)
|
43
|
+
end
|
37
44
|
end
|
38
45
|
|
39
46
|
# Gets the
|
40
|
-
# {https://docs.aws.amazon.com/sdk-for-ruby/v3/api/Aws/DynamoDB/Client.html}
|
47
|
+
# {https://docs.aws.amazon.com/sdk-for-ruby/v3/api/Aws/DynamoDB/Client.html Client}
|
41
48
|
# instance that Transactions use. When called for the first time, if
|
42
49
|
# {#configure_client} has not yet been called, will configure a new
|
43
50
|
# client for you with default parameters.
|
44
51
|
#
|
52
|
+
# *Note*: +dynamodb_client+ is inherited from a parent model when
|
53
|
+
# {configure_client} is explicitly specified in the parent.
|
54
|
+
#
|
45
55
|
# @return [Aws::DynamoDB::Client] the Amazon DynamoDB client instance.
|
46
56
|
def dynamodb_client
|
47
57
|
@dynamodb_client ||= configure_client
|
@@ -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
|
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
|
-
#
|
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
|
@@ -32,6 +32,13 @@ module Aws
|
|
32
32
|
attribute
|
33
33
|
end
|
34
34
|
|
35
|
+
def register_superclass_attribute (name, attribute)
|
36
|
+
_new_attr_validation(name, attribute)
|
37
|
+
@attributes[name] = attribute.dup
|
38
|
+
@storage_attributes[attribute.database_name] = name
|
39
|
+
attribute
|
40
|
+
end
|
41
|
+
|
35
42
|
def attribute_for(name)
|
36
43
|
@attributes[name]
|
37
44
|
end
|
@@ -20,6 +20,17 @@ module Aws
|
|
20
20
|
sub_class.instance_variable_set("@local_secondary_indexes", {})
|
21
21
|
sub_class.instance_variable_set("@global_secondary_indexes", {})
|
22
22
|
sub_class.extend(SecondaryIndexesClassMethods)
|
23
|
+
if Aws::Record.extends_record?(sub_class)
|
24
|
+
inherit_indexes(sub_class)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
private
|
29
|
+
def self.inherit_indexes(klass)
|
30
|
+
superclass_lsi = klass.superclass.instance_variable_get("@local_secondary_indexes").dup
|
31
|
+
superclass_gsi = klass.superclass.instance_variable_get("@global_secondary_indexes").dup
|
32
|
+
klass.instance_variable_set("@local_secondary_indexes", superclass_lsi)
|
33
|
+
klass.instance_variable_set("@global_secondary_indexes", superclass_gsi)
|
23
34
|
end
|
24
35
|
|
25
36
|
module SecondaryIndexesClassMethods
|
@@ -28,6 +39,8 @@ module Aws
|
|
28
39
|
# Secondary Indexes in the
|
29
40
|
# {http://docs.aws.amazon.com/amazondynamodb/latest/developerguide/LSI.html Amazon DynamoDB Developer Guide}.
|
30
41
|
#
|
42
|
+
# *Note*: {#local_secondary_indexes} is inherited from a parent model
|
43
|
+
# when +local_secondary_index+ is explicitly specified in the parent.
|
31
44
|
# @param [Symbol] name index name for this local secondary index
|
32
45
|
# @param [Hash] opts
|
33
46
|
# @option opts [Symbol] :range_key the range key used by this local
|
@@ -46,6 +59,8 @@ module Aws
|
|
46
59
|
# Global Secondary Indexes in the
|
47
60
|
# {http://docs.aws.amazon.com/amazondynamodb/latest/developerguide/GSI.html Amazon DynamoDB Developer Guide}.
|
48
61
|
#
|
62
|
+
# *Note*: {#global_secondary_indexes} is inherited from a parent model
|
63
|
+
# when +global_secondary_index+ is explicitly specified in the parent.
|
49
64
|
# @param [Symbol] name index name for this global secondary index
|
50
65
|
# @param [Hash] opts
|
51
66
|
# @option opts [Symbol] :hash_key the hash key used by this global
|
@@ -60,12 +75,20 @@ module Aws
|
|
60
75
|
global_secondary_indexes[name] = opts
|
61
76
|
end
|
62
77
|
|
78
|
+
# Returns hash of local secondary index names to the index’s attributes.
|
79
|
+
#
|
80
|
+
# *Note*: +local_secondary_indexes+ is inherited from a parent model when {#local_secondary_index}
|
81
|
+
# is explicitly specified in the parent.
|
63
82
|
# @return [Hash] hash of local secondary index names to the index's
|
64
83
|
# attributes.
|
65
84
|
def local_secondary_indexes
|
66
85
|
@local_secondary_indexes
|
67
86
|
end
|
68
87
|
|
88
|
+
# Returns hash of global secondary index names to the index’s attributes.
|
89
|
+
#
|
90
|
+
# *Note*: +global_secondary_indexes+ is inherited from a parent model when {#global_secondary_index}
|
91
|
+
# is explicitly specified in the parent.
|
69
92
|
# @return [Hash] hash of global secondary index names to the index's
|
70
93
|
# attributes.
|
71
94
|
def global_secondary_indexes
|
data/lib/aws-record/record.rb
CHANGED
@@ -17,7 +17,19 @@ module Aws
|
|
17
17
|
# decorate them with the Amazon DynamoDB integration methods provided by this
|
18
18
|
# library. Methods you can use are shown below, in sub-modules organized by
|
19
19
|
# functionality.
|
20
|
-
#
|
20
|
+
# === Inheritance Support
|
21
|
+
# Aws Record models can be extended using standard ruby inheritance. The child
|
22
|
+
# model must include +Aws::Record+ in their model and the following will
|
23
|
+
# be inherited:
|
24
|
+
# * {#set_table_name set_table_name}
|
25
|
+
# * {#initialize Attributes and keys}
|
26
|
+
# * Mutation Tracking:
|
27
|
+
# * {#enable_mutation_tracking enable_mutation_tracking}
|
28
|
+
# * {#disable_mutation_tracking disable_mutation_tracking}
|
29
|
+
# * {#local_secondary_indexes local_secondary_indexes}
|
30
|
+
# * {#global_secondary_indexes global_secondary_indexes}
|
31
|
+
# * {ClientConfiguration#configure_client configure_client}
|
32
|
+
# See example below to see the feature in action.
|
21
33
|
# @example A class definition using +Aws::Record+
|
22
34
|
# class MyModel
|
23
35
|
# include Aws::Record
|
@@ -28,6 +40,21 @@ module Aws
|
|
28
40
|
# string_set_attr :tags
|
29
41
|
# map_attr :metadata
|
30
42
|
# end
|
43
|
+
# @example Inheritance between models
|
44
|
+
# class Animal
|
45
|
+
# include Aws::Record
|
46
|
+
# string_attr :name, hash_key: true
|
47
|
+
# integer_attr :age
|
48
|
+
# end
|
49
|
+
#
|
50
|
+
# class Dog < Animal
|
51
|
+
# include Aws::Record
|
52
|
+
# boolean_attr :family_friendly
|
53
|
+
# end
|
54
|
+
#
|
55
|
+
# dog = Dog.find(name: 'Sunflower')
|
56
|
+
# dog.age = 3
|
57
|
+
# dog.family_friendly = true
|
31
58
|
module Record
|
32
59
|
# @!parse extend RecordClassMethods
|
33
60
|
# @!parse include Attributes
|
@@ -57,6 +84,14 @@ module Aws
|
|
57
84
|
sub_class.send(:include, DirtyTracking)
|
58
85
|
sub_class.send(:include, Query)
|
59
86
|
sub_class.send(:include, SecondaryIndexes)
|
87
|
+
if Aws::Record.extends_record?(sub_class)
|
88
|
+
inherit_track_mutations(sub_class)
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
# @api private
|
93
|
+
def self.extends_record?(klass)
|
94
|
+
klass.superclass.include?(Aws::Record)
|
60
95
|
end
|
61
96
|
|
62
97
|
private
|
@@ -64,6 +99,11 @@ module Aws
|
|
64
99
|
self.class.dynamodb_client
|
65
100
|
end
|
66
101
|
|
102
|
+
def self.inherit_track_mutations(klass)
|
103
|
+
superclass_track_mutations = klass.superclass.instance_variable_get("@track_mutations")
|
104
|
+
klass.instance_variable_set("@track_mutations", superclass_track_mutations)
|
105
|
+
end
|
106
|
+
|
67
107
|
module RecordClassMethods
|
68
108
|
|
69
109
|
# Returns the Amazon DynamoDB table name for this model class.
|
@@ -72,12 +112,14 @@ module Aws
|
|
72
112
|
# also define a custom table name at the class level to be anything that
|
73
113
|
# you want.
|
74
114
|
#
|
115
|
+
# *Note*: +table_name+ is inherited from a parent model when {set_table_name}
|
116
|
+
# is explicitly specified in the parent.
|
75
117
|
# @example
|
76
118
|
# class MyTable
|
77
119
|
# include Aws::Record
|
78
120
|
# end
|
79
121
|
#
|
80
|
-
# class
|
122
|
+
# class MyOtherTable
|
81
123
|
# include Aws::Record
|
82
124
|
# set_table_name "test_MyTable"
|
83
125
|
# end
|
@@ -85,29 +127,65 @@ module Aws
|
|
85
127
|
# MyTable.table_name # => "MyTable"
|
86
128
|
# MyOtherTable.table_name # => "test_MyTable"
|
87
129
|
def table_name
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
130
|
+
@table_name ||= begin
|
131
|
+
if Aws::Record.extends_record?(self) &&
|
132
|
+
default_table_name(self.superclass) != self.superclass.table_name
|
133
|
+
self.superclass.instance_variable_get('@table_name')
|
134
|
+
else
|
135
|
+
default_table_name(self)
|
136
|
+
end
|
92
137
|
end
|
93
138
|
end
|
94
139
|
|
95
140
|
# Allows you to set a custom Amazon DynamoDB table name for this model
|
96
141
|
# class.
|
142
|
+
# === Inheritance Support
|
143
|
+
# +table_name+ is inherited from a parent model when it is explicitly specified
|
144
|
+
# in the parent.
|
97
145
|
#
|
98
|
-
#
|
146
|
+
# The parent model will need to have +set_table_name+ defined in their model
|
147
|
+
# for the child model to inherit the +table_name+.
|
148
|
+
# If no +set_table_name+ is defined, the parent and child models will have separate
|
149
|
+
# table names based on their class name.
|
150
|
+
#
|
151
|
+
# If both parent and child models have defined +set_table_name+ in their model,
|
152
|
+
# the child model will override the +table_name+ with theirs.
|
153
|
+
# @example Setting custom table name for model class
|
99
154
|
# class MyTable
|
100
155
|
# include Aws::Record
|
101
156
|
# set_table_name "prod_MyTable"
|
102
157
|
# end
|
103
158
|
#
|
104
|
-
# class
|
159
|
+
# class MyOtherTable
|
105
160
|
# include Aws::Record
|
106
161
|
# set_table_name "test_MyTable"
|
107
162
|
# end
|
108
163
|
#
|
109
164
|
# MyTable.table_name # => "prod_MyTable"
|
110
165
|
# MyOtherTable.table_name # => "test_MyTable"
|
166
|
+
# @example Child model inherits table name from Parent model
|
167
|
+
# class Animal
|
168
|
+
# include Aws::Record
|
169
|
+
# set_table_name "AnimalTable"
|
170
|
+
# end
|
171
|
+
#
|
172
|
+
# class Dog < Animal
|
173
|
+
# include Aws::Record
|
174
|
+
# end
|
175
|
+
#
|
176
|
+
# Dog.table_name # => "AnimalTable"
|
177
|
+
# @example Child model overrides table name from Parent model
|
178
|
+
# class Animal
|
179
|
+
# include Aws::Record
|
180
|
+
# set_table_name "AnimalTable"
|
181
|
+
# end
|
182
|
+
#
|
183
|
+
# class Dog < Animal
|
184
|
+
# include Aws::Record
|
185
|
+
# set_table_name "DogTable"
|
186
|
+
# end
|
187
|
+
#
|
188
|
+
# Dog.table_name # => "DogTable"
|
111
189
|
def set_table_name(name)
|
112
190
|
@table_name = name
|
113
191
|
end
|
@@ -149,6 +227,9 @@ module Aws
|
|
149
227
|
end
|
150
228
|
|
151
229
|
# Turns off mutation tracking for all attributes in the model.
|
230
|
+
#
|
231
|
+
# *Note*: +disable_mutation_tracking+ is inherited from a parent model
|
232
|
+
# when it is explicitly specified in the parent.
|
152
233
|
def disable_mutation_tracking
|
153
234
|
@track_mutations = false
|
154
235
|
end
|
@@ -158,6 +239,9 @@ module Aws
|
|
158
239
|
# call this. It is provided in case there is a need to dynamically turn
|
159
240
|
# this feature on and off, though that would be generally discouraged and
|
160
241
|
# could cause inaccurate mutation tracking at runtime.
|
242
|
+
#
|
243
|
+
# *Note*: +enable_mutation_tracking+ is inherited from a parent model
|
244
|
+
# when it is explicitly specified in the parent.
|
161
245
|
def enable_mutation_tracking
|
162
246
|
@track_mutations = true
|
163
247
|
end
|
@@ -177,6 +261,13 @@ module Aws
|
|
177
261
|
raise Errors::InvalidModel.new("Table models must include a hash key")
|
178
262
|
end
|
179
263
|
end
|
264
|
+
|
265
|
+
private
|
266
|
+
def default_table_name(klass)
|
267
|
+
return unless klass.name
|
268
|
+
klass.name.split("::").join("_")
|
269
|
+
end
|
270
|
+
|
180
271
|
end
|
181
272
|
end
|
182
273
|
end
|
data/lib/aws-record.rb
CHANGED
@@ -1,15 +1,4 @@
|
|
1
|
-
#
|
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.
|
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:
|
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:
|
69
|
+
homepage: https://github.com/aws/aws-sdk-ruby-record
|
69
70
|
licenses:
|
70
71
|
- Apache 2.0
|
71
72
|
metadata: {}
|