public
Last active

  • Download Gist
couch_foo_overview.rb
Ruby
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85
require 'couch_foo'
 
## Setup code. Put this in an initializer to set up a database connection.
 
CouchFoo::Base.set_database(:host => "http://localhost:5984",
:database => "couch_foo_example")
 
# Uncomment this line if you are using Rails
#CouchFoo::Base.logger = Rails.logger
 
## Examples of models
 
class User < CouchFoo::Base
property :name, String
property :handle, String
property :email, String
property :created_at, Time
# Type declarations are encouraged but are now required. Properties can be
# given with no declared type. Values for those properties will be
# serialized and stored inside a string value.
 
has_many :posts
end
 
class Post < CouchFoo::Base
property :title, String
property :text, String
property :user_id, String
property :created_at, Time
 
belongs_to :user
 
# Views can be defined explicitly. This map function creates a view that
# indexes documents by content length.
view :length, <<-EOF
function(doc) {
if (doc.ruby_class == "#{self.class.name}" && doc.text) {
emit(doc.text.length, doc);
}
}
EOF
end
 
 
## couch_foo in action
 
user = User.create(:name => "Jesse", :handle => "hallettj")
 
# Associations are handled transparently.
 
user.posts.create(:title => "First Post", :text => "Hello, world!")
 
# Views are created on demand. This query implicitly creates a 'title' view.
 
post = Post.find(:first, :conditions => { :title => "First Post" })
 
# Elegant API for retrieving multiple documents.
short_posts = Post.find(:all, :conditions => { :length => 0..140 })
long_posts = Post.find(:all, :use_key => :length, :startkey => 141)
 
# All of the views created through a given class are stored in one design
# document with a matching name. Thus model classes map to design documents.
 
# Supports transactions via CouchDB's bulk API
 
Post.bulk_save_default = true
 
(2..1000).each do |i|
Post.create(:user => user, :title => "Post ##{i}", :text => Array.new(i, "post").join(" "))
end
Post.database.commit
 
Post.bulk_save_default = false
 
# Sort based on a column other than the lookup key. Normally query results are
# sorted by the lookup key. In this case CouchFoo 'cheats' by creating a view
# with keys that are a composite of two fields.
 
Post.find(:all, :use_key => [:title, :user_id], :conditions => { :user_id => user.id })
 
# Retrieve records that match a set of discrete keys. This requires CouchDB >= 0.9.
 
User.find(:all, :conditions => { :handle => ['hallettj', 'igalko', 'pdxruby'] })
couchrest_overview.rb
Ruby
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124
## Examples copied from the CouchRest examples directory.
## examples/model/example.rb
 
require 'couchrest'
 
def show obj
puts obj.inspect
puts
end
 
## Setup code. Put this in an initializer to set up a database connection.
 
COUCHDB_SERVER = CouchRest.new
COUCHDB_SERVER.default_database = 'couchrest-extendeddoc-example'
 
 
## Examples of CouchRest models.
 
class Author < CouchRest::ExtendedDocument
use_database COUCHDB_SERVER.default_database
property :name
end
 
class Post < CouchRest::ExtendedDocument
use_database COUCHDB_SERVER.default_database
property :title
property :body
property :author, :cast_as => 'Author'
 
timestamps!
end
 
class Comment < CouchRest::ExtendedDocument
use_database COUCHDB_SERVER.default_database
property :commenter, :cast_as => 'Author'
timestamps!
def post= post
self["post_id"] = post.id
end
def post
Post.get(self['post_id']) if self['post_id']
end
end
 
 
## CouchRest models in action.
 
puts "Act I: CRUD"
 
puts "Create an author."
quentin = Author.new("name" => "Quentin Hazel")
 
puts "Create a new post."
post = Post.new(:title => "First Post", :body => "Lorem ipsum dolor sit amet, consectetur adipisicing elit...")
 
puts "Add the author to the post."
post.author = quentin
 
puts "Save the post."
post.save
 
puts "Load the post."
reloaded = Post.get(post.id)
 
puts "\nAdd some comments to the post."
comment_one = Comment.new :text => "Blah blah blah", :commenter => {:name => "Joe Sixpack"}
comment_two = Comment.new :text => "Yeah yeah yeah", :commenter => {:name => "Jane Doe"}
comment_three = Comment.new :text => "Whatever...", :commenter => {:name => "John Stewart"}
 
# TODO - maybe add some magic here?
comment_one.post = post
comment_two.post = post
comment_three.post = post
comment_one.save
comment_two.save
comment_three.save
 
puts "We can load a post through its comment (no magic here)."
show post = comment_one.post
 
puts "\nLet's save an author to her own document."
jane = comment_two['commenter']
jane.save
 
puts "Oh, that's neat! Because Ruby passes hash valuee by reference, Jane's new id has been added to the comment she left."
show comment_two
 
puts "Of course, we'd better remember to save it."
comment_two.save
 
puts "Oooh, denormalized... feel the burn!"
 
 
puts "Act II: Views"
 
puts "Let's find all the comments that go with our post."
puts "Our post has id #{post.id}, so lets find all the comments with that post_id."
 
class Comment
view_by :post_id
end
 
comments = Comment.by_post_id :key => post.id
 
puts "That was too easy."
puts "We can even wrap it up in a finder on the Post class."
 
class Post
def comments
Comment.by_post_id :key => id
end
end
 
puts "Gimme 5 minutes and I'll roll this into the framework. ;)"
puts
puts "There is a lot more that can be done with views, but a lot of the interesting stuff is joins, which of course range across types. We'll pick up where we left off, next time."
 
 
## See more examples at:
## http://jchrisa.net/drl/_design/sofa/_show/post/couchrest__model___orm__the_cou
gistfile1.txt
1
Overview of Object-Document Mapping libraries for Ruby and CouchDB.
invoice.rb
Ruby
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132
require 'couch_potato'
 
CouchPotato::Config.database_name = 'odm_overview'
 
class Address
attr_accessor :name, :street, :city, :state, :zip
def initialize(attrs={})
attrs.each do |k,v|
setter = k.to_s + '='
send(k.to_s + '=', v) if respond_to? setter
end
end
end
 
class LineItem
attr_accessor :product_code, :qty, :price_per_unit
def initialize(attrs={})
attrs.each do |k,v|
setter = k.to_s + '='
send(k.to_s + '=', v) if respond_to? setter
end
end
end
 
 
## The document class
 
class Invoice
include CouchPotato::Persistence
 
property :shipping_address #, :class => Address
property :billing_address #, :class => Address
property :ordered_at, :type => Time
property :items
property :tax
property :shipping
property :total
 
validates_presence_of :ordered_at
 
view :all, :key => :ordered_at
 
# view(:total_sales, :type => :aggregate,
# :key => :ordered_at, :sum => 'items.qty * items.price_per_unit')
# view(:average_sale, :type => :aggregate,
# :key => :ordered_at, :average => 'items.qty * items.price_per_unit')
 
view(:total_sales, :type => :raw, :map => %q{
function(doc) {
var i;
if (doc.items) {
for (i = 0; i < doc.items.length; i += 1) {
emit(doc.ordered_at, doc.items[i].qty * doc.items[i].price_per_unit);
}
}
}
},
:reduce => %q{
function(keys, values, rereduce) {
return sum(values);
}
}, :results_filter => lambda { |results| results['rows'].map { |r| r['value'] } })
view(:average_sale, :type => :raw, :map => %q{
function(doc) {
var i, total = 0;
if (doc.items) {
for (i = 0; i < doc.items.length; i += 1) {
total += doc.items[i].qty * doc.items[i].price_per_unit;
}
emit(doc.ordered_at, total);
}
}
},
:reduce => %q{
function(keys, values, rereduce) {
return sum(values) / values.length;
}
}, :results_filter => lambda { |results| results['rows'].map { |r| r['value'] } })
 
end
 
# Initialize views
CouchPotato.database.view Invoice.all
CouchPotato.database.view Invoice.total_sales
 
 
## Creating a document
 
invoice = Invoice.new(
:shipping_address => Address.new(:name => 'Joe Smith',
:street => '123 Main St',
:city => 'Anytown',
:state => 'CA',
:zip => '12345'),
:billing_address => Address.new(:name => 'Joe Smith',
:street => '123 Main St',
:city => 'Anytown',
:state => 'CA',
:zip => '12345'),
:ordered_at => Time.now.utc,
:items => [
LineItem.new(:product_code => 'AX5718', :qty => 1, :price_per_unit => 5.00),
LineItem.new(:product_code => 'BB9388', :qty => 3, :price_per_unit => 2.00),
],
:tax => 0.00,
:shipping => 10.00,
:total => 21.00
)
CouchPotato.database.save_document invoice
 
 
## Looking up a single document
 
invoice_copy = CouchPotato.database.load_document invoice._id
 
 
## Querying up documents
 
invoices = CouchPotato.database.view Invoice.all(:key => (Time.now - 300000)..(Time.now),
:descending => true)
 
 
## Aggregations
 
count = CouchPotato.database.view Invoice.all(:reduce => true)
puts "%i invoices" % count
 
sales = CouchPotato.database.view Invoice.total_sales(:reduce => true)
puts "$%0.2f total sales" % sales
 
average = CouchPotato.database.view Invoice.average_sale(:reduce => true)
puts "$%0.2f average sale" % average

Please sign in to comment on this gist.

Something went wrong with that request. Please try again.