-
Notifications
You must be signed in to change notification settings - Fork 21
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
Add helper functions #21
base: master
Are you sure you want to change the base?
Conversation
What should the workflow be to maintain that the manually created modules match the code from the automatically generated modules? If we do add helper functions to this library I think we need a method to automatically add custom code to generated modules or the helper functions needs to live in a separate modules so they don't interfere with generated code. |
Update: It might actually be easy to update the generation script to add the functions 🤔 let me try prototyping something out. |
Alright, the Off the top of my head, two things stand out:
|
Personally, I don't think this is the way to go. I have thought about it a lot, and I think the Google stuff belongs in the core library. The core library already supports Google types in its JSON encoding/decoding, so it's already aware of those. We could bake the helpers into the main Protobuf library directly, since these types are supported officially. I don't personally have time to spend on this at all, so I’m just throwing this out there here 😬 |
I should be able to throw up a PR for that soon then. I’ll split it up into two PRs.
|
I know that helper functions have been discussed before (#8 and #15 (comment)) and rejected because this repository should only keep generated code. I respect that there is a well defined line of what this package handles, but I'd strongly urge to move that line slightly to the right and add helper functions to make these well known Protobuf types more usable in Elixir.
Protobuf handles a lot of the hard work for converting data between languages, but most language implementations have some code to patch over the bad stuff. Take the
google.protobuf.Struct
message for example. A simple JSON blob like so:will output this Elixir code (removed some lines for readability):
No sane person would want to work with that in their Elixir code. Here is a list of other languages and how they handle this:
Go
Implements functions like
AsMap
,AsTime
, andAsDuration
to convert Protobuf messages to standard Go code.Java
Implements
fromDate
and an absurd amount of other functions for handling well known types.Python
Implements
ToDatetime
,FromDatetime
,ToTimedelta
,FromTimedelta
and magic functions for Struct to work like a dictionary.Ruby
Has
to
andfrom
methods defined.Rust
Implements into and from
Timestamp
, into and fromDuration
, as well as Rust just being able to implement well known struct transforms in user code.Typescript
The JavaScript world is kinda a mess, so naturally there are 10+ different libraries for Protobuf handling.
protobuf-es
includes atoDate
functionts-proto
will just automatically convert from well known types to native types.Library vs User Code
You could argue that this code would be better lived in each application instead of this library, though I'd suspect most use cases for this library would use the helper functions. If that's the case, it would make more sense to include this code so it can be better documented and tested.
There is an alternative way to make this easier (and something I experimented on earlier) with
Transformer
modules to loop over all message values and rewrite anyGoogle.Protobuf.Struct
andGoogle.Protobuf.Timestamp
values tomap()
andDateTime.t()
, though that comes with a ton of other problems like not being able to see the original data, incorrect types, and just generally being hacky. Ideally you'd be able to encode aDateTime
in place ofGoogle.Protobuf.Timestamp
transparently, but the Elixir Protobuf library does not have support for this yet.Implementation
For this PR, I've decided to create new files for
duration
,struct
, andtimestamp
. The generated files (duration.pb.ex
) have been added to the.gitignore
to prevent them from being overwritten, while still making it easy to compare the generated output to what was custom edited. I've taken the liberty to updateex_doc
and include documentation for those modules so they show up, as well as add more details to theREADME.md
file and add it to the generated documentation. Since none of the encoding or decoding was touched, this is a non breaking change.You'll notice that I did not use doc tests here. I would have preferred to use them, but compile logic with Protobuf causes errors with the module structs not being defined in time. I've instead written the tests in separate files. I can also add more test cases if requested.
My current employer as well as previous both worked with Elixir and Protobuf. If maintaining is an issue, I'd be happy to help / take over.