For the tasks
schema below, I’m trying to add linking tasks to one another with a many_to_many
relationship joined through a task_links
table.
schema "tasks" do
field :title, :integer
field :description, :string
belongs_to :assignee, User
timestamps()
end
The task_links
table is setup as follows:
def change do
create table(:task_links) do
add :left_task_id, references(:tasks)
add :right_task_id, references(:tasks)
add :creator_id, references(:users)
timestamps()
end
create constraint(:task_links, :left_less_than_right_check, check: "left_task_id < right_task_id")
create unique_index(:task_links, [:left_task_id, :right_task_id])
end
The check constraint and unique index are used to ensure links aren’t duplicated.
My question is, what is the best way to alter the tasks
schema (or my approach to linking tasks) so queries preloading the task_links
association return a single list of linked tasks?
The issues is a task’s id
can be in the :left_task_id
or :right_task_id
column of the task_links
table. I’ve almost achieved my goal with two many-to-many relationships:
schema "tasks" do
...
many_to_many :right_links, Task, join_through: TaskLinks, join_keys: [left_task_id: :id, right_task_id: :id]
many_to_many :left_links, Task, join_through: TaskLinks, join_keys: [right_task_id: :id, left_task_id: :id]
end
This setup is close to what I’m aiming for, but the query below returns links separately depending on whether the target task’s id
was in the :left_task_id
or right_task_id
column of the task_links
table:
def get_task_and_links(task_id) do
from(t in Task,
left_join: right in assoc(t, :right_links),
left_join: left in assoc(t, :left_links),
preload [right_links: right, left_links: left]
where: t.id == ^task_id
) |> Repo.one
-----------------
iex(1)> Tasks.get_task_and_links(6)
%Task{
id: 6,
...,
left_links: [
%Task{id: 4, ...},
%Task{id: 5, ...}
],
right_links: [
%Task{id: 32, ...}
]
Is there a way I could set up my tasks
schema (or change my method of linking tasks) so a query would return a list of every task linked to a task under a single field?