CouchRest::Model - ORM, the CouchDB way

2008/09/30 17:05:32 +0000

There are a few ActiveRecord-style wrappers for CouchDB out there these days, but many of them have fallen behind as CouchDB's powers have increased. I've taken an interest in writing regular old web apps again - so now is the time when CouchRest grows wings and flies to the vaulted heights of DataMapper and ActiveRecord. (I could have written a DataMapper adapter for CouchDB, but much of DataMapper's code is based around SQL-like problems that CouchDB just doesn't have.) CouchRest::Model provides the ease-of-use Rubyists have come to expect from their ORMs, and it does it in CouchDB style.

h3. Getting Started

Here is an example (taken from the bright shiny new documentation) of what your Models can look like. If you click through to the actual blog post, there is also a longer example pasted as a gist embed which details the capabilities of the view-generation system even more.



class Article < CouchRest::Model

use_database CouchRest.database!('http://localhost:5984/couchrest-model-test')
unique_id :slug

view_by :date, :descending => true
view_by :user_id, :date

view_by :tags,
:map =>
"function(doc) {
if (doc.type == 'Article' && doc.tags) {
doc.tags.forEach(function(tag){
emit(tag, 1);
});
}
}",
:reduce =>
"function(keys, values, rereduce) {
return sum(values);
}"

key_reader :slug, :created_at, :updated_at
key_accessor :title, :tags

# You can make dates work nice without magic or special fields
key_writer :date
def date
Time.parse(@doc['date'])
end

timestamps!

before(:create, :generate_slug_from_title)
def generate_slug_from_title
doc['slug'] = title.downcase.gsub(/[a-z0-9]/,'-').squeeze('-').gsub(/\-|\-$/,'')
end
end



You can do the standard CRUD:


@post = Post.get(params[:id])
@post.title = "New Title"
@post.save


h3. View Generation

The view generation system is what I'm proudest of. It's designed to be performant, and it strikes a balance between magic and usability. Simple views are as easy to declare as:


view_by :date, :descending => true


They can be queried easily like this:

  1. get the 10 most recent posts
    @posts = Post.by_date :count => 10
  2. get the raw view
    @view = Post.by_date :count => 10, :raw => true


Views defined in this way take all the options of a CouchRest::Database#view call, and those options can be provided either as defaults at definition time, or overriden at query time. There is an additional option, :raw, which defaults to false. When :raw is true, you get back just what CouchDB sends. When :raw is false, CouchRest::Model::MagicViews requests the associated document for each view row, and gives you an array of documents. W00t!

CouchRest::Model views use _design documents, not temp views, so they take advantage of all the performance CouchDB has to offer.

Views can also be manually composed, if you want to write something that's more complex than the built-in helpers can provide.

If you're at the permalink page for this post, you'll see a Gist embed here with an even longer example of CouchRest::Model in action.



Enjoy!