Skip to content
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

includes does not work as expected in historical queries #315

Open
tagliala opened this issue Jun 11, 2024 · 0 comments
Open

includes does not work as expected in historical queries #315

tagliala opened this issue Jun 11, 2024 · 0 comments

Comments

@tagliala
Copy link
Member

tagliala commented Jun 11, 2024

Reproducible test case

# frozen_string_literal: true

require 'bundler/inline'

gemfile(true) do
  source 'https://rubygems.org'

  gem 'chrono_model'
  # Test against latest Chronomodel:
  # gem 'chrono_model', github: 'ifad/chronomodel'

  gem 'pg'
  gem 'debug'
  gem 'rails'
end

require 'chrono_model'
require 'minitest/autorun'
require 'logger'
require 'debug'

# Needs a database called `chronomodel_test`

ActiveRecord::Base.establish_connection(adapter: 'chronomodel', database: 'chronomodel_test')
ActiveRecord::Base.logger = Logger.new($stdout)

ActiveRecord::Schema.define do
  enable_extension :btree_gist

  create_table :activities, temporal: true, force: true do |t|
    t.string :name
    t.timestamps
  end

  create_table :activity_roadmaps, temporal: true, force: true do |t|
    t.belongs_to :activity
    t.string :name

    t.timestamps
  end

  create_table :activity_steps, temporal: true, force: true do |t|
    t.belongs_to :activity_roadmap
    t.string :name
    t.integer :position, default: 1
    t.boolean :active, default: false

    t.timestamps
  end
end

class Activity < ActiveRecord::Base
  include ChronoModel::TimeMachine

  has_one :activity_roadmap, dependent: :destroy

  has_many :activity_steps, through: :activity_roadmap
  has_one :current_activity_step, through: :activity_roadmap

  scope :with_includes, lambda {
    includes(
      :current_activity_step,
      activity_roadmap: %i[activity_steps]
    )
  }
end

class ActivityRoadmap < ActiveRecord::Base
  include ChronoModel::TimeMachine

  belongs_to :activity

  has_many :activity_steps, -> { sorted }, dependent: :destroy, inverse_of: :activity_roadmap
  has_one :current_activity_step, -> { active.sorted }, class_name: 'ActivityStep', dependent: nil, inverse_of: false
end

class ActivityStep < ActiveRecord::Base
  include ChronoModel::TimeMachine

  belongs_to :activity_roadmap

  scope :sorted, -> { order(:position) }
  scope :active, -> { where(active: true) }
end

activity = Activity.create!(name: 'Test')
activity_roadmap = activity.create_activity_roadmap!(name: 'Test')
activity_roadmap.activity_steps.create!(position: 1, active: false)
activity_roadmap.activity_steps.create!(position: 2, active: true)

class BugTest < Minitest::Test
  def test_temporal_includes
    assert Activity.with_includes.first
  end

  def test_historical_includes
    assert Activity.as_of(Time.now).with_includes.first
  end
end

Workarounds

    includes(
-     :current_activity_step,
-     activity_roadmap: :activity_steps
+     activity_roadmap: :activity_steps,
+     current_activity_step: []
    )

or

+   # Use `activity.current_activity_step` through the roadmap to take advantage of eager loading
    includes(
-     :current_activity_step,
-     activity_roadmap: :activity_steps
+     activity_roadmap: %i[activity_steps current_activity_step]
    )
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

1 participant