diff --git a/src/Decode_AsResult_OfParseError.rei b/src/Decode_AsResult_OfParseError.rei index 11d501e..f080590 100644 --- a/src/Decode_AsResult_OfParseError.rei +++ b/src/Decode_AsResult_OfParseError.rei @@ -90,10 +90,26 @@ let literal: let literalString: (string, Js.Json.t) => result(string, ParseError.failure); let literalInt: (int, Js.Json.t) => result(int, ParseError.failure); let literalFloat: (float, Js.Json.t) => result(float, ParseError.failure); +let literalBool: (bool, Js.Json.t) => result(bool, ParseError.failure); +let literalTrue: Js.Json.t => result(bool, ParseError.failure); +let literalFalse: Js.Json.t => result(bool, ParseError.failure); + +let union: + ( + ('a, Js.Json.t) => result('a, ParseError.failure), + ('a, 'b), + list(('a, 'b)), + Js.Json.t + ) => + result('b, ParseError.failure); + let stringUnion: ((string, 'a), list((string, 'a)), Js.Json.t) => result('a, ParseError.failure); +let intUnion: + ((int, 'a), list((int, 'a)), Js.Json.t) => result('a, ParseError.failure); + [@deprecated "Use literal instead"] let variantFromJson: ( diff --git a/src/Decode_Base.re b/src/Decode_Base.re index dcfef7c..609fe9c 100644 --- a/src/Decode_Base.re +++ b/src/Decode_Base.re @@ -65,11 +65,21 @@ module Make = let literalFloat = literal((==), floatFromNumber); - let stringUnion = (first, rest) => { - let mkDecode = ((s, v)) => literalString(s) |> map(_ => v); + let literalBool = literal((==), boolean); + + let literalTrue = literalBool(true); + + let literalFalse = literalBool(false); + + let union = (decode, first, rest) => { + let mkDecode = ((s, v)) => decode(s) |> map(_ => v); first |> mkDecode |> oneOf(_, rest |> List.map(mkDecode)); }; + let stringUnion = first => union(literalString, first); + + let intUnion = first => union(literalInt, first); + let variantFromJson = (jsonToJs, jsToVariant) => jsonToJs |> map(jsToVariant) diff --git a/test/Decode_AsOption_test.re b/test/Decode_AsOption_test.re index f11e64a..c1a5ed5 100644 --- a/test/Decode_AsOption_test.re +++ b/test/Decode_AsOption_test.re @@ -8,7 +8,7 @@ module Sample = Decode_TestSampleData; describe("Simple decoders", () => { test("bool (success)", () => - expect(Decode.boolean(Sample.jsonBool)) + expect(Decode.boolean(Sample.jsonTrue)) |> toEqual(Some(Sample.valBool)) ); @@ -182,7 +182,7 @@ describe("Nested decoders", () => { ); test("optional float (fails on bool)", () => - expect(Decode.(optional(floatFromNumber, Sample.jsonBool))) + expect(Decode.(optional(floatFromNumber, Sample.jsonTrue))) |> toEqual(None) ); @@ -225,7 +225,7 @@ describe("Nested decoders", () => { ); test("tuple2 (fails on non-array)", () => - expect(Decode.(tuple(string, boolean, Sample.jsonBool))) + expect(Decode.(tuple(string, boolean, Sample.jsonTrue))) |> toEqual(None) ); @@ -429,7 +429,7 @@ describe("Decode with alternatives/fallbacks", () => { ); test("oneOf (succeeds on last)", () => - expect(decodeUnion(Sample.jsonBool)) + expect(decodeUnion(Sample.jsonTrue)) |> toEqual(Some(Sample.(B(valBool)))) ); diff --git a/test/Decode_AsResult_OfParseError_test.re b/test/Decode_AsResult_OfParseError_test.re index a35ac55..0893985 100644 --- a/test/Decode_AsResult_OfParseError_test.re +++ b/test/Decode_AsResult_OfParseError_test.re @@ -17,7 +17,7 @@ let objErrSingle = (field, err) => objErr((field, err), []); describe("Decode utils", () => { test("hush (success)", () => { let decodeBooleanOpt = Decode.(boolean |> hush); - expect(decodeBooleanOpt(Sample.jsonBool)) |> toEqual(Some(true)); + expect(decodeBooleanOpt(Sample.jsonTrue)) |> toEqual(Some(true)); }); test("hush (failure)", () => { @@ -27,6 +27,9 @@ describe("Decode utils", () => { }); describe("Simple decoders", () => { + let decodeIntColor = + Decode.intUnion((0, `blue), [(1, `red), (2, `green)]); + test("boolean", () => expect(Decode.boolean(Sample.jsonNull)) |> toEqual(valErr(`ExpectedBoolean, Sample.jsonNull)) @@ -78,6 +81,48 @@ describe("Simple decoders", () => { ) ); + test("literalTrue (success)", () => + expect(Decode.literalTrue(Sample.jsonTrue)) |> toEqual(Result.ok(true)) + ); + + test("literalTrue (failure)", () => + expect(Decode.literalTrue(Sample.jsonFalse)) + |> toEqual(valErr(`ExpectedValidOption, Sample.jsonFalse)) + ); + + test("literalFalse (success)", () => + expect(Decode.literalFalse(Sample.jsonFalse)) + |> toEqual(Result.ok(false)) + ); + + test("literalFalse (failure)", () => + expect(Decode.literalFalse(Sample.jsonTrue)) + |> toEqual(valErr(`ExpectedValidOption, Sample.jsonTrue)) + ); + + test("intUnion (success)", () => + expect(decodeIntColor(Sample.jsonIntZero)) |> toEqual(Result.ok(`blue)) + ); + + test("intUnion (failure)", () => + expect(decodeIntColor(Sample.jsonIntFive)) + |> toEqual( + Result.error( + Decode.ParseError.( + TriedMultiple( + NonEmpty.List.make( + Val(`ExpectedValidOption, Sample.jsonIntFive), + [ + Val(`ExpectedValidOption, Sample.jsonIntFive), + Val(`ExpectedValidOption, Sample.jsonIntFive), + ], + ), + ) + ), + ), + ) + ); + test("variant", () => [@ocaml.warning "-3"] expect(Decode.variantFromString(Sample.colorFromJs, Sample.jsonString)) @@ -181,7 +226,7 @@ describe("Inner decoders", () => { ); test("oneOf (success on last)", () => - expect(decodeUnion(Sample.jsonBool)) + expect(decodeUnion(Sample.jsonTrue)) |> toEqual(Result.ok(Sample.B(Sample.valBool))) ); diff --git a/test/Decode_AsResult_OfStringNel_test.re b/test/Decode_AsResult_OfStringNel_test.re index b88d5db..938ebed 100644 --- a/test/Decode_AsResult_OfStringNel_test.re +++ b/test/Decode_AsResult_OfStringNel_test.re @@ -127,7 +127,7 @@ describe("Inner decoders", () => { ) ); - expect(decodeUnion(Sample.jsonBool)) + expect(decodeUnion(Sample.jsonTrue)) |> toEqual(Result.ok(Sample.(B(valBool)))); }); }); diff --git a/test/utils/Decode_TestSampleData.re b/test/utils/Decode_TestSampleData.re index d9881cc..1618fe4 100644 --- a/test/utils/Decode_TestSampleData.re +++ b/test/utils/Decode_TestSampleData.re @@ -1,6 +1,7 @@ // Simple JSON values let jsonNull: Js.Json.t = [%raw {| null |}]; -let jsonBool: Js.Json.t = [%raw {| true |}]; +let jsonTrue: Js.Json.t = [%raw {| true |}]; +let jsonFalse: Js.Json.t = [%raw {| false |}]; let jsonString: Js.Json.t = [%raw {| "string" |}]; let jsonStringTrue: Js.Json.t = [%raw {| "true" |}]; let jsonString4: Js.Json.t = [%raw {| "4" |}];