From e73e2fd8820839ca9faaeafa6d1d680b7bbeccd2 Mon Sep 17 00:00:00 2001 From: Jinkyou Son Date: Wed, 25 Feb 2026 17:21:47 +0900 Subject: [PATCH] feat: support offset option in lateral join queries Applies relationship.offset to the lateral join base query so that has_one/has_many relationships with offset work correctly in PostgreSQL. Co-Authored-By: Claude Opus 4.6 --- lib/data_layer.ex | 7 +++++++ test/load_test.exs | 27 +++++++++++++++++++++++++++ test/support/resources/post.ex | 6 ++++++ 3 files changed, 40 insertions(+) diff --git a/lib/data_layer.ex b/lib/data_layer.ex index 3a0c9915..b5132bf8 100644 --- a/lib/data_layer.ex +++ b/lib/data_layer.ex @@ -1113,6 +1113,13 @@ defmodule AshPostgres.DataLayer do base_query end + base_query = + if Map.get(relationship, :offset) do + from(row in base_query, offset: ^relationship.offset) + else + base_query + end + base_query = cond do Map.get(relationship, :manual) -> diff --git a/test/load_test.exs b/test/load_test.exs index 35a844cc..eb13d343 100644 --- a/test/load_test.exs +++ b/test/load_test.exs @@ -65,6 +65,33 @@ defmodule AshPostgres.Test.LoadTest do |> Map.get(:latest_comment) end + test "has_one with offset returns the correct record" do + post = + Post + |> Ash.Changeset.for_create(:create, %{title: "title"}) + |> Ash.create!() + + %{id: first_comment_id} = + Comment + |> Ash.Changeset.for_create(:create, %{title: "first"}) + |> Ash.Changeset.manage_relationship(:post, post, type: :append_and_remove) + |> Ash.create!() + + :timer.sleep(1) + + Comment + |> Ash.Changeset.for_create(:create, %{title: "second"}) + |> Ash.Changeset.manage_relationship(:post, post, type: :append_and_remove) + |> Ash.create!() + + # second_latest_comment: sort(created_at: :desc), offset(1) => first comment + assert %{id: ^first_comment_id} = + Post + |> Ash.Query.load(:second_latest_comment) + |> Ash.read_one!() + |> Map.get(:second_latest_comment) + end + test "belongs_to relationships can be loaded" do assert %Comment{post: %Ash.NotLoaded{type: :relationship}} = comment = diff --git a/test/support/resources/post.ex b/test/support/resources/post.ex index 1ac51c57..4a29b167 100644 --- a/test/support/resources/post.ex +++ b/test/support/resources/post.ex @@ -756,6 +756,12 @@ defmodule AshPostgres.Test.Post do public?(true) end + has_one :second_latest_comment, AshPostgres.Test.Comment do + sort(created_at: :desc) + offset(1) + public?(true) + end + has_many :comments_matching_post_title, AshPostgres.Test.Comment do public?(true) filter(expr(title == parent_expr(title)))