aboutsummaryrefslogtreecommitdiff
path: root/lib/meme.ex
blob: caeccaf9f2e55dd2caa47597dfef2300829fb8ee (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
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