-
Notifications
You must be signed in to change notification settings - Fork 40
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
Question: Smart constructor pattern / composable validations #96
Comments
In fact, thinking about it, there isn't even the need for bind (i.e. for ValidationResult to be a Monad), apply would be enough (i.e. for it to be an Applicative). Something along the lines of: public fun <A, B> ValidationResult<(A) -> B>.apply(x: ValidationResult<A>): ValidationResult<B> =
when (this) {
is Invalid -> this
is Valid -> x.map(value)
} Would allow one to compose various value class validations through smart constructors to build validated data classes, as so: // If Foo and Bar are value classes with validation in their companion object invoke methods
data class FooBar(val foo: Foo, val bar: Bar) {
// Does this exist somehow in Kotlin ?
companion object { fun curried(foo: Foo) = { bar: Bar -> FooBar(foo, bar) } }
}
// And then this works:
val validatedFooBar: ValidationResult<FooBar> = Foo("abc").map(FooBar::curry).apply(Bar("cde")) My kotlin is not good enough to make a DSL-y thing, but one could imagine a syntax like below to be rather nice to work with: val validatedFooBar: ValidationResult<FooBar> = validateApply<FooBar> {
Foo("abc")
Bar("cde")
} |
I'm not 100% sure I follow, but I think it would be good enough for val customer: Customer = ...
val dto: ValidationResult<CustomerDto>= customerValidation(customer).map { it.toDto() } The current (0.4.0) To help you: In the JVM world functor is usually implemented by Trying to find these in types and using this nomenclature for issues will make things more clear. You will probably also enjoy Arrow (altough I personally don't think Kotlin is suitable for going so hard on the FP) |
Closing this as it's not an issue per se, feel free to reply or open a new issue with a more directed question/problem |
Hello, and thank you for this nice library. Coming from the FP world, I am trying to use it with the smart constructor pattern and, not having a bind (or flatMap, or andThen, or anything you call
(ValidationResult<T1> -> (T1 -> ValidationResult<T2>)) -> ValidationResult<T2>
), am having a bit of trouble: I'd be happy to open a PR with a bind implementation, but first I'm thinking maybe I'm using this wrong.Using Konform, I've managed to build the following inline class, who'se type represents a proof of being valid (I don't want to have
Valid<x>
's all over my domain code), which works well enough:But then when I have a class that is using the above value class as a member, I cannot compose both validations. Given:
Going from the first above to the second, I cannot do something like
CustomerID(id).andThen { id -> ... }
to build the final object. But I have to validate theCustomerID
before passing it to theCustomer
constructor (since theCustomerID
type enforces validity of the data it contains), and so I am left with no choice but to validate by hand the different elements, and compose the errors manually.What is the suggested usage pattern for Konform to have both type-level guarantees of data validity when passing values around and composability of validations to build more complex objects ?
I hope I've managed to explain my question correctly, and I'm looking forward to your answer! Have a great day 😃
The text was updated successfully, but these errors were encountered: