Originally, you could only define associations within schema blocks. This is no longer needed due to automatic resolution of runtime objects, including schemas and their attributes. So now we can define associations anywhere, the most obvious place is a relation itself of course.
To make this possible I had to port schema and associations DSLs to the new component-based DSL. Backward-compatibility is maintained via rom/compat.
Bonus: improved plugins
This refactoring introduced additional challenge because of the way how schema DSL plugins worked. To make things better and easier to manage, plugins are now created per component with their own configurations. This is actually a pretty significant improvement because it allows you to write plugins for any component type and you have an isolated context with plugin's options and its target component configuration available to you.
This means that for example the customized Schema DSL in rom-sql can now be turned into a tiny plugin rather than having a full-blown Schema::DSL subclass and having to deal with it during setup.
Example
require "rom"
require "rom/core"
require "rom/types"
require "rom/compat"
require "rom/sql"
require "rom-changeset"
require "dry-monitor"
module Types
include ROM::Types
end
rom = ROM::Runtime.new(:sql, "sqlite::memory") do |runtime|
runtime.relation(:users) do
schema do
attribute :id, Types::Integer, primary_key: true
attribute :name, Types::String
end
associations do
has_many :tasks
end
end
runtime.relation(:tasks) do
schema do
attribute :id, Types::Integer, primary_key: true
attribute :user_id, Types.ForeignKey(:users)
attribute :title, Types::String
end
associations do
belongs_to :user
end
end
end
rom, time = Dry::Monitor::CLOCK.measure { ROM.runtime(rom) }
puts "rom loaded in #{time}ms"
# rom loaded in 0ms :D
rom.gateways[:default].auto_migrate!(rom, inline: true)
users = rom.relations[:users]
tasks = rom.relations[:tasks]
user = users.changeset(:create, name: "Jane").commit
# {:id=>1, :name=>"Jane"}
task = tasks.changeset(:create, title: "Do Something").associate(user, :user).commit
# {:id=>1, :user_id=>1, :title=>"Do Something"}
Originally, you could only define associations within schema blocks. This is no longer needed due to automatic resolution of runtime objects, including schemas and their attributes. So now we can define associations anywhere, the most obvious place is a relation itself of course.
To make this possible I had to port
schema
andassociations
DSLs to the new component-based DSL. Backward-compatibility is maintained viarom/compat
.Bonus: improved plugins
This refactoring introduced additional challenge because of the way how schema DSL plugins worked. To make things better and easier to manage, plugins are now created per component with their own configurations. This is actually a pretty significant improvement because it allows you to write plugins for any component type and you have an isolated context with plugin's options and its target component configuration available to you.
This means that for example the customized Schema DSL in rom-sql can now be turned into a tiny plugin rather than having a full-blown Schema::DSL subclass and having to deal with it during setup.
Example