Skip to content

Commit 34a9012

Browse files
committed
validationoption tests fix
1 parent 2514029 commit 34a9012

35 files changed

+473
-21
lines changed

examples/Danom.Samples.sln

+22
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
2+
Microsoft Visual Studio Solution File, Format Version 12.00
3+
# Visual Studio Version 17
4+
VisualStudioVersion = 17.0.31903.59
5+
MinimumVisualStudioVersion = 10.0.40219.1
6+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Danom.Examples.Todo", "Todo\Danom.Examples.Todo.csproj", "{47A6898A-F004-47B6-94BD-9C5A064FDCC4}"
7+
EndProject
8+
Global
9+
GlobalSection(SolutionConfigurationPlatforms) = preSolution
10+
Debug|Any CPU = Debug|Any CPU
11+
Release|Any CPU = Release|Any CPU
12+
EndGlobalSection
13+
GlobalSection(SolutionProperties) = preSolution
14+
HideSolutionNode = FALSE
15+
EndGlobalSection
16+
GlobalSection(ProjectConfigurationPlatforms) = postSolution
17+
{47A6898A-F004-47B6-94BD-9C5A064FDCC4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
18+
{47A6898A-F004-47B6-94BD-9C5A064FDCC4}.Debug|Any CPU.Build.0 = Debug|Any CPU
19+
{47A6898A-F004-47B6-94BD-9C5A064FDCC4}.Release|Any CPU.ActiveCfg = Release|Any CPU
20+
{47A6898A-F004-47B6-94BD-9C5A064FDCC4}.Release|Any CPU.Build.0 = Release|Any CPU
21+
EndGlobalSection
22+
EndGlobal
File renamed without changes.

samples/Mvc/Features/Home/HomeController.cs examples/Mvc/Features/Home/HomeController.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
namespace Danom.Samples.Mvc;
1+
namespace Danom.Examples.Mvc;
22

33
using Microsoft.AspNetCore.Mvc;
44

File renamed without changes.

samples/Mvc/Features/Option/OptionController.cs examples/Mvc/Features/Option/OptionController.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
namespace Danom.Samples.Mvc;
1+
namespace Danom.Examples.Mvc;
22

33
using Danom.Mvc;
44
using Microsoft.AspNetCore.Mvc;

samples/Mvc/Features/Result/ResultController.cs examples/Mvc/Features/Result/ResultController.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
namespace Danom.Samples.Mvc;
1+
namespace Danom.Examples.Mvc;
22

33
using Danom.Mvc;
44
using Microsoft.AspNetCore.Mvc;

samples/Mvc/Features/ResultOption/ResultOptionController.cs examples/Mvc/Features/ResultOption/ResultOptionController.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
namespace Danom.Samples.Mvc;
1+
namespace Danom.Examples.Mvc;
22

33
using Danom.Mvc;
44
using Microsoft.AspNetCore.Mvc;
File renamed without changes.
File renamed without changes.
File renamed without changes.
+19
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
<Project Sdk="Microsoft.NET.Sdk.Web">
2+
3+
<PropertyGroup>
4+
<TargetFramework>net9.0</TargetFramework>
5+
<Nullable>enable</Nullable>
6+
<ImplicitUsings>enable</ImplicitUsings>
7+
</PropertyGroup>
8+
9+
<ItemGroup>
10+
<PackageReference Include="Leger" Version="1.*" />
11+
<PackageReference Include="System.Data.SQLite" Version="1.*" />
12+
</ItemGroup>
13+
14+
<ItemGroup>
15+
<ProjectReference Include="..\..\src\Danom\Danom.csproj" />
16+
<ProjectReference Include="..\..\src\Danom.Validation\Danom.Validation.csproj" />
17+
<ProjectReference Include="..\..\src\Danom.Mvc\Danom.Mvc.csproj" />
18+
</ItemGroup>
19+
</Project>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
<!DOCTYPE html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="UTF-8">
5+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
6+
<title>Document</title>
7+
</head>
8+
<body>
9+
@RenderBody()
10+
</body>
11+
</html>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
namespace Danom.Examples.Todo;
2+
3+
using Danom;
4+
using Danom.Validation;
5+
6+
public sealed record CompleteTodoCommand(
7+
int TodoId);
8+
9+
public sealed class CompleteTodoCommandHandler(
10+
Func<CompleteTodo, Unit> completeTodo)
11+
{
12+
public Result<Unit, ResultErrors> Handle(CompleteTodoCommand command) =>
13+
ValidationResult<CompleteTodo>
14+
.From<CompleteTodoValidator>(
15+
new(TodoId: new(command.TodoId),
16+
CompletedDate: DateTime.UtcNow))
17+
.Map(completeTodo);
18+
}
+19
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
namespace Danom.Examples.Todo;
2+
3+
using Danom;
4+
using Danom.Validation;
5+
6+
public sealed record CreateTodoCommand(
7+
string Title,
8+
DateOnly? DueDate);
9+
10+
public sealed class CreateTodoCommandHandler(
11+
Func<CreateTodo, Unit> createTodo)
12+
{
13+
public Result<Unit, ResultErrors> Handle(CreateTodoCommand command) =>
14+
ValidationResult<CreateTodo>
15+
.From<CreateTodoValidator>(
16+
new(Title: command.Title,
17+
DueDate: command.DueDate.ToOption()))
18+
.Map(createTodo);
19+
}
+18
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
namespace Danom.Examples.Todo;
2+
3+
using Danom;
4+
using Danom.Validation;
5+
6+
public sealed record DeleteTodoCommand(
7+
int TodoId);
8+
9+
public sealed class DeleteTodoCommandHandler(
10+
Func<DeleteTodo, Unit> deleteTodo)
11+
{
12+
public Result<Unit, ResultErrors> Handle(DeleteTodoCommand command) =>
13+
ValidationResult<DeleteTodo>
14+
.From<DeleteTodoValidator>(
15+
new(TodoId: new(command.TodoId),
16+
DeletedDate: DateTime.UtcNow))
17+
.Map(deleteTodo);
18+
}
+17
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
namespace Danom.Examples.Todo;
2+
3+
using Danom;
4+
using Danom.Validation;
5+
6+
public sealed record GetTodoQuery(
7+
int TodoId);
8+
9+
public sealed class GetTodoQueryHandler(
10+
Func<TodoId, Option<Todo>> getTodo)
11+
{
12+
public Option<Todo> Handle(GetTodoQuery query) =>
13+
ValidationResult<TodoId>
14+
.From<TodoIdValidator>(new(query.TodoId))
15+
.Map(getTodo)
16+
.DefaultWith(Option<Todo>.None);
17+
}
+29
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
@model TodoList
2+
3+
<h1>Todo MVC</h1>
4+
5+
<nav>
6+
<a asp-controller=Todo asp-action=Create>Create Todo</a>
7+
</nav>
8+
9+
@if(Model.Incomplete.Any())
10+
{
11+
<ul>
12+
@foreach(var todo in Model.Incomplete)
13+
{
14+
<li>@todo.Title</li>
15+
}
16+
</ul>
17+
}
18+
19+
@if(Model.Complete.Any())
20+
{
21+
<h2><i>Completed</i></h2>
22+
23+
<ul>
24+
@foreach(var todo in Model.Complete)
25+
{
26+
<li>@todo.Title (Completed:@todo.CompletedDate.Map(x => x.ToLocalTime().ToString()).DefaultValue("-"))</li>
27+
}
28+
</ul>
29+
}
+24
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
namespace Danom.Examples.Todo;
2+
3+
using Danom;
4+
5+
public sealed class ListTodoQueryHandler(
6+
Func<IEnumerable<Todo>> getAllTodos)
7+
{
8+
public Option<TodoList> Handle()
9+
{
10+
var todos = getAllTodos();
11+
if (todos.Any())
12+
{
13+
var todoList = new TodoList(
14+
Incomplete: todos.Where(x => x.CompletedDate.IsNone),
15+
Complete: todos.Where(x => x.CompletedDate.IsSome));
16+
17+
return Option.Some(todoList);
18+
}
19+
else
20+
{
21+
return Option<TodoList>.None();
22+
}
23+
}
24+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
namespace Danom.Examples.Todo;
2+
3+
using Danom;
4+
using Danom.Mvc;
5+
using Microsoft.AspNetCore.Mvc;
6+
7+
public sealed class TodoController(
8+
TodoStore todo) : DanomController
9+
{
10+
[Route("/")]
11+
[Route("/todo")]
12+
public IActionResult Index()
13+
{
14+
var result = new ListTodoQueryHandler(todo.GetAll).Handle();
15+
return ViewOption(result);
16+
}
17+
18+
[HttpGet("/todo/create")]
19+
public IActionResult Create() =>
20+
View();
21+
22+
[HttpPost("/todo/create")]
23+
public IActionResult Create(CreateTodoCommand command)
24+
{
25+
var result = new CreateTodoCommandHandler(todo.Create).Handle(command);
26+
return result.Match(
27+
ok: _ => RedirectToAction(nameof(Index)),
28+
error: e => ViewResultErrors(e));
29+
}
30+
31+
[HttpGet("/todo/complete/{id}")]
32+
public IActionResult Complete(GetTodoQuery query)
33+
{
34+
var result = new GetTodoQueryHandler(todo.Get).Handle(query);
35+
return ViewOption(result);
36+
}
37+
38+
[HttpPost("/todo/complete/{id}")]
39+
public IActionResult Complete(CompleteTodoCommand command)
40+
{
41+
var result = new CompleteTodoCommandHandler(todo.Complete).Handle(command);
42+
return result.Match(
43+
ok: _ => RedirectToAction(nameof(Index)),
44+
error: e => ViewResultErrors(e));
45+
}
46+
47+
[HttpGet("/todo/delete/{id}")]
48+
public IActionResult Delete(GetTodoQuery query)
49+
{
50+
var result = new GetTodoQueryHandler(todo.Get).Handle(query);
51+
return ViewOption(result);
52+
}
53+
54+
[HttpPost("/todo/delete/{id}")]
55+
public IActionResult Delete(DeleteTodoCommand command)
56+
{
57+
var result = new DeleteTodoCommandHandler(todo.Delete).Handle(command);
58+
return result.Match(
59+
ok: _ => RedirectToAction(nameof(Index)),
60+
error: e => ViewResultErrors(e));
61+
}
62+
}
+92
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
namespace Danom.Examples.Todo;
2+
3+
using Danom;
4+
using Danom.Validation;
5+
using FluentValidation;
6+
7+
public sealed class TodoId(int value)
8+
{
9+
internal readonly int _value = value;
10+
public static explicit operator int(TodoId todoId) =>
11+
todoId._value;
12+
}
13+
14+
public sealed class TodoIdValidator : AbstractValidator<TodoId>
15+
{
16+
public TodoIdValidator()
17+
{
18+
RuleFor(todoId => (int)todoId).GreaterThan(0);
19+
}
20+
}
21+
22+
public sealed record Todo(
23+
TodoId TodoId,
24+
string Title,
25+
Option<DateOnly> DueDate,
26+
Option<DateTime> CompletedDate);
27+
28+
public sealed record TodoList(
29+
IEnumerable<Todo> Incomplete,
30+
IEnumerable<Todo> Complete);
31+
32+
//
33+
// Create
34+
35+
public sealed record CreateTodo(
36+
string Title,
37+
Option<DateOnly> DueDate);
38+
39+
public sealed class CreateTodoValidator : AbstractValidator<CreateTodo>
40+
{
41+
public CreateTodoValidator()
42+
{
43+
RuleFor(x => x.Title)
44+
.NotEmpty()
45+
.MaximumLength(256);
46+
47+
RuleFor(x => x.DueDate)
48+
.Optional(x =>
49+
x.GreaterThan(DateOnly.FromDateTime(DateTime.Now.Date)));
50+
}
51+
}
52+
53+
54+
//
55+
// Update
56+
57+
public sealed record CompleteTodo(
58+
TodoId TodoId,
59+
DateTime CompletedDate);
60+
61+
public sealed class CompleteTodoValidator : AbstractValidator<CompleteTodo>
62+
{
63+
public CompleteTodoValidator()
64+
{
65+
RuleFor(x => x.TodoId)
66+
.SetValidator(new TodoIdValidator());
67+
68+
RuleFor(x => x.CompletedDate)
69+
.NotEmpty()
70+
.GreaterThanOrEqualTo(DateTime.Now);
71+
}
72+
}
73+
74+
75+
//
76+
// Delete
77+
78+
public sealed record DeleteTodo(
79+
TodoId TodoId,
80+
DateTime DeletedDate);
81+
82+
public sealed class DeleteTodoValidator : AbstractValidator<DeleteTodo>
83+
{
84+
public DeleteTodoValidator()
85+
{
86+
RuleFor(x => x.TodoId)
87+
.SetValidator(new TodoIdValidator());
88+
89+
RuleFor(x => x.DeletedDate)
90+
.NotEmpty();
91+
}
92+
}

0 commit comments

Comments
 (0)