aws-sdk-rails 3.6.1 → 3.13.0

Sign up to get free protection for your applications and to get access to all the features.
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