dynamo-record 0.4.0 → 1.4.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: e81e37de2e8ba6804662a756c1af90a60a85bc1e
4
- data.tar.gz: 512d203880a9b118735f17fb66886578e5b3ed1a
2
+ SHA256:
3
+ metadata.gz: 9a8e9652f6a8164e4c7f9d1ca2ae3c0509c396ebc11e6e9d0596fd1c132184c1
4
+ data.tar.gz: f0b31912eba1e7a0b53068e530e2c9b6573a7b4edeb3ff94315d3599dfd6789f
5
5
  SHA512:
6
- metadata.gz: c6dec5f3cef468bd4dcbb024c17d7e45a2cf55507c895fb66f082dc37bf9db55ab0ac6fa67f6a3f3215fcf88d708b03705235f660db8e5172b52f1b40eded2e8
7
- data.tar.gz: b8eb760aef776b82c3ea5d1ded6cb02aca7201937cb390a9629e94002f73ce81974475386b15f85e05bf7b6ca5b571476bac93ab4d5b607d09843c26138b7ebb
6
+ metadata.gz: b8664fc94e0a0a72f4ca4f44682d6fbff512c3808a0ab89a8626c691e93b20b894852f240174ac8dc6c4c44498274c6a436ac48c0184ea10e839720625df18b3
7
+ data.tar.gz: 69b6aaacf990a51b25363791b14c5d500d227fe9a53e404bf55d7668b335d6f2795a743ec2d16aaa4c694d90aee5d8034c7aaae3fe1bd3bd5a72d34ee0dd2a59
@@ -1,9 +1,11 @@
1
- Rails:
2
- Enabled: true
1
+ require:
2
+ - rubocop-rails
3
3
 
4
4
  AllCops:
5
+ NewCops: disable
6
+ SuggestExtensions: false
5
7
  TargetRailsVersion: 4.2
6
- TargetRubyVersion: 2.3
8
+ TargetRubyVersion: 2.6
7
9
 
8
10
  Metrics/AbcSize:
9
11
  Max: 20 # Default: 15
@@ -11,19 +13,22 @@ Metrics/AbcSize:
11
13
  Metrics/ClassLength:
12
14
  Max: 200 # Default: 100
13
15
 
14
- Metrics/LineLength:
15
- Max: 120 # Default: 80
16
-
17
16
  Metrics/MethodLength:
18
17
  Max: 20 # Default: 10
19
18
 
20
19
  Metrics/BlockLength:
21
20
  Max: 30
22
21
  Exclude:
23
- - 'dynamo-record.gemspec'
24
- - 'spec/**/*.rb'
22
+ - dynamo-record.gemspec
23
+ - spec/**/*.rb
24
+
25
+ Layout/EndAlignment:
26
+ EnforcedStyleAlignWith: variable
25
27
 
26
- Layout/AlignParameters:
28
+ Layout/LineLength:
29
+ Max: 120 # Default: 80
30
+
31
+ Layout/ParameterAlignment:
27
32
  # Alignment of parameters in multi-line method calls.
28
33
  #
29
34
  # The `with_fixed_indentation` style aligns the following lines with one
@@ -33,8 +38,16 @@ Layout/AlignParameters:
33
38
  # b)
34
39
  EnforcedStyle: with_fixed_indentation
35
40
 
36
- Lint/EndAlignment:
37
- EnforcedStyleAlignWith: variable
41
+ Lint/ConstantDefinitionInBlock:
42
+ Exclude:
43
+ - spec/**/*.rb
44
+
45
+ Naming/FileName:
46
+ Exclude:
47
+ - spec/gemfiles/*
48
+
49
+ Naming/VariableNumber:
50
+ EnforcedStyle: snake_case
38
51
 
39
52
  Style/Documentation:
40
53
  # This cop checks for missing top-level documentation of classes and modules.
@@ -43,18 +56,6 @@ Style/Documentation:
43
56
  # classes or other modules.
44
57
  Enabled: false
45
58
 
46
- Style/FrozenStringLiteralComment:
47
- # `when_needed` will add the frozen string literal comment to files
48
- # only when the `TargetRubyVersion` is set to 2.3+.
49
- # `always` will always add the frozen string literal comment to a file
50
- # regardless of the Ruby version or if `freeze` or `<<` are called on a
51
- # string literal. If you run code against multiple versions of Ruby, it is
52
- # possible that this will create errors in Ruby 2.3.0+.
53
- #
54
- # See: https://wyeworks.com/blog/2015/12/1/immutable-strings-in-ruby-2-dot-3
55
- EnforcedStyle: when_needed
56
- Enabled: false
57
-
58
59
  Style/NumericPredicate:
59
60
  Exclude:
60
- - 'spec/**/*.rb'
61
+ - spec/**/*.rb
@@ -4,18 +4,25 @@ language: ruby
4
4
  cache: bundler
5
5
 
6
6
  rvm:
7
- - 2.3
8
- - 2.4
7
+ - 2.6
8
+ - 2.7
9
+ - 3.0
9
10
 
10
11
  gemfile:
11
- - spec/gemfiles/rails-4.2.gemfile
12
- - spec/gemfiles/rails-5.0.gemfile
13
- - spec/gemfiles/rails-5.1.gemfile
12
+ - spec/gemfiles/rails-5.2.gemfile
13
+ - spec/gemfiles/rails-6.0.gemfile
14
+ - spec/gemfiles/rails-6.1.gemfile
15
+
16
+ # Rails 5.2 doesn't support Ruby 3.0, so don't try
17
+ matrix:
18
+ exclude:
19
+ - rvm: 3.0
20
+ gemfile: spec/gemfiles/rails-5.2.gemfile
14
21
 
15
22
  before_install: gem update bundler
16
23
  bundler_args: --jobs 3
17
24
  install: bundle install --jobs 3
18
25
 
19
26
  script:
20
- - bash -c "if [ '$TRAVIS_RUBY_VERSION' = '2.4' ] && [[ '$BUNDLE_GEMFILE' == *'rails-5.0'* ]]; then bundle exec rubocop --fail-level autocorrect; fi"
27
+ - bash -c "if [ '$TRAVIS_RUBY_VERSION' = '3.0' ] && [[ '$BUNDLE_GEMFILE' == *'rails-6.1'* ]]; then bundle exec rubocop --fail-level autocorrect; fi"
21
28
  - bundle exec rspec
data/Dockerfile CHANGED
@@ -1,22 +1,21 @@
1
1
  FROM instructure/rvm
2
2
 
3
3
  WORKDIR /app
4
-
5
- COPY dynamo-record.gemspec Gemfile /app/
6
- COPY lib/dynamo/record/version.rb /app/lib/dynamo/record/version.rb
7
-
8
- USER root
9
- RUN mkdir -p /app/coverage \
10
- /app/spec/gemfiles/.bundle \
11
- /app/spec/internal/log \
12
- && chown -R docker:docker /app
13
-
14
- USER docker
15
- RUN /bin/bash -l -c "cd /app && rvm-exec 2.4 bundle install --jobs 5"
16
- COPY . /app
17
-
18
4
  USER root
19
5
  RUN chown -R docker:docker /app
20
6
  USER docker
21
7
 
22
- CMD /bin/bash -l -c "rvm-exec 2.4 bundle exec wwtd"
8
+ COPY --chown=docker:docker dynamo-record.gemspec Gemfile /app/
9
+ COPY --chown=docker:docker lib/dynamo/record/version.rb /app/lib/dynamo/record/version.rb
10
+
11
+ RUN mkdir -p coverage \
12
+ spec/gemfiles/.bundle \
13
+ spec/internal/log
14
+
15
+ RUN bash -lc "rvm 2.6,2.7,3.0 do gem install --no-document bundler -v '~> 2.2'"
16
+ RUN bash -lc "cd /app && rvm-exec 2.6 bundle install --jobs 5"
17
+ RUN bash -lc "cd /app && rvm-exec 2.7 bundle install --jobs 5"
18
+ RUN bash -lc "cd /app && rvm-exec 3.0 bundle install --jobs 5"
19
+ COPY --chown=docker:docker . /app
20
+
21
+ CMD /bin/bash -lc "rvm-exec 3.0 bundle exec wwtd"
data/Gemfile CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  source 'https://rubygems.org'
2
4
 
3
5
  gemspec
@@ -0,0 +1,45 @@
1
+ #!/usr/bin/env groovy
2
+
3
+ pipeline {
4
+ agent {
5
+ label 'docker'
6
+ }
7
+ options {
8
+ ansiColor("xterm")
9
+ buildDiscarder(logRotator(numToKeepStr: '50'))
10
+ timeout(time: 20, unit: 'MINUTES')
11
+ }
12
+ stages {
13
+ stage('Build') {
14
+ steps {
15
+ sh 'docker-compose pull dynamo'
16
+ sh 'docker-compose up -d dynamo'
17
+ sh 'docker-compose build --pull app'
18
+ }
19
+ }
20
+ stage('Test') {
21
+ steps {
22
+ sh '''
23
+ docker-compose run --rm app /bin/bash -l -c \
24
+ "rvm-exec 3.0 bundle exec rubocop --fail-level autocorrect"
25
+ docker-compose run --name coverage app
26
+ '''
27
+ }
28
+ post {
29
+ always {
30
+ sh 'docker cp coverage:/app/coverage .'
31
+ sh 'docker-compose down --rmi=all --volumes --remove-orphans'
32
+
33
+ publishHTML target: [
34
+ allowMissing: false,
35
+ alwaysLinkToLastBuild: false,
36
+ keepAll: true,
37
+ reportDir: "coverage",
38
+ reportFiles: 'index.html',
39
+ reportName: 'Coverage Report'
40
+ ]
41
+ }
42
+ }
43
+ }
44
+ }
45
+ }
data/README.md CHANGED
@@ -211,11 +211,13 @@ gem with multiple versions of Ruby. This requires docker and docker-compose to
211
211
  be installed. To get started, run the following:
212
212
 
213
213
  ```bash
214
- ./build.sh
214
+ docker-compose build --pull
215
+ docker-compose up -d dynamo
216
+ docker-compose run --rm app
215
217
  ```
216
218
 
217
219
  This will install the gem in a docker image with all versions of Ruby installed,
218
- and install all gem dependencies in the Ruby 2.4 set of gems. It will also
220
+ and install all gem dependencies in the Ruby 2.6 set of gems. It will also
219
221
  download and spin up a DynamoDB Local container for use with specs. Finally, it
220
222
  will run [wwtd](https://github.com/grosser/wwtd), which runs all specs across
221
223
  all supported version of Ruby and Rails, bundling gems for each combination
@@ -228,7 +230,7 @@ Individual spec runs can be started like so:
228
230
 
229
231
  ```bash
230
232
  docker-compose run --rm app /bin/bash -l -c \
231
- "BUNDLE_GEMFILE=spec/gemfiles/rails-5.0.gemfile rvm-exec 2.4 bundle exec rspec"
233
+ "BUNDLE_GEMFILE=spec/gemfiles/rails-6.1.gemfile rvm-exec 3.0 bundle exec rspec"
232
234
  ```
233
235
 
234
236
  If you'd like to mount your git checkout within the docker container running
@@ -1,4 +1,6 @@
1
- lib = File.expand_path('../lib', __FILE__)
1
+ # frozen_string_literal: true
2
+
3
+ lib = File.expand_path('lib', __dir__)
2
4
  $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
3
5
  require 'dynamo/record/version'
4
6
 
@@ -33,18 +35,21 @@ Gem::Specification.new do |s|
33
35
  end
34
36
  s.require_paths = ['lib']
35
37
 
36
- s.add_dependency 'aws-record', '~> 1.1'
37
- s.add_dependency 'activemodel', '>= 4.2', '< 5.2'
38
- s.add_dependency 'railties', '>= 4.2', '< 5.2'
38
+ s.required_ruby_version = '>= 2.6'
39
+
40
+ s.add_dependency 'activemodel', '>= 5.2', '< 6.2'
41
+ s.add_dependency 'aws-record', '~> 2.0'
42
+ s.add_dependency 'railties', '>= 5.2', '< 6.2'
39
43
 
40
- s.add_development_dependency 'activesupport', '>= 4.2', '< 5.2'
41
- s.add_development_dependency 'bundler', '~> 1.15'
42
- s.add_development_dependency 'byebug', '~> 9.0'
43
- s.add_development_dependency 'combustion', '~> 0.6.0'
44
- s.add_development_dependency 'rake', '~> 12.0'
44
+ s.add_development_dependency 'activesupport', '>= 5.2', '< 6.2'
45
+ s.add_development_dependency 'bundler', '~> 2.2'
46
+ s.add_development_dependency 'byebug', '~> 11.0'
47
+ s.add_development_dependency 'combustion', '~> 1.3'
48
+ s.add_development_dependency 'rake', '~> 13.0'
45
49
  s.add_development_dependency 'rspec', '~> 3.6'
46
- s.add_development_dependency 'rubocop', '~> 0.50.0'
47
- s.add_development_dependency 'simplecov', '~> 0.14'
48
- s.add_development_dependency 'webmock', '~> 2.1'
50
+ s.add_development_dependency 'rubocop', '~> 1.8.1'
51
+ s.add_development_dependency 'rubocop-rails', '~> 2.9.1'
52
+ s.add_development_dependency 'simplecov', '~> 0.16'
53
+ s.add_development_dependency 'webmock', '~> 3.3'
49
54
  s.add_development_dependency 'wwtd', '~> 1.3'
50
55
  end
@@ -1,8 +1,11 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'active_model'
2
4
  require 'aws-record'
3
5
  require 'rails/railtie'
4
6
 
5
7
  require 'dynamo/record/marshalers'
8
+ require 'dynamo/record/batch_get'
6
9
  require 'dynamo/record/batch_write'
7
10
  require 'dynamo/record/batch_request'
8
11
  require 'dynamo/record/model'
@@ -17,3 +20,15 @@ require 'dynamo/record/task_helpers/drop_table'
17
20
  require 'dynamo/record/task_helpers/list_tables'
18
21
  require 'dynamo/record/task_helpers/migration_runner'
19
22
  require 'dynamo/record/task_helpers/scale'
23
+
24
+ module Dynamo
25
+ module Record
26
+ class << self
27
+ attr_writer :logger
28
+
29
+ def logger
30
+ @logger ||= Logger.new($stdout).tap { |log| log.progname = name }
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,84 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'json'
4
+
5
+ module Dynamo
6
+ module Record
7
+ module BatchGet
8
+ BATCH_SIZE = 100
9
+
10
+ module ClassMethods
11
+ def batch_get(keys)
12
+ process_batch_get_requests(keys)
13
+ end
14
+
15
+ private
16
+
17
+ def process_batch_get_requests(keys) # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity
18
+ attempt = 1
19
+ results = []
20
+ unprocessed_keys = keys.dup.map(&:stringify_keys)
21
+ while !unprocessed_keys.empty? && attempt <= max_retries
22
+ batch = unprocessed_keys.shift(BATCH_SIZE)
23
+ Dynamo::Record.logger.debug "#{name} batch_get_item #{batch.count} request_items"
24
+ processed, unprocessed = get_batch_from_dynamo(batch)
25
+ results.concat(processed)
26
+
27
+ next if unprocessed.empty?
28
+
29
+ Dynamo::Record.logger.debug "#{name} batch_get_item #{unprocessed.count} unprocessed_keys"
30
+ unprocessed_keys.unshift(*unprocessed)
31
+ sleep(rand(1 << attempt) + 1)
32
+ attempt += 1
33
+ end
34
+
35
+ if !unprocessed_keys.empty? && attempt > max_retries
36
+ raise NumberOfRetriesExceeded.new(keys), 'Number of retries exceeded'
37
+ end
38
+
39
+ results.map { |r| build_item_from_hash(r) }
40
+ end
41
+
42
+ # BatchGetItem will return a partial result if provisioned throughput is
43
+ # exceeded or an internal error occurs. If all items cannot be processed
44
+ # ProvisionedThroughputExceededException is raised.
45
+ # https://docs.aws.amazon.com/sdkforruby/api/Aws/DynamoDB/Client.html#batch_get_item-instance_method
46
+ def get_batch_from_dynamo(batch)
47
+ response = dynamodb_client.batch_get_item(
48
+ request_items: {
49
+ table_name => { keys: batch }
50
+ }
51
+ )
52
+ [
53
+ response.responses[table_name],
54
+ response.unprocessed_keys[table_name]&.keys || []
55
+ ]
56
+ rescue Aws::DynamoDB::Errors::ProvisionedThroughputExceededException
57
+ [[], batch]
58
+ end
59
+
60
+ # Convert response hashes to Record instances
61
+ # Adapted from `build_item_from_resp` used by `find` but that method is closely tied to get_item response format
62
+ # https://github.com/aws/aws-sdk-ruby-record/blob/v2.3.0/lib/aws-record/record/item_operations.rb#L593
63
+ def build_item_from_hash(resp)
64
+ record = new
65
+ data = record.instance_variable_get('@data')
66
+ attributes.attributes.each do |name, attr|
67
+ data.set_attribute(name, attr.extract(resp))
68
+ data.new_record = false
69
+ end
70
+ record
71
+ end
72
+ end
73
+
74
+ class NumberOfRetriesExceeded < RuntimeError
75
+ attr_reader :keys
76
+
77
+ def initialize(keys)
78
+ super
79
+ @keys = keys
80
+ end
81
+ end
82
+ end
83
+ end
84
+ end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Dynamo
2
4
  module Record
3
5
  class BatchRequest
@@ -13,7 +15,7 @@ module Dynamo
13
15
  end
14
16
 
15
17
  def request
16
- @_request ||= send("#{type}_request")
18
+ @request ||= send("#{type}_request")
17
19
  end
18
20
 
19
21
  def save_request
@@ -33,25 +35,29 @@ module Dynamo
33
35
  end
34
36
 
35
37
  def request_size
36
- @_request_size ||= request.to_json.length
38
+ @request_size ||= request.to_json.length
37
39
  end
38
40
 
39
41
  def validate_request_size
40
42
  return unless request_size > MAX_RECORD_SIZE
43
+
41
44
  raise RecordTooLargeError.new(record), 'Record is too large'
42
45
  end
43
46
 
44
47
  def validate_type
45
48
  return if %i[save delete].include? type
49
+
46
50
  raise UnsupportedRequestTypeError
47
51
  end
48
52
  end
49
53
 
50
54
  class UnsupportedRequestTypeError < RuntimeError; end
55
+
51
56
  class RecordTooLargeError < RuntimeError
52
57
  attr_reader :record
53
58
 
54
59
  def initialize(record)
60
+ super
55
61
  @record = record
56
62
  end
57
63
  end
@@ -1,8 +1,9 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Dynamo
2
4
  module Record
3
5
  module BatchWrite
4
6
  BATCH_SIZE = 25
5
- DEFAULT_MAX_RETRIES = 5
6
7
  MAX_PAYLOAD_SIZE = 16_000_000 # 16 MB
7
8
 
8
9
  module ClassMethods
@@ -62,11 +63,14 @@ module Dynamo
62
63
  if retry_count > max_retries
63
64
  raise NumberOfRetriesExceeded.new(unprocessed_items.map(&:record)), 'Number of retries exceeded'
64
65
  end
66
+
65
67
  sleep(rand(1 << retry_count) + 1)
66
68
  process_batch_write_requests(unprocessed_items, retry_count + 1)
67
69
  end
68
70
 
69
71
  def pre_batch(requests)
72
+ return [] if requests.empty?
73
+
70
74
  current_batch_size = 0
71
75
  requests.each_with_object([[]]) do |request, batches|
72
76
  if batches.last.length >= BATCH_SIZE || current_batch_size + request.request_size > MAX_PAYLOAD_SIZE
@@ -77,17 +81,13 @@ module Dynamo
77
81
  current_batch_size += request.request_size
78
82
  end
79
83
  end
80
-
81
- # Override in model if you want it to be different.
82
- def max_retries
83
- DEFAULT_MAX_RETRIES
84
- end
85
84
  end
86
85
 
87
86
  class NumberOfRetriesExceeded < RuntimeError
88
87
  attr_reader :unprocessed_items
89
88
 
90
89
  def initialize(unprocessed_items)
90
+ super
91
91
  @unprocessed_items = unprocessed_items
92
92
  end
93
93
  end
@@ -1,7 +1,9 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Dynamo
2
4
  module Record
3
5
  module Marshalers
4
- COMPOSITE_DELIMETER = '|'.freeze
6
+ COMPOSITE_DELIMETER = '|'
5
7
 
6
8
  def self.included(sub_class)
7
9
  sub_class.extend(ClassMethods)
@@ -25,15 +27,14 @@ module Dynamo
25
27
  opts[:dynamodb_type] = 'S'
26
28
 
27
29
  # It is very unfortunate that Aws::Record used `attr`
28
- # rubocop:disable Style/Attr
29
30
  attr(name, Aws::Record::Marshalers::StringMarshaler.new(opts), opts)
30
- # rubocop:enable Style/Attr
31
31
  end
32
32
 
33
33
  def define_readers(name, parts, cast_function)
34
34
  parts.each_with_index do |part, i|
35
35
  raise "#{part} already defined" unless parts.find_index(part) == i
36
36
  next if method_defined?(part)
37
+
37
38
  define_method(part) do
38
39
  # @data is used internally by Aws::Record to store all of the attributes
39
40
  @data.get_attribute(name).split(COMPOSITE_DELIMETER)[i].send(cast_function)
@@ -1,7 +1,10 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Dynamo
2
4
  module Record
3
5
  module Model
4
- COMPOSITE_DELIMITER = '|'.freeze
6
+ COMPOSITE_DELIMITER = '|'
7
+ DEFAULT_MAX_RETRIES = 5
5
8
 
6
9
  def self.included(klass)
7
10
  klass.include(Aws::Record)
@@ -9,6 +12,7 @@ module Dynamo
9
12
 
10
13
  klass.extend ClassMethods
11
14
  klass.extend Dynamo::Record::BatchWrite::ClassMethods
15
+ klass.extend Dynamo::Record::BatchGet::ClassMethods
12
16
  klass.send :prepend, InstanceMethods
13
17
  end
14
18
 
@@ -19,6 +23,7 @@ module Dynamo
19
23
 
20
24
  def scan
21
25
  raise 'no scanning in production' if Rails.env.production?
26
+
22
27
  super
23
28
  end
24
29
 
@@ -104,7 +109,9 @@ module Dynamo
104
109
  string.split(COMPOSITE_DELIMITER)
105
110
  end
106
111
 
107
- # TODO: Create a batch save method.
112
+ def max_retries
113
+ DEFAULT_MAX_RETRIES
114
+ end
108
115
  end
109
116
 
110
117
  module InstanceMethods
@@ -1,8 +1,11 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Dynamo
2
4
  module Record
3
5
  class ModelExistenceValidator < ActiveModel::EachValidator
4
6
  def validate_each(record, attribute, value)
5
7
  return if options[:model].exists? value
8
+
6
9
  record.errors[attribute] << (options[:message] || "#{attribute}:#{value} is not a valid #{options[:model]}")
7
10
  end
8
11
  end
@@ -1,8 +1,14 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Dynamo
2
4
  module Record
3
5
  class Railtie < Rails::Railtie
4
6
  railtie_name :dynamo_record
5
7
 
8
+ initializer 'logger' do
9
+ Dynamo::Record.logger = Rails.logger
10
+ end
11
+
6
12
  rake_tasks do
7
13
  load 'tasks/dynamo.rake'
8
14
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Dynamo
2
4
  module Record
3
5
  class TableMigration
@@ -13,11 +15,11 @@ module Dynamo
13
15
  migration = Aws::Record::TableMigration.new(model)
14
16
  begin
15
17
  migration.client.describe_table(table_name: model.table_name)
16
- return :exists
18
+ :exists
17
19
  rescue Aws::DynamoDB::Errors::ResourceNotFoundException
18
20
  yield migration
19
21
  migration.wait_until_available
20
- return :migrated
22
+ :migrated
21
23
  end
22
24
  end
23
25
 
@@ -39,10 +41,11 @@ module Dynamo
39
41
  end
40
42
  rescue Aws::DynamoDB::Errors::ValidationException => e
41
43
  return e.message if e.message == 'Table already has an enabled stream'
44
+
42
45
  raise e
43
46
  end
44
47
 
45
- def self.migrate_table?(update_provisioned_throughput = false)
48
+ def self.migrate_table?(update_provisioned_throughput: false)
46
49
  unless update_provisioned_throughput
47
50
  table_name = table_config.instance_values['model_class'].table_name
48
51
  described_table = table_config.client.describe_table table_name: table_name
@@ -1,10 +1,13 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Dynamo
2
4
  module Record
3
5
  module TaskHelpers
4
6
  class Cleanup
5
7
  def self.run
6
8
  raise 'Task not available on production' if Rails.env.production?
7
- Dir[Rails.root.join('app', 'models', '*.rb').to_s].each do |filename|
9
+
10
+ Dir[Rails.root.join('app/models/*.rb').to_s].each do |filename|
8
11
  delete_by_class(filename)
9
12
  end
10
13
  end
@@ -12,6 +15,7 @@ module Dynamo
12
15
  def self.delete_by_class(filename)
13
16
  klass = File.basename(filename, '.rb').camelize.constantize
14
17
  return unless klass.included_modules.include? Dynamo::Record::Model
18
+
15
19
  Rails.logger.info "Deleting all items in table: #{klass}"
16
20
  klass.scan.each(&:delete!)
17
21
  end
@@ -1,14 +1,18 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Dynamo
2
4
  module Record
3
5
  module TaskHelpers
4
6
  class DropAllTables
5
- def self.run(override = false)
7
+ def self.run(override: false)
6
8
  raise 'Task not available on production' if Rails.env.production?
9
+
7
10
  env = Rails.env
8
11
  dynamodb = Aws::DynamoDB::Client.new
9
12
  tables = dynamodb.list_tables
10
13
  tables.table_names.map do |t|
11
14
  next unless t.include?(env) || override
15
+
12
16
  dt = dynamodb.delete_table(table_name: t)
13
17
  dt ? "Deleted: #{t}" : "Delete failed: #{t}"
14
18
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Dynamo
2
4
  module Record
3
5
  module TaskHelpers
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Dynamo
2
4
  module Record
3
5
  module TaskHelpers
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Dynamo
2
4
  module Record
3
5
  module TaskHelpers
@@ -7,8 +9,8 @@ module Dynamo
7
9
  filename_regexp = /\A([0-9]+)_([_a-z0-9]*)\.?([_a-z0-9]*)?\.rb\z/
8
10
 
9
11
  # Sorts the files located in `db/dynamo_migrate` to ensure order is preserved
10
- Dir[Rails.root.join("#{path}/*.rb")].sort.each do |f|
11
- migration = migration(f, filename_regexp, constants)
12
+ Dir[Rails.root.join("#{path}/*.rb")].sort.each do |file|
13
+ migration = migration(file, filename_regexp, constants)
12
14
 
13
15
  # starts the migration
14
16
  yield "Migrating: #{migration}"
@@ -28,9 +30,10 @@ module Dynamo
28
30
  end
29
31
  end
30
32
 
31
- def self.migration(f, filename_regexp, constants)
32
- raise "Non-numeric prefix: #{f}" if File.basename(f).scan(filename_regexp).first.nil?
33
- require f
33
+ def self.migration(file, filename_regexp, constants)
34
+ raise "Non-numeric prefix: #{file}" if File.basename(file).scan(filename_regexp).first.nil?
35
+
36
+ require file
34
37
 
35
38
  # finds the constant that was added on the require statement above
36
39
  migration_sym = (DynamoMigrate.constants - constants).first
@@ -52,18 +55,22 @@ module Dynamo
52
55
 
53
56
  def self.up(migration)
54
57
  return unless migration.respond_to? :up
58
+
55
59
  status_message migration.up
56
60
  end
57
61
 
58
62
  def self.table_config_check(migration)
59
63
  return unless migration.respond_to? :table_config
64
+
60
65
  status_message migration.table_config_check
61
66
  end
62
67
 
63
68
  def self.update(migration)
64
69
  return unless migration.respond_to? :update
70
+
65
71
  status = migration.update
66
72
  return 'Migration successful' if status == :updated
73
+
67
74
  status
68
75
  end
69
76
  end
@@ -1,9 +1,10 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Dynamo
2
4
  module Record
3
5
  module TaskHelpers
4
6
  class Scale
5
- attr_reader :model, :attribute_selector, :new_throughput
6
- attr_reader :migration, :existing_throughput, :model_name
7
+ attr_reader :model, :attribute_selector, :new_throughput, :migration, :existing_throughput, :model_name
7
8
 
8
9
  def initialize(model_name, attribute_selector, new_throughput)
9
10
  @model_name = model_name
@@ -1,5 +1,7 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Dynamo
2
4
  module Record
3
- VERSION = '0.4.0'.freeze
5
+ VERSION = '1.4.0'
4
6
  end
5
7
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  namespace :dynamo do
2
4
  desc 'Run dynamo migrations'
3
5
  task migrate: :environment do
@@ -5,7 +7,7 @@ namespace :dynamo do
5
7
  end
6
8
 
7
9
  desc 'Drops all dynamo tables and re-runs migrations'
8
- task :reset do
10
+ task reset: :environment do
9
11
  Rake::Task['dynamo:drop_all'].invoke
10
12
  Rake::Task['dynamo:migrate'].invoke
11
13
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: dynamo-record
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.0
4
+ version: 1.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Davis McClellan
@@ -14,138 +14,138 @@ authors:
14
14
  autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
- date: 2018-01-09 00:00:00.000000000 Z
17
+ date: 2021-01-26 00:00:00.000000000 Z
18
18
  dependencies:
19
19
  - !ruby/object:Gem::Dependency
20
- name: aws-record
20
+ name: activemodel
21
21
  requirement: !ruby/object:Gem::Requirement
22
22
  requirements:
23
- - - "~>"
23
+ - - ">="
24
+ - !ruby/object:Gem::Version
25
+ version: '5.2'
26
+ - - "<"
24
27
  - !ruby/object:Gem::Version
25
- version: '1.1'
28
+ version: '6.2'
26
29
  type: :runtime
27
30
  prerelease: false
28
31
  version_requirements: !ruby/object:Gem::Requirement
29
32
  requirements:
30
- - - "~>"
33
+ - - ">="
34
+ - !ruby/object:Gem::Version
35
+ version: '5.2'
36
+ - - "<"
31
37
  - !ruby/object:Gem::Version
32
- version: '1.1'
38
+ version: '6.2'
33
39
  - !ruby/object:Gem::Dependency
34
- name: activemodel
40
+ name: aws-record
35
41
  requirement: !ruby/object:Gem::Requirement
36
42
  requirements:
37
- - - ">="
38
- - !ruby/object:Gem::Version
39
- version: '4.2'
40
- - - "<"
43
+ - - "~>"
41
44
  - !ruby/object:Gem::Version
42
- version: '5.2'
45
+ version: '2.0'
43
46
  type: :runtime
44
47
  prerelease: false
45
48
  version_requirements: !ruby/object:Gem::Requirement
46
49
  requirements:
47
- - - ">="
48
- - !ruby/object:Gem::Version
49
- version: '4.2'
50
- - - "<"
50
+ - - "~>"
51
51
  - !ruby/object:Gem::Version
52
- version: '5.2'
52
+ version: '2.0'
53
53
  - !ruby/object:Gem::Dependency
54
54
  name: railties
55
55
  requirement: !ruby/object:Gem::Requirement
56
56
  requirements:
57
57
  - - ">="
58
58
  - !ruby/object:Gem::Version
59
- version: '4.2'
59
+ version: '5.2'
60
60
  - - "<"
61
61
  - !ruby/object:Gem::Version
62
- version: '5.2'
62
+ version: '6.2'
63
63
  type: :runtime
64
64
  prerelease: false
65
65
  version_requirements: !ruby/object:Gem::Requirement
66
66
  requirements:
67
67
  - - ">="
68
68
  - !ruby/object:Gem::Version
69
- version: '4.2'
69
+ version: '5.2'
70
70
  - - "<"
71
71
  - !ruby/object:Gem::Version
72
- version: '5.2'
72
+ version: '6.2'
73
73
  - !ruby/object:Gem::Dependency
74
74
  name: activesupport
75
75
  requirement: !ruby/object:Gem::Requirement
76
76
  requirements:
77
77
  - - ">="
78
78
  - !ruby/object:Gem::Version
79
- version: '4.2'
79
+ version: '5.2'
80
80
  - - "<"
81
81
  - !ruby/object:Gem::Version
82
- version: '5.2'
82
+ version: '6.2'
83
83
  type: :development
84
84
  prerelease: false
85
85
  version_requirements: !ruby/object:Gem::Requirement
86
86
  requirements:
87
87
  - - ">="
88
88
  - !ruby/object:Gem::Version
89
- version: '4.2'
89
+ version: '5.2'
90
90
  - - "<"
91
91
  - !ruby/object:Gem::Version
92
- version: '5.2'
92
+ version: '6.2'
93
93
  - !ruby/object:Gem::Dependency
94
94
  name: bundler
95
95
  requirement: !ruby/object:Gem::Requirement
96
96
  requirements:
97
97
  - - "~>"
98
98
  - !ruby/object:Gem::Version
99
- version: '1.15'
99
+ version: '2.2'
100
100
  type: :development
101
101
  prerelease: false
102
102
  version_requirements: !ruby/object:Gem::Requirement
103
103
  requirements:
104
104
  - - "~>"
105
105
  - !ruby/object:Gem::Version
106
- version: '1.15'
106
+ version: '2.2'
107
107
  - !ruby/object:Gem::Dependency
108
108
  name: byebug
109
109
  requirement: !ruby/object:Gem::Requirement
110
110
  requirements:
111
111
  - - "~>"
112
112
  - !ruby/object:Gem::Version
113
- version: '9.0'
113
+ version: '11.0'
114
114
  type: :development
115
115
  prerelease: false
116
116
  version_requirements: !ruby/object:Gem::Requirement
117
117
  requirements:
118
118
  - - "~>"
119
119
  - !ruby/object:Gem::Version
120
- version: '9.0'
120
+ version: '11.0'
121
121
  - !ruby/object:Gem::Dependency
122
122
  name: combustion
123
123
  requirement: !ruby/object:Gem::Requirement
124
124
  requirements:
125
125
  - - "~>"
126
126
  - !ruby/object:Gem::Version
127
- version: 0.6.0
127
+ version: '1.3'
128
128
  type: :development
129
129
  prerelease: false
130
130
  version_requirements: !ruby/object:Gem::Requirement
131
131
  requirements:
132
132
  - - "~>"
133
133
  - !ruby/object:Gem::Version
134
- version: 0.6.0
134
+ version: '1.3'
135
135
  - !ruby/object:Gem::Dependency
136
136
  name: rake
137
137
  requirement: !ruby/object:Gem::Requirement
138
138
  requirements:
139
139
  - - "~>"
140
140
  - !ruby/object:Gem::Version
141
- version: '12.0'
141
+ version: '13.0'
142
142
  type: :development
143
143
  prerelease: false
144
144
  version_requirements: !ruby/object:Gem::Requirement
145
145
  requirements:
146
146
  - - "~>"
147
147
  - !ruby/object:Gem::Version
148
- version: '12.0'
148
+ version: '13.0'
149
149
  - !ruby/object:Gem::Dependency
150
150
  name: rspec
151
151
  requirement: !ruby/object:Gem::Requirement
@@ -166,42 +166,56 @@ dependencies:
166
166
  requirements:
167
167
  - - "~>"
168
168
  - !ruby/object:Gem::Version
169
- version: 0.50.0
169
+ version: 1.8.1
170
170
  type: :development
171
171
  prerelease: false
172
172
  version_requirements: !ruby/object:Gem::Requirement
173
173
  requirements:
174
174
  - - "~>"
175
175
  - !ruby/object:Gem::Version
176
- version: 0.50.0
176
+ version: 1.8.1
177
+ - !ruby/object:Gem::Dependency
178
+ name: rubocop-rails
179
+ requirement: !ruby/object:Gem::Requirement
180
+ requirements:
181
+ - - "~>"
182
+ - !ruby/object:Gem::Version
183
+ version: 2.9.1
184
+ type: :development
185
+ prerelease: false
186
+ version_requirements: !ruby/object:Gem::Requirement
187
+ requirements:
188
+ - - "~>"
189
+ - !ruby/object:Gem::Version
190
+ version: 2.9.1
177
191
  - !ruby/object:Gem::Dependency
178
192
  name: simplecov
179
193
  requirement: !ruby/object:Gem::Requirement
180
194
  requirements:
181
195
  - - "~>"
182
196
  - !ruby/object:Gem::Version
183
- version: '0.14'
197
+ version: '0.16'
184
198
  type: :development
185
199
  prerelease: false
186
200
  version_requirements: !ruby/object:Gem::Requirement
187
201
  requirements:
188
202
  - - "~>"
189
203
  - !ruby/object:Gem::Version
190
- version: '0.14'
204
+ version: '0.16'
191
205
  - !ruby/object:Gem::Dependency
192
206
  name: webmock
193
207
  requirement: !ruby/object:Gem::Requirement
194
208
  requirements:
195
209
  - - "~>"
196
210
  - !ruby/object:Gem::Version
197
- version: '2.1'
211
+ version: '3.3'
198
212
  type: :development
199
213
  prerelease: false
200
214
  version_requirements: !ruby/object:Gem::Requirement
201
215
  requirements:
202
216
  - - "~>"
203
217
  - !ruby/object:Gem::Version
204
- version: '2.1'
218
+ version: '3.3'
205
219
  - !ruby/object:Gem::Dependency
206
220
  name: wwtd
207
221
  requirement: !ruby/object:Gem::Requirement
@@ -236,13 +250,14 @@ files:
236
250
  - ".travis.yml"
237
251
  - Dockerfile
238
252
  - Gemfile
253
+ - Jenkinsfile
239
254
  - LICENSE.txt
240
255
  - README.md
241
- - build.sh
242
256
  - docker-compose.override.example.yml
243
257
  - docker-compose.yml
244
258
  - dynamo-record.gemspec
245
259
  - lib/dynamo/record.rb
260
+ - lib/dynamo/record/batch_get.rb
246
261
  - lib/dynamo/record/batch_request.rb
247
262
  - lib/dynamo/record/batch_write.rb
248
263
  - lib/dynamo/record/marshalers.rb
@@ -270,17 +285,15 @@ required_ruby_version: !ruby/object:Gem::Requirement
270
285
  requirements:
271
286
  - - ">="
272
287
  - !ruby/object:Gem::Version
273
- version: '0'
288
+ version: '2.6'
274
289
  required_rubygems_version: !ruby/object:Gem::Requirement
275
290
  requirements:
276
291
  - - ">="
277
292
  - !ruby/object:Gem::Version
278
293
  version: '0'
279
294
  requirements: []
280
- rubyforge_project:
281
- rubygems_version: 2.6.13
295
+ rubygems_version: 3.0.3
282
296
  signing_key:
283
297
  specification_version: 4
284
298
  summary: Extensions to Aws::Record for working with DynamoDB.
285
299
  test_files: []
286
- has_rdoc:
data/build.sh DELETED
@@ -1,20 +0,0 @@
1
- #!/bin/bash -ex
2
-
3
- COMPOSE_FILE="docker-compose.yml"
4
-
5
- function cleanup() {
6
- exit_code=$?
7
- set +e
8
- docker cp coverage:/app/coverage .
9
- docker-compose kill
10
- docker-compose rm -f
11
- exit $exit_code
12
- }
13
- trap cleanup INT TERM EXIT
14
-
15
- docker-compose pull dynamo
16
- docker-compose up -d dynamo
17
- docker-compose build --pull app
18
- docker-compose run --rm app /bin/bash -l -c \
19
- "rvm-exec 2.4 bundle exec rubocop --fail-level autocorrect"
20
- docker-compose run --name coverage app $@