let getInt = (obj: Js.Dict.t<Js.Json.t>, key: string) : int => {
switch obj -> Js.Dict.get(key) {
| Some(valueObj) =>
switch valueObj -> classify {
| JSONNumber(num) => num -> Belt.Int.fromFloat
| _ => raise(PARSE_FAILED(`${key} is not a number`))
}
| None => raise(PARSE_FAILED(`${key} not found`))
}
}
let getValue = (obj: Js.Dict.t<Js.Json.t>, key: string) : string => {
switch obj -> Js.Dict.get(key) {
| Some(valueObj) =>
switch valueObj -> classify {
| JSONString(value) => value
| JSONNull => ""
| _ => raise(PARSE_FAILED(`${key} is not a string`))
}
| None => raise(PARSE_FAILED(`${key} not found`))
}
}
These two pieces of code are almost identical but differ only in the pattern matching. Usually in such cases I pass a function as an argument which contains the “diff” of the logic into a function which contains common code.
But I cannot do that here because the different is the pattern matching logic which cannot be passed as a function.
let data = `{"abc": "def", "ghi": 10}`->Json.parseExn
let pointStruct = S.object(o => {
"x": o->S.field("abc", S.string()),
"y": o->S.field("ghi", S.float()),
})
let point = data->S.parseWith(pointStruct)->S.Result.getExn