dynamo-record 0.2.0 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (46) hide show
  1. checksums.yaml +4 -4
  2. data/.dockerignore +15 -0
  3. data/.gitignore +9 -5
  4. data/.rspec +1 -0
  5. data/.rubocop.yml +9 -30
  6. data/.travis.yml +18 -2
  7. data/Dockerfile +22 -0
  8. data/Gemfile +0 -1
  9. data/LICENSE.txt +21 -0
  10. data/README.md +75 -17
  11. data/build.sh +10 -20
  12. data/docker-compose.override.example.yml +19 -0
  13. data/docker-compose.yml +7 -2
  14. data/dynamo-record.gemspec +40 -28
  15. data/lib/dynamo/record.rb +17 -0
  16. data/lib/dynamo/record/marshalers.rb +46 -0
  17. data/lib/dynamo/record/model.rb +127 -0
  18. data/lib/dynamo/record/model_existence_validator.rb +10 -0
  19. data/lib/{dynamo-record → dynamo}/record/railtie.rb +1 -3
  20. data/lib/dynamo/record/table_migration.rb +59 -0
  21. data/lib/dynamo/record/task_helpers/cleanup.rb +21 -0
  22. data/lib/dynamo/record/task_helpers/drop_all_tables.rb +19 -0
  23. data/lib/dynamo/record/task_helpers/drop_table.rb +13 -0
  24. data/lib/dynamo/record/task_helpers/list_tables.rb +15 -0
  25. data/lib/dynamo/record/task_helpers/migration_runner.rb +72 -0
  26. data/lib/dynamo/record/task_helpers/scale.rb +90 -0
  27. data/lib/dynamo/record/version.rb +5 -0
  28. data/lib/tasks/dynamo.rake +7 -7
  29. metadata +96 -37
  30. data/Dockerfile.test +0 -23
  31. data/Gemfile.lock +0 -178
  32. data/doc/testing.md +0 -11
  33. data/docker-compose.dev.override.yml +0 -6
  34. data/lib/dynamo-record.rb +0 -4
  35. data/lib/dynamo-record/marshalers.rb +0 -44
  36. data/lib/dynamo-record/model.rb +0 -127
  37. data/lib/dynamo-record/record.rb +0 -7
  38. data/lib/dynamo-record/record/version.rb +0 -5
  39. data/lib/dynamo-record/table_migration.rb +0 -58
  40. data/lib/dynamo-record/task_helpers/cleanup.rb +0 -19
  41. data/lib/dynamo-record/task_helpers/drop_all_tables.rb +0 -17
  42. data/lib/dynamo-record/task_helpers/drop_table.rb +0 -11
  43. data/lib/dynamo-record/task_helpers/list_tables.rb +0 -13
  44. data/lib/dynamo-record/task_helpers/migration_runner.rb +0 -70
  45. data/lib/dynamo-record/task_helpers/scale.rb +0 -86
  46. data/lib/model_existence_validator.rb +0 -7
@@ -1,19 +0,0 @@
1
- module DynamoRecord
2
- module TaskHelpers
3
- class Cleanup
4
- def self.run
5
- raise 'Task not available on production' if Rails.env.production?
6
- Dir[Rails.root.join('app/models/*.rb').to_s].each do |filename|
7
- delete_by_class(filename)
8
- end
9
- end
10
-
11
- def self.delete_by_class(filename)
12
- klass = File.basename(filename, '.rb').camelize.constantize
13
- return unless klass.included_modules.include? DynamoRecord::Model
14
- Rails.logger.info "Deleting all items in table: #{klass}"
15
- klass.scan.each(&:delete!)
16
- end
17
- end
18
- end
19
- end
@@ -1,17 +0,0 @@
1
- module DynamoRecord
2
- module TaskHelpers
3
- class DropAllTables
4
- def self.run(override = false)
5
- raise 'Task not available on production' if Rails.env.production?
6
- env = Rails.env
7
- dynamodb = Aws::DynamoDB::Client.new
8
- tables = dynamodb.list_tables
9
- tables.table_names.map do |t|
10
- next unless t.include?(env) || override
11
- dt = dynamodb.delete_table(table_name: t)
12
- dt ? "Deleted: #{t}" : "Delete failed: #{t}"
13
- end
14
- end
15
- end
16
- end
17
- end
@@ -1,11 +0,0 @@
1
- module DynamoRecord
2
- module TaskHelpers
3
- class DropTable
4
- def self.run(table_name)
5
- dynamodb = Aws::DynamoDB::Client.new
6
- resp = dynamodb.delete_table(table_name: table_name)
7
- "Deleted: #{resp.table_description.table_name}"
8
- end
9
- end
10
- end
11
- end
@@ -1,13 +0,0 @@
1
- module DynamoRecord
2
- module TaskHelpers
3
- class ListTables
4
- def self.run
5
- dynamodb = Aws::DynamoDB::Client.new
6
- tables = dynamodb.list_tables
7
- tables.table_names.select do |tn|
8
- tn.starts_with?(Rails.configuration.dynamo['prefix'])
9
- end
10
- end
11
- end
12
- end
13
- end
@@ -1,70 +0,0 @@
1
- module DynamoRecord
2
- module TaskHelpers
3
- class MigrationRunner
4
- def self.run(path = 'db/dynamo_migrate')
5
- constants = []
6
- filename_regexp = /\A([0-9]+)_([_a-z0-9]*)\.?([_a-z0-9]*)?\.rb\z/
7
-
8
- # Sorts the files located in `db/dynamo_migrate` to ensure order is preserved
9
- Dir[Rails.root.join("#{path}/*.rb")].sort.each do |f|
10
- migration = migration(f, filename_regexp, constants)
11
-
12
- # starts the migration
13
- yield "Migrating: #{migration}"
14
-
15
- begin
16
- status = table_config_check(migration)
17
- yield status if status
18
-
19
- status = up(migration)
20
- yield status if status
21
-
22
- status = update(migration)
23
- yield status if status
24
- rescue => e
25
- yield "Migration failed: #{e}"
26
- end
27
- end
28
- end
29
-
30
- def self.migration(f, filename_regexp, constants)
31
- raise "Non-numeric prefix: #{f}" if File.basename(f).scan(filename_regexp).first.nil?
32
- require f
33
-
34
- # finds the constant that was added on the require statement above
35
- migration_sym = (DynamoMigrate.constants - constants).first
36
- migration = DynamoMigrate.const_get(migration_sym)
37
- constants.push migration_sym
38
- migration
39
- end
40
-
41
- def self.status_message(status)
42
- case status
43
- when :exists
44
- 'Table already exists'
45
- when :migrated
46
- 'Migration successful'
47
- else
48
- raise 'Migration failed'
49
- end
50
- end
51
-
52
- def self.up(migration)
53
- return unless migration.respond_to? :up
54
- status_message migration.up
55
- end
56
-
57
- def self.table_config_check(migration)
58
- return unless migration.respond_to? :table_config
59
- status_message migration.table_config_check
60
- end
61
-
62
- def self.update(migration)
63
- return unless migration.respond_to? :update
64
- status = migration.update
65
- return 'Migration successful' if status == :updated
66
- status
67
- end
68
- end
69
- end
70
- end
@@ -1,86 +0,0 @@
1
- module DynamoRecord
2
- module TaskHelpers
3
- class Scale
4
- attr_reader :model, :attribute_selector, :new_throughput
5
- attr_reader :migration, :existing_throughput, :model_name
6
-
7
- def initialize(model_name, attribute_selector, new_throughput)
8
- @model_name = model_name
9
- @attribute_selector = attribute_selector
10
- @new_throughput = new_throughput
11
- end
12
-
13
- def run
14
- return description if [model_name, attribute_selector, new_throughput].any?(&:nil?)
15
-
16
- @model = model_name.constantize
17
- @migration = Aws::Record::TableMigration.new(model)
18
- @existing_throughput = model.provisioned_throughput
19
-
20
- update_throughput
21
- success_message
22
- end
23
-
24
- private
25
-
26
- def success_message
27
- "Successfully updated #{model.table_name} throughput to #{update_instructions[:provisioned_throughput]}"
28
- end
29
-
30
- def update_throughput
31
- raise_attribute_error if !read? && !write?
32
-
33
- migration.update!(update_instructions)
34
- end
35
-
36
- def update_instructions
37
- {
38
- provisioned_throughput: {
39
- write_capacity_units: (write? && new_throughput) || existing_write,
40
- read_capacity_units: (read? && new_throughput) || existing_read
41
- }
42
- }
43
- end
44
-
45
- def existing_write
46
- existing_throughput[:write_capacity_units]
47
- end
48
-
49
- def existing_read
50
- existing_throughput[:read_capacity_units]
51
- end
52
-
53
- def both?
54
- attribute_selector.to_sym == :both
55
- end
56
-
57
- def read?
58
- both? || attribute_selector.to_sym == :read
59
- end
60
-
61
- def write?
62
- both? || attribute_selector.to_sym == :write
63
- end
64
-
65
- def raise_attribute_error
66
- raise ArgumentError, 'You didn\'t provide an appropriate attribute selection. We accept [:both, :read, :write]'
67
- end
68
-
69
- def description
70
- <<~DESCRIPTION
71
- --------------------------------------------------------------------------------
72
- Here's some usage information:
73
- Scale a dynamo table. Requires three inputs.
74
- - ModelName
75
- ruby class of the model
76
- - attribute
77
- valid values include "both", "read" and "write"
78
- - new_throughput
79
- numerical value for the new read/write capacity units
80
- Example: `rake dynamo:scale[MySuperDynamoModel,both,50]`
81
- --------------------------------------------------------------------------------
82
- DESCRIPTION
83
- end
84
- end
85
- end
86
- end
@@ -1,7 +0,0 @@
1
- require 'active_model'
2
- class ModelExistenceValidator < ActiveModel::EachValidator
3
- def validate_each(record, attribute, value)
4
- return if options[:model].exists? value
5
- record.errors[attribute] << (options[:message] || "#{attribute}:#{value} is not a valid #{options[:model]}")
6
- end
7
- end