Dowser.Elasticsearch.Codec (Dowser.Elasticsearch v0.1.1)

View Source

Casts Elasticsearch documents and search results to and from native Elixir terms, based on each document's own index mapping — a Dowser.Client.Codec implementation, set as :codec_adapter (see Dowser.Client):

Dowser.Client.Config.new(
  endpoint: "http://localhost:9200",
  codec_adapter: Dowser.Elasticsearch.Codec
)

Once configured, every API function in Dowser.Elasticsearch.Document and Dowser.Elasticsearch.Search casts automatically — no per-call option needed. Mappings are fetched (and cached) through Dowser.Elasticsearch.MappingCacher.

decode/2

Finds and casts every document in a response body, at any nesting depth: a bare document (Document.get/3), hits.hits[] (Search.search/2), responses[].hits.hits[] (Search.msearch/2), and so on — each hit's own _index selects its mapping, so mixed-index results (e.g. msearch/2 across different indices) are cast correctly. opts[:source], alongside opts[:index], casts a bare _source document with no _index of its own (Document.get_source/3).

If no mapping can be found for a document's index (no Dowser.Elasticsearch.MappingCacher running, or the fetch fails), its values pass through unchanged; keys are still cast per opts[:key_fn].

encode/2

Casts a request body against opts[:index]'s mapping — a no-op when opts[:index] is absent. opts[:doc_key] casts only that sub-key instead of the whole body (Document.update/4's %{doc: ...} shape). A list body is treated as a Document.bulk/2 NDJSON action list: index/create actions cast their whole payload, update actions cast only doc, and delete actions (which carry no payload) are left alone; a per-action _index overrides opts[:index].

Field-level casting

Per-field casting is dispatched via load/2/dump/2, built with Dowser.Client.Codec.Builder from the table below. Only the field types JSON can't natively represent are cast; any other mapping entry — and nil values — fall back to identity.

mapping typefieldElixir term
date, date_nanosDowser.Elasticsearch.Fields.DateDateTime
date_rangeDowser.Elasticsearch.Fields.DateRangeDate.Range
integer_rangeDowser.Elasticsearch.Fields.RangeRange
ipDowser.Elasticsearch.Fields.IP:inet tuple
binaryDowser.Elasticsearch.Fields.Binaryraw binary
geo_pointDowser.Elasticsearch.Fields.GeoPoint{lat, lon}

Custom codecs

Add field types by inheriting the built-in casts:

defmodule MyApp.Codec do
  use Dowser.Client.Codec.Builder, inherit: Dowser.Elasticsearch.Codec

  cast %{"type" => "scaled_float"}, MyApp.Fields.ScaledFloat
end

Inherited casts are matched first, so to replace a built-in cast (e.g. handle a custom date format), declare every cast yourself instead of inheriting. A module built this way only gets load/2/dump/2 (single-field casting), not decode/2/encode/2 — it can't be set as :codec_adapter directly; write your own whole-body module modeled on this one, dispatching to MyApp.Codec.load/2/dump/2 instead.

Summary

Functions

dump(value, field)

Callback implementation for Dowser.Client.Field.dump/2.

load(value, field)

Callback implementation for Dowser.Client.Field.load/2.