module TinyDyno::Adapter

Interactions with the DynamoDB store through aws-sdk-v2

Attributes

table_names[R]

Public Instance Methods

aws_attribute(field_type:, value:) click to toggle source
# File lib/tiny_dyno/adapter/attributes.rb, line 151
def aws_attribute(field_type:, value:)
  av = TinyDyno::Adapter::AttributeValue.new
  av.marshal(type: field_type, value: value)
end
connect() click to toggle source
# File lib/tiny_dyno/adapter.rb, line 18
def connect
  connection
  connected?
end
connected?() click to toggle source
# File lib/tiny_dyno/adapter.rb, line 23
def connected?
  begin
    connection.list_tables(limit: 1)
  rescue Errno::ECONNREFUSED, Aws::DynamoDB::Errors::UnrecognizedClientException => e
    return false
  end
  return true if @connection.class == Aws::DynamoDB::Client
  return false
end
create_table(create_table_request) click to toggle source

docs.aws.amazon.com/sdkforruby/api/Aws/DynamoDB/Client.html#create_table-instance_method expect create_table_request to conform to above schema

Send the actual table creation to DynamoDB

@example Create the table for the class

Person.create_table

@return [ true ] if the operation succeeds

# File lib/tiny_dyno/adapter/tables.rb, line 33
def create_table(create_table_request)
  table_settings = {
      provisioned_throughput: {
          read_capacity_units: 200,
          write_capacity_units: 200,
      },
  }.merge!(create_table_request)

  # Should or shouldn't we?
  # begin
  #   resp = connection.describe_table(table_name: table_settings[:table_name])
  # rescue Aws::DynamoDB::Errors::ResourceNotFoundException
  # ensure
  #   if resp.respond_to?(:table)
  #     p "Warning, table was already present : #{ table_settings[:table_name]}"
  #   end
  # end
  connection.create_table(table_settings)
  if wait_on_table_status(table_status: :table_exists, table_name: table_settings[:table_name])
    update_table_cache
    return true
  else
    return false
  end
end
delete_item(request:) click to toggle source
# File lib/tiny_dyno/adapter/items.rb, line 21
def delete_item(request:)
  connection.delete_item(request).successful?
end
delete_table(table_name:) click to toggle source
# File lib/tiny_dyno/adapter/tables.rb, line 59
def delete_table(table_name:)
  begin
    connection.describe_table(table_name: table_name)
  rescue Aws::DynamoDB::Errors::ResourceNotFoundException
    # table not there anyway
    return true
  end
  if wait_on_table_status(table_status: :table_exists, table_name: table_name)
    connection.delete_table(table_name: table_name)
  else
    return false
  end
  wait_on_table_status(table_status: :table_not_exists, table_name: table_name)
  update_table_cache
  return true unless table_exists?(table_name: table_name)
  return false
end
disconnect!() click to toggle source
# File lib/tiny_dyno/adapter.rb, line 33
def disconnect!
  @connection = nil
end
doc_attribute(value) click to toggle source
# File lib/tiny_dyno/adapter/attributes.rb, line 156
def doc_attribute(value)
  return nil if value.nil?
  av = TinyDyno::Adapter::AttributeValue.new
  av.unmarshal(value)
end
get_item(get_item_request:) click to toggle source
# File lib/tiny_dyno/adapter/items.rb, line 13
def get_item(get_item_request:)
  resp = connection.get_item(get_item_request)
  return nil if resp.item.nil?
  typed_attributes = {}
  resp.item.each {|k,v| typed_attributes[k] = TinyDyno::Adapter.doc_attribute(v) }
  typed_attributes
end
put_item(put_item_request:) click to toggle source
# File lib/tiny_dyno/adapter/items.rb, line 9
def put_item(put_item_request:)
  connection.put_item(put_item_request).successful?
end
query(body:) click to toggle source
# File lib/tiny_dyno/adapter.rb, line 37
def query(body:)
  @connection.query(body)
end
simple_attribute(field_type:, value:) click to toggle source
# File lib/tiny_dyno/adapter/attributes.rb, line 162
def simple_attribute(field_type:, value:)
  raw_attribute = aws_attribute(field_type: field_type, value: value)

  case field_type.to_s
    when 'Fixnum', 'Integer' then simple_value = doc_attribute(raw_attribute).to_i
    when 'Float' then simple_value = doc_attribute(raw_attribute).to_f
    when 'Numeric', 'String', 'Array', 'Hash', 'TinyDyno::Boolean' then simple_value = doc_attribute(raw_attribute)
  else
    raise ArgumentError, "unhandled type #{ field_type.inspect }"
  end
  simple_value
end
table_exists?(table_name:) click to toggle source

Answer, whether a table is present, first by cache lookup and if miss on datastore

@example Does the table exists?

TinyDyno::Adapter.table_exists?(table_name: Person.table_name)

@return [ true ] if the table is present

# File lib/tiny_dyno/adapter/tables.rb, line 17
def table_exists?(table_name:)
  return true if @table_names.include?(table_name)
  update_table_cache
  @table_names.include?(table_name)
end
update_item(update_item_request:) click to toggle source
# File lib/tiny_dyno/adapter/items.rb, line 5
def update_item(update_item_request:)
  connection.update_item(update_item_request).successful?
end
update_table_cache() click to toggle source

Hold a cache of available table names in an instance variable

# File lib/tiny_dyno/adapter/tables.rb, line 79
def update_table_cache
  return unless connected?
  new_table_names = connection.list_tables.table_names
  @table_names = new_table_names
end

Protected Instance Methods

connection() click to toggle source
# File lib/tiny_dyno/adapter.rb, line 43
def connection
  unless @connection
    TinyDyno.logger.info 'setting up new connection ... ' if TinyDyno.logger
    @connection =  Aws::DynamoDB::Client.new(simple_attributes: false)
    update_table_cache
  end
  @connection
end

Private Instance Methods

wait_on_table_status(table_status:, table_name:) click to toggle source

Use the aws-sdk provided waiter methods to wait on either table_exists, table_not_exists

# File lib/tiny_dyno/adapter/tables.rb, line 89
def wait_on_table_status(table_status:, table_name:)
  begin
    connection.wait_until(table_status, table_name: table_name) do |w|
      w.interval = 1
      w.max_attempts = 10
    end
  rescue Aws::Waiters::Errors => e
    p "Waiter failed: #{ e .inspect }"
    return false
  end
  return true
end