Shopify / Shopify/identity_cache

should inverse_of work?

Open
#357 5 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
Ruby
Stars
2k
Forks
174
Avg merge
13m
Merged PRs (30d)
3

Description

Not sure if it's a misconfiguration on my side or if it's simply not supported.

Rails 5.1.4
identity_cache 0.5.1

Given:

class Person < ActiveRecord::Base
  include IdentityCache
  belongs_to :client, inverse_of: :persons
  cache_belongs_to :client
end

class Client < ActiveRecord::Base
  include IdentityCache
  has_many :persons, -> { where partner_id: nil }, dependent: :destroy, inverse_of: :client
  cache_has_many :persons
end

Without the cache the client isn't fetched again when we fetch persons on a client:

irb(main):002:0> client = Client.find(4)
  Client Load (0.5ms)  SELECT  `clients`.* FROM `clients` WHERE `clients`.`id` = 4 LIMIT 1
=> #<Client id: 4, name: .... >
irb(main):003:0> client.persons.map{|p| p.client.object_id}
  Person Load (0.7ms)  SELECT `persons`.* FROM `persons` WHERE `persons`.`deleted_at` IS NULL AND `persons`.`client_id` = 4 AND `persons`.`partner_id` IS NULL
=> [70220559135500, 70220559135500, 70220559135500, 70220559135500, 70220559135500, 70220559135500, 70220559135500, 70220559135500]

With IdentityCache I get a client query for every person and different objects. Shouldn't IdentityCache simply setup the association to the existing client object?

irb(main):002:0> client = Client.find(4)
  Client Load (0.5ms)  SELECT  `clients`.* FROM `clients` WHERE `clients`.`id` = 4 LIMIT 1
=> #<Client id: 4, name: .... >
irb(main):002:0> client.fetch_persons.map{|p| p.client.object_id}
   (1.2ms)  SELECT `persons`.`id` FROM `persons` WHERE `persons`.`deleted_at` IS NULL AND `persons`.`client_id` = 4 AND `persons`.`partner_id` IS NULL
Cache cas_multi: greenlight:1:IDC:7:blob:Person:7919784493729940308:9/IDC:7:blob:Person:7919784493729940308:10/IDC:7:blob:Person:7919784493729940308:11/IDC:7:blob:Person:7919784493729940308:3459/IDC:7:blob:Person:79197844937299403:md5:1e1faf6c2624ebf80c00411dbf35dcc9 ({:namespace=>"greenlight:1", :expires_in=>21600})
  Person Load (0.8ms)  SELECT `persons`.* FROM `persons` WHERE `persons`.`deleted_at` IS NULL AND `persons`.`id` IN (9, 10, 11, 3459, 4135, 4147, 4312, 4458)
Cache write: greenlight:1:IDC:7:blob:Person:7919784493729940308:9 ({:namespace=>"greenlight:1", :expires_in=>21600, :unless_exist=>true})
Cache write: greenlight:1:IDC:7:blob:Person:7919784493729940308:10 ({:namespace=>"greenlight:1", :expires_in=>21600, :unless_exist=>true})
Cache write: greenlight:1:IDC:7:blob:Person:7919784493729940308:11 ({:namespace=>"greenlight:1", :expires_in=>21600, :unless_exist=>true})
Cache write: greenlight:1:IDC:7:blob:Person:7919784493729940308:3459 ({:namespace=>"greenlight:1", :expires_in=>21600, :unless_exist=>true})
Cache write: greenlight:1:IDC:7:blob:Person:7919784493729940308:4135 ({:namespace=>"greenlight:1", :expires_in=>21600, :unless_exist=>true})
Cache write: greenlight:1:IDC:7:blob:Person:7919784493729940308:4147 ({:namespace=>"greenlight:1", :expires_in=>21600, :unless_exist=>true})
Cache write: greenlight:1:IDC:7:blob:Person:7919784493729940308:4312 ({:namespace=>"greenlight:1", :expires_in=>21600, :unless_exist=>true})
Cache write: greenlight:1:IDC:7:blob:Person:7919784493729940308:4458 ({:namespace=>"greenlight:1", :expires_in=>21600, :unless_exist=>true})
[IdentityCache] cache miss for IDC:7:blob:Person:7919784493729940308:9 (multi)
[IdentityCache] cache miss for IDC:7:blob:Person:7919784493729940308:10 (multi)
[IdentityCache] cache miss for IDC:7:blob:Person:7919784493729940308:11 (multi)
[IdentityCache] cache miss for IDC:7:blob:Person:7919784493729940308:3459 (multi)
[IdentityCache] cache miss for IDC:7:blob:Person:7919784493729940308:4135 (multi)
[IdentityCache] cache miss for IDC:7:blob:Person:7919784493729940308:4147 (multi)
[IdentityCache] cache miss for IDC:7:blob:Person:7919784493729940308:4312 (multi)
[IdentityCache] cache miss for IDC:7:blob:Person:7919784493729940308:4458 (multi)
  Client Load (0.6ms)  SELECT  `clients`.* FROM `clients` WHERE `clients`.`id` = 4 LIMIT 1
  Client Load (0.5ms)  SELECT  `clients`.* FROM `clients` WHERE `clients`.`id` = 4 LIMIT 1
  Client Load (0.6ms)  SELECT  `clients`.* FROM `clients` WHERE `clients`.`id` = 4 LIMIT 1
  Client Load (0.5ms)  SELECT  `clients`.* FROM `clients` WHERE `clients`.`id` = 4 LIMIT 1
  Client Load (0.6ms)  SELECT  `clients`.* FROM `clients` WHERE `clients`.`id` = 4 LIMIT 1
  Client Load (0.5ms)  SELECT  `clients`.* FROM `clients` WHERE `clients`.`id` = 4 LIMIT 1
  Client Load (0.5ms)  SELECT  `clients`.* FROM `clients` WHERE `clients`.`id` = 4 LIMIT 1
  Client Load (0.5ms)  SELECT  `clients`.* FROM `clients` WHERE `clients`.`id` = 4 LIMIT 1
=> [70220565335420, 70220557688780, 70220557994400, 70220558006100, 70220589297320, 70220589903960, 70220589965920, 70220560291960]

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start by reproducing the reported behavior with the Person and Client associations, including inverse_of, cache_belongs_to, cache_has_many, and fetch_persons. Trace the association-loading and cache-fetch paths, then add coverage for object identity and repeated Client queries. Done means the expected inverse association behavior is documented and verified by tests.

Written by the indexing model from the issue text.

Assessment

Tech stack
rails, ruby
Domain
backend, databases
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.