Skip to content

Commit

Permalink
some merge stuff
Browse files Browse the repository at this point in the history
  • Loading branch information
AngelMunoz committed Nov 20, 2024
2 parents f8d777a + 2b15073 commit 2e62560
Show file tree
Hide file tree
Showing 4 changed files with 156 additions and 31 deletions.
126 changes: 126 additions & 0 deletions JDeck.Tests/AutoTests.fs
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
namespace JDeck.Tests

open System.Text.Json
open Microsoft.VisualStudio.TestTools.UnitTesting

open JDeck

type T1 = { name: string; age: int }

type TC =
| A of int
| B
| C of bool

type T2 = { t1: T1; tcustom: TC }

module ReadmeExamples =
type Person = {
Name: string
Age: int
Emails: string list
}

type ServerResponse = { Data: Person; Message: string }

[<TestClass>]
type AutoTests() =

[<TestMethod>]
member _.``JDeck can auto decode things``() =
match Decoding.auto """{ "name": "John Doe", "age": 30 }""" with
| Ok person ->
Assert.AreEqual("John Doe", person.name)
Assert.AreEqual(30, person.age)
| Error err -> Assert.Fail(err.message)


[<TestMethod>]
member _.``JDeck can auto decode types with nested decoders``() =
let tcDecoder tc =
Decode.oneOf
[
(Required.int >> Result.map A)
(Required.boolean >> Result.map C)
(Required.unit >> Result.map(fun _ -> B))
]
tc

let options = JsonSerializerOptions() |> Decode.useDecoder tcDecoder

match
Decoding.auto(
"""{ "t1": { "name": "John Doe", "age": 30 }, "tcustom": 10 }""",
options
)
with
| Ok t2 ->
Assert.AreEqual("John Doe", t2.t1.name)
Assert.AreEqual(30, t2.t1.age)

match t2.tcustom with
| A a -> Assert.AreEqual(10, a)
| _ -> Assert.Fail()

| Error err -> Assert.Fail(err.message)

[<TestMethod>]
member _.``JDeck readme example 1 works``() =

let json =
"""{"name": "Alice", "age": 30, "emails": ["alice@name.com", "alice@age.com"] }"""

let result: Result<ReadmeExamples.Person, DecodeError> =
Decoding.auto(
json,
JsonSerializerOptions(PropertyNameCaseInsensitive = true)
)

match result with
| Ok person ->

Assert.AreEqual("Alice", person.Name)
Assert.AreEqual(30, person.Age)
Assert.AreEqual(2, person.Emails.Length)
Assert.AreEqual("alice@name.com", person.Emails[0])
Assert.AreEqual("alice@age.com", person.Emails[1])
| Error err -> Assert.Fail(err.message)

[<TestMethod>]
member _.``JDeck readme example 2 works``() =

let personDecoder: Decoder<ReadmeExamples.Person> =
fun person -> decode {
let! name = person |> Required.Property.get("name", Optional.string)
and! age = person |> Required.Property.get("age", Required.int)

and! emails =
person |> Required.Property.list("emails", Optional.string)

return {
Name = name |> Option.defaultValue "<missing name>"
Age = age
// Remove any optional value from the list
Emails = emails |> List.choose id
}
}
// Inconclusive data coming from the server
let person =
"""{"name": null, "age": 30, "emails": ["alice@name.com", "alice@age.com", null] }"""

let result: Result<ReadmeExamples.ServerResponse, DecodeError> =
// ServerResponse will decode automatically while Person will use the custom decoder
Decoding.auto(
$$"""{ "data": {{person}}, "message": "Success" }""",
// Include your own decoder
JsonSerializerOptions(PropertyNameCaseInsensitive = true) |> Decode.useDecoder personDecoder
)

match result with
| Ok { Data = data; Message = message } ->
Assert.AreEqual("Success", message)
Assert.AreEqual(30, data.Age)
Assert.AreEqual(2, data.Emails.Length)
Assert.AreEqual("alice@name.com", data.Emails[0])
Assert.AreEqual("alice@age.com", data.Emails[1])
| Error err -> Assert.Fail(err.message)
1 change: 1 addition & 0 deletions JDeck.Tests/JDeck.Tests.fsproj
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
<Compile Include="RequiredTests.fs" />
<Compile Include="OptionalTests.fs" />
<Compile Include="DecodeTests.fs" />
<Compile Include="AutoTests.fs" />
<Compile Include="DecodeBuilderTests.fs" />
<Compile Include="EncodingAndSerializationTests.fs" />
<Compile Include="Program.fs" />
Expand Down
31 changes: 15 additions & 16 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# JDeck a System.Text.Json wrapper

JDeck is a [Thoth.Json]-like Json decoder based on `System.Text.Json` in a single file with no external
JDeck is a [Thoth.Json]-like Json decoder based on `System.Text.Json` in a single file with no external
dependencies. Plays well with other libraries that use `System.Text.Json` like [FSharp.SystemTextJson]

> **Note:** While JDeck has no dependencies to start working right away, it is recommended to
Expand All @@ -16,9 +16,9 @@ For most F# types, you can use the `Decode.auto` function to decode JSON as show
open JDeck
type Person = {
Name: string
Age: int
Emails: string list
name: string
age: int
emails: string list
}
let json = """{"name": "Alice", "age": 30, "emails": ["alice@name.com", "alice@age.com"] }"""
Expand All @@ -44,18 +44,17 @@ type Person = {
}
type ServerResponse = { Data: Person; Message: string }
module Person =
let Decoder person = decode {
let! name = person |> Required.Property.get("name", Optional.string)
and! age = person |> Required.Property.get("name", Required.int)
and! emails = person |> Required.Property.list("emails", Optional.string)
return {
Name = name |> Option.defaultValue "<missing name>"
Age = age
// Remove any optional value from the list
Emails = emails |> List.choose id
}
let personDecoder: Decoder<Person> = fun person -> decode {
let! name = person |> Required.Property.get("name", Optional.string)
and! age = person |> Required.Property.get("age", Required.int)
and! emails = person |> Required.Property.list("emails", Optional.string)
return {
Name = name |> Option.defaultValue "<missing name>"
Age = age
// Remove any optional value from the list
Emails = emails |> List.choose id
}
}
// Inconclusive data coming from the server
let person = """{"name": null, "age": 30, "emails": ["alice@name.com", "alice@age.com", null] }"""
Expand All @@ -64,7 +63,7 @@ let result: Result<ServerResponse, DecodeError> =
Decoding.auto(
$$"""{ "data": {{person}}, "message": "Success" }""",
// Include your own decoder
JsonSerializerOptions() |> Decode.useDecoder Person.Decoder
JsonSerializerOptions(PropertyNameCaseInsensitive = true) |> Decode.useDecoder personDecoder
)
match result with
Expand Down
29 changes: 14 additions & 15 deletions docs/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,9 @@ For most F# types, you can use the `Decode.auto` function to decode JSON as show
open JDeck
type Person = {
Name: string
Age: int
Emails: string list
name: string
age: int
emails: string list
}
let json = """{"name": "Alice", "age": 30, "emails": ["alice@name.com", "alice@age.com"] }"""
Expand All @@ -44,18 +44,17 @@ type Person = {
}
type ServerResponse = { Data: Person; Message: string }
module Person =
let Decoder person = decode {
let! name = person |> Required.Property.get("name", Optional.string)
and! age = person |> Required.Property.get("name", Required.int)
and! emails = person |> Required.Property.list("emails", Optional.string)
return {
Name = name |> Option.defaultValue "<missing name>"
Age = age
// Remove any optional value from the list
Emails = emails |> List.choose id
}
let personDecoder: Decoder<Person> = fun person -> decode {
let! name = person |> Required.Property.get("name", Optional.string)
and! age = person |> Required.Property.get("age", Required.int)
and! emails = person |> Required.Property.list("emails", Optional.string)
return {
Name = name |> Option.defaultValue "<missing name>"
Age = age
// Remove any optional value from the list
Emails = emails |> List.choose id
}
}
// Inconclusive data coming from the server
let person = """{"name": null, "age": 30, "emails": ["alice@name.com", "alice@age.com", null] }"""
Expand All @@ -64,7 +63,7 @@ let result: Result<ServerResponse, DecodeError> =
Decoding.auto(
$$"""{ "data": {{person}}, "message": "Success" }""",
// Include your own decoder
JsonSerializerOptions() |> Decode.useDecoder Person.Decoder
JsonSerializerOptions(PropertyNameCaseInsensitive = true) |> Decode.useDecoder personDecoder
)
match result with
Expand Down

0 comments on commit 2e62560

Please sign in to comment.