是否可以使用elm-decode-pipeline有条件地解码某些字段

时间:2017-01-04 13:50:39

标签: elm

我想解码一个API响应,其中一个字段值(category)将确定如何使用不同的子解码器解码另一个字段(configuration)。

我能够使用Json.Decode.mapn函数和andThen函数完成此类操作,但我想知道是否有任何方法可以使用elm-decode-pipeline进行此类操作,因为它具有更好的功能API和我最终会耗尽mapn个函数。

最小化且有些微不足道的例子是这样的:

type alias Machine =
    { name : String
    , specs : MachineSpecs
    }

type MachineSpecs
    = ElectricMachine ElectricSpecs
    | MechanicalMachine MechanicalSpecs
    | UnknownMachine

type alias ElectricSpecs =
    { voltage : Int
    }

type alias MechanicalSpecs =
    { gears : Int
    }

一些有效的JSON响应会有这些形状:

{
  "name": "Foo electric machine",
  "category": "electric",
  "configuration": {
    "voltage": 12
  }
}
{
  "name": "Bar mechanical machine",
  "category": "mechanical",
  "configuration": {
    "gears": 5
  }
}
{
  "name": "Some machine of unknown category",
  "category": "foo"
}

我尝试了与mapn函数使用的方法类似的方法,但它不起作用。

decoder : Decoder Machine
decoder =
    decode Machine
        |> required "name" string
        |> required "category" (string |> andThen catDec)


catDec : String -> Decoder MachineSpecs
catDec cat =
    case cat of
        "electric" ->
            map ElectricMachine electricDecoder

        "mechanical" ->
            map MechanicalMachine mechanicalDecoder

        _ ->
            succeed UnknownMachine


electricDecoder : Decoder ElectricSpecs
electricDecoder =
    decode ElectricSpecs
        |> requiredAt [ "configuration", "voltage" ] int


mechanicalDecoder : Decoder MechanicalSpecs
mechanicalDecoder =
    decode MechanicalSpecs
        |> requiredAt [ "configuration", "gears" ] int

事实上,我还没有在同时使用Json.Decode.PipelineandThen的网络或文档上看过任何示例,所以我不确定它是否会&#39甚至可能。

我已经设置了此问题的在线示例,说明了如何解码条件部分:https://runelm.io/c/3ut

2 个答案:

答案 0 :(得分:4)

作为替代方案,您可以将andThen绑定放在管道(ellie example)之前:

decoder : Decoder Machine
decoder =
    field "category" string
        |> andThen catDec
        |> andThen
            (\cat ->
                decode Machine
                    |> required "name" string
                    |> hardcoded cat
            )

如果您的mapN号码用完,请考虑在andMap包中切换到|:(或中缀版本elm-community/json-extra)。

答案 1 :(得分:4)

Chad Gilbert's answer正常工作(谢谢!)并引导我阅读Json.Decode.Pipeline源代码,以了解更多有关管道如何实施的信息,并且我找到了另一种解决方案有点简洁,所以我想在这里分享它:

decoder : Decoder Machine
decoder =
    decode Machine
        |> required "name" string
        |> custom (field "category" string |> andThen catDec)