couchrest_model/README.md

197 lines
6.8 KiB
Markdown
Raw Normal View History

2009-01-11 11:27:22 +01:00
# CouchRest: CouchDB, close to the metal
2008-09-07 21:54:22 +02:00
2008-10-02 19:57:13 +02:00
CouchRest is based on [CouchDB's couch.js test
library](http://svn.apache.org/repos/asf/couchdb/trunk/share/www/script/couch.js),
2008-10-02 19:57:13 +02:00
which I find to be concise, clear, and well designed. CouchRest lightly wraps
CouchDB's HTTP API, managing JSON serialization, and remembering the URI-paths
to CouchDB's API endpoints so you don't have to.
2008-09-07 21:54:22 +02:00
2009-01-16 00:05:55 +01:00
CouchRest is designed to make a simple base for application and framework-specific object oriented APIs. CouchRest is Object-Mapper agnostic, the parsed JSON it returns from CouchDB shows up as subclasses of Ruby's Hash. Naked JSON, just as it was mean to be.
2008-09-07 21:54:22 +02:00
2009-04-16 21:20:17 +02:00
Note: CouchRest only support CouchDB 0.9.0 or newer.
2009-01-11 11:27:22 +01:00
## Easy Install
2008-09-07 21:54:22 +02:00
2009-07-17 20:07:23 +02:00
$ sudo gem install couchrest
Alternatively, you can install from Github:
$ gem sources -a http://gems.github.com (you only have to do this once)
2009-08-03 21:23:13 +02:00
$ sudo gem install couchrest-couchrest
2008-09-07 21:54:22 +02:00
2009-01-11 11:27:22 +01:00
### Relax, it's RESTful
2008-09-07 21:54:22 +02:00
2009-07-17 20:07:23 +02:00
CouchRest rests on top of a HTTP abstraction layer using by default Herokus excellent REST Client Ruby HTTP wrapper.
Other adapters can be added to support more http libraries.
2008-09-07 21:54:22 +02:00
2009-01-11 11:27:22 +01:00
### Running the Specs
2008-09-07 21:54:22 +02:00
2008-10-02 19:57:13 +02:00
The most complete documentation is the spec/ directory. To validate your
CouchRest install, from the project root directory run `rake`, or `autotest`
(requires RSpec and optionally ZenTest for autotest support).
2008-09-07 21:54:22 +02:00
2009-07-17 20:07:23 +02:00
## Examples (CouchRest Core)
2008-09-07 21:54:22 +02:00
Quick Start:
# with !, it creates the database if it doesn't already exist
2008-12-14 12:05:02 +01:00
@db = CouchRest.database!("http://127.0.0.1:5984/couchrest-test")
2009-01-29 08:04:22 +01:00
response = @db.save_doc({:key => 'value', 'another key' => 'another value'})
2008-09-07 21:54:22 +02:00
doc = @db.get(response['id'])
puts doc.inspect
Bulk Save:
@db.bulk_save([
{"wild" => "and random"},
{"mild" => "yet local"},
{"another" => ["set","of","keys"]}
])
# returns ids and revs of the current docs
puts @db.documents.inspect
Creating and Querying Views:
2009-01-29 08:04:22 +01:00
@db.save_doc({
2008-09-07 21:54:22 +02:00
"_id" => "_design/first",
:views => {
:test => {
:map => "function(doc){for(var w in doc){ if(!w.match(/^_/))emit(w,doc[w])}}"
}
}
})
puts @db.view('first/test')['rows'].inspect
2009-07-17 20:07:23 +02:00
## CouchRest::ExtendedDocument
CouchRest::ExtendedDocument is a DSL/ORM for CouchDB. Basically, ExtendedDocument seats on top of CouchRest Core to add the concept of Model.
ExtendedDocument offers a lot of the usual ORM tools such as optional yet defined schema, validation, callbacks, pagination, casting and much more.
### Model example
Check spec/couchrest/more and spec/fixtures/more for more examples
class Article < CouchRest::ExtendedDocument
use_database DB
unique_id :slug
2009-07-17 20:07:23 +02:00
view_by :date, :descending => true
view_by :user_id, :date
2009-07-17 20:07:23 +02:00
view_by :tags,
:map =>
"function(doc) {
if (doc['couchrest-type'] == 'Article' && doc.tags) {
doc.tags.forEach(function(tag){
emit(tag, 1);
});
}
}",
:reduce =>
"function(keys, values, rereduce) {
return sum(values);
}"
property :date
property :slug, :read_only => true
property :title
property :tags, :cast_as => ['String']
timestamps!
2009-07-17 20:07:23 +02:00
save_callback :before, :generate_slug_from_title
2009-07-17 20:07:23 +02:00
def generate_slug_from_title
2009-07-19 09:01:07 +02:00
self['slug'] = title.downcase.gsub(/[^a-z0-9]/,'-').squeeze('-').gsub(/^\-|\-$/,'') if new?
2009-07-17 20:07:23 +02:00
end
end
### Callbacks
`CouchRest::ExtendedDocuments` instances have 4 callbacks already defined for you:
`:validate`, `:create`, `:save`, `:update` and `:destroy`
`CouchRest::CastedModel` instances have 1 callback already defined for you:
`:validate`
Define your callback as follows:
set_callback :save, :before, :generate_slug_from_name
CouchRest uses a mixin you can find in lib/mixins/callbacks which is extracted from Rails 3, here are some simple usage examples:
set_callback :save, :before, :before_method
set_callback :save, :after, :after_method, :if => :condition
set_callback :save, :around {|r| stuff; yield; stuff }
2009-07-19 09:01:07 +02:00
Or the aliased short version:
2009-06-08 02:01:21 +02:00
before_save :before_method, :another_method
after_save :after_method, :another_method, :if => :condition
2009-06-08 02:01:21 +02:00
around_save {|r| stuff; yield; stuff }
2009-07-19 09:01:07 +02:00
To halt the callback, simply return a :halt symbol in your callback method.
Check the mixin or the ExtendedDocument class to see how to implement your own callbacks.
2009-09-03 05:12:16 +02:00
### Properties
property :last_name, :alias => :family_name
property :read_only_value, :read_only => true
2009-09-04 04:43:06 +02:00
property :name, :length => 4...20
property :price, :type => Integer
2009-11-01 13:47:48 +01:00
Attribute protection from mass assignment to CouchRest properties. There are two modes of protection:
2009-11-21 12:17:38 +01:00
1) Declare accessible properties, assume all the rest are protected
2009-11-01 13:47:48 +01:00
property :name, :accessible => true
property :admin # this will be automatically protected
2) Declare protected properties, assume all the rest are accessible
property :name # this will not be protected
property :admin, :protected => true
Note: you cannot set both flags in a single class
2009-09-03 05:12:16 +02:00
### Casting
Often, you will want to store multiple objects within a document, to be able to retrieve your objects when you load the document,
you can define some casting rules.
property :casted_attribute, :cast_as => 'WithCastedModelMixin'
property :keywords, :cast_as => ["String"]
property :occurs_at, :cast_as => 'Time', :init_method => 'parse
property :end_date, :cast_as => 'Date', :init_method => 'parse
If you want to cast an array of instances from a specific Class, use the trick shown above ["ClassName"]
### Pagination
Pagination is available in any ExtendedDocument classes. Here are some usage examples:
basic usage:
Article.all.paginate(:page => 1, :per_page => 5)
note: the above query will look like: `GET /db/_design/Article/_view/all?include_docs=true&skip=0&limit=5&reduce=false` and only fetch 5 documents.
Slightly more advance usage:
Article.by_name(:startkey => 'a', :endkey => {}).paginate(:page => 1, :per_page => 5)
note: the above query will look like: `GET /db/_design/Article/_view/by_name?startkey=%22a%22&limit=5&skip=0&endkey=%7B%7D&include_docs=true`
Basically, you can paginate through the articles starting by the letter a, 5 articles at a time.
Low level usage:
Article.paginate(:design_doc => 'Article', :view_name => 'by_date',
2009-07-17 20:07:23 +02:00
:per_page => 3, :page => 2, :descending => true, :key => Date.today, :include_docs => true)
## Ruby on Rails
CouchRest is compatible with rails and can even be used a Rails plugin.
However, you might be interested in the CouchRest companion rails project:
2009-07-19 09:01:07 +02:00
[http://github.com/hpoydar/couchrest-rails](http://github.com/hpoydar/couchrest-rails)