Skip to content

Commit b02b43c

Browse files
authored
Remove unnecessary trips to the DB (#1189)
* Use subquery to get submission IDs * Add TODO * Fix n+1 query problem * Fix typo * Fix tests * Comment Sentry DSN in example secrets * Fix admin assessments controller * fix: Fix n + 1 query in assessments_view * Fix format * Fix format
1 parent 6d33c09 commit b02b43c

File tree

7 files changed

+49
-56
lines changed

7 files changed

+49
-56
lines changed

config/dev.secrets.exs.example

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -104,8 +104,8 @@ config :cadet,
104104
# optional, passed to [HTTPoison.Request](https://hexdocs.pm/httpoison/HTTPoison.Request.html) options
105105
http_options: [recv_timeout: 170_0000]
106106

107-
config :sentry,
108-
dsn: "https://public_key/sentry.io/somethingsomething"
107+
# config :sentry,
108+
# dsn: "https://public_key/sentry.io/somethingsomething"
109109

110110
# # Additional configuration for SAML authentication
111111
# # For more details, see https://github.com/handnot2/samly

lib/cadet/assessments/assessments.ex

Lines changed: 38 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,7 @@ defmodule Cadet.Assessments do
113113
Submission
114114
|> where(
115115
[s],
116-
s.id in ^submission_ids
116+
s.id in subquery(submission_ids)
117117
)
118118
|> where(is_grading_published: true)
119119
|> join(:inner, [s], a in Answer, on: s.id == a.submission_id)
@@ -337,7 +337,7 @@ defmodule Cadet.Assessments do
337337
|> join(:left, [s], ans in Answer, on: ans.submission_id == s.id)
338338
|> where(
339339
[s],
340-
s.id in ^submission_ids
340+
s.id in subquery(submission_ids)
341341
)
342342
|> group_by([s], s.assessment_id)
343343
|> select([s, ans], %{
@@ -351,7 +351,7 @@ defmodule Cadet.Assessments do
351351
Submission
352352
|> where(
353353
[s],
354-
s.id in ^submission_ids
354+
s.id in subquery(submission_ids)
355355
)
356356
|> select([s], [:assessment_id, :status, :is_grading_published])
357357

@@ -382,21 +382,46 @@ defmodule Cadet.Assessments do
382382
end
383383

384384
defp get_submission_ids(cr_id, teams) do
385-
query =
386-
from(s in Submission,
387-
where: s.student_id == ^cr_id or s.team_id in ^Enum.map(teams, & &1.id),
388-
select: s.id
389-
)
385+
from(s in Submission,
386+
where: s.student_id == ^cr_id or s.team_id in ^Enum.map(teams, & &1.id),
387+
select: s.id
388+
)
389+
end
390390

391-
Repo.all(query)
391+
defp is_voting_assigned(assessment_ids) do
392+
voting_assigned_question_ids =
393+
SubmissionVotes
394+
|> select([v], v.question_id)
395+
|> Repo.all()
396+
397+
# Map of assessment_id to boolean
398+
voting_assigned_assessment_ids =
399+
Question
400+
|> where(type: :voting)
401+
|> where([q], q.id in ^voting_assigned_question_ids)
402+
|> where([q], q.assessment_id in ^assessment_ids)
403+
|> select([q], q.assessment_id)
404+
|> distinct(true)
405+
|> Repo.all()
406+
407+
Enum.reduce(assessment_ids, %{}, fn id, acc ->
408+
Map.put(acc, id, Enum.member?(voting_assigned_assessment_ids, id))
409+
end)
392410
end
393411

394412
@doc """
395413
A helper function which removes grading information from all assessments
396414
if it's grading is not published.
397415
"""
398416
def format_all_assessments(assessments) do
417+
is_voting_assigned_map =
418+
assessments
419+
|> Enum.map(& &1.id)
420+
|> is_voting_assigned()
421+
399422
Enum.map(assessments, fn a ->
423+
a = Map.put(a, :is_voting_published, Map.get(is_voting_assigned_map, a.id, false))
424+
400425
if a.is_grading_published do
401426
a
402427
else
@@ -653,17 +678,16 @@ defmodule Cadet.Assessments do
653678
end
654679
end
655680

656-
def is_voting_published(assessment_id) do
681+
defp is_voting_published(assessment_id) do
657682
voting_assigned_question_ids =
658683
SubmissionVotes
659684
|> select([v], v.question_id)
660-
|> Repo.all()
661685

662686
Question
663687
|> where(type: :voting)
664688
|> where(assessment_id: ^assessment_id)
665-
|> where([q], q.id in ^voting_assigned_question_ids)
666-
|> Repo.exists?()
689+
|> where([q], q.id in subquery(voting_assigned_question_ids))
690+
|> Repo.exists?() || false
667691
end
668692

669693
def update_final_contest_entries do
@@ -1442,6 +1466,7 @@ defmodule Cadet.Assessments do
14421466

14431467
@spec update_xp_bonus(Submission.t()) ::
14441468
{:ok, Submission.t()} | {:error, Ecto.Changeset.t()}
1469+
# TODO: Should destructure and pattern match on the function
14451470
defp update_xp_bonus(submission = %Submission{id: submission_id}) do
14461471
# to ensure backwards compatibility
14471472
if submission.xp_bonus == 0 do

lib/cadet_web/admin_controllers/admin_assessments_controller.ex

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ defmodule CadetWeb.AdminAssessmentsController do
1414
def index(conn, %{"course_reg_id" => course_reg_id}) do
1515
course_reg = Repo.get(CourseRegistration, course_reg_id)
1616
{:ok, assessments} = Assessments.all_assessments(course_reg)
17-
17+
assessments = Assessments.format_all_assessments(assessments)
1818
render(conn, "index.json", assessments: assessments)
1919
end
2020

lib/cadet_web/admin_views/admin_assessments_view.ex

Lines changed: 1 addition & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,6 @@ defmodule CadetWeb.AdminAssessmentsView do
22
use CadetWeb, :view
33
use Timex
44
import CadetWeb.AssessmentsHelpers
5-
import Ecto.Query
6-
alias Cadet.Assessments.{Question, SubmissionVotes}
7-
alias Cadet.Repo
85

96
def render("index.json", %{assessments: assessments}) do
107
render_many(assessments, CadetWeb.AdminAssessmentsView, "overview.json", as: :assessment)
@@ -35,7 +32,7 @@ defmodule CadetWeb.AdminAssessmentsView do
3532
maxTeamSize: :max_team_size,
3633
hasVotingFeatures: :has_voting_features,
3734
hasTokenCounter: :has_token_counter,
38-
isVotingPublished: &is_voting_assigned(&1.id)
35+
isVotingPublished: :is_voting_published
3936
})
4037
end
4138

@@ -84,17 +81,4 @@ defmodule CadetWeb.AdminAssessmentsView do
8481
defp password_protected?(nil), do: false
8582

8683
defp password_protected?(_), do: true
87-
88-
defp is_voting_assigned(assessment_id) do
89-
voting_assigned_question_ids =
90-
SubmissionVotes
91-
|> select([v], v.question_id)
92-
|> Repo.all()
93-
94-
Question
95-
|> where(type: :voting)
96-
|> where(assessment_id: ^assessment_id)
97-
|> where([q], q.id in ^voting_assigned_question_ids)
98-
|> Repo.exists?()
99-
end
10084
end

lib/cadet_web/views/assessments_view.ex

Lines changed: 1 addition & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,6 @@
11
defmodule CadetWeb.AssessmentsView do
22
use CadetWeb, :view
33
use Timex
4-
import Ecto.Query
5-
alias Cadet.Assessments.{Question, SubmissionVotes}
6-
alias Cadet.Repo
74

85
import CadetWeb.AssessmentsHelpers
96

@@ -37,7 +34,7 @@ defmodule CadetWeb.AssessmentsView do
3734
maxTeamSize: :max_team_size,
3835
hasVotingFeatures: :has_voting_features,
3936
hasTokenCounter: :has_token_counter,
40-
isVotingPublished: &is_voting_assigned(&1.id),
37+
isVotingPublished: :is_voting_published,
4138
hoursBeforeEarlyXpDecay: & &1.config.hours_before_early_xp_decay
4239
})
4340
end
@@ -87,17 +84,4 @@ defmodule CadetWeb.AssessmentsView do
8784
defp password_protected?(nil), do: false
8885

8986
defp password_protected?(_), do: true
90-
91-
defp is_voting_assigned(assessment_id) do
92-
voting_assigned_question_ids =
93-
SubmissionVotes
94-
|> select([v], v.question_id)
95-
|> Repo.all()
96-
97-
Question
98-
|> where(type: :voting)
99-
|> where(assessment_id: ^assessment_id)
100-
|> where([q], q.id in ^voting_assigned_question_ids)
101-
|> Repo.exists?()
102-
end
10387
end

test/cadet_web/admin_controllers/admin_assessments_controller_test.exs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -90,11 +90,11 @@ defmodule CadetWeb.AdminAssessmentsControllerTest do
9090
"isPublished" => &1.is_published,
9191
"gradedCount" => 0,
9292
"questionCount" => 9,
93-
"xp" => (800 + 500 + 100) * 3,
93+
"xp" => if(&1.is_grading_published, do: (800 + 500 + 100) * 3, else: 0),
9494
"earlySubmissionXp" => &1.config.early_submission_xp,
9595
"hasVotingFeatures" => &1.has_voting_features,
9696
"hasTokenCounter" => &1.has_token_counter,
97-
"isVotingPublished" => Assessments.is_voting_published(&1.id)
97+
"isVotingPublished" => false
9898
}
9999
)
100100

@@ -145,7 +145,7 @@ defmodule CadetWeb.AdminAssessmentsControllerTest do
145145
"earlySubmissionXp" => &1.config.early_submission_xp,
146146
"hasVotingFeatures" => &1.has_voting_features,
147147
"hasTokenCounter" => &1.has_token_counter,
148-
"isVotingPublished" => Assessments.is_voting_published(&1.id)
148+
"isVotingPublished" => false
149149
}
150150
)
151151

test/cadet_web/controllers/assessments_controller_test.exs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ defmodule CadetWeb.AssessmentsControllerTest do
8383
"earlySubmissionXp" => &1.config.early_submission_xp,
8484
"hasVotingFeatures" => &1.has_voting_features,
8585
"hasTokenCounter" => &1.has_token_counter,
86-
"isVotingPublished" => Assessments.is_voting_published(&1.id),
86+
"isVotingPublished" => false,
8787
"hoursBeforeEarlyXpDecay" => &1.config.hours_before_early_xp_decay
8888
}
8989
)
@@ -174,7 +174,7 @@ defmodule CadetWeb.AssessmentsControllerTest do
174174
"earlySubmissionXp" => &1.config.early_submission_xp,
175175
"hasVotingFeatures" => &1.has_voting_features,
176176
"hasTokenCounter" => &1.has_token_counter,
177-
"isVotingPublished" => Assessments.is_voting_published(&1.id),
177+
"isVotingPublished" => false,
178178
"hoursBeforeEarlyXpDecay" => &1.config.hours_before_early_xp_decay
179179
}
180180
)
@@ -288,7 +288,7 @@ defmodule CadetWeb.AssessmentsControllerTest do
288288
"questionCount" => 9,
289289
"hasVotingFeatures" => &1.has_voting_features,
290290
"hasTokenCounter" => &1.has_token_counter,
291-
"isVotingPublished" => Assessments.is_voting_published(&1.id),
291+
"isVotingPublished" => false,
292292
"earlySubmissionXp" => &1.config.early_submission_xp,
293293
"isGradingPublished" => nil,
294294
"hoursBeforeEarlyXpDecay" => &1.config.hours_before_early_xp_decay,

0 commit comments

Comments
 (0)