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_bitstring(name) do
from(m in Meme, where: m.title == ^name)
end
end
|