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

NamedEncode for a row of columns #43

Open
Profpatsch opened this issue Jul 9, 2021 · 6 comments
Open

NamedEncode for a row of columns #43

Profpatsch opened this issue Jul 9, 2021 · 6 comments

Comments

@Profpatsch
Copy link

Profpatsch commented Jul 9, 2021

I have a datatype with a list of translations, like so:

type Lang = Text

data Trans = Trans {
  key :: Text,
  translations :: [(Lang, Text)]
}

And I want to generate a csv like

key de en es fr
title Ein Titel A Title Un Titre
something Something Quelqechose

from a [Trans] like

[
  Trans {
    key = "title",
    translations = [("de", "Ein Titel"), ("en", "A Title"), …]
  },
  …
]

But it is not clear to me whether it’s possible to generate a NamedEncoder a that sets their column names based on the a.

i.e. I think I need something like

namedRow :: (a -> Builder) -> Encoder a -> NamedEncoder [a]

But there only is

row :: Builder -> Encoder a -> Encoder [a]

and I’m not sure the internal encoding (heh) of Encoder would even allow for such a thing.

A complication here is that it’s not entirely clear that every translations would even list the same languages, so the rows might be different for every Trans; maybe my Trans should be represented differently?

@Profpatsch
Copy link
Author

To be clear, every Trans could have a variable amount of languages, and I kinda want to encode a superset of all languages, so my representation probably has to change anyway.

@Profpatsch
Copy link
Author

Profpatsch commented Jul 9, 2021

Okay, I solved it by passing the list of all language fields into the function returning an encoder, and then looking up the translation in a map:

type Lang = Text

data Trans = Trans {
  key :: Text,
  translations :: Map Lang Text
}

transEncoder :: [Lang] -> Encoder Trans
transEncoder languagesToEncodeInColumns = 
  (\Trans { key, translations } -> (key, translations))
  $ contrazip2 _keyEnc translationsEnc
  where 
    translationEnc lang =
      _toBytesBuilder lang
        Enc.=: (encFromMap lang translatedString)
    translationsEnc = foldMap translationEnc languagesToEncodeInColumns

-- | Takes a key to fetch from the map and gives back an encoder that fetches that key from the map (or empty string)
encFromMap :: Ord k => k -> Encode a -> Encode (Map k a)
encFromMap key = contramap (Map.lookup key) . orEmpty

@Profpatsch
Copy link
Author

Then you have to collect a list of all languages that you want to encode beforehand, but you have to do that anyway to figure out which columns you need.

@gwils
Copy link
Member

gwils commented Jul 11, 2021

Does the CSV come out as you'd expect? I'm glad you found a solution.
I am the maintainer (to be generous) for this library, but as you can see, not much has happened for a long time. I should catch up on things like dependency/GHC upgrades, and moving from Travis to Github Actions. Once I'm back up to speed those mundane tasks, I can try to implement this combinator you've asked for. It's good to see we have at least one user!
Maintenance of this library is no longer part of my day job, and I've been strapped for time lately, so I don't have a particular timeframe for you. Two weeks from now I will be taking a bit of time off work, so that would be my best bet.

@Profpatsch
Copy link
Author

it works just as expected!

Maybe it could go into the examples or something? I might try to whip something up once I’ve written the decoder that can do it in reverse.

@Profpatsch
Copy link
Author

The combinator I posted above is not really viable, I has the conceptual problem that the NamedEncoder has to statically know the fields before seeing any data, and then for data it just applies the schema, which is totally fine.

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