scalalandio / chimney

Scala library for boilerplate-free, type-safe data transformations

Home Page:https://chimney.readthedocs.io

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Automatic Coproduct Rename from/to Protobuf GeneratedEnum

saeltz opened this issue · comments

Checklist

Describe the desired behavior

#409 proposes to allow renaming of coproducts. I think this is a good idea if one wants to transform from one enum to another with only the names being different.

I propose to allow for an automatic renaming if using Protobuf. If you follow the official Protobuf guidelines, enums are prefixed with the name of the enum and all uppercase, e.g.

enum Field {
  FIELD_UNSPECIFIED = 0;
  FIELD_CASE_ONE = 1;
  FIELD_CASE_TWO = 2;
}

In Scala (3), one wants to follow the best practices and use an enum with different names, e.g.

enum Field:
  case One, Two

This requires to define a custom transformer with one .withCoproductInstance per case. Introducing .withCoproductRenamed would simplify the code a bit but would still require a custom transformer with all cases.

I propose to have automatic renaming from Protobuf GeneratedEnum to Scala 3 enum with CamelCase. Possibly as an opt-in with the special protobuf import.

Additional context

I know this is heavily opinionated. I would love to get to know to solve this problem differently. If you're willing to have this feature, I'd be able to spend some time on it. I think it'd need to be added in TransformSealedHierarchyToSealedHierarchyRuleModule.scala.

Hey 👋, great thanks for suggestion!

I agree that such feature would be quite useful, but I would hesitate to enable it by default - virtually every feature that we ever added and had it turned on by default ended up with a bug report from someone who expected the code to fail/require manual intervention. I don't think that all such cases make sense (if one ends up with more configs than code they are helping to replace, it kind of misses the point), but this one feels like something that could be opt-in.

I recently started developing a feature allowing to customize how fields and subtypes are compared. It would address quite similar request for fields (#89) but also add an ability to customize comparison of subtypes/enum values.

If it was merged then adding enum support could be done e.g.

import io.scalaland.chimney.dsl.*
import io.scalaland.chimney.protobufs.*

implicit val config = TransformerConfiguration.default
  .enableCustomSubtypeNameComparison(PbEnumAwareNameComparison)

(alternatively, there could be several conventions prepared inside TransformedNamesComparison, one of them supporting UPPERCASE_WITH_UNDERSCORES).

Would such solution work for you?

I am not sure when I finish working on it. I started that mainly to take a break from some more mundane tickets that has to be implemented before 1.0.0-RC1, but I also have less time on mu hand AT.

Hey Mateusz, thanks for your reply!

I totally missed #89. #478 looks great. I think it would solve our problem. Do you think I could help somehow getting it merged?

I think right now, it's mostly grind:

  • replace all usages of "global" methods with something that uses ctx
  • write tests, they should make sure that top-level object/objects nested only on other objects work fine, and that disabling of the feature works as well
  • documentation - it should explain the limitation of this approach really well
    • to make code available to macro (we cannot rely on reify) it has to be available on the classpath
    • it also has to be instantiable with no dependencies
    • so the only sane choice are objects defined in module current module depends on
    • only then we can safely load object to memory and call it
    • it's basically unholy hack, but it seems to work

It isn't necessarily trivial, low-hanging fruit, but for the kind of work that happens in this project it's relatively simple - if you want to try, you can create a branch off #478 and see how it goes. :)

I continued in https://github.com/saeltz/chimney/tree/custom-name-comparator-saeltz.

All usages have been replaced with TransformerContext. Tests and documentation still missing.

Thank you! I've created a PR out of your changes.

Added in 1.0.0-M3

This is not really solved by #478. I opened #489.

I think it might be useful to have something OOTB in Chimney for some very common cases like Protobufs and Java integrations, however I need to point out that

This is not really solved by #478.

the whole point of #489 the PR is that everyone can add a custom comparator in their own codebase. The code in macros is as tricky as you see because we are not relying on pattern-matching on a sealed trait to obtain the comparator, but we are reading singleton value from the class-path by its type, so that every project is able to create and employ its own comparators without being blocked whether Chimney supports a particular convention OOTB.