From 0d4deb680576c6c420fe7936c94da4adf8f9e2c4 Mon Sep 17 00:00:00 2001 From: shibao Date: Sat, 18 Mar 2023 13:46:26 -0400 Subject: [PATCH] fix n+1 queries with invite card --- lib/memex/accounts/invites.ex | 20 +- lib/memex_web/components/core_components.ex | 58 +----- .../core_components/invite_card.html.heex | 48 +++++ lib/memex_web/live/invite_live/index.ex | 4 +- .../live/invite_live/index.html.heex | 7 +- priv/gettext/actions.pot | 10 +- priv/gettext/de/LC_MESSAGES/actions.po | 10 +- priv/gettext/de/LC_MESSAGES/default.po | 18 +- priv/gettext/de/LC_MESSAGES/prompts.po | 8 +- priv/gettext/default.pot | 18 +- priv/gettext/en/LC_MESSAGES/actions.po | 10 +- priv/gettext/en/LC_MESSAGES/default.po | 18 +- priv/gettext/en/LC_MESSAGES/prompts.po | 8 +- priv/gettext/prompts.pot | 8 +- test/memex/accounts/invites_test.exs | 36 +++- test/memex/accounts/invites_text.exs | 176 ------------------ 16 files changed, 164 insertions(+), 293 deletions(-) create mode 100644 lib/memex_web/components/core_components/invite_card.html.heex delete mode 100644 test/memex/accounts/invites_text.exs diff --git a/lib/memex/accounts/invites.ex b/lib/memex/accounts/invites.ex index 2bc74cf..923022c 100644 --- a/lib/memex/accounts/invites.ex +++ b/lib/memex/accounts/invites.ex @@ -100,13 +100,23 @@ defmodule Memex.Accounts.Invites do end end - @spec get_use_count(Invite.t(), User.t()) :: non_neg_integer() - def get_use_count(%Invite{id: invite_id}, %User{role: :admin}) do - Repo.one( + @spec get_use_count(Invite.t(), User.t()) :: non_neg_integer() | nil + def get_use_count(%Invite{id: invite_id} = invite, user) do + [invite] |> get_use_counts(user) |> Map.get(invite_id) + end + + @spec get_use_counts([Invite.t()], User.t()) :: + %{optional(Invite.id()) => non_neg_integer()} + def get_use_counts(invites, %User{role: :admin}) do + invite_ids = invites |> Enum.map(fn %{id: invite_id} -> invite_id end) + + Repo.all( from u in User, - where: u.invite_id == ^invite_id, - select: count(u.id) + where: u.invite_id in ^invite_ids, + group_by: u.invite_id, + select: {u.invite_id, count(u.id)} ) + |> Map.new() end @spec decrement_invite_changeset(Invite.t()) :: Invite.changeset() diff --git a/lib/memex_web/components/core_components.ex b/lib/memex_web/components/core_components.ex index ecc9bff..f089650 100644 --- a/lib/memex_web/components/core_components.ex +++ b/lib/memex_web/components/core_components.ex @@ -4,7 +4,7 @@ defmodule MemexWeb.CoreComponents do """ use Phoenix.Component import MemexWeb.{Gettext, ViewHelpers} - alias Memex.{Accounts, Accounts.Invite, Accounts.Invites, Accounts.User} + alias Memex.{Accounts, Accounts.Invite, Accounts.User} alias Memex.Contexts.Context alias Memex.Notes.Note alias Memex.Pipelines.Steps.Step @@ -77,64 +77,12 @@ defmodule MemexWeb.CoreComponents do def user_card(assigns) attr :invite, Invite, required: true + attr :use_count, :integer, default: nil attr :current_user, User, required: true slot(:inner_block) slot(:code_actions) - def invite_card(%{invite: invite, current_user: current_user} = assigns) do - assigns = assigns |> assign(:use_count, Invites.get_use_count(invite, current_user)) - - ~H""" -
-

- <%= @invite.name %> -

- - <%= if @invite.disabled_at |> is_nil() do %> -

- <%= if @invite.uses_left do %> - <%= gettext( - "uses left: %{uses_left_count}", - uses_left_count: @invite.uses_left - ) %> - <% else %> - <%= gettext("uses left: unlimited") %> - <% end %> -

- <% else %> -

- <%= gettext("invite disabled") %> -

- <% end %> - - <.qr_code - content={Routes.user_registration_url(Endpoint, :new, invite: @invite.token)} - filename={@invite.name} - /> - -

- <%= gettext("uses: %{uses_count}", uses_count: @use_count) %> -

- -
- <%= Routes.user_registration_url(Endpoint, :new, invite: @invite.token) %> - <%= if @code_actions, do: render_slot(@code_actions) %> -
- -
- <%= render_slot(@inner_block) %> -
-
- """ - end + def invite_card(assigns) attr :id, :string, required: true attr :datetime, :any, required: true, doc: "A `DateTime` struct or nil" diff --git a/lib/memex_web/components/core_components/invite_card.html.heex b/lib/memex_web/components/core_components/invite_card.html.heex new file mode 100644 index 0000000..da0374a --- /dev/null +++ b/lib/memex_web/components/core_components/invite_card.html.heex @@ -0,0 +1,48 @@ +
+

+ <%= @invite.name %> +

+ + <%= if @invite.disabled_at |> is_nil() do %> +

+ <%= if @invite.uses_left do %> + <%= gettext( + "uses left: %{uses_left_count}", + uses_left_count: @invite.uses_left + ) %> + <% else %> + <%= gettext("uses left: unlimited") %> + <% end %> +

+ <% else %> +

+ <%= gettext("invite disabled") %> +

+ <% end %> + + <.qr_code + content={Routes.user_registration_url(Endpoint, :new, invite: @invite.token)} + filename={@invite.name} + /> + +

+ <%= gettext("uses: %{uses_count}", uses_count: @use_count) %> +

+ +
+ <%= Routes.user_registration_url(Endpoint, :new, invite: @invite.token) %> + <%= if @code_actions, do: render_slot(@code_actions) %> +
+ +
+ <%= render_slot(@inner_block) %> +
+
diff --git a/lib/memex_web/live/invite_live/index.ex b/lib/memex_web/live/invite_live/index.ex index 66fdecd..784e14e 100644 --- a/lib/memex_web/live/invite_live/index.ex +++ b/lib/memex_web/live/invite_live/index.ex @@ -148,7 +148,9 @@ defmodule MemexWeb.InviteLive.Index do |> Map.get(:admin, []) |> Enum.reject(fn %{id: user_id} -> user_id == current_user.id end) + use_counts = invites |> Invites.get_use_counts(current_user) users = all_users |> Map.get(:user, []) - socket |> assign(invites: invites, admins: admins, users: users) + + socket |> assign(invites: invites, use_counts: use_counts, admins: admins, users: users) end end diff --git a/lib/memex_web/live/invite_live/index.html.heex b/lib/memex_web/live/invite_live/index.html.heex index 88de97f..bbe0c18 100644 --- a/lib/memex_web/live/invite_live/index.html.heex +++ b/lib/memex_web/live/invite_live/index.html.heex @@ -14,7 +14,12 @@ <% end %>
- <.invite_card :for={invite <- @invites} invite={invite} current_user={@current_user}> + <.invite_card + :for={invite <- @invites} + invite={invite} + current_user={@current_user} + use_count={Map.get(@use_counts, invite.id)} + > <:code_actions>