<commit_before>defmodule Animu.Media do
  @moduledoc """
  The boundary for the Media system
  """
  import Ecto.{Query, Changeset}, warn: false

  import Animu.Media.Query
  import Animu.Schema

  alias Animu.Repo
  alias Animu.Media.{Franchise, Series, Episode}

  ##
  # Franchise Interactions
  ##

  @doc """
  Returns `%Ecto.Changeset{}` for tracking Franchise changes
  """
  def franchise_changeset(%Franchise{} = franchise, attrs) do
    franchise
    |> cast(attrs, all_fields(Franchise))
    |> validate_required([:canon_title, :slug])
  end

  def change_franchise(%Franchise{} = franchise) do
    franchise_changeset(franchise, %{})
  end

  @doc """
  Returns a list of Franchises
  """
  def list_franchises(params) do
    Franchise
      |> build_query(params)
      |> Repo.all()
  end

  @doc """
  Returns single Franchise using it's id or slug

  Raises `Ecto.NoResultsError` if the Franchise does not exist.
  """
  def get_franchise!(id) when is_integer(id) do
    Repo.get!(Franchise, id)
      |> Repo.preload(:series)
  end
  def get_franchise!(slug) when is_binary(slug) do
    Repo.get_by!(Franchise, slug: slug)
      |> Repo.preload(:series)
  end

  @doc """
  Creates new Franchise
  """
  def create_franchise(attrs \\ %{}) do
    %Franchise{}
    |> franchise_changeset(attrs)
    |> Repo.insert()
  end

  @doc """
  Updates a Franchise
  """
  def update_franchise(%Franchise{} = franchise, attrs) do
    franchise
    |> franchise_changeset(attrs)
    |> Repo.update()
  end

  @doc """
  Deletes a Franchise
  """
  def delete_franchise(%Franchise{} = franchise) do
    Repo.delete(franchise)
  end

  ##
  # Series Interactions
  ##

  @doc """
  Returns `%Ecto.Changeset{}` for tracking Series changes
  """
  def series_changeset(%Series{} = series, attrs) do
    virtual_fields =
      [ :populate,
        :audit,
        :spawn_episodes,
      ]

    series
    |> Repo.preload(:episodes)
    |> Repo.preload(:franchise)
    |> cast(attrs, all_fields(Series) ++ virtual_fields)
    |> Series.Invoke.populate
    |> Series.Invoke.audit
    |> Series.Invoke.spawn_episodes
    |> unique_constraint(:slug)
    |> validate_required([:canon_title, :slug, :directory])
  end

  def change_series(%Series{} = series) do
    series_changeset(series, %{})
  end

  @doc """
  Returns all watched Series with Episodes that have nil Videos
  """
  def all_watched_series do
    episode_query =
      from e in Episode,
       where: is_nil(e.video),
      select: {e.id, e.number}
    series_query =
      from s in Series,
      preload: [episodes: ^episode_query],
        where: s.watch == true,
       select: struct(s, [:id, :rss_feed, :regex, :directory])

    Repo.all(series_query)
  end<commit_msg>Fixed Series slug constraint issue<commit_after>defmodule Animu.Media do
  @moduledoc """
  The boundary for the Media system
  """
  import Ecto.{Query, Changeset}, warn: false

  import Animu.Media.Query
  import Animu.Schema

  alias Animu.Repo
  alias Animu.Media.{Franchise, Series, Episode}

  ##
  # Franchise Interactions
  ##

  @doc """
  Returns `%Ecto.Changeset{}` for tracking Franchise changes
  """
  def franchise_changeset(%Franchise{} = franchise, attrs) do
    franchise
    |> cast(attrs, all_fields(Franchise))
    |> validate_required([:canon_title, :slug])
  end

  def change_franchise(%Franchise{} = franchise) do
    franchise_changeset(franchise, %{})
  end

  @doc """
  Returns a list of Franchises
  """
  def list_franchises(params) do
    Franchise
      |> build_query(params)
      |> Repo.all()
  end

  @doc """
  Returns single Franchise using it's id or slug

  Raises `Ecto.NoResultsError` if the Franchise does not exist.
  """
  def get_franchise!(id) when is_integer(id) do
    Repo.get!(Franchise, id)
      |> Repo.preload(:series)
  end
  def get_franchise!(slug) when is_binary(slug) do
    Repo.get_by!(Franchise, slug: slug)
      |> Repo.preload(:series)
  end

  @doc """
  Creates new Franchise
  """
  def create_franchise(attrs \\ %{}) do
    %Franchise{}
    |> franchise_changeset(attrs)
    |> Repo.insert()
  end

  @doc """
  Updates a Franchise
  """
  def update_franchise(%Franchise{} = franchise, attrs) do
    franchise
    |> franchise_changeset(attrs)
    |> Repo.update()
  end

  @doc """
  Deletes a Franchise
  """
  def delete_franchise(%Franchise{} = franchise) do
    Repo.delete(franchise)
  end

  ##
  # Series Interactions
  ##

  @doc """
  Returns `%Ecto.Changeset{}` for tracking Series changes
  """
  def series_changeset(%Series{} = series, attrs) do
    virtual_fields =
      [ :populate,
        :audit,
        :spawn_episodes,
      ]

    series
    |> Repo.preload(:episodes)
    |> Repo.preload(:franchise)
    |> cast(attrs, all_fields(Series) ++ virtual_fields)
    |> Series.Invoke.populate
    |> Series.Invoke.audit
    |> Series.Invoke.spawn_episodes
    |> validate_required([:canon_title, :slug, :directory])
    |> unique_constraint(:slug)
  end

  def change_series(%Series{} = series) do
    series_changeset(series, %{})
  end

  @doc """
  Returns all watched Series with Episodes that have nil Videos
  """
  def all_watched_series do
    episode_query =
      from e in Episode,
       where: is_nil(e.video),
      select: {e.id, e.number}
    series_query =
      from s in Series,
      preload: [episodes: ^episode_query],
        where: s.watch == true,
       select: struct(s, [:id, :rss_feed, :regex, :directory])

    Repo.all(series_query)
  end
{'fraction_non_alphanumeric': 0.12802327695944718, 'fraction_numerical': 0.0, 'mean_word_length': 3.1698256254738437, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 39, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 6, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1325544', 'n_tokens_mistral': 1976, 'n_tokens_neox': 1930, 'n_words': 433}