BYPIOTR SOLNICA
Plan Prezentacji
1. Istniejące Implementacje ORM2. Architektura
1. Repozytoria2. Adaptery3. Zasoby
3. Podstawy4. Key Features 5. Status projektu
2
November 19, 2008© Piotr Solnica
DataMapper3
Istniejące Implementacje ORM
November 19, 2008© Piotr Solnica
Istniejące Implementacje ORM4
ActiveRecord & Sequel
November 19, 2008© Piotr Solnica
Istniejące Implementacje ORM5
Po co trzeci zawodnik…?
November 19, 2008© Piotr Solnica
Istniejące Implementacje ORM6
ActiveRecord:
• Kiepska architektura – obsługuje tylko relacyjne bazy danych i do tego nie wie czym jest klucz złożony…
• Dużo wtyczek, przy czym każdy update powoduje, że połowa przestaje działać
• Szybki kosztem pamięci• Frustrujące API!
November 19, 2008© Piotr Solnica
Istniejące Implementacje ORM7
Sequel:
• Trochę lepszy ActiveRecord
November 19, 2008© Piotr Solnica
Istniejące implementacje ORM8
November 19, 2008© Piotr Solnica
Istniejące Implementacje ORM9
Poza tym wszystkim…
November 19, 2008© Piotr Solnica
Istniejące Implementacje ORM10
…ActiveRecord & Sequel używają…
November 19, 2008© Piotr Solnica
Istniejące Implementacje ORM11
MIGRACJI!
November 19, 2008© Piotr Solnica
Istniejące Implementacje ORM12
DataMapper
November 19, 2008© Piotr Solnica
DataMapper13
Architektura
November 19, 2008© Piotr Solnica
DataMapper / Architektura14
Repozytoria
MySQL
CauchDB
SimpleDB
Adaptery Zasoby
November 19, 2008© Piotr Solnica
DataMapper / Architektura 15
Repozytoria
November 19, 2008© Piotr Solnica
DataMapper / Architektura / Repozytoria
16
Repozytoria są to źródła danych, na przykład:
• relacyjne bazy danych (doooh!)• obiektowe bazy danych• systemy plików• YAML, JSON, XML itd.• Amazon SimpleDB• REST-based
November 19, 2008© Piotr Solnica
DataMapper / Architektura / Repozytoria
17
Każdy system udostępniający dane za
pomocą swojego interfejsu może stać się repozytorium
DataMappera
November 19, 2008© Piotr Solnica
DataMapper / Architektura 18
Adaptery
November 19, 2008© Piotr Solnica
DataMapper / Architektura / Adaptery19
Adaptery zapewniają transparentny dostęp do danych z repozytoriów
November 19, 2008© Piotr Solnica
DataMapper / Architektura / Adaptery20
Istniejące adaptery:• MySQL / Postgres / SQLite• YAML• CSV• CouchDB• Amazon SimpleDB• Ferret• IMAP• …masa innych under development
November 19, 2008© Piotr Solnica
DataMapper / Architetura21
Zasoby
November 19, 2008© Piotr Solnica
DataMapper / Architektura / Zasoby22
Zasoby reprezentują dane z repozytoriów, za ich
pośrednictwem wykonujemy operacje CRUD
November 19, 2008© Piotr Solnica
DataMapper / Architektura / Zasoby23
Każdy zasób charakteryzuje się różnymi własnościami,
przy czym własności te mogą być związane z różnymi
repozytoriami…
November 19, 2008© Piotr Solnica
DataMapper / Architektura / Zasoby24
…to my decydujemy jakie własności zasobów nas
interesują, a nie zautomatyzowany do bólu
ORM!
November 19, 2008© Piotr Solnica
DataMapper / Architektura / Zasoby25
Pomiędzy zasobami mogą istnieć powiązania typowe dla relacyjnych baz danych (one-
to-one, one-to-many etc.)
November 19, 2008© Piotr Solnica
DataMapper26
Podstawy
November 19, 2008© Piotr Solnica
DataMapper / Podstawy27
dm-core & dm-more
November 19, 2008© Piotr Solnica
DataMapper / Podstawy28
Trzy poziomy API:
• public• semi-public• private
November 19, 2008© Piotr Solnica
DataMapper / Podstawy29
Własności modelu deklaruje się na poziomie jego klasy!
class Zoo include DataMapper::Resource property :id, Serial property :name, Stringend
November 19, 2008© Piotr Solnica
DataMapper / Podstawy30
Relacjeclass Zoo include DataMapper::Resource
property :id, Serial property :name, String
has n, :animals has 1..10, :young_animals, :class_name => ‘Animal’, :age => 1..3end
class Animal include DataMapper::Resource
property :id, Serial property :name, String property :age, Integer
belongs_to :zooend
November 19, 2008© Piotr Solnica
DataMapper / Podstawy31
Automigracje
Zoo.auto_migrate!Zoo.auto_upgrade!
November 19, 2008© Piotr Solnica
DataMapper / Podstawy32
Tworzenie nowych zasobów
some_zoo = Zoo.create(:name => ‘Some Zoo’)
some_zoo.animals.create(:name => ‘Marty’)
another_zoo = Zoo.new(:name => ‘Another Zoo’)
another_animal = Animal.new( :name => ‘Alex’, :zoo => another_zoo)
another_zoo.saveanother_animal.save
November 19, 2008© Piotr Solnica
DataMapper / Podstawy33
Pobieranie zasobów
zoo = Zoo.get(1)
zoo.animals.get(1)
zoo = Zoo.first(:name => ‘Some Zoo’)
zoo.animals.all(:name => ‘Marty’)
November 19, 2008© Piotr Solnica
DataMapper / Podstawy34
Callbacks
class Zoo include DataMapper::Resource
property :id, Serial property :name, String
before :save do name = ‘Default Name’ if name.blank? endend
November 19, 2008© Piotr Solnica
DataMapper35
Key Features
November 19, 2008© Piotr Solnica
DataMapper / Key Features36
IdentityMap
repository do marty1 = Zoo.get(1) marty2 = Zoo.get(1)
marty1.object_id == marty2.object_id # trueend
November 19, 2008© Piotr Solnica
DataMapper / Key Features37
Animal.create(:name => ‘Marty’, :age => 12)
marty = Animal.first(:name => 'Marty')
marty.attribute_dirty?(:age) # false
marty.age = 21
marty.attribute_dirty?(:age) # false
marty.save # UPDATE `animals` SET `age` = 21 WHERE (`id` = 1)
Dirty Properties Tracking
November 19, 2008© Piotr Solnica
DataMapper / Key Features38
class Zoo include DataMapper::Resource
property :id, Serial property :description, Textend
Zoo.create(:description => ‘This is a very nice zoo’)
# SELECT `id` FROM `zoos` WHERE (`id` = 1) ORDER BY `id` LIMIT 1zoo = Zoo.get(zoo1.id)
# SELECT `description`, `id` FROM `zoos` WHERE (`id` = 1) ORDER BY `id`zoo.description
Lazy Loading
November 19, 2008© Piotr Solnica
DataMapper / Key Features39
zoos = Zoo.all # nie wykonuje się żadne zapytanie!
zoos.each do |zoo| # dopiero tutaj zostaną pobrane wszystkie zoo zoo.animals.each do |animal| # a tutaj wszystkie animals należące do zoos! puts "Animal #{animal.name} from #{zoo.name}" end
end
Strategic Eager Loading
November 19, 2008© Piotr Solnica
DataMapper / Key Features40
class Zoo include DataMapper::Resource
property :id, Serialend
class Cage include DataMapper::Resource
property :id, Serialend
class Animal include DataMapper::Resource
property :zoo_id, :key => true property :cage_id, :key => trueend
Composite Keys
November 19, 2008© Piotr Solnica
DataMapper / Key Features41
zoo = Zoo.create
cage = Cage.create(:zoo => zoo)
Animal.create(:zoo => zoo, :cage => cage)
animal = Animal.get(zoo.id, cage.id)
Composite Keys
November 19, 2008© Piotr Solnica
DataMapper / Key Features42
class Zoo include DataMapper::Resource
property :id, Serial property :name, String, :length => 12..64end
zoo = Zoo.new(:name => ‘Too short’)
# ["Name must be between 12 and 64 characters long"]zoo.errors[:name]
Auto-Validations
November 19, 2008© Piotr Solnica
DataMapper / Key Features43
class Article include DataMapper::Resource property :id, Serial property :title, String property :body, Text validates_present :title, :when => [:publish] validates_length :body, :minimum => 1000, :when => [:publish]end
article = Article.new
article.valid_for_publish? # falsearticle.title = 'Hello World'article.valid_for_publish? # falsearticle.body = '...some 1000 chars text...'article.valid_for_publish? # true!
Contextual Validations
November 19, 2008© Piotr Solnica
DataMapper / Key Features44
class User include DataMapper::Resource
property :id, Serial property :postal_code, PostalCodeend
user = User.new(:postal_code => '12-34')
user.valid? # falseuser.errors[:postal_code] # ["Postal code has an invalid format"]
user.postal_code = '12-345'
user.valid? # true
Custom Data Types
November 19, 2008© Piotr Solnica
DataMapper / Key Features45
module DataMapper module Types class PostalCode < DataMapper::Type primitive String format(/^\d{2}\-\d{3}$/) end endend
Custom Data Types
November 19, 2008© Piotr Solnica
DataMapper46
Status Projektu
November 19, 2008© Piotr Solnica
DataMapper / Status Projektu47
CURRENT VERSION: 0.9.6
November 19, 2008© Piotr Solnica
DataMapper48
Pytania?
November 19, 2008© Piotr Solnica
DataMapper49
Dziękuję
November 19, 2008© Piotr Solnica