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.
- checksums.yaml +4 -4
- data/.dockerignore +15 -0
- data/.gitignore +9 -5
- data/.rspec +1 -0
- data/.rubocop.yml +9 -30
- data/.travis.yml +18 -2
- data/Dockerfile +22 -0
- data/Gemfile +0 -1
- data/LICENSE.txt +21 -0
- data/README.md +75 -17
- data/build.sh +10 -20
- data/docker-compose.override.example.yml +19 -0
- data/docker-compose.yml +7 -2
- data/dynamo-record.gemspec +40 -28
- data/lib/dynamo/record.rb +17 -0
- data/lib/dynamo/record/marshalers.rb +46 -0
- data/lib/dynamo/record/model.rb +127 -0
- data/lib/dynamo/record/model_existence_validator.rb +10 -0
- data/lib/{dynamo-record → dynamo}/record/railtie.rb +1 -3
- data/lib/dynamo/record/table_migration.rb +59 -0
- data/lib/dynamo/record/task_helpers/cleanup.rb +21 -0
- data/lib/dynamo/record/task_helpers/drop_all_tables.rb +19 -0
- data/lib/dynamo/record/task_helpers/drop_table.rb +13 -0
- data/lib/dynamo/record/task_helpers/list_tables.rb +15 -0
- data/lib/dynamo/record/task_helpers/migration_runner.rb +72 -0
- data/lib/dynamo/record/task_helpers/scale.rb +90 -0
- data/lib/dynamo/record/version.rb +5 -0
- data/lib/tasks/dynamo.rake +7 -7
- metadata +96 -37
- data/Dockerfile.test +0 -23
- data/Gemfile.lock +0 -178
- data/doc/testing.md +0 -11
- data/docker-compose.dev.override.yml +0 -6
- data/lib/dynamo-record.rb +0 -4
- data/lib/dynamo-record/marshalers.rb +0 -44
- data/lib/dynamo-record/model.rb +0 -127
- data/lib/dynamo-record/record.rb +0 -7
- data/lib/dynamo-record/record/version.rb +0 -5
- data/lib/dynamo-record/table_migration.rb +0 -58
- data/lib/dynamo-record/task_helpers/cleanup.rb +0 -19
- data/lib/dynamo-record/task_helpers/drop_all_tables.rb +0 -17
- data/lib/dynamo-record/task_helpers/drop_table.rb +0 -11
- data/lib/dynamo-record/task_helpers/list_tables.rb +0 -13
- data/lib/dynamo-record/task_helpers/migration_runner.rb +0 -70
- data/lib/dynamo-record/task_helpers/scale.rb +0 -86
- data/lib/model_existence_validator.rb +0 -7
data/Dockerfile.test
DELETED
@@ -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"]
|
data/Gemfile.lock
DELETED
@@ -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
|
data/doc/testing.md
DELETED
data/lib/dynamo-record.rb
DELETED
@@ -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
|
data/lib/dynamo-record/model.rb
DELETED
@@ -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
|
data/lib/dynamo-record/record.rb
DELETED
@@ -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
|