Validators for collections#1879
Validators for collections#1879msosnicki wants to merge 10 commits intodisneystreaming:series/0.18from
Conversation
| memberRefinements = memberRefinements | ||
| ) | ||
|
|
||
| override def toSchema(a: Schema[A]): Schema[B] = { |
There was a problem hiding this comment.
This is not correct in the current implementation. See for example how ValidatedString changed - the underlyingType contains schema with all refinements attached to it. We also have validator with the same schema information duplicated. Then we have implicit val schema = validator.toSchema(underlyingSchema).
So the resulting schema will have refinements applied twice.
I removed that duplication, but that means that the Validator.toSchema` is just applying the outermost bijection, which in my opinion defeats it's purpose.
|
|
||
| } | ||
|
|
||
| @deprecated |
There was a problem hiding this comment.
todo: add details for all deprecations + update changelog
| def validate(value: A): Either[String, B] | ||
|
|
||
| // todo: deprecate | ||
| def toSchema(a: Schema[A]): Schema[B] |
There was a problem hiding this comment.
I think this method is a bit problematic, especially the more complex scenario there is. For example, see the code generated for ValidatedRefinedListConstrainedMember.
The underlyingType contains the full schema besides bijection, and I haven't changed that.
So doing the schema = validator.toSchema(underlyingSchema) where the validator contains all the schema bindings kind of duplicated. There was a bug present before (see here) that was wrapping schemas in refinements multiple times and after fixing it the validator is just applying the outermost bijection.
| package smithy4s | ||
|
|
||
| sealed trait Validator[A, B] { | ||
| sealed trait Validator[A, B] { self => |
There was a problem hiding this comment.
I tried not to change the current API too much, but given the issues highlighted in the other comments, I think that having a simpler interface, just:
trait Validator[A] {
def validate(a: A): Either[String, A]
}and having a schema visitor Schema ~> Validator that works for any type would be much better. at least at first glance. We would get rid of the duplication of schema bindings that are basically the same in the Schema and Validator members, and this would open up possibility to validate any type, not just the ones that the @validatedNewtype is restricted to.
Not sure how it would fit the 0.18 though
There was a problem hiding this comment.
It's possible that by trying to unifying constraints with type refinements, we've made things awkward / more complicated they'd have to be.
Maybe targeting 0.19 directly and trying to separate the concepts might be a good idea. It'd also be good to get the Disney and SXM contributors together in a call and decide and whiteboard it
| final class ValidatorBuilder[A, B] private[smithy4s] ( | ||
| bijection: Bijection[A, B] | ||
| ) { | ||
| trait Builder[A, B] { self => |
There was a problem hiding this comment.
I'm not too sure about this, as the exposure of public traits feels like a bincompat issue waiting to happen, because it's seemingly adding a lot of api surface.
I'd rather you tried to have compositional functions
sealed trait Validator[A, B]{ ...}
object Validator {
def list[A, B](validator: Validator[A, B]) : Validator[List[A], List[B]] = ???
def map[K0, K1, V0, V1](key : Validator[K0, K1], value: Validator[V0, V1]) = ???
}... but then, I think this is a little awkward too, and I think it'd be simplified by having a clearer delimitation between constraints (which may lead to the creation of validated newtypes) and type-refinements as they currently stand (which generally target types that are external to the metamode)
There was a problem hiding this comment.
I made it package private for smithy4s and everything still works, so it might help a bit.
I started without a builder, just the methods directly on Validator, but the API was very awkward, using the type evidences all over the place. So it was even worse - it would impact the whole Validator interface, which is really public.
I could try with the approach you're suggesting here, just passing the fully constructed validators for collections. Whenever I have some time I can try that out.
Overview
Closes #1843
PR Checklist (not all items are relevant to all PRs)