Top Banner
A cool, clear drink of Ruby object persistence Aqua Kane Baccigalupi RubyConf 09
32

A cool, clear drink of Ruby object persistence

Sep 01, 2014

Download

Technology

baccigalupi

Introduction to a proof of concept library 'Aqua' that uses CouchDB and other document oriented back ends to transparently persist Ruby objects.
Welcome message from author
This document is posted to help you gain knowledge. Please leave a comment to let me know what you think about it! Share it to your friends and learn new things together.
Transcript
Page 1: A cool, clear drink of  Ruby object persistence

A cool, clear drink of

Ruby object persistence

Aqua

Kane Baccigalupi RubyConf 09

Page 2: A cool, clear drink of  Ruby object persistence

Aqua A cool, clear drink of Ruby object persistence

Kane Baccigalupi RubyConf ‘09

Page 3: A cool, clear drink of  Ruby object persistence

Got unemployment?

Relax with CouchDB

Aqua A cool, clear drink of Ruby object persistence

Kane Baccigalupi RubyConf ‘09

Page 4: A cool, clear drink of  Ruby object persistence

ORMs are great,

but normalization is expensive.

Aqua A cool, clear drink of Ruby object persistence

Kane Baccigalupi RubyConf ‘09

# DataMapper

class Mammal include DataMapper::Resource property :my_id, Serial has n, :legsend

# ActiveRecord

class Bird < ActiveRecord::Base # properties defined by migration has_many, :legsend

Page 5: A cool, clear drink of  Ruby object persistence

CouchDB + Ruby ~= CouchRest

Aqua A cool, clear drink of Ruby object persistence

Kane Baccigalupi RubyConf ‘09

# CouchRest

class Reptile < CouchRest::ExtendedDocument use_database MY_DB unique_id :my_id property :legs # a collection!end

Page 6: A cool, clear drink of  Ruby object persistence

CouchRest is different from ORMs because:

• It allows collections• Models are hashes• Instance variables are discarded

Aqua A cool, clear drink of Ruby object persistence

Kane Baccigalupi RubyConf ‘09

Page 7: A cool, clear drink of  Ruby object persistence

What defines Ruby object state?

Instance variables @my_variable

Fundamental data Hash key-values, Array values, etc.

Aqua A cool, clear drink of Ruby object persistence

Kane Baccigalupi RubyConf ‘09

Page 8: A cool, clear drink of  Ruby object persistence

Database abstractionsfocus on databases

Aqua A cool, clear drink of Ruby object persistence

Kane Baccigalupi RubyConf ‘09

# DataMapper

class Mammal include DataMapper::Resource property :my_id, Serial has n, :legsend

# CouchRest

class Reptile < CouchRest::ExtendedDocument use_database MY_DB unique_id :my_id property :legs # a collection!end

# ActiveRecord

class Bird < ActiveRecord::Base # properties defined by schema has_many, :legsend

Page 9: A cool, clear drink of  Ruby object persistence

Aqua’s goal:

Focus on objects

Aqua A cool, clear drink of Ruby object persistence

Kane Baccigalupi RubyConf ‘09

object.commit!

Page 10: A cool, clear drink of  Ruby object persistence

Because Ruby is awesome

Aqua A cool, clear drink of Ruby object persistence

Kane Baccigalupi RubyConf ‘09

class Event < Range attr_accessor :nameend

rubyconf = Event.new(Date.parse('11/19/2009'), Date.parse('11/21/2009'))rubyconf.name = 'RubyConf 09'rubyconf.include?(Date.parse('11/20/2009')) # true

Page 11: A cool, clear drink of  Ruby object persistence

How does Aqua work?

Aqua A cool, clear drink of Ruby object persistence

Kane Baccigalupi RubyConf ‘09

Page 12: A cool, clear drink of  Ruby object persistence

Just add Aqua

Aqua A cool, clear drink of Ruby object persistence

Kane Baccigalupi RubyConf ‘09

class User aquatic # ...end

Page 13: A cool, clear drink of  Ruby object persistence

Just add Aqua

Aqua A cool, clear drink of Ruby object persistence

Kane Baccigalupi RubyConf ‘09

class User aquatic # ...end

user = User.new# ... More stuff happens to the user

# saving an objectuser.commit! # commit without the ! also works but raises no errors.

Page 14: A cool, clear drink of  Ruby object persistence

Behind the scene

Aqua A cool, clear drink of Ruby object persistence

Kane Baccigalupi RubyConf ‘09

user.commit!

Page 15: A cool, clear drink of  Ruby object persistence

Behind the scene

Aqua A cool, clear drink of Ruby object persistence

Kane Baccigalupi RubyConf ‘09

{ "class"=>"User", "ivars"=>{ "@username"=>"kane", "@email"=>"[email protected]", "@password"=>"secret" }}

user.commit!

serialization

Page 16: A cool, clear drink of  Ruby object persistence

Behind the scene

Aqua A cool, clear drink of Ruby object persistence

Kane Baccigalupi RubyConf ‘09

{ "class"=>"User", "ivars"=>{ "@username"=>"kane", "@email"=>"[email protected]", "@password"=>"secret" }}

user.commit!

serialization

data post

Page 17: A cool, clear drink of  Ruby object persistence

Objects ~= Documents,&& Documents ~= Hashes

Aqua A cool, clear drink of Ruby object persistence

Kane Baccigalupi RubyConf ‘09

# YAML for a Ruby User object

--- &id001 !ruby/object:User email: [email protected] password: secret username: kane

# Aqua Serialization for same object

{ "class"=>"User", "ivars"=>{ "@username"=>"kane", "@email"=>"[email protected]", "@password"=>"secret" }}

Page 18: A cool, clear drink of  Ruby object persistence

Sometimes state should not hang around.

There is a method for that.

Aqua A cool, clear drink of Ruby object persistence

Kane Baccigalupi RubyConf ‘09

class User aquatic attr_accessor :username, :email, :password hide_attributes :passwordend

Page 19: A cool, clear drink of  Ruby object persistence

Going deeper with embedded objects …

Aqua A cool, clear drink of Ruby object persistence

Kane Baccigalupi RubyConf ‘09

address = Address.new # . . . user = User.newuser.addresses = [ address ]

class Address # not an aquatic object, just plain ruby attr_accessor :name, :street, :city, :state, :zipend

Page 20: A cool, clear drink of  Ruby object persistence

Ordinary objectsget serializedinside aquaticobjects

Aqua A cool, clear drink of Ruby object persistence

Kane Baccigalupi RubyConf ‘09

{ "class"=>"User", "ivars"=>{ "@addresses"=>{ "class"=>"Array", "init"=>[{ "class"=>"Address", "ivars"=>{ "@city"=>"San Francisco", "@name"=>"work", "@street"=>"P0 Box 58", "@state"=>"94102" } }] }, "@username"=>"kane", "@email"=>"[email protected]" }}

Page 21: A cool, clear drink of  Ruby object persistence

Embedded aquatic objects are saved by reference.

Aqua A cool, clear drink of Ruby object persistence

Kane Baccigalupi RubyConf ‘09

class User aquatic # ... def friends @friends ||= [] endend

user.friends << alex # where alex is another user object

{ "class"=>"User", "ivars"=>{ # ... "@friends"=>{ "class"=>"Array", "init"=>[{ "class"=>"Aqua::Stub", "init"=>{"class"=>"User", "id"=>"32"} }] } }}

Page 22: A cool, clear drink of  Ruby object persistence

Aqua::Stub ~= Lazy Delegate

Aqua A cool, clear drink of Ruby object persistence

Kane Baccigalupi RubyConf ‘09

• Gets the object from the db

• Triggered by #method_missing

• Stubs/caches methods

{ "class"=>"User", "ivars"=>{ # ... "@friends"=>{ "class"=>"Array", "init"=>[{ "class"=>"Aqua::Stub", "init"=>{"class"=>"User", "id"=>"32"} }] } }}

Page 23: A cool, clear drink of  Ruby object persistence

Stubbing methods in Aqua::Stub

Aqua A cool, clear drink of Ruby object persistence

Kane Baccigalupi RubyConf ‘09

{ "class"=>"User", "ivars"=>{ # ... "@friends"=>{ "class"=>"Array", "init"=>[{ "class"=>"Aqua::Stub", "init"=>{ "class"=>"User", "id"=>"32”, "methods"=>{"username"=>"alex"}, } }] } }}

class User aquatic :embed =>

{ :stub => :username } # ...end

Page 24: A cool, clear drink of  Ruby object persistence

Stubbed behavior

Aqua A cool, clear drink of Ruby object persistence

Kane Baccigalupi RubyConf ‘09

user.reload friend = user.friends.first

friend.class # Aqua::Stub

friend.username # ‘alex’# username was cached

friend.email# this triggers the database call # for the friend object

Page 25: A cool, clear drink of  Ruby object persistence

Got Files?

Aqua A cool, clear drink of Ruby object persistence

Kane Baccigalupi RubyConf ‘09

class User aquatic # ... attr_accessor :avatarend

user.avatar = my_pic

{ "class"=>"User", "ivars"=>{ # ... "@avatar"=>{

"class"=>"Aqua::FileStub” "init"=>{ "methods"=>{ "content_type"=>"image/png", "content_length"=>{ "class"=>"Fixnum", "init"=>"26551” } } "id"=>"image_attach.png" }, } }}

Page 26: A cool, clear drink of  Ruby object persistence

Getting Objects:The basics

Aqua A cool, clear drink of Ruby object persistence

Kane Baccigalupi RubyConf ‘09

User.load( some_id )

user.reload

Page 27: A cool, clear drink of  Ruby object persistence

Indexed Searches

Aqua A cool, clear drink of Ruby object persistence

Kane Baccigalupi RubyConf ‘09

class User aquatic # ... index_on :usernameend

" // javascript map function

function(doc) { if( doc['class'] == 'User' && doc['ivars'] && doc['ivars']['@username'] ){ emit( doc['ivars']['@username'], 1 ); } }"

User.query(:username, ’kane') # returns an array of all users named kane

Page 28: A cool, clear drink of  Ruby object persistence

What’s next?

Aqua A cool, clear drink of Ruby object persistence

Kane Baccigalupi RubyConf ‘09

More querying ease

• Search on nested variables• Criteria pattern ???• Custom dsl ???• Much coding love

Page 29: A cool, clear drink of  Ruby object persistence

What’s next?

Aqua A cool, clear drink of Ruby object persistence

Kane Baccigalupi RubyConf ‘09

Mixins

• Validations• Attribute constraints for class, size, etc.• Collections & relationships• ActiveRecord conversion ???

Page 30: A cool, clear drink of  Ruby object persistence

What’s next?

Aqua A cool, clear drink of Ruby object persistence

Kane Baccigalupi RubyConf ‘09

Serializing Code

• Lambdas and Procs• Singleton methods• Classes (are objects too)

Page 31: A cool, clear drink of  Ruby object persistence

What’s next?

Aqua A cool, clear drink of Ruby object persistence

Kane Baccigalupi RubyConf ‘09

Repository Layer

• In memory

• Stores objects, not serializations

• commits objects as needed

Page 32: A cool, clear drink of  Ruby object persistence

More Info

Rdocs: ruby-aqua.org

Get the gem: sudo gem install aqua

Explore the code: github.com/baccigalupi/aqua

Aqua A cool, clear drink of Ruby object persistence

Kane Baccigalupi RubyConf ‘09