Skip to content

Commit

Permalink
optimized contained objectives
Browse files Browse the repository at this point in the history
  • Loading branch information
darrensiegel committed Dec 20, 2023
1 parent a326f88 commit cf2fc5a
Show file tree
Hide file tree
Showing 2 changed files with 62 additions and 52 deletions.
97 changes: 61 additions & 36 deletions lib/oli/delivery/sections.ex
Original file line number Diff line number Diff line change
Expand Up @@ -2108,63 +2108,88 @@ defmodule Oli.Delivery.Sections do
page_type_id = ResourceType.get_id_by_type("page")
activity_type_id = ResourceType.get_id_by_type("activity")

section_resource_pages =
from(
[sr: sr, rev: rev, s: s] in DeliveryResolver.section_resource_revisions(section_slug),
where: not rev.deleted and rev.resource_type_id == ^page_type_id
)
section_id = repo.one(from(s in Section, where: s.slug == ^section_slug, select: s.id))

section_resource_activities =
from(
[sr: sr, rev: rev, s: s] in DeliveryResolver.section_resource_revisions(section_slug),
where: not rev.deleted and rev.resource_type_id == ^activity_type_id,
select: rev
# Read current contained pages tuples
contained_pages = repo.all(
from(cp in ContainedPage,
where: cp.section_id == ^section_id
)
)

activity_references =
# Get all activity ids for all contained pages, via a JSONB query across model content
mark = Oli.Timing.mark()

page_activities =
from(
rev in Revision,
[rev: rev] in DeliveryResolver.section_resource_revisions(section_slug),
join: content_elem in fragment("jsonb_array_elements(?->'model')", rev.content),
on: true,
select: %{
revision_id: rev.id,
page_id: rev.resource_id,
activity_id: fragment("(?->>'activity_id')::integer", content_elem)
},
where: fragment("?->>'type'", content_elem) == "activity-reference"
where: not rev.deleted and rev.resource_type_id == ^page_type_id and fragment("?->>'type'", content_elem) == "activity-reference"
)
|> repo.all()
|> Enum.reduce(%{}, fn %{page_id: page_id, activity_id: activity_id}, acc ->
case Map.get(acc, page_id) do
nil -> Map.put(acc, page_id, [activity_id])
activities -> Map.put(acc, page_id, [activity_id | activities])
end
end)

Logger.info("build_contained_objectives pages: #{Oli.Timing.elapsed(mark) / 1000 / 1000}ms")
mark = Oli.Timing.mark()

activity_objectives =
from(
rev in Revision,
[rev: rev] in DeliveryResolver.section_resource_revisions(section_slug),
join: obj in fragment("jsonb_each_text(?)", rev.objectives),
on: true,
select: %{
objective_revision_id: rev.id,
objective_resource_id:
activity_id: rev.resource_id,
objective_id:
fragment("jsonb_array_elements_text(?::jsonb)::integer", obj.value)
},
where: rev.deleted == false and rev.resource_type_id == ^activity_type_id
)

contained_objectives =
from(
[sr: sr, rev: rev, s: s] in section_resource_pages,
join: cp in ContainedPage,
on: cp.page_id == rev.resource_id and cp.section_id == s.id,
join: ar in subquery(activity_references),
on: ar.revision_id == rev.id,
join: act in subquery(section_resource_activities),
on: act.resource_id == ar.activity_id,
join: ao in subquery(activity_objectives),
on: ao.objective_revision_id == act.id,
group_by: [cp.section_id, cp.container_id, ao.objective_resource_id],
select: %{
section_id: cp.section_id,
container_id: cp.container_id,
objective_id: ao.objective_resource_id
}
)
|> repo.all()
|> Enum.reduce(%{}, fn %{activity_id: activity_id, objective_id: objective_id}, acc ->
case Map.get(acc, activity_id) do
nil -> Map.put(acc, activity_id, [objective_id])
objs -> Map.put(acc, activity_id, [objective_id | objs])
end
end)

Logger.info("build_contained_objectives activities: #{Oli.Timing.elapsed(mark) / 1000 / 1000}ms")
mark = Oli.Timing.mark()

# Build a list of ContainedObjective tuples by mapping over the ContainedPages
# tuples
contained_objectives = Enum.map(contained_pages, fn cp ->

# Get the activity ids for the page
activity_ids = Map.get(page_activities, cp.page_id, [])

# Get the objective ids for the activities
objective_ids = Enum.flat_map(activity_ids, fn activity_id ->
Map.get(activity_objectives, activity_id, [])
end)

# Build a ContainedObjective tuple for each objective
Enum.map(objective_ids, fn objective_id ->
%{
section_id: section_id,
container_id: cp.container_id,
objective_id: objective_id
}
end)
end)
|> List.flatten()
|> Enum.uniq()

Logger.info("build_contained_objectives contained_objectives: #{Oli.Timing.elapsed(mark) / 1000 / 1000}ms")

{:ok, contained_objectives}
end
Expand Down
17 changes: 1 addition & 16 deletions lib/oli_web/live/new_course/new_course.ex
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ defmodule OliWeb.Delivery.NewCourse do
alias OliWeb.Common.{Breadcrumb, Stepper}
alias OliWeb.Common.Stepper.Step
alias OliWeb.Delivery.NewCourse.{CourseDetails, NameCourse, SelectSource}
import Oli.Timing
alias Lti_1p3.Tool.ContextRoles

alias Phoenix.LiveView.JS
Expand Down Expand Up @@ -366,31 +365,19 @@ defmodule OliWeb.Delivery.NewCourse do

defp create_from_publication(socket, publication, section_params) do

mark = mark()

ms = fn v -> elapsed(v) / 1000 / 1000 end

Repo.transaction(fn ->
with {:ok, section} <- Sections.create_section(section_params),
_ <- Logger.info("Created section in #{ms.(mark)} ms"),
{:ok, section} <- Sections.create_section_resources(section, publication),
_ <- Logger.info("Created section resources in #{ms.(mark)} ms"),
{:ok, _} <- Sections.rebuild_contained_pages(section),
_ <- Logger.info("Rebuild contained pages #{ms.(mark)} ms"),
{:ok, _} <- Sections.rebuild_contained_objectives(section),
_ <- Logger.info("Rebuild contained objectives #{ms.(mark)} ms"),
{:ok, _enrollment} <- enroll(socket, section),
_ <- Logger.info("Enrolled #{ms.(mark)} ms"),
{:ok, section} <-
Oli.Delivery.maybe_update_section_contains_explorations(section),
_ <- Logger.info("Maybe update section contains explor #{ms.(mark)} ms"),
{:ok, updated_section} <-
Oli.Delivery.maybe_update_section_contains_deliberate_practice(section),
_ <- Logger.info("Maybe update section deliberate practice #{ms.(mark)} ms") do
Oli.Delivery.maybe_update_section_contains_deliberate_practice(section) do
updated_section
else
{:error, changeset} ->
Logger.error("Failed to create section: #{inspect(changeset)}")
Repo.rollback(changeset)
end
end)
Expand Down Expand Up @@ -421,7 +408,6 @@ defmodule OliWeb.Delivery.NewCourse do

def handle_info({:section_created, section_slug}, socket) do
socket = put_flash(socket, :info, "Section successfully created.")
Logger.info("Handle info succeeded")
{:noreply,
redirect(socket,
to: Routes.live_path(OliWeb.Endpoint, OliWeb.Sections.OverviewView, section_slug)
Expand All @@ -430,7 +416,6 @@ defmodule OliWeb.Delivery.NewCourse do

def handle_info({:section_created_error, error_msg}, socket) do
socket = put_flash(socket, :form_error, error_msg)
Logger.info("Handle info failed")
{:noreply, socket}
end

Expand Down

0 comments on commit cf2fc5a

Please sign in to comment.