I have a moderately complicated data model in postgresql with lots of relations, and I need to gather them all together for display in a view.
I have a
Conversation which associates with a few other objects, which have their own associations, and I need some or all of those loaded depending on the view being rendered. For example,
Conversation has many
Messages belongs to
User, and in a single-conversation view (
GET /conversations/1234) I want to include the recent messages and the users that sent them, while in the conversation-list view (
GET /conversations) I want only the users and the one most recent message. I’m struggling with 1) how to write relations and repositories that might involve complex queries like LATERAL JOINS, and 2) how do I share those queries with other repositories/relations?
Some specific questions I’ve had that don’t have satisfying answers in the documentation include:
- Is there a way to reuse or combine the methods on the repository? For example, to get a single conversation with all the associated objects, I have a method
#by_slug_with_embeds(slug). To get all the conversations with those associations loaded, I have a separate method
#with_embeds. A feature I need to add next is to limit the conversations by account, do I just add it to those methods, eg
#for_account_by_slug_with_embeds(account, slug)? If I need to add another, this method is starting to get unwieldy. Do I instead name it for its purpose, like
- I have a custom
ConversationROM::Struct model that these get loaded into. A single Conversation has a
messagesattribute containing all it messages, but to save memory and load, the Conversations within a list should not load those, and instead have a single
latest_messageattribute. Are these a single Model with two optional attribute, or two separate models that have very similar attributes?
I’ve found some examples to crib from in Hanami , but few for ROM itself. I imagine the patterns are similar since Hanami is just ROM underneath, but are the any ROM-specific examples I’m missing?
class ConversationsRelation < ROM::Relation[:sql] gateway :default schema(:conversations, infer: true) do associations do belongs_to :contact belongs_to :account has_many :messages has_many :conversation_events end end def with_embeds combine(:account, :conversation_events, contact: :phone, messages: :user) end end
class ConversationRepository < ROM::Repository::Root root :conversations commands :create, update: :by_pk, delete: :by_pk, mapper: :conversation def by_slug_with_embeds(slug) conversations.with_embeds.by_pk(slug).one! end end
And for comparison, this is a cleaned-up version of an ActiveRecord-based query object I’m trying to replace with ROM functionality: https://gist.github.com/paul/07d62974e4c8e401f00af58a98b8e9fa (The actual one is way gnarlier, and getting worse by the iteration).