dynamo-record 0.2.0 → 0.3.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 (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