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

Top-level Tables #404

Open
pnotequalnp opened this issue Apr 10, 2022 · 3 comments
Open

Top-level Tables #404

pnotequalnp opened this issue Apr 10, 2022 · 3 comments

Comments

@pnotequalnp
Copy link

This TOML

[foo]
field = "bar"

[baz]
field = "quux"

is equivalent to this JSON

{
  "foo": {
    "field": "bar"
  },
  "baz": {
    "field": "quux"
  }
}

This data maps cleanly to this Haskell representation

type Data = Map String Entry

data Entry = Entry { field :: String }

However, I cannot figure out how to parse this shape of data with tomland. I threw together a quick repo to demonstrate my attempts and problems. The exact errors are in the CI run. I'm not sure if I'm misunderstanding how the library is supposed to be used, or if this sort of data is simply not able to be parsed by it currently.

Additionally, Map1 fails to decode the data that it just encoded. I'm not sure why that is, or if it's something I'm missing or a bug in the library. Map3, which should work from my understanding, also has curious behavior in regard to parsing equivalent TOML files differently (in particular, one being an error with the -Exact decoding variants).

@Qqwy
Copy link

Qqwy commented Oct 1, 2022

If I understand it correctly, you need to use the BiMap related functionality rather than the preexisting TomlCodec related functionality here, because a TomlCodec requires looking at a specific key (or multiple specific keys). c.f. https://hackage.haskell.org/package/tomland-1.3.3.1/docs/Toml-Codec-Combinator-Common.html#v:match. You can build your own alternative to match that does not look at a key however. I think that is the way to go here.

In the TOML datastructure itself, the root datastructures are introduced by the tree fields 'tomlPairs', 'tomlTables' and 'tomlTableArrays'. You are able to read/write these in a custom function that takes a bimap as input an creates a TomlCodec as output.

@thomasjm
Copy link

thomasjm commented Apr 6, 2023

I'm having trouble coming up with the solution described here, could anyone provide an example?

I've only been able to parse a file like this by calling parse, then manually iterating over the tomlTables and calling runTomlCodec on each individual value. Which leaves something to be desired in terms of validation etc.

@acowley
Copy link

acowley commented Apr 30, 2023

I had trouble with this, too. I followed @thomasjm's advice, and ended up with these helpers to get me unblocked. Pasting here as a starting point in case anyone else runs into a similar situation.

keyText :: Toml.Key -> T.Text
keyText = F.fold . cleanup . map Toml.unPiece . F.toList . Toml.unKey
  where
    -- Top-level table names are parsed as @"name" :|
    -- ["name"]@. Remove that duplication here.
    cleanup [x, y] | x == y = [x]
    cleanup x = x

-- | Parse a TOML file that is a top-level table whose values are all
-- the same type. The @tomland@ codec API is centered around starting
-- with a key, but a top-level table does not have a key, so we must
-- use the lower level 'Toml.parse' and 'Toml.tomlTables' before
-- repeatedly applying the provided 'Toml.TomlCodec'.
parseFileOf :: forall a. Toml.TomlCodec a -> T.Text -> Either [T.Text] [(T.Text, a)]
parseFileOf codec =
    first (map Toml.prettyTomlDecodeError)
        . validationToEither
        . traverse (uncurry go)
        . Toml.toList
        . Toml.tomlTables
        . either (error . show) id
        . Toml.parse
  where
    go :: Toml.Key -> Toml.TOML -> Validation [Toml.TomlDecodeError] (T.Text, a)
    go k v = (keyText k,) <$> Toml.runTomlCodec codec v

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

4 participants