如何编写一个 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))
我发现很难将旧模型状态迁移到新模型状态。
假设最初我们的代码有模型,我们将它保存到本地存储。
现在我们想添加一个额外的字段,"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))