Module: Dynamoid::Adapter

Extended by:
Adapter
Included in:
Adapter
Defined in:
lib/dynamoid/adapter.rb,
lib/dynamoid/adapter/local.rb,
lib/dynamoid/adapter/aws_sdk.rb

Overview

Adapter provides a generic, write-through class that abstracts variations in the underlying connections to provide a uniform response to Dynamoid.

Defined Under Namespace

Modules: AwsSdk, Local

Instance Attribute Summary (collapse)

Instance Method Summary (collapse)

Dynamic Method Handling

This class handles dynamic methods through the method_missing method

- (Object) method_missing(method, *args)

Delegate all methods that aren't defind here to the underlying adapter.

Since:

  • 0.2.0



169
170
171
172
# File 'lib/dynamoid/adapter.rb', line 169

def method_missing(method, *args)
  return benchmark(method, *args) {adapter.send(method, *args)} if @adapter.respond_to?(method)
  super
end

Instance Attribute Details

- (Object) tables

Returns the value of attribute tables



8
9
10
# File 'lib/dynamoid/adapter.rb', line 8

def tables
  @tables
end

Instance Method Details

- (Object) adapter

The actual adapter currently in use: presently, either AwsSdk or Local.

Since:

  • 0.2.0



13
14
15
16
# File 'lib/dynamoid/adapter.rb', line 13

def adapter
  reconnect! unless @adapter
  @adapter
end

- (Object) benchmark(method, *args) { ... }

Shows how long it takes a method to run on the adapter. Useful for generating logged output.

Parameters:

  • method (Symbol)

    the name of the method to appear in the log

  • args (Array)

    the arguments to the method to appear in the log

Yields:

  • the actual code to benchmark

Returns:

  • the result of the yield

Since:

  • 0.2.0



37
38
39
40
41
42
# File 'lib/dynamoid/adapter.rb', line 37

def benchmark(method, *args)
  start = Time.now
  result = yield
  Dynamoid.logger.info "(#{((Time.now - start) * 1000.0).round(2)} ms) #{method.to_s.split('_').collect(&:upcase).join(' ')}#{ " - #{args.inspect}" unless args.nil? || args.empty? }"
  return result
end

- (Object) delete(table, id, options = {})

Delete an item from a table. If partitioning is turned on, deletes all partitioned keys as well.

Parameters:

  • table (String)

    the name of the table to write the object to

  • id (String)

    the id of the record

  • range_key (Number)

    the range key of the record

Since:

  • 0.2.0



98
99
100
101
102
103
104
105
106
# File 'lib/dynamoid/adapter.rb', line 98

def delete(table, id, options = {})
  if Dynamoid::Config.partitioning?
    benchmark('Delete Item', id) do
      id_with_partitions(id).each {|i| delete_item(table, i, options)}
    end
  else
    benchmark('Delete Item', id) {delete_item(table, id, options)}
  end
end

- (Object) id_with_partitions(ids)

Takes a list of ids and returns them with partitioning added. If an array of arrays is passed, we assume the second key is the range key and pass it in unchanged.

Examples:

Partition id 1

Dynamoid::Adapter.id_with_partitions(['1']) # ['1.0', '1.1', '1.2', ..., '1.199']

Partition id 1 and range_key 1.0

Dynamoid::Adapter.id_with_partitions([['1', 1.0]]) # [['1.0', 1.0], ['1.1', 1.0], ['1.2', 1.0], ..., ['1.199', 1.0]]

Parameters:

  • ids (Array)

    array of ids to partition

Since:

  • 0.2.0



143
144
145
# File 'lib/dynamoid/adapter.rb', line 143

def id_with_partitions(ids)
  Array(ids).collect {|id| (0...Dynamoid::Config.partition_size).collect{|n| id.is_a?(Array) ? ["#{id.first}.#{n}", id.last] : "#{id}.#{n}"}}.flatten(1)
end

- (Object) read(table, ids, options = {})

Read one or many keys from the selected table. This method intelligently calls batch_get or get on the underlying adapter depending on whether ids is a range or a single key: additionally, if partitioning is enabled, it batch_gets all keys in the partition space automatically. Finally, if a range key is present, it will also interpolate that into the ids so that the batch get will acquire the correct record.

Parameters:

  • table (String)

    the name of the table to write the object to

  • ids (Array)

    to fetch, can also be a string of just one id

  • range_key (Number)

    the range key of the record

Since:

  • 0.2.0



70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
# File 'lib/dynamoid/adapter.rb', line 70

def read(table, ids, options = {})
  range_key = options[:range_key]
  if ids.respond_to?(:each)
    ids = ids.collect{|id| range_key ? [id, range_key] : id}
    if Dynamoid::Config.partitioning?
      results = benchmark('Partitioned Batch Get Item', ids) {batch_get_item(table => id_with_partitions(ids))}
      {table => result_for_partition(results[table])}
    else
      benchmark('Batch Get Item', ids) {batch_get_item(table => ids)}
    end
  else
    if Dynamoid::Config.partitioning?
      ids = range_key ? [[ids, range_key]] : ids
      results = benchmark('Partitioned Get Item', ids) {batch_get_item(table => id_with_partitions(ids))}
      result_for_partition(results[table]).first
    else
      benchmark('Get Item', ids) {get_item(table, ids, options)}
    end
  end
end

- (Object) reconnect!

Establishes a connection to the underyling adapter and caches all its tables for speedier future lookups. Issued when the adapter is first called.

Since:

  • 0.2.0



21
22
23
24
25
26
# File 'lib/dynamoid/adapter.rb', line 21

def reconnect!
  require "dynamoid/adapter/#{Dynamoid::Config.adapter}" unless Dynamoid::Adapter.const_defined?(Dynamoid::Config.adapter.camelcase)
  @adapter = Dynamoid::Adapter.const_get(Dynamoid::Config.adapter.camelcase)
  @adapter.connect! if @adapter.respond_to?(:connect!)
  self.tables = benchmark('Cache Tables') {list_tables}
end

- (Object) result_for_partition(results)

Takes an array of results that are partitioned, find the most recently updated one, and return only it. Compares each result by their id and updated_at attributes; if the updated_at is the greatest, then it must be the correct result.

Parameters:

  • returned (Array)

    partitioned results from a query

Since:

  • 0.2.0



153
154
155
156
157
158
159
160
161
162
163
164
# File 'lib/dynamoid/adapter.rb', line 153

def result_for_partition(results)
  {}.tap do |hash|
    Array(results).each do |result|
      next if result.nil?
      id = result[:id].split('.').first
      if !hash[id] || (result[:updated_at] > hash[id][:updated_at])
        result[:id] = id
        hash[id] = result
      end
    end
  end.values
end

- (Object) scan(table, query, opts = {})

Scans a table. Generally quite slow; try to avoid using scan if at all possible.

Parameters:

  • table (String)

    the name of the table to write the object to

  • scan_hash (Hash)

    a hash of attributes: matching records will be returned by the scan

Since:

  • 0.2.0



114
115
116
117
118
119
120
121
# File 'lib/dynamoid/adapter.rb', line 114

def scan(table, query, opts = {})
  if Dynamoid::Config.partitioning?
    results = benchmark('Scan', table, query) {adapter.scan(table, query, opts)}
    result_for_partition(results)
  else
    adapter.scan(table, query, opts)
  end
end

- (Object) write(table, object)

Write an object to the adapter. Partition it to a randomly selected key first if necessary.

Parameters:

  • table (String)

    the name of the table to write the object to

  • object (Object)

    the object itself

Returns:

  • (Object)

    the persisted object

Since:

  • 0.2.0



52
53
54
55
56
57
58
# File 'lib/dynamoid/adapter.rb', line 52

def write(table, object)
  if Dynamoid::Config.partitioning? && object[:id]
    object[:id] = "#{object[:id]}.#{Random.rand(Dynamoid::Config.partition_size)}"
    object[:updated_at] = Time.now.to_f
  end
  benchmark('Put Item', object) {put_item(table, object)}
end