Skip to content

Instantly share code, notes, and snippets.

@sco
Created February 1, 2009 21:09
Show Gist options
  • Save sco/56659 to your computer and use it in GitHub Desktop.
Save sco/56659 to your computer and use it in GitHub Desktop.
require 'net/http'
require 'rubygems'
require 'json'
# Mimics the interface of RightAws::SdbInterface, using CouchDB for persistence.
#
# FS = FakeSimpleDB.new('myapp')
# FS.create_domain('mydb')
# FS.put_attributes('mydb', 'myitem', { 'Jon' => ['foo', 'bar'] })
# FS.get_attributes('mydb', 'myitem')
# FS.delete_attributes('mydb', 'myitem')
# FS.delete_domain('mydb')
# TODO
# - handle existing items in put_attributes
# - handle replace on put_attributes
# - handle deleting just attributes, and specific attribute values
# sdb.delete_attributes 'family', 'toys', { 'Jon' => ['vodka', 'girls'], 'cat' => ['mice'] }
# sdb.delete_attributes 'family', 'toys', [ 'Jon', 'cat' ]
# - #query
#
class FakeSimpleDB
def initialize(namespace, host='localhost', port=5984)
@namespace = namespace
@http = Net::HTTP.new(host, port)
end
def create_domain(domain_name)
@http.put path(domain_name), ''
end
def delete_domain(domain_name)
@http.delete path(domain_name)
end
# all keys should be strings; all values should be arrays of strings
def put_attributes(domain_name, item_name, attributes, replace=false)
@http.put(path(domain_name, item_name), attributes.to_json, { "Content-Type" => "application/json" })
end
def get_attributes(domain_name, item_name, attribute_name=nil)
path = path(domain_name, item_name)
data = JSON::parse @http.get(path).read_body
{ :attributes => data }
end
def delete_attributes(domain_name, item_name, attributes=nil)
if attributes.nil?
rev = get_attributes(domain_name, item_name)[:attributes]['_rev']
@http.delete path(domain_name, item_name, :rev => rev)
else
end
end
# sdb.query('family', [ "['cat'=?] union ['dog'=?]", "clew", "Jon's boot" ])
#
# return a hash with a key named :items with an array of doc ids
# take a block and iterate with it
# handle query_expression as an array or a string
# handle max numbers
# handle next_tokens
#
# "['foo'='bar']"
#
# FS.query('mydb', "['Jon'='foo']")
#
def query(domain_name, query_expression=nil, max_number_of_items=nil, next_token=nil)
if query_expression.nil?
response = @http.get(path(domain_name, "_all_docs"), { "Content-Type" => "text/javascript" })
else
# TODO: parse query_expression into query_parts
query_parts = { :Jon => 'foo' }
conditions = query_parts.map { |k, v| "doc.#{k}.indexOf('#{v}')!=-1" }.join(' && ')
function = "function(doc) { if (#{conditions}) { map(null, doc._id); } }"
response = @http.post(path(domain_name, "_temp_view"), function, { "Content-Type" => "text/javascript" })
end
data = JSON::parse(response.read_body)
ids = data["rows"].map{ |row| row["id"] }
{ :items => ids }
end
private
def path(domain_name, item_name='', params={})
path = "/fsdb_#{@namespace}_#{domain_name}/#{item_name}"
path << '?' + params.map{ |k, v| "#{k}=#{v}" }.join('&') if params.any?
path
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment