Ash extension that mirrors a resource into a SearchAsh.GlobalIndex so it shows up in
the unified global search.
defmodule MyApp.Sales.BonDeCommande do
use Ash.Resource,
domain: MyApp.Sales,
data_layer: AshPostgres.DataLayer,
extensions: [SearchAsh.Source]
searchable do
index MyApp.Search.Document
source_type :bon_de_commande
fields [:numero, :client_nom, :description]
language_attribute :language
label_field :numero
archived :deleted_at # optional — truthy value marks the row archived
end
# ... attributes + create/update/destroy actions ...
endChoosing the language
Each indexed row is stemmed in one language, resolved one of two ways — pick whichever fits the resource:
language_attribute :language(the default) reads the language per row from that attribute, so one resource can hold rows in many languages.language :frfixes one language for every row of the resource. Use it for a mono-language resource, which then needs no language attribute at all.
The two are mutually exclusive, and setting neither is only valid when the resource
actually has a :language attribute — a compile-time verifier enforces both rules.
searchable do
index MyApp.Search.Document
source_type :page_statique
fields [:titre, :corps]
language :fr # no :language attribute on this resource
endThe extension sets require_atomic? false on the update/destroy actions it augments
(stemming happens in Elixir, so the sync can't be expressed as an atomic SQL statement),
so you don't
set it yourself. Because the sync writes only to the separate index table (never to a
source attribute), it is atomic-compatible: Ash.bulk_create/bulk_update/bulk_destroy
keep the index in sync with no strategy: option required.
On create/update it upserts a stemmed document into the index (tenant-aware). archived
derives the index flag from a source attribute's truthiness (a boolean, or a
deleted_at timestamp) or a record -> boolean function; :global_search hides
archived rows by default. On destroy, on_destroy either removes the row (:remove,
default) or keeps it archived (:archive, for AshArchival-style soft deletes).
Backfill existing rows with SearchAsh.reindex(MyApp.Sales.BonDeCommande).