Given:
create_table(:foos) do
primary_key(:id)
String(:name)
end
create_table(:bars) do
primary_key(:id)
String(:name)
end
create_table(:foos_bars) do
primary_key(:id)
foreign_key(:foo_id, :foos)
foreign_key(:bar_id, :bars)
String(:name)
end
class Foos < ROM::Relation[:sql]
dataset :foos
def with_bars(id)
prefix('foos').qualified.select(
:foos__id, :foos__name
).select_append(
:bars__id, :bars__name
).left_join(
:foos_bars, foos_bars__bars_id: :foos__id
).left_join(
:bars, bars__id: :foos_bars__bars_id
).where(foos__id: id)
end
end
class FoosModel
include Virtus.model
attribute :id
attribute :name
attribute :bars
end
class BarsModel
include Virtus.model
attribute :id
attribute :name
attribute :foos
end
I've tried many, many random variations on the keywords shown in (but not explained in) the ROM docs to no avail. Here's a literal interpretation of the docs into a mapper for Foos, which doesn't work:
class FoosMapper < ROM::Mapper
relation :foos
register_as :foos
model Foo
prefix('foos')
attribute :id
attribute :name
group :bars do
model Bar
attribute :id, from: :bar
attribute :name, from: :bar
end
end
How does one write a mapper (or rework the relation to work with the mapper) to get the simple result of a foo with a bars attribute having all the bars linked by the foos_bars table?
Building up complex joins like that is not recommended unless you have good reasons like performance. It's much simpler to use repositories to compose relations by defining relation views that you need for reusability and composing those in various way inside repos. Defining custom mappers should also be avoided unless you have some unique requirements.
I made a gist that illustrates that right here: https://gist.github.com/solnic/9307e1b2e3428718dd12
We're working on a new set of docs that will properly explain those things.