DataMapper @ RubyEnRails2009
-
Upload
dirkjan-bussink -
Category
Technology
-
view
5.848 -
download
3
description
Transcript of DataMapper @ RubyEnRails2009
Dirkjan Bussinkhttp://github.com/dbussink
http://twitter.com/dbussink
ORM?
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.
1.81.9
Windows *
* Sorry, no Windows / 1.9 yet...
JRuby
Dan Kubb
DataMapper 101
class Person include DataMapper::Resource property :id, Serial property :name, String property :age, Integerend
DataMapper.auto_migrate!
DataMapper.auto_upgrade!
class Person
...
property :name, String, :length => 512
...
end
Ruby!
Person.all(:name.like => "%me%")
Identity Map
repository do puts Person.get(1).object_id => 2232427080 puts Person.get(1).object_id => 2232427080end
Pluggable Identity Map
http://www.flickr.com/photos/mattimattila
people = Person.all(:name.like => "%me%")~ Query log empty...
p people~ SELECT "id", "name" FROM people
:each
Kicker
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))
RDBMS
IMAP
YAML
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
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
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
Person.all(:name.like => 'dirk%').update!(:age => 28)
Person.all.destroy!(:age.gte => 100)
Bulk updates
When simple querying is not enough
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"
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
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
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"
Person.all - Person.all(:name => 'Dan Kubb')
SELECT * FROM people WHERE NOT(name = 'Dan Kubb')
[1, 2] & [2, 3] == [2][1, 2] | [2, 3] == [1, 2, 3]
Plugins
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"))
DataObjects::IntegrityError: ERROR: null value in column "name" violates not-null constraint
Person.create
person = Person.createp person.errors => #<DataMapper::Validate::ValidationErrors:0x101d217a0 @errors={:name=>["Name must not be blank"]}, @resource=#<Person @id=nil @name=nil @age=nil>>
Validations
class Person
...
validates_present :name
end
Timestamps
class Person
...
property :created_at, DateTime property :updated_at, DateTime
end
Adjustments
Person.all.adjust!(:age => 1)
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
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
class Address include DataMapper::EmbeddedValue
property :street, Stringend
class Person include DataMapper::Resource
property :id, Serial property :name, String has n, :addressesend
Ambition style queries
User.select { |u| u.id == 1 && u.name == 'Dan Kubb' }
http://www.flickr.com/photos/zoomar
http://github.com/datamapper
http://datamapper.org/
http://groups.google.com/group/datamapper
irc://irc.freenode.net/#datamapper
Questions?