Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Write/Read nested objects #39

Open
haf opened this issue Jul 30, 2015 · 10 comments
Open

Write/Read nested objects #39

haf opened this issue Jul 30, 2015 · 10 comments

Comments

@haf
Copy link
Contributor

haf commented Jul 30, 2015

I often have a tuple in F# 3-5 items long, but want to serialise it as an object;
then I need to do lots of shenanigans.

With these I don't:

module Json =
    let writeNested key (toJson : _ -> Json<unit>) value : Json<unit> =
      fun json ->
        let inner = snd (toJson value json)
        Json.write key inner json
module Patterns =
  let inline (|InProperty|_|) key (fromJson : 'a -> Json<'a>) =
        Aether.Lens.getPartial (Json.ObjectPLens >??> Aether.mapPLens key)
     >> Option.bind (fromJson (Unchecked.defaultof<_>)
                     >> fst
                     >> function | Value x -> Some x
                                 | Error _ -> None)

Means I can have this usage:

type Interact =
  | Create of owner:Owner * createdByPrincipal:Id * bbf:Money
  | TopUp of amount:Money
  | Charge of amount:Money

  static member ToJson (i : Interact) : Json<unit> =
    let writeInner (owner, createdBy, bbf) : Json<unit> =
      Json.write "owner" owner
      *> Json.write "createdByPrincipal" createdBy
      *> Json.write "bbf" bbf

    match i with
    | Create (o, cb, bbf) -> Json.writeNested "create" writeInner (o, cb, bbf)
    | TopUp amount -> Json.write "topUp" amount
    | Charge amount -> Json.write "charge" amount

  static member FromJson (_ : Interact) : Json<Interact> =
    let inline readInner _ : Json<_ * _ * _> =
      (fun o cb bbf -> o, cb, bbf)
      <!> Json.read "owner"
      <*> Json.read "createdByPrincipal"
      <*> Json.read "bbf"

    function
    | InProperty "create" readInner (o, cb, bbf) as json ->
      Json.init (Create (o, cb, bbf)) json
    | Property "topUp" amount as json ->
      Json.init (TopUp amount) json
    | Property "charge" amount as json ->
      Json.init (Charge amount) json
    | json ->
      Json.error (sprintf "couldn't convert %A to Interact" json) json

What about adding them to the project?

@haf haf changed the title Write/Read nested Write/Read nested objects Jul 30, 2015
@neoeinstein
Copy link
Member

This use case might be solved by the addition of Json.writeWith and Json.readWith from #44.

@haf
Copy link
Contributor Author

haf commented Dec 4, 2015

Here's a PropertyWith, please add?

  let inline (|PropertyWith|) fromJson key =
       Lens.getPartial (Json.Object_ >??> key_ key)
    >> Option.bind (fromJson >> function | Value a, _ -> Some a
                                         | _, _ -> None)

@kolektiv
Copy link
Member

kolektiv commented Dec 4, 2015

No problem, I'll get that in very soon - useful addition. There's likely to be a new Aether and Chiron (better in some serious ways I hope) out very soon, I'm kind of considering this weekend...

@haf
Copy link
Contributor Author

haf commented Dec 4, 2015

Awesome.

Beware that I've lost the connection with the API changes you've done to Aether (haven't seen any docs either), so I'm currently only using older versions of it.

@kolektiv
Copy link
Member

kolektiv commented Dec 4, 2015

Yeah new docs do need to be done before a release actually... I think I
might branch off the new version bits for Chiron for now and do a point
release to get this change in, as it's useful to an actual user.

How are you using Aether at the moment? If a library, then the new changes
have backwards compatible aliases until the next major version anyway. The
new changes are cool though, reducing the number of operators, better type
inference, etc.

On 4 December 2015 at 13:13, Henrik Feldt [email protected] wrote:

Awesome.

Beware that I've lost the connection with the API changes you've done to
Aether (haven't seen any docs either), so I'm currently only using older
versions of it.


Reply to this email directly or view it on GitHub
#39 (comment).

@haf
Copy link
Contributor Author

haf commented Dec 4, 2015

In Suave, in proprietary software, in Logary v4 mostly.

@kolektiv
Copy link
Member

kolektiv commented Dec 4, 2015

Cool. Well if you're usually pulling it in as a library, then it should be fine. And obviously it'll be a new major version, so if you've pinned things also no problem.

@haf
Copy link
Contributor Author

haf commented Dec 4, 2015

I'm thinking of using it like this:

type PointValue =
  /// Value at point in time
  | Gauge of Value * Units
  /// Any sort of derived measure
  | Derived of Value * Units
  /// All simple-valued fields' values can be templated into the template string
  /// when outputting the value in the target.
  | Event of template:string
with
  static member private valueUnitsToJson (value : Value, units : Units) : Json<unit> =
    Json.write "value" value
    *> Json.write "units" units

  static member private valueUnitsFromJson : Json<Value * Units> =
    (fun value units -> value, units)
    <!> Json.read "value"
    <*> Json.read "units"

  static member ToJson (pv : PointValue) : Json<unit> =
    let inJsonObject writer =
      writer (Json.Object Map.empty) |> snd

    match pv with
    | Gauge (value, units) ->
      Json.writeWith (PointValue.valueUnitsToJson >> inJsonObject) "gauge" (value, units)

    | Derived (value, units) ->
      Json.writeWith (PointValue.valueUnitsToJson >> inJsonObject) "derived" (value, units)

    | Event template ->
      Json.write "event" template

@kolektiv
Copy link
Member

kolektiv commented Dec 4, 2015

That seems pretty sensible.

@kolektiv
Copy link
Member

This has been merged in, and is out in 8.0.0-rc4 - definitely take a look at getting the latest. There's a backwards compat layer, but the new version is nicer when switched!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants