diff --git a/CHANGELOG.md b/CHANGELOG.md index ef45acd..7a3fee1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,13 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## 1.0.2 - 2022-08-11 + +### Fixed + +- Fixed issues which caused select some expressions to fail when used with join + queries. + ## 1.0.1 - 2022-05-12 ### Added diff --git a/lib/fob/ordering.ex b/lib/fob/ordering.ex index e9bc134..903f12b 100644 --- a/lib/fob/ordering.ex +++ b/lib/fob/ordering.ex @@ -82,9 +82,13 @@ defmodule Fob.Ordering do expr: {:%{}, _, [{:|, _, [{:&, _, [0]}, merges]}]} } }) do - Map.new(merges, fn {toplevel_name, - {{:., _, [{:&, _, [table]}, name_in_table]}, _, _}} -> - {{table, name_in_table}, toplevel_name} + Enum.reduce(merges, %{}, fn + {toplevel_name, {{:., _, [{:&, _, [table]}, name_in_table]}, _, _}}, + acc -> + Map.put(acc, {table, name_in_table}, toplevel_name) + + {_toplevel_name, _ast_expr}, acc -> + acc end) end diff --git a/test/fob/computed_select_test.exs b/test/fob/computed_select_test.exs new file mode 100644 index 0000000..2eaaf9e --- /dev/null +++ b/test/fob/computed_select_test.exs @@ -0,0 +1,100 @@ +defmodule Fob.ComputedSelectTest do + use Fob.RepoCase + alias Fob.Cursor + alias Ecto.Multi + + describe "query with single table" do + setup do + [schema: SimplePrimaryKeySchema, repo: Fob.Repo] + end + + setup c do + records = for n <- 1..20, do: %{id: n} + + Multi.new() + |> Multi.insert_all(:seeds, c.schema, records) + |> c.repo.transaction() + + :ok + end + + test "when selecting with computed query, we can get each page", c do + cursor = + Cursor.new( + from( + s in c.schema, + select: %{ + id: s.id, + computed_column: s.id >= 5 + }, + order_by: [asc: s.id] + ), + c.repo, + _initial_page_breaks = nil, + 5 + ) + + assert {records, cursor} = Cursor.next(cursor) + assert Enum.map(records, & &1.id) == Enum.to_list(1..5) + + assert {records, cursor} = Cursor.next(cursor) + assert Enum.map(records, & &1.id) == Enum.to_list(6..10) + + assert {records, cursor} = Cursor.next(cursor) + assert Enum.map(records, & &1.id) == Enum.to_list(11..15) + + assert {records, cursor} = Cursor.next(cursor) + assert Enum.map(records, & &1.id) == Enum.to_list(16..20) + + # end of the data set + assert {[], _cursor} = Cursor.next(cursor) + end + end + + describe "query with left join" do + setup do + [repo: Fob.Repo, trunk_schema: TrunkSchema, child_schema: ChildSchema] + end + + setup c do + trunk_records = for n <- 1..10, do: %{id: n - 1, child: 10 - n} + + child_records = + for n <- 1..10 do + %{id: n - 1, name: String.pad_trailing("", n, "b")} + end + + Multi.new() + |> Multi.insert_all(:trunk_seeds, c.trunk_schema, trunk_records) + |> Multi.insert_all(:child_seeds, c.child_schema, child_records) + |> c.repo.transaction() + + :ok + end + + test """ + we can select a computed value with a left-joined field + """, + c do + child_schema = c.child_schema + + cursor = + Cursor.new( + from(t in c.trunk_schema, + left_join: c in ^child_schema, + on: t.child == c.id, + select: %{t | child_name: c.name, id_next: t.id + 1}, + order_by: [asc: c.name, desc: t.id] + ), + c.repo, + nil, + 5 + ) + + {records, cursor} = Cursor.next(cursor) + assert Enum.all?(records, &(&1.id_next == &1.id + 1)) + {records, _cursor} = Cursor.next(cursor) + assert Enum.all?(records, &(&1.id_next == &1.id + 1)) + end + end +end diff --git a/test/support/left_join_schemas.ex b/test/support/left_join_schemas.ex index bc73480..95390be 100644 --- a/test/support/left_join_schemas.ex +++ b/test/support/left_join_schemas.ex @@ -7,6 +7,7 @@ defmodule TrunkSchema do schema "trunk_schema" do field :child, :integer field :child_name, :string, virtual: true + field :id_next, :integer, virtual: true end end