Cushion: A slim CouchDB client

Cushion is a Ruby client for accessing CouchDB servers that’s light on the extras and heavy on the syntatical sugar.

Credit goes to CouchRest (github.com/jchris/couchrest/tree/master) for the inspiration.

Getting Started

# myapp.rb
require 'cushion'

db = Cushion!(:mydb)

Document Basics

Storing documents is simple. Just supply a hash of attributes. Leave out the _id attribute if you want to use an auto-generated UUID. Set the _rev attribute to update a document:

db.store("baz" => "bat")
# => {"ok"=>true, "id"=> "bdd39a3f9a1e5894d3d1283aa0d0f53f", "rev"=> "2699240268"}

response = db.store("_id" => "mydoc", "foo" => "bar")
# => {"ok"=>true, "id"=>"mydoc", "rev"=>"882534292"}

db.store("_id" => "mydoc", "foo" => "baz", "_rev" => response['rev'])
# => {"ok"=>true, "id"=>"mydoc", "rev"=>"3617508982"}

Fetching documents is just as simple.

db.key?("mydoc")    # => true
db.fetch("mydoc")   # => {"_id"=>"mydoc", "_rev"=>"3617508982", "foo"=>"baz"}
db.fetch("bogusid") # => raises RestClient::ResourceNotFound

# Use etags to perform a conditional GET
db.fetch("mydoc", :etag => cur_rev)  # => raises RestClient::NotModified

Store attachments inline or via CouchDB’s standalone attachment API. The standalone method accepts both IO objects and strings:

# Inline
db.store("_id" => "hasfiles", ..., "_attachments" => {
  "foo.txt" => {
    "content_type" => "text/plain",
    "data" => "Hello World!"
  }})

# Standalone
res = @db.store("_id" => "savemefirst", ...)
db.attach("savemefirst", "foo.txt", "Hello World!", :rev => res['rev'],
  :content_type => "text/plain")
# => Foo now contains an attachment hash similar to the above example

# Fetch attachment data
db.fetch("savemefirst", "foo.txt")  # => "Hello World!"

Cushion returns parsed JSON by default. In those cases where you need the raw JSON string, simply set an accept header:

db.fetch("mydoc", :headers => { :accept => "text/plain" })
# => "{\"_id\":\"mydoc\",\"_rev\":\"3617508982\",\"foo\":\"baz\"}\n"

The technique above works for nearly every Cushion request method.

Document Macros

You can use CouchDB’s bulk docs feature to create, update and delete many documents at once:

docs = [
  { "_id" => "0", "_rev" => "123456", "_deleted" => true }, #=> Delete
  { "_id" => "1", "_rev" => "32486671", "foo" => "bar" },   #=> Update
  { "_id" => "2", "baz" => "bat" }                          #=> Create
]

db.bulk(docs)                  # => returns a hash of updated documents
db.bulk(docs, :delete => true) # => deletes the selected docs

Documents and attachments may also be copied or moved within the same database. Some useful examples:

# Documents
db.copy("mydoc", "new_doc")
# => {"ok"=>true, "id"=>"new_doc", "rev"=> ...}
db.move("mydoc", "existing_doc", :rev => ..., :dest_rev => ...)
# => overwrites the existing doc

# Attachments
db.copy_attachment("mydoc", "foo.txt", "bar.txt")
# => copies an attachment within the same doc
db.move_attachment("mydoc", "foo.txt", "bar.txt")
# => renames an attachment; aliased at #rename_attachment

See the database specs for more copy and move examples.

Views

  • creating (design docs)

  • querying

  • temp views

Servers and Databases

The server location defaults to 127.0.0.1:5984, so you may omit the host when initializing a server if you are satisfied with the default.

NOTE: Some cruft needs cleaning up. Use Cushion!(dbname, opts) for now.

Display various bits of server metadata as follows:

server.info          #=> welcome message
server.all_dbs       #=> all dbs available
server.active_tasks  #=> running tasks (e.g., replication or compaction)
server.config        #=> server config
server.restart       #=> restart the server
server.stats         #=> detailed runtime stats

Cushion::Server can also replicate local and remote databases:

server.replicate("db1", "db2")
server.replicate("db1", "http://host2:5984/bar")

Creating database instances:

  • top level methods

  • options

DB Operations:

db.create
db.delete
db.compact

Cushion::Document

Tricks

Use the #headers method to obtain response headers on any request:

db.fetch("mydoc").headers
# => {:server=>"CouchDB/0.9.0a (Erlang OTP/R12B)", :etag=>"\"3617508982\"",
  :date=>"Fri, 06 Mar 2009 10:21:59 GMT", :content_type=>"application/json",
  :content_length=>"48", :cache_control=>"must-revalidate"}