171 lines
4.6 KiB
Elixir
171 lines
4.6 KiB
Elixir
defmodule BallsPDS.Ecto.Schema.CollectionObject do
|
|
use Ecto.Schema
|
|
import Ecto.Query
|
|
import Ecto.Changeset
|
|
alias BallsPDS.Repo
|
|
alias BallsPDS.Ecto.Schema.Object
|
|
|
|
schema "collection_objects" do
|
|
belongs_to(:collection, BallsPDS.Ecto.Schema.Object, foreign_key: :collection_id)
|
|
belongs_to(:object, BallsPDS.Ecto.Schema.Object, foreign_key: :object_id)
|
|
field(:remote_id, :string)
|
|
field(:order_num, :integer)
|
|
|
|
timestamps()
|
|
end
|
|
|
|
def changeset(struct, params \\ %{}) do
|
|
struct
|
|
|> cast(params, [
|
|
:collection_id,
|
|
:remote_id,
|
|
:object_id
|
|
])
|
|
|> validate_required([:collection_id])
|
|
|> foreign_key_constraint(:collection_id)
|
|
|> foreign_key_constraint(:object_id)
|
|
end
|
|
|
|
def delete(%Object{id: collection_id}, object_id) when is_integer(object_id) do
|
|
from(co in __MODULE__,
|
|
where: co.collection_id == ^collection_id,
|
|
where: co.object_id == ^object_id
|
|
)
|
|
|> Repo.delete_all()
|
|
end
|
|
|
|
# FIXME: handle if local id passed
|
|
def delete(%Object{id: collection_id}, remote_id) when is_binary(remote_id) do
|
|
from(co in __MODULE__,
|
|
where: co.collection_id == ^collection_id,
|
|
where: co.remote_id == ^remote_id
|
|
)
|
|
|> Repo.delete_all()
|
|
end
|
|
|
|
def delete_all(%Object{id: collection_id}) do
|
|
from(co in __MODULE__,
|
|
where: co.collection_id == ^collection_id
|
|
)
|
|
|> Repo.delete_all()
|
|
end
|
|
|
|
def delete_all(%Object{id: collection_id}, ids) when is_list(ids) do
|
|
{object_ids, remote_ids} =
|
|
ids
|
|
|> Enum.map(&resolve_id/1)
|
|
|> Enum.reduce({[], []}, fn
|
|
nil, acc ->
|
|
acc
|
|
|
|
object_id, {object_ids, remote_ids} when is_integer(object_id) ->
|
|
{[object_id | object_ids], remote_ids}
|
|
|
|
remote_id, {object_ids, remote_ids} when is_binary(remote_id) ->
|
|
{object_ids, [remote_id | remote_ids]}
|
|
end)
|
|
|
|
from(co in __MODULE__,
|
|
where:
|
|
co.collection_id == ^collection_id and
|
|
(co.object_id in ^object_ids or co.remote_id in ^remote_ids)
|
|
)
|
|
|> Repo.delete_all()
|
|
end
|
|
|
|
def get_ids(%Object{id: object_id}) do
|
|
from(co in __MODULE__,
|
|
left_join: o in Object,
|
|
on: o.id == co.object_id,
|
|
where: co.collection_id == ^object_id,
|
|
order_by: co.order_num,
|
|
select: {o.id, o.path, co.remote_id}
|
|
)
|
|
|> Repo.query()
|
|
end
|
|
|
|
def get_highest_order_num(%Object{id: object_id}) do
|
|
from(co in __MODULE__,
|
|
where: co.collection_id == ^object_id,
|
|
select: max(co.order_num)
|
|
)
|
|
|> Repo.one()
|
|
|> case do
|
|
nil -> 0
|
|
order_num -> order_num
|
|
end
|
|
end
|
|
|
|
def insert(%Object{id: collection_id} = collection_object, object_id, order_num)
|
|
when is_integer(object_id) do
|
|
next_order_num =
|
|
if order_num == nil do
|
|
current_highest_order_num = get_highest_order_num(collection_object)
|
|
current_highest_order_num + 100
|
|
else
|
|
order_num
|
|
end
|
|
|
|
cs =
|
|
changeset(%__MODULE__{}, %{
|
|
collection_id: collection_id,
|
|
object_id: object_id,
|
|
order_num: next_order_num
|
|
})
|
|
|
|
Repo.insert(cs)
|
|
end
|
|
|
|
def insert(%Object{id: collection_id} = collection_object, remote_id, order_num)
|
|
when is_binary(remote_id) do
|
|
next_order_num =
|
|
if order_num == nil do
|
|
current_highest_order_num = get_highest_order_num(collection_object)
|
|
current_highest_order_num + 100
|
|
else
|
|
order_num
|
|
end
|
|
|
|
cs =
|
|
changeset(%__MODULE__{}, %{
|
|
collection_id: collection_id,
|
|
remote_id: remote_id,
|
|
order_num: next_order_num
|
|
})
|
|
|
|
Repo.insert(cs)
|
|
end
|
|
|
|
def insert_all(%Object{} = collection_object, ids) when is_list(ids) do
|
|
ids = ids |> Enum.map(&resolve_id/1) |> Enum.filter(fn val -> val == nil end)
|
|
|
|
current_highest_order_num = get_highest_order_num(collection_object)
|
|
next_order_num = current_highest_order_num + 100
|
|
|
|
Enum.reduce(ids, next_order_num, fn id, next_order_num ->
|
|
insert(collection_object, id, next_order_num)
|
|
next_order_num + 100
|
|
end)
|
|
end
|
|
|
|
defp resolve_id(ap_id) when is_binary(ap_id) do
|
|
owner_id = Application.get_env(:balls_pds, :owner_ap_id)
|
|
|
|
case ap_id do
|
|
^owner_id <> suffix ->
|
|
with {:uri, %URI{:query => query}} <- {:uri, URI.parse(suffix)},
|
|
{:rel, %{"relativeRef" => relative_ref, "service" => service}} <-
|
|
{:rel, URI.decode_query(query)},
|
|
{:service, true} <-
|
|
{:service, Application.get_env(:balls_pds, :did_service) == service} do
|
|
Object.get_by_path(relative_ref)
|
|
else
|
|
_ -> nil
|
|
end
|
|
|
|
remote_id ->
|
|
remote_id
|
|
end
|
|
end
|
|
end
|