-
-
Notifications
You must be signed in to change notification settings - Fork 161
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Nested combine fails when using views #568
Comments
Thanks for the report. I'll look into this. |
@mrship that's an interesting bug 😅 It looks like the same mapper is being applied twice, I need to dig deeper. Does the same problem happen when you have identical setup except that standard PK/FK are used so that there's no need for overidden views? |
If I use PK/FK for those relationships where I can - leaving one view for a many-to-many join then it does still throw the same error: The "simpler" setup: #!/usr/bin/env ruby
require 'bundler/inline'
gemfile do
source 'https://rubygems.org'
gem 'rom'
gem 'rom-sql'
gem 'rom-repository'
gem 'dry-types'
gem 'sqlite3'
end
module Types
include Dry::Types(default: :nominal)
end
rom = ROM.container(:sql, 'sqlite::memory') do |c|
c.gateways[:default].create_table :product_groups do
primary_key :id
String :name
end
c.gateways[:default].create_table :products do
String :id
String :name
end
c.gateways[:default].create_table :grouped_products do
primary_key :id
Integer :product_group_id
Integer :product_id
end
c.gateways[:default].create_table :allocations do
primary_key :id
Integer :product_config_id
String :name
end
c.gateways[:default].create_table :product_configs do
primary_key :id
Integer :product_group_id
end
c.gateways[:default].use_logger(Logger.new($stdout))
c.relation(:product_groups) do
schema(:product_groups, infer: false) do
attribute :id, Types::Integer, primary_key: true
attribute :name, Types::String
associations do
has_many :grouped_products
has_many :products, through: :grouped_products
end
end
def for_allocations(_assoc, loaded)
product_groups
.join(:product_configs, { product_group_id: :id })
.where(product_configs[:id] => loaded.pluck(:product_config_id).uniq)
.select_append(product_configs[:id].as(:product_config_id))
end
end
c.relation(:grouped_products) do
schema(:grouped_products, infer: false) do
attribute :id, Types::Integer.meta(primary_key: true)
attribute :product_group_id, Types::Integer
attribute :product_id, Types::String
associations do
belongs_to :products
end
end
end
c.relation(:products) do
schema(:products, infer: false) do
attribute :id, Types::String.meta(primary_key: true)
attribute :name, Types::String
end
end
c.relation(:allocations) do
schema(:allocations, infer: false) do
attribute :id, Types::Integer.meta(primary_key: true)
attribute :product_config_id, Types::Integer
attribute :name, Types::String
associations do
belongs_to :product_config
has_one :product_group, view: :for_allocations, override: true,
combine_keys: { product_config_id: :product_config_id }
end
end
end
c.relation(:product_configs) do
schema(:product_configs, infer: false) do
attribute :id, Types::Integer.meta(primary_key: true)
attribute :product_group_id, Types::Integer
associations do
belongs_to :product_groups
end
end
end
end
rom.relations[:products].insert id: "ABC", name: "TV"
rom.relations[:product_groups].insert id: 2002, name: "Broadcasters"
rom.relations[:grouped_products].insert id: 3003, product_group_id: 2002, product_id: "ABC"
rom.relations[:product_configs].insert id: 4004, product_group_id: 2002
rom.relations[:allocations].insert id: 5005, product_config_id: 4004
class AllocationRepo < ROM::Repository[:allocations]
def boom
allocations.combine(product_group: :products).to_a
end
def ok
allocations.combine(:product_group).to_a
end
end
repo = AllocationRepo.new(rom)
# puts repo.ok.inspect
puts repo.boom.inspect # => transproc-1.1.0/lib/transproc/array/combine.rb:51:in `block in group_candidates_by_keys': no implicit conversion of Symbol into Integer (TypeError) |
Is it possible to set it up in a way that this view is not needed? I just want to make sure that this only happens with a custom overridden view. |
Yes, it works (in a test, per below) using another join table and not using a view. However, that's not how my real world application works unfortunately. #!/usr/bin/env ruby
require 'bundler/inline'
gemfile do
source 'https://rubygems.org'
gem 'rom'
gem 'rom-sql'
gem 'rom-repository'
gem 'dry-types'
gem 'sqlite3'
end
module Types
include Dry::Types(default: :nominal)
end
rom = ROM.container(:sql, 'sqlite::memory') do |c|
c.gateways[:default].create_table :product_groups do
primary_key :id
String :name
end
c.gateways[:default].create_table :products do
String :id
String :name
end
c.gateways[:default].create_table :grouped_products do
primary_key :id
Integer :product_group_id
Integer :product_id
end
c.gateways[:default].create_table :allocation_product_groups do
primary_key :id
Integer :product_group_id
Integer :allocation_id
end
c.gateways[:default].create_table :allocations do
primary_key :id
Integer :product_config_id
String :name
end
c.gateways[:default].create_table :product_configs do
primary_key :id
Integer :product_group_id
end
c.gateways[:default].use_logger(Logger.new($stdout))
c.relation(:product_groups) do
schema(:product_groups, infer: false) do
attribute :id, Types::Integer, primary_key: true
attribute :name, Types::String
associations do
has_many :grouped_products
has_many :products, through: :grouped_products
end
end
def for_allocations(_assoc, loaded)
product_groups
.join(:product_configs, { product_group_id: :id })
.where(product_configs[:id] => loaded.pluck(:product_config_id).uniq)
.select_append(product_configs[:id].as(:product_config_id))
end
end
c.relation(:grouped_products) do
schema(:grouped_products, infer: false) do
attribute :id, Types::Integer.meta(primary_key: true)
attribute :product_group_id, Types::Integer
attribute :product_id, Types::String
associations do
belongs_to :products
end
end
end
c.relation(:products) do
schema(:products, infer: false) do
attribute :id, Types::String.meta(primary_key: true)
attribute :name, Types::String
end
end
c.relation(:allocations) do
schema(:allocations, infer: false) do
attribute :id, Types::Integer.meta(primary_key: true)
attribute :product_config_id, Types::Integer
attribute :name, Types::String
associations do
belongs_to :product_config
has_many :allocation_product_groups
has_many :product_groups, through: :allocation_product_groups
end
end
end
c.relation(:product_configs) do
schema(:product_configs, infer: false) do
attribute :id, Types::Integer.meta(primary_key: true)
attribute :product_group_id, Types::Integer
associations do
belongs_to :product_groups
end
end
end
c.relation(:allocation_product_groups) do
schema(:allocation_product_groups, infer: false) do
attribute :allocation_id, Types::Integer
attribute :product_group_id, Types::Integer
associations do
belongs_to :product_groups
end
end
end
end
rom.relations[:products].insert id: "ABC", name: "TV"
rom.relations[:product_groups].insert id: 2002, name: "Broadcasters"
rom.relations[:grouped_products].insert id: 3003, product_group_id: 2002, product_id: "ABC"
rom.relations[:product_configs].insert id: 4004, product_group_id: 2002
rom.relations[:allocations].insert id: 5005, product_config_id: 4004
rom.relations[:allocation_product_groups].insert id: 3003, product_group_id: 2002, allocation_id: 5005
class AllocationRepo < ROM::Repository[:allocations]
def boom
allocations.combine(product_groups: :products).to_a
end
end
repo = AllocationRepo.new(rom)
puts repo.boom.inspect
# => [#<ROM::Struct::Allocation id=5005 product_config_id=4004 name=nil product_groups=[#<ROM::Struct::ProductGroup id=2002 name="Broadcasters" allocation_id=5005 products=[#<ROM::Struct::Product id="ABC" name="TV" product_group_id=2002>]>]>] |
@mrship thank you for checking it, this is good news because I was worried the association type is broken regardless if you're custom views or not. OK I will keep digging into your scenario then and fix it in the next release. |
@solnic just checking in on this one as I've been bitten by it again today in another project. |
@mrship no progress yet, sorry. It's hard to find time to work on OSS these days. I'll try to look into it later this week but can't promise anything :( |
@solnic FYI we worked around this by using a database view instead of combining multiple tables in Ruby, so no rush to fix! Thanks. |
Describe the bug
When using a nested combine and views we get an error thrown in the transproc gem.
Without using the nested combine, the data structure is retrieved correctly (although obviously without the child data)
As far as I can tell, the data is pulled from the data source correctly. We end up with a hash of data that fails the
group_by
call in transproc.To Reproduce
Expected behavior
No error thrown and a correctly combined dataset.
Your environment
The text was updated successfully, but these errors were encountered: