EDA.Poll (EDA v0.3.0)

Copy Markdown View Source

Represents a Discord message poll.

Combines a data struct (received from the gateway), a pipe-friendly builder (for creating polls), and query helpers (for analyzing results).

Building a poll

import EDA.Poll

poll =
  new("What's your favorite color?", duration: 48, multiselect: true)
  |> add_answer("Red", emoji: "🔴")
  |> add_answer("Blue", emoji: "🔵")
  |> add_answer("Green", emoji: "🟢")

EDA.API.Message.create(channel_id, poll: poll)

Analyzing results

poll = message.poll

EDA.Poll.expired?(poll)
EDA.Poll.finalized?(poll)
EDA.Poll.total_votes(poll)
EDA.Poll.winning_answer(poll)

Summary

Functions

Adds an answer to the poll (max 10 answers).

Returns true if the poll has expired.

Returns true if the poll results are finalized (votes precisely counted).

Parses a poll from a raw Discord API map.

Returns the default layout type (1).

Returns the maximum answer text length (55).

Returns the maximum number of answers (10).

Returns the maximum poll duration in hours (768).

Returns the maximum question length (300).

Returns the minimum poll duration in hours (1).

Creates a new poll with the given question.

Serializes a poll to the Discord API format for message creation.

Returns the total number of votes across all answers.

Returns the answer with the most votes, or nil if there are no results.

Types

t()

@type t() :: %EDA.Poll{
  allow_multiselect: boolean(),
  answers: [EDA.Poll.Answer.t()],
  duration: integer() | nil,
  expiry: String.t() | nil,
  layout_type: integer() | nil,
  question: String.t(),
  results: {boolean(), [EDA.Poll.AnswerCount.t()]} | nil
}

Functions

add_answer(poll, text, opts \\ [])

@spec add_answer(t(), String.t(), keyword()) :: t()

Adds an answer to the poll (max 10 answers).

Options

  • :emoji - An EDA.Emoji struct or a unicode string (e.g. "🔴")

Examples

iex> poll = EDA.Poll.new("Test?") |> EDA.Poll.add_answer("Option A")
iex> length(poll.answers)
1

iex> poll = EDA.Poll.new("Test?") |> EDA.Poll.add_answer("Fire", emoji: "🔥")
iex> hd(poll.answers).emoji
%EDA.Emoji{name: "🔥"}

expired?(poll)

@spec expired?(t()) :: boolean()

Returns true if the poll has expired.

Compares the expiry timestamp against DateTime.utc_now/0. Returns false if expiry is nil.

Examples

iex> EDA.Poll.expired?(%EDA.Poll{expiry: "2020-01-01T00:00:00+00:00"})
true

iex> EDA.Poll.expired?(%EDA.Poll{expiry: nil})
false

finalized?(poll)

@spec finalized?(t()) :: boolean()

Returns true if the poll results are finalized (votes precisely counted).

Examples

iex> EDA.Poll.finalized?(%EDA.Poll{results: {true, []}})
true

iex> EDA.Poll.finalized?(%EDA.Poll{results: {false, []}})
false

iex> EDA.Poll.finalized?(%EDA.Poll{results: nil})
false

from_raw(raw)

@spec from_raw(map()) :: t()

Parses a poll from a raw Discord API map.

Examples

iex> raw = %{
...>   "question" => %{"text" => "Best language?"},
...>   "answers" => [%{"answer_id" => 1, "poll_media" => %{"text" => "Elixir"}}],
...>   "expiry" => "2025-01-01T00:00:00+00:00",
...>   "allow_multiselect" => false,
...>   "layout_type" => 1,
...>   "results" => %{
...>     "is_finalized" => true,
...>     "answer_counts" => [%{"id" => 1, "count" => 10, "me_voted" => false}]
...>   }
...> }
iex> poll = EDA.Poll.from_raw(raw)
iex> poll.question
"Best language?"
iex> poll.results
{true, [%EDA.Poll.AnswerCount{id: 1, count: 10, me_voted: false}]}

layout_default()

@spec layout_default() :: integer()

Returns the default layout type (1).

max_answer_length()

@spec max_answer_length() :: integer()

Returns the maximum answer text length (55).

max_answers()

@spec max_answers() :: integer()

Returns the maximum number of answers (10).

max_duration()

@spec max_duration() :: integer()

Returns the maximum poll duration in hours (768).

max_question_length()

@spec max_question_length() :: integer()

Returns the maximum question length (300).

min_duration()

@spec min_duration() :: integer()

Returns the minimum poll duration in hours (1).

new(question, opts \\ [])

@spec new(
  String.t(),
  keyword()
) :: t()

Creates a new poll with the given question.

Options

  • :duration - Duration in hours (1-768, default: 24)
  • :multiselect - Allow multiple votes (default: false)
  • :layout - Layout type (default: 1)

Examples

iex> poll = EDA.Poll.new("Favorite color?")
iex> poll.question
"Favorite color?"
iex> poll.duration
24

iex> poll = EDA.Poll.new("Pick many", duration: 48, multiselect: true)
iex> poll.duration
48
iex> poll.allow_multiselect
true

to_raw(poll)

@spec to_raw(t()) :: map()

Serializes a poll to the Discord API format for message creation.

Examples

iex> poll = %EDA.Poll{question: "Yes?", answers: [%EDA.Poll.Answer{text: "Yes"}], duration: 24, allow_multiselect: false, layout_type: 1}
iex> raw = EDA.Poll.to_raw(poll)
iex> raw["question"]
%{"text" => "Yes?"}

total_votes(poll)

@spec total_votes(t()) :: integer()

Returns the total number of votes across all answers.

Returns 0 if there are no results.

Examples

iex> counts = [%EDA.Poll.AnswerCount{id: 1, count: 5, me_voted: false}, %EDA.Poll.AnswerCount{id: 2, count: 3, me_voted: true}]
iex> EDA.Poll.total_votes(%EDA.Poll{results: {true, counts}})
8

iex> EDA.Poll.total_votes(%EDA.Poll{results: nil})
0

winning_answer(poll)

@spec winning_answer(t()) :: EDA.Poll.Answer.t() | nil

Returns the answer with the most votes, or nil if there are no results.

Matches answer counts back to answers by ID.

Examples

iex> answers = [%EDA.Poll.Answer{answer_id: 1, text: "A"}, %EDA.Poll.Answer{answer_id: 2, text: "B"}]
iex> counts = [%EDA.Poll.AnswerCount{id: 1, count: 3, me_voted: false}, %EDA.Poll.AnswerCount{id: 2, count: 7, me_voted: false}]
iex> EDA.Poll.winning_answer(%EDA.Poll{answers: answers, results: {true, counts}})
%EDA.Poll.Answer{answer_id: 2, text: "B"}

iex> EDA.Poll.winning_answer(%EDA.Poll{results: nil})
nil