如何编写一个 Json 解码器,将 ModelV1 类型转换为 ModelV2 类型

How to write a Json decoder that converts from type ModelV1 to type ModelV2

我发现很难将旧模型状态迁移到新模型状态。

假设最初我们的代码有模型,我们将它保存到本地存储。

现在我们想添加一个额外的字段,"createdAt" 到我们的模型,所以我为它创建了一个新的类型别名。

import Json.Decode as D
import Html as H


type alias Todo = {id:Int, title: String}

jsonV1 = """

  {"id":1, "title":"Elm-Rocks"}

"""

jsonV2 = """

  {"id":1, "title":"Elm-Rocks", "createdAt":1479633701604}


"""


type alias TodoV2 = {id:Int, title: String, createdAt:Int}

decode = D.map2 Todo
  (D.field "id" D.int)
  (D.field "title" D.string)

decodeV2 = D.map3 TodoV2
  (D.field "id" D.int)
  (D.field "title" D.string)
  (D.field "createdAt" D.int)


result1 = D.decodeString decode jsonV1

result2 = D.decodeString decodeV2 jsonV2


type alias Model = {todos: List Todo}
type alias ModelV2 = {todos: List TodoV2}


main = H.div[] [ 
    H.div[][H.text (toString result1)]
  , H.div[][H.text (toString result2)]
  ]

如何编写一个 decoder/function,接受任何 v1/v2 格式 json 字符串并给我一个 ModelV2 记录。

我知道 Decoder.andThen 但我不知道如何为 todoDecoderV1: ??? -> TodoV2

编写实现

如果将新字段设为可选,则可以使用单个模型。

type alias Todo = {id:Int, title: String, createdAt: Maybe Int}

decode = D.map3 Todo
  (D.field "id" D.int)
  (D.field "title" D.string)
  D.maybe(D.field "createdAt" D.int)

您可以使用 Json.Decode.oneOf 来尝试解析器并使用 Json.Decode.succeed 提供默认回退。如果您想将 createdAt 的缺失表示为 0,您可以这样编写解码器:

decode = D.map3 TodoV2
  (D.field "id" D.int)
  (D.field "title" D.string)
  (D.oneOf [(D.field "createdAt" D.int), D.succeed 0])

但是,为了更准确地表示现实,我建议更改您的模型,以便通过将其类型更改为 Maybe Int,使 createdAt 成为可选的。这是 make impossible states impossible.

的好方法
type alias TodoV3 = {id:Int, title: String, createdAt:Maybe Int}

decodeV3 = D.map3 TodoV3
  (D.field "id" D.int)
  (D.field "title" D.string)
  (D.maybe (D.field "createdAt" D.int))