feat: create request projects for basic CQRS
This commit is contained in:
commit
d614788e06
190 changed files with 12236 additions and 0 deletions
334
src/request.validation/RuleBuilderExtensions.cs
Normal file
334
src/request.validation/RuleBuilderExtensions.cs
Normal file
|
|
@ -0,0 +1,334 @@
|
|||
// Copyright (c) The Geekeey Authors
|
||||
// SPDX-License-Identifier: EUPL-1.2
|
||||
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
namespace Geekeey.Request.Validation;
|
||||
|
||||
/// <summary>
|
||||
/// Provides built-in validators for common validation scenarios.
|
||||
/// </summary>
|
||||
public static class RuleBuilderExtensions
|
||||
{
|
||||
private static bool IsNull<TProperty>([NotNullWhen(false)] TProperty? value)
|
||||
{
|
||||
object? boxed = value;
|
||||
return boxed is null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds a rule to ensure that the property value is not null for reference types.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type of the object being validated.</typeparam>
|
||||
/// <typeparam name="TProperty">The type of the property being validated. Must be a nullable reference type.</typeparam>
|
||||
/// <param name="rule">The rule builder to which the condition is applied.</param>
|
||||
/// <returns>The updated rule builder with the not-null condition added.</returns>
|
||||
public static IPropertyRuleBuilder<T, TProperty> NotNull<T, TProperty>(
|
||||
this IPropertyRuleBuilder<T, TProperty> rule)
|
||||
where TProperty : class?
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(rule);
|
||||
|
||||
return rule.Must(static value => value is not null, "Value is required.");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds a rule to ensure that the property value is not null for nullable value types.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type of the object being validated.</typeparam>
|
||||
/// <typeparam name="TProperty">The underlying non-nullable value type of the property being validated.</typeparam>
|
||||
/// <param name="rule">The rule builder to which the condition is applied.</param>
|
||||
/// <returns>The updated rule builder with the not-null condition added.</returns>
|
||||
public static IPropertyRuleBuilder<T, TProperty?> NotNull<T, TProperty>(
|
||||
this IPropertyRuleBuilder<T, TProperty?> rule)
|
||||
where TProperty : struct
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(rule);
|
||||
|
||||
return rule.Must(static value => value.HasValue, "Value is required.");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds a rule to ensure that the string property value is not null, empty, or whitespace.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type of the object being validated.</typeparam>
|
||||
/// <param name="rule">The rule builder to which the condition is applied.</param>
|
||||
/// <returns>The updated rule builder with the not-empty condition added.</returns>
|
||||
public static IPropertyRuleBuilder<T, string?> NotEmpty<T>(this IPropertyRuleBuilder<T, string?> rule)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(rule);
|
||||
|
||||
return rule.Must(static value => !string.IsNullOrWhiteSpace(value), "Value is required.");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds a rule to ensure that the collection property value is not null and contains at least one element.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type of the object being validated.</typeparam>
|
||||
/// <typeparam name="TElement">The type of the elements in the collection being validated.</typeparam>
|
||||
/// <param name="rule">The rule builder to which the condition is applied.</param>
|
||||
/// <returns>The updated rule builder with the not-empty condition added.</returns>
|
||||
public static IPropertyRuleBuilder<T, IEnumerable<TElement>?> NotEmpty<T, TElement>(
|
||||
this IPropertyRuleBuilder<T, IEnumerable<TElement>?> rule)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(rule);
|
||||
|
||||
return rule.Must(static value => value is not null && value.Any(), "Value is required.");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes the current rule property path from emitted validation problems.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type of the object being validated.</typeparam>
|
||||
/// <typeparam name="TProperty">The type of the property being validated.</typeparam>
|
||||
/// <param name="rule">The rule builder to which the property path transform is applied.</param>
|
||||
/// <returns>The updated rule builder with the property path removed.</returns>
|
||||
public static IPropertyRuleBuilder<T, TProperty> WithoutPropertyPath<T, TProperty>(
|
||||
this IPropertyRuleBuilder<T, TProperty> rule)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(rule);
|
||||
|
||||
return rule.WithPropertyPath(static _ => string.Empty);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds a rule to ensure that the string property value meets the specified minimum length.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type of the object being validated.</typeparam>
|
||||
/// <param name="rule">The rule builder to which the condition is applied.</param>
|
||||
/// <param name="minLength">The minimum allowed number of characters.</param>
|
||||
/// <returns>The updated rule builder with the minimum length condition added.</returns>
|
||||
public static IPropertyRuleBuilder<T, string?> MinLength<T>(
|
||||
this IPropertyRuleBuilder<T, string?> rule,
|
||||
int minLength)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(rule);
|
||||
ArgumentOutOfRangeException.ThrowIfNegative(minLength);
|
||||
|
||||
return rule.Must(value => IsNull(value) || value.Length >= minLength,
|
||||
$"Value must be at least {minLength} characters long.");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds a rule to ensure that the string property value does not exceed the specified maximum length.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type of the object being validated.</typeparam>
|
||||
/// <param name="rule">The rule builder to which the condition is applied.</param>
|
||||
/// <param name="maxLength">The maximum allowed number of characters.</param>
|
||||
/// <returns>The updated rule builder with the maximum length condition added.</returns>
|
||||
public static IPropertyRuleBuilder<T, string?> MaxLength<T>(
|
||||
this IPropertyRuleBuilder<T, string?> rule,
|
||||
int maxLength)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(rule);
|
||||
ArgumentOutOfRangeException.ThrowIfNegative(maxLength);
|
||||
|
||||
return rule.Must(value => IsNull(value) || value.Length <= maxLength,
|
||||
$"Value must be at most {maxLength} characters long.");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds a rule to ensure that the string property value falls within the specified inclusive length range.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type of the object being validated.</typeparam>
|
||||
/// <param name="rule">The rule builder to which the condition is applied.</param>
|
||||
/// <param name="minLength">The minimum allowed number of characters.</param>
|
||||
/// <param name="maxLength">The maximum allowed number of characters.</param>
|
||||
/// <returns>The updated rule builder with the length range condition added.</returns>
|
||||
public static IPropertyRuleBuilder<T, string?> Length<T>(
|
||||
this IPropertyRuleBuilder<T, string?> rule,
|
||||
int minLength,
|
||||
int maxLength)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(rule);
|
||||
ArgumentOutOfRangeException.ThrowIfNegative(minLength);
|
||||
ArgumentOutOfRangeException.ThrowIfNegative(maxLength);
|
||||
|
||||
if (maxLength < minLength)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException(nameof(maxLength),
|
||||
"Maximum length must be greater than or equal to minimum length.");
|
||||
}
|
||||
|
||||
return rule.Must(value => IsNull(value) || (value.Length >= minLength && value.Length <= maxLength),
|
||||
$"Value must be between {minLength} and {maxLength} characters long.");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds a rule to ensure that the property value is greater than the specified comparison value.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type of the object being validated.</typeparam>
|
||||
/// <typeparam name="TProperty">The type of the property being validated.</typeparam>
|
||||
/// <param name="rule">The rule builder to which the condition is applied.</param>
|
||||
/// <param name="comparisonValue">The value that the property must be greater than.</param>
|
||||
/// <returns>The updated rule builder with the greater-than condition added.</returns>
|
||||
public static IPropertyRuleBuilder<T, TProperty> GreaterThan<T, TProperty>(
|
||||
this IPropertyRuleBuilder<T, TProperty> rule,
|
||||
TProperty comparisonValue)
|
||||
where TProperty : IComparable<TProperty>?
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(rule);
|
||||
|
||||
return rule.Must(value => IsNull(value) || value.CompareTo(comparisonValue) > 0,
|
||||
$"Value must be greater than {comparisonValue}.");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds a rule to ensure that the property value is greater than or equal to the specified comparison value.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type of the object being validated.</typeparam>
|
||||
/// <typeparam name="TProperty">The type of the property being validated.</typeparam>
|
||||
/// <param name="rule">The rule builder to which the condition is applied.</param>
|
||||
/// <param name="comparisonValue">The value that the property must be greater than or equal to.</param>
|
||||
/// <returns>The updated rule builder with the greater-than-or-equal condition added.</returns>
|
||||
public static IPropertyRuleBuilder<T, TProperty> GreaterThanOrEqualTo<T, TProperty>(
|
||||
this IPropertyRuleBuilder<T, TProperty> rule,
|
||||
TProperty comparisonValue)
|
||||
where TProperty : IComparable<TProperty>?
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(rule);
|
||||
|
||||
return rule.Must(value => IsNull(value) || value.CompareTo(comparisonValue) >= 0,
|
||||
$"Value must be greater than or equal to {comparisonValue}.");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds a rule to ensure that the property value is less than the specified comparison value.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type of the object being validated.</typeparam>
|
||||
/// <typeparam name="TProperty">The type of the property being validated.</typeparam>
|
||||
/// <param name="rule">The rule builder to which the condition is applied.</param>
|
||||
/// <param name="comparisonValue">The value that the property must be less than.</param>
|
||||
/// <returns>The updated rule builder with the less-than condition added.</returns>
|
||||
public static IPropertyRuleBuilder<T, TProperty> LessThan<T, TProperty>(
|
||||
this IPropertyRuleBuilder<T, TProperty> rule,
|
||||
TProperty comparisonValue)
|
||||
where TProperty : IComparable<TProperty>?
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(rule);
|
||||
|
||||
return rule.Must(value => IsNull(value) || value.CompareTo(comparisonValue) < 0,
|
||||
$"Value must be less than {comparisonValue}.");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds a rule to ensure that the property value is less than or equal to the specified comparison value.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type of the object being validated.</typeparam>
|
||||
/// <typeparam name="TProperty">The type of the property being validated.</typeparam>
|
||||
/// <param name="rule">The rule builder to which the condition is applied.</param>
|
||||
/// <param name="comparisonValue">The value that the property must be less than or equal to.</param>
|
||||
/// <returns>The updated rule builder with the less-than-or-equal condition added.</returns>
|
||||
public static IPropertyRuleBuilder<T, TProperty> LessThanOrEqualTo<T, TProperty>(
|
||||
this IPropertyRuleBuilder<T, TProperty> rule,
|
||||
TProperty comparisonValue)
|
||||
where TProperty : IComparable<TProperty>?
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(rule);
|
||||
|
||||
return rule.Must(value => IsNull(value) || value.CompareTo(comparisonValue) <= 0,
|
||||
$"Value must be less than or equal to {comparisonValue}.");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds a rule to ensure that the property value falls within the specified inclusive range.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type of the object being validated.</typeparam>
|
||||
/// <typeparam name="TProperty">The type of the property being validated.</typeparam>
|
||||
/// <param name="rule">The rule builder to which the condition is applied.</param>
|
||||
/// <param name="minValue">The minimum allowed value.</param>
|
||||
/// <param name="maxValue">The maximum allowed value.</param>
|
||||
/// <returns>The updated rule builder with the range condition added.</returns>
|
||||
public static IPropertyRuleBuilder<T, TProperty> Between<T, TProperty>(
|
||||
this IPropertyRuleBuilder<T, TProperty> rule,
|
||||
TProperty minValue,
|
||||
TProperty maxValue)
|
||||
where TProperty : IComparable<TProperty>?
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(rule);
|
||||
|
||||
if (minValue is not null && maxValue is not null && minValue.CompareTo(maxValue) > 0)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException(nameof(maxValue),
|
||||
"Maximum value must be greater than or equal to minimum value.");
|
||||
}
|
||||
|
||||
return rule.Must(value => IsNull(value) || (value.CompareTo(minValue) >= 0 && value.CompareTo(maxValue) <= 0),
|
||||
$"Value must be between {minValue} and {maxValue}.");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds a rule to ensure that the property value is equal to the specified comparison value.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type of the object being validated.</typeparam>
|
||||
/// <typeparam name="TProperty">The type of the property being validated.</typeparam>
|
||||
/// <param name="rule">The rule builder to which the condition is applied.</param>
|
||||
/// <param name="comparisonValue">The required value for the property.</param>
|
||||
/// <returns>The updated rule builder with the equality condition added.</returns>
|
||||
public static IPropertyRuleBuilder<T, TProperty> Equal<T, TProperty>(
|
||||
this IPropertyRuleBuilder<T, TProperty> rule,
|
||||
TProperty comparisonValue)
|
||||
where TProperty : IEquatable<TProperty>?
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(rule);
|
||||
|
||||
return rule.Must(value => EqualityComparer<TProperty>.Default.Equals(value, comparisonValue),
|
||||
$"Value must be equal to {comparisonValue}.");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds a rule to ensure that the property value is not equal to the specified disallowed value.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type of the object being validated.</typeparam>
|
||||
/// <typeparam name="TProperty">The type of the property being validated.</typeparam>
|
||||
/// <param name="rule">The rule builder to which the condition is applied.</param>
|
||||
/// <param name="disallowedValue">The value that the property must not equal.</param>
|
||||
/// <returns>The updated rule builder with the inequality condition added.</returns>
|
||||
public static IPropertyRuleBuilder<T, TProperty> NotEqual<T, TProperty>(
|
||||
this IPropertyRuleBuilder<T, TProperty> rule,
|
||||
TProperty disallowedValue)
|
||||
where TProperty : IEquatable<TProperty>?
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(rule);
|
||||
|
||||
return rule.Must(value => !EqualityComparer<TProperty>.Default.Equals(value, disallowedValue),
|
||||
$"Value must not be equal to {disallowedValue}.");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds a rule to ensure that the string property value matches the specified regular expression pattern.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type of the object being validated.</typeparam>
|
||||
/// <param name="rule">The rule builder to which the condition is applied.</param>
|
||||
/// <param name="pattern">The regular expression pattern that the property value must match.</param>
|
||||
/// <returns>The updated rule builder with the pattern-matching condition added.</returns>
|
||||
public static IPropertyRuleBuilder<T, string?> Matches<T>(
|
||||
this IPropertyRuleBuilder<T, string?> rule,
|
||||
string pattern)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(rule);
|
||||
ArgumentException.ThrowIfNullOrEmpty(pattern);
|
||||
|
||||
return rule.Must(value => IsNull(value) || Regex.IsMatch(value, pattern),
|
||||
"Value is not in the correct format.");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds a rule to ensure that the string property value matches the specified regular expression.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type of the object being validated.</typeparam>
|
||||
/// <param name="rule">The rule builder to which the condition is applied.</param>
|
||||
/// <param name="regex">The regular expression that the property value must match.</param>
|
||||
/// <returns>The updated rule builder with the pattern-matching condition added.</returns>
|
||||
public static IPropertyRuleBuilder<T, string?> Matches<T>(
|
||||
this IPropertyRuleBuilder<T, string?> rule,
|
||||
Regex regex)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(rule);
|
||||
ArgumentNullException.ThrowIfNull(regex);
|
||||
|
||||
return rule.Must(value => IsNull(value) || regex.IsMatch(value),
|
||||
"Value is not in the correct format.");
|
||||
}
|
||||
}
|
||||
Loading…
Reference in a new issue