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,23 +0,0 @@
1
- FROM instructure/ruby:2.3
2
-
3
- ENV APP_HOME "/usr/src/app/"
4
-
5
- USER root
6
-
7
- COPY dynamo-record.gemspec Gemfile Gemfile.lock $APP_HOME
8
- RUN mkdir -p $APP_HOME/lib/dynamo-record/record
9
- COPY lib/dynamo-record/record/version.rb $APP_HOME/lib/dynamo-record/record
10
- RUN chown -R docker:docker $APP_HOME
11
-
12
- USER docker
13
- RUN gem install bundler
14
- RUN bundle install --quiet --jobs 8
15
- USER root
16
-
17
- COPY . $APP_HOME
18
- RUN mkdir -p $APP_HOME/coverage && \
19
- mkdir -p $APP_HOME/spec/internal/log && \
20
- chown -R docker:docker $APP_HOME
21
- USER docker
22
-
23
- CMD ["bundle", "exec", "rspec"]
@@ -1,178 +0,0 @@
1
- PATH
2
- remote: .
3
- specs:
4
- dynamo-record (0.1.3)
5
- aws-record (~> 1.1)
6
- rails (~> 4.2)
7
-
8
- GEM
9
- remote: https://rubygems.org/
10
- specs:
11
- actionmailer (4.2.8)
12
- actionpack (= 4.2.8)
13
- actionview (= 4.2.8)
14
- activejob (= 4.2.8)
15
- mail (~> 2.5, >= 2.5.4)
16
- rails-dom-testing (~> 1.0, >= 1.0.5)
17
- actionpack (4.2.8)
18
- actionview (= 4.2.8)
19
- activesupport (= 4.2.8)
20
- rack (~> 1.6)
21
- rack-test (~> 0.6.2)
22
- rails-dom-testing (~> 1.0, >= 1.0.5)
23
- rails-html-sanitizer (~> 1.0, >= 1.0.2)
24
- actionview (4.2.8)
25
- activesupport (= 4.2.8)
26
- builder (~> 3.1)
27
- erubis (~> 2.7.0)
28
- rails-dom-testing (~> 1.0, >= 1.0.5)
29
- rails-html-sanitizer (~> 1.0, >= 1.0.3)
30
- activejob (4.2.8)
31
- activesupport (= 4.2.8)
32
- globalid (>= 0.3.0)
33
- activemodel (4.2.8)
34
- activesupport (= 4.2.8)
35
- builder (~> 3.1)
36
- activerecord (4.2.8)
37
- activemodel (= 4.2.8)
38
- activesupport (= 4.2.8)
39
- arel (~> 6.0)
40
- activesupport (4.2.8)
41
- i18n (~> 0.7)
42
- minitest (~> 5.1)
43
- thread_safe (~> 0.3, >= 0.3.4)
44
- tzinfo (~> 1.1)
45
- addressable (2.5.1)
46
- public_suffix (~> 2.0, >= 2.0.2)
47
- arel (6.0.4)
48
- ast (2.3.0)
49
- aws-record (1.1.0)
50
- aws-sdk-resources (~> 2.0)
51
- aws-sdk-core (2.9.14)
52
- aws-sigv4 (~> 1.0)
53
- jmespath (~> 1.0)
54
- aws-sdk-resources (2.9.14)
55
- aws-sdk-core (= 2.9.14)
56
- aws-sigv4 (1.0.0)
57
- builder (3.2.3)
58
- byebug (9.0.6)
59
- combustion (0.6.0)
60
- activesupport (>= 3.0.0)
61
- railties (>= 3.0.0)
62
- thor (>= 0.14.6)
63
- concurrent-ruby (1.0.5)
64
- crack (0.4.3)
65
- safe_yaml (~> 1.0.0)
66
- diff-lcs (1.3)
67
- docile (1.1.5)
68
- erubis (2.7.0)
69
- globalid (0.4.0)
70
- activesupport (>= 4.2.0)
71
- hashdiff (0.3.2)
72
- i18n (0.8.1)
73
- jmespath (1.3.1)
74
- json (2.1.0)
75
- loofah (2.0.3)
76
- nokogiri (>= 1.5.9)
77
- mail (2.6.5)
78
- mime-types (>= 1.16, < 4)
79
- mime-types (3.1)
80
- mime-types-data (~> 3.2015)
81
- mime-types-data (3.2016.0521)
82
- mini_portile2 (2.1.0)
83
- minitest (5.10.1)
84
- nokogiri (1.7.1)
85
- mini_portile2 (~> 2.1.0)
86
- parser (2.4.0.0)
87
- ast (~> 2.2)
88
- powerpack (0.1.1)
89
- public_suffix (2.0.5)
90
- rack (1.6.5)
91
- rack-test (0.6.3)
92
- rack (>= 1.0)
93
- rails (4.2.8)
94
- actionmailer (= 4.2.8)
95
- actionpack (= 4.2.8)
96
- actionview (= 4.2.8)
97
- activejob (= 4.2.8)
98
- activemodel (= 4.2.8)
99
- activerecord (= 4.2.8)
100
- activesupport (= 4.2.8)
101
- bundler (>= 1.3.0, < 2.0)
102
- railties (= 4.2.8)
103
- sprockets-rails
104
- rails-deprecated_sanitizer (1.0.3)
105
- activesupport (>= 4.2.0.alpha)
106
- rails-dom-testing (1.0.8)
107
- activesupport (>= 4.2.0.beta, < 5.0)
108
- nokogiri (~> 1.6)
109
- rails-deprecated_sanitizer (>= 1.0.1)
110
- rails-html-sanitizer (1.0.3)
111
- loofah (~> 2.0)
112
- railties (4.2.8)
113
- actionpack (= 4.2.8)
114
- activesupport (= 4.2.8)
115
- rake (>= 0.8.7)
116
- thor (>= 0.18.1, < 2.0)
117
- rainbow (2.2.2)
118
- rake
119
- rake (10.5.0)
120
- rspec (3.5.0)
121
- rspec-core (~> 3.5.0)
122
- rspec-expectations (~> 3.5.0)
123
- rspec-mocks (~> 3.5.0)
124
- rspec-core (3.5.4)
125
- rspec-support (~> 3.5.0)
126
- rspec-expectations (3.5.0)
127
- diff-lcs (>= 1.2.0, < 2.0)
128
- rspec-support (~> 3.5.0)
129
- rspec-mocks (3.5.0)
130
- diff-lcs (>= 1.2.0, < 2.0)
131
- rspec-support (~> 3.5.0)
132
- rspec-support (3.5.0)
133
- rubocop (0.44.1)
134
- parser (>= 2.3.1.1, < 3.0)
135
- powerpack (~> 0.1)
136
- rainbow (>= 1.99.1, < 3.0)
137
- ruby-progressbar (~> 1.7)
138
- unicode-display_width (~> 1.0, >= 1.0.1)
139
- ruby-progressbar (1.8.1)
140
- safe_yaml (1.0.4)
141
- simplecov (0.14.1)
142
- docile (~> 1.1.0)
143
- json (>= 1.8, < 3)
144
- simplecov-html (~> 0.10.0)
145
- simplecov-html (0.10.0)
146
- sprockets (3.7.1)
147
- concurrent-ruby (~> 1.0)
148
- rack (> 1, < 3)
149
- sprockets-rails (3.2.0)
150
- actionpack (>= 4.0)
151
- activesupport (>= 4.0)
152
- sprockets (>= 3.0.0)
153
- thor (0.19.4)
154
- thread_safe (0.3.6)
155
- tzinfo (1.2.3)
156
- thread_safe (~> 0.1)
157
- unicode-display_width (1.2.1)
158
- webmock (2.3.2)
159
- addressable (>= 2.3.6)
160
- crack (>= 0.3.2)
161
- hashdiff
162
-
163
- PLATFORMS
164
- ruby
165
-
166
- DEPENDENCIES
167
- bundler (~> 1.14)
168
- byebug (~> 9.0)
169
- combustion (~> 0.6.0)
170
- dynamo-record!
171
- rake (~> 10.0)
172
- rspec (~> 3.0)
173
- rubocop (~> 0.44.1)
174
- simplecov (~> 0.12)
175
- webmock (~> 2.1)
176
-
177
- BUNDLED WITH
178
- 1.14.6
@@ -1,11 +0,0 @@
1
- # Testing
2
-
3
- Run rspec in the `test` container:
4
-
5
- `docker-compose run --rm test bundle exec rspec`
6
-
7
- ## Static Code Analysis
8
-
9
- Run RuboCop static code analysis in the `test` container:
10
-
11
- `docker-compose run --rm test bundle exec rubocop`
@@ -1,6 +0,0 @@
1
- version: '2'
2
-
3
- services:
4
- test:
5
- volumes:
6
- - .:/usr/src/app
@@ -1,4 +0,0 @@
1
- Gem.find_files("#{File.dirname(__FILE__)}/dynamo-record/**/*.rb").each do |path|
2
- require path.gsub(/\.rb$/, '')
3
- end
4
- require 'model_existence_validator'
@@ -1,44 +0,0 @@
1
- module DynamoRecord
2
- module Marshalers
3
- COMPOSITE_DELIMETER = '|'.freeze
4
-
5
- def self.included(sub_class)
6
- sub_class.extend(ClassMethods)
7
- super(sub_class)
8
- end
9
-
10
- module ClassMethods
11
- def composite_integer_attr(name, opts = {})
12
- composite_attr(name, opts)
13
- define_readers(name, opts[:parts], :to_i) if opts.key? :parts
14
- end
15
-
16
- def composite_string_attr(name, opts = {})
17
- composite_attr(name, opts)
18
- define_readers(name, opts[:parts], :to_s) if opts.key? :parts
19
- end
20
-
21
- private
22
-
23
- def composite_attr(name, opts = {})
24
- opts[:dynamodb_type] = 'S'
25
-
26
- # It is very unfortunate that Aws::Record used `attr`
27
- # rubocop:disable Style/Attr
28
- attr(name, Aws::Record::Marshalers::StringMarshaler.new(opts), opts)
29
- # rubocop:enable Style/Attr
30
- end
31
-
32
- def define_readers(name, parts, cast_function)
33
- parts.each_with_index do |part, i|
34
- raise "#{part} already defined" unless parts.find_index(part) == i
35
- next if method_defined?(part)
36
- define_method(part) do
37
- # @data is used internally by Aws::Record to store all of the attributes
38
- @data.get_attribute(name).split(COMPOSITE_DELIMETER)[i].send(cast_function)
39
- end
40
- end
41
- end
42
- end
43
- end
44
- end
@@ -1,127 +0,0 @@
1
- require 'aws-record'
2
-
3
- module DynamoRecord
4
- module Model
5
- COMPOSITE_DELIMITER = '|'.freeze
6
-
7
- def self.included(klass)
8
- klass.include(Aws::Record)
9
- klass.include(DynamoRecord::Marshalers)
10
-
11
- klass.extend ClassMethods
12
- klass.send :prepend, InstanceMethods
13
- end
14
-
15
- module ClassMethods
16
- def table_name
17
- [Rails.configuration.dynamo['prefix'], name.tableize].join('-').tr('/', '.')
18
- end
19
-
20
- def scan
21
- raise 'no scanning in production' if Rails.env.production?
22
- super
23
- end
24
-
25
- def find(opts)
26
- super(opts).tap do |record|
27
- unless record
28
- name = self.name.demodulize
29
- conditions = opts.map { |k, v| "#{k}=#{v}" }.join(', ')
30
- error = "Couldn't find #{name} with #{conditions}"
31
- raise Aws::Record::Errors::NotFound, error
32
- end
33
- end
34
- end
35
-
36
- def find_all_by_hash_key(hash_key_value, opts = {})
37
- find_all_by_index_and_hash_key(hash_key, hash_key_value, opts)
38
- end
39
-
40
- def find_all_by_gsi_hash_key(gsi_name, hash_key_value, opts = {})
41
- hash_key_name = global_secondary_indexes[gsi_name.to_sym][:hash_key]
42
- find_all_by_index_and_hash_key(hash_key_name, hash_key_value, opts, gsi_name.to_s)
43
- end
44
-
45
- def find_all_by_gsi_hash_and_range_keys(gsi_name, hash_key_value, range_key_value)
46
- gsi_config = global_secondary_indexes[gsi_name.to_sym]
47
- find_all_by_index_hash_and_range_keys(
48
- hash_config: { name: gsi_config[:hash_key], value: hash_key_value },
49
- range_config: { name: gsi_config[:range_key], value: range_key_value },
50
- index_name: gsi_name.to_s
51
- )
52
- end
53
-
54
- def find_all_by_lsi_hash_key(lsi_name, hash_key_value, opts = {})
55
- hash_key_name = local_secondary_indexes[lsi_name.to_sym][:hash_key]
56
- find_all_by_index_and_hash_key(hash_key_name, hash_key_value, opts, lsi_name.to_s)
57
- end
58
-
59
- def find_all_by_lsi_hash_and_range_keys(lsi_name, hash_key_value, range_key_value)
60
- lsi_config = local_secondary_indexes[lsi_name.to_sym]
61
- find_all_by_index_hash_and_range_keys(
62
- hash_config: { name: lsi_config[:hash_key], value: hash_key_value },
63
- range_config: { name: lsi_config[:range_key], value: range_key_value },
64
- index_name: lsi_name.to_s
65
- )
66
- end
67
-
68
- def find_all_by_index_and_hash_key(hash_key_name, hash_key_value, opts = {}, index_name = nil)
69
- query_options = {
70
- select: 'ALL_ATTRIBUTES',
71
- key_condition_expression: "#{hash_key_name} = :hash_key_value",
72
- expression_attribute_values: {
73
- ':hash_key_value': hash_key_value
74
- },
75
- scan_index_forward: true
76
- }
77
- query_options[:index_name] = index_name if index_name
78
- query_options.merge!(opts)
79
- query(query_options)
80
- end
81
-
82
- def find_all_by_index_hash_and_range_keys(hash_config:, range_config:, index_name: nil,
83
- scan_index_forward: true, limit: nil)
84
- range_expression = range_config[:expression] || "#{range_config[:name]} = :rkv"
85
- query_options = {
86
- select: 'ALL_ATTRIBUTES',
87
- key_condition_expression: "#{hash_config[:name]} = :hkv AND #{range_expression}",
88
- expression_attribute_values: {
89
- ':hkv': hash_config[:value],
90
- ':rkv': range_config[:value]
91
- },
92
- scan_index_forward: scan_index_forward,
93
- limit: limit
94
- }
95
- query_options[:index_name] = index_name if index_name
96
- query(query_options)
97
- end
98
-
99
- def composite_key(*args)
100
- args.join(COMPOSITE_DELIMITER)
101
- end
102
-
103
- def split_composite(string)
104
- string.split(COMPOSITE_DELIMITER)
105
- end
106
-
107
- # TODO: Create a batch save method.
108
- end
109
-
110
- module InstanceMethods
111
- def read_attribute_for_serialization(attribute)
112
- send(attribute)
113
- end
114
-
115
- def attribute_hash
116
- attrs = self.class.attributes.attributes
117
- attr_keys = attrs.keys
118
- hash = {}
119
-
120
- attr_keys.each do |key|
121
- hash[key] = attrs[key].type_cast(send(key))
122
- end
123
- hash
124
- end
125
- end
126
- end
127
- end
@@ -1,7 +0,0 @@
1
- require 'dynamo-record/record/version'
2
-
3
- module DynamoRecord
4
- module Record
5
- require 'dynamo-record/record/railtie' if defined? Rails
6
- end
7
- end
@@ -1,5 +0,0 @@
1
- module DynamoRecord
2
- module Record
3
- VERSION = '0.2.0'.freeze
4
- end
5
- end
@@ -1,58 +0,0 @@
1
- module DynamoRecord
2
- class TableMigration
3
- def self.table_config_check
4
- if migrate_table?
5
- table_config.migrate!
6
- return :migrated
7
- end
8
- :exists
9
- end
10
-
11
- def self.migrate(model)
12
- migration = Aws::Record::TableMigration.new(model)
13
- begin
14
- migration.client.describe_table(table_name: model.table_name)
15
- return :exists
16
- rescue Aws::DynamoDB::Errors::ResourceNotFoundException
17
- yield migration
18
- migration.wait_until_available
19
- return :migrated
20
- end
21
- end
22
-
23
- def self.migrate_updates(model)
24
- migration = Aws::Record::TableMigration.new(model)
25
- yield migration
26
- migration.wait_until_available
27
- :updated
28
- end
29
-
30
- def self.add_stream(model)
31
- migrate_updates(model) do |migration|
32
- migration.update!(
33
- stream_specification: {
34
- stream_enabled: true,
35
- stream_view_type: 'NEW_IMAGE'
36
- }
37
- )
38
- end
39
- rescue Aws::DynamoDB::Errors::ValidationException => e
40
- return e.message if e.message == 'Table already has an enabled stream'
41
- raise e
42
- end
43
-
44
- def self.migrate_table?(update_provisioned_throughput = false)
45
- unless update_provisioned_throughput
46
- client = table_config.client
47
- table_name = table_config.instance_values['model_class'].table_name
48
- described_table = client.describe_table table_name: table_name
49
- provisioned_throughput = described_table.table.provisioned_throughput
50
- table_config.read_capacity_units provisioned_throughput.read_capacity_units
51
- table_config.write_capacity_units provisioned_throughput.write_capacity_units
52
- end
53
- !table_config.exact_match?
54
- rescue Aws::DynamoDB::Errors::ResourceNotFoundException
55
- true
56
- end
57
- end
58
- end