Databases - Have it your way - Space Vatican · 2009/12/4 · • Database toolkit - A ruby DSL...
Transcript of Databases - Have it your way - Space Vatican · 2009/12/4 · • Database toolkit - A ruby DSL...
Databases - Have it your way
Frederick Cheung - kgb
[email protected]://www.spacevatican.org
1Friday, 4 December 2009
kgb
• Operates a number of Directory Enquiry type products in several countries
• Runs the 542542 ‘Ask Us Anything’ SMS service in the US
• 542542 backend is handled by several Rails apps
2Friday, 4 December 2009
kgb
• Operates a number of Directory Enquiry type products in several countries
• Runs the 542542 ‘Ask Us Anything’ SMS service in the US
• 542542 backend is handled by several Rails apps
Whats the difference between 1080i and 1080p?
2Friday, 4 December 2009
kgb
• Operates a number of Directory Enquiry type products in several countries
• Runs the 542542 ‘Ask Us Anything’ SMS service in the US
• 542542 backend is handled by several Rails apps
Whats the difference between 1080i and 1080p?
What is the address for the sperm bank of Pittsburgh?
2Friday, 4 December 2009
kgb
• Operates a number of Directory Enquiry type products in several countries
• Runs the 542542 ‘Ask Us Anything’ SMS service in the US
• 542542 backend is handled by several Rails apps
Whats the difference between 1080i and 1080p?
What is the address for the sperm bank of Pittsburgh?
Where is the Greyhound bus station in Rochester, NY?
2Friday, 4 December 2009
kgb
• Operates a number of Directory Enquiry type products in several countries
• Runs the 542542 ‘Ask Us Anything’ SMS service in the US
• 542542 backend is handled by several Rails apps
Is marijuana legal in Oregon?
Whats the difference between 1080i and 1080p?
What is the address for the sperm bank of Pittsburgh?
Where is the Greyhound bus station in Rochester, NY?
2Friday, 4 December 2009
kgb
• Operates a number of Directory Enquiry type products in several countries
• Runs the 542542 ‘Ask Us Anything’ SMS service in the US
• 542542 backend is handled by several Rails apps
Is marijuana legal in Oregon?
Whats the difference between 1080i and 1080p?
What is the address for the sperm bank of Pittsburgh?
What is the longest life span of a dog in recorded history?
Where is the Greyhound bus station in Rochester, NY?
2Friday, 4 December 2009
ORMs
• Hide the gunk that map objects to database storage
• Eliminate a lot of the repetitive code
• don’t forget about not relational storage (eg CouchDB)
3Friday, 4 December 2009
Active Record within Rails
• redirect_to @person
• form_for @person
• rake tasks for migrations
• automatically configured on app load
4Friday, 4 December 2009
What ORM agnosticism isn’t
• gsub(‘ActiveRecord’, ‘DataMapper’)
• Not trying to make all ORM libraries look the same
5Friday, 4 December 2009
What ORM agnosticism isn’t
• gsub(‘ActiveRecord’, ‘DataMapper’)
• Not trying to make all ORM libraries look the same
5Friday, 4 December 2009
Then what is it?
• Document / codify interactions between persistence layer and rest of Rails
• Grease the wheels
• Don’t make you feel like a second class citizen
• Should be almost invisible to end user - things should just work
6Friday, 4 December 2009
Choose your ORM on its features without worrying about bumps in
the road
7Friday, 4 December 2009
Patterns• Active Record: “An object that wraps a
row in a database table or view, encapsulates the database access, and adds domain logic on that data.” (Martin Fowler)
• Data Mapper: “A layer of Mappers hat moves data between objects and a database while keeping them independent of each other and the mapper itself.” (Martin Fowler)
8Friday, 4 December 2009
Some ORMs, side by side
Active Record, DataMapper, Sequel
9Friday, 4 December 2009
Similar features across the board
• User.new(params[:user])
• Associations, scopes, migrations etc.
• Watch out for subtle differences!
10Friday, 4 December 2009
Similar features across the board
• User.new(params[:user])
• Associations, scopes, migrations etc.
• Watch out for subtle differences!
#Active Recordperson.save! #=> raises if invalidperson.save #=> returns false if invalid
#Sequelperson.save #=> raises if invalidperson.save! #=> save ignoring validations
10Friday, 4 December 2009
Active Record
• You all know it
• Does a lot of manipulation of SQL fragments - very difficult to build an Active Record adapter for non sql datasource
• SQL fragments make some things easy, others awkward
11Friday, 4 December 2009
Active Record Evolution
• In the beginning conditions were strings: composing sets of conditions: yuck!
• hash conditions for equality & ranges
• named_scope
• and ...
12Friday, 4 December 2009
Arel - Relation Algebra
• generates db queries
• Destined to underpin future version Active Record
• Operations all closed under composition
posts = Table(:posts)
posts.where(posts[:subject].eq('Bacon'))
posts.join(comments).on(posts[:id].eq(comments[:post_id]))
13Friday, 4 December 2009
DataMapper• Query objects: lazy loaded definition of a query
• Easy to compose queries
• Easy construction of complicated joins
• Modular design
all_posts = Post.all
about_test = all_posts.all :subject.like => '%test%'
with_comment_by_fred = about_test.all Post.comments.name => 'fred'
14Friday, 4 December 2009
A DM using Model
• mappy feel to it
• explicit about attributes (versus checking schema)
class Post include DataMapper::Resource include DataMapper::Timestamps property :id, Serial property :subject, String, :nullable => false property :body, Text, :nullable => false property :created_at, DateTime, :nullable => false property :updated_at, DateTime, :nullable => false
has n, :commentsend
15Friday, 4 December 2009
Laziness
• attributes can be lazy loaded
• loads lazy loaded attributes in one query for all results in collection
• property groups when defining laziness
• same strategy for loading associations
Post.get 1=> #<Post @id=1 @subject="Hello world" @body=<not loaded> >
16Friday, 4 December 2009
Laziness
• attributes can be lazy loaded
• loads lazy loaded attributes in one query for all results in collection
• property groups when defining laziness
• same strategy for loading associations
Post.get 1=> #<Post @id=1 @subject="Hello world" @body=<not loaded> >
16Friday, 4 December 2009
Sequel
• Database toolkit - A ruby DSL for databases
• ORM layer (Migrations, associations etc. - the usual)
• Master/Slave databases, sharding
• pure ruby DSL for conditions
• Mosts things are Datasets
DB[:posts].filter { created_at > Date::today - 1}.all
17Friday, 4 December 2009
Sequel Model
class Post < Sequel::Model plugin :timestamps one_to_many :commentsend
• comments_dataset• loads of customisation for eager loads• inverse associations• flexible - join on non standard columns
18Friday, 4 December 2009
Very modular
19Friday, 4 December 2009
Very modularSome high level
19Friday, 4 December 2009
Very modular
Lazy attributes
Callbacks
Identity map
Single/Class Table inheritance
Some high level
19Friday, 4 December 2009
Very modular
Lazy attributes
Callbacks
Identity map
Single/Class Table inheritance
Some high level
Some quite grungy
19Friday, 4 December 2009
Very modular
Lazy attributes
Callbacks
Identity map
Single/Class Table inheritance
Some high level
Some quite grungy
Association proxies
Boolean readers
19Friday, 4 December 2009
Monolithic vs Modular
• Active Record in theory modular, but no easy way to choose
• DM explicitly modular: plugins implement validations, migrations, ...
• Sequel::Model entirely plugin driven
• Modularity great when you know what you’re doing, but ...
• Tyranny of choice?
20Friday, 4 December 2009
Conditions
#Active RecordPost.all :conditions => ["subject like ?", "%bacon%"]Post.all :conditions => {:approved => true}Post.all :conditions => ["comments.name like ?", "%bacon%"],
:joins => :comments, :select => "distinct posts.*"
#DataMapperPost.all :subject.like => '%bacon%' Post.all Post.comments.name.like => '%fred%'
#SequelPost.filter {subject.like '%test%'}.allPost.select('distinct posts.*').inner_join(:comments, :post_id => :id).filter {comments__name.like '%test%'}.all
21Friday, 4 December 2009
More Finders
#Active RecordPost.find :all, :include => :comments, :order => 'created_at desc'
#DataMapper
Post.all :order => [:created_at.desc]
#Sequel
Post.eager(:comments).order(:created_at.desc).allPost.eager_graph(:comments).order('posts.created_at desc').all
22Friday, 4 December 2009
You can use these today
• You can already build apps with other data stores
• You can use some of the niceties like redirect_to @person
• You need to figure out dependencies between Action Pack and Active Record
• Compatibility worries
23Friday, 4 December 2009
Little niggles
• Action summary doesn’t count time in DM/Sequel as database time
• Some manual setup
• have to define to_param
24Friday, 4 December 2009
Code time!
25Friday, 4 December 2009