Open dmitriyi-affinity opened 1 year ago
Thanks for the report @dmitriyi-affinity. The idea of the Validate
method is to just return Validation.Ok
or Validation.Invalid("[what is wrong with the value")
You can change the type of exception thrown using Configuration, or, as you're doing, just throw your own exception.
The argument name specification isn't really relevant here as the caller doesn't provide the argument; the validation method is either called via the From
method, or when the value object is being deserialized..
Apologies if I'm missing something; what problems are you seeing and what changes would make it better?
The reason exactly is to generate the correct argument exception for the MyTypedKey.From(T value) method. The raised custom exceptions inherited from the ArgumentException should has ArgumentName = "value".
I think what we could do here is, if the custom exception specified is ArgumentException
, then pass in value
.
Does it have to throw an exception, could the generator be configure to create a Either<CustomErrors, T> From(string value)
for example?
I'm looking again at this one. The From
method calls Validate
if there is one. It doesn't know what exceptions are thrown from this user-supplied method.
The generated code for the From
method is:
/// <summary>
/// Builds an instance from the provided underlying type.
/// </summary>
/// <param name=""value"">The underlying type.</param>
/// <returns>An instance of this type.</returns>
Do you want it to emit the exceptions that it throws, something like:
/// <exception cref="InvalidOperationException"></exception>
Or, it could inspect the Validation method that you supply and copy of the exceptions specified in the triple-slash comments...
Could we have something like [ValueObject(typeof(string), UseErrors=typeof(CustomErrors)]
or [ValueObject(typeof(string), UseExceptions=true)]
(<- assuming this is the default)
I'm about to add TryFrom
which will look like bool TryFrom(string input, out Name result)
.
I could also add something like Either<Validation, Name> TryFrom(input)
.
Yeah that Either<> TryFrom
would be great!
It's in the next version, and it's a simple maybe/result named ValueObjectOrError
. Hopefully released today.
So I just quickly tried it out:
[ValueObject(typeof(string))]
public partial record struct Name;
public record struct NameError(string message);
public record struct AgeError(string message);
[GenerateOneOf]
public partial class Errors : OneOfBase<NameError, AgeError> { }
public static class Extensions
{
public static Either<Errors, T> ToEither<T>(
this ValueObjectOrError<T> validation,
Func<Vogen.Validation, Errors> onError)
=> validation.IsSuccess switch
{
true => validation.ValueObject,
false => onError(validation.Error)
};
}
// Some Method somewhere
Name.TryFrom("jeff")
.ToEither(validation => new NameError(validation.ErrorMessage))
.Match(
vo => vo,
errors => throw new("Got errors"));
Seems pretty reasonable!
Obviously I could a lot more granular with the Data property of Vogen.Validation
maybe storing some more fine grain NameErrors
in there (expecting that NameErrors
would become another discriminated union).
Either I could actually store the record struct TooLongError
in the data or, just look for the string key "TooLong" and just map that in the onError
parameter
Thanks for the feedback @clinington . I can't wait for DU's to be a 1st class citizen!
Can I close this issue now, or is there anything else that you feel needs fixing or improving?
I wrote this blog post on it: https://medium.com/p/7ff4af9d2322
I wrote this extension:
public static class Extensions
{
public static Validation<TValidationError, T> ToValidationMonad<TValidationError, T>(
this ValueObjectOrError<T> validation,
Func<IReadOnlyList<string>, TValidationError> onError)
=> validation.IsSuccess switch
{
true => validation.ValueObject,
false => onError(validation.Error.Data?.Keys.Cast<string>().ToList() ?? [])
};
}
If i wanted to fork your repo to add either support internally, where in the code would I put the autogen stuff to create a Validation<TError, TValueObject> Validate
method?
Describe the feature
Please include the next scenario in your microbenchmarks and help:
It's currently impossible to well generate exceptions with argument name specification. VogenValidationException might be not a good default. Please consider also supporting ArgumentException as a first-class citizen for this library.