Current section
Files
Jump to
Current section
Files
doc/readme.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="x-ua-compatible" content="ie=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="generator" content="ExDoc v0.40.1">
<meta name="project" content="ash_gleam v0.4.0">
<title>README — ash_gleam v0.4.0</title>
<link rel="stylesheet" href="dist/html-elixir-YJO4MOOW.css" />
<script defer src="dist/sidebar_items-37036786.js"></script>
<script defer src="docs_config.js"></script>
<script defer src="dist/html-YU4BZFVS.js"></script>
</head>
<body>
<script>(()=>{var t="ex_doc:settings",e="dark";var o="dark",s="light";var E="sidebar_state",n="closed";var r="sidebar_width";var a="sidebar-open";var i=new URLSearchParams(window.location.search),S=i.get("theme")||JSON.parse(localStorage.getItem(t)||"{}").theme;(S===o||S!==s&&window.matchMedia("(prefers-color-scheme: dark)").matches)&&document.body.classList.add(e);var d=sessionStorage.getItem(E),A=d!==n&&!window.matchMedia(`screen and (max-width: ${768}px)`).matches;document.body.classList.toggle(a,A);var c=sessionStorage.getItem(r);c&&document.body.style.setProperty("--sidebarWidth",`${c}px`);var p=/(Macintosh|iPhone|iPad|iPod)/.test(window.navigator.userAgent);document.documentElement.classList.toggle("apple-os",p);})();
</script>
<div class="body-wrapper">
<button id="sidebar-menu" class="sidebar-button sidebar-toggle" aria-label="toggle sidebar" aria-controls="sidebar">
<i class="ri-menu-line ri-lg" title="Collapse/expand sidebar"></i>
</button>
<nav id="sidebar" class="sidebar">
<div class="sidebar-header">
<div class="sidebar-projectInfo">
<div>
<a href="api-reference.html" class="sidebar-projectName" translate="no">
ash_gleam
</a>
<div class="sidebar-projectVersion" translate="no">
v0.4.0
</div>
</div>
</div>
<ul id="sidebar-list-nav" class="sidebar-list-nav" role="tablist" data-extras="Pages"></ul>
</div>
</nav>
<output role="status" id="toast"></output>
<main class="content page-extra" id="main" data-type="extras">
<div id="content" class="content-inner">
<div class="top-search">
<div class="search-settings">
<form class="search-bar" action="search.html">
<label class="search-label">
<span class="sr-only">Search documentation of ash_gleam</span>
<div class="search-input-wrapper">
<input name="q" type="text" class="search-input" placeholder="Press / to search" autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false" />
<button type="button" tabindex="-1" class="search-close-button" aria-hidden="true">
<i class="ri-close-line ri-lg" title="Cancel search"></i>
</button>
</div>
</label>
</form>
<div class="autocomplete">
</div>
<div class="engine-selector" data-multiple="false">
<button type="button" class="engine-button" aria-label="Select search engine" aria-haspopup="true" aria-expanded="false">
<i class="ri-search-2-line" aria-hidden="true"></i>
<span class="engine-name">Default</span>
<i class="ri-arrow-down-s-line" aria-hidden="true"></i>
</button>
<div class="engine-dropdown" hidden role="menu">
<button type="button"
class="engine-option"
data-engine-url="search.html?q="
role="menuitemradio"
aria-checked="true">
<span class="name">Default</span>
<span class="help">In-browser search</span>
</button>
</div>
</div>
<button class="icon-settings display-settings">
<i class="ri-settings-3-line"></i>
<span class="sr-only">Settings</span>
</button>
</div>
</div>
<div id="top-content">
<div class="heading-with-actions top-heading">
<h1>README</h1>
<a href="readme.md" title="Copy Markdown (hold Ctrl/Cmd and click it to open as Markdown)" class="copy-markdown icon-action" rel="help">
<i class="ri-markdown-line" aria-hidden="true"></i>
<span class="sr-only">Copy Markdown</span>
</a>
</div>
<!--SPDX-FileCopyrightText: 2026 Nduati KuriaSPDX-License-Identifier: MIT--><img src="https://github.com/NduatiK/ash_gleam/blob/main/logo.png?raw=true" alt="Logo" width="300"/><p><a href="https://opensource.org/licenses/MIT"><img src="https://img.shields.io/badge/License-MIT-yellow.svg" alt="License: MIT"/></a>
<a href="https://hex.pm/packages/ash_gleam"><img src="https://img.shields.io/hexpm/v/ash_gleam.svg" alt="Hex version badge"/></a>
<a href="https://hexdocs.pm/ash_gleam"><img src="https://img.shields.io/badge/docs-hexdocs-purple" alt="Hexdocs badge"/></a></p><h1>AshGleam</h1><p><strong>Type-safe Gleam interop for Ash resources</strong></p><p>AshGleam integrates Elixir's Ash framework and Gleam into a single, cohesive system. It enables you to move data and execution across the boundary with compile-time guarantees.</p><p>You can:</p><ul><li><a href="#ashgleam">AshGleam</a><ul><li><a href="#installation">Installation</a><ul><li><a href="#with-igniter-recommended">With Igniter (recommended)</a></li><li><a href="#manual-setup">Manual setup</a></li></ul></li><li><a href="#standalone-elixir-and-gleam-bridges">Standalone Elixir and Gleam bridges</a></li><li><a href="#generate-gleam-types-from-your-ash-resources">Generate Gleam types from your Ash resources</a></li><li><a href="#expose-gleam-functions-as-ash-actions">Expose Gleam functions as Ash actions</a></li><li><a href="#expose-ash-actions-to-gleam">Expose Ash actions to Gleam</a></li><li><a href="#represent-gleam-custom-types-in-elixir">Represent Gleam custom-types in Elixir</a></li><li><a href="#embedded-resources">Embedded resources</a></li><li><a href="#requirements">Requirements</a></li><li><a href="#contributing">Contributing</a></li><li><a href="#license">License</a></li><li><a href="#links">Links</a></li></ul></li></ul><h2 id="installation" class="section-heading"><a href="#installation" class="hover-link"><i class="ri-link-m" aria-hidden="true"></i></a><span class="text">Installation</span></h2><h3 id="with-igniter-recommended" class="section-heading"><a href="#with-igniter-recommended" class="hover-link"><i class="ri-link-m" aria-hidden="true"></i></a><span class="text">With Igniter (recommended)</span></h3><pre><code class="makeup bash" translate="no"><span class="">mix igniter.install ash_gleam
</span></code></pre><pre><code class="makeup bash" translate="no"><span class="">mix igniter.install ash_gleam
</span><span class=""># If testing locally:
</span><span class="">mix igniter.install ash_gleam@path:..
</span></code></pre><p>This automatically configures your <code class="inline">mix.exs</code> with all the settings required by
<a href="https://github.com/gleam-lang/mix_gleam">MixGleam</a>: compilers, <code class="inline">erlc_paths</code>,
<code class="inline">erlc_include_path</code>, <code class="inline">prune_code_paths</code>, the <code class="inline">deps.get</code> alias, and the
<code class="inline">gleam_stdlib</code> / <code class="inline">gleeunit</code> dependencies. It also creates the <code class="inline">src/</code> directory
and adds <code class="inline">build/</code> to your <code class="inline">.gitignore</code>.</p><p>You will still need to install the Gleam compiler and the MixGleam archive:</p><pre><code class="makeup bash" translate="no"><span class=""># Install the Gleam compiler — see https://gleam.run/getting-started/installing-gleam.html
</span><span class="">
</span><span class=""># Install the MixGleam Mix archive
</span><span class="">mix archive.install hex mix_gleam
</span></code></pre><h3 id="manual-setup" class="section-heading"><a href="#manual-setup" class="hover-link"><i class="ri-link-m" aria-hidden="true"></i></a><span class="text">Manual setup</span></h3><p>Add <code class="inline">ash_gleam</code> to your dependencies:</p><pre><code class="makeup elixir" translate="no"><span class="c1"># mix.exs</span><span class="w">
</span><span class="kd">defp</span><span class="w"> </span><span class="nf">deps</span><span class="w"> </span><span class="k" data-group-id="6079361752-1">do</span><span class="w">
</span><span class="p" data-group-id="6079361752-2">[</span><span class="w">
</span><span class="p" data-group-id="6079361752-3">{</span><span class="ss">:ash_gleam</span><span class="p">,</span><span class="w"> </span><span class="s">"~> 0.1"</span><span class="p" data-group-id="6079361752-3">}</span><span class="p">,</span><span class="w">
</span><span class="p" data-group-id="6079361752-4">{</span><span class="ss">:gleam_stdlib</span><span class="p">,</span><span class="w"> </span><span class="s">"~> 0.34 or ~> 1.0"</span><span class="p" data-group-id="6079361752-4">}</span><span class="p">,</span><span class="w">
</span><span class="p" data-group-id="6079361752-5">{</span><span class="ss">:gleeunit</span><span class="p">,</span><span class="w"> </span><span class="s">"~> 1.0"</span><span class="p">,</span><span class="w"> </span><span class="ss">only</span><span class="p">:</span><span class="w"> </span><span class="p" data-group-id="6079361752-6">[</span><span class="ss">:dev</span><span class="p">,</span><span class="w"> </span><span class="ss">:test</span><span class="p" data-group-id="6079361752-6">]</span><span class="p">,</span><span class="w"> </span><span class="ss">runtime</span><span class="p">:</span><span class="w"> </span><span class="no">false</span><span class="p" data-group-id="6079361752-5">}</span><span class="w">
</span><span class="p" data-group-id="6079361752-2">]</span><span class="w">
</span><span class="k" data-group-id="6079361752-1">end</span></code></pre><p>Then follow the <a href="https://github.com/gleam-lang/mix_gleam">MixGleam README</a> to
configure your project:</p><pre><code class="makeup elixir" translate="no"><span class="c1"># mix.exs</span><span class="w">
</span><span class="na">@app</span><span class="w"> </span><span class="ss">:my_app</span><span class="w">
</span><span class="kd">def</span><span class="w"> </span><span class="nf">project</span><span class="w"> </span><span class="k" data-group-id="6467302923-1">do</span><span class="w">
</span><span class="p" data-group-id="6467302923-2">[</span><span class="w">
</span><span class="ss">app</span><span class="p">:</span><span class="w"> </span><span class="na">@app</span><span class="p">,</span><span class="w">
</span><span class="c1"># ...</span><span class="w">
</span><span class="ss">archives</span><span class="p">:</span><span class="w"> </span><span class="p" data-group-id="6467302923-3">[</span><span class="ss">mix_gleam</span><span class="p">:</span><span class="w"> </span><span class="s">"~> 0.6"</span><span class="p" data-group-id="6467302923-3">]</span><span class="p">,</span><span class="w">
</span><span class="ss">compilers</span><span class="p">:</span><span class="w"> </span><span class="p" data-group-id="6467302923-4">[</span><span class="ss">:gleam</span><span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="nc">Mix</span><span class="o">.</span><span class="n">compilers</span><span class="p" data-group-id="6467302923-5">(</span><span class="p" data-group-id="6467302923-5">)</span><span class="p" data-group-id="6467302923-4">]</span><span class="p">,</span><span class="w">
</span><span class="ss">aliases</span><span class="p">:</span><span class="w"> </span><span class="p" data-group-id="6467302923-6">[</span><span class="w">
</span><span class="ss">"deps.get"</span><span class="p">:</span><span class="w"> </span><span class="p" data-group-id="6467302923-7">[</span><span class="s">"deps.get"</span><span class="p">,</span><span class="w"> </span><span class="s">"gleam.deps.get"</span><span class="p" data-group-id="6467302923-7">]</span><span class="w">
</span><span class="p" data-group-id="6467302923-6">]</span><span class="p">,</span><span class="w">
</span><span class="ss">erlc_paths</span><span class="p">:</span><span class="w"> </span><span class="p" data-group-id="6467302923-8">[</span><span class="w">
</span><span class="s">"_build/dev/lib/</span><span class="si" data-group-id="6467302923-9">#{</span><span class="na">@app</span><span class="si" data-group-id="6467302923-9">}</span><span class="s">/_gleam_artefacts"</span><span class="p">,</span><span class="w">
</span><span class="s">"_build/dev/lib/</span><span class="si" data-group-id="6467302923-10">#{</span><span class="na">@app</span><span class="si" data-group-id="6467302923-10">}</span><span class="s">/build"</span><span class="w">
</span><span class="p" data-group-id="6467302923-8">]</span><span class="p">,</span><span class="w">
</span><span class="ss">erlc_include_path</span><span class="p">:</span><span class="w"> </span><span class="s">"_build/dev/lib/</span><span class="si" data-group-id="6467302923-11">#{</span><span class="na">@app</span><span class="si" data-group-id="6467302923-11">}</span><span class="s">/include"</span><span class="p">,</span><span class="w">
</span><span class="ss">prune_code_paths</span><span class="p">:</span><span class="w"> </span><span class="no">false</span><span class="w">
</span><span class="p" data-group-id="6467302923-2">]</span><span class="w">
</span><span class="k" data-group-id="6467302923-1">end</span></code></pre><p>Create a <code class="inline">src/</code> directory for your Gleam source files and add the following to your <code class="inline">.gitignore</code>:</p><pre><code class="makeup elixir" translate="no"><span class="c1"># gleam build files</span><span class="w">
</span><span class="o">/</span><span class="n">build</span><span class="o">/</span><span class="w">
</span><span class="c1"># intermediate generation file</span><span class="w">
</span><span class="o">/</span><span class="n">src</span><span class="o">/</span><span class="n">generated</span><span class="o">/</span><span class="n">manifest</span><span class="o">.</span><span class="n">term</span></code></pre><h2 id="standalone-elixir-and-gleam-bridges" class="section-heading"><a href="#standalone-elixir-and-gleam-bridges" class="hover-link"><i class="ri-link-m" aria-hidden="true"></i></a><span class="text">Standalone Elixir and Gleam bridges</span></h2><p>If you only want Elixir↔Gleam interop and do not want to hook into Ash, use <a href="AshGleam.GleamBridge.html"><code class="inline">AshGleam.GleamBridge</code></a>.</p><pre><code class="makeup elixir" translate="no"><span class="kd">defmodule</span><span class="w"> </span><span class="nc">MyApp.MathBridge</span><span class="w"> </span><span class="k" data-group-id="0615746274-1">do</span><span class="w">
</span><span class="kn">use</span><span class="w"> </span><span class="nc">AshGleam.GleamBridge</span><span class="w">
</span><span class="n">gleam</span><span class="w"> </span><span class="k" data-group-id="0615746274-2">do</span><span class="w">
</span><span class="n">consume</span><span class="w"> </span><span class="k" data-group-id="0615746274-3">do</span><span class="w">
</span><span class="n">function</span><span class="w"> </span><span class="ss">:add_in_gleam</span><span class="p">,</span><span class="w"> </span><span class="ss">:integer</span><span class="w"> </span><span class="k" data-group-id="0615746274-4">do</span><span class="w">
</span><span class="n">argument</span><span class="w"> </span><span class="ss">:a</span><span class="p">,</span><span class="w"> </span><span class="ss">:integer</span><span class="p">,</span><span class="w"> </span><span class="ss">allow_nil?</span><span class="p">:</span><span class="w"> </span><span class="no">false</span><span class="w">
</span><span class="n">argument</span><span class="w"> </span><span class="ss">:b</span><span class="p">,</span><span class="w"> </span><span class="ss">:integer</span><span class="p">,</span><span class="w"> </span><span class="ss">allow_nil?</span><span class="p">:</span><span class="w"> </span><span class="no">false</span><span class="w">
</span><span class="n">run</span><span class="w"> </span><span class="o">&</span><span class="nc">:my_gleam_module</span><span class="o">.</span><span class="n">add</span><span class="o">/</span><span class="mi">2</span><span class="w">
</span><span class="k" data-group-id="0615746274-4">end</span><span class="w">
</span><span class="k" data-group-id="0615746274-3">end</span><span class="w">
</span><span class="n">expose</span><span class="w"> </span><span class="k" data-group-id="0615746274-5">do</span><span class="w">
</span><span class="n">function</span><span class="w"> </span><span class="ss">:add</span><span class="p">,</span><span class="w"> </span><span class="ss">:integer</span><span class="w"> </span><span class="k" data-group-id="0615746274-6">do</span><span class="w">
</span><span class="n">argument</span><span class="w"> </span><span class="ss">:a</span><span class="p">,</span><span class="w"> </span><span class="ss">:integer</span><span class="p">,</span><span class="w"> </span><span class="ss">allow_nil?</span><span class="p">:</span><span class="w"> </span><span class="no">false</span><span class="w">
</span><span class="n">argument</span><span class="w"> </span><span class="ss">:b</span><span class="p">,</span><span class="w"> </span><span class="ss">:integer</span><span class="p">,</span><span class="w"> </span><span class="ss">allow_nil?</span><span class="p">:</span><span class="w"> </span><span class="no">false</span><span class="w">
</span><span class="n">run</span><span class="w"> </span><span class="k" data-group-id="0615746274-7">fn</span><span class="w"> </span><span class="n">a</span><span class="p">,</span><span class="w"> </span><span class="n">b</span><span class="w"> </span><span class="o">-></span><span class="w"> </span><span class="p" data-group-id="0615746274-8">{</span><span class="ss">:ok</span><span class="p">,</span><span class="w"> </span><span class="n">a</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="n">b</span><span class="p" data-group-id="0615746274-8">}</span><span class="w"> </span><span class="k" data-group-id="0615746274-7">end</span><span class="w">
</span><span class="k" data-group-id="0615746274-6">end</span><span class="w">
</span><span class="k" data-group-id="0615746274-5">end</span><span class="w">
</span><span class="k" data-group-id="0615746274-2">end</span><span class="w">
</span><span class="k" data-group-id="0615746274-1">end</span></code></pre><ul><li><code class="inline">consume</code> makes Gleam functions callable from Elixir <code class="inline">MyApp.MathBridge.add(2, 3)</code></li><li><code class="inline">expose</code> generates Gleam-callable functions backed by Elixir. <code class="inline">math_bridge.add_in_elixr(2, 3)</code></li></ul><p>Run <code class="inline">mix ash_gleam.codegen</code> to generate both sides.</p><h2 id="generate-gleam-types-from-your-ash-resources" class="section-heading"><a href="#generate-gleam-types-from-your-ash-resources" class="hover-link"><i class="ri-link-m" aria-hidden="true"></i></a><span class="text">Generate Gleam types from your Ash resources</span></h2><ol><li>Add <a href="AshGleam.Resource.html"><code class="inline">AshGleam.Resource</code></a> to your resource and declare a <code class="inline">gleam</code> block:</li></ol><pre><code class="makeup elixir" translate="no"><span class="kd">defmodule</span><span class="w"> </span><span class="nc">MyApp.Todo</span><span class="w"> </span><span class="k" data-group-id="4437354749-1">do</span><span class="w">
</span><span class="kn">use</span><span class="w"> </span><span class="nc">Ash.Resource</span><span class="p">,</span><span class="w">
</span><span class="n">...</span><span class="p">,</span><span class="w">
</span><span class="ss">extensions</span><span class="p">:</span><span class="w"> </span><span class="p" data-group-id="4437354749-2">[</span><span class="nc">AshGleam.Resource</span><span class="p">,</span><span class="w"> </span><span class="nc">AshGleam.Actions</span><span class="p" data-group-id="4437354749-2">]</span><span class="w">
</span><span class="n">gleam</span><span class="w"> </span><span class="k" data-group-id="4437354749-3">do</span><span class="w">
</span><span class="n">type_name</span><span class="w"> </span><span class="s">"Todo"</span><span class="w"> </span><span class="c1"># required — the Gleam type name</span><span class="w">
</span><span class="n">module_name</span><span class="w"> </span><span class="s">"todo_item"</span><span class="w"> </span><span class="c1"># optional — overrides the generated file name</span><span class="w">
</span><span class="k" data-group-id="4437354749-3">end</span><span class="w">
</span><span class="n">attributes</span><span class="w"> </span><span class="k" data-group-id="4437354749-4">do</span><span class="w">
</span><span class="n">uuid_primary_key</span><span class="w"> </span><span class="ss">:id</span><span class="w">
</span><span class="n">attribute</span><span class="w"> </span><span class="ss">:title</span><span class="p">,</span><span class="w"> </span><span class="ss">:string</span><span class="p">,</span><span class="w"> </span><span class="ss">allow_nil?</span><span class="p">:</span><span class="w"> </span><span class="no">false</span><span class="p">,</span><span class="w"> </span><span class="ss">public?</span><span class="p">:</span><span class="w"> </span><span class="no">true</span><span class="w">
</span><span class="n">attribute</span><span class="w"> </span><span class="ss">:completed</span><span class="p">,</span><span class="w"> </span><span class="ss">:boolean</span><span class="p">,</span><span class="w"> </span><span class="ss">default</span><span class="p">:</span><span class="w"> </span><span class="no">false</span><span class="p">,</span><span class="w"> </span><span class="ss">public?</span><span class="p">:</span><span class="w"> </span><span class="no">true</span><span class="w">
</span><span class="k" data-group-id="4437354749-4">end</span><span class="w">
</span><span class="k" data-group-id="4437354749-1">end</span></code></pre><ol start="2"><li>Run <code class="inline">mix ash_gleam.codegen</code></li></ol><pre><code class="gleam">// generated at src/generated/src/todo_item
pub type TicTacToe {
TicTacToe(
id: String,
title: String,
completed: Boolean,
)
}</code></pre><p>Only <code class="inline">public?: true</code> attributes are included in the generated Gleam type.</p><h2 id="expose-gleam-functions-as-ash-actions" class="section-heading"><a href="#expose-gleam-functions-as-ash-actions" class="hover-link"><i class="ri-link-m" aria-hidden="true"></i></a><span class="text">Expose Gleam functions as Ash actions</span></h2><ol><li>Create a gleam function (make sure you have run the generator first)</li></ol><pre><code class="gleam">// Import the generated Todo type
import src/generated/src/todo_item.{type Todo, Todo}
pub fn mark_completed(item: Todo) -> Todo {
Todo(..item, completed: True)
}</code></pre><ol start="2"><li>Add <a href="AshGleam.Actions.html"><code class="inline">AshGleam.Actions</code></a> to your resource and declare a <code class="inline">gleam.actions</code> block for that function</li></ol><pre><code class="makeup elixir" translate="no"><span class="kd">defmodule</span><span class="w"> </span><span class="nc">MyApp.Todo</span><span class="w"> </span><span class="k" data-group-id="1933239049-1">do</span><span class="w">
</span><span class="kn">use</span><span class="w"> </span><span class="nc">Ash.Resource</span><span class="p">,</span><span class="w">
</span><span class="n">...</span><span class="p">,</span><span class="w">
</span><span class="ss">extensions</span><span class="p">:</span><span class="w"> </span><span class="p" data-group-id="1933239049-2">[</span><span class="nc">AshGleam.Resource</span><span class="p">,</span><span class="w"> </span><span class="nc">AshGleam.Actions</span><span class="p" data-group-id="1933239049-2">]</span><span class="w">
</span><span class="n">gleam</span><span class="w"> </span><span class="k" data-group-id="1933239049-3">do</span><span class="w">
</span><span class="n">type_name</span><span class="w"> </span><span class="s">"Todo"</span><span class="w">
</span><span class="n">module_name</span><span class="w"> </span><span class="s">"todo_item"</span><span class="w">
</span><span class="n">actions</span><span class="w"> </span><span class="k" data-group-id="1933239049-4">do</span><span class="w">
</span><span class="n">action</span><span class="w"> </span><span class="ss">:mark_completed</span><span class="p">,</span><span class="w"> </span><span class="bp">__MODULE__</span><span class="w"> </span><span class="k" data-group-id="1933239049-5">do</span><span class="w">
</span><span class="n">update?</span><span class="w"> </span><span class="no">true</span><span class="w">
</span><span class="n">argument</span><span class="w"> </span><span class="ss">:todo</span><span class="p">,</span><span class="w"> </span><span class="bp">__MODULE__</span><span class="p">,</span><span class="w"> </span><span class="ss">allow_nil?</span><span class="p">:</span><span class="w"> </span><span class="no">false</span><span class="w">
</span><span class="n">run</span><span class="w"> </span><span class="o">&</span><span class="nc">:test_gleam</span><span class="o">.</span><span class="n">mark_completed</span><span class="o">/</span><span class="mi">1</span><span class="w">
</span><span class="k" data-group-id="1933239049-5">end</span><span class="w">
</span><span class="k" data-group-id="1933239049-4">end</span><span class="w">
</span><span class="k" data-group-id="1933239049-3">end</span><span class="w">
</span><span class="k" data-group-id="1933239049-1">end</span></code></pre><ol start="3"><li>Use the exposed function</li></ol><pre><code class="makeup elixir" translate="no"><span class="n">todo</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="c1"># create a todo</span><span class="w">
</span><span class="c1"># mark_completed in memory</span><span class="w">
</span><span class="n">assert</span><span class="w"> </span><span class="p" data-group-id="2598642739-1">{</span><span class="ss">:ok</span><span class="p">,</span><span class="w"> </span><span class="n">updated</span><span class="p" data-group-id="2598642739-1">}</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nc">MyApp.Todo</span><span class="o">.</span><span class="n">mark_completed</span><span class="p" data-group-id="2598642739-2">(</span><span class="p" data-group-id="2598642739-3">%{</span><span class="ss">todo</span><span class="p">:</span><span class="w"> </span><span class="n">todo</span><span class="p" data-group-id="2598642739-3">}</span><span class="p" data-group-id="2598642739-2">)</span><span class="w">
</span><span class="c1"># mark_completed and persist</span><span class="w">
</span><span class="p" data-group-id="2598642739-4">{</span><span class="ss">:ok</span><span class="p">,</span><span class="w"> </span><span class="n">changeset</span><span class="p" data-group-id="2598642739-4">}</span><span class="w"> </span><span class="o">=</span><span class="w">
</span><span class="n">todo</span><span class="w">
</span><span class="o">|></span><span class="w"> </span><span class="nc">AshGleam.Changeset</span><span class="o">.</span><span class="n">for_update</span><span class="p" data-group-id="2598642739-5">(</span><span class="ss">:mark_completed</span><span class="p">,</span><span class="w"> </span><span class="p" data-group-id="2598642739-6">%{</span><span class="p" data-group-id="2598642739-6">}</span><span class="p">,</span><span class="w"> </span><span class="ss">action</span><span class="p">:</span><span class="w"> </span><span class="ss">:update</span><span class="p" data-group-id="2598642739-5">)</span><span class="w">
</span><span class="o">|></span><span class="w"> </span><span class="nc">Ash</span><span class="o">.</span><span class="n">update!</span><span class="p" data-group-id="2598642739-7">(</span><span class="p" data-group-id="2598642739-7">)</span></code></pre><ol start="4"><li>If you want a code interface that does the update for you, update your domain</li></ol><pre><code class="makeup elixir" translate="no"><span class="kd">defmodule</span><span class="w"> </span><span class="nc">MyApp.Domain</span><span class="w"> </span><span class="k" data-group-id="6261883602-1">do</span><span class="w">
</span><span class="kn">use</span><span class="w"> </span><span class="nc">Ash.Domain</span><span class="p">,</span><span class="w">
</span><span class="ss">otp_app</span><span class="p">:</span><span class="w"> </span><span class="ss">:my_app</span><span class="p">,</span><span class="w">
</span><span class="ss">extensions</span><span class="p">:</span><span class="w"> </span><span class="p" data-group-id="6261883602-2">[</span><span class="nc">AshGleam.Domain</span><span class="p" data-group-id="6261883602-2">]</span><span class="w">
</span><span class="n">gleam</span><span class="w"> </span><span class="k" data-group-id="6261883602-3">do</span><span class="w">
</span><span class="n">code_interface</span><span class="w"> </span><span class="k" data-group-id="6261883602-4">do</span><span class="w">
</span><span class="n">resource</span><span class="w"> </span><span class="nc">AshGleam.TestTodo</span><span class="w"> </span><span class="k" data-group-id="6261883602-5">do</span><span class="w">
</span><span class="n">define_gleam_update</span><span class="w"> </span><span class="ss">:mark_completed</span><span class="p">,</span><span class="w"> </span><span class="ss">action</span><span class="p">:</span><span class="w"> </span><span class="ss">:update</span><span class="w">
</span><span class="k" data-group-id="6261883602-5">end</span><span class="w">
</span><span class="k" data-group-id="6261883602-4">end</span><span class="w">
</span><span class="k" data-group-id="6261883602-3">end</span><span class="w">
</span><span class="k" data-group-id="6261883602-1">end</span><span class="w">
</span><span class="c1"># mark_completed and persist</span><span class="w">
</span><span class="p" data-group-id="6261883602-6">{</span><span class="ss">:ok</span><span class="p">,</span><span class="w"> </span><span class="n">updated</span><span class="p" data-group-id="6261883602-6">}</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nc">MyApp.Domain</span><span class="o">.</span><span class="n">mark_completed</span><span class="p" data-group-id="6261883602-7">(</span><span class="n">todo</span><span class="p" data-group-id="6261883602-7">)</span></code></pre><h2 id="expose-ash-actions-to-gleam" class="section-heading"><a href="#expose-ash-actions-to-gleam" class="hover-link"><i class="ri-link-m" aria-hidden="true"></i></a><span class="text">Expose Ash actions to Gleam</span></h2><ol><li>Add the resource actions you want to expose to Gleam</li></ol><pre><code class="makeup elixir" translate="no"><span class="kd">defmodule</span><span class="w"> </span><span class="nc">MyApp.Todo</span><span class="w"> </span><span class="k" data-group-id="5746842312-1">do</span><span class="w">
</span><span class="kn">use</span><span class="w"> </span><span class="nc">Ash.Resource</span><span class="p">,</span><span class="w">
</span><span class="n">...</span><span class="p">,</span><span class="w">
</span><span class="ss">extensions</span><span class="p">:</span><span class="w"> </span><span class="p" data-group-id="5746842312-2">[</span><span class="nc">AshGleam.Resource</span><span class="p">,</span><span class="w"> </span><span class="nc">AshGleam.Actions</span><span class="p" data-group-id="5746842312-2">]</span><span class="w">
</span><span class="n">...</span><span class="w">
</span><span class="n">actions</span><span class="w"> </span><span class="k" data-group-id="5746842312-3">do</span><span class="w">
</span><span class="n">defaults</span><span class="w"> </span><span class="p" data-group-id="5746842312-4">[</span><span class="ss">:read</span><span class="p" data-group-id="5746842312-4">]</span><span class="w">
</span><span class="n">create</span><span class="w"> </span><span class="ss">:create</span><span class="w"> </span><span class="k" data-group-id="5746842312-5">do</span><span class="w">
</span><span class="n">accept</span><span class="w"> </span><span class="p" data-group-id="5746842312-6">[</span><span class="ss">:title</span><span class="p">,</span><span class="w"> </span><span class="ss">:completed</span><span class="p">,</span><span class="w"> </span><span class="ss">:priority</span><span class="p" data-group-id="5746842312-6">]</span><span class="w">
</span><span class="k" data-group-id="5746842312-5">end</span><span class="w">
</span><span class="n">update</span><span class="w"> </span><span class="ss">:update</span><span class="w"> </span><span class="k" data-group-id="5746842312-7">do</span><span class="w">
</span><span class="n">accept</span><span class="w"> </span><span class="p" data-group-id="5746842312-8">[</span><span class="ss">:title</span><span class="p">,</span><span class="w"> </span><span class="ss">:completed</span><span class="p">,</span><span class="w"> </span><span class="ss">:priority</span><span class="p" data-group-id="5746842312-8">]</span><span class="w">
</span><span class="n">require_atomic?</span><span class="w"> </span><span class="no">false</span><span class="w">
</span><span class="k" data-group-id="5746842312-7">end</span><span class="w">
</span><span class="n">destroy</span><span class="w"> </span><span class="ss">:destroy</span><span class="w">
</span><span class="n">read</span><span class="w"> </span><span class="ss">:get</span><span class="w"> </span><span class="k" data-group-id="5746842312-9">do</span><span class="w">
</span><span class="n">get_by</span><span class="w"> </span><span class="p" data-group-id="5746842312-10">[</span><span class="ss">:id</span><span class="p" data-group-id="5746842312-10">]</span><span class="w">
</span><span class="k" data-group-id="5746842312-9">end</span><span class="w">
</span><span class="n">read</span><span class="w"> </span><span class="ss">:first_completed</span><span class="w"> </span><span class="k" data-group-id="5746842312-11">do</span><span class="w">
</span><span class="n">get?</span><span class="w"> </span><span class="no">true</span><span class="w">
</span><span class="n">filter</span><span class="w"> </span><span class="n">expr</span><span class="p" data-group-id="5746842312-12">(</span><span class="n">completed</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="no">true</span><span class="p" data-group-id="5746842312-12">)</span><span class="w">
</span><span class="n">prepare</span><span class="w"> </span><span class="n">build</span><span class="p" data-group-id="5746842312-13">(</span><span class="ss">sort</span><span class="p">:</span><span class="w"> </span><span class="p" data-group-id="5746842312-14">[</span><span class="ss">title</span><span class="p">:</span><span class="w"> </span><span class="ss">:asc</span><span class="p" data-group-id="5746842312-14">]</span><span class="p">,</span><span class="w"> </span><span class="ss">limit</span><span class="p">:</span><span class="w"> </span><span class="mi">1</span><span class="p" data-group-id="5746842312-13">)</span><span class="w">
</span><span class="k" data-group-id="5746842312-11">end</span><span class="w">
</span><span class="k" data-group-id="5746842312-3">end</span><span class="w">
</span><span class="k" data-group-id="5746842312-1">end</span></code></pre><ol start="2"><li>Create an entry in gleam.ffi for your resource actions</li></ol><pre><code class="makeup elixir" translate="no"><span class="kd">defmodule</span><span class="w"> </span><span class="nc">MyApp.Domain</span><span class="w"> </span><span class="k" data-group-id="4993555580-1">do</span><span class="w">
</span><span class="kn">use</span><span class="w"> </span><span class="nc">Ash.Domain</span><span class="p">,</span><span class="w">
</span><span class="ss">otp_app</span><span class="p">:</span><span class="w"> </span><span class="ss">:my_app</span><span class="p">,</span><span class="w">
</span><span class="ss">extensions</span><span class="p">:</span><span class="w"> </span><span class="p" data-group-id="4993555580-2">[</span><span class="nc">AshGleam.Domain</span><span class="p" data-group-id="4993555580-2">]</span><span class="w">
</span><span class="n">gleam</span><span class="w"> </span><span class="k" data-group-id="4993555580-3">do</span><span class="w">
</span><span class="n">ffi</span><span class="w"> </span><span class="k" data-group-id="4993555580-4">do</span><span class="w">
</span><span class="n">resource</span><span class="w"> </span><span class="nc">MyApp.Todo</span><span class="w"> </span><span class="k" data-group-id="4993555580-5">do</span><span class="w">
</span><span class="n">action</span><span class="w"> </span><span class="ss">:list_todos</span><span class="p">,</span><span class="w"> </span><span class="ss">:read</span><span class="w">
</span><span class="n">action</span><span class="w"> </span><span class="ss">:create_todo</span><span class="p">,</span><span class="w"> </span><span class="ss">:create</span><span class="w">
</span><span class="n">action</span><span class="w"> </span><span class="ss">:get_todo</span><span class="p">,</span><span class="w"> </span><span class="ss">:get</span><span class="w">
</span><span class="n">action</span><span class="w"> </span><span class="ss">:destroy_todo</span><span class="p">,</span><span class="w"> </span><span class="ss">:destroy</span><span class="w">
</span><span class="n">action</span><span class="w"> </span><span class="ss">:first_completed</span><span class="p">,</span><span class="w"> </span><span class="ss">:first_completed</span><span class="w">
</span><span class="k" data-group-id="4993555580-5">end</span><span class="w">
</span><span class="k" data-group-id="4993555580-4">end</span><span class="w">
</span><span class="k" data-group-id="4993555580-3">end</span><span class="w">
</span><span class="k" data-group-id="4993555580-1">end</span></code></pre><ol start="3"><li><p>Run <code class="inline">mix ash_gleam.codegen</code></p></li><li><p>Use the generated gleam functions</p></li></ol><pre><code class="gleam">import myapp/generated/src/list_todos
import myapp/generated/src/todo_item.{type TodoFilter, type TodoSort}
pub fn fetch_incomplete_todo_titles(): Result(List(String), String) {
list_todos.new()
|> list_todos.filter([todo_item.CompletedEq(False)])
|> list_todos.sort([todo_item.Title(Asc)])
|> list_todos.limit(option.Some(10))
|> list_todos.run()
|> result.map(fn (todo_item) {
todo_item.title
})
}</code></pre><h2 id="represent-gleam-custom-types-in-elixir" class="section-heading"><a href="#represent-gleam-custom-types-in-elixir" class="hover-link"><i class="ri-link-m" aria-hidden="true"></i></a><span class="text">Represent Gleam custom-types in Elixir</span></h2><p>You can define the equivalent to Gleam's custom types using <a href="https://hexdocs.pm/ash_sum_type/1.0.3/AshSumType.html"><code class="inline">AshSumType</code></a> from <a href="https://github.com/NduatiK/ash_sum_type">ash_sum_type</a>.</p><table> <thead>
<tr>
<th>Elixir</th>
<th>Generated Gleam</th>
</tr>
</thead>
<tbody><tr><td>
```elixir
defmodule MyApp.Mark do
use AshSumType, variants: [:x, :o]
end
```
</td><td>
```gleam
pub type Mark {
X
O
}
```
</td></tr><tr><td>
```elixir
defmodule MyApp.Mark do
use AshSumType
variant :x
variant :o
end
```
</td><td>
```gleam
pub type Mark {
X
O
}
```
</td></tr><tr><td>
```elixir
defmodule MyApp.LookupOutcome do
use AshSumType
variant :found do
field :value, MyApp.Todo, allow_nil?: false
end
variant :missing do
field :error, :string, allow_nil?: false
end
end
````
</td>
<td>
```gleam
pub type LookupOutcome {
Found(Todo)
Missing(String)
}
````
</td>
</tr>
</tbody>
</table>
## Embedded resources
Resources with the `:embedded` data layer work as field types in other resources. The embedded resource gets its own Gleam type and is imported automatically in the parent resource's generated file.
```elixir
defmodule MyApp.Tag do
use Ash.Resource,
domain: MyApp.Domain,
data_layer: :embedded,
extensions: [AshGleam.Resource]
gleam do
type_name "Tag"
end
attributes do
attribute :label, :string, allow_nil?: false, public?: true
attribute :color, :string, allow_nil?: false, public?: true
end
end
defmodule MyApp.Todo do
use Ash.Resource,
...,
extensions: [AshGleam.Resource]
attributes do
...
# Gleam type List(Tag)
attribute :tags, {:array, MyApp.Tag}, allow_nil?: false, default: [], public?: true
# Gleam type List(Option(Tag))
attribute :nullable_tags, {:array, MyApp.Tag}, allow_nil?: false, default: [], public?: true, nil_items?: true
end
end
```
## Requirements
- Elixir 1.15+
- Ash 3.0+
- Gleam (with `mix_gleam` configured)
## Contributing
1. Fork the repository
2. Create a feature branch
3. Add tests for any new behaviour
4. Run `mix test` and `mix format`
5. Open a pull request
## License
MIT — see [LICENSES/MIT.txt](https://github.com/NduatiK/ash_gleam/blob/main/LICENSES/MIT.txt).
## Links
- **Hex**: [https://hex.pm/packages/ash_gleam](https://hex.pm/packages/ash_gleam)
- **Docs**: [https://hexdocs.pm/ash_gleam](https://hexdocs.pm/ash_gleam)
- **Issues**: [https://github.com/NduatiK/ash_gleam/issues](https://github.com/NduatiK/ash_gleam/issues)</table>
</div>
<div class="bottom-actions" id="bottom-actions">
<div class="bottom-actions-item">
</div>
<div class="bottom-actions-item">
</div>
</div>
<footer class="footer">
<p>
<span class="line">
<a href="https://hex.pm/packages/ash_gleam/0.4.0">Hex Package</a>
<a href="https://preview.hex.pm/preview/ash_gleam/0.4.0">Hex Preview</a>
(<a href="https://preview.hex.pm/preview/ash_gleam/0.4.0/show/README.md">current file</a>)
</span>
<span class="line">
<button class="a-main footer-button display-quick-switch" title="Go to package docs">
Go to package docs
</button>
<a href="llms.txt" target="_blank">
View llms.txt
</a>
<a href="ash_gleam.epub">
Download ePub version
</a>
</span>
</p>
<p class="built-using">
Built using
<a href="https://github.com/elixir-lang/ex_doc" title="ExDoc" target="_blank" rel="help noopener" translate="no">ExDoc</a> (v0.40.1) for the
<a href="https://elixir-lang.org" title="Elixir" target="_blank" translate="no">Elixir programming language</a>
</p>
</footer>
</div>
</main>
</div>
</body>
</html>