DynamoRecord

Provides helpful rake tasks and model extensions on top of aws-record.

Installation

Add this line to your application's Gemfile:

gem 'dynamo-record'

And then execute:

$ bundle

Or install it yourself as:

$ gem install dynamo-record

Usage

Models

In app/models, create a class that includes DynamoRecord::Model and contains one or more of the standard set of attribute declarations, along with the following new composite attribute types:

  • composite_string_attr
  • composite_integer_attr

An example file:

class MyModel
  include DynamoRecord::Model
  composite_string_attr(
    :model_key,
    hash_key: true,
    parts: [:model_id, :account_id]
  )
  integer_attr :position, range_key: true
  string_attr  :user_id
  float_attr   :score
  map_attr     :map_value
end

The partition key is labeled with hash_key: true. The sort key is labeled with range_key: true.

Declaring secondary indexes are included in aws-record and are defined here.

As an example, a global secondary index can be defined as follows:

  global_secondary_index(
    :user_idx,
    hash_key: :user_id,
    range_key: :score,
    projection: {
      projection_type: 'INCLUDE',
      non_key_attributes: [
        :map_value
      ]
    }
  )

As an example, a local secondary index can be defined as follows:

  local_secondary_index(
    :score_idx,
    range_key: :score,
    projection: {
      projection_type: 'INCLUDE',
      non_key_attributes: [
        :map_value
      ]
    }
  )

The full documentation for projection_type and non_key_attributes can be found here.

Query Helpers

Query helpers are included as class methods.

  • composite_key(*args)

For models that have composite attributes, create a composite key value from the individual attribute parts:

hash_key = MyModel.composite_key('model_1', 'account_1')
  • split_composite(string)

Split a composite attribute value into its individual attribute parts:

model_id, acccount_id = MyModel.split_composite(hash_key)
  • find_all_by_hash_key(hash_key_value, opts = {})

Find all item instances that match a given hash key value. opts are options passed to the underlying query.

MyModel.find_all_by_hash_key(hash_key)
  • find_all_by_gsi_hash_key(gsi_name, hash_key_value, opts = {})

Find all item instances using a global secondary instance using a hash key value. opts are options passed to the underlying query.

MyModel.find_all_by_gsi_hash_key('user_idx', 'user_1')
  • find_all_by_gsi_hash_and_range_keys(gsi_name, hash_key_value, range_key_value)

Find all item instances using a global secondary instance using a hash key value and range key value.

MyModel.find_all_by_gsi_hash_key('user_idx', 'user_1', 0.0)
  • find_all_by_lsi_hash_key(lsi_name, hash_key_value, opts = {})

Find all item instances using a local secondary instance using a hash key value. opts are options passed to the underlying query.

MyModel.find_all_by_lsi_hash_key('score_idx', 'user_1')
  • find_all_by_lsi_hash_and_range_keys(lsi_name, hash_key_value, range_key_value)

Find all item instances using a local secondary instance using a hash key value and range key value.

MyModel.find_all_by_lsi_hash_key('score_idx', 'user_1', 0.0)

Migrations

Dynamo migration files are stored in db/dynamo_migrate. The name of the file follows the style of standard Rails migration files like YYYYMMDDHHMMSS_create_model_1.rb. A migration file that creates a Dynamo table looks like:

module DynamoMigrate
  class CreateMyModel < DynamoRecord::TableMigration
    def self.up
      migrate(MyModel) do |migration|
        migration.create!(
          provisioned_throughput: {
            read_capacity_units: 1,
            write_capacity_units: 1
          },
          global_secondary_index_throughput: {
            user_idx: {
              read_capacity_units: 1,
              write_capacity_units: 1
            }
          }
        )
      end
    end
  end
end

Note that the throughput of the table can be configured separately from the throughput of the secondary index.

A migration file that creates a Dynamo stream looks like:

module DynamoMigrate
  class AddMyModelStream < DynamoRecord::TableMigration
    def self.update
      add_stream(MyModel)
    end
  end
end