lib/pardall_markdown/content/link.ex

defmodule PardallMarkdown.Content.Link do
  @moduledoc """
  This model has many usages in PardallMarkdown:
  - Taxonomies/categories are saved as `Link`. A taxonomy `Link` also has all of its `Post` posts embedded into `:children` (notice that the post content is set to `nil` when the post in emdebbed into a `Link`).
  - Post links for navigation and hierarchisation. A `Post` own `Link` also contains links to the `:previous` and `:next` posts of the content tree.

  Special notes:
  - `:sort_by` and `:sort_order`: the sorting rule to sort a taxonomy's posts. Used only by links of the `type: :taxonomy`.
  - `:index_post`: the parsed `_index.md` file as a `Post`. Can be used when showing the archive page of a taxonomy (alongside the taxonomy `Link.children` posts). Used only by links of the `type: :taxonomy`.
  """

  use Ecto.Schema
  import Ecto.Changeset

  @primary_key {:slug, :binary, autogenerate: false}
  @foreign_key_type :slug
  embedded_schema do
    field :title, :string
    field :type, Ecto.Enum, values: [:post, :taxonomy], default: :taxonomy
    field :custom_type, :string, default: nil
    field :level, :integer, default: 1
    field :parents, {:array, :string}, default: ["/"]
    field :position, :integer, default: 0
    embeds_one :previous, __MODULE__
    embeds_one :next, __MODULE__
    embeds_many :children, PardallMarkdown.Content.Post

    #

    # Taxonomy specific fields

    #

    # how to sort children posts

    field :sort_by, Ecto.Enum, values: [:title, :date, :slug, :position], default: :date
    field :sort_order, Ecto.Enum, values: [:asc, :desc], default: :desc
    # the taxonomy own post/custom page

    embeds_one :index_post, PardallMarkdown.Content.Post
  end

  def changeset(model, params) do
    model
    |> cast(params, [
      :title,
      :slug,
      :type,
      :level,
      :parents,
      :custom_type,
      :position,
      :sort_by,
      :sort_order
    ])
    |> validate_required([
      :title,
      :slug,
      :type,
      :level,
      :parents,
      :position,
      :sort_by,
      :sort_order
    ])
    |> cast_embed(:children)
    |> cast_embed(:previous)
    |> cast_embed(:next)
    |> cast_embed(:index_post)
  end
end