Support for custom field mapping / converter / wrapper
It would be great if we could convert some protobuf field type to custom typescript type using a user provided mapper.
It is a very useful feature allowing to avoid having to recreate intermediate classes and doing mapping between protobuf generated class and "slightly better typed" classes.
Now the generated classes would have a very good typing natively.
A concrete example is a timestamp: some people want to use native Date, others will want to map it to a more specialized type of a library.
Same could apply to UUID or other Id classes, it could use a bytearray in protobuf (optimum space usage) but be represented a custom UUID class in the generated classes.
Here is a library implementing this pattern with kotlin.
Imagine the following protobuf:
message MyMessage {
string id = 1 [(wrapper) = "UUID"];
string timestamp = 2 [(wrapper) = "LocalDateTime"];
}
It would generate the following class:
export type MyMessage = Message<"MyMessage"> & {
id: UUID;
timestamp: LocalDateTime;
};
We would just need to find a way to pass the classes implementing the Converter:
interface Converter<FROM, TO> {
serialize(obj: FROM): TO
deserialize(obj: TO): FROM
}
class LocalDateTimeConverter implements Converter<string, LocalDateTime> {
deserialize(obj: LocalDateTime): string {
return obj.toString();
}
serialize(obj: string): LocalDateTime {
return LocalDateTime.parse(obj);
}
}
And toBinary/toJson/... could just use the converter before sending/receiving from the wire.
Hey @noguespi, gogo/protobuf has a similar feature.
Issues that could be supported with this feature:
- https://github.com/bufbuild/protobuf-es/issues/1031
- https://github.com/bufbuild/protobuf-es/issues/1015
- https://github.com/bufbuild/protobuf-es/issues/703
- https://github.com/bufbuild/protobuf-es/issues/227
- https://github.com/bufbuild/protobuf-es/issues/226
- https://github.com/bufbuild/protobuf-es/issues/1074
Note that the Protobuf option on the fields would have to specify how to import the type, which means it has to provide a name (e.g. "LocalDateTime") and a source (e.g. "somepackage").
The approach is not without downsides. For example, users must provide matching converters, and generating speed-optimized serialization code becomes impossible. Before designing and implementing this feature, we will need to explore alternatives.
Hi @timostamm, did you have a chance to look into this?
We use binary ULIDs in Protobuf with a special type, which at the moment means we have to either:
- Manually convert them back and forth every time we use them
- Build an extra abstraction layer on top of Protobuf-ES which would convert the ID fields into ULIDs
Neither solution is as elegant as adding custom field mapping in the Protobuf-ES codegen & serialization process. The downsides you mentioned seem much more acceptable compared to the above alternatives, especially since they should not affect users who don't need this feature.