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

Return only unique record when using includes #8

Open
wants to merge 8 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@ GEM

PLATFORMS
x86_64-darwin-21
x86_64-darwin-22
x86_64-linux

DEPENDENCIES
Expand Down
2 changes: 1 addition & 1 deletion lib/fast_page/active_record_methods.rb
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ def deferred_join_load
@values[:limit] = limit_value + 1 if limit_value
id_scope = dup
id_scope = id_scope.except(:includes) unless references_eager_loaded_tables?
ids = id_scope.pluck(:id)
ids = id_scope.pluck(:id).uniq

if limit_value
@values[:limit] = limit_value - 1
Expand Down
28 changes: 20 additions & 8 deletions test/fast_page_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,14 @@ def setup
User.delete_all
Organization.delete_all

org = Organization.create(name: "planetscale")
User.create(login: "mikeissocool", organization: org)
User.create(login: "iheanyi")
User.create(login: "nicknicknick")
User.create(login: "frances")
organizations = [
Organization.create(name: "planetscale"),
Organization.create(name: "github")
]
User.create(login: "mikeissocool", organizations: [organizations[0], organizations[1]])
User.create(login: "iheanyi", organizations: [organizations[0], organizations[1]])
User.create(login: "nicknicknick", organizations: [organizations[0]])
User.create(login: "frances", organizations: [organizations[1]])
User.create(login: "phani")
User.create(login: "jason")
User.create(login: "derek")
Expand Down Expand Up @@ -54,15 +57,16 @@ def test_removes_includes_id_query
queries << sql.payload[:sql]
end

User.all.includes(:organization).limit(50).fast_page
User.all.includes(:organizations).limit(50).fast_page

assert_equal 3, queries.size
assert_equal 4, queries.size

# Organizations are not included on the ID query (not needed)
assert_includes queries, 'SELECT "users"."id" FROM "users" LIMIT ?'
assert_includes queries, 'SELECT "users".* FROM "users" WHERE "users"."id" IN (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)'
# Includes are still loaded
assert_includes queries, 'SELECT "organizations".* FROM "organizations" WHERE "organizations"."id" = ?'
assert_includes queries, 'SELECT "user_organizations".* FROM "user_organizations" WHERE "user_organizations"."user_id" IN (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)'
assert_includes queries, 'SELECT "organizations".* FROM "organizations" WHERE "organizations"."id" IN (?, ?)'

ActiveSupport::Notifications.unsubscribe("sql.active_record")
end
Expand Down Expand Up @@ -99,4 +103,12 @@ def test_works_offset_only
def test_to_a_returns_an_array
assert_equal Array, User.all.limit(5).fast_page.to_a.class
end

def test_returns_unique_records_when_including_associations
og = User.includes(:organizations).where(organizations: { id: Organization.pluck(:id) }).limit(2).order(created_at: :asc)
fast = User.includes(:organizations).where(organizations: { id: Organization.pluck(:id) }).limit(2).order(created_at: :asc).fast_page

assert_equal og.length, fast.length
assert_equal og.select(&:id), fast.select(&:id)
end
end
9 changes: 7 additions & 2 deletions test/test_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,16 @@

create_table :users, force: true do |t|
t.string :login
t.integer :organization_id
t.timestamps
t.index ["login"], unique: true
end

create_table :user_organizations, force: true do |t|
t.integer :user_id
t.integer :organization_id
t.timestamps
end

create_table :organizations, force: true do |t|
t.string :name
t.timestamps
Expand All @@ -31,5 +36,5 @@ class Organization < ActiveRecord::Base
end

class User < ActiveRecord::Base
belongs_to :organization
has_and_belongs_to_many :organizations, join_table: "user_organizations"
end