import Ecto.Query alias Thulani.Schema.Meme defmodule Thulani.Meme do @type kind :: :audio | :text | :image def any, do: [:audio, :text, :image] |> MapSet.new() def silent, do: [:text, :image] |> MapSet.new() @spec random(MapSet.t(kind) | kind) :: {:ok, Meme} | {:err, term()} def random(allowed_kinds \\ any()) def random(allowed_kinds) when is_struct(allowed_kinds) do from(m in Meme, where: ^random_predicates(allowed_kinds), order_by: fragment("random()"), limit: 1 ) end def random(kind) when is_atom(kind) do [kind] |> MapSet.new() |> random end defp random_predicates(allowed_kinds) do not_permitted = any() |> MapSet.difference(allowed_kinds) not_permitted |> Enum.map(fn x -> require_nil(x) end) |> Enum.reduce(true, fn acc, x -> dynamic([], ^acc and ^x) end) end defp require_nil(:audio), do: dynamic([m], is_nil(m.audio_id)) defp require_nil(:image), do: dynamic([m], is_nil(m.image_id)) defp require_nil(:text), do: dynamic([m], is_nil(m.content)) @spec by_name(String.t()) :: Meme def by_name(name) when is_binary(name) do from(m in Meme, where: m.title == ^name) end end