Skip to content

Instantly share code, notes, and snippets.

@solnic
Last active May 14, 2021 05:33
Show Gist options
  • Star 6 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save solnic/7df076239cfe79f6459b3f6ea6c7d741 to your computer and use it in GitHub Desktop.
Save solnic/7df076239cfe79f6459b3f6ea6c7d741 to your computer and use it in GitHub Desktop.
[rom-sql] AR-like polymorphic associations (PLEASE DON'T USE IT UNLESS YOU HAVE A LEGACY SCHEMA)
require 'rom-repository'
require 'rom-sql'
require 'logger'
config = ROM::Configuration.new(:sql, 'sqlite::memory')
config.gateways[:default].connection.create_table(:songs) do
primary_key :id
column :title, String
end
config.gateways[:default].connection.create_table(:books) do
primary_key :id
column :title, String
end
config.gateways[:default].connection.create_table(:tags) do
primary_key :id
column :taggable_id, Integer
column :taggable_type, String
column :name, String
end
config.relation(:songs) do
schema(infer: true) do
associations do
has_many :tags, foreign_key: :taggable_id, view: :for_songs
end
end
def for_tags(tags)
by_pk(tags.select { |tag| tag[:taggable_type] == 'Song' }.map { |tag| tag[:taggable_id] })
end
end
config.relation(:books) do
schema(infer: true) do
associations do
has_many :tags, foreign_key: :taggable_id, view: :for_books
end
end
def for_tags(tags)
by_pk(tags.select { |tag| tag[:taggable_type] == 'Book' }.map { |tag| tag[:taggable_id] })
end
end
config.relation(:tags) do
schema(infer: true) do
associations do
belongs_to :books, as: :book, foreign_key: :taggable_id, view: :for_tags
belongs_to :songs, as: :song, foreign_key: :taggable_id, view: :for_tags
end
end
def for_songs
where(taggable_type: 'Song')
end
def for_books
where(taggable_type: 'Book')
end
end
class SongRepo < ROM::Repository[:songs]
relations :tags
commands :create
end
class BookRepo < ROM::Repository[:books]
relations :tags
commands :create
end
class TagRepo < ROM::Repository[:tags]
relations :songs, :books
commands :create
end
rom = ROM.container(config)
song_repo = SongRepo.new(rom)
book_repo = BookRepo.new(rom)
tag_repo = TagRepo.new(rom)
song = song_repo.create(title: 'A song')
book = book_repo.create(title: 'A book')
song_tag = tag_repo.create(taggable_id: song.id, taggable_type: 'Song', name: 'red')
book_tag = tag_repo.create(taggable_id: book.id, taggable_type: 'Book', name: 'blue')
puts song_repo.aggregate(:tags).to_a.first.inspect
#<ROM::Struct[Song] id=1 title="A song" tags=[#<ROM::Struct[Tag] id=1 taggable_id=1 taggable_type="Song" name="red">]>
puts book_repo.aggregate(:tags).to_a.first.inspect
#<ROM::Struct[Book] id=1 title="A book" tags=[#<ROM::Struct[Tag] id=2 taggable_id=1 taggable_type="Book" name="blue">]>
puts tag_repo.tags.wrap(:book).for_books.to_a.first.inspect
# #<ROM::Struct[Tag] id=2 taggable_id=1 taggable_type="Book" name="blue" book=#<ROM::Struct[Book] id=1 title="A book">>
puts tag_repo.tags.wrap(:song).for_songs.to_a.first.inspect
# #<ROM::Struct[Tag] id=1 taggable_id=1 taggable_type="Song" name="red" song=#<ROM::Struct[Song] id=1 title="A song">>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment