From 4dc9c4ede25ab5fb2881044a6471b9609fab9d6a Mon Sep 17 00:00:00 2001
From: Tomohisa Takaoka <ttakaoka@jtechs.com>
Date: Fri, 9 Aug 2024 17:57:32 -0700
Subject: [PATCH] Add OptionalValue.FromNullableValue

---
 .../ResultBoxes.Test/ConveyorSpec.cs          |  4 +--
 src/ResultBoxes/ResultBoxes.Test/UnitTest1.cs | 28 +++++++++++++++++++
 src/ResultBoxes/ResultBoxes/OptionalValue.cs  | 19 +++++++------
 .../ResultBoxes/ResultBoxes.csproj            |  6 ++--
 src/Samples/ConsoleApp2Optional/Program.cs    |  2 +-
 5 files changed, 44 insertions(+), 15 deletions(-)

diff --git a/src/ResultBoxes/ResultBoxes.Test/ConveyorSpec.cs b/src/ResultBoxes/ResultBoxes.Test/ConveyorSpec.cs
index f039e8a..a40a016 100644
--- a/src/ResultBoxes/ResultBoxes.Test/ConveyorSpec.cs
+++ b/src/ResultBoxes/ResultBoxes.Test/ConveyorSpec.cs
@@ -2,10 +2,8 @@
 
 namespace ResultBoxes.Test;
 
-public class ConveyorSpec(ITestOutputHelper testOutputHelper)
+public class ConveyorSpec()
 {
-
-
     [Fact]
     public void ConveyorWithNoParam()
     {
diff --git a/src/ResultBoxes/ResultBoxes.Test/UnitTest1.cs b/src/ResultBoxes/ResultBoxes.Test/UnitTest1.cs
index 3a225d3..bd931d3 100644
--- a/src/ResultBoxes/ResultBoxes.Test/UnitTest1.cs
+++ b/src/ResultBoxes/ResultBoxes.Test/UnitTest1.cs
@@ -101,3 +101,31 @@ public async Task Railway3AsyncSpec()
         Assert.Equal(12, sut.GetValue());
     }
 }
+
+public class OptionalValueTests
+{
+    [Fact]
+    public void OptionalValueEmptyTest()
+    {
+        var sut = OptionalValue<string>.Empty;
+
+        Assert.False(sut.HasValue);
+        Assert.Throws<ResultsInvalidOperationException>(() => sut.GetValue());
+    }
+
+    [Fact]
+    public void OptionalValueCreateSpec()
+    {
+        var value = (Guid?) Guid.NewGuid();
+        var sut = OptionalValue.FromNullableValue(value);
+        Assert.True(sut.HasValue);
+    }
+    [Fact]
+    public void OptionalValueCreateSpec2()
+    {
+        var value = (Guid?) null;
+        var sut = OptionalValue.FromNullableValue(value);
+        Assert.False(sut.HasValue);
+    }
+
+}
\ No newline at end of file
diff --git a/src/ResultBoxes/ResultBoxes/OptionalValue.cs b/src/ResultBoxes/ResultBoxes/OptionalValue.cs
index 5182d2b..956ed00 100644
--- a/src/ResultBoxes/ResultBoxes/OptionalValue.cs
+++ b/src/ResultBoxes/ResultBoxes/OptionalValue.cs
@@ -1,14 +1,17 @@
 using System.Text.Json.Serialization;
 namespace ResultBoxes;
 
-public record OptionalValue<TValue>(TValue? Value)
+public record OptionalValue<TValue>(TValue? Value, bool HasValue = true)
 {
-    [JsonIgnore]
-    public bool HasValue => Value is not null;
-
-    public static OptionalValue<TValue> Empty => new(default);
-    public static OptionalValue<TValue> Null => new(default);
-    public TValue GetValue() => Value ?? throw new ResultsInvalidOperationException("no value");
+    public static OptionalValue<TValue> Empty => new(default, false);
+    public static OptionalValue<TValue> Null => new(default, false);
+    public TValue GetValue() => HasValue && Value is not null ? Value : throw new ResultsInvalidOperationException("no value");
     public static implicit operator OptionalValue<TValue>(TValue value) => new(value);
-    public static OptionalValue<TValue> FromValue(TValue value) => new(value);
+}
+public static class OptionalValue
+{
+    public static OptionalValue<TValue> FromValue<TValue>(TValue value) where TValue : notnull => new(value);
+    public static OptionalValue<TValue> FromNullableValue<TValue>(TValue? value) where TValue : notnull => value is null ? OptionalValue<TValue>.Null : new(value);
+    public static OptionalValue<TValue> FromNullableValue<TValue>(TValue? value) where TValue : struct => value.HasValue ? new(value.Value) : OptionalValue<TValue>.Null;
+    public static  ResultBox<TValue> GetValueResult<TValue>(this OptionalValue<TValue> optional) where TValue : notnull => optional.HasValue && optional.Value is not null ? optional.Value : new ResultsInvalidOperationException("no value");
 }
diff --git a/src/ResultBoxes/ResultBoxes/ResultBoxes.csproj b/src/ResultBoxes/ResultBoxes/ResultBoxes.csproj
index be6e615..841b2e0 100644
--- a/src/ResultBoxes/ResultBoxes/ResultBoxes.csproj
+++ b/src/ResultBoxes/ResultBoxes/ResultBoxes.csproj
@@ -7,13 +7,13 @@
         <RootNamespace>ResultBoxes</RootNamespace>
         <LangVersion>preview</LangVersion>
         <PackageId>ResultBoxes</PackageId>
-        <Version>0.3.21</Version>
+        <Version>0.3.22</Version>
         <Authors>J-Tech Group</Authors>
         <Company>J-Tech-Japan</Company>
         <PackageDescription>ResultBoxes - C# Results Library that focus on Railway Programming.</PackageDescription>
         <RepositoryUrl>https://github.com/J-Tech-Japan/ResultBoxes</RepositoryUrl>
-        <PackageVersion>0.3.21</PackageVersion>
-        <Description>CheckNullWrapTry - CheckNull exception go through exceptionMapper</Description>
+        <PackageVersion>0.3.22</PackageVersion>
+        <Description>Adding OptionalValue.FromNullableValue</Description>
         <GeneratePackageOnBuild>true</GeneratePackageOnBuild>
         <PackageReadmeFile>README.md</PackageReadmeFile>
         <IncludeSymbols>true</IncludeSymbols>
diff --git a/src/Samples/ConsoleApp2Optional/Program.cs b/src/Samples/ConsoleApp2Optional/Program.cs
index 2ce1b21..2a99fe4 100644
--- a/src/Samples/ConsoleApp2Optional/Program.cs
+++ b/src/Samples/ConsoleApp2Optional/Program.cs
@@ -8,7 +8,7 @@ public static ResultBox<OptionalValue<string>> ConvertStringToHalfLength(string
         {
             0 => new ApplicationException("Input string is empty"), // Exception
             1 => OptionalValue<string>.Empty, // Not error but Empty 
-            _ => OptionalValue<string>.FromValue(input[..^(input.Length / 2)]) // has value 
+            _ => OptionalValue.FromValue(input[..^(input.Length / 2)]) // has value 
         };
     private static void Main(string[] args)
     {