class Aws::Record::TableMigration

Attributes

client[RW]

@!attribute [rw] client

@return [Aws::DynamoDB::Client] the
  {http://docs.aws.amazon.com/sdkforruby/api/Aws/DynamoDB/Client.html Aws::DynamoDB::Client}
  class used by this table migration instance.

Public Class Methods

new(model, opts = {}) click to toggle source

@param [Aws::Record] model a model class that includes {Aws::Record}. @param [Hash] opts @option opts [Aws::DynamoDB::Client] :client Allows you to inject your

own
{http://docs.aws.amazon.com/sdkforruby/api/Aws/DynamoDB/Client.html Aws::DynamoDB::Client}
class. If this option is not included, a client will be constructed for
you with default parameters.
# File lib/aws-record/record/table_migration.rb, line 31
def initialize(model, opts = {})
  _assert_model_valid(model)
  @model = model
  @client = opts[:client] || model.dynamodb_client || Aws::DynamoDB::Client.new
end

Public Instance Methods

create!(opts) click to toggle source

This method calls {docs.aws.amazon.com/sdkforruby/api/Aws/DynamoDB/Client.html#create_table-instance_method Aws::DynamoDB::Client#create_table}, populating the attribute definitions and key schema based on your model class, as well as passing through other parameters as provided by you.

@example Creating a table with a global secondary index named :gsi

migration.create!(
  provisioned_throughput: {
    read_capacity_units: 5,
    write_capacity_units: 2
  },
  global_secondary_index_throughput: {
    gsi: {
      read_capacity_units: 3,
      write_capacity_units: 1
    }
  }
)

@param [Hash] opts options to pass on to the client call to

+#create_table+. See the documentation above in the AWS SDK for Ruby
V2.

@option opts [Hash] :billing_mode Accepts values 'PAY_PER_REQUEST' or

'PROVISIONED'. If :provisioned_throughput option is specified, this
option is not required, as 'PROVISIONED' is assumed. If
:provisioned_throughput is not specified, this option is required
and must be set to 'PAY_PER_REQUEST'.

@option opts [Hash] :provisioned_throughput Unless :billing_mode is

set to 'PAY_PER_REQUEST', this is a required argument, in which
you must specify the +:read_capacity_units+ and
+:write_capacity_units+ of your new table.

@option opts [Hash] :global_secondary_index_throughput This argument is

required if you define any global secondary indexes, unless
:billing_mode is set to 'PAY_PER_REQUEST'. It should map your
global secondary index names to their provisioned throughput, similar
to how you define the provisioned throughput for the table in general.
# File lib/aws-record/record/table_migration.rb, line 73
def create!(opts)
  gsit = opts.delete(:global_secondary_index_throughput)
  _validate_billing(opts)

  create_opts = opts.merge({
    table_name: @model.table_name,
    attribute_definitions: _attribute_definitions,
    key_schema: _key_schema
  })
  if lsis = @model.local_secondary_indexes_for_migration
    create_opts[:local_secondary_indexes] = lsis
    _append_to_attribute_definitions(lsis, create_opts)
  end
  if gsis = @model.global_secondary_indexes_for_migration
    unless gsit || opts[:billing_mode] == 'PAY_PER_REQUEST'
      raise ArgumentError.new(
        'If you define global secondary indexes, you must also define'\
          ' :global_secondary_index_throughput on table creation,'\
          " unless :billing_mode is set to 'PAY_PER_REQUEST'."
      )
    end
    gsis_opts = if opts[:billing_mode] == 'PAY_PER_REQUEST'
                  gsis
                else
                  _add_throughput_to_gsis(gsis, gsit)
                end
    create_opts[:global_secondary_indexes] = gsis_opts
    _append_to_attribute_definitions(gsis, create_opts)
  end
  @client.create_table(create_opts)
end
delete!() click to toggle source

This method calls {docs.aws.amazon.com/sdkforruby/api/Aws/DynamoDB/Client.html#delete_table-instance_method Aws::DynamoDB::Client#delete_table} using the table name of your model.

@raise [Aws::Record::Errors::TableDoesNotExist] if the table did not

exist in Amazon DynamoDB at the time of calling.
# File lib/aws-record/record/table_migration.rb, line 131
def delete!
  begin
    @client.delete_table(table_name: @model.table_name)
  rescue DynamoDB::Errors::ResourceNotFoundException => e
    raise Errors::TableDoesNotExist.new(e)
  end
end
update!(opts) click to toggle source

This method calls {docs.aws.amazon.com/sdkforruby/api/Aws/DynamoDB/Client.html#update_table-instance_method Aws::DynamoDB::Client#update_table} using the parameters that you provide.

@param [Hash] opts options to pass on to the client call to

+#update_table+. See the documentation above in the AWS SDK for Ruby
V2.

@raise [Aws::Record::Errors::TableDoesNotExist] if the table does not

currently exist in Amazon DynamoDB.
# File lib/aws-record/record/table_migration.rb, line 114
def update!(opts)
  begin
    update_opts = opts.merge({
      table_name: @model.table_name
    })
    @client.update_table(update_opts)
  rescue DynamoDB::Errors::ResourceNotFoundException => e
    raise Errors::TableDoesNotExist.new(e)
  end
end
wait_until_available() click to toggle source

This method waits on the table specified in the model to exist and be marked as ACTIVE in Amazon DynamoDB. Note that this method can run for several minutes if the table does not exist, and is not created within the wait period.

# File lib/aws-record/record/table_migration.rb, line 143
def wait_until_available
  @client.wait_until(:table_exists, table_name: @model.table_name)
end

Private Instance Methods

_add_throughput_to_gsis(global_secondary_indexes, gsi_throughput) click to toggle source
# File lib/aws-record/record/table_migration.rb, line 217
def _add_throughput_to_gsis(global_secondary_indexes, gsi_throughput)
  missing_throughput = []
  ret = global_secondary_indexes.map do |params|
    name = params[:index_name]
    throughput = gsi_throughput[name]
    missing_throughput << name unless throughput
    params.merge(provisioned_throughput: throughput)
  end
  unless missing_throughput.empty?
    raise ArgumentError.new(
      "Missing provisioned throughput for the following global secondary"\
        " indexes: #{missing_throughput.join(", ")}. GSIs:"\
        " #{global_secondary_indexes} and defined throughput:"\
        " #{gsi_throughput}"
    )
  end
  ret
end
_append_to_attribute_definitions(secondary_indexes, create_opts) click to toggle source
# File lib/aws-record/record/table_migration.rb, line 195
def _append_to_attribute_definitions(secondary_indexes, create_opts)
  attributes = @model.attributes
  attr_def = create_opts[:attribute_definitions]
  secondary_indexes.each do |si|
    si[:key_schema].each do |key_schema|
      exists = attr_def.find { |a|
        a[:attribute_name] == key_schema[:attribute_name]
      }
      unless exists
        attr = attributes.attribute_for(
          attributes.db_to_attribute_name(key_schema[:attribute_name])
        )
        attr_def << {
          attribute_name: attr.database_name,
          attribute_type: attr.dynamodb_type
        }
      end
    end
  end
  create_opts[:attribute_definitions] = attr_def
end
_assert_model_valid(model) click to toggle source
# File lib/aws-record/record/table_migration.rb, line 148
def _assert_model_valid(model)
  _assert_required_include(model)
  model.model_valid?
end
_assert_required_include(model) click to toggle source
# File lib/aws-record/record/table_migration.rb, line 153
def _assert_required_include(model)
  unless model.include?(::Aws::Record)
    raise Errors::InvalidModel.new("Table models must include Aws::Record")
  end
end
_attribute_definitions() click to toggle source
# File lib/aws-record/record/table_migration.rb, line 186
def _attribute_definitions
  _keys.map do |type, attr|
    {
      attribute_name: attr.database_name,
      attribute_type: attr.dynamodb_type
    }
  end
end
_key_schema() click to toggle source
# File lib/aws-record/record/table_migration.rb, line 236
def _key_schema
  _keys.map do |type, attr|
    {
      attribute_name: attr.database_name,
      key_type: type == :hash ? "HASH" : "RANGE"
    }
  end
end
_keys() click to toggle source
# File lib/aws-record/record/table_migration.rb, line 245
def _keys
  @model.keys.inject({}) do |acc, (type, name)|
    acc[type] = @model.attributes.attribute_for(name)
    acc
  end
end
_validate_billing(opts) click to toggle source
# File lib/aws-record/record/table_migration.rb, line 159
def _validate_billing(opts)
  valid_modes = %w[PAY_PER_REQUEST PROVISIONED]
  if opts.key?(:billing_mode)
    unless valid_modes.include?(opts[:billing_mode])
      raise ArgumentError.new(
        ":billing_mode option must be one of #{valid_modes.join(', ')}"\
          " current value is: #{opts[:billing_mode]}"
      )
    end
  end
  if opts.key?(:provisioned_throughput)
    if opts[:billing_mode] == 'PAY_PER_REQUEST'
      raise ArgumentError.new(
        'when :provisioned_throughput option is specified, :billing_mode'\
          " must either be unspecified or have a value of 'PROVISIONED'"
      )
    end
  else
    if opts[:billing_mode] != 'PAY_PER_REQUEST'
      raise ArgumentError.new(
        'when :provisioned_throughput option is not specified,'\
          " :billing_mode must be set to 'PAY_PER_REQUEST'"
      )
    end
  end
end