6. DATAMAPPER
▸ Active Record ORM with explicit model property
definitions
▸ Advanced query API in 2009 already (lazy queries, lazy
properties, advanced query operators etc.)
▸ Custom data types for properties
▸ Database-agnostic through adapters
8. VIRTUS
▸ Typed attribute definitions in PORO extracted from
DataMapper
▸ Advanced coercion mechanism
▸ Fully configurable and flexible
▸ Form objects, data objects (ie loaded from JSON),
coercion backends etc.
▸ For some reason people loved it…
10. DATAMAPPER 2
▸ Active Record => Data Mapper (patterns)
▸ Adapters based on pure relational algebra backend
▸ Advanced Session with Unit of Work for state tracking and
data synchronization
▸ Didn’t really work out ¯_(⊙_ʖ⊙)_/¯
▸ However…
12. RESULTS OF THE DATAMAPPER 2 EXPERIMENT
▸ Immutability-oriented object design!
▸ Focus on simpler, foundational abstractions
▸ Embracing small, composable libraries
▸ Lots of interesting new patterns in Ruby
14. ROM-RB 2013->2014
▸ DataMapper 2 renamed to rom-rb (Ruby Object Mapper)
in 2013
▸ More work has been put into its relational algebra
backend and optimizing sql queries
▸ Prototype of Session with Unit of Work
▸ Still not production ready ¯_(⊙_ʖ⊙)_/¯
16. “ORM is one of the most complex things that you can ever touch…and we
chose it over and over again, without thinking at all, because everybody is
doing it”
Rich Hickey
41. ROM 2.0 + ROM-SQL + ROM-REPOSITORY UPDATES
▸ type-safe and flexible relation schema DSL
▸ association support in schemas
▸ simplified, automatic eager-loading based on association
definitions
▸ simplified interface for returning aggregate objects in
repositories
▸ support for persisting nested data into multiple relations
47. require 'dry-container'
class MyContainer
extend Dry::Container::Mixin
end
# register a singleton
MyContainer.register(:user_repo, UserRepo.new)
# or resolve as a new object
MyContainer.register(:user_repo) { UserRepo.new }
# simply access your registered objects
MyContainer[:user_repo]
48. class PersistUser
attr_reader :user_repo
def initialize(user_repo)
@user_repo = user_repo
end
def call(user)
user_repo.create(user)
end
end
PersistUser.new(MyContainer[:user_repo])
57. require 'dry/component/container'
class Application < Dry::Component::Container
configure do |config|
config.root = Pathname.new('./my/app')
end
end
# now you can register a logger
require 'logger'
Application.register('utils.logger', Logger.new($stdout))
# and access it
Application['utils.logger']
60. # under /my/app/lib/logger.rb we put
class Logger
# some neat logger implementation
end
# we can finalize the container which triggers auto-registration
Application.finalize!
# the logger becomes available
Application[‘logger']
63. class Application < Dry::Component::Container
configure do |config|
config.root = '/my/app'
end
end
# requires needed files and boots your persistence component
Application.boot!(:persistence)
# and now `database` becomes available
Application['database']
86. OMG MORE DRY-RB GEMS!
▸ dry-transaction
▸ dry-monads
▸ dry-initializer
▸ dry-web
▸ dry-web-roda (we plan to add support for more!)
▸ more gems are planned!