aws-sdk-rails 2.1.0 → 3.4.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (29) hide show
  1. checksums.yaml +4 -4
  2. data/VERSION +1 -0
  3. data/bin/aws_sqs_active_job +5 -0
  4. data/lib/action_dispatch/session/dynamodb_store.rb +32 -0
  5. data/lib/active_job/queue_adapters/amazon_sqs_adapter.rb +49 -0
  6. data/lib/active_job/queue_adapters/amazon_sqs_async_adapter.rb +32 -0
  7. data/lib/aws-sdk-rails.rb +15 -31
  8. data/lib/aws/rails/mailer.rb +7 -8
  9. data/lib/aws/rails/notifications.rb +33 -0
  10. data/lib/aws/rails/railtie.rb +68 -0
  11. data/lib/aws/rails/sqs_active_job/configuration.rb +152 -0
  12. data/lib/aws/rails/sqs_active_job/executor.rb +58 -0
  13. data/lib/aws/rails/sqs_active_job/job_runner.rb +22 -0
  14. data/lib/aws/rails/sqs_active_job/lambda_handler.rb +66 -0
  15. data/lib/aws/rails/sqs_active_job/poller.rb +126 -0
  16. data/lib/generators/aws_record/base.rb +217 -0
  17. data/lib/generators/aws_record/generated_attribute.rb +129 -0
  18. data/lib/generators/aws_record/model/USAGE +24 -0
  19. data/lib/generators/aws_record/model/model_generator.rb +21 -0
  20. data/lib/generators/aws_record/model/templates/model.rb +48 -0
  21. data/lib/generators/aws_record/model/templates/table_config.rb +18 -0
  22. data/lib/generators/aws_record/secondary_index.rb +60 -0
  23. data/lib/generators/dynamo_db/session_store_migration/USAGE +13 -0
  24. data/lib/generators/dynamo_db/session_store_migration/session_store_migration_generator.rb +46 -0
  25. data/lib/generators/dynamo_db/session_store_migration/templates/dynamo_db_session_store.yml +70 -0
  26. data/lib/generators/dynamo_db/session_store_migration/templates/session_store_migration.rb +9 -0
  27. data/lib/tasks/aws_record/migrate.rake +12 -0
  28. data/lib/tasks/dynamo_db/session_store.rake +8 -0
  29. metadata +110 -14
@@ -0,0 +1,129 @@
1
+ module AwsRecord
2
+ module Generators
3
+ 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)
7
+ attr_reader :name, :type
8
+ attr_accessor :options
9
+
10
+ def field_type
11
+ 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
17
+ end
18
+ end
19
+
20
+ class << self
21
+
22
+ def parse(field_definition)
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 }
26
+
27
+ opts = opts.split(',') if opts
28
+ type, opts = parse_type_and_options(name, type, opts)
29
+ validate_opt_combs(name, type, opts)
30
+
31
+ new(name, type, opts)
32
+ end
33
+
34
+ private
35
+
36
+ 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
+
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
43
+ end
44
+ end
45
+
46
+ 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
49
+ end
50
+
51
+ def parse_option(name, opt)
52
+ case opt
53
+
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
60
+ when /db_attr_name\{(\w+)\}/
61
+ return :database_attribute_name, '"' + $1 + '"'
62
+ when /ddb_type\{(S|N|B|BOOL|SS|NS|BS|M|L)\}/i
63
+ return :dynamodb_type, '"' + $1.upcase + '"'
64
+ when /default_value\{(.+)\}/
65
+ return :default_value, $1
66
+ else
67
+ raise ArgumentError.new("You provided an invalid option for #{name}: #{opt}")
68
+ end
69
+ end
70
+
71
+ def parse_type(name, type)
72
+ case type.downcase
73
+
74
+ when "bool", "boolean"
75
+ :boolean_attr
76
+ when "date"
77
+ :date_attr
78
+ when "datetime"
79
+ :datetime_attr
80
+ when "float"
81
+ :float_attr
82
+ when "int", "integer"
83
+ :integer_attr
84
+ when "list"
85
+ :list_attr
86
+ when "map"
87
+ :map_attr
88
+ when "num_set", "numeric_set", "nset"
89
+ :numeric_set_attr
90
+ when "string_set", "s_set", "sset"
91
+ :string_set_attr
92
+ when "string"
93
+ :string_attr
94
+ else
95
+ raise ArgumentError.new("Invalid type for #{name}: #{type}")
96
+ end
97
+ end
98
+ end
99
+
100
+ def initialize(name, type = :string_attr, options = {})
101
+ @name = name
102
+ @type = type
103
+ @options = options
104
+ @digest = options.delete(:digest)
105
+ end
106
+
107
+ # Methods used by rails scaffolding
108
+ def password_digest?
109
+ @digest
110
+ end
111
+
112
+ def polymorphic?
113
+ false
114
+ end
115
+
116
+ def column_name
117
+ if @name == "password_digest"
118
+ "password"
119
+ else
120
+ @name
121
+ end
122
+ end
123
+
124
+ def human_name
125
+ name.humanize
126
+ end
127
+ end
128
+ end
129
+ end
@@ -0,0 +1,24 @@
1
+ Description:
2
+ rails generator for aws-record models
3
+
4
+ Pass the name of the model (preferably in singular form), and an optional list of attributes
5
+
6
+ Attributes are declarations of the fields that you wish to store within a model. You can pass
7
+ a type and list of options for each attribtue in the form: `name:type:options` if you do not provide
8
+ a type, it is assumed that the attribute is of type `string_attr`
9
+
10
+ Each model should have an hkey, if one is not present a `uuid:hkey` will be created for you.
11
+
12
+ Timestamps are not added by default but you can add them using the `--timestamps` flag
13
+ More information can be found at: https://github.com/awslabs/aws-record-generator/blob/master/README.md
14
+
15
+ You don't have to think up every attribute up front, but it helps to
16
+ sketch out a few so you can start working with the resource immediately.
17
+
18
+ Example:
19
+ rails generate aws_record:model Forum forum_uuid:hkey post_id:rkey post_title post_body tags:sset:default_value{Set.new} created_at:datetime:d_attr_name{PostCreatedAtTime} moderation:boolean:default_value{false}
20
+
21
+ This will create:
22
+ app/models/forum.rb
23
+ db/table_config/forum_config.rb
24
+ lib/tasks/table_config_migrate_task.rake # This is created once the first time the generator is run
@@ -0,0 +1,21 @@
1
+ require_relative '../base'
2
+
3
+ module AwsRecord
4
+ module Generators
5
+ class ModelGenerator < Base
6
+ def initialize(args, *options)
7
+ self.class.source_root File.expand_path('../templates', __FILE__)
8
+ super
9
+ end
10
+
11
+ def create_model
12
+ template "model.rb", File.join("app/models", class_path, "#{file_name}.rb")
13
+ end
14
+
15
+ 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
+
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,48 @@
1
+ require 'aws-record'
2
+ <% if has_validations? -%>
3
+ require 'active_model'
4
+ <% end -%>
5
+
6
+ <% module_namespacing do -%>
7
+ class <%= class_name %>
8
+ include Aws::Record
9
+ <% if options.key? :scaffold -%>
10
+ extend ActiveModel::Naming
11
+ <% end -%>
12
+ <% if has_validations? -%>
13
+ include ActiveModel::Validations
14
+ <% end -%>
15
+ <% if options.key? :password_digest -%>
16
+ include ActiveModel::SecurePassword
17
+ <% end -%>
18
+ <% if mutation_tracking_disabled? -%>
19
+ disable_mutation_tracking
20
+ <% end -%>
21
+
22
+ <% attributes.each do |attribute| -%>
23
+ <%= attribute.type %> :<%= attribute.name %><% *opts, last_opt = attribute.options.to_a %><%= ', ' if last_opt %><% opts.each do |opt| %><%= opt[0] %>: <%= opt[1] %>, <% end %><% if last_opt %><%= last_opt[0] %>: <%= last_opt[1] %><% end %>
24
+ <% end -%>
25
+ <% gsis.each do |index| %>
26
+ global_secondary_index(
27
+ :<%= index.name %>,
28
+ hash_key: :<%= index.hash_key -%>,<%- if index.range_key %>
29
+ range_key: :<%= index.range_key -%>,<%- end %>
30
+ projection: {
31
+ projection_type: <%= index.projection_type %>
32
+ }
33
+ )
34
+ <% end -%>
35
+ <% if !required_attrs.empty? -%>
36
+ validates_presence_of <% *req, last_req = required_attrs -%><% req.each do |required_validation|-%>:<%= required_validation %>, <% end -%>:<%= last_req %>
37
+ <% end -%>
38
+ <% length_validations.each do |attribute, validation| -%>
39
+ validates_length_of :<%= attribute %>, within: <%= validation %>
40
+ <% end -%>
41
+ <% if options['table_name'] -%>
42
+ set_table_name "<%= options['table_name'] %>"
43
+ <% end -%>
44
+ <% if options.key? :password_digest -%>
45
+ has_secure_password
46
+ <% end -%>
47
+ end
48
+ <% end -%>
@@ -0,0 +1,18 @@
1
+ require 'aws-record'
2
+
3
+ module ModelTableConfig
4
+ def self.config
5
+ Aws::Record::TableConfig.define do |t|
6
+ t.model_class <%= class_name %>
7
+
8
+ t.read_capacity_units <%= primary_read_units %>
9
+ t.write_capacity_units <%= primary_write_units %>
10
+ <%- gsis.each do |index| %>
11
+ t.global_secondary_index(:<%= index.name %>) do |i|
12
+ i.read_capacity_units <%= gsi_rw_units[index.name][0] %>
13
+ i.write_capacity_units <%= gsi_rw_units[index.name][1] %>
14
+ end
15
+ <%- end -%>
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,60 @@
1
+ module AwsRecord
2
+ module Generators
3
+ class SecondaryIndex
4
+
5
+ PROJ_TYPES = %w(ALL KEYS_ONLY INCLUDE)
6
+ attr_reader :name, :hash_key, :range_key, :projection_type
7
+
8
+ class << self
9
+ def parse(key_definition)
10
+ name, index_options = key_definition.split(':')
11
+ index_options = index_options.split(',') if index_options
12
+ opts = parse_raw_options(index_options)
13
+
14
+ new(name, opts)
15
+ end
16
+
17
+ 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
+
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
35
+ end
36
+ end
37
+
38
+ 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
+
42
+ 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
+ else
46
+ opts[:projection_type] = "ALL"
47
+ end
48
+
49
+ if opts[:hash_key] == opts[:range_key]
50
+ raise ArgumentError.new("#{opts[:hash_key]} cannot be both the rkey and hkey for gsi #{name}")
51
+ end
52
+
53
+ @name = name
54
+ @hash_key = opts[:hash_key]
55
+ @range_key = opts[:range_key]
56
+ @projection_type = '"' + "#{opts[:projection_type]}" + '"'
57
+ end
58
+ end
59
+ end
60
+ end
@@ -0,0 +1,13 @@
1
+ Description:
2
+ Generates a migration file for deleting and a creating a DynamoDB
3
+ sessions table, and a configuration file for the session store.
4
+
5
+ Example:
6
+ rails generate dynamo_db:session_store_migration <MIGRATION_NAME>
7
+
8
+ This will create:
9
+ db/migrate/#{VERSION}_#{MIGRATION_NAME}.rb
10
+ config/dynamo_db_session_store.yml
11
+
12
+ The migration will be run when the command rake db:migrate is run
13
+ in the command line.
@@ -0,0 +1,46 @@
1
+ require 'rails/generators/named_base'
2
+
3
+ # This class generates a migration file for deleting and creating
4
+ # a DynamoDB sessions table.
5
+ module DynamoDb
6
+ module Generators
7
+ # Generates an ActiveRecord migration that creates and deletes a DynamoDB
8
+ # Session table.
9
+ class SessionStoreMigrationGenerator < Rails::Generators::NamedBase
10
+ include Rails::Generators::Migration
11
+
12
+ source_root File.expand_path('templates', __dir__)
13
+
14
+ # Desired name of migration class
15
+ argument :name, type: :string, default: 'create_dynamo_db_sessions_table'
16
+
17
+ # @return [Rails Migration File] migration file for creation and deletion
18
+ # of a DynamoDB session table.
19
+ def generate_migration_file
20
+ migration_template(
21
+ 'session_store_migration.rb',
22
+ "db/migrate/#{name.underscore}.rb"
23
+ )
24
+ end
25
+
26
+ def copy_sample_config_file
27
+ template(
28
+ 'dynamo_db_session_store.yml',
29
+ 'config/dynamo_db_session_store.yml'
30
+ )
31
+ end
32
+
33
+ # Next migration number - must be implemented
34
+ def self.next_migration_number(_dir = nil)
35
+ Time.now.utc.strftime('%Y%m%d%H%M%S')
36
+ end
37
+
38
+ private
39
+
40
+ # @return [String] activerecord migration version
41
+ def migration_version
42
+ "#{Rails::VERSION::MAJOR}.#{Rails::VERSION::MINOR}"
43
+ end
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,70 @@
1
+ # Uncomment and manipulate the key value pairs below
2
+ # in order to configure the DynamoDB Session Store Application.
3
+
4
+ # [String] The secret key for HMAC encryption. This defaults to
5
+ # `Rails.application.secret_key_base`. You can use a different key if desired.
6
+ #
7
+ # secret_key: SECRET_KEY
8
+
9
+ # [String] Session table name.
10
+ #
11
+ # table_name: Sessions
12
+
13
+ # [String] Session table hash key name.
14
+ #
15
+ # table_key: session_id
16
+
17
+ # [Boolean] Define as true or false depending on if you want a strongly
18
+ # consistent read.
19
+ # See AWS DynamoDB documentation for table consistent_read for more
20
+ # information on this setting.
21
+ #
22
+ # consistent_read: true
23
+
24
+ # [Integer] Maximum number of reads consumed per second before
25
+ # DynamoDB returns a ThrottlingException. See AWS DynamoDB documentation
26
+ # or table read_capacity for more information on this setting.
27
+ #
28
+ # read_capacity: 10
29
+
30
+ # [Integer] Maximum number of writes consumed per second before
31
+ # DynamoDB returns a ThrottlingException. See AWS DynamoDB documentation
32
+ # or table write_capacity for more information on this setting.
33
+ #
34
+ # write_capacity: 5
35
+
36
+ # [Boolean] Define as true or false depending on whether you want all errors to be
37
+ # raised up the stack.
38
+ #
39
+ # raise_errors: false
40
+
41
+ # [Integer] Maximum number of seconds earlier
42
+ # from the current time that a session was created.
43
+ # By default this is 7 days.
44
+ #
45
+ # max_age: 604800
46
+
47
+ # [Integer] Maximum number of seconds
48
+ # before the current time that the session was last accessed.
49
+ # By default this is 5 hours.
50
+ #
51
+ # max_stale: 18000
52
+
53
+ # [Boolean] Define as true or false for whether you want to enable locking
54
+ # for all accesses to session data.
55
+ #
56
+ # enable_locking: false
57
+
58
+ # [Integer] Time in milleseconds after which lock will expire.
59
+ #
60
+ # lock_expiry_time: 500
61
+
62
+ # [Integer] Time in milleseconds to wait before retrying to obtain
63
+ # lock once an attempt to obtain lock has been made and has failed.
64
+ #
65
+ # lock_retry_delay: 500
66
+
67
+ # [Integer] Maximum time in seconds to wait to acquire lock
68
+ # before giving up.
69
+ #
70
+ # lock_max_wait_time: 1
@@ -0,0 +1,9 @@
1
+ class <%= name.camelize %> < ActiveRecord::Migration[<%= migration_version %>]
2
+ def up
3
+ Aws::SessionStore::DynamoDB::Table.create_table
4
+ end
5
+
6
+ def down
7
+ Aws::SessionStore::DynamoDB::Table.delete_table
8
+ end
9
+ end