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

Graphqelm.Field

Fields are automatically generated by the graphqelm CLI command. You can use Graphqelm.Field.map to transform a value.

Safe Transformations

map : (decodesTo -> mapsTo) -> Field decodesTo typeLock -> Field mapsTo typeLock

Maps the data coming back from the GraphQL endpoint. In this example, User.name is a function that the graphqelm CLI tool created which tells us that the name field on a User object is a String according to your GraphQL schema.

import Api.Object
import Api.Object.User as User
import Graphqelm.Field as Field
import Graphqelm.SelectionSet exposing (SelectionSet, with)

human : SelectionSet String Api.Object.User
human =
    User.selection identity
        |> with
            (User.name
                |> Field.map String.toUpper
            )

You can also map to values of a different type (String -> Int, for example), see examples/StarWars.elm for more advanced example.

Result (...OrFail) Transformations

Warning When you use these functions, you lose the guarantee that the server response will decode successfully.

These helpers, though convenient, will cause your entire decoder to fail if it ever maps to an Err instead of an Ok Result.

mapOrFail : (decodesTo -> Result String mapsTo) -> Field decodesTo typeLock -> Field mapsTo typeLock

If the map function provided returns an Ok Result, it will map to that value. If it returns an Err, the entire response will fail to decode.

import Date exposing (Date)
import Github.Object
import Github.Object.Repository
import Github.Scalar
import Graphqelm.Field as Field exposing (Field)

createdAt : Field Date Github.Object.Repository
createdAt =
    Github.Object.Repository.createdAt
        |> Field.mapOrFail
            (\(Github.Scalar.DateTime dateTime) ->
                Date.fromString dateTime
            )
nonNullOrFail : Field (Maybe decodesTo) typeLock -> Field decodesTo typeLock

Effectively turns an attribute that is String => String!, or User => User! (if you're not familiar with the GraphQL type language notation, learn more here).

This will cause your entire decoder to fail if the field comes back as null. It's far better to fix your schema then to use this escape hatch!

nonNullElementsOrFail : Field (List (Maybe decodesTo)) typeLock -> Field (List decodesTo) typeLock

Effectively turns a field that is [String] => [String!], or [User] => [User!] (if you're not familiar with the GraphQL type language notation, learn more here).

This will cause your entire decoder to fail if any elements in the list for this field comes back as null. It's far better to fix your schema then to use this escape hatch!

Often GraphQL schemas will contain things like [String] (i.e. a nullable list of nullable strings) when they really mean [String!]! (a non-nullable list of non-nullable strings). You can chain together these nullable helpers if for some reason you can't go in and fix this in the schema, for example:

releases : SelectionSet (List Release) Github.Object.ReleaseConnection
releases =
    Github.Object.ReleaseConnection.selection identity
        |> with
            (Github.Object.ReleaseConnection.nodes release
                |> Field.nonNullOrFail
                |> Field.nonNullElementsOrFail
            )

Without the Field.nonNull... transformations here, the type would be SelectionSet (Maybe (List (Maybe Release))) Github.Object.ReleaseConnection.

Types

type Field decodesTo typeLock = Field RawField (Decoder decodesTo)
module Graphqelm.Field exposing (Field(Field), map, mapOrFail, nonNullElementsOrFail, nonNullOrFail)

{-| `Field`s are automatically generated by the `graphqelm` CLI command.
You can use `Graphqelm.Field.map` to transform a value.


## Safe Transformations

@docs map


## Result (`...OrFail`) Transformations

**Warning** When you use these functions, you lose the guarantee that the
server response will decode successfully.

These helpers, though convenient, will cause your entire decoder to fail if
it ever maps to an `Err` instead of an `Ok` `Result`.

@docs mapOrFail, nonNullOrFail, nonNullElementsOrFail


## Types

@docs Field

-}

import Graphqelm.RawField as Field exposing (RawField)
import Json.Decode as Decode exposing (Decoder)


{-| -}
type Field decodesTo typeLock
    = Field RawField (Decoder decodesTo)


{-| Maps the data coming back from the GraphQL endpoint. In this example,
`User.name` is a function that the `graphqelm` CLI tool created which tells us
that the `name` field on a `User` object is a String according to your GraphQL
schema.

    import Api.Object
    import Api.Object.User as User
    import Graphqelm.Field as Field
    import Graphqelm.SelectionSet exposing (SelectionSet, with)

    human : SelectionSet String Api.Object.User
    human =
        User.selection identity
            |> with
                (User.name
                    |> Field.map String.toUpper
                )

You can also map to values of a different type (`String -> Int`, for example), see
[`examples/StarWars.elm`](https://github.com/dillonkearns/graphqelm/blob/master/examples/src/Starwars.elm) for more advanced example.

-}
map : (decodesTo -> mapsTo) -> Field decodesTo typeLock -> Field mapsTo typeLock
map mapFunction (Field field decoder) =
    Field field (Decode.map mapFunction decoder)


{-| If the map function provided returns an `Ok` `Result`, it will map to that value.
If it returns an `Err`, the _entire_ response will fail to decode.

    import Date exposing (Date)
    import Github.Object
    import Github.Object.Repository
    import Github.Scalar
    import Graphqelm.Field as Field exposing (Field)

    createdAt : Field Date Github.Object.Repository
    createdAt =
        Github.Object.Repository.createdAt
            |> Field.mapOrFail
                (\(Github.Scalar.DateTime dateTime) ->
                    Date.fromString dateTime
                )

-}
mapOrFail : (decodesTo -> Result String mapsTo) -> Field decodesTo typeLock -> Field mapsTo typeLock
mapOrFail mapFunction (Field field decoder) =
    decoder
        |> Decode.map mapFunction
        |> Decode.andThen
            (\result ->
                case result of
                    Ok value ->
                        Decode.succeed value

                    Err errorMessage ->
                        Decode.fail ("Check your code for calls to mapOrFail, your map function returned an `Err` with the message: " ++ errorMessage)
            )
        |> Field field


{-| Effectively turns an attribute that is `String` => `String!`, or `User` =>
`User!` (if you're not familiar with the GraphQL type language notation, learn more
[here](http://graphql.org/learn/schema/#type-language)).

This will cause your _entire_ decoder to fail if the field comes back as null.
It's far better to fix your schema then to use this escape hatch!

-}
nonNullOrFail : Field (Maybe decodesTo) typeLock -> Field decodesTo typeLock
nonNullOrFail (Field field decoder) =
    decoder
        |> Decode.andThen
            (\result ->
                case result of
                    Just value ->
                        Decode.succeed value

                    Nothing ->
                        Decode.fail "Expected non-null but got null, check for calls to nonNullOrFail in your code. Ideally your schema should indicate that this is non-nullable so you don't need to use nonNullOrFail at all."
            )
        |> Field field


{-| Effectively turns a field that is `[String]` => `[String!]`, or `[User]` =>
`[User!]` (if you're not familiar with the GraphQL type language notation, learn more
[here](http://graphql.org/learn/schema/#type-language)).

This will cause your _entire_ decoder to fail if any elements in the list for this
field comes back as null.
It's far better to fix your schema then to use this escape hatch!

Often GraphQL schemas will contain things like `[String]` (i.e. a nullable list
of nullable strings) when they really mean `[String!]!` (a non-nullable list of
non-nullable strings). You can chain together these nullable helpers if for some
reason you can't go in and fix this in the schema, for example:

    releases : SelectionSet (List Release) Github.Object.ReleaseConnection
    releases =
        Github.Object.ReleaseConnection.selection identity
            |> with
                (Github.Object.ReleaseConnection.nodes release
                    |> Field.nonNullOrFail
                    |> Field.nonNullElementsOrFail
                )

Without the `Field.nonNull...` transformations here, the type would be
`SelectionSet (Maybe (List (Maybe Release))) Github.Object.ReleaseConnection`.

-}
nonNullElementsOrFail : Field (List (Maybe decodesTo)) typeLock -> Field (List decodesTo) typeLock
nonNullElementsOrFail (Field field decoder) =
    decoder
        |> Decode.andThen
            (\result ->
                case combineMaybeList result of
                    Nothing ->
                        Decode.fail "Expected only non-null list elements but found a null. Check for calls to nonNullElementsOrFail in your code. Ideally your schema should indicate that this is non-nullable so you don't need to use nonNullElementsOrFail at all."

                    Just listWithoutNulls ->
                        Decode.succeed listWithoutNulls
            )
        |> Field field


combineMaybeList : List (Maybe a) -> Maybe (List a)
combineMaybeList listOfMaybes =
    let
        step maybeElement accumulator =
            case maybeElement of
                Nothing ->
                    Nothing

                Just element ->
                    Maybe.map ((::) element) accumulator
    in
    List.foldr step (Just []) listOfMaybes