This is an alternative site for discovering Elm packages. You may be looking for the official Elm package site instead.
README

Json.Decode.Extra

Convenience functions for working with Json

Date

date : Decoder Date.Date

Extract a date.

Note that this function is not total, it will throw an exception given an incorrectly formatted date. See Date.fromString and Json.customDecoder.

Incremental Decoding

apply : Decoder (a -> b) -> Decoder a -> Decoder b

Can be helpful when decoding large objects incrementally.

import Date (Date)

type alias User =
  { id                : Int
  , createdAt         : Date
  , updatedAt         : Date
  , deletedAt         : Maybe Date
  , username          : Maybe String
  , email             : Maybe String
  , fullname          : Maybe String
  , avatar            : Maybe String
  , isModerator       : Bool
  , isOrganization    : Bool
  , isAdmin           : Bool
  }

metaDecoder : (Int -> Date -> Date -> Maybe Date -> b) -> Decoder b
metaDecoder f = f
  `map`      ("id"        := int)
  `apply` ("createdAt" := date)
  `apply` ("updatedAt" := date)
  `apply` ("deletedAt" := maybe date)

userDecoder : Decoder User
userDecoder = metaDecoder User
  `apply` ("username"          := maybe string)
  `apply` ("email"             := maybe string)
  `apply` ("fullname"          := maybe string)
  `apply` ("avatar"            := maybe string)
  `apply` ("isModerator"       := bool)
  `apply` ("isOrganization"    := bool)
  `apply` ("isAdmin"           := bool)

This is a shortened form of

metaDecoder : (Int -> Date -> Date -> Maybe Date -> b) -> Decoder b
metaDecoder f = f
  `map`      ("id"        := int)
  `andThen` \f -> f `map` ("createdAt" := date)
  `andThen` \f -> f `map` ("updatedAt" := date)
  `andThen` \f -> f `map` ("deletedAt" := maybe date)

userDecoder : Decoder User
userDecoder = metaDecoder User
  `andThen` \f -> f `map` ("username"          := maybe string)
  `andThen` \f -> f `map` ("email"             := maybe string)
  `andThen` \f -> f `map` ("fullname"          := maybe string)
  `andThen` \f -> f `map` ("avatar"            := maybe string)
  `andThen` \f -> f `map` ("isModerator"       := bool)
  `andThen` \f -> f `map` ("isOrganization"    := bool)
  `andThen` \f -> f `map` ("isAdmin"           := bool)

Set

set : Decoder comparable -> Decoder (Set comparable)

Extract a set.

Dict

dict2 : Decoder comparable -> Decoder v -> Decoder (Dict comparable v)

Extract a dict using separate decoders for keys and values.

Maybe

withDefault : a -> Decoder a -> Decoder a

Try running the given decoder; if that fails, then succeed with the given fallback value.

-- If this field is missing or malformed, it will decode to [].
("optionalNames" := list string)
  |> (withDefault [])
maybeNull : Decoder a -> Decoder (Maybe a)

Extract a value that might be null. If the value is null, succeed with Nothing. If the value is present but not null, succeed with Just that value. If the value is missing, fail.

-- Yields Nothing if middleName is null, and Just middleName if it's a string.
"middleName" := maybeNull string

Recursively Defined Decoders

lazy : (() -> Decoder a) -> Decoder a

Enable decoders defined in terms of themselves by lazily creating them.

treeNode =
  object2
    instantiateTreeNode
    ("name" := string)
    ("children" := list (lazy (\_ -> treeNode)))
module Json.Decode.Extra (date, apply, (|:), set, dict2, withDefault, maybeNull, lazy) where
{-| Convenience functions for working with Json

# Date
@docs date

# Incremental Decoding
@docs apply, (|:)

# Set
@docs set

# Dict
@docs dict2

# Maybe
@docs withDefault, maybeNull

# Recursively Defined Decoders
@docs lazy

-}

import Json.Decode exposing (..)
import Date
import Time
import Dict exposing (Dict)
import Set exposing (Set)

{-| Can be helpful when decoding large objects incrementally.

    import Date (Date)

    type alias User =
      { id                : Int
      , createdAt         : Date
      , updatedAt         : Date
      , deletedAt         : Maybe Date
      , username          : Maybe String
      , email             : Maybe String
      , fullname          : Maybe String
      , avatar            : Maybe String
      , isModerator       : Bool
      , isOrganization    : Bool
      , isAdmin           : Bool
      }

    metaDecoder : (Int -> Date -> Date -> Maybe Date -> b) -> Decoder b
    metaDecoder f = f
      `map`      ("id"        := int)
      `apply` ("createdAt" := date)
      `apply` ("updatedAt" := date)
      `apply` ("deletedAt" := maybe date)

    userDecoder : Decoder User
    userDecoder = metaDecoder User
      `apply` ("username"          := maybe string)
      `apply` ("email"             := maybe string)
      `apply` ("fullname"          := maybe string)
      `apply` ("avatar"            := maybe string)
      `apply` ("isModerator"       := bool)
      `apply` ("isOrganization"    := bool)
      `apply` ("isAdmin"           := bool)

This is a shortened form of

    metaDecoder : (Int -> Date -> Date -> Maybe Date -> b) -> Decoder b
    metaDecoder f = f
      `map`      ("id"        := int)
      `andThen` \f -> f `map` ("createdAt" := date)
      `andThen` \f -> f `map` ("updatedAt" := date)
      `andThen` \f -> f `map` ("deletedAt" := maybe date)

    userDecoder : Decoder User
    userDecoder = metaDecoder User
      `andThen` \f -> f `map` ("username"          := maybe string)
      `andThen` \f -> f `map` ("email"             := maybe string)
      `andThen` \f -> f `map` ("fullname"          := maybe string)
      `andThen` \f -> f `map` ("avatar"            := maybe string)
      `andThen` \f -> f `map` ("isModerator"       := bool)
      `andThen` \f -> f `map` ("isOrganization"    := bool)
      `andThen` \f -> f `map` ("isAdmin"           := bool)

-}
apply : Decoder (a -> b) -> Decoder a -> Decoder b
apply f aDecoder =
  f `andThen` (\f' -> f' `map` aDecoder)


{-| Infix version of `apply` that makes for a nice DSL when decoding objects:

    locationDecoder : Decoder Location
    locationDecoder =
        succeed Location
            |: ("id" := int)
            |: ("name" := string)
            |: ("address" := string)
            |: ("city" := string)
            |: ("state" := string)


    type alias Location =
        { id : Int
        , name : String
        , address : String
        , city : String
        , state : String
        }

-}
(|:) : Decoder (a -> b) -> Decoder a -> Decoder b
(|:) =
  apply

{-| Extract a date.

Note that this function is not total, it will throw an exception given an incorrectly formatted date.
See `Date.fromString` and `Json.customDecoder`.

-}
date : Decoder Date.Date
date = customDecoder string Date.fromString

-- {-| Extract a time value.
--
-- Note that this function is not total, it will throw an exception given an incorrectly formatted time value.
-- See `Time.fromString` and `Json.customDecoder`.
--
-- -}
-- time : Decoder Time.Time
-- time = customDecoder string (Date.fromString >> Date.toTime)


{-| Extract a set. -}
set : Decoder comparable -> Decoder (Set comparable)
set decoder =
    (list decoder)
        `andThen`
            (Set.fromList >> succeed)


{-| Extract a dict using separate decoders for keys and values. -}
dict2 : Decoder comparable -> Decoder v -> Decoder (Dict comparable v)
dict2 keyDecoder valueDecoder =
    (dict valueDecoder) `andThen`
        (Dict.toList >> (decodeDictFromTuples keyDecoder))


{- Helper function for dict -}
decodeDictFromTuples :
    Decoder comparable ->
    List (String, v) ->
    Decoder (Dict comparable v)
decodeDictFromTuples keyDecoder tuples =
    case tuples of
        [] ->
            succeed Dict.empty

        (strKey, value)::rest ->
            case decodeString keyDecoder strKey of
                Ok key ->
                    (decodeDictFromTuples keyDecoder rest) `andThen`
                        ((Dict.insert key value) >> succeed)

                Err error ->
                    fail error


{-| Try running the given decoder; if that fails, then succeed with the given
fallback value.

    -- If this field is missing or malformed, it will decode to [].
    ("optionalNames" := list string)
      |> (withDefault [])

-}
withDefault : a -> Decoder a -> Decoder a
withDefault fallback decoder =
    maybe decoder
        `andThen`
            ((Maybe.withDefault fallback) >> succeed)


{-| Extract a value that might be null. If the value is null,
succeed with Nothing. If the value is present but not null, succeed with
Just that value. If the value is missing, fail.

    -- Yields Nothing if middleName is null, and Just middleName if it's a string.
    "middleName" := maybeNull string

-}
maybeNull : Decoder a -> Decoder (Maybe a)
maybeNull decoder =
    oneOf [null Nothing, map Just decoder]


{-| Enable decoders defined in terms of themselves by lazily creating them.

    treeNode =
      object2
        instantiateTreeNode
        ("name" := string)
        ("children" := list (lazy (\_ -> treeNode)))

-}
lazy : (() -> Decoder a) -> Decoder a
lazy getDecoder =
    customDecoder value <|
       \rawValue ->
            decodeValue (getDecoder ()) rawValue