avh4 / elm-desktop-app / DesktopApp.JsonMapping

Mapping Elm values to JSON objects


type ObjectMapping encodesFrom decodesTo

Represents both how to encode encodesFrom into a JSON object and decode a JSON object into decodesTo. This is similar to JsonMapping, but it allows a pipeline-style API for building up mappings (see object, with, static).

Notably this is used with DesktopApp.program to specify how to save and load data. When used in that way, the encodesFrom type will be your program's model, and the decodesTo type will be your program's msg (which will be produced when data is loaded).

Also of note: when encodesFrom and decodesTo are the same type it specifies a two-way mapping to and from JSON (and can then be turned into a JsonMapping with fromObjectMapping).

object : decodesTo -> ObjectMapping encodesFrom decodesTo

Creates a trivial ObjectMapping. This, along with with, static make up a pipeline-style API which can be used like this:

import DesktopApp.JsonMapping exposing (ObjectMapping, int, object, with)

type alias MyData =
    { total : Int
    , count : Int
    }

myObjectMapping : ObjectMapping MyData MyData
myObjectMapping =
    object MyData
        |> with "total" .total int
        |> with "count" .count int

with : String -> (encodesFrom -> a) -> JsonMapping a -> ObjectMapping encodesFrom (a -> decodesTo) -> ObjectMapping encodesFrom decodesTo

Adds a field to an object. It will be represented in both your Elm model and in the JSON.

static : String -> a -> JsonMapping a -> ObjectMapping encodesFrom decodesTo -> ObjectMapping encodesFrom decodesTo

Adds a static field to an object. The field will not be represented in your Elm model, but this exact field name and value will be added to the encoded JSON.

mapObjectDecoding : (a -> b) -> ObjectMapping encodesFrom a -> ObjectMapping encodesFrom b

Transforms the type that an ObjectMapping decodes.

mapObjectEncoding : (b -> a) -> ObjectMapping a decodesTo -> ObjectMapping b decodesTo

Transforms the type that an ObjectMapping encodes.

customObject : (encodesFrom -> List ( String, Json.Encode.Value )) -> Json.Decode.Decoder decodesTo -> ObjectMapping encodesFrom decodesTo

If you have some data type for which the object and with API doesn't meet your needs, you can use customObject to create an ObjectMapping for any type that you can write an encoder and decoder for.

Using ObjectMappings

Normally you will just pass your ObjectMapping to DesktopApp.program, but the following functions are available if you want to manually make use of an ObjectMapping for other purposes.

encodeString : ObjectMapping encodesFrom decodesTo -> encodesFrom -> String

Encodes a given encodesFrom value with the given ObjectMapping (into a JSON string).

encodeValue : ObjectMapping encodesFrom decodesTo -> encodesFrom -> Json.Encode.Value

Encodes a given encodesFrom value with the given ObjectMapping (into a Json.Encode.Value).

decoder : ObjectMapping encodesFrom decodesTo -> Json.Decode.Decoder decodesTo

Gets the Json.Decode.Decoder for the given ObjectMapping.

Mapping Elm values to JSON


type JsonMapping a

Represents how to encode a to and from JSON.

int : JsonMapping Basics.Int

Maps an Elm Int to and from JSON.

string : JsonMapping String

Maps an Elm String to and from JSON.

bool : JsonMapping Basics.Bool

Maps an Elm Bool to and from JSON.

maybe : JsonMapping a -> JsonMapping (Maybe a)

Maps an Elm Maybe to and from JSON. Nothing will map to null, and Just a will use the given mapping for a.

import DesktopApp.JsonMapping exposing (maybe, int, encode, decoder)
import Json.Decode exposing (decodeString)

encode (maybe int) (Just 7)  --> "7"
encode (maybe int) Nothing  --> "null"

decodeString (decoder (maybe string)) "\"hi\""  --> Just "hi"
decodeString (decoder (maybe string)) "null"  --> Nothing

list : JsonMapping a -> JsonMapping (List a)

Maps an Elm List to and from a JSON array.

custom : (a -> Json.Encode.Value) -> Json.Decode.Decoder a -> JsonMapping a

Creates a JsonMapping that uses the given Elm JSON encoder and decoder

fromObjectMapping : ObjectMapping a a -> JsonMapping a

Creates a JsonMapping from an ObjectMapping.

This allows you to create JsonMappings that can then be used as nested fields within other ObjectMappings.

import DesktopApp.JsonMapping exposing (fromObjectMapping, int, object, string, with)

type alias MyData =
    { name : String
    , admin : Bool
    }

myDataMapping : JsonMapping MyData
myDataMapping =
    object MyData
        |> with "name" .name string
        |> with "admin" .admin bool
        |> fromObjectMapping

map : (a -> b) -> (b -> a) -> JsonMapping a -> JsonMapping b

Transforms a JsonMapping. This requires functions for transforming in each direction so that both encoding and decoding can be handled.

customType : List (VariantDecoder a) -> (a -> VariantEncoder) -> ObjectMapping a a

Maps an Elm custom type (sometimes also called a "union type", "tagged union", or "ADT") to and from a JSON object.

VariantDecoders and VariantEncoders are created using the variant* functions (see the example below).

This function returns an ObjectMapping instead of a JsonMapping so that it is possible to have a custom type as the top-level of your persisted data when using DesktopApp.program. If you need a JsonMapping, you can use this with fromObjectMapping (as shown in the example).

As this example shows, creating a mapping for your custom type requires the following:

Example:

import DesktopApp.JsonMapping exposing (JsonMapping, bool, customType, fromObjectMapping, int, string, variant0, variant1, variant2)

type MyType
    = NotAuthorized
    | Guest Bool String
    | Employee Int

myTypeMapping : JsonMapping MyType
myTypeMapping =
    let
        notAuthorized =
            variant0
            "NotAuthorized"
            NotAuthorized

        guest =
            variant2
                "Guest"
                Guest
                ( "is_vip", bool )
                ( "name", string )

        employee =
            variant1
                "Employee"
                Employee
                ( "employee_id", int )
      in
      customType
          [ notAuthorized.decode
          , guest.decode
          , employeed.decode
          ]
          (\x ->
              case x of
                  NotAuthorized ->
                      notAuthorized.encode

                  Guest isVip name ->
                      guest.encode isVip name

                  Employee id ->
                      employeed.encode id
          )
          |> fromObjectMapping

encodeString myTypeMapping NotAuthorized
    --> """{"$":"NotAuthorized"}"""
encodeString myTypeMapping (Guest True "Kai")
    --> """{"$":"Guest","is\_vip":true,"name":"Kai"}"""
encodeString myTypeMapping (Employee 24601)
    --> """{"$":"Employee","employee\_id":24601}"""


type alias Variant decodesTo encoder =
{ decode : VariantDecoder decodesTo
, encode : encoder 
}

Represents how to map an Elm custom type variant (sometimes also called a "tag", "contructor", or "enum value") to and from a JSON object. This is different from a JsonMapping because it carries with it information about the name of the variant and does some tricks with the type system to make the customType API as nice as possible.

Normally you will not need to reference this type directly. See the example for customType.


type VariantEncoder

Represents how to encode an Elm custom type variant to a JSON object.

Normally you will not need to reference this type directly. See the example for customType.


type VariantDecoder decodesTo

Represents how to decode an Elm custom type variant from a JSON object.

Normally you will not need to reference this type directly. See the example for customType.

variant0 : String -> decodesTo -> Variant decodesTo VariantEncoder

Creates a VariantEncoder and VariantDecoder for an Elm custom type variant that takes no parameters.

See customType for an example of how to use the variant* functions.

variant1 : String -> (a -> decodesTo) -> ( String, JsonMapping a ) -> Variant decodesTo (a -> VariantEncoder)

Creates a VariantEncoder and VariantDecoder for an Elm custom type variant that takes one parameter.

See customType for an example of how to use the variant* functions.

variant2 : String -> (a -> b -> decodesTo) -> ( String, JsonMapping a ) -> ( String, JsonMapping b ) -> Variant decodesTo (a -> b -> VariantEncoder)

Creates a VariantEncoder and VariantDecoder for an Elm custom type variant that takes two parameters.

See customType for an example of how to use the variant* functions.

variant3 : String -> (a -> b -> c -> decodesTo) -> ( String, JsonMapping a ) -> ( String, JsonMapping b ) -> ( String, JsonMapping c ) -> Variant decodesTo (a -> b -> c -> VariantEncoder)

Creates a VariantEncoder and VariantDecoder for an Elm custom type variant that takes three parameters.

See customType for an example of how to use the variant* functions.

variant4 : String -> (a -> b -> c -> d -> decodesTo) -> ( String, JsonMapping a ) -> ( String, JsonMapping b ) -> ( String, JsonMapping c ) -> ( String, JsonMapping d ) -> Variant decodesTo (a -> b -> c -> d -> VariantEncoder)

Creates a VariantEncoder and VariantDecoder for an Elm custom type variant that takes four parameters.

See customType for an example of how to use the variant* functions.

variant5 : String -> (a -> b -> c -> d -> e -> decodesTo) -> ( String, JsonMapping a ) -> ( String, JsonMapping b ) -> ( String, JsonMapping c ) -> ( String, JsonMapping d ) -> ( String, JsonMapping e ) -> Variant decodesTo (a -> b -> c -> d -> e -> VariantEncoder)

Creates a VariantEncoder and VariantDecoder for an Elm custom type variant that takes five parameters.

See customType for an example of how to use the variant* functions.