class HomesRelation < ROM::Relation[:sql]
gateway :default
schema(:homes, infer: true) do
associations do
has_many :attributes, through: :home_attributes
end
end
end
class HomeAttributesRelation < ROM::Relation[:sql]
gateway :default
schema(:home_attributes, infer: true) do
associations do
belongs_to :home
belongs_to :attribute
end
end
end
class AttributesRelation < ROM::Relation[:sql]
gateway :default
schema(:attributes, infer: true)
end
Using my HomeRepository, I would like to query for all homes with their attributes like:
class HomeRepository < ROM::Repository::Root
root :homes
def all_with_attributes
homes.combine(:attributes).to_a
end
end
I am able to successfully retrieve the data, but am attempting to flatten the results using a Mapper and return Home objects. I would like these Home objects to have the following attributes:
all of the attributes coming from the HomesRelation schema
each associated attribute nested in the results of homes.combine(:attributes).to_a
Given the following raw data returned from the relation: [{:id=>1, :address=>"Fake Address", attributes: [{:attr1=>"attr value"}, {:attr2=>"attr value"}]}]
I’d like to map this into something like: #<Home id=1 address="Fake Address" attr1="attr value", attr2="attr value">
Anyone have any thoughts on how to do this/best practices? Thanks!
This is possible by using custom mappers. You can do something like this:
require 'rom/transformer'
class HomeMapper < ROM::Transformer
register_as :flat_attrs
relation :homes
def call(data)
data.map { |tuple|
home = tuple.dup
attrs = home.delete(:attributes)
home.update(attrs.map.with_index { |a, i| [:"attr#{i}", attr[:attr1]] }.to_h)
}
end
end
your_rom_config.register_mapper(HomeMapper)
# then you'll be able to do:
homes.combine(:attributes).map_with(:flat_attrs).to_a
The only trick is that if you want to use auto-structs, you will also have to provide a customized schema. I’m not sure how exactly your schemas look like so it’s hard to say how to do it. I suspect attr1 etc. is not the actual column names.
If you could provide an executable script that sets up tables and relations, I could tweak it to make it work like you want.
Thanks @solnic! And apologies for taking so long to respond. I am going to take some time to dive deeper into this and will send over an executable script if I get stuck.
This covers retrieving a Home and that home’s associated attributes.
Any thoughts on best practices to create a new Home where the incoming params from the client are flattened attributes?
The incoming params would be something like: {:address=>"Home1", attr1: "attr value1", attr2: "attr value2"}
I would like to create 3 new entries in the db:
“Home1” stored in the address column on the homes table
The PK for the home and the PK for attr1 stored in the home_attributes table as references
The PK for the home and the PK for attr2 stored in the home_attributes table as references
I know I will have to find the PK for each incoming attribute; however, I am curious if ROM provides a transformation layer that I can use to change data going into the DB into a format that the DB expects.
Would I use a changeset?
Happy to clarify any of the above if need be. Thanks again for your help!