aws-record 2.7.0 → 2.9.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: 67f48531ca8b917f680a1d9a5d21afd1611aba0eb96916a5783addaf7939cda8
4
- data.tar.gz: 7f6cbb16271455ada17a61f32106800b65d3b4103a5254e7686e06d5cf715cca
3
+ metadata.gz: 6316b0ad6349fdea29d10e1325b6044b54eb3f2696a9bd1692cc30881e5e2e02
4
+ data.tar.gz: 57c1d3c37435e3bc79eac488738c08f8ac6536bfbd5f493ac221f248bdf3e8c8
5
5
  SHA512:
6
- metadata.gz: 5bb474f4d13e469b9af991e061b10a54279f37d7390b9cb1bffafd40d039c649c12ca5423140d4a232a08536ec715df89db2e07f6670ef0242732cbe78d1d890
7
- data.tar.gz: 9b61d0d93ce9b657989fefde1201aab35253e656035ffb87ccbebfbafe4ea423883146dd4dec510dfdf5deec74b274784f6490d86804cf76b09aeee58f41cdfb
6
+ metadata.gz: 8bdca623e0884f5cd2a704bf807be58687077e04f746e5c99a6e15ce2df4ad378afd6e3d6bdb74899d4a86521e921fd588a5fbdc5ba1c6b6c06e3daf08ad3d16
7
+ data.tar.gz: 2448123077cea61bf1ab263278ce1a2209d69d9a7ed53d8f665feb8bef2c7185c447378f3c4ae70a96a16ef4d62e4d2a3ffd1769f94bc367e8cd2e0c1733c4cd
@@ -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
- # Base initialization method for a new item. Optionally, allows you to
36
- # provide initial attribute values for the model. You do not need to
37
- # provide all, or even any, attributes at item creation time.
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.
@@ -382,6 +437,77 @@ module Aws
382
437
  attr(name, Marshalers::NumericSetMarshaler.new(opts), opts)
383
438
  end
384
439
 
440
+ # Define an atomic counter attribute for your model.
441
+ #
442
+ # Atomic counter are an integer-type attribute that is incremented,
443
+ # unconditionally, without interfering with other write requests.
444
+ # The numeric value increments each time you call +increment_<attr>!+.
445
+ # If a specific numeric value are passed in the call, the attribute will
446
+ # increment by that value.
447
+ #
448
+ # To use +increment_<attr>!+ method, the following condition must be true:
449
+ # * None of the attributes have dirty changes.
450
+ # * If there is a value passed in, it must be an integer.
451
+ # For more information, see
452
+ # {https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/WorkingWithItems.html#WorkingWithItems.AtomicCounters Atomic counter}
453
+ # in the Amazon DynamoDB Developer Guide.
454
+ #
455
+ # @param [Symbol] name Name of this attribute. It should be a name that
456
+ # is safe to use as a method.
457
+ # @param [Hash] opts
458
+ # @option opts [Object] :default_value Optional attribute used to
459
+ # define a "default value" to be used if the attribute's value on an
460
+ # item is nil or not set at persistence time. The "default value" of
461
+ # the attribute starts at 0.
462
+ #
463
+ # @example Usage Example
464
+ # class MyRecord
465
+ # include Aws::Record
466
+ # integer_attr :id, hash_key: true
467
+ # atomic_counter :counter
468
+ # end
469
+ #
470
+ # record = MyRecord.find(id: 1)
471
+ # record.counter #=> 0
472
+ # record.increment_counter! #=> 1
473
+ # record.increment_counter!(2) #=> 3
474
+ # @see #attr #attr method for additional hash options.
475
+ def atomic_counter(name, opts = {})
476
+ opts[:dynamodb_type] = "N"
477
+ opts[:default_value] ||= 0
478
+ attr(name, Marshalers::IntegerMarshaler.new(opts), opts)
479
+
480
+ define_method("increment_#{name}!") do |increment=1|
481
+
482
+ if dirty?
483
+ msg = "Attributes need to be saved before atomic counter can be incremented"
484
+ raise Errors::RecordError, msg
485
+ end
486
+
487
+ unless increment.is_a?(Integer)
488
+ msg = "expected an Integer value, got #{increment.class}"
489
+ raise ArgumentError, msg
490
+ end
491
+
492
+ resp = dynamodb_client.update_item({
493
+ table_name: self.class.table_name,
494
+ key: key_values,
495
+ expression_attribute_values: {
496
+ ":i" => increment
497
+ },
498
+ expression_attribute_names: {
499
+ "#n" => name
500
+ },
501
+ update_expression: "SET #n = #n + :i",
502
+ return_values: "UPDATED_NEW"
503
+ })
504
+ assign_attributes(resp[:attributes])
505
+ @data.clean!
506
+ @data.get_attribute(name)
507
+ end
508
+
509
+ end
510
+
385
511
  # @return [Symbol,nil] The symbolic name of the table's hash key.
386
512
  def hash_key
387
513
  @keys.hash_key
@@ -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
- @dynamodb_client = _build_client(opts)
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
@@ -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
@@ -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 MyTableTest
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
- if @table_name
89
- @table_name
90
- else
91
- @table_name = self.name.split("::").join("_")
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
- # @example
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 MyTableTest
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
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.7.0
4
+ version: 2.9.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: 2021-10-28 00:00:00.000000000 Z
11
+ date: 2022-11-16 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: aws-sdk-dynamodb
@@ -84,7 +84,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
84
84
  - !ruby/object:Gem::Version
85
85
  version: '0'
86
86
  requirements: []
87
- rubygems_version: 3.2.7
87
+ rubygems_version: 3.3.3
88
88
  signing_key:
89
89
  specification_version: 4
90
90
  summary: AWS Record library for Amazon DynamoDB