Powered by AppSignal & Oban Pro
Would you like to see your link here? Contact us

Structs

08-structs.livemd

Structs

Structs are just enhanced Maps

Remember maps? the “go to” data structure

Struct just allows you to define keys at compile time, it also allows to do certain validations making they are really powerful in lot of applications

we can define a struct with defstruct macro

defmodule GitHub.Repository do
  @moduledoc """
  Represents a GitHub repository with common attributes and operations.
  """

  @enforce_keys [:name, :owner] # this is a module attribute
  defstruct [
    :name,
    :owner,
    :description,
    :url,
    :private,
    stars: 0,
    forks: 0,
    open_issues: 0,
    created_at: nil,
    updated_at: nil,
    topics: []
  ]

  # this is typespec, a way to define types(not like typescript)
  @type t :: %__MODULE__{
          name: String.t(),
          owner: String.t(),
          description: String.t() | nil,
          url: String.t() | nil,
          private: boolean() | nil,
          stars: non_neg_integer(),
          forks: non_neg_integer(),
          open_issues: non_neg_integer(),
          created_at: DateTime.t() | nil,
          updated_at: DateTime.t() | nil,
          topics: list(String.t())
        }

  @doc """
  Creates a new repository struct with the given attributes.
  """
  def new(name, owner, description \\ nil) do
    %__MODULE__{
      name: name,
      owner: owner,
      description: description,
      private: false,
      url: "https://github.com/#{owner}/#{name}"
    }
  end

  @doc """
  Adds topics to a repository.
  """
  def add_topics(repo, new_topics) when is_list(new_topics) do
    %{repo | topics: Enum.uniq(repo.topics ++ new_topics)}
  end

  @doc """
  Updates the star count and returns the updated repository.
  """
  def update_stars(repo, count) when is_integer(count) and count >= 0 do
    %{repo | stars: count, updated_at: DateTime.utc_now()}
  end

  @doc """
  Returns true if the repository is popular (has more than 1000 stars).
  """
  def popular?(repo) do
    repo.stars >= 1000
  end
end

Usage is like here

repo =
  GitHub.Repository.new(
    "phoenix",
    "phoenixframework",
    "Peace of mind from prototype to production"
  )
  |> GitHub.Repository.add_topics(["elixir", "web", "framework"])
  |> GitHub.Repository.update_stars(19000)
is_popular = GitHub.Repository.popular?(repo)

If we try to skip enforced keys

%GitHub.Repository{name: "my-repo"}

we get an error