From 69e4cd4080f79e0a6ba1c624d9e0eceac1aae12b Mon Sep 17 00:00:00 2001 From: jatkowskee Date: Mon, 16 Oct 2017 21:50:46 +0200 Subject: [PATCH] enhancement(elixir): Preload all questions --- aion/lib/aion/room_channel/question_set.ex | 35 ++++++++++++++++++ aion/lib/aion/room_channel/room.ex | 41 +++++++++++---------- aion/test/lib/room_channel/monitor_test.exs | 2 +- aion/test/models/question_test.exs | 25 ++++++++++++- aion/web/models/question.ex | 12 +++++- 5 files changed, 93 insertions(+), 22 deletions(-) create mode 100644 aion/lib/aion/room_channel/question_set.ex diff --git a/aion/lib/aion/room_channel/question_set.ex b/aion/lib/aion/room_channel/question_set.ex new file mode 100644 index 0000000..a44d5b3 --- /dev/null +++ b/aion/lib/aion/room_channel/question_set.ex @@ -0,0 +1,35 @@ +defmodule Aion.RoomChannel.QuestionSet do + @moduledoc """ + This module provides logic for generating new question set + """ + alias Aion.{Question, Answer} + require Logger + + @type t :: %__MODULE__{questions: (list Question.t), current_question: Question.t, answers: (list Answer.t)} + + defstruct questions: [], + current_question: nil, + answers: [] + + @spec create((list Question.t), integer) :: __MODULE__.t + def create(questions, room_id) do + case questions do + [] -> + %{questions: [], current_question: nil, answers: []} + + [last_question] -> + remaining_questions = Question.get_questions_by_room_id(room_id) + build_new(last_question, remaining_questions) + + [next_question | remaining_questions] -> + build_new(next_question, remaining_questions) + end + end + + @spec build_new(Question.t, (list Question.t)) :: __MODULE__.t + defp build_new(current_question, remaining_questions) do + answers = Answer.get_answers(current_question.id) + Logger.debug fn -> "Answers: #{inspect(Enum.map(answers, fn answer -> answer.content end))}" end + %{questions: remaining_questions, current_question: current_question, answers: answers} + end +end diff --git a/aion/lib/aion/room_channel/room.ex b/aion/lib/aion/room_channel/room.ex index d16e923..6a5f401 100644 --- a/aion/lib/aion/room_channel/room.ex +++ b/aion/lib/aion/room_channel/room.ex @@ -3,28 +3,31 @@ defmodule Aion.RoomChannel.Room do This module represents one game room, and fetches resources from the db """ alias Aion.{Question, Answer} - alias Aion.RoomChannel.{Room, UserRecord} + alias Aion.RoomChannel.{Room, UserRecord, QuestionSet} require Logger @type t :: %__MODULE__{users: %{String.t => UserRecord.t}, users_count: integer, - question: Question.t, - answers: list Answer.t} + questions: (list Question.t), + current_question: Question.t, + answers: (list Answer.t)} defstruct users: %{}, users_count: 0, - question: nil, + questions: [], + current_question: nil, answers: [] - @spec new(integer, [question: nil | Question.t]) :: %__MODULE__{} + @spec new(integer, [current_question: nil | Question.t]) :: %__MODULE__{} def new(room_id, state \\ []) do case state do [] -> %Room{} + |> load_questions(room_id) |> change_question(room_id) - {:question, question} -> - %Room{question: question} + {:current_question, question} -> + %Room{current_question: question} _ -> Logger.error fn -> "Unexpected state passed to Room.new: #{state}" end %Room{} @@ -50,8 +53,17 @@ defmodule Aion.RoomChannel.Room do """ @spec change_question(%__MODULE__{}, integer) :: __MODULE__.t def change_question(room, room_id) do - room - |> struct(get_new_question_with_answers(room_id)) + new_questions_with_answers = QuestionSet.create(room.questions, room_id) + struct(room, new_questions_with_answers) + end + + @spec load_questions(%__MODULE__{}, integer) :: __MODULE__.t + def load_questions(room, room_id) do + questions = + room_id + |> Question.get_questions_by_room_id() + |> Enum.shuffle() + struct(room, %{questions: questions}) end @spec add_user(__MODULE__.t, UserRecord.t) :: __MODULE__.t @@ -73,15 +85,6 @@ defmodule Aion.RoomChannel.Room do @spec get_current_question(__MODULE__.t) :: Question.t def get_current_question(room) do - room.question - end - - @spec get_new_question_with_answers(integer) :: %{question: Question.t, answers: list Answer.t} - defp get_new_question_with_answers(room_id) do - question = Question.get_random_question(room_id) - answers = Answer.get_answers(question.id) - Logger.debug fn -> "Answers: #{inspect(Enum.map(answers, fn answer -> answer.content end))}" end - - %{question: question, answers: answers} + room.current_question end end diff --git a/aion/test/lib/room_channel/monitor_test.exs b/aion/test/lib/room_channel/monitor_test.exs index 78ce3ea..3a3024c 100644 --- a/aion/test/lib/room_channel/monitor_test.exs +++ b/aion/test/lib/room_channel/monitor_test.exs @@ -8,7 +8,7 @@ defmodule Aion.MonitorTest do @question %Question{content: "Content"} setup do - Monitor.create(@room_id, question: @question) + Monitor.create(@room_id, current_question: @question) :ok end diff --git a/aion/test/models/question_test.exs b/aion/test/models/question_test.exs index 73acecd..0aca781 100644 --- a/aion/test/models/question_test.exs +++ b/aion/test/models/question_test.exs @@ -1,7 +1,7 @@ defmodule Aion.QuestionTest do use Aion.ModelCase - alias Aion.Question + alias Aion.{Question, RoomCategory, Room, Category} @valid_attrs %{content: "some content", image_name: "some content"} @invalid_attrs %{} @@ -16,6 +16,29 @@ defmodule Aion.QuestionTest do refute changeset.valid? end + test "get_questions_by_room_id when there are no questions" do + room1 = Repo.insert! %Room{} + + result = Question.get_questions_by_room_id(room1.id) + assert length(result) == 0 + end + + test "get_questions_by_room_id when there are some questions" do + room1 = Repo.insert! %Room{} + room2 = Repo.insert! %Room{} + + question_1 = Repo.insert! %Question{category: (Repo.insert! %Category{})} + question_2 = Repo.insert! %Question{category: (Repo.insert! %Category{})} + question_3 = Repo.insert! %Question{category: (Repo.insert! %Category{})} + + room_category1 = Repo.insert! %RoomCategory{room_id: room1.id, category_id: question_1.category_id} + room_category2 = Repo.insert! %RoomCategory{room_id: room1.id, category_id: question_2.category_id} + room_category2 = Repo.insert! %RoomCategory{room_id: room2.id, category_id: question_3.category_id} + + result = Question.get_questions_by_room_id(room1.id) + assert length(result) == 2 + end + def get_question(question_id) do Repo.get(Question, question_id) end diff --git a/aion/web/models/question.ex b/aion/web/models/question.ex index 33e760d..a8cff5d 100644 --- a/aion/web/models/question.ex +++ b/aion/web/models/question.ex @@ -6,7 +6,7 @@ defmodule Aion.Question do use Aion.Web, :model alias Aion.Repo - alias Aion.{Question, Category} + alias Aion.{Question, Category, RoomCategory, Room} schema "questions" do field :content, :string @@ -36,6 +36,16 @@ defmodule Aion.Question do Repo.get(Question, question_id) end + @spec get_questions_by_room_id(integer) :: Question.t + def get_questions_by_room_id(room_id) do + Repo.all( + from q in Question, + join: rc in RoomCategory, on: rc.category_id == q.category_id, + join: r in Room, on: r.id == rc.room_id, + where: r.id == ^room_id + ) + end + @spec get_random_question(integer) :: Question.t def get_random_question(room_id) do query = Repo.query("