Packages
Event-driven notification system for Ash Framework with multiple transport types
Current section
Files
Jump to
Current section
Files
lib/content_map.ex
defmodule AshDispatch.ContentMap do
@moduledoc """
Helper module for accessing content maps with mixed atom/string keys.
Content maps may have atom keys when created in-memory, but string keys when
loaded from the database (PostgreSQL JSONB columns return string keys).
This module provides safe access that handles both cases.
## Why This Exists
When you store a map like `%{title: "Hello"}` in a JSONB column,
PostgreSQL returns it as `%{"title" => "Hello"}`. This module
eliminates the `content[:title] || content["title"]` pattern
scattered throughout transport code.
## Usage
import AshDispatch.ContentMap
# Get a value (checks atom key first, then string)
title = get_content(content, :title)
# Get with default
type = get_content(content, :notification_type, :info)
## Key Resolution Order
1. Atom key (e.g., `:title`)
2. String key (e.g., `"title"`)
3. Default value (if provided)
"""
@doc """
Gets a value from a content map, handling both atom and string keys.
Checks atom key first, then string key. Returns nil if not found.
## Examples
iex> get_content(%{title: "Hello"}, :title)
"Hello"
iex> get_content(%{"title" => "Hello"}, :title)
"Hello"
iex> get_content(%{}, :title)
nil
"""
@spec get_content(map(), atom()) :: any()
def get_content(content, key) when is_map(content) and is_atom(key) do
content[key] || content[Atom.to_string(key)]
end
def get_content(nil, _key), do: nil
def get_content(_content, _key), do: nil
@doc """
Gets a value from a content map with a default if not found.
## Examples
iex> get_content(%{}, :notification_type, :info)
:info
iex> get_content(%{notification_type: :success}, :notification_type, :info)
:success
"""
@spec get_content(map(), atom(), any()) :: any()
def get_content(content, key, default) when is_map(content) and is_atom(key) do
get_content(content, key) || default
end
def get_content(nil, _key, default), do: default
def get_content(_content, _key, default), do: default
end