Bonfire.API.MastoCompat.Helpers (Bonfire v1.0.1-social-alpha.28)

View Source

Shared helper functions for Mastodon API mappers.

This module provides common utilities used across mappers to safely extract and transform data from Bonfire structures to Mastodon format.

Summary

Functions

Recursively converts structs to JSON-safe values.

Formats a datetime to ISO8601 format as expected by Mastodon API.

Safely get a field from a map or struct, handling nil and NotLoaded associations.

Get the first non-nil value from a map by trying multiple keys in order.

Normalize a hashtag string for querying.

Converts a value to string, handling nil gracefully.

Validates an entity against a schema module and returns the valid entity or nil.

Functions

deep_struct_to_map(value, opts \\ [])

Recursively converts structs to JSON-safe values.

Handles DateTime, NaiveDateTime, Date, and Ecto NotLoaded associations. Can optionally filter out nil values and drop unknown struct types.

Options

  • :filter_nils - Remove nil values from maps and lists (default: false)
  • :drop_unknown_structs - Return nil for unrecognized structs instead of converting to map (default: false)

Examples

iex> deep_struct_to_map(%{date: ~U[2024-01-15 10:30:00Z]})
%{date: "2024-01-15T10:30:00Z"}

iex> deep_struct_to_map(%{value: nil}, filter_nils: true)
%{}

iex> deep_struct_to_map(%Ecto.Association.NotLoaded{})
nil

format_datetime(dt)

Formats a datetime to ISO8601 format as expected by Mastodon API.

Handles various datetime types (DateTime, NaiveDateTime, Date) and returns nil for invalid inputs.

Examples

iex> format_datetime(~U[2024-01-15 10:30:00Z])
"2024-01-15T10:30:00.000Z"

iex> format_datetime(nil)
nil

get_field(map, key)

Safely get a field from a map or struct, handling nil and NotLoaded associations.

Returns nil for:

  • nil input
  • Empty maps
  • NotLoaded Ecto associations
  • Non-map inputs
  • Missing keys

Examples

iex> get_field(%{name: "test"}, :name)
"test"

iex> get_field(nil, :name)
nil

iex> get_field(%{}, :name)
nil

iex> get_field(%{assoc: %Ecto.Association.NotLoaded{}}, :assoc)
nil

get_fields(map, keys)

Get the first non-nil value from a map by trying multiple keys in order.

Useful when data can come from either GraphQL (with aliased field names) or directly from Ecto (with raw schema field names).

Examples

iex> get_fields(%{display_name: "Alice"}, [:display_name, :name])
"Alice"

iex> get_fields(%{name: "Bob"}, [:display_name, :name])
"Bob"

iex> get_fields(%{other: "value"}, [:display_name, :name])
nil

iex> get_fields(%{"avatar" => "url"}, [:avatar, "avatar", :icon, "icon"])
"url"

normalize_hashtag(hashtag)

Normalize a hashtag string for querying.

Removes # prefix if present and handles case normalization. Uses Bonfire's hashtag normalization if available, otherwise falls back to simple lowercase.

Examples

iex> normalize_hashtag("#Bonfire")
"bonfire"

iex> normalize_hashtag("ELIXIR")
"elixir"

iex> normalize_hashtag(nil)
""

to_string_safe(value)

Converts a value to string, handling nil gracefully.

Examples

iex> to_string_safe(123)
"123"

iex> to_string_safe(nil)
nil

iex> to_string_safe("already_string")
"already_string"

validate_and_return(entity, schema_module)

Validates an entity against a schema module and returns the valid entity or nil.

Logs warnings for validation failures to aid debugging without crashing.

Parameters

  • entity - The map to validate
  • schema_module - The schema module with a validate/1 function

Examples

iex> validate_and_return(%{"id" => "123"}, Schemas.Status)
%{"id" => "123", ...}

iex> validate_and_return(%{}, Schemas.Status)
nil  # Logs warning about missing required fields