繁体   English   中英

如何在 elm 0.19 中将 Json.Decode.Value 解码为标记联合类型?

[英]How to a decode Json.Decode.Value into tagged union type in elm 0.19?

我懂了

我不相信第一个与 elm 0.19 相关。 我在NoRedInk/elm-json-decode-pipeline 中找不到decode函数,我不相信:=缀运算符仍然有效。

第二个解决了根据 JSON 字段的值进行条件解码的稍微不同的问题。

如果我有数据通过端口和以下类型:

导入 Json.Decode 暴露 (Decoder, map, oneOf, string, success, andThen, map2, map4)

import Json.Decode exposing (Decoder, andThen, map, map2, map4, oneOf, string, succeed, field)


port loginResponse : (Value -> msg) -> Sub msg


type Status
    = Authenticated Data
    | Unauthenticated (Maybe Error)


type alias Data =
    { accessToken : String
    , email : String
    , name : String
    , nickname : String
    }


dataDecoder : Decoder Data
dataDecoder =
    map4 Data
        (field "accessToken" string)
        (field "email" string)
        (field "name" string)
        (field "nickname" string)


type alias Error =
    { error : String
    , errorDescription : String
    }


errorDecoder : Decoder Error
errorDecoder =
    map2 Error
        (field "error" string)
        (field "errorDescription" string)

如何为标记联合类型Status编写解码器以解码从端口返回的数据?

到目前为止我得到的最好的是

statusDecoder : Decoder Status
statusDecoder =
    oneOf
        [ dataDecoder andThen (\data -> succeed (Authenticated data)
        , errorDecoder andThen (\error -> succeed (Unauthenticated (Just error)))
        ]

这是无效的,或

getStatus : Json.Decode.Value -> Status
getStatus value =
    let
        decodedData =
            decodeValue dataDecoder value
    in
    case decodedData of
        Ok data ->
            Authenticated data

        Err _ ->
            let
                decodedError =
                    decodeValue errorDecoder value
            in
            case decodedError of
                Ok error ->
                    Unauthenticated (Just error)

                Err err ->
                    Unauthenticated (Just { error = "There was a problem decoding the JSON", errorDescription = "" })

这真的很丑,感觉不对。

你已经完成了所有的艰苦工作。 这应该就是你现在所需要的。 注意.map是执行 case 语句的快捷方式。

import Json.Decode as Decode exposing (Decoder)
statusDecoder =
    Decode.oneOf
        [ Decode.map Authenticated dataDecoder
        , Decode.map Unauthenticated <| Decode.maybe errorDecoder
        ]

我采用的解决方案是使用Json.Decode.map使用Status类型构造函数Authenticated dataUnauthenticated Maybe errorDecoder DataDecoder Error类型转换为Decoder Status类型。

然后我可以使用Json.Decode.oneOf函数根据数据的形状解码成一个或另一个,因为两个解码器现在都是相同类型的Decoder Status

dataDecoder : Decoder Status
dataDecoder =
    map Authenticated <|
        map4 Data
            (field "accessToken" string)
            (field "email" string)
            (field "name" string)
            (field "nickname" string)


errorDecoder : Decoder Status
errorDecoder =
    map Unauthenticated <|
        maybe <|
            map2 Error
                (field "error" string)
                (field "errorDescription" string)


statusDecoder : Decoder Status
statusDecoder =
    oneOf [ dataDecoder, errorDecoder ]

为简洁起见,您可以使用Json.Decode.decodeValue函数和上面定义的statusDecoder函数来解码从更新函数中的端口出来的Json.Decode.Value

-- UPDATE

update : Msg -> Model -> ( Model, Cmd Msg )
update msg model =
    case msg of
        ReceiveLoginResponse response ->
            let
                decodedResponse = decodeValue Auth.statusDecoder response
            in
            case decodedResponse of
                Ok status ->
                    ( { model
                        | authStatus = status 
                      }
                      , Cmd.none
                    )
         ...

-- SUBSCRIPTIONS


subscriptions : Model -> Sub Msg
subscriptions model =
    Sub.batch
        [ loginResponse ReceiveLoginResponse
        ]

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM