Module

Data.Codec.Argonaut.Migration

Codecs that provide forward migrations.

In a forward migration, the decoder migrates to the new format while decoding from JSON and the encoder uses the new format while encoding to JSON.

If you need more control over a forward migration, the Functor instance allows operating on the underlying Json value directly.

If you need both forward and backward migrations, the Profunctor instance allows operating on the underlying Json value directly in both directions.

Sometimes even greater control over migration is required, and new error states need to be introduced. In this situation a JsonCodec will need to be constructed manually - this should be a last resort though, as building a codec manually means there is no guarantee that it will roundtrip successfully.

Migrations are applied by composing a migration codec to run in advance of the codec proper. Codec composition is performed with the (<~<) and (>~>) operators from Data.Codec.

An example of a codec with a migration applied:

import Data.Codec ((>~>))
import Data.Codec.Argonaut as CA
import Data.Codec.Argonaut.Migration as CAM
import Data.Codec.Argonaut.Record as CAR

type MyModel = { key ∷ String, value ∷ Int }

codec ∷ CA.JsonCodec MyModel
codec =
  CAM.renameField "tag" "key" >~>
    CA.object "MyModel" (CAR.record
     { key: CA.string
     , value: CA.int
     })

Here we're using the renameField migration to rename a property of our JSON object from "tag" to "key", and then in the codec proper we only need to deal with "key".

Multiple migrations can be chained together using the codec composition operators.

#addDefaultField

addDefaultField :: String -> Json -> JsonCodec Json

When dealing with a JSON object that may be missing a field, this codec can be used to alter the JSON before parsing to ensure a default value is present instead.

#updateField

updateField :: String -> (Json -> Json) -> JsonCodec Json

Re-maps the value of a field in a JSON object.

#addDefaultOrUpdateField

addDefaultOrUpdateField :: String -> (Maybe Json -> Json) -> JsonCodec Json

When dealing with a JSON object that may be missing a field, this codec can be used to alter the JSON before parsing to ensure a default value is present instead. Similar to addDefaultField, but allows existing values to be modified also.

#renameField

renameField :: String -> String -> JsonCodec Json

When dealing with a JSON object that has had a field name changed, this codec can be used to alter the JSON before parsing to ensure the new field name is used instead

#nestForTagged

nestForTagged :: JsonCodec Json

Prepares an object from a legacy codec for use in a Variant or taggedSum codec.

For an input like: { "tag": "tag", "x": 1, "y": 2, "z": 3 } the result will be: { "tag": "tag", "value": { "x": 1, "y": 2, "z": 3 } }

For an input like: { "tag": "tag", "value": 1, "foo": 2 } the result will be: { "tag": "tag", "value": { "value": 1, "foo": 2 }

If the value is already in the expected form, where there is only value and no other keys (aside from tag): { "tag": "tag", "value": true } the result will be the same as the input.

If the tag field is missing from the input, it will also be missing in the output.

Modules