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

The toEncoding function is not used for YAML but is for JSON. #114

Closed
philderbeast opened this issue Aug 5, 2017 · 5 comments
Closed

The toEncoding function is not used for YAML but is for JSON. #114

philderbeast opened this issue Aug 5, 2017 · 5 comments

Comments

@philderbeast
Copy link

To encode JSON and specify the field order or rename fields, there's a way to do this using toEncoding ...

Encoding is ordered because it's just a Builder under the hood. So, if you write something like

instance ToJSON X where
toEncoding X{..} = pairs ("b" .= xB <> "a" .= xA)
the order is going to be {"b": ..., "a": ...}.
SOURCE: Object is unordered

This does not work when encoding to YAML ...

{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE RecordWildCards #-}
{-# LANGUAGE OverloadedStrings #-}

type SpeedSection = Maybe (Integer, Integer)

data Task =
    Task { taskName :: Name
         , speedSection :: SpeedSection
         , zones :: [Turnpoint]
         } deriving (Eq, Show, Generic)

instance ToJSON Task where
    toEncoding Task{..} =
        pairs ( "zones#1" .= zones
              <> "taskName#2" .= taskName
              <> "speedSection#3" .= speedSection
              )

> let a = Task "AA" Nothing []
> Data.Aeson.encode a
"{\"zones#1\":[],\"taskName#2\":\"AA\",\"speedSection#3\":null}"
> Data.Yaml.encode a
"taskName: AA\nzones: []\nspeedSection: null\n"

The yaml package docs mention the toEncoding function. Please add a note about this unexpected behaviour.

Can the encoding to YAML be made to use the renames and reordering the way encoding to JSON does?

@philderbeast
Copy link
Author

philderbeast commented Aug 5, 2017

As toEncoding is not used, perhaps the renaming effect can be had using toJSON ...

instance ToJSON Task where
    toJSON Task{..} =
        object [ "zones#1" .= zones
               , "taskName#2" .= taskName
               , "speedSection#3" .= speedSection
               ]

> Data.Aeson.encode a
"{\"zones#1\":[],\"taskName#2\":\"AA\",\"speedSection#3\":null}"
> Data.Yaml.encode a
"zones#1: []\ntaskName#2: AA\nspeedSection#3: null\n"

@philderbeast
Copy link
Author

The ordering effect cannot be had using toJSON ...

instance ToJSON Task where
    toJSON Task{..} =
        object [ "taskName#1" .= taskName
               , "speedSection#2" .= speedSection
               , "zones#3" .= zones
               ]

> Data.Aeson.encode a
"{\"speedSection#2\":null,\"taskName#1\":\"AA\",\"zones#3\":[]}"
> Data.Yaml.encode a
"speedSection#2: null\ntaskName#1: AA\nzones#3: []\n"

@snoyberg
Copy link
Owner

Doc improvements are always welcome via a pull request. However, there's no way for the yaml package to take advantage of the toEncoding field, since it embeds a JSON encoding within. If you'd like to control ordering, please see the Text.Libyaml module, which is more low-level.

@philderbeast
Copy link
Author

I've seen code snippets where compare is used for the ordering.

https://gist.github.com/tfausak/52e4560cbe175a84fd30?L25#file-ppy-hs-L26

I've tried this, setting deriving (Eq, Ord) on all records and field types. The resulting order I see then is alphabetical in field order. What I want is a structural layout ordering that matches the field order of the records as they're defined.

@snoyberg
Copy link
Owner

snoyberg commented Jul 9, 2018

In order to achieve this, I believe you'll need to use the Text.Libyaml layer, which does not encoding via Data.Aeson.Value. The latter forces arbitrary ordering.

@snoyberg snoyberg closed this as completed Jul 9, 2018
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

2 participants