couchrest_model/lib/couchrest/core/database.rb
2008-09-30 17:22:54 -07:00

129 lines
4.1 KiB
Ruby

require 'cgi'
require "base64"
module CouchRest
class Database
attr_reader :server, :host, :name, :root
# Create a CouchRest::Database adapter for the supplied CouchRest::Server and database name.
#
# ==== Parameters
# server<CouchRest::Server>:: database host
# name<String>:: database name
#
def initialize server, name
@name = name
@server = server
@host = server.uri
@root = "#{host}/#{name}"
end
# returns the database's uri
def to_s
@root
end
# GET the database info from CouchDB
def info
CouchRest.get @root
end
# Query the <tt>_all_docs</tt> view. Accepts all the same arguments as view.
def documents params = nil
url = CouchRest.paramify_url "#{@root}/_all_docs", params
CouchRest.get url
end
# POST a temporary view function to CouchDB for querying. This is not recommended, as you don't get any performance benefit from CouchDB's materialized views. Can be quite slow on large databases.
def temp_view funcs, params = nil
url = CouchRest.paramify_url "#{@root}/_temp_view", params
JSON.parse(RestClient.post(url, funcs.to_json, {"Content-Type" => 'application/json'}))
end
# Query a CouchDB view as defined by a <tt>_design</tt> document. Accepts paramaters as described in http://wiki.apache.org/couchdb/HttpViewApi
def view name, params = nil
url = CouchRest.paramify_url "#{@root}/_view/#{name}", params
CouchRest.get url
end
# GET a document from CouchDB, by id. Returns a Ruby Hash.
def get id
slug = CGI.escape(id)
CouchRest.get "#{@root}/#{slug}"
end
# GET an attachment directly from CouchDB
def fetch_attachment doc, name
doc = CGI.escape(doc)
name = CGI.escape(name)
RestClient.get "#{@root}/#{doc}/#{name}"
end
# PUT an attachment directly to CouchDB
def put_attachment doc, name, file, options = {}
docid = CGI.escape(doc['_id'])
name = CGI.escape(name)
uri = if doc['_rev']
"#{@root}/#{docid}/#{name}?rev=#{doc['_rev']}"
else
"#{@root}/#{docid}/#{name}"
end
JSON.parse(RestClient.put(uri, file, options))
end
# Save a document to CouchDB. This will use the <tt>_id</tt> field from the document as the id for PUT, or request a new UUID from CouchDB, if no <tt>_id</tt> is present on the document. IDs are attached to documents on the client side because POST has the curious property of being automatically retried by proxies in the event of network segmentation and lost responses.
def save doc
if doc['_attachments']
doc['_attachments'] = encode_attachments(doc['_attachments'])
end
if doc['_id']
slug = CGI.escape(doc['_id'])
CouchRest.put "#{@root}/#{slug}", doc
else
begin
slug = doc['_id'] = @server.next_uuid
CouchRest.put "#{@root}/#{slug}", doc
rescue #old version of couchdb
CouchRest.post @root, doc
end
end
end
# POST an array of documents to CouchDB. If any of the documents are missing ids, supply one from the uuid cache.
def bulk_save docs
ids, noids = docs.partition{|d|d['_id']}
uuid_count = [noids.length, @server.uuid_batch_count].max
noids.each do |doc|
nextid = @server.next_uuid(uuid_count) rescue nil
doc['_id'] = nextid if nextid
end
CouchRest.post "#{@root}/_bulk_docs", {:docs => docs}
end
# DELETE the document from CouchDB that has the given <tt>_id</tt> and <tt>_rev</tt>.
def delete doc
slug = CGI.escape(doc['_id'])
CouchRest.delete "#{@root}/#{slug}?rev=#{doc['_rev']}"
end
# DELETE the database itself. This is not undoable and could be rather catastrophic. Use with care!
def delete!
CouchRest.delete @root
end
private
def encode_attachments attachments
attachments.each do |k,v|
next if v['stub']
v['data'] = base64(v['data'])
end
attachments
end
def base64 data
Base64.encode64(data).gsub(/\s/,'')
end
end
end