diff --git a/lib/lanttern/students_records/student_record.ex b/lib/lanttern/students_records/student_record.ex index 4d6ab6cf..b6a08db4 100644 --- a/lib/lanttern/students_records/student_record.ex +++ b/lib/lanttern/students_records/student_record.ex @@ -8,9 +8,11 @@ defmodule Lanttern.StudentsRecords.StudentRecord do import LantternWeb.Gettext + alias Lanttern.StudentsRecords.StudentRecordClassRelationship alias Lanttern.StudentsRecords.StudentRecordRelationship alias Lanttern.StudentsRecords.StudentRecordStatus alias Lanttern.StudentsRecords.StudentRecordType + alias Lanttern.Schools.Class alias Lanttern.Schools.School alias Lanttern.Schools.Student @@ -21,6 +23,9 @@ defmodule Lanttern.StudentsRecords.StudentRecord do date: Date.t(), time: Time.t(), students: [Student.t()], + students_ids: [pos_integer()], + classes: [Class.t()], + classes_ids: [pos_integer()], school_id: pos_integer(), school: School.t(), status_id: pos_integer(), @@ -37,17 +42,21 @@ defmodule Lanttern.StudentsRecords.StudentRecord do field :date, :date field :time, :time field :students_ids, {:array, :id}, virtual: true + field :classes_ids, {:array, :id}, virtual: true belongs_to :school, School belongs_to :status, StudentRecordStatus belongs_to :type, StudentRecordType has_many :students_relationships, StudentRecordRelationship, on_replace: :delete + has_many :classes_relationships, StudentRecordClassRelationship, on_replace: :delete many_to_many :students, Student, join_through: "students_students_records", preload_order: [asc: :name] + many_to_many :classes, Class, join_through: "students_records_classes" + timestamps() end @@ -60,12 +69,14 @@ defmodule Lanttern.StudentsRecords.StudentRecord do :date, :time, :students_ids, + :classes_ids, :school_id, :type_id, :status_id ]) |> validate_required([:description, :date, :school_id, :type_id, :status_id]) |> cast_and_validate_students() + |> cast_classes() end def cast_and_validate_students(changeset) do @@ -96,4 +107,21 @@ defmodule Lanttern.StudentsRecords.StudentRecord do end defp cast_students(changeset, _), do: changeset + + defp cast_classes(changeset) do + case get_change(changeset, :classes_ids) do + classes_ids when is_list(classes_ids) -> + school_id = get_field(changeset, :school_id) + + classes_relationships_params = + Enum.map(classes_ids, &%{class_id: &1, school_id: school_id}) + + changeset + |> put_change(:classes_relationships, classes_relationships_params) + |> cast_assoc(:classes_relationships) + + _ -> + changeset + end + end end diff --git a/lib/lanttern/students_records/student_record_class_relationship.ex b/lib/lanttern/students_records/student_record_class_relationship.ex new file mode 100644 index 00000000..8ea4e5c3 --- /dev/null +++ b/lib/lanttern/students_records/student_record_class_relationship.ex @@ -0,0 +1,22 @@ +defmodule Lanttern.StudentsRecords.StudentRecordClassRelationship do + @moduledoc """ + The `StudentRecordClassRelationship` schema (join table) + """ + + use Ecto.Schema + import Ecto.Changeset + + @primary_key false + schema "students_records_classes" do + field :student_record_id, :id, primary_key: true + field :class_id, :id, primary_key: true + field :school_id, :id + end + + @doc false + def changeset(student_record_class_relationship, attrs) do + student_record_class_relationship + |> cast(attrs, [:class_id, :student_record_id, :school_id]) + |> validate_required([:class_id, :student_record_id, :school_id]) + end +end diff --git a/lib/lanttern/students_records/student_record_relationship.ex b/lib/lanttern/students_records/student_record_relationship.ex index c0623074..9b3a85c9 100644 --- a/lib/lanttern/students_records/student_record_relationship.ex +++ b/lib/lanttern/students_records/student_record_relationship.ex @@ -16,7 +16,7 @@ defmodule Lanttern.StudentsRecords.StudentRecordRelationship do @doc false def changeset(student_record_relationship, attrs) do student_record_relationship - |> cast(attrs, [:student_id, :student_record_i, :school_id]) + |> cast(attrs, [:student_id, :student_record_id, :school_id]) |> validate_required([:student_id, :student_record_id, :school_id]) end end diff --git a/priv/repo/migrations/20241212195844_create_students_records_classes.exs b/priv/repo/migrations/20241212195844_create_students_records_classes.exs new file mode 100644 index 00000000..1ee3dbfb --- /dev/null +++ b/priv/repo/migrations/20241212195844_create_students_records_classes.exs @@ -0,0 +1,28 @@ +defmodule Lanttern.Repo.Migrations.CreateStudentsRecordsClasses do + use Ecto.Migration + + def change do + # creating unique constraints to allow composite foreign keys. + # this guarantees, in the database level, that record and class + # belong to the same school + + # removing existing "classes_school_id_index" to prevent unnecessary index + drop index(:classes, [:school_id]) + create unique_index(:classes, [:school_id, :id]) + + create table(:students_records_classes, primary_key: false) do + # in the future we will handle how to cascade class and school deletion to ss records + add :class_id, references(:classes, with: [school_id: :school_id], on_delete: :nothing), + null: false + + add :student_record_id, + references(:students_records, with: [school_id: :school_id], on_delete: :delete_all), + null: false + + add :school_id, references(:schools, on_delete: :nothing), null: false + end + + create index(:students_records_classes, [:class_id]) + create unique_index(:students_records_classes, [:student_record_id, :class_id]) + end +end