Orkestra.ES.Repository (orkestra v0.2.0)

Copy Markdown View Source

Generates a CRUD/read repository for an Orkestra.ES.Schema.

A repository binds a schema to a Snap.Cluster and exposes an idiomatic, tuple-returning API over Elasticsearch/OpenSearch: single-document get/2, save/2, delete/2, bulk save_all/2, count/2, a lazy stream/1, refresh/1, and a raw search/2 escape hatch. Every function accepts a trailing opts :: keyword() with an optional :culture for multi-culture schemas.

Defining a repository

defmodule MyApp.Search.Products do
  use Orkestra.ES.Repository,
    schema: MyApp.Search.Product,
    cluster: MyApp.ESCluster
end

Both :schema and :cluster are required; omitting either raises an ArgumentError at compile time.

Generated API

  • get(id, opts \\ []){:ok, struct} | {:error, :not_found} | {:error, term}.

  • save(struct, opts \\ []) — upsert; {:ok, struct} | {:error, term}.

  • save_all(structs, opts \\ []) — bulk upsert; :ok | {:error, %Snap.BulkError{}} | {:error, term}.

  • delete(id, opts \\ []):ok | {:error, :not_found} | {:error, term}.

  • count(opts \\ []){:ok, non_neg_integer} | {:error, term}.

  • stream(opts \\ []) — a lazy Enumerable of schema structs.
  • refresh(opts \\ []):ok | {:error, term}.

  • search(query, opts \\ []){:ok, %Snap.SearchResponse{}} | {:error, term}.

  • get_paged(opts \\ []) — paginated/faceted query; {:ok, %Orkestra.ES.Page{}} | {:error, term}.

  • __es_repository__(:schema | :cluster) — introspection.

All generated functions are defoverridable, so a repository may redefine any of them (e.g. to add caching) and delegate with super/….

Culture resolution

The document _id comes from the schema's primary_key field. The target index alias is resolved from the schema and the optional :culture option:

  • no :culture — the schema default alias (multi-culture) or the single unsuffixed alias (mono-culture).
  • :culture on a multi-culture schema — the per-culture alias, or {:error, {:unknown_culture, culture, valid_cultures}} when the culture is not declared.
  • :culture on a mono-culture schema — always {:error, {:unknown_culture, culture, []}}, since mono-culture schemas accept no culture argument.

Culture is validated before the schema's alias_for/1 is called (that function raises), so the tuple-returning functions never raise on an unknown culture. stream/1 is the sole exception: because it must return an Enumerable rather than a tuple, it raises ArgumentError on an unknown culture.

count/2, stream/1 and search/2 queries

count/2 and stream/1 accept an optional :query in opts:

  • omitted — matches all documents.
  • an %Orkestra.ES.Query{} — built via Orkestra.ES.Query.build/1; only its "query" clause is used.
  • a raw map — used as-is when it already carries a "query" key, otherwise wrapped as %{"query" => map}.

search/2 takes the query as its first argument: either an %Orkestra.ES.Query{} (built into a full request body) or a raw request map. Hits are not decoded — the caller inspects the %Snap.SearchResponse{} and may rebuild structs with the schema's from_hit/1 on each hit.source.

Observability

Every public function opens an OpenTelemetry span (orkestra.es.get, orkestra.es.save, …) with "es.index", "es.culture" and "orkestra.es.schema" attributes (plus "es.doc_count" for save_all/2) and emits a [:orkestra, :es, :request] :telemetry event with %{duration_ms: …} measurements and %{op:, index:, culture:, schema:, result:} metadata. stream/1 spans only the opening of the stream — the actual scroll requests happen lazily as the consumer pulls elements. Cluster credentials and adapter options are never logged (convention T-08-02).