Skip to content

Commit

Permalink
validationoption tests fix
Browse files Browse the repository at this point in the history
  • Loading branch information
pimbrouwers committed Dec 6, 2024
1 parent 2514029 commit 34a9012
Show file tree
Hide file tree
Showing 35 changed files with 473 additions and 21 deletions.
22 changes: 22 additions & 0 deletions examples/Danom.Samples.sln
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.0.31903.59
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Danom.Examples.Todo", "Todo\Danom.Examples.Todo.csproj", "{47A6898A-F004-47B6-94BD-9C5A064FDCC4}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{47A6898A-F004-47B6-94BD-9C5A064FDCC4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{47A6898A-F004-47B6-94BD-9C5A064FDCC4}.Debug|Any CPU.Build.0 = Debug|Any CPU
{47A6898A-F004-47B6-94BD-9C5A064FDCC4}.Release|Any CPU.ActiveCfg = Release|Any CPU
{47A6898A-F004-47B6-94BD-9C5A064FDCC4}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
EndGlobal
File renamed without changes.
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
namespace Danom.Samples.Mvc;
namespace Danom.Examples.Mvc;

using Microsoft.AspNetCore.Mvc;

Expand Down
File renamed without changes.
File renamed without changes.
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
namespace Danom.Samples.Mvc;
namespace Danom.Examples.Mvc;

using Danom.Mvc;
using Microsoft.AspNetCore.Mvc;
Expand Down
File renamed without changes.
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
namespace Danom.Samples.Mvc;
namespace Danom.Examples.Mvc;

using Danom.Mvc;
using Microsoft.AspNetCore.Mvc;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
namespace Danom.Samples.Mvc;
namespace Danom.Examples.Mvc;

using Danom.Mvc;
using Microsoft.AspNetCore.Mvc;
Expand Down
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
19 changes: 19 additions & 0 deletions examples/Todo/Danom.Examples.Todo.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<Project Sdk="Microsoft.NET.Sdk.Web">

<PropertyGroup>
<TargetFramework>net9.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Leger" Version="1.*" />
<PackageReference Include="System.Data.SQLite" Version="1.*" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\..\src\Danom\Danom.csproj" />
<ProjectReference Include="..\..\src\Danom.Validation\Danom.Validation.csproj" />
<ProjectReference Include="..\..\src\Danom.Mvc\Danom.Mvc.csproj" />
</ItemGroup>
</Project>
11 changes: 11 additions & 0 deletions examples/Todo/Features/Shared/Default.cshtml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
@RenderBody()
</body>
</html>
18 changes: 18 additions & 0 deletions examples/Todo/Features/Todo/CompleteTodo.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
namespace Danom.Examples.Todo;

using Danom;
using Danom.Validation;

public sealed record CompleteTodoCommand(
int TodoId);

public sealed class CompleteTodoCommandHandler(
Func<CompleteTodo, Unit> completeTodo)
{
public Result<Unit, ResultErrors> Handle(CompleteTodoCommand command) =>
ValidationResult<CompleteTodo>
.From<CompleteTodoValidator>(
new(TodoId: new(command.TodoId),
CompletedDate: DateTime.UtcNow))
.Map(completeTodo);
}
19 changes: 19 additions & 0 deletions examples/Todo/Features/Todo/CreateTodo.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
namespace Danom.Examples.Todo;

using Danom;
using Danom.Validation;

public sealed record CreateTodoCommand(
string Title,
DateOnly? DueDate);

public sealed class CreateTodoCommandHandler(
Func<CreateTodo, Unit> createTodo)
{
public Result<Unit, ResultErrors> Handle(CreateTodoCommand command) =>
ValidationResult<CreateTodo>
.From<CreateTodoValidator>(
new(Title: command.Title,
DueDate: command.DueDate.ToOption()))
.Map(createTodo);
}
18 changes: 18 additions & 0 deletions examples/Todo/Features/Todo/DeleteTodo.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
namespace Danom.Examples.Todo;

using Danom;
using Danom.Validation;

public sealed record DeleteTodoCommand(
int TodoId);

public sealed class DeleteTodoCommandHandler(
Func<DeleteTodo, Unit> deleteTodo)
{
public Result<Unit, ResultErrors> Handle(DeleteTodoCommand command) =>
ValidationResult<DeleteTodo>
.From<DeleteTodoValidator>(
new(TodoId: new(command.TodoId),
DeletedDate: DateTime.UtcNow))
.Map(deleteTodo);
}
17 changes: 17 additions & 0 deletions examples/Todo/Features/Todo/GetTodo.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
namespace Danom.Examples.Todo;

using Danom;
using Danom.Validation;

public sealed record GetTodoQuery(
int TodoId);

public sealed class GetTodoQueryHandler(
Func<TodoId, Option<Todo>> getTodo)
{
public Option<Todo> Handle(GetTodoQuery query) =>
ValidationResult<TodoId>
.From<TodoIdValidator>(new(query.TodoId))
.Map(getTodo)
.DefaultWith(Option<Todo>.None);
}
29 changes: 29 additions & 0 deletions examples/Todo/Features/Todo/Index.cshtml
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
@model TodoList

<h1>Todo MVC</h1>

<nav>
<a asp-controller=Todo asp-action=Create>Create Todo</a>
</nav>

@if(Model.Incomplete.Any())
{
<ul>
@foreach(var todo in Model.Incomplete)
{
<li>@todo.Title</li>
}
</ul>
}

@if(Model.Complete.Any())
{
<h2><i>Completed</i></h2>

<ul>
@foreach(var todo in Model.Complete)
{
<li>@todo.Title (Completed:@todo.CompletedDate.Map(x => x.ToLocalTime().ToString()).DefaultValue("-"))</li>
}
</ul>
}
24 changes: 24 additions & 0 deletions examples/Todo/Features/Todo/ListTodo.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
namespace Danom.Examples.Todo;

using Danom;

public sealed class ListTodoQueryHandler(
Func<IEnumerable<Todo>> getAllTodos)
{
public Option<TodoList> Handle()
{
var todos = getAllTodos();
if (todos.Any())
{
var todoList = new TodoList(
Incomplete: todos.Where(x => x.CompletedDate.IsNone),
Complete: todos.Where(x => x.CompletedDate.IsSome));

return Option.Some(todoList);
}
else
{
return Option<TodoList>.None();
}
}
}
62 changes: 62 additions & 0 deletions examples/Todo/Features/Todo/TodoController.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
namespace Danom.Examples.Todo;

using Danom;
using Danom.Mvc;
using Microsoft.AspNetCore.Mvc;

public sealed class TodoController(
TodoStore todo) : DanomController
{
[Route("/")]
[Route("/todo")]
public IActionResult Index()
{
var result = new ListTodoQueryHandler(todo.GetAll).Handle();
return ViewOption(result);
}

[HttpGet("/todo/create")]
public IActionResult Create() =>
View();

[HttpPost("/todo/create")]
public IActionResult Create(CreateTodoCommand command)
{
var result = new CreateTodoCommandHandler(todo.Create).Handle(command);
return result.Match(
ok: _ => RedirectToAction(nameof(Index)),
error: e => ViewResultErrors(e));
}

[HttpGet("/todo/complete/{id}")]
public IActionResult Complete(GetTodoQuery query)
{
var result = new GetTodoQueryHandler(todo.Get).Handle(query);
return ViewOption(result);
}

[HttpPost("/todo/complete/{id}")]
public IActionResult Complete(CompleteTodoCommand command)
{
var result = new CompleteTodoCommandHandler(todo.Complete).Handle(command);
return result.Match(
ok: _ => RedirectToAction(nameof(Index)),
error: e => ViewResultErrors(e));
}

[HttpGet("/todo/delete/{id}")]
public IActionResult Delete(GetTodoQuery query)
{
var result = new GetTodoQueryHandler(todo.Get).Handle(query);
return ViewOption(result);
}

[HttpPost("/todo/delete/{id}")]
public IActionResult Delete(DeleteTodoCommand command)
{
var result = new DeleteTodoCommandHandler(todo.Delete).Handle(command);
return result.Match(
ok: _ => RedirectToAction(nameof(Index)),
error: e => ViewResultErrors(e));
}
}
92 changes: 92 additions & 0 deletions examples/Todo/Features/Todo/TodoModel.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
namespace Danom.Examples.Todo;

using Danom;
using Danom.Validation;
using FluentValidation;

public sealed class TodoId(int value)
{
internal readonly int _value = value;
public static explicit operator int(TodoId todoId) =>
todoId._value;
}

public sealed class TodoIdValidator : AbstractValidator<TodoId>
{
public TodoIdValidator()
{
RuleFor(todoId => (int)todoId).GreaterThan(0);
}
}

public sealed record Todo(
TodoId TodoId,
string Title,
Option<DateOnly> DueDate,
Option<DateTime> CompletedDate);

public sealed record TodoList(
IEnumerable<Todo> Incomplete,
IEnumerable<Todo> Complete);

//
// Create

public sealed record CreateTodo(
string Title,
Option<DateOnly> DueDate);

public sealed class CreateTodoValidator : AbstractValidator<CreateTodo>
{
public CreateTodoValidator()
{
RuleFor(x => x.Title)
.NotEmpty()
.MaximumLength(256);

RuleFor(x => x.DueDate)
.Optional(x =>
x.GreaterThan(DateOnly.FromDateTime(DateTime.Now.Date)));
}
}


//
// Update

public sealed record CompleteTodo(
TodoId TodoId,
DateTime CompletedDate);

public sealed class CompleteTodoValidator : AbstractValidator<CompleteTodo>
{
public CompleteTodoValidator()
{
RuleFor(x => x.TodoId)
.SetValidator(new TodoIdValidator());

RuleFor(x => x.CompletedDate)
.NotEmpty()
.GreaterThanOrEqualTo(DateTime.Now);
}
}


//
// Delete

public sealed record DeleteTodo(
TodoId TodoId,
DateTime DeletedDate);

public sealed class DeleteTodoValidator : AbstractValidator<DeleteTodo>
{
public DeleteTodoValidator()
{
RuleFor(x => x.TodoId)
.SetValidator(new TodoIdValidator());

RuleFor(x => x.DeletedDate)
.NotEmpty();
}
}
Loading

0 comments on commit 34a9012

Please sign in to comment.