saga/codec

Converts saved values to and from text with a version, for saga/durable checkpoints.

Use this module only with saga/durable: local runs with saga/execution need no codecs. durable.new takes a codec for a workflow’s input, output, error and undo error, and durable.recoverable takes one for a step’s input and output. The version of every codec enters the workflow’s compatibility stamp, so changing a codec’s version makes saved checkpoints incompatible instead of misread.

json is the ordinary constructor: it takes the gleam/json encoder and the gleam/dynamic/decode decoder an application already has. The encoder may refuse a value with a message, so a JSON Blueprint codec bridges with result.map_error:

import gleam/result
import json/blueprint/codec as blueprint
import saga/codec

let order =
  codec.json(
    "order-1",
    fn(order) {
      blueprint.to_json(order_codec(), order)
      |> result.map_error(blueprint.describe_encode_error)
    },
    blueprint.decoder(order_codec()),
  )

A plain encoder that cannot fail is wrapped in Ok: codec.json("amount-1", fn(n) { Ok(json.int(n)) }, decode.int).

Types

A versioned pair of conversions between a value and saved text.

pub opaque type Codec(a)

Why a codec could not save or restore a value. The union is closed.

pub type CodecError {
  EncodeFailed(detail: String)
  DecodeFailed(detail: String)
  JsonDecodeFailed(error: json.DecodeError)
  RoundTripFailed(error: CodecError)
  CodecRaised(reason: String)
}

Constructors

  • EncodeFailed(detail: String)

    The encoder refused the value; detail is its message, for logs.

  • DecodeFailed(detail: String)

    A new codec’s decoder refused the saved text; detail is its message, for logs.

  • JsonDecodeFailed(error: json.DecodeError)

    A json codec’s saved text was not JSON, or its decoder refused it.

  • RoundTripFailed(error: CodecError)

    The text the encoder produced did not decode back; error is the decoding failure. Saga checks this before every effect.

  • CodecRaised(reason: String)

    A conversion raised; reason is the formatted exception, for logs.

Values

pub fn bool() -> Codec(Bool)

A codec for Bool as "true"/"false", version "bool-1".

pub fn describe_error(error: CodecError) -> String

Describes a codec error for logs.

pub fn int() -> Codec(Int)

A codec for Int as its decimal text, version "int-1".

pub fn json(
  version: String,
  encode: fn(a) -> Result(json.Json, String),
  decoder: decode.Decoder(a),
) -> Codec(a)

A codec over gleam/json: encode builds the JSON of a value or refuses it with a message, and decoder reads it back. durable.new panics on an empty version.

pub fn new(
  version: String,
  encode: fn(a) -> Result(String, String),
  decode: fn(String) -> Result(a, String),
) -> Codec(a)

A codec from a version and two text conversions, for a format other than JSON. decode must accept every text encode produces. durable.new panics on an empty version.

pub fn text() -> Codec(String)

The identity codec for String, version "text-1".

✨ Search Document