Skip to content

Commit bd93e86

Browse files
committed
Add various performance fixes for API endpoints
- Remove preloads from views and write explicitly in controllers - Reduce id filter repetition - Ensure id query filters are run on every controller that has an index action - Add missing indexes
1 parent 6f40cb4 commit bd93e86

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

42 files changed

+384
-137
lines changed

lib/code_corps/helpers/query.ex

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -36,14 +36,6 @@ defmodule CodeCorps.Helpers.Query do
3636

3737
# end task queries
3838

39-
# def comment queries
40-
41-
def task_filter(query, task_id) do
42-
query |> where([object], object.task_id == ^task_id)
43-
end
44-
45-
# end comment queries
46-
4739
# user queries
4840

4941
def user_filter(query, %{"query" => query_string}) do
@@ -61,8 +53,6 @@ defmodule CodeCorps.Helpers.Query do
6153

6254
# sorting
6355

64-
def sort_by_newest_first(query), do: query |> order_by([desc: :inserted_at])
65-
6656
def sort_by_order(query), do: query |> order_by([asc: :order])
6757

6858
# end sorting

lib/code_corps/task/query.ex

Lines changed: 22 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -19,44 +19,49 @@ defmodule CodeCorps.Task.Query do
1919
@spec list(map) :: list(Project.t)
2020
def list(%{} = params) do
2121
Task
22+
|> Helpers.Query.id_filter(params)
2223
|> apply_archived_status(params)
24+
|> apply_status(params)
2325
|> apply_optional_filters(params)
2426
|> order_by([asc: :order])
25-
|> Repo.all
27+
|> Repo.all()
2628
end
2729

2830
@spec apply_optional_filters(Queryable.t, map) :: Queryable.t
29-
defp apply_optional_filters(queryable, %{"filter" => %{} = params}) do
30-
queryable |> apply_optional_filters(params)
31+
defp apply_optional_filters(query, %{"filter" => %{} = params}) do
32+
query |> apply_optional_filters(params)
3133
end
32-
defp apply_optional_filters(queryable, %{"project_id" => project_id} = params) do
33-
queryable
34+
defp apply_optional_filters(query, %{"project_id" => project_id} = params) do
35+
query
3436
|> where(project_id: ^project_id)
3537
|> apply_optional_filters(params |> Map.delete("project_id"))
3638
end
37-
defp apply_optional_filters(queryable, %{"task_list_ids" => task_list_ids} = params) do
39+
defp apply_optional_filters(query, %{"task_list_ids" => task_list_ids} = params) do
3840
task_list_ids = task_list_ids |> Helpers.String.coalesce_id_string
3941

40-
queryable
42+
query
4143
|> where([r], r.task_list_id in ^task_list_ids)
4244
|> apply_optional_filters(params |> Map.delete("task_list_ids"))
4345
end
44-
defp apply_optional_filters(queryable, %{"status" => status} = params) do
45-
queryable
46-
|> where(status: ^status)
47-
|> apply_optional_filters(params |> Map.delete("status"))
48-
end
49-
defp apply_optional_filters(queryable, %{}), do: queryable
46+
defp apply_optional_filters(query, %{}), do: query
5047

5148
@spec apply_archived_status(Queryable.t, map) :: Queryable.t
52-
defp apply_archived_status(queryable, %{"archived" => archived}) do
53-
queryable
49+
defp apply_archived_status(query, %{"archived" => archived}) do
50+
query
5451
|> where(archived: ^archived)
5552
end
56-
defp apply_archived_status(queryable, %{}) do
57-
queryable
53+
defp apply_archived_status(query, %{}) do
54+
query
5855
|> where(archived: false)
5956
end
57+
58+
@spec apply_status(Queryable.t, map) :: Queryable.t
59+
defp apply_status(query, %{"status" => status}) do
60+
query
61+
|> where(status: ^status)
62+
end
63+
defp apply_status(query, %{}), do: query
64+
6065
@doc ~S"""
6166
Returns a `Task` record retrived using a set of parameters.
6267

lib/code_corps_web/controllers/category_controller.ex

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,21 +2,20 @@ defmodule CodeCorpsWeb.CategoryController do
22
@moduledoc false
33
use CodeCorpsWeb, :controller
44

5-
alias CodeCorps.{Category, User, Helpers.Query}
5+
alias CodeCorps.{Category, Repo, User, Helpers.Query}
66

77
action_fallback CodeCorpsWeb.FallbackController
88
plug CodeCorpsWeb.Plug.DataToAttributes
99

1010
@spec index(Conn.t, map) :: Conn.t
1111
def index(%Conn{} = conn, %{} = params) do
12-
with categories <- Category |> Query.id_filter(params) |> Repo.all do
13-
conn |> render("index.json-api", data: categories)
14-
end
12+
categories = Category |> Query.id_filter(params) |> Repo.all |> preload()
13+
conn |> render("index.json-api", data: categories)
1514
end
1615

1716
@spec show(Conn.t, map) :: Conn.t
1817
def show(%Conn{} = conn, %{"id" => id}) do
19-
with %Category{} = category <- Category |> Repo.get(id) do
18+
with %Category{} = category <- Category |> Repo.get(id) |> preload() do
2019
conn |> render("show.json-api", data: category)
2120
end
2221
end
@@ -25,7 +24,8 @@ defmodule CodeCorpsWeb.CategoryController do
2524
def create(%Conn{} = conn, %{} = params) do
2625
with %User{} = current_user <- conn |> Guardian.Plug.current_resource,
2726
{:ok, :authorized} <- current_user |> Policy.authorize(:create, %Category{}, params),
28-
{:ok, %Category{} = category} <- %Category{} |> Category.create_changeset(params) |> Repo.insert
27+
{:ok, %Category{} = category} <- %Category{} |> Category.create_changeset(params) |> Repo.insert,
28+
category <- preload(category)
2929
do
3030
conn |> put_status(:created) |> render("show.json-api", data: category)
3131
end
@@ -36,9 +36,16 @@ defmodule CodeCorpsWeb.CategoryController do
3636
with %Category{} = category <- Category |> Repo.get(id),
3737
%User{} = current_user <- conn |> Guardian.Plug.current_resource,
3838
{:ok, :authorized} <- current_user |> Policy.authorize(:update, category),
39-
{:ok, %Category{} = category} <- category |> Category.changeset(params) |> Repo.update
39+
{:ok, %Category{} = category} <- category |> Category.changeset(params) |> Repo.update,
40+
category <- preload(category)
4041
do
4142
conn |> render("show.json-api", data: category)
4243
end
4344
end
45+
46+
@preloads [:project_categories]
47+
48+
def preload(data) do
49+
Repo.preload(data, @preloads)
50+
end
4451
end

lib/code_corps_web/controllers/donation_goal_controller.ex

Lines changed: 21 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -11,14 +11,18 @@ defmodule CodeCorpsWeb.DonationGoalController do
1111

1212
@spec index(Conn.t, map) :: Conn.t
1313
def index(%Conn{} = conn, %{} = params) do
14-
with donation_goals <- DonationGoal |> Query.id_filter(params) |> Repo.all do
15-
conn |> render("index.json-api", data: donation_goals)
16-
end
14+
donation_goals =
15+
DonationGoal
16+
|> Query.id_filter(params)
17+
|> Repo.all
18+
|> preload()
19+
20+
conn |> render("index.json-api", data: donation_goals)
1721
end
1822

1923
@spec show(Conn.t, map) :: Conn.t
2024
def show(%Conn{} = conn, %{"id" => id}) do
21-
with %DonationGoal{} = donation_goal <- DonationGoal |> Repo.get(id) do
25+
with %DonationGoal{} = donation_goal <- DonationGoal |> Repo.get(id) |> preload() do
2226
conn |> render("show.json-api", data: donation_goal)
2327
end
2428
end
@@ -27,7 +31,9 @@ defmodule CodeCorpsWeb.DonationGoalController do
2731
def create(%Conn{} = conn, %{} = params) do
2832
with %User{} = current_user <- conn |> Guardian.Plug.current_resource,
2933
{:ok, :authorized} <- current_user |> Policy.authorize(:create, %DonationGoal{}, params),
30-
{:ok, %DonationGoal{} = donation_goal} <- DonationGoalsService.create(params) do
34+
{:ok, %DonationGoal{} = donation_goal} <- DonationGoalsService.create(params),
35+
donation_goal <- preload(donation_goal)
36+
do
3137
conn |> put_status(:created) |> render("show.json-api", data: donation_goal)
3238
end
3339
end
@@ -48,8 +54,16 @@ defmodule CodeCorpsWeb.DonationGoalController do
4854
with %DonationGoal{} = donation_goal <- DonationGoal |> Repo.get(id),
4955
%User{} = current_user <- conn |> Guardian.Plug.current_resource,
5056
{:ok, :authorized} <- current_user |> Policy.authorize(:update, donation_goal),
51-
{:ok, %DonationGoal{} = updated_donation_goal} <- donation_goal |> DonationGoalsService.update(params) do
52-
conn |> render("show.json-api", data: updated_donation_goal)
57+
{:ok, %DonationGoal{} = updated_donation_goal} <- donation_goal |> DonationGoalsService.update(params),
58+
updated_donation_goal <- preload(updated_donation_goal)
59+
do
60+
conn |> render("show.json-api", data: updated_donation_goal)
5361
end
5462
end
63+
64+
@preloads [:project]
65+
66+
def preload(data) do
67+
Repo.preload(data, @preloads)
68+
end
5569
end

lib/code_corps_web/controllers/github_app_installation_controller.ex

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -12,14 +12,18 @@ defmodule CodeCorpsWeb.GithubAppInstallationController do
1212

1313
@spec index(Conn.t, map) :: Conn.t
1414
def index(%Conn{} = conn, %{} = params) do
15-
with installations <- GithubAppInstallation |> id_filter(params) |> Repo.all do
16-
conn |> render("index.json-api", data: installations)
17-
end
15+
installations =
16+
GithubAppInstallation
17+
|> id_filter(params)
18+
|> Repo.all()
19+
|> preload()
20+
21+
conn |> render("index.json-api", data: installations)
1822
end
1923

2024
@spec show(Conn.t, map) :: Conn.t
2125
def show(%Conn{} = conn, %{"id" => id}) do
22-
with %GithubAppInstallation{} = installation <- GithubAppInstallation |> Repo.get(id) do
26+
with %GithubAppInstallation{} = installation <- GithubAppInstallation |> Repo.get(id) |> preload() do
2327
conn |> render("show.json-api", data: installation)
2428
end
2529
end
@@ -28,13 +32,20 @@ defmodule CodeCorpsWeb.GithubAppInstallationController do
2832
def create(%Conn{} = conn, %{} = params) do
2933
with %User{} = current_user <- conn |> Guardian.Plug.current_resource,
3034
{:ok, :authorized} <- current_user |> Policy.authorize(:create, %GithubAppInstallation{}, params),
31-
{:ok, %GithubAppInstallation{} = installation} <- %GithubAppInstallation{} |> GithubAppInstallation.create_changeset(params) |> Repo.insert do
32-
35+
{:ok, %GithubAppInstallation{} = installation} <- %GithubAppInstallation{} |> GithubAppInstallation.create_changeset(params) |> Repo.insert,
36+
installation <- preload(installation)
37+
do
3338
current_user |> track_created(installation)
3439
conn |> put_status(:created) |> render("show.json-api", data: installation)
3540
end
3641
end
3742

43+
@preloads [:github_repos, :organization_github_app_installations]
44+
45+
def preload(data) do
46+
Repo.preload(data, @preloads)
47+
end
48+
3849
@spec track_created(User.t, GithubAppInstallation.t) :: any
3950
defp track_created(%User{id: user_id}, %GithubAppInstallation{} = installation) do
4051
user_id |> SegmentTracker.track("Created GitHub App Installation", installation)

lib/code_corps_web/controllers/organization_controller.ex

Lines changed: 23 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4,19 +4,24 @@ defmodule CodeCorpsWeb.OrganizationController do
44

55
alias CodeCorps.{Helpers.Query, Organization, User}
66

7-
action_fallback CodeCorpsWeb.FallbackController
8-
plug CodeCorpsWeb.Plug.DataToAttributes
7+
action_fallback CodeCorpsWeb.FallbackController
8+
plug CodeCorpsWeb.Plug.DataToAttributes
99

1010
@spec index(Conn.t, map) :: Conn.t
1111
def index(%Conn{} = conn, %{} = params) do
12-
with organizations <- Organization |> Query.id_filter(params) |> Repo.all do
13-
conn |> render("index.json-api", data: organizations)
14-
end
12+
organizations =
13+
Organization
14+
|> Query.id_filter(params)
15+
|> Repo.all
16+
|> preload()
17+
18+
conn |> render("index.json-api", data: organizations)
1519
end
1620

1721
@spec show(Conn.t, map) :: Conn.t
1822
def show(%Conn{} = conn, %{"id" => id}) do
19-
with %Organization{} = organization <- Organization |> Repo.get(id) do
23+
with %Organization{} = organization <- Organization |> Repo.get(id) |> preload()
24+
do
2025
conn |> render("show.json-api", data: organization)
2126
end
2227
end
@@ -25,7 +30,9 @@ defmodule CodeCorpsWeb.OrganizationController do
2530
def create(%Conn{} = conn, %{} = params) do
2631
with %User{} = current_user <- conn |> Guardian.Plug.current_resource,
2732
{:ok, :authorized} <- current_user |> Policy.authorize(:create, %Organization{}, params),
28-
{:ok, %Organization{} = organization} <- %Organization{} |> Organization.create_changeset(params) |> Repo.insert do
33+
{:ok, %Organization{} = organization} <- %Organization{} |> Organization.create_changeset(params) |> Repo.insert,
34+
organization <- preload(organization)
35+
do
2936
conn |> put_status(:created) |> render("show.json-api", data: organization)
3037
end
3138
end
@@ -35,8 +42,16 @@ defmodule CodeCorpsWeb.OrganizationController do
3542
with %Organization{} = organization <- Organization |> Repo.get(id),
3643
%User{} = current_user <- conn |> Guardian.Plug.current_resource,
3744
{:ok, :authorized} <- current_user |> Policy.authorize(:update, organization),
38-
{:ok, %Organization{} = organization} <- organization |> Organization.changeset(params) |> Repo.update do
45+
{:ok, %Organization{} = organization} <- organization |> Organization.changeset(params) |> Repo.update,
46+
organization <- preload(organization)
47+
do
3948
conn |> render("show.json-api", data: organization)
4049
end
4150
end
51+
52+
@preloads [:organization_github_app_installations, :projects, :slugged_route, :stripe_connect_account]
53+
54+
def preload(data) do
55+
Repo.preload(data, @preloads)
56+
end
4257
end

lib/code_corps_web/controllers/project_controller.ex

Lines changed: 21 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -9,14 +9,14 @@ defmodule CodeCorpsWeb.ProjectController do
99

1010
@spec index(Conn.t, map) :: Conn.t
1111
def index(%Conn{} = conn, %{} = params) do
12-
with projects <- Project.Query.list(params) do
12+
with projects <- Project.Query.list(params) |> preload do
1313
conn |> render("index.json-api", data: projects)
1414
end
1515
end
1616

1717
@spec show(Conn.t, map) :: Conn.t
1818
def show(%Conn{} = conn, %{} = params) do
19-
with %Project{} = project <- Project.Query.find(params) do
19+
with %Project{} = project <- Project.Query.find(params) |> preload do
2020
conn |> render("show.json-api", data: project)
2121
end
2222
end
@@ -25,18 +25,32 @@ defmodule CodeCorpsWeb.ProjectController do
2525
def create(%Conn{} = conn, %{} = params) do
2626
with %User{} = current_user <- conn |> Guardian.Plug.current_resource,
2727
{:ok, :authorized} <- current_user |> Policy.authorize(:create, %Project{}, params),
28-
{:ok, %Project{} = project} <- %Project{} |> Project.create_changeset(params) |> Repo.insert do
28+
{:ok, %Project{} = project} <- %Project{} |> Project.create_changeset(params) |> Repo.insert,
29+
project <- preload(project)
30+
do
2931
conn |> put_status(:created) |> render("show.json-api", data: project)
3032
end
3133
end
3234

3335
@spec update(Conn.t, map) :: Conn.t
3436
def update(%Conn{} = conn, %{} = params) do
3537
with %Project{} = project <- Project.Query.find(params),
36-
%User{} = current_user <- conn |> Guardian.Plug.current_resource,
37-
{:ok, :authorized} <- current_user |> Policy.authorize(:update, project),
38-
{:ok, %Project{} = project} <- project |> Project.changeset(params) |> Repo.update do
39-
conn |> render("show.json-api", data: project)
38+
%User{} = current_user <- conn |> Guardian.Plug.current_resource,
39+
{:ok, :authorized} <- current_user |> Policy.authorize(:update, project),
40+
{:ok, %Project{} = project} <- project |> Project.changeset(params) |> Repo.update,
41+
project <- preload(project)
42+
do
43+
conn |> render("show.json-api", data: project)
4044
end
4145
end
46+
47+
@preloads [
48+
:donation_goals, [organization: :stripe_connect_account],
49+
:project_categories, :project_github_repos, :project_skills,
50+
:project_users, :stripe_connect_plan, :task_lists, :tasks
51+
]
52+
53+
def preload(data) do
54+
Repo.preload(data, @preloads)
55+
end
4256
end

lib/code_corps_web/controllers/role_controller.ex

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,14 +10,13 @@ defmodule CodeCorpsWeb.RoleController do
1010

1111
@spec index(Conn.t, map) :: Conn.t
1212
def index(%Conn{} = conn, %{} = params) do
13-
with roles <- Role |> Query.id_filter(params) |> Repo.all do
14-
conn |> render("index.json-api", data: roles)
15-
end
13+
roles = Role |> Query.id_filter(params) |> Repo.all |> preload()
14+
conn |> render("index.json-api", data: roles)
1615
end
1716

1817
@spec show(Conn.t, map) :: Conn.t
1918
def show(%Conn{} = conn, %{"id" => id}) do
20-
with %Role{} = role <- Role |> Repo.get(id) do
19+
with %Role{} = role <- Role |> Repo.get(id) |> preload() do
2120
conn |> render("show.json-api", data: role)
2221
end
2322
end
@@ -26,8 +25,16 @@ defmodule CodeCorpsWeb.RoleController do
2625
def create(%Conn{} = conn, %{} = params) do
2726
with %User{} = current_user <- conn |> Guardian.Plug.current_resource,
2827
{:ok, :authorized} <- current_user |> Policy.authorize(:create, %Role{}, params),
29-
{:ok, %Role{} = role} <- %Role{} |> Role.changeset(params) |> Repo.insert do
28+
{:ok, %Role{} = role} <- %Role{} |> Role.changeset(params) |> Repo.insert,
29+
role = preload(role)
30+
do
3031
conn |> put_status(:created) |> render("show.json-api", data: role)
3132
end
3233
end
34+
35+
@preloads [:role_skills]
36+
37+
def preload(data) do
38+
Repo.preload(data, @preloads)
39+
end
3340
end

0 commit comments

Comments
 (0)