aws-sdk-rails 3.6.1 → 3.13.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.
Files changed (30) hide show
  1. checksums.yaml +4 -4
  2. data/VERSION +1 -1
  3. data/bin/aws_sqs_active_job +1 -0
  4. data/lib/action_dispatch/session/dynamodb_store.rb +9 -3
  5. data/lib/active_job/queue_adapters/amazon_sqs_adapter/params.rb +78 -0
  6. data/lib/active_job/queue_adapters/amazon_sqs_adapter.rb +33 -37
  7. data/lib/active_job/queue_adapters/amazon_sqs_async_adapter.rb +12 -11
  8. data/lib/aws/rails/middleware/ebs_sqs_active_job_middleware.rb +31 -5
  9. data/lib/aws/rails/notifications.rb +1 -4
  10. data/lib/aws/rails/railtie.rb +9 -4
  11. data/lib/aws/rails/{mailer.rb → ses_mailer.rb} +12 -10
  12. data/lib/aws/rails/sesv2_mailer.rb +60 -0
  13. data/lib/aws/rails/sqs_active_job/configuration.rb +61 -24
  14. data/lib/aws/rails/sqs_active_job/deduplication.rb +21 -0
  15. data/lib/aws/rails/sqs_active_job/executor.rb +47 -28
  16. data/lib/aws/rails/sqs_active_job/job_runner.rb +5 -1
  17. data/lib/aws/rails/sqs_active_job/lambda_handler.rb +3 -6
  18. data/lib/aws/rails/sqs_active_job/poller.rb +56 -32
  19. data/lib/aws-sdk-rails.rb +4 -1
  20. data/lib/generators/aws_record/base.rb +164 -168
  21. data/lib/generators/aws_record/generated_attribute.rb +50 -41
  22. data/lib/generators/aws_record/model/model_generator.rb +8 -4
  23. data/lib/generators/aws_record/secondary_index.rb +31 -25
  24. data/lib/generators/dynamo_db/session_store_migration/session_store_migration_generator.rb +3 -1
  25. data/lib/tasks/aws_record/migrate.rake +2 -0
  26. data/lib/tasks/dynamo_db/session_store.rake +2 -0
  27. metadata +52 -18
  28. /data/lib/generators/aws_record/model/templates/{model.rb → model.erb} +0 -0
  29. /data/lib/generators/aws_record/model/templates/{table_config.rb → table_config.erb} +0 -0
  30. /data/lib/generators/dynamo_db/session_store_migration/templates/{session_store_migration.rb → session_store_migration.erb} +0 -0
@@ -1,217 +1,213 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'rails/generators'
2
4
  require_relative 'generated_attribute'
3
5
  require_relative 'secondary_index'
4
6
 
5
7
  module AwsRecord
6
- module Generators
7
- class Base < Rails::Generators::NamedBase
8
- argument :attributes, type: :array, default: [], banner: "field[:type][:opts]...", desc: "Describes the fields in the model"
9
- check_class_collision
10
-
11
- class_option :disable_mutation_tracking, type: :boolean, desc: "Disables dirty tracking"
12
- class_option :timestamps, type: :boolean, desc: "Adds created, updated timestamps to the model"
13
- class_option :table_config, type: :hash, default: {}, banner: "primary:R-W [SecondaryIndex1:R-W]...", desc: "Declares the r/w units for the model as well as any secondary indexes", :required => true
14
- class_option :gsi, type: :array, default: [], banner: "name:hkey{field_name}[,rkey{field_name},proj_type{ALL|KEYS_ONLY|INCLUDE}]...", desc: "Allows for the declaration of secondary indexes"
15
- class_option :table_name, type: :string, banner: "model_table_name"
16
- class_option :password_digest, type: :boolean, desc: "Whether to add a password_digest field to the model"
17
-
18
- class_option :required, type: :string, banner: "field1...", desc: "A list of attributes that are required for an instance of the model"
19
- class_option :length_validations, type: :hash, default: {}, banner: "field1:MIN-MAX...", desc: "Validations on the length of attributes in a model"
20
-
21
- attr_accessor :primary_read_units, :primary_write_units, :gsi_rw_units, :gsis, :required_attrs, :length_validations
22
-
23
- private
24
-
25
- def initialize(args, *options)
26
- options[0] << "--skip-table-config" if options[1][:behavior] == :revoke
27
- @parse_errors = []
28
-
29
- super
30
- ensure_unique_fields
31
- ensure_hkey
32
- parse_gsis!
33
- parse_table_config!
34
- parse_validations!
35
-
36
- if !@parse_errors.empty?
37
- STDERR.puts "The following errors were encountered while trying to parse the given attributes"
38
- STDERR.puts
39
- STDERR.puts @parse_errors
40
- STDERR.puts
41
-
42
- abort("Please fix the errors before proceeding.")
43
- end
8
+ module Generators
9
+ class Base < Rails::Generators::NamedBase
10
+ argument :attributes, type: :array, default: [], banner: 'field[:type][:opts]...',
11
+ desc: 'Describes the fields in the model'
12
+ check_class_collision
13
+
14
+ class_option :disable_mutation_tracking, type: :boolean, desc: 'Disables dirty tracking'
15
+ class_option :timestamps, type: :boolean, desc: 'Adds created, updated timestamps to the model'
16
+ class_option :table_config, type: :hash, default: {}, banner: 'primary:R-W [SecondaryIndex1:R-W]...',
17
+ desc: 'Declares the r/w units for the model as well as any secondary indexes', required: true
18
+ class_option :gsi, type: :array, default: [],
19
+ banner: 'name:hkey{field_name}[,rkey{field_name},proj_type{ALL|KEYS_ONLY|INCLUDE}]...', desc: 'Allows for the declaration of secondary indexes'
20
+ class_option :table_name, type: :string, banner: 'model_table_name'
21
+ class_option :password_digest, type: :boolean, desc: 'Whether to add a password_digest field to the model'
22
+
23
+ class_option :required, type: :string, banner: 'field1...',
24
+ desc: 'A list of attributes that are required for an instance of the model'
25
+ class_option :length_validations, type: :hash, default: {}, banner: 'field1:MIN-MAX...',
26
+ desc: 'Validations on the length of attributes in a model'
27
+
28
+ attr_accessor :primary_read_units, :primary_write_units, :gsi_rw_units, :gsis, :required_attrs,
29
+ :length_validations
30
+
31
+ private
32
+
33
+ def initialize(args, *options)
34
+ options[0] << '--skip-table-config' if options[1][:behavior] == :revoke
35
+ @parse_errors = []
36
+
37
+ super
38
+ ensure_unique_fields
39
+ ensure_hkey
40
+ parse_gsis!
41
+ parse_table_config!
42
+ parse_validations!
43
+
44
+ return if @parse_errors.empty?
45
+
46
+ warn 'The following errors were encountered while trying to parse the given attributes'
47
+ $stderr.puts
48
+ warn @parse_errors
49
+ $stderr.puts
50
+
51
+ abort('Please fix the errors before proceeding.')
52
+ end
53
+
54
+ def parse_attributes!
55
+ self.attributes = (attributes || []).map do |attr|
56
+ GeneratedAttribute.parse(attr)
57
+ rescue ArgumentError => e
58
+ @parse_errors << e
59
+ next
44
60
  end
61
+ self.attributes = attributes.compact
45
62
 
46
- def parse_attributes!
63
+ if options['password_digest']
64
+ attributes << GeneratedAttribute.new('password_digest', :string_attr, digest: true)
65
+ end
47
66
 
48
- self.attributes = (attributes || []).map do |attr|
49
- begin
50
- GeneratedAttribute.parse(attr)
51
- rescue ArgumentError => e
52
- @parse_errors << e
53
- next
54
- end
55
- end
56
- self.attributes = self.attributes.compact
67
+ return unless options['timestamps']
57
68
 
58
- if options['password_digest']
59
- self.attributes << GeneratedAttribute.new("password_digest", :string_attr, :digest => true)
60
- end
69
+ attributes << GeneratedAttribute.parse('created:datetime:default_value{Time.now}')
70
+ attributes << GeneratedAttribute.parse('updated:datetime:default_value{Time.now}')
71
+ end
61
72
 
62
- if options['timestamps']
63
- self.attributes << GeneratedAttribute.parse("created:datetime:default_value{Time.now}")
64
- self.attributes << GeneratedAttribute.parse("updated:datetime:default_value{Time.now}")
65
- end
66
- end
73
+ def ensure_unique_fields
74
+ used_names = Set.new
75
+ duplicate_fields = []
67
76
 
68
- def ensure_unique_fields
69
- used_names = Set.new
70
- duplicate_fields = []
77
+ attributes.each do |attr|
78
+ duplicate_fields << [:attribute, attr.name] if used_names.include? attr.name
79
+ used_names.add attr.name
71
80
 
72
- self.attributes.each do |attr|
81
+ next unless attr.options.key? :database_attribute_name
73
82
 
74
- if used_names.include? attr.name
75
- duplicate_fields << [:attribute, attr.name]
76
- end
77
- used_names.add attr.name
83
+ raw_db_attr_name = attr.options[:database_attribute_name].delete('"') # db attribute names are wrapped with " to make template generation easier
78
84
 
79
- if attr.options.key? :database_attribute_name
80
- raw_db_attr_name = attr.options[:database_attribute_name].delete('"') # db attribute names are wrapped with " to make template generation easier
85
+ duplicate_fields << [:database_attribute_name, raw_db_attr_name] if used_names.include? raw_db_attr_name
81
86
 
82
- if used_names.include? raw_db_attr_name
83
- duplicate_fields << [:database_attribute_name, raw_db_attr_name]
84
- end
87
+ used_names.add raw_db_attr_name
88
+ end
85
89
 
86
- used_names.add raw_db_attr_name
87
- end
88
- end
90
+ return if duplicate_fields.empty?
89
91
 
90
- if !duplicate_fields.empty?
91
- duplicate_fields.each do |invalid_attr|
92
- @parse_errors << ArgumentError.new("Found duplicated field name: #{invalid_attr[1]}, in attribute#{invalid_attr[0]}")
93
- end
94
- end
92
+ duplicate_fields.each do |invalid_attr|
93
+ @parse_errors << ArgumentError.new("Found duplicated field name: #{invalid_attr[1]}, in attribute#{invalid_attr[0]}")
95
94
  end
95
+ end
96
96
 
97
- def ensure_hkey
98
- uuid_member = nil
99
- hkey_member = nil
100
- rkey_member = nil
101
-
102
- self.attributes.each do |attr|
103
- if attr.options.key? :hash_key
104
- if hkey_member
105
- @parse_errors << ArgumentError.new("Redefinition of hash_key attr: #{attr.name}, original declaration of hash_key on: #{hkey_member.name}")
106
- next
107
- end
108
-
109
- hkey_member = attr
110
- elsif attr.options.key? :range_key
111
- if rkey_member
112
- @parse_errors << ArgumentError.new("Redefinition of range_key attr: #{attr.name}, original declaration of range_key on: #{hkey_member.name}")
113
- next
114
- end
115
-
116
- rkey_member = attr
117
- end
97
+ def ensure_hkey
98
+ uuid_member = nil
99
+ hkey_member = nil
100
+ rkey_member = nil
118
101
 
119
- if attr.name.include? "uuid"
120
- uuid_member = attr
102
+ attributes.each do |attr|
103
+ if attr.options.key? :hash_key
104
+ if hkey_member
105
+ @parse_errors << ArgumentError.new("Redefinition of hash_key attr: #{attr.name}, original declaration of hash_key on: #{hkey_member.name}")
106
+ next
121
107
  end
122
- end
123
108
 
124
- if !hkey_member
125
- if uuid_member
126
- uuid_member.options[:hash_key] = true
127
- else
128
- self.attributes.unshift GeneratedAttribute.parse("uuid:hkey")
109
+ hkey_member = attr
110
+ elsif attr.options.key? :range_key
111
+ if rkey_member
112
+ @parse_errors << ArgumentError.new("Redefinition of range_key attr: #{attr.name}, original declaration of range_key on: #{hkey_member.name}")
113
+ next
129
114
  end
115
+
116
+ rkey_member = attr
130
117
  end
131
- end
132
118
 
133
- def mutation_tracking_disabled?
134
- options['disable_mutation_tracking']
119
+ uuid_member = attr if attr.name.include? 'uuid'
135
120
  end
136
121
 
137
- def has_validations?
138
- !@required_attrs.empty? || !@length_validations.empty?
122
+ return if hkey_member
123
+
124
+ if uuid_member
125
+ uuid_member.options[:hash_key] = true
126
+ else
127
+ attributes.unshift GeneratedAttribute.parse('uuid:hkey')
139
128
  end
129
+ end
130
+
131
+ def mutation_tracking_disabled?
132
+ options['disable_mutation_tracking']
133
+ end
140
134
 
141
- def parse_table_config!
142
- return unless options['table_config']
135
+ def has_validations?
136
+ !@required_attrs.empty? || !@length_validations.empty?
137
+ end
143
138
 
144
- @primary_read_units, @primary_write_units = parse_rw_units("primary")
139
+ def parse_table_config!
140
+ return unless options['table_config']
145
141
 
146
- @gsi_rw_units = @gsis.map { |idx|
147
- [idx.name, parse_rw_units(idx.name)]
148
- }.to_h
142
+ @primary_read_units, @primary_write_units = parse_rw_units('primary')
149
143
 
150
- options['table_config'].each do |config, rw_units|
151
- if config == "primary"
152
- next
153
- else
154
- gsi = @gsis.select { |idx| idx.name == config}
144
+ @gsi_rw_units = @gsis.map do |idx|
145
+ [idx.name, parse_rw_units(idx.name)]
146
+ end.to_h
155
147
 
156
- if gsi.empty?
157
- @parse_errors << ArgumentError.new("Could not find a gsi declaration for #{config}")
158
- end
159
- end
160
- end
148
+ options['table_config'].each_key do |config|
149
+ next if config == 'primary'
150
+
151
+ gsi = @gsis.select { |idx| idx.name == config }
152
+
153
+ @parse_errors << ArgumentError.new("Could not find a gsi declaration for #{config}") if gsi.empty?
161
154
  end
155
+ end
162
156
 
163
- def parse_rw_units(name)
164
- if !options['table_config'].key? name
165
- @parse_errors << ArgumentError.new("Please provide a table_config definition for #{name}")
166
- else
167
- rw_units = options['table_config'][name]
168
- return rw_units.gsub(/[,.-]/, ':').split(':').reject { |s| s.empty? }
169
- end
157
+ def parse_rw_units(name)
158
+ if options['table_config'].key? name
159
+ rw_units = options['table_config'][name]
160
+ rw_units.gsub(/[,.-]/, ':').split(':').reject(&:empty?)
161
+ else
162
+ @parse_errors << ArgumentError.new("Please provide a table_config definition for #{name}")
170
163
  end
164
+ end
165
+
166
+ def parse_gsis!
167
+ @gsis = (options['gsi'] || []).map do |raw_idx|
168
+ idx = SecondaryIndex.parse(raw_idx)
169
+
170
+ attributes = self.attributes.select { |attr| attr.name == idx.hash_key }
171
+ if attributes.empty?
172
+ @parse_errors << ArgumentError.new("Could not find attribute #{idx.hash_key} for gsi #{idx.name} hkey")
173
+ next
174
+ end
171
175
 
172
- def parse_gsis!
173
- @gsis = (options['gsi'] || []).map do |raw_idx|
174
- begin
175
- idx = SecondaryIndex.parse(raw_idx)
176
-
177
- attributes = self.attributes.select { |attr| attr.name == idx.hash_key}
178
- if attributes.empty?
179
- @parse_errors << ArgumentError.new("Could not find attribute #{idx.hash_key} for gsi #{idx.name} hkey")
180
- next
181
- end
182
-
183
- if idx.range_key
184
- attributes = self.attributes.select { |attr| attr.name == idx.range_key}
185
- if attributes.empty?
186
- @parse_errors << ArgumentError.new("Could not find attribute #{idx.range_key} for gsi #{idx.name} rkey")
187
- next
188
- end
189
- end
190
-
191
- idx
192
- rescue ArgumentError => e
193
- @parse_errors << e
176
+ if idx.range_key
177
+ attributes = self.attributes.select { |attr| attr.name == idx.range_key }
178
+ if attributes.empty?
179
+ @parse_errors << ArgumentError.new("Could not find attribute #{idx.range_key} for gsi #{idx.name} rkey")
194
180
  next
195
181
  end
196
182
  end
197
183
 
198
- @gsis = @gsis.compact
184
+ idx
185
+ rescue ArgumentError => e
186
+ @parse_errors << e
187
+ next
199
188
  end
200
189
 
201
- def parse_validations!
202
- @required_attrs = options['required'] ? options['required'].split(',') : []
203
- @required_attrs.each do |val_attr|
204
- @parse_errors << ArgumentError.new("No such field #{val_attr} in required validations") if !self.attributes.any? { |attr| attr.name == val_attr }
205
- end
190
+ @gsis = @gsis.compact
191
+ end
206
192
 
207
- @length_validations = options['length_validations'].map do |val_attr, bounds|
208
- @parse_errors << ArgumentError.new("No such field #{val_attr} in required validations") if !self.attributes.any? { |attr| attr.name == val_attr }
193
+ def parse_validations!
194
+ @required_attrs = options['required'] ? options['required'].split(',') : []
195
+ @required_attrs.each do |val_attr|
196
+ @parse_errors << ArgumentError.new("No such field #{val_attr} in required validations") if attributes.none? do |attr|
197
+ attr.name == val_attr
198
+ end
199
+ end
209
200
 
210
- bounds = bounds.gsub(/[,.-]/, ':').split(':').reject { |s| s.empty? }
211
- [val_attr, "#{bounds[0]}..#{bounds[1]}"]
212
- end
213
- @length_validations = @length_validations.to_h
201
+ @length_validations = options['length_validations'].map do |val_attr, bounds|
202
+ @parse_errors << ArgumentError.new("No such field #{val_attr} in required validations") if attributes.none? do |attr|
203
+ attr.name == val_attr
204
+ end
205
+
206
+ bounds = bounds.gsub(/[,.-]/, ':').split(':').reject(&:empty?)
207
+ [val_attr, "#{bounds[0]}..#{bounds[1]}"]
214
208
  end
209
+ @length_validations = @length_validations.to_h
215
210
  end
216
211
  end
217
212
  end
213
+ end
@@ -1,28 +1,31 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module AwsRecord
2
4
  module Generators
3
5
  class GeneratedAttribute
4
-
5
- OPTS = %w(hkey rkey persist_nil db_attr_name ddb_type default_value)
6
- INVALID_HKEY_TYPES = %i(map_attr list_attr numeric_set_attr string_set_attr)
6
+ OPTS = %w[hkey rkey persist_nil db_attr_name ddb_type default_value].freeze
7
+ INVALID_HKEY_TYPES = %i[map_attr list_attr numeric_set_attr string_set_attr].freeze
7
8
  attr_reader :name, :type
8
9
  attr_accessor :options
9
10
 
10
11
  def field_type
11
12
  case @type
12
- when :integer_attr then :number_field
13
- when :date_attr then :date_select
14
- when :datetime_attr then :datetime_select
15
- when :boolean_attr then :check_box
16
- else :text_field
13
+ when :integer_attr then :number_field
14
+ when :date_attr then :date_select
15
+ when :datetime_attr then :datetime_select
16
+ when :boolean_attr then :check_box
17
+ else :text_field
17
18
  end
18
19
  end
19
20
 
20
21
  class << self
21
-
22
22
  def parse(field_definition)
23
23
  name, type, opts = field_definition.split(':')
24
- type = "string" if not type
25
- type, opts = "string", type if OPTS.any? { |opt| type.include? opt }
24
+ type ||= 'string'
25
+ if OPTS.any? { |opt| type.include? opt }
26
+ opts = type
27
+ type = 'string'
28
+ end
26
29
 
27
30
  opts = opts.split(',') if opts
28
31
  type, opts = parse_type_and_options(name, type, opts)
@@ -34,65 +37,71 @@ module AwsRecord
34
37
  private
35
38
 
36
39
  def validate_opt_combs(name, type, opts)
37
- if opts
38
- is_hkey = opts.key?(:hash_key)
39
- is_rkey = opts.key?(:range_key)
40
+ return unless opts
41
+
42
+ is_hkey = opts.key?(:hash_key)
43
+ is_rkey = opts.key?(:range_key)
40
44
 
41
- raise ArgumentError.new("Field #{name} cannot be a range key and hash key simultaneously") if is_hkey && is_rkey
42
- raise ArgumentError.new("Field #{name} cannot be a hash key and be of type #{type}") if is_hkey and INVALID_HKEY_TYPES.include? type
45
+ if is_hkey && is_rkey
46
+ raise ArgumentError,
47
+ "Field #{name} cannot be a range key and hash key simultaneously"
43
48
  end
49
+ return unless is_hkey && INVALID_HKEY_TYPES.include?(type)
50
+
51
+ raise ArgumentError,
52
+ "Field #{name} cannot be a hash key and be of type #{type}"
44
53
  end
45
54
 
46
55
  def parse_type_and_options(name, type, opts)
47
- opts = [] if not opts
48
- return parse_type(name, type), opts.map { |opt| parse_option(name, opt) }.to_h
56
+ opts ||= []
57
+ [parse_type(name, type), opts.map { |opt| parse_option(name, opt) }.to_h]
49
58
  end
50
59
 
51
60
  def parse_option(name, opt)
52
61
  case opt
53
62
 
54
- when "hkey"
55
- return :hash_key, true
56
- when "rkey"
57
- return :range_key, true
58
- when "persist_nil"
59
- return :persist_nil, true
63
+ when 'hkey'
64
+ [:hash_key, true]
65
+ when 'rkey'
66
+ [:range_key, true]
67
+ when 'persist_nil'
68
+ [:persist_nil, true]
60
69
  when /db_attr_name\{(\w+)\}/
61
- return :database_attribute_name, '"' + $1 + '"'
70
+ [:database_attribute_name, "\"#{::Regexp.last_match(1)}\""]
62
71
  when /ddb_type\{(S|N|B|BOOL|SS|NS|BS|M|L)\}/i
63
- return :dynamodb_type, '"' + $1.upcase + '"'
72
+ [:dynamodb_type, "\"#{::Regexp.last_match(1).upcase}\""]
64
73
  when /default_value\{(.+)\}/
65
- return :default_value, $1
74
+ [:default_value, ::Regexp.last_match(1)]
66
75
  else
67
- raise ArgumentError.new("You provided an invalid option for #{name}: #{opt}")
76
+ raise ArgumentError, "You provided an invalid option for #{name}: #{opt}"
68
77
  end
69
78
  end
70
79
 
71
80
  def parse_type(name, type)
72
81
  case type.downcase
73
82
 
74
- when "bool", "boolean"
83
+ when 'bool', 'boolean'
75
84
  :boolean_attr
76
- when "date"
85
+ when 'date'
77
86
  :date_attr
78
- when "datetime"
87
+ when 'datetime'
79
88
  :datetime_attr
80
- when "float"
89
+ when 'float'
81
90
  :float_attr
82
- when "int", "integer"
91
+ when 'int', 'integer'
83
92
  :integer_attr
84
- when "list"
93
+ when 'list'
85
94
  :list_attr
86
- when "map"
95
+ when 'map'
87
96
  :map_attr
88
- when "num_set", "numeric_set", "nset"
97
+ when 'num_set', 'numeric_set', 'nset'
89
98
  :numeric_set_attr
90
- when "string_set", "s_set", "sset"
99
+ when 'string_set', 's_set', 'sset'
91
100
  :string_set_attr
92
- when "string"
101
+ when 'string'
93
102
  :string_attr
94
103
  else
95
- raise ArgumentError.new("Invalid type for #{name}: #{type}")
104
+ raise ArgumentError, "Invalid type for #{name}: #{type}"
96
105
  end
97
106
  end
98
107
  end
@@ -114,8 +123,8 @@ module AwsRecord
114
123
  end
115
124
 
116
125
  def column_name
117
- if @name == "password_digest"
118
- "password"
126
+ if @name == 'password_digest'
127
+ 'password'
119
128
  else
120
129
  @name
121
130
  end
@@ -1,21 +1,25 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require_relative '../base'
2
4
 
3
5
  module AwsRecord
4
6
  module Generators
5
7
  class ModelGenerator < Base
6
8
  def initialize(args, *options)
7
- self.class.source_root File.expand_path('../templates', __FILE__)
9
+ self.class.source_root File.expand_path('templates', __dir__)
8
10
  super
9
11
  end
10
12
 
11
13
  def create_model
12
- template "model.rb", File.join("app/models", class_path, "#{file_name}.rb")
14
+ template 'model.erb', File.join('app/models', class_path, "#{file_name}.rb")
13
15
  end
14
16
 
15
17
  def create_table_config
16
- template "table_config.rb", File.join("db/table_config", class_path, "#{file_name}_config.rb") if options["table_config"]
17
- end
18
+ return unless options['table_config']
18
19
 
20
+ template 'table_config.erb',
21
+ File.join('db/table_config', class_path, "#{file_name}_config.rb")
22
+ end
19
23
  end
20
24
  end
21
25
  end
@@ -1,8 +1,9 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module AwsRecord
2
4
  module Generators
3
5
  class SecondaryIndex
4
-
5
- PROJ_TYPES = %w(ALL KEYS_ONLY INCLUDE)
6
+ PROJ_TYPES = %w[ALL KEYS_ONLY INCLUDE].freeze
6
7
  attr_reader :name, :hash_key, :range_key, :projection_type
7
8
 
8
9
  class << self
@@ -15,45 +16,50 @@ module AwsRecord
15
16
  end
16
17
 
17
18
  private
18
- def parse_raw_options(raw_opts)
19
- raw_opts = [] if not raw_opts
20
- raw_opts.map { |opt| get_option_value(opt) }.to_h
21
- end
22
19
 
23
- def get_option_value(raw_option)
24
- case raw_option
25
-
26
- when /hkey\{(\w+)\}/
27
- return :hash_key, $1
28
- when /rkey\{(\w+)\}/
29
- return :range_key, $1
30
- when /proj_type\{(\w+)\}/
31
- return :projection_type, $1
32
- else
33
- raise ArgumentError.new("Invalid option for secondary index #{raw_option}")
34
- end
20
+ def parse_raw_options(raw_opts)
21
+ raw_opts ||= []
22
+ raw_opts.map { |opt| get_option_value(opt) }.to_h
23
+ end
24
+
25
+ def get_option_value(raw_option)
26
+ case raw_option
27
+
28
+ when /hkey\{(\w+)\}/
29
+ [:hash_key, ::Regexp.last_match(1)]
30
+ when /rkey\{(\w+)\}/
31
+ [:range_key, ::Regexp.last_match(1)]
32
+ when /proj_type\{(\w+)\}/
33
+ [:projection_type, ::Regexp.last_match(1)]
34
+ else
35
+ raise ArgumentError, "Invalid option for secondary index #{raw_option}"
35
36
  end
37
+ end
36
38
  end
37
39
 
38
40
  def initialize(name, opts)
39
- raise ArgumentError.new("You must provide a name") if not name
40
- raise ArgumentError.new("You must provide a hash key") if not opts[:hash_key]
41
+ raise ArgumentError, 'You must provide a name' unless name
42
+ raise ArgumentError, 'You must provide a hash key' unless opts[:hash_key]
41
43
 
42
44
  if opts.key? :projection_type
43
- raise ArgumentError.new("Invalid projection type #{opts[:projection_type]}") if not PROJ_TYPES.include? opts[:projection_type]
44
- raise NotImplementedError.new("ALL is the only projection type currently supported") if opts[:projection_type] != "ALL"
45
+ unless PROJ_TYPES.include? opts[:projection_type]
46
+ raise ArgumentError, "Invalid projection type #{opts[:projection_type]}"
47
+ end
48
+ if opts[:projection_type] != 'ALL'
49
+ raise NotImplementedError, 'ALL is the only projection type currently supported'
50
+ end
45
51
  else
46
- opts[:projection_type] = "ALL"
52
+ opts[:projection_type] = 'ALL'
47
53
  end
48
54
 
49
55
  if opts[:hash_key] == opts[:range_key]
50
- raise ArgumentError.new("#{opts[:hash_key]} cannot be both the rkey and hkey for gsi #{name}")
56
+ raise ArgumentError, "#{opts[:hash_key]} cannot be both the rkey and hkey for gsi #{name}"
51
57
  end
52
58
 
53
59
  @name = name
54
60
  @hash_key = opts[:hash_key]
55
61
  @range_key = opts[:range_key]
56
- @projection_type = '"' + "#{opts[:projection_type]}" + '"'
62
+ @projection_type = "\"#{opts[:projection_type]}\""
57
63
  end
58
64
  end
59
65
  end