defmodule Memex.Notes do @moduledoc """ The Notes context. """ import Ecto.Query, warn: false alias Ecto.Changeset alias Memex.{Accounts.User, Notes.Note, Repo} @doc """ Returns the list of notes. ## Examples iex> list_notes(%User{id: 123}) [%Note{}, ...] """ @spec list_notes(User.t() | nil) :: [Note.t()] def list_notes(%{id: user_id}) do Repo.all(from n in Note, where: n.user_id == ^user_id, order_by: n.title) end @doc """ Returns the list of public notes for viewing ## Examples iex> list_public_notes() [%Note{}, ...] """ @spec list_public_notes() :: [Note.t()] def list_public_notes do Repo.all(from n in Note, where: n.visibility == :public, order_by: n.title) end @doc """ Gets a single note. Raises `Ecto.NoResultsError` if the Note does not exist. ## Examples iex> get_note!(123, %User{id: 123}) %Note{} iex> get_note!(456, %User{id: 123}) ** (Ecto.NoResultsError) """ @spec get_note!(Note.id(), User.t()) :: Note.t() def get_note!(id, %{id: user_id}) do Repo.one!( from n in Note, where: n.id == ^id, where: n.user_id == ^user_id or n.visibility in [:public, :unlisted] ) end def get_note!(id, _invalid_user) do Repo.one!( from n in Note, where: n.id == ^id, where: n.visibility in [:public, :unlisted] ) end @doc """ Creates a note. ## Examples iex> create_note(%{field: value}, %User{id: 123}) {:ok, %Note{}} iex> create_note(%{field: bad_value}, %User{id: 123}) {:error, %Ecto.Changeset{}} """ @spec create_note(User.t()) :: {:ok, Note.t()} | {:error, Changeset.t()} @spec create_note(attrs :: map(), User.t()) :: {:ok, Note.t()} | {:error, Changeset.t()} def create_note(attrs \\ %{}, user) do Note.create_changeset(attrs, user) |> Repo.insert() end @doc """ Updates a note. ## Examples iex> update_note(note, %{field: new_value}, %User{id: 123}) {:ok, %Note{}} iex> update_note(note, %{field: bad_value}, %User{id: 123}) {:error, %Ecto.Changeset{}} """ @spec update_note(Note.t(), attrs :: map(), User.t()) :: {:ok, Note.t()} | {:error, Changeset.t()} def update_note(%Note{} = note, attrs, user) do note |> Note.update_changeset(attrs, user) |> Repo.update() end @doc """ Deletes a note. ## Examples iex> delete_note(note, %User{id: 123}) {:ok, %Note{}} iex> delete_note(note, %User{id: 123}) {:error, %Ecto.Changeset{}} """ @spec delete_note(Note.t(), User.t()) :: {:ok, Note.t()} | {:error, Changeset.t()} def delete_note(%Note{user_id: user_id} = note, %{id: user_id}) do note |> Repo.delete() end @doc """ Returns an `%Ecto.Changeset{}` for tracking note changes. ## Examples iex> change_note(note, %User{id: 123}) %Ecto.Changeset{data: %Note{}} iex> change_note(note, %{title: "new title"}, %User{id: 123}) %Ecto.Changeset{data: %Note{}} """ @spec change_note(Note.t(), User.t()) :: Changeset.t(Note.t()) @spec change_note(Note.t(), attrs :: map(), User.t()) :: Changeset.t(Note.t()) def change_note(%Note{} = note, attrs \\ %{}, user) do note |> Note.update_changeset(attrs, user) end @doc """ Gets a canonical string representation of the `:tags` field for a Note """ @spec get_tags_string(Note.t() | Changeset.t() | [String.t()] | nil) :: String.t() def get_tags_string(nil), do: "" def get_tags_string(tags) when tags |> is_list(), do: tags |> Enum.join(",") def get_tags_string(%Note{tags: tags}), do: tags |> get_tags_string() def get_tags_string(%Changeset{} = changeset) do changeset |> Changeset.get_field(:tags) |> get_tags_string() end end