Skip to content

Commit

Permalink
Merge pull request #60 from Takasaki-Studio/new-validator
Browse files Browse the repository at this point in the history
New validator
  • Loading branch information
Takasakiii authored May 13, 2024
2 parents dc0e0d8 + 3250350 commit b75f157
Show file tree
Hide file tree
Showing 20 changed files with 218 additions and 184 deletions.
6 changes: 6 additions & 0 deletions Lina.sln
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TakasakiStudio.Lina.AutoDep
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TakasakiStudio.Lina", "TakasakiStudio.Lina\TakasakiStudio.Lina.csproj", "{51F04308-2658-4EF5-AA3A-3126B77040C7}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TakasakiStudio.Lina.Test", "TakasakiStudio.Lina.Test\TakasakiStudio.Lina.Test.csproj", "{F368617F-1314-4AFB-A8F6-0103A48DA3E2}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand Down Expand Up @@ -42,5 +44,9 @@ Global
{51F04308-2658-4EF5-AA3A-3126B77040C7}.Debug|Any CPU.Build.0 = Debug|Any CPU
{51F04308-2658-4EF5-AA3A-3126B77040C7}.Release|Any CPU.ActiveCfg = Release|Any CPU
{51F04308-2658-4EF5-AA3A-3126B77040C7}.Release|Any CPU.Build.0 = Release|Any CPU
{F368617F-1314-4AFB-A8F6-0103A48DA3E2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{F368617F-1314-4AFB-A8F6-0103A48DA3E2}.Debug|Any CPU.Build.0 = Debug|Any CPU
{F368617F-1314-4AFB-A8F6-0103A48DA3E2}.Release|Any CPU.ActiveCfg = Release|Any CPU
{F368617F-1314-4AFB-A8F6-0103A48DA3E2}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
EndGlobal
55 changes: 13 additions & 42 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -163,33 +163,17 @@ await user.Validate();

Console.WriteLine("Valid");

public class User : BaseEntityValidate<User, UserValidation, int>
public class User : BaseValidated<User>
{
public required string Name { get; set; }
public required string Cpf { get; set; }
public required string Cnpj { get; set; }
}

public class UserValidation : AbstractValidator<User>
{
public UserValidation()
{
RuleFor(x => x.Name).NotEmpty();
RuleFor(x => x.Cpf).ValidCpf();
RuleFor(x => x.Cnpj).ValidCnpj();
}
}

public record UserViewModel(string Name, string Cpf, string Cnpj)
: BaseValidationRecord<UserViewModel, UserViewModelValidation>;

public class UserViewModelValidation : AbstractValidator<UserViewModel>
{
public UserViewModelValidation()

protected override void SetupValidator(LinaAbstractValidator<User> rules)
{
RuleFor(x => x.Name).NotEmpty();
RuleFor(x => x.Cpf).ValidCpf();
RuleFor(x => x.Cnpj).ValidCnpj();
rules.RuleFor(x => x.Name).NotEmpty();
rules.RuleFor(x => x.Cpf).ValidCpf();
rules.RuleFor(x => x.Cnpj).ValidCnpj();
}
}
```
Expand Down Expand Up @@ -225,9 +209,14 @@ public interface IAppConfig
public string DatabaseUrl { get; }
}

public class User : BaseValidateBaseEntity<User, UserValidation, int>
public class User : BaseValidatedEntity<User, int>
{
public string Name { get; set; } = string.Empty;

protected override void SetupValidator(LinaAbstractValidator<ExampleModel> rules)
{
rules.RuleFor(x => x.Name).NotEmpty();
}

public static implicit operator User(UserViewModel viewModel)
{
Expand All @@ -246,14 +235,6 @@ public class User : BaseValidateBaseEntity<User, UserValidation, int>
}
}

public class UserValidation : AbstractValidator<User>
{
public UserValidation()
{
RuleFor(x => x.Name).NotEmpty();
}
}

public class UserConfiguration : IEntityTypeConfiguration<User>
{
public void Configure(EntityTypeBuilder<User> builder)
Expand All @@ -264,19 +245,11 @@ public class UserConfiguration : IEntityTypeConfiguration<User>
}
}

public record UserViewModel : BaseValidationRecord<UserViewModel, UserViewModelValidation>
public record UserViewModel
{
public string Name { get; set; } = string.Empty;
}

public class UserViewModelValidation : AbstractValidator<UserViewModel>
{
public UserViewModelValidation()
{
RuleFor(x => x.Name).NotEmpty();
}
}

public interface IUserRepository : IBaseRepository<User, int>
{
}
Expand Down Expand Up @@ -305,8 +278,6 @@ public class UserService : IUserService

public async Task<UserViewModel?> Add(UserViewModel userViewModel)
{
if (!await userViewModel.IsValid()) throw new Exception("Not valid");

User user = userViewModel;
await user.Validate();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<Version>2.0.13</Version>
<Version>2.1.0</Version>
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
<PackageId>TakasakiStudio.Lina.AspNet</PackageId>
<Authors>TakasakiStudio</Authors>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<Version>2.0.13</Version>
<Version>2.1.0</Version>
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
<PackageId>TakasakiStudio.Lina.AutoDependencyInjection</PackageId>
<Authors>TakasakiStudio</Authors>
Expand Down
77 changes: 77 additions & 0 deletions TakasakiStudio.Lina.Common/BaseValidated.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
using FluentValidation;
using FluentValidation.Results;
using TakasakiStudio.Lina.Common.Interfaces;

namespace TakasakiStudio.Lina.Common;

/// <summary>
/// Base class to view model with basic validation using <a href="https://docs.fluentvalidation.net/en/latest/">Fluent Validation</a>
/// </summary>
/// <typeparam name="TModel">Self ref class</typeparam>
public abstract class BaseValidated<TModel> : IValidate
{
private LinaAbstractValidator<TModel>? _validator;

protected BaseValidated()
{
InstanceValidator();
}

/// <summary>
/// Validate view model with class validation and throw exception if failure
/// </summary>
/// <exception cref="ValidationException">Failure validation information</exception>
public virtual async ValueTask Validate()
{
await _validator!.ValidateAndThrowAsync(GetClassInstance());
}

/// <summary>
/// Get validation errors
/// </summary>
/// <returns>Failure validation information</returns>
public virtual async Task<ValidationResult> GetErrors()
{
return await _validator!.ValidateAsync(GetClassInstance());
}

/// <summary>
/// Verify if validation pass
/// </summary>
/// <returns>If valid</returns>
public virtual async ValueTask<bool> IsValid()
{
return (await GetErrors()).IsValid;
}

/// <summary>
/// Setups the validator rules
/// </summary>
/// <param name="rules">The validator instance, used to configure the validation rules</param>
/// <see href="https://docs.fluentvalidation.net/en/latest/index.html">Fluent Validation documentation</see>
/// <example>
/// <code language="cs">
/// public class ExampleModel : BaseValidated&lt;ExampleModel>
/// {
/// public required string Test { get; set; }
///
/// protected override void SetupValidator(LinaAbstractValidator&lt;ExampleModel> rules)
/// {
/// rules.RuleFor(x => x.Test).NotEmpty().NotNull();
/// }
/// }
/// </code>
/// </example>
protected abstract void SetupValidator(LinaAbstractValidator<TModel> rules);

private void InstanceValidator()
{
var setupValidator = (LinaAbstractValidator<TModel>.ValidationBuilder)SetupValidator;
_validator = new LinaAbstractValidator<TModel>(setupValidator);
}

private TModel GetClassInstance()
{
return (TModel)(object)this;
}
}
43 changes: 0 additions & 43 deletions TakasakiStudio.Lina.Common/BaseValidationRecord.cs

This file was deleted.

44 changes: 0 additions & 44 deletions TakasakiStudio.Lina.Common/Interfaces/IBaseValidate.cs

This file was deleted.

12 changes: 12 additions & 0 deletions TakasakiStudio.Lina.Common/LinaAbstractValidator.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
using FluentValidation;

namespace TakasakiStudio.Lina.Common;

public class LinaAbstractValidator<TModel> : AbstractValidator<TModel>
{
public delegate void ValidationBuilder(LinaAbstractValidator<TModel> builder);
internal LinaAbstractValidator(ValidationBuilder constructorBuilder)
{
constructorBuilder(this);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<Version>2.0.13</Version>
<Version>2.1.0</Version>
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
<PackageId>TakasakiStudio.Lina.Common</PackageId>
<Title>TakasakiStudio.Lina.Common</Title>
Expand Down
16 changes: 16 additions & 0 deletions TakasakiStudio.Lina.Database/Interfaces/IBaseEntity.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
namespace TakasakiStudio.Lina.Database.Interfaces;

public interface IBaseEntity<TPkType>
{
/// <summary>
/// Entity id
/// </summary>
public TPkType Id { get; set; }

/// <summary>
/// Create a clone of value
/// </summary>
/// <typeparam name="T">Value type</typeparam>
/// <returns></returns>
public T Clone<T>();
}
2 changes: 1 addition & 1 deletion TakasakiStudio.Lina.Database/Interfaces/IBaseRepository.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ namespace TakasakiStudio.Lina.Database.Interfaces;
/// <typeparam name="TEntity">Entity type</typeparam>
/// <typeparam name="TPkType">Entity id type</typeparam>
public interface IBaseRepository<TEntity, in TPkType>
where TEntity : BaseEntity<TPkType>
where TEntity : IBaseEntity<TPkType>
{
/// <summary>
/// Base function for find by id
Expand Down
7 changes: 4 additions & 3 deletions TakasakiStudio.Lina.Database/Models/BaseEntity.cs
Original file line number Diff line number Diff line change
@@ -1,23 +1,24 @@
using TakasakiStudio.Lina.Database.Interfaces;

namespace TakasakiStudio.Lina.Database.Models;

/// <summary>
/// Base entity database
/// </summary>
/// <typeparam name="TPkType">Entity id type</typeparam>
public abstract class BaseEntity<TPkType>
public abstract class BaseEntity<TPkType> : IBaseEntity<TPkType>
{
/// <summary>
/// Entity id
/// </summary>
public TPkType Id { get; set; } = default!;

/// <summary>
/// Create a clone of value
/// </summary>
/// <typeparam name="T">Value type</typeparam>
/// <returns></returns>
public T Clone<T>()
where T: BaseEntity<TPkType>
{
return (T)MemberwiseClone();
}
Expand Down
Loading

0 comments on commit b75f157

Please sign in to comment.