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

perf: add InfiniteScroll on transfers page #214

Merged
merged 5 commits into from
Feb 17, 2024
Merged
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
25 changes: 22 additions & 3 deletions apps/app/lib/app/transfers.ex
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,13 @@ defmodule App.Transfers do
@doc """
Find all money transfers of a book.

The result may be filtered by passing a map of filters.
The result may be filtered by passing a options.

## Options

- `:filters` - a map of filters to apply to the query. See the `Filters` section below.
- `:offset` - the offset of the query
- `:limit` - the limit of the query

## Filters

Expand All @@ -40,10 +46,15 @@ defmodule App.Transfers do
- `:tenanted_by` - the tenancy of the transfer, one of :anyone, a member id or
`{:not, member_id}`
"""
@spec list_transfers_of_book(Book.t(), map()) :: [MoneyTransfer.t()]
def list_transfers_of_book(%Book{} = book, filters \\ %{}) do
@spec list_transfers_of_book(Book.t(), Keyword.t()) :: [MoneyTransfer.t()]
def list_transfers_of_book(%Book{} = book, opts \\ []) do
filters = Keyword.get(opts, :filters, %{})
offset = Keyword.get(opts, :offset, 0)
limit = Keyword.get(opts, :limit, 25)

MoneyTransfer.transfers_of_book_query(book)
|> filter_money_transfers_query(filters)
|> paginate_query(offset, limit)
|> Repo.all()
end

Expand Down Expand Up @@ -118,6 +129,14 @@ defmodule App.Transfers do
where: money_transfer.tenant_id == ^member_id
)

## Pagination

defp paginate_query(query, offset, limit) do
query
|> limit(^limit)
|> offset(^offset)
end

## Amount summary

@typep amount_summary :: %{
Expand Down
97 changes: 89 additions & 8 deletions apps/app/test/app/transfers_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ defmodule App.TransfersTest do
alias App.Transfers
alias App.Transfers.Peer

describe "list_transfers_of_book/1" do
describe "list_transfers_of_book/2" do
setup :book_with_member_context

test "lists all transfers in book", %{book: book, member: member} do
Expand All @@ -29,15 +29,15 @@ defmodule App.TransfersTest do
transfer1 = money_transfer_fixture(book, date: ~D[2020-06-29], tenant_id: member.id)
transfer2 = money_transfer_fixture(book, date: ~D[2020-06-30], tenant_id: member.id)

assert Transfers.list_transfers_of_book(book, %{sort_by: :most_recent})
assert Transfers.list_transfers_of_book(book, filters: %{sort_by: :most_recent})
|> Enum.map(& &1.id) == [transfer2.id, transfer1.id]
end

test "sorts by oldest", %{book: book, member: member} do
transfer1 = money_transfer_fixture(book, date: ~D[2020-06-29], tenant_id: member.id)
transfer2 = money_transfer_fixture(book, date: ~D[2020-06-30], tenant_id: member.id)

assert Transfers.list_transfers_of_book(book, %{sort_by: :oldest})
assert Transfers.list_transfers_of_book(book, filters: %{sort_by: :oldest})
|> Enum.map(& &1.id) == [transfer1.id, transfer2.id]
end

Expand All @@ -48,7 +48,7 @@ defmodule App.TransfersTest do
transfer2 =
money_transfer_fixture(book, inserted_at: ~N[2020-06-30 12:00:00], tenant_id: member.id)

assert Transfers.list_transfers_of_book(book, %{sort_by: :last_created})
assert Transfers.list_transfers_of_book(book, filters: %{sort_by: :last_created})
|> Enum.map(& &1.id) == [transfer2.id, transfer1.id]
end

Expand All @@ -59,7 +59,7 @@ defmodule App.TransfersTest do
transfer2 =
money_transfer_fixture(book, inserted_at: ~N[2020-06-30 12:00:00], tenant_id: member.id)

assert Transfers.list_transfers_of_book(book, %{sort_by: :first_created})
assert Transfers.list_transfers_of_book(book, filters: %{sort_by: :first_created})
|> Enum.map(& &1.id) == [transfer1.id, transfer2.id]
end

Expand All @@ -70,7 +70,7 @@ defmodule App.TransfersTest do
member2 = book_member_fixture(book)
transfer2 = money_transfer_fixture(book, tenant_id: member2.id)

assert Transfers.list_transfers_of_book(book, %{tenanted_by: :anyone})
assert Transfers.list_transfers_of_book(book, filters: %{tenanted_by: :anyone})
|> Enum.map(& &1.id)
|> Enum.sort() == [transfer1.id, transfer2.id]
end
Expand All @@ -82,7 +82,7 @@ defmodule App.TransfersTest do
member2 = book_member_fixture(book)
_transfer2 = money_transfer_fixture(book, tenant_id: member2.id)

assert Transfers.list_transfers_of_book(book, %{tenanted_by: member1.id})
assert Transfers.list_transfers_of_book(book, filters: %{tenanted_by: member1.id})
|> Enum.map(& &1.id) == [transfer1.id]
end

Expand All @@ -93,9 +93,90 @@ defmodule App.TransfersTest do
member2 = book_member_fixture(book)
transfer2 = money_transfer_fixture(book, tenant_id: member2.id)

assert Transfers.list_transfers_of_book(book, %{tenanted_by: {:not, member1.id}})
assert Transfers.list_transfers_of_book(book, filters: %{tenanted_by: {:not, member1.id}})
|> Enum.map(& &1.id) == [transfer2.id]
end

test "paginates results", %{book: book, member: member} do
transfer1 = money_transfer_fixture(book, tenant_id: member.id, date: ~D[2020-06-29])
transfer2 = money_transfer_fixture(book, tenant_id: member.id, date: ~D[2020-06-30])

assert Transfers.list_transfers_of_book(book, offset: 0, limit: 1)
|> Enum.map(& &1.id) == [transfer2.id]

assert Transfers.list_transfers_of_book(book, offset: 1, limit: 1)
|> Enum.map(& &1.id) == [transfer1.id]

assert Transfers.list_transfers_of_book(book, offset: 0, limit: 25)
|> Enum.map(& &1.id) == [transfer2.id, transfer1.id]
end

test "paginated results are filtered and consistent", %{book: book} do
member1 = book_member_fixture(book)
member2 = book_member_fixture(book)

transfer1 = money_transfer_fixture(book, tenant_id: member1.id, date: ~D[2020-06-29])
_transfer2 = money_transfer_fixture(book, tenant_id: member1.id, date: ~D[2020-06-30])
transfer3 = money_transfer_fixture(book, tenant_id: member2.id, date: ~D[2020-06-28])

assert Transfers.list_transfers_of_book(book,
filters: %{tenanted_by: member2.id},
offset: 0,
limit: 25
)
|> Enum.map(& &1.id) == [transfer3.id]

assert Transfers.list_transfers_of_book(book,
filters: %{tenanted_by: {:not, member2.id}},
offset: 1,
limit: 25
)
|> Enum.map(& &1.id) == [transfer1.id]
end

test "paginated results are sorted and consistent", %{book: book, member: member} do
transfer1 =
money_transfer_fixture(book,
tenant_id: member.id,
date: ~D[2020-06-29],
inserted_at: ~N[2020-06-29 12:00:00]
)

transfer2 =
money_transfer_fixture(book,
tenant_id: member.id,
date: ~D[2020-06-30],
inserted_at: ~N[2020-06-30 12:00:00]
)

transfer3 =
money_transfer_fixture(book,
tenant_id: member.id,
date: ~D[2020-06-28],
inserted_at: ~N[2020-06-28 12:00:00]
)

assert Transfers.list_transfers_of_book(book,
filters: %{sort_by: :most_recent},
offset: 0,
limit: 25
)
|> Enum.map(& &1.id) == [transfer2.id, transfer1.id, transfer3.id]

assert Transfers.list_transfers_of_book(book,
filters: %{sort_by: :oldest},
offset: 2,
limit: 25
)
|> Enum.map(& &1.id) == [transfer2.id]

assert Transfers.list_transfers_of_book(book,
filters: %{sort_by: :last_created},
offset: 1,
limit: 25
)
|> Enum.map(& &1.id) == [transfer1.id, transfer3.id]
end
end

describe "list_transfers_of_members/1" do
Expand Down
1 change: 0 additions & 1 deletion apps/app_web/lib/app_web/live/book_balance_live.ex
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,6 @@ defmodule AppWeb.BookBalanceLive do
socket
|> assign(
page_title: "Balance · #{book.name}",
layout_heading: gettext("Balance"),
current_transaction: nil
)
|> assign_transactions()
Expand Down
6 changes: 1 addition & 5 deletions apps/app_web/lib/app_web/live/book_members_live.ex
Original file line number Diff line number Diff line change
Expand Up @@ -84,11 +84,7 @@ defmodule AppWeb.BookMembersLive do
def mount(_params, _session, socket) do
book = socket.assigns.book

socket =
assign(socket,
page_title: book.name,
layout_heading: gettext("Details")
)
socket = assign(socket, page_title: book.name)

{:ok, socket, layout: {AppWeb.Layouts, :book}}
end
Expand Down
Loading
Loading