SearchAsh.Source (search_ash v0.2.2)

Copy Markdown View Source

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 ...
end

Choosing 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 :fr fixes 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
end

The 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).

Summary

Functions

searchable(body)

(macro)