Current section
Files
Jump to
Current section
Files
lib/nostrum/cache/guild_cache.ex
defmodule Nostrum.Cache.GuildCache do
@moduledoc """
Functions for retrieving guild states.
"""
alias Nostrum.Cache.Guild.GuildServer
alias Nostrum.Cache.Mapping.ChannelGuild
alias Nostrum.Struct.Channel
alias Nostrum.Struct.Guild
alias Nostrum.Struct.Message
alias Nostrum.Util
import Nostrum.Snowflake, only: [is_snowflake: 1]
@type clause ::
{:id, Guild.id()}
| {:channel_id, Channel.id()}
| {:message, Message.t()}
@type clauses :: [clause] | map
@type selector :: (Guild.t() -> any)
@type reason ::
:id_not_found
| :id_not_found_on_guild_lookup
defguardp is_selector(term) when is_function(term, 1)
@doc """
Retrives all `Nostrum.Struct.Guild` from the cache as a stream.
"""
@spec all() :: Enum.t()
def all, do: select_all(fn guild -> guild end)
@doc """
Selects values using a `selector` from all `Nostrum.Struct.Guild` in the cache.
"""
@spec select_all(selector) :: Enum.t()
def select_all(selector)
def select_all(selector) when is_selector(selector) do
Supervisor.which_children(GuildSupervisor)
|> Stream.map(fn {_, pid, _, _} -> pid end)
|> Task.async_stream(fn pid -> GenServer.call(pid, {:select, selector}) end)
|> Stream.map(fn {:ok, value} -> value end)
end
@doc """
Retrives a single `Nostrum.Struct.Guild` from the cache via its `id`.
Returns `{:error, reason}` if no result was found.
## Examples
```Elixir
iex> Nostrum.Cache.GuildCache.get(0)
{:ok, %Nostrum.Struct.Guild{id: 0}}
iex> Nostrum.Cache.GuildCache.get(10)
{:error, :id_not_found_on_guild_lookup}
```
"""
@spec get(Guild.id()) :: {:ok, Guild.t()} | {:error, reason}
def get(id) do
select(id, fn guild -> guild end)
end
@doc ~S"""
Same as `get/1`, but raises `Nostrum.Error.CacheError` in case of failure.
"""
@spec get!(Guild.id()) :: Guild.t() | no_return
def get!(id), do: get(id) |> Util.bangify_find(id, __MODULE__)
@doc """
Retrives a single `Nostrum.Struct.Guild` where it matches the `clauses`.
Returns `{:error, reason}` if no result was found.
```Elixir
iex> Nostrum.Cache.GuildCache.get_by(id: 0)
{:ok, %Nostrum.Struct.Guild{id: 0}}
iex> Nostrum.Cache.GuildCache.get_by(%{id: 0})
{:ok, %Nostrum.Struct.Guild{id: 0}}
iex> Nostrum.Cache.GuildCache.get_by(id: 10)
{:error, :id_not_found_on_guild_lookup}
```
"""
@spec get_by(clauses) :: {:ok, Guild.t()} | {:error, reason}
def get_by(clauses) do
select_by(clauses, fn guild -> guild end)
end
@doc ~S"""
Same as `get_by/1`, but raises `Nostrum.Error.CacheError` in case of failure.
"""
@spec get_by!(clauses) :: Guild.t() | no_return
def get_by!(clauses), do: get_by(clauses) |> Util.bangify_find(clauses, __MODULE__)
@doc """
Selects values using a `selector` from a `Nostrum.Struct.Guild`.
Returns `{:error, reason}` if no result was found.
## Examples
```Elixir
iex> Nostrum.Cache.GuildCache.select(0, fn guild -> guild.id end)
{:ok, 0}
iex> Nostrum.Cache.GuildCache.select(10, fn guild -> guild.id end)
{:error, :id_not_found_on_guild_lookup}
```
"""
@spec select(Guild.id(), selector) :: {:ok, any} | {:error, reason}
def select(id, selector) do
select_by(%{id: id}, selector)
end
@doc ~S"""
Same as `select/2`, but raises `Nostrum.Error.CacheError` in case of failure.
"""
@spec select!(Guild.id(), selector) :: any | no_return
def select!(id, selector), do: select(id, selector) |> Util.bangify_find(id, __MODULE__)
@doc """
Selects values using a `selector` from a `Nostrum.Struct.Guild` that matches
the `clauses`.
Returns `{:error, reason}` if no result was found.
```Elixir
iex> Nostrum.Cache.GuildCache.select_by([id: 0], fn guild -> guild.id end)
{:ok, 0}
iex> Nostrum.Cache.GuildCache.select_by(%{id: 0}, fn guild -> guild.id end)
{:ok, 0}
iex> Nostrum.Cache.GuildCache.select_by([id: 10], fn guild -> guild.id end)
{:error, :id_not_found_on_guild_lookup}
```
"""
@spec select_by(clauses, selector) :: {:ok, any} | {:error, reason}
def select_by(clauses, selector)
def select_by(clauses, selector) when is_list(clauses) and is_selector(selector),
do: select_by(Map.new(clauses), selector)
def select_by(%{id: id}, selector) when is_snowflake(id) and is_selector(selector) do
case GuildServer.select(id, selector) do
{:error, _} = error -> error
guild -> {:ok, guild}
end
end
def select_by(%{channel_id: channel_id}, selector)
when is_snowflake(channel_id) and is_selector(selector) do
case ChannelGuild.get_guild(channel_id) do
{:ok, guild_id} -> select_by(%{id: guild_id}, selector)
{:error, _} = error -> error
end
end
def select_by(%{message: %Message{channel_id: channel_id}}, selector) do
select_by(%{channel_id: channel_id}, selector)
end
@doc ~S"""
Same as `select_by/2`, but raises `Nostrum.Error.CacheError` in case of failure.
"""
@spec select_by!(clauses, selector) :: any | no_return
def select_by!(clauses, selector),
do: select_by(clauses, selector) |> Util.bangify_find(clauses, __MODULE__)
end