Every repository with this icon (
Every repository with this icon (
| name | age | message | |
|---|---|---|---|
| |
CREDITS | Sun Sep 21 09:54:21 -0700 2008 | |
| |
INSTALL | Sun Oct 26 08:13:16 -0700 2008 | |
| |
MIT-LICENSE.txt | Fri Oct 24 10:48:11 -0700 2008 | |
| |
README.textile | ||
| |
Rakefile | ||
| |
TODO | Sun Oct 26 09:46:51 -0700 2008 | |
| |
couch_potato.gemspec | ||
| |
init.rb | ||
| |
lib/ | ||
| |
spec/ |
Couch Potato
… is a persistence layer written in ruby for CouchDB.
Mission
The goal of Couch Potato is to create a migration path for users of ActiveRecord and other object relational mappers to port their applications to CouchDB. It therefore offers a basic set of the functionality provided by most ORMs and adds functionality unique to CouchDB on top.
Core Features
Couch Potato is a work in progress so this list will hopefully grow over time.
- persisting objects by including the CouchPotato::Persistence module
- has_many/belongs_to relationships between persistant objects
- atomic write operations spanning multiple objects using bulk save queues
- extensive spec suite
- included versioning support via the CouchPotato::Versioning module
- included ordered lists support via the CouchPotato::Ordering module
Installation
Couch Potato is hosted as a gem on github which you can install like this:
sudo gem source —add http://gems.github.com # if you haven’t alread sudo gem install langalex-couch_potatoTo use it in your ruby application:
require ‘rubygems’ gem ‘couch_potato’ require ‘couch_potato’ CouchPotato::Config.database_name = ‘name of the db’Alternatively you can download or clone the source repository and then require lib/couhc_potato.rb. If you are using Rails you can also install Couch Potato directly as a plugin. Then create a RAILS_ROOT/config/couchdb.yml file that looks like this:
- couchdb.yml
test: test_db_name
development: development_db_name
production: production_db_name
Introduction
This is a basic tutorial on how to use Couch Potato. If you want to know all the details feel free to read the specs.
Save, load objects
First you need a class.
class User endTo make instances of this class persistent include the persistence module:
class User include CouchPotato::Persistence endIf you want to store any properties you have to declare them:
class User include CouchPotato::Persistence property :name endNow you can save your objects:
user = User.new :name => ‘joe’ user.save # or save!Properties:
user.name # => ‘joe’ user.name = {:first => [‘joe’, ‘joey’], :last => ‘doe’, :middle => ’J’} # you can set any ruby object that responds_to :to_json (includes all core objects) user._id # => “02097f33a0046123f1ebc0ebb6937269” user._rev # => “2769180384” user.created_at # => Fri Oct 24 19:05:54 +0200 2008 user.updated_at # => Fri Oct 24 19:05:54 +0200 2008 user.new_document? # => false, for compatibility new_record? will work as wellYou can of course also retrieve your instance:
User.get “02097f33a0046123f1ebc0ebb6937269” # => <#User 0×3075>Object validations
Couch Potato uses the validatable library for vaidation (http://validatable.rubyforge.org/)\
class User property :name validates_presence_of :name end user = User.new user.valid? # => false user.errors.on(:name) # => [:name, ’can’t be blank’]Finding stuff
For running basic finds (e.g. creating/querying views) you can either use the CouchPotato::Persistence::Finder class:
joe = User.create! :first_name => ‘joe’, :position => 1 jane = User.create! :first_name => ‘jane’, :position => 2 Finder.new.find User, :first_name => ‘joe’ # => [joe] Finder.new.find User, :first_name => [‘joe’, ‘jane’] # => [joe, jane] Finder.new.find User, :position => 1..2 # => [joe, jane]You can also count:
user = User.create! :first_name => ‘joe’ Finder.new.count User, :first_name => ‘joe’ # => 1Or you can call first/all/count on a class persistent class which will call the Finder.find, e.g.:
User.first :login => ‘alex’ User.all User.count :activated => trueBe warned though that executing these finder methods will generate a new view for every new combination of class and attribute names it gets called with, so you really don’t want to use this in a console on a production system.
Support for more sophisticated views will be added later.
Associations
As of now has_many and belongs_to are supported. By default the associated objects are stored in separate documents linked via foreign keys just like in relational databases.
class User has_many :addresses, :dependent => :destroy end class Address belongs_to :user property :street end user = User.new user.addresses.build :street => ‘potato way’ user.addresses.first # => <#Address 0×987> user.addresses.create! # raises an exception as street is blank user.addresses.first.user == user # => trueAs CouchDB can not only store flat structures you also store associations inline:
class User has_many :addresses, :stored => :inline endThis will store the addresses of the user as an array within your CouchDB document.
callbacks
Couch Potato supports the usual lifecycle callbacks known from ActiveRecord:
class User include CouchPotato::Persistence before_create :do_something_before_create after_update :do_something_else endThis will call the method do_something_before_create before creating an object and do_something_else after updating one. Supported callbacks are: :before_validation_on_create, :before_validation_on_update, :before_validation_on_save, :before_create, :after_create, :before_update, :after_update, :before_save, :after_save, :before_destroy, :after_destroy
If you want to do any CouchDB update/create/delete operation in your callback methods…
class User include CouchPotato::Persistence has_many :comments before_update :create_a_comment private def create_a_comment comments.create :body => ‘i was updated’ end end… and you want the entire operation including its hooks to be atomic you can do this:
class User include CouchPotato::Persistence has_many :comments before_update :create_a_comment private def create_a_comment bulk_save_queue << Comment.new(:body => ‘i was updated’) end endVersioning
Couch Potato supports versioning your objects, very similar to the popular acts_as_versioned plugin for ActiveRecord. To use it include the module:
class Document include CouchPotato::Persistence include CouchPotato::Versioning endAfter that your object will have a version that gets incremented on each save.
doc = Document.create doc.version # => 1 doc.save doc.version # => 2You can access the older versions via the versions method.
doc.versions.first.version # => 1When passing a version number the version method will only return that version:
doc.versions(1).version # => 1You can set a condition for when to create a new version:
class Document attr_accessor :update_version include CouchPotato::Persistence include CouchPotato::Versioning set_version_condition lambda {|doc| doc.update_version} end doc = Document.create doc.update_version = false doc.version # => 1 doc.save doc.version # => 1 doc.update_version = true doc.save doc.version # => 2Ordered Lists
Couch Potato supports ordered lists for has_many relationships (with the :stored => :separately option only), very similar to the popular acts_as_list plugin for ActiveRecord. To use it include the module:
class PersistenArray include CouchPotato::Persistence has_many :items end class Item include CouchPotato::Ordering belongs_to :persistent_array set_ordering_scope :persistent_array_id end array = PersistenArray.new item1 = array.items.create! item1.position # => 1 item2 = array.items.create! item2.position # => 2You can move items up and down simply by changing the position:
item2.position = 1 item2.save! item1.position # => 2And you can insert new items at any position you want:
item3 = array.items.create! :position => 2 item1.position # => 3And remove:
item3.destroy item1.position # => 2Helping out
Please fix bugs, add more specs, implement new features by forking the github repo at http://github.com/langalex/couch_potato.
You can run all the specs by calling rake with no options in the root folder of Couch Potato. The specs require a running CouchDB instance at http://localhost:5984
I will only accept patches that are covered by specs – sorry.
Contact
If you have any questions/suggestions etc. please contact me at alex at upstream-berlin.com or @langalex on twitter.








