Created
April 5, 2016 15:13
-
-
Save mjul/4bff61662ed2e60b89cd1533c9fcaba6 to your computer and use it in GitHub Desktop.
F# Chiron JSON serialization experiments
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#I "./packages" | |
#r "FParsec/lib/net40-client/FParsec.dll" | |
#r "FParsec/lib/net40-client/FParsecCS.dll" | |
#r "Aether/lib/net35/Aether.dll" | |
#r "Chiron/lib/net40/Chiron.dll" | |
#r "System.Runtime.Serialization" | |
open Chiron | |
// Serialization works well with static members | |
// as the default serializer uses the ToJson and FromJson | |
// member functions | |
// | |
// This is from the article by Marcus Griep: | |
// Chiron Compuation Expressions | |
// https://neoeinstein.github.io//blog/2016/04-02-chiron-computation-expressions/index.html | |
type User = | |
{ Name: string; IsAdmin: bool } | |
static member ToJson (x:User) = | |
json { | |
do! Json.write "name" x.Name | |
do! Json.write "isAdmin" x.IsAdmin | |
} | |
static member FromJson (_:User) = | |
json { | |
let! n = Json.read "name" | |
let! a = Json.read "isAdmin" | |
return {Name=n; IsAdmin=a} | |
} | |
Json.serialize {Name="Martin";IsAdmin=true} | |
|> Json.formatWith Chiron.Formatting.JsonFormattingOptions.Pretty | |
|> printfn "%s" | |
// | |
// Let's turn op the volume | |
// | |
// Define the internal data model: investment funds in categories | |
// Note that the model does not know about JSON formats | |
type Category = {Id: int; Name: string} | |
type InvestmentFund = { Id: int; Name: string; AnnualCostInPercent:decimal; Isin: string; Category: Category} | |
// Some test data | |
let loadAllProducts () = | |
let danishStocks = {Category.Id=1; Name="Danish Stocks"} | |
let globalStocks = {Category.Id=2; Name="Global Stocks"} | |
let categories = [danishStocks; globalStocks] | |
let products = | |
[ | |
{Id=1; Name="Golddigger Danish"; AnnualCostInPercent=1.25m; Isin="DK11111111"; Category=danishStocks} | |
{Id=2; Name="Starmanager Danish"; AnnualCostInPercent=1.75m; Isin="DK22222222"; Category=danishStocks} | |
{Id=3; Name="Thrifty Danish"; AnnualCostInPercent=0.55m; Isin="DK33333333"; Category=globalStocks} | |
{Id=4; Name="Golden Globals"; AnnualCostInPercent=2.25m; Isin="DK44444444"; Category=globalStocks} | |
{Id=5; Name="Thrifty Globals"; AnnualCostInPercent=0.55m; Isin="DK55555555"; Category=globalStocks} | |
] | |
(categories, products) | |
// We can use the "json" computation expression | |
// to handle serialization and deserialization | |
// | |
// This way, the serialization is not conflated into the data type | |
// | |
// The trick is to use the serializeWith and readWith functions | |
// and provide the serializers directly | |
let serializeCategory (x:Category) = | |
json { | |
do! Json.write "_type" "Category" | |
do! Json.write "id" x.Id | |
do! Json.write "name" x.Name | |
} | |
let deserializeCategory = | |
json { | |
let! (t:string) = Json.read "_type" | |
let! id = Json.read "id" | |
let! name = Json.read "name" | |
return {Category.Id = id; Name=name} | |
} | |
let someCategory = loadAllProducts () |> fst |> Seq.head | |
// Try serializing with the non-member functions | |
let serialized = | |
someCategory | |
|> Json.serializeWith serializeCategory | |
|> Json.formatWith JsonFormattingOptions.Pretty | |
// That was easy | |
// Unfortunately deserialization is not as easy as since there | |
// Json.deserialize requires a member function on the type for | |
// deserialization. It does not offer a Json.deserializeWith | |
// either. | |
// | |
// Anyway, we can deserialize it like this | |
// (this is a bit clumsy - I wonder if there is a better way) | |
// | |
let dc = serialized |> Json.parse |> deserializeCategory | |
let deserialized = | |
(dc) |> function | |
| Value (c:Category), _ -> Some c | |
| Error e, _ -> None | |
printfn "Serialized:%s%s" System.Environment.NewLine serialized | |
printfn "Deserialized:%s%A" System.Environment.NewLine deserialized |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment