際際滷

際際滷Share a Scribd company logo
AquaA cool, clear drink of Ruby object persistenceKane BaccigalupiRubyConf 09
AquaA cool, clear drink of Ruby object persistenceKane BaccigalupiRubyConf 09
AquaA cool, clear drink of Ruby object persistenceGot unemployment?Relax with CouchDBKane BaccigalupiRubyConf 09
AquaA cool, clear drink of Ruby object persistenceORMs are great,but normalization is expensive.# DataMapperclass Mammal  include DataMapper::Resource  property :my_id, Serial  has n, :legsend# ActiveRecordclass Bird < ActiveRecord::Base  # properties defined by migrationhas_many, :legsendKane BaccigalupiRubyConf 09
AquaA cool, clear drink of Ruby object persistenceCouchDB + Ruby  ~= CouchRest# CouchRestclass Reptile < CouchRest::ExtendedDocumentuse_database MY_DBunique_id :my_id  property  :legs # a collection!endKane BaccigalupiRubyConf 09
AquaA cool, clear drink of Ruby object persistenceCouchRest is different from ORMs because:It allows collectionsModels are hashesInstance variables are discardedKane BaccigalupiRubyConf 09
AquaA cool, clear drink of Ruby object persistenceWhat defines Ruby object state?Instance variables @my_variableFundamental data 	Hash key-values, Array values, etc.Kane BaccigalupiRubyConf 09
AquaA cool, clear drink of Ruby object persistenceDatabase abstractionsfocus on databases# DataMapperclass Mammal  include DataMapper::Resource  property :my_id,    Serial  has n, :legsend# ActiveRecordclass Bird < ActiveRecord::Base  # properties defined by schemahas_many, :legsend# CouchRestclass Reptile < CouchRest::ExtendedDocumentuse_database MY_DBunique_id :my_id  property  :legs # a collection!endKane BaccigalupiRubyConf 09
AquaA cool, clear drink of Ruby object persistenceAquas goal:Focus on objects object.commit!Kane BaccigalupiRubyConf 09
AquaA cool, clear drink of Ruby object persistenceBecause Ruby is awesomeclass Event < Range attr_accessor :nameendrubyconf = Event.new(Date.parse('11/19/2009'), Date.parse('11/21/2009'))rubyconf.name = 'RubyConf 09'rubyconf.include?(Date.parse('11/20/2009')) # true Kane BaccigalupiRubyConf 09
AquaA cool, clear drink of Ruby object persistenceHow does Aqua work?Kane BaccigalupiRubyConf 09
AquaA cool, clear drink of Ruby object persistenceJust add Aquaclass Useraquatic# ...endKane BaccigalupiRubyConf 09
AquaA cool, clear drink of Ruby object persistenceJust add Aquaclass Useraquatic# ...enduser = User.new# ... More stuff happens to the user# saving an objectuser.commit! # commit without the ! also works but raises no errors.Kane BaccigalupiRubyConf 09
AquaA cool, clear drink of Ruby object persistenceBehind the sceneuser.commit!Kane BaccigalupiRubyConf 09
AquaA cool, clear drink of Ruby object persistenceBehind the sceneserializationuser.commit!{  "class"=>"User",   "ivars"=>{    "@username"=>"kane",     "@email"=>"baccigalupi@gmail.com",     "@password"=>"secret"   }}Kane BaccigalupiRubyConf 09
AquaA cool, clear drink of Ruby object persistenceBehind the sceneserializationuser.commit!{  "class"=>"User",   "ivars"=>{    "@username"=>"kane",     "@email"=>"baccigalupi@gmail.com",     "@password"=>"secret"   }}data postKane BaccigalupiRubyConf 09
AquaA cool, clear drink of Ruby object persistenceObjects ~= Documents,&& Documents ~= Hashes# YAML for a Ruby User object--- &id001 !ruby/object:User  email: baccigalupi@gmail.com  password: secret  username: kane# Aqua Serialization for same object{  "class"=>"User",   "ivars"=>{    "@username"=>"kane",     "@email"=>"baccigalupi@gmail.com",     "@password"=>"secret"   }} Kane BaccigalupiRubyConf 09
AquaA cool, clear drink of Ruby object persistenceSometimes state should not hang around.There is a method for that. class User  aquaticattr_accessor :username, :email, :password hide_attributes :passwordendKane BaccigalupiRubyConf 09
AquaA cool, clear drink of Ruby object persistenceGoing deeper with embedded objects class Address# not an aquatic object, just plain rubyattr_accessor :name, :street, :city, :state, :zipend  address  = Address.new# . . . user = User.newuser.addresses = [ address ]Kane BaccigalupiRubyConf 09
AquaA cool, clear drink of Ruby object persistenceOrdinary objectsget serializedinside aquaticobjects{  "class"=>"User",   "ivars"=>{"@addresses"=>{      "class"=>"Array",       "init"=>[{        "class"=>"Address",         "ivars"=>{          "@city"=>"San Francisco",           "@name"=>"work",           "@street"=>"P0 Box 58",           "@state"=>"94102"        }      }]     },     "@username"=>"kane",     "@email"=>"baccigalupi@gmail.com"  }} Kane BaccigalupiRubyConf 09
AquaA cool, clear drink of Ruby object persistenceEmbedded aquatic objects are saved by reference.{  "class"=>"User",   "ivars"=>{    # ...    "@friends"=>{      "class"=>"Array",       "init"=>[{        "class"=>"Aqua::Stub",         "init"=>{"class"=>"User", "id"=>"32"}       }]    }  }}class Useraquatic# ...def friends   @friends ||= []  endenduser.friends << alex# where alex is another user objectKane BaccigalupiRubyConf 09
AquaA cool, clear drink of Ruby object persistenceAqua::Stub~= Lazy DelegateGets 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"}       }]    }  }}Kane BaccigalupiRubyConf 09
AquaA cool, clear drink of Ruby object persistenceStubbing methods in Aqua::Stub{  "class"=>"User",   "ivars"=>{    # ...    "@friends"=>{      "class"=>"Array",       "init"=>[{        "class"=>"Aqua::Stub",         "init"=>{          "class"=>"User",          "id"=>"32,"methods"=>{"username"=>"alex"},         }       }]    }  }}class Useraquatic :embed =>{ :stub => :username } # ...endKane BaccigalupiRubyConf 09
AquaA cool, clear drink of Ruby object persistenceStubbed behavioruser.reloadfriend = user.friends.firstfriend.class # Aqua::Stubfriend.username# alex# username was cachedfriend.email# this triggers the database call # for the friend objectKane BaccigalupiRubyConf 09
AquaA cool, clear drink of Ruby object persistenceGot Files?{  "class"=>"User",   "ivars"=>{    # ..."@avatar"=>{	 "class"=>"Aqua::FileStub      "init"=>{       "methods"=>{         "content_type"=>"image/png",         "content_length"=>{           "class"=>"Fixnum", "init"=>"26551         }       }"id"=>"image_attach.png"      },     }  }}class Useraquatic  # ...attr_accessor :avatarenduser.avatar = my_picKane BaccigalupiRubyConf 09
AquaA cool, clear drink of Ruby object persistenceGetting Objects:The basicsUser.load( some_id )user.reloadKane BaccigalupiRubyConf 09
AquaA cool, clear drink of Ruby object persistenceIndexed Searchesclass Useraquatic  # ...index_on :usernameend" // javascript map functionfunction(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 kaneKane BaccigalupiRubyConf 09
AquaA cool, clear drink of Ruby object persistenceWhats next?More querying ease Search on nested variables
 Criteria pattern ???
 Custom dsl ???

More Related Content

A cool, clear drink of Ruby object persistence

  • 1. AquaA cool, clear drink of Ruby object persistenceKane BaccigalupiRubyConf 09
  • 2. AquaA cool, clear drink of Ruby object persistenceKane BaccigalupiRubyConf 09
  • 3. AquaA cool, clear drink of Ruby object persistenceGot unemployment?Relax with CouchDBKane BaccigalupiRubyConf 09
  • 4. AquaA cool, clear drink of Ruby object persistenceORMs are great,but normalization is expensive.# DataMapperclass Mammal include DataMapper::Resource property :my_id, Serial has n, :legsend# ActiveRecordclass Bird < ActiveRecord::Base # properties defined by migrationhas_many, :legsendKane BaccigalupiRubyConf 09
  • 5. AquaA cool, clear drink of Ruby object persistenceCouchDB + Ruby ~= CouchRest# CouchRestclass Reptile < CouchRest::ExtendedDocumentuse_database MY_DBunique_id :my_id property :legs # a collection!endKane BaccigalupiRubyConf 09
  • 6. AquaA cool, clear drink of Ruby object persistenceCouchRest is different from ORMs because:It allows collectionsModels are hashesInstance variables are discardedKane BaccigalupiRubyConf 09
  • 7. AquaA cool, clear drink of Ruby object persistenceWhat defines Ruby object state?Instance variables @my_variableFundamental data Hash key-values, Array values, etc.Kane BaccigalupiRubyConf 09
  • 8. AquaA cool, clear drink of Ruby object persistenceDatabase abstractionsfocus on databases# DataMapperclass Mammal include DataMapper::Resource property :my_id, Serial has n, :legsend# ActiveRecordclass Bird < ActiveRecord::Base # properties defined by schemahas_many, :legsend# CouchRestclass Reptile < CouchRest::ExtendedDocumentuse_database MY_DBunique_id :my_id property :legs # a collection!endKane BaccigalupiRubyConf 09
  • 9. AquaA cool, clear drink of Ruby object persistenceAquas goal:Focus on objects object.commit!Kane BaccigalupiRubyConf 09
  • 10. AquaA cool, clear drink of Ruby object persistenceBecause Ruby is awesomeclass Event < Range attr_accessor :nameendrubyconf = Event.new(Date.parse('11/19/2009'), Date.parse('11/21/2009'))rubyconf.name = 'RubyConf 09'rubyconf.include?(Date.parse('11/20/2009')) # true Kane BaccigalupiRubyConf 09
  • 11. AquaA cool, clear drink of Ruby object persistenceHow does Aqua work?Kane BaccigalupiRubyConf 09
  • 12. AquaA cool, clear drink of Ruby object persistenceJust add Aquaclass Useraquatic# ...endKane BaccigalupiRubyConf 09
  • 13. AquaA cool, clear drink of Ruby object persistenceJust add Aquaclass Useraquatic# ...enduser = User.new# ... More stuff happens to the user# saving an objectuser.commit! # commit without the ! also works but raises no errors.Kane BaccigalupiRubyConf 09
  • 14. AquaA cool, clear drink of Ruby object persistenceBehind the sceneuser.commit!Kane BaccigalupiRubyConf 09
  • 15. AquaA cool, clear drink of Ruby object persistenceBehind the sceneserializationuser.commit!{ "class"=>"User", "ivars"=>{ "@username"=>"kane", "@email"=>"baccigalupi@gmail.com", "@password"=>"secret" }}Kane BaccigalupiRubyConf 09
  • 16. AquaA cool, clear drink of Ruby object persistenceBehind the sceneserializationuser.commit!{ "class"=>"User", "ivars"=>{ "@username"=>"kane", "@email"=>"baccigalupi@gmail.com", "@password"=>"secret" }}data postKane BaccigalupiRubyConf 09
  • 17. AquaA cool, clear drink of Ruby object persistenceObjects ~= Documents,&& Documents ~= Hashes# YAML for a Ruby User object--- &id001 !ruby/object:User email: baccigalupi@gmail.com password: secret username: kane# Aqua Serialization for same object{ "class"=>"User", "ivars"=>{ "@username"=>"kane", "@email"=>"baccigalupi@gmail.com", "@password"=>"secret" }} Kane BaccigalupiRubyConf 09
  • 18. AquaA cool, clear drink of Ruby object persistenceSometimes state should not hang around.There is a method for that. class User aquaticattr_accessor :username, :email, :password hide_attributes :passwordendKane BaccigalupiRubyConf 09
  • 19. AquaA cool, clear drink of Ruby object persistenceGoing deeper with embedded objects class Address# not an aquatic object, just plain rubyattr_accessor :name, :street, :city, :state, :zipend address = Address.new# . . . user = User.newuser.addresses = [ address ]Kane BaccigalupiRubyConf 09
  • 20. AquaA cool, clear drink of Ruby object persistenceOrdinary objectsget serializedinside aquaticobjects{ "class"=>"User", "ivars"=>{"@addresses"=>{ "class"=>"Array", "init"=>[{ "class"=>"Address", "ivars"=>{ "@city"=>"San Francisco", "@name"=>"work", "@street"=>"P0 Box 58", "@state"=>"94102" } }] }, "@username"=>"kane", "@email"=>"baccigalupi@gmail.com" }} Kane BaccigalupiRubyConf 09
  • 21. AquaA cool, clear drink of Ruby object persistenceEmbedded aquatic objects are saved by reference.{ "class"=>"User", "ivars"=>{ # ... "@friends"=>{ "class"=>"Array", "init"=>[{ "class"=>"Aqua::Stub", "init"=>{"class"=>"User", "id"=>"32"} }] } }}class Useraquatic# ...def friends @friends ||= [] endenduser.friends << alex# where alex is another user objectKane BaccigalupiRubyConf 09
  • 22. AquaA cool, clear drink of Ruby object persistenceAqua::Stub~= Lazy DelegateGets the object from the db
  • 23. Triggered by #method_missing
  • 24. Stubs/caches methods{ "class"=>"User", "ivars"=>{ # ... "@friends"=>{ "class"=>"Array", "init"=>[{ "class"=>"Aqua::Stub", "init"=>{"class"=>"User", "id"=>"32"} }] } }}Kane BaccigalupiRubyConf 09
  • 25. AquaA cool, clear drink of Ruby object persistenceStubbing methods in Aqua::Stub{ "class"=>"User", "ivars"=>{ # ... "@friends"=>{ "class"=>"Array", "init"=>[{ "class"=>"Aqua::Stub", "init"=>{ "class"=>"User", "id"=>"32,"methods"=>{"username"=>"alex"}, } }] } }}class Useraquatic :embed =>{ :stub => :username } # ...endKane BaccigalupiRubyConf 09
  • 26. AquaA cool, clear drink of Ruby object persistenceStubbed behavioruser.reloadfriend = user.friends.firstfriend.class # Aqua::Stubfriend.username# alex# username was cachedfriend.email# this triggers the database call # for the friend objectKane BaccigalupiRubyConf 09
  • 27. AquaA cool, clear drink of Ruby object persistenceGot Files?{ "class"=>"User", "ivars"=>{ # ..."@avatar"=>{ "class"=>"Aqua::FileStub "init"=>{ "methods"=>{ "content_type"=>"image/png", "content_length"=>{ "class"=>"Fixnum", "init"=>"26551 } }"id"=>"image_attach.png" }, } }}class Useraquatic # ...attr_accessor :avatarenduser.avatar = my_picKane BaccigalupiRubyConf 09
  • 28. AquaA cool, clear drink of Ruby object persistenceGetting Objects:The basicsUser.load( some_id )user.reloadKane BaccigalupiRubyConf 09
  • 29. AquaA cool, clear drink of Ruby object persistenceIndexed Searchesclass Useraquatic # ...index_on :usernameend" // javascript map functionfunction(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 kaneKane BaccigalupiRubyConf 09
  • 30. AquaA cool, clear drink of Ruby object persistenceWhats next?More querying ease Search on nested variables
  • 33. Much coding loveKane BaccigalupiRubyConf 09
  • 34. AquaA cool, clear drink of Ruby object persistenceWhats next?Mixins Validations
  • 35. Attribute constraints for class, size, etc.
  • 36. Collections & relationships
  • 37. ActiveRecord conversion ???Kane BaccigalupiRubyConf 09
  • 38. AquaA cool, clear drink of Ruby object persistenceWhats next?Serializing Code Lambdas and Procs
  • 40. Classes (are objects too)Kane BaccigalupiRubyConf 09
  • 41. AquaA cool, clear drink of Ruby object persistenceWhats next?Repository LayerIn memory
  • 42. Stores objects, not serializations
  • 43. commits objects as neededKane BaccigalupiRubyConf 09
  • 44. AquaA cool, clear drink of Ruby object persistenceMore InfoRdocs: ruby-aqua.orgGet the gem: sudo gem install aquaExplore the code: github.com/baccigalupi/aquaKane BaccigalupiRubyConf 09