identity_cache icon indicating copy to clipboard operation
identity_cache copied to clipboard

Cannot fetch_multi_by polymorphic field

Open thallada opened this issue 6 years ago • 1 comments

I have made a new rails app with these models on the latest master of identity_cache:

models/item.rb

class Item < ApplicationRecord
  include IdentityCache

  belongs_to :widget, polymorphic: true

  cache_belongs_to :widget
  cache_index :widget
end

models/foo_widget.rb

class FooWidget < ApplicationRecord
  include IdentityCache

  has_many :items, as: :widget

  cache_has_many :items, inverse: :widget
end

models/bar_widget.rb

class BarWidget < ApplicationRecord
  include IdentityCache

  has_many :items, as: :widget

  cache_has_many :items, inverse: :widget
end

schema:

class AddTables < ActiveRecord::Migration[5.2]
  def change
    create_table :items do |t|
      t.bigint :widget_id, null: false
      t.string :widget_type, null: false
    end

    create_table :foo_widgets

    create_table :bar_widgets

    add_index :items, %i[widget_type widget_id]
  end
end

I would like to be able to run this:

widgets = FooWidget.fetch_multi([1, 2, 3])
items = Item.fetch_multi_by_widget(widgets)

But, that generates an invalid SQL query:

ActiveRecord::StatementInvalid (SQLite3::SQLException: no such column: widget: SELECT widget, "items"."id" FROM "items" WHERE "items"."widget_type" = ? AND "items"."widget_id" IN (?, ?))

I can't change my cache_index to cache_index :widget_id, :widget_type because fetch_multi_by methods are only generated for cache_indexes with only one field.

I used to be able to pass in arrays into the fetch_by_widget_id_and_subject_type methods in 0.5.1, but now that doesn't work on master (e.g. an array of widget_ids generates a SQL query with NULL as the widget_id value). I guess was never the way those methods were intended to be used, but now I don't have a way to bulk fetch Items in a way that won't make N+1 queries when the cache is missed.

thallada avatar Sep 24 '19 16:09 thallada

I can't change my cache_index to cache_index :widget_id, :widget_type because fetch_multi_by methods are only generated for cache_indexes with only one field.

Right, there isn't cache_attribute by multiple columns support, which means there is no cache_index by multiple columns support.

In your example

widgets = FooWidget.fetch_multi([1, 2, 3])
items = Item.fetch_multi_by_widget(widgets)

it looks like you could add cache_has_many :items, embed: :ids to FooWidget, then you could do

widgets = FooWidget.fetch_multi([1, 2, 3], include: :items)
items = widgets.flat_map(&:items)

dylanahsmith avatar Nov 26 '21 21:11 dylanahsmith