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

Define a canonical set of annotations that can be applied to sealed traits, case classes, and fields #203

Open
9 of 11 tasks
jdegoes opened this issue Feb 18, 2022 · 6 comments

Comments

@jdegoes
Copy link
Member

jdegoes commented Feb 18, 2022

Downstream libraries sometimes want to offer the ability to tweak the way codecs are generated from case classes, sealed traits, and fields inside case classes. A convenient way to do this is with annotations, e.g. ZIO DynamoDB's @discriminator("type") annotation, which specifies a different way to encode sealed trait hierarchies.

Rather than encouraging library authors to come up with a set of per-library annotations, with attendant duplication, we should instead introduce a "canonical" set of annotations that we expect can be used by a wide percentage of downstream library authors.

I'd start off by proposing the following set of annotations, which could live inside zio.schema.annotation._, and which could offer a standardized way to tweak common codec settings.

  • @discriminatorName, for specifying the name of a field that will be used to contain the id which identifies which term in an enum is being serialized / deserialized. For example, if you set @discriminatorName("type"), then a field called "type" will be used to store the identity of the case of the enum that is being serialized / deserialized.
  • @fieldName, for specifying an alternate identity for a field of a case class. Currently, the field name is always used. But sometimes, it will be convenient to have control over that name. For example, maybe the API expects username to be stored as user_name, but inside the case class, the field is named username. Such an annotation, applied directly to the field, could indicate a different identity for the field than the field name itself.
  • @caseName, for specifying an alternate identity for a case of an enum. Currently, the subtype name is always used. This is the dual of @fieldName, but for sums rather than products.
  • '@recordName`, for specifying an alternate name for a record.
  • @enumName, for specifying an alternate name for an enum.
  • @fieldNameAliases("alias1", "alias2"), for specifying a list of aliases the field is sometimes known by.
  • @caseNameAliases("alias1", "alias2"), for specifying a list of aliases the case is sometimes known by.
  • @optionalField, specifying that deserialization should not fail even if a value of this type is not specified.
  • @rejectExtraFields, specifying that deserialization should reject payloads that contain more fields than specified.
  • @transientField, specifying that serialization should make no effort to encode the field to which the annotation is applied. This is the dual of @optionalField.
  • @fieldDefaultValue, specifying the specified default value should be utilized when the field is not present during deserialization. This is similar to optionalField, except that the default value is user-defined rather than computed automatically using the field schema.

This ticket is only to add and document these annotations inside zio.schema.annotation, not to actually use them in the codecs provided by ZIO Schema. That work can be specified and completed in other, separate tickets.

@vigoo
Copy link
Contributor

vigoo commented Feb 20, 2022

@transientCase would also be useful to ignore some cases of a sum type completely (that are known to be never serialized)

@TobiasPfeifer
Copy link
Contributor

TobiasPfeifer commented Mar 3, 2022

these would be useful for avro schema:

  • @recordName("name")
  • @recordNameAliases("alias1", "alias2")
  • @default(???)
  • @formatter(DateTimeFormatter.ISO_INSTANT)
  • @documentation(???)
  • @namespace("com.example")
  • @arraySize(5) for fixed arrays
  • @bigInteger(digits)
  • @bigDecimal(scale, digits) (digits = precision)

The latter ones might be to specific for avro though

@vigoo
Copy link
Contributor

vigoo commented Oct 25, 2022

@jdegoes could we have transientCase too? :)

@devsprint
Copy link
Contributor

@vigoo transientCase will make sense only during serialisation, right ?

@vigoo
Copy link
Contributor

vigoo commented Nov 18, 2022

In some cases it could make sense to not try to derive schema for them, so you can have some constructors with types not supported by zio-schema (like holding some references to service traits for example). But maybe it's not something we want to support on this level. If not, it can be just a marker for serializers etc. My original use case why I asked for it was the first one though (in the context of serializers).

@beem812
Copy link
Contributor

beem812 commented Nov 21, 2022

I've opened a separate issue, but this may be just the place to ask for an annotation to override the default generator that you get from deriving a Gen for your schema. Swapping out Gen.anyString for Gen.alphaNumericString for instance.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

5 participants