aboutsummaryrefslogtreecommitdiff
path: root/lib/meme.ex
diff options
context:
space:
mode:
Diffstat (limited to 'lib/meme.ex')
-rw-r--r--lib/meme.ex42
1 files changed, 42 insertions, 0 deletions
diff --git a/lib/meme.ex b/lib/meme.ex
new file mode 100644
index 0000000..36048f8
--- /dev/null
+++ b/lib/meme.ex
@@ -0,0 +1,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