Skip to content

Instantly share code, notes, and snippets.

@chaslemley
Created January 23, 2012 15:17
Show Gist options
  • Save chaslemley/1663672 to your computer and use it in GitHub Desktop.
Save chaslemley/1663672 to your computer and use it in GitHub Desktop.
Example of using Amazon's DynamoDB to store user activity
require "aws-sdk"
class Dynamo
attr_accessor :attributes
def initialize(hash)
raise ArgumentError, "argument passed to .new must be a Hash" unless hash.is_a? Hash
raise ArgumentError, "hash must contain key :#{self.class.hash_key}" unless hash.has_key? self.class.hash_key.to_sym
raise ArgumentError, "hash must contain key :#{self.class.range_key}" unless self.class.has_range_key? && hash.has_key?(self.class.range_key.to_sym)
@attributes = {}
@attributes[self.class.hash_key] = hash[self.class.hash_key]
@attributes[self.class.range_key] = hash[self.class.range_key] if self.class.has_range_key?
self.class.fields.each do |f|
key, type = f
raise ArgumentError, "hash must contain key :#{key}" unless hash.has_key? key
@attributes[key] = hash[key]
end
end
def save
self.class.table.items.put(@attributes)
end
class << self
attr_accessor :table_name, :hash_key, :range_key, :fields
def table_name(table_name = nil)
@table_name = table_name
end
def has_range_key?
!@range_key.nil?
end
def hash_key(key_name = nil, key_type = nil)
return @hash_key unless key_name && key_type
@hash_key = key_name
@hash_key_type = key_type
end
def range_key(key_name = nil, key_type = nil)
return @range_key unless key_name && key_type
@range_key = key_name
@range_key_type = key_type
end
def fields
@fields ||= []
end
def field(key, type)
@fields ||= []
@fields << [key, type]
end
def count
table.items.count
end
def find(hash_key_value, range_from = nil, range_to = nil)
query_hash = build_query_hash(hash_key_value, range_from, range_to)
table.items.query(query_hash).find_all
end
def build_query_hash(hash_key_value, range_from = nil, range_to = nil)
query_hash = {hash_value: hash_key_value}
query_hash[:range_greater_than] = range_from if range_from
query_hash[:range_less_than] = range_to if range_to
query_hash
end
def schema
schema = {}
schema[:hash_key] = {}
schema[:hash_key][@hash_key] = @hash_key_type
schema[:range_key] = {}
schema[:range_key][@range_key] = @range_key_type
schema
end
def table
@table ||= lambda {
dynamo.tables.create(@table_name.to_s,5,5,schema) rescue nil
table = dynamo.tables[@table_name.to_s]
table.load_schema
table
}.call
end
def dynamo
@dynamo ||= lambda {
sts = AWS::STS.new(
access_key_id: AMAZON_AWS_ACCESS_KEY_ID,
secret_access_key: AMAZON_AWS_SECRET_ACCESS_KEY
)
session = sts.new_session
AWS::DynamoDB.new(session.credentials)
}.call
end
end
end
class UserActivity < Dynamo
table_name :user_activity
hash_key :user_id, :number
range_key :time, :number
field :event_type, :string
end
start_time = Time.now.to_f
# create some user login events
10.times do
time = Time.now.to_f
puts "saving at: #{time}"
UserActivity.new({
user_id: 4,
time: time,
event_type: "login"
}).save
end
puts ""
# load the data since we started adding it should return 10 results
puts "Saved " + UserActivity.find(4, start_time, nil).count.to_s + " records since #{start_time}"
puts "user_activity table has " + UserActivity.count.to_s + " total records"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment