by Matthew Lyon <firstname.lastname@example.org>
A CouchDB ODM (Object/Document Mapper) in Ruby.
Encourages per-“Account” databases. Actually, does not even currently provide a way to do a “singleton” or global database, however this is planned. Since a given class (say, “Article”) cannot know what database it is supposed to get/search from you cannot do classical class-based finders such as “Article.find('value')”. While it might be possible to pass in a database to use for some class-wide view, Exegesis takes the opinion that this is bad design for couchdb for the reasons that views may return multiple document types other than the desired class, and that views should be scoped to objects that mixin the database accessors.
CouchDB is table-less, and Exegesis's design reflects this. In CouchDB, Documents are retrieved by their unique id, or can be queried from a view function in a design document. Exegesis provides tools to aid this. Additionally, since view functions can be used for map/reduce computations against your documents, Exegesis helps you get non-document data out of your views.
class Account include Exegesis::Database # declares the existence of a design document named 'articles' # view functions will be loaded from 'views/articles/:viewname/*.js design :articles do docs :by_author docs :at_path docs :tagged_with hash :tags_count, :view => :tagged_with end end @account.articles.by_author('user-mattly') # performs GET '/_design/articles/_view/by_author?key="user-mattly"&include_docs=true&reduce=false' @account.articles.at_path('blog/2009'..'blog/2009/04/04') # transforms the range into startkey/endkey # performs GET '/_design/articles/_view/at_path?startkey="blog/2009"&endkey="blog/2009/04/04" # &include_docs=true&reduce=false' @account.articles.tags_count('couchdb') # performs GET '/_design/articles/_view/tagged_with?key="couchdb"&group=true' class Article include Exegesis::Document # defines readers, writers for given attributes expose :path, :title, :body, :tags expose :published_at, :writer => false, :as => Time timestamps! # will load the document at the id referenced by doc['author']; does not yet set writer. expose :author, :as => :reference end
RestClient 0.9 or later.
For running the tests:
MiniTest MiniTest is the default testing framework for Ruby 1.9 However, these tests require the trunk version, and my patches against the trunk version. The trunk version is here: github.com/seattlerb/minitest My patches are in my fork: github.com/mattly/minitest You will need to clone my repo and from its directory, do the following:
`rake gem` `sudo gem install pkg/minitest-1.3.1`
Once MiniTest 1.3.2 is released you should be able to use the standard gem.
The test suite creates and destroys a database for each test that requires access to the database. This is slow, and the test suite may take some time to run. However, I would rather the test suite be slow and accurate than quick and full of mocking or possibly error-prone deleting.