DataMapper @ RubyEnRails2009

48
Dirkjan Bussink http://github.com/dbussink http://twitter.com/dbussink

description

An overview of what DataMapper can do and where it will go in the future

Transcript of DataMapper @ RubyEnRails2009

Page 1: DataMapper @ RubyEnRails2009

Dirkjan Bussinkhttp://github.com/dbussink

http://twitter.com/dbussink

Page 2: DataMapper @ RubyEnRails2009
Page 3: DataMapper @ RubyEnRails2009

ORM?

Page 4: DataMapper @ RubyEnRails2009

DataMapper 0.10 is ReleasedDataMapper 0.10 is ready for release. We’ve worked on it for the past 11 months, pushed 1250 commits, written 3000+ specs, and fixed 140 tickets in the process.

Page 5: DataMapper @ RubyEnRails2009

1.81.9

Windows *

* Sorry, no Windows / 1.9 yet...

JRuby

Page 6: DataMapper @ RubyEnRails2009
Page 7: DataMapper @ RubyEnRails2009

Dan Kubb

Page 8: DataMapper @ RubyEnRails2009

DataMapper 101

Page 9: DataMapper @ RubyEnRails2009

class Person include DataMapper::Resource property :id, Serial property :name, String property :age, Integerend

Page 10: DataMapper @ RubyEnRails2009

DataMapper.auto_migrate!

DataMapper.auto_upgrade!

Page 11: DataMapper @ RubyEnRails2009
Page 12: DataMapper @ RubyEnRails2009

class Person

...

property :name, String, :length => 512

...

end

Page 13: DataMapper @ RubyEnRails2009

Ruby!

Person.all(:name.like => "%me%")

Page 14: DataMapper @ RubyEnRails2009

Identity Map

repository do puts Person.get(1).object_id => 2232427080 puts Person.get(1).object_id => 2232427080end

Page 15: DataMapper @ RubyEnRails2009
Page 16: DataMapper @ RubyEnRails2009

Pluggable Identity Map

Page 18: DataMapper @ RubyEnRails2009

people = Person.all(:name.like => "%me%")~ Query log empty...

p people~ SELECT "id", "name" FROM people

Page 19: DataMapper @ RubyEnRails2009

:each

Kicker

Page 20: DataMapper @ RubyEnRails2009

Eager loading

people = Person.allpeople.each do |person| p person.addressesend

SELECT "id", "name" FROM people;SELECT "id", "street" FROM addresses WHERE ("person_id" IN (1,2,3))

Page 21: DataMapper @ RubyEnRails2009

RDBMS

IMAP

YAML

Page 22: DataMapper @ RubyEnRails2009

Multiple repositories

DataMapper.setup(:repo1, "postgres://postgres@localhost/dm")DataMapper.setup(:repo2, "mysql://root@localhost/dm")

repository(:repo1) do p Person.get(1) => #<Person @id=1 @name="Dirkjan" @age=27>end

repository(:repo2) do p Person.get(1) => #<Person @id=1 @name="Dan" @age=35>end

Page 23: DataMapper @ RubyEnRails2009

DataMapper.setup(:repo1, "postgres://postgres@localhost/dm")DataMapper.setup(:repo2, "mysql://root@localhost/dm")

get "/" do # Odd / even sharding repo = "repo#{user.id % 2 + 1}".to_sym

repository(repo) do @people = Person.all end

erb :peopleend

Simple sharding

Page 24: DataMapper @ RubyEnRails2009

module DataMapper module Adapters

class MyStorageAdapter < AbstractAdapter

def create(resources) end

def read(query) end

def update(attributes, collection) end

def delete(collection) end

end endend

Page 25: DataMapper @ RubyEnRails2009

Person.all(:name.like => 'dirk%').update!(:age => 28)

Person.all.destroy!(:age.gte => 100)

Bulk updates

Page 26: DataMapper @ RubyEnRails2009

When simple querying is not enough

Page 27: DataMapper @ RubyEnRails2009

Complex querying!

Person.all(Person.addresses.street.like => "%street%")

SELECT "people"."id", "people"."name", "people"."age" FROM "people"INNER JOIN "addresses" ON "people"."id" = "addresses"."person_id" WHERE "addresses"."street" LIKE '%street%' GROUP BY "people"."id", "people"."name", "people"."age" ORDER BY "people"."id"

Page 28: DataMapper @ RubyEnRails2009

class Person include DataMapper::Resource property :id, Serial property :name, String property :age, Integer

has n, :addresses

def self.named_like_me all(:name.like => "%me%") end

def self.older_than_me all(:age.gt => 27) endend

Person.named_like_me.older_than_me

~ SELECT "id", "name", "age" FROM "people" WHERE ("name" LIKE '%me%' AND "age" > 27) ORDER BY "id"

Query chaining

Page 29: DataMapper @ RubyEnRails2009

class Person include DataMapper::Resource property :id, Serial property :name, String property :age, Integer

has n, :addresses

def self.named_like_me all(:name.like => "%me%") end

def self.older_than_me all(:age.gt => 27) endend

Person.named_like_me.older_than_me

~ SELECT "id", "name", "age" FROM "people" WHERE ("name" LIKE '%me%' AND "age" > 27) ORDER BY "id"

Query chaining

Named scopes

in plain Ruby

Page 30: DataMapper @ RubyEnRails2009

Subqueries

Person.all(:name.like => '%me%').addresses.all(:street.not => nil)

SELECT "id", "street", "person_id" FROM "addresses" WHERE ( "person_id" IN (SELECT "id" FROM "people" WHERE "name" LIKE '%me%') AND "street" IS NOT NULL ) ORDER BY "id"

Page 31: DataMapper @ RubyEnRails2009
Page 32: DataMapper @ RubyEnRails2009

Person.all - Person.all(:name => 'Dan Kubb')

SELECT * FROM people WHERE NOT(name = 'Dan Kubb')

Page 33: DataMapper @ RubyEnRails2009

[1, 2] & [2, 3] == [2][1, 2] | [2, 3] == [1, 2, 3]

Page 34: DataMapper @ RubyEnRails2009

Plugins

Page 35: DataMapper @ RubyEnRails2009

Automatic Validations

class Person

...

property :name, String, :nullable => false

end

CREATE TABLE "people" ("id" SERIAL NOT NULL, "name" VARCHAR(50) NOT NULL, "age" INTEGER, PRIMARY KEY("id"))

Page 36: DataMapper @ RubyEnRails2009

DataObjects::IntegrityError: ERROR: null value in column "name" violates not-null constraint

Person.create

Page 37: DataMapper @ RubyEnRails2009

person = Person.createp person.errors => #<DataMapper::Validate::ValidationErrors:0x101d217a0 @errors={:name=>["Name must not be blank"]}, @resource=#<Person @id=nil @name=nil @age=nil>>

Page 38: DataMapper @ RubyEnRails2009

Validations

class Person

...

validates_present :name

end

Page 39: DataMapper @ RubyEnRails2009

Timestamps

class Person

...

property :created_at, DateTime property :updated_at, DateTime

end

Page 40: DataMapper @ RubyEnRails2009

Adjustments

Person.all.adjust!(:age => 1)

Page 41: DataMapper @ RubyEnRails2009

Constraints

class Person

...

has n, :addresses, :constraint => :destroy!

end

ALTER TABLE addressesADD CONSTRAINT addresses_person_id_fkFOREIGN KEY (person_id)REFERENCES peopleON DELETE CASCADEON UPDATE CASCADE

Page 42: DataMapper @ RubyEnRails2009

module DataMapper module Types class IPAddress < DataMapper::Type primitive String length 16

def self.load(value, property) IPAddr.new(value) end

def self.dump(value, property) value.to_s end

def self.typecast(value, property) value.kind_of?(IPAddr) ? value : load(value, property) end end endend

class NetworkNode

...

property :ipaddress, IPAddress

end

Custom types

Page 43: DataMapper @ RubyEnRails2009
Page 44: DataMapper @ RubyEnRails2009

class Address include DataMapper::EmbeddedValue

property :street, Stringend

class Person include DataMapper::Resource

property :id, Serial property :name, String has n, :addressesend

Page 45: DataMapper @ RubyEnRails2009

Ambition style queries

User.select { |u| u.id == 1 && u.name == 'Dan Kubb' }

Page 47: DataMapper @ RubyEnRails2009

http://github.com/datamapper

http://datamapper.org/

http://groups.google.com/group/datamapper

irc://irc.freenode.net/#datamapper

Page 48: DataMapper @ RubyEnRails2009

Questions?