defmodule Carve do @moduledoc """ Carve simplifies JSON API development in Phoenix by automatically formatting endpoint outputs with associated links. Define resource relationships with a simple DSL, and let Carve handle link inclusion and query-based filtering, reducing boilerplate and ensuring consistent, flexible API responses. It provides functionality for: - Rendering JSON endpoints with links automatically - Creating index/show methods for views from a DSL - Retrieving links between different data types - Encoding and decoding IDs using HashIds - Configuring the application """ use Application require Logger @doc """ Starts the Carve application. This function is called automatically by the OTP application behaviour. It configures Carve using the configuration returned by `Carve.Config.get/0`. ## Returns - `{:ok, pid}`: The pid is the process identifier of the started application. """ def start(_type, _args) do Logger.info("Starting Carve") configure(Carve.Config.get()) {:ok, self()} end @doc """ Configures Carve with the given arguments. This function is typically called during application start, but can also be used to reconfigure Carve at runtime. ## Parameters - `args`: A keyword list of configuration options. ## Examples iex> Carve.configure(salt: "my_salt", min_length: 8) :ok """ def configure(args) do Logger.info("Configuring Carve") hash_ids_config = args Carve.HashIds.configure(hash_ids_config) end @doc """ Retrieves links for a given module and data or ID(s). This function supports various input types: - Single integer ID - List of integer IDs - Single map (data structure) - List of maps (data structures) ## Parameters - `module`: The module to retrieve links for. - `data_or_ids`: The data or ID(s) to retrieve links for. ## Returns A list of link maps, each containing `:type`, `:id`, and `:data` keys. ## Examples iex> Carve.links(PostJSON, 1) [%{type: :user, id: "abc123", data: %{...}}, %{type: :comment, id: "def456", data: %{...}}] iex> Carve.links(PostJSON, [1, 2, 3]) [%{type: :user, id: "abc123", data: %{...}}, %{type: :comment, id: "def456", data: %{...}}, ...] iex> Carve.links(PostJSON, %{id: 1, title: "Test Post"}) [%{type: :user, id: "abc123", data: %{...}}, %{type: :comment, id: "def456", data: %{...}}] """ def links(module, data_or_ids) do cond do is_integer(data_or_ids) -> Carve.Links.get_links_by_id(module, data_or_ids) is_list(data_or_ids) and Enum.all?(data_or_ids, &is_integer/1) -> Carve.Links.get_links_by_id(module, data_or_ids) is_map(data_or_ids) -> Carve.Links.get_links_by_data(module, data_or_ids) is_list(data_or_ids) and Enum.all?(data_or_ids, &is_map/1) -> Carve.Links.get_links_by_data(module, data_or_ids) true -> [] end end @doc """ Encodes an ID for a given type using HashIds. ## Parameters - `type`: The type of the ID (as an atom). - `id`: The integer ID to encode. ## Returns A string representing the encoded ID. ## Examples iex> Carve.encode(:user, 123) "abc123def" """ def encode(type, id) when is_atom(type) and is_integer(id) do Carve.HashIds.encode(type, id) end @doc """ Decodes a hash with a given type using HashIds. ## Parameters - `type`: The type of the ID (as an atom). - `hash`: The string hash to decode. ## Returns The decoded integer ID. ## Examples iex> Carve.decode(:user, "abc123def") {:ok, 123} """ def decode(type, hash) when is_atom(type) and is_binary(hash) do Carve.HashIds.decode(type, hash) end @doc """ Decodes a hash without a type using HashIds. This function attempts to decode the hash without knowing its type. ## Parameters - `hash`: The string hash to decode. ## Returns The decoded integer ID. ## Examples iex> Carve.decode("abc123def") {:ok, 123} """ def decode(hash) when is_binary(hash) do Carve.HashIds.decode(hash) end end