made Error fully immutable
All checks were successful
.NET Test / test (push) Successful in 4m16s

This commit is contained in:
2023-12-12 18:55:53 +04:00
parent bb8c2135b5
commit 9ae185342b
2 changed files with 33 additions and 37 deletions

View File

@@ -1,4 +1,5 @@
using System.Collections; using System.Collections;
using System.Collections.Immutable;
using System.Runtime.Serialization; using System.Runtime.Serialization;
using System.Text; using System.Text;
@@ -10,8 +11,6 @@ namespace Just.Railway;
[JsonDerivedType(typeof(ManyErrors))] [JsonDerivedType(typeof(ManyErrors))]
public abstract class Error : IEquatable<Error>, IComparable<Error> public abstract class Error : IEquatable<Error>, IComparable<Error>
{ {
private IDictionary<string, object>? _extensionData;
protected internal Error(){} protected internal Error(){}
/// <summary> /// <summary>
@@ -77,28 +76,8 @@ public abstract class Error : IEquatable<Error>, IComparable<Error>
[Pure] public abstract string Type { get; } [Pure] public abstract string Type { get; }
[Pure] public abstract string Message { get; } [Pure] public abstract string Message { get; }
[Pure, JsonExtensionData] public IDictionary<string, object> ExtensionData [Pure, JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] public ImmutableDictionary<string, string>? ExtensionData { get; init; }
{ [Pure] public string? this[string key] => ExtensionData?.TryGetValue(key, out var value) == true ? value : null;
get => _extensionData ??= new Dictionary<string, object>();
init => _extensionData = value ?? new Dictionary<string, object>();
}
[Pure] public object? this[string name]
{
get => _extensionData?.TryGetValue(name, out var val) == true ? val : null;
set
{
if (value is null)
{
_extensionData?.Remove(name);
}
else
{
_extensionData ??= new Dictionary<string, object>();
_extensionData[name] = value;
}
}
}
[Pure, JsonIgnore] public abstract int Count { get; } [Pure, JsonIgnore] public abstract int Count { get; }
[Pure, JsonIgnore] public abstract bool IsEmpty { get; } [Pure, JsonIgnore] public abstract bool IsEmpty { get; }
@@ -199,13 +178,13 @@ public sealed class ExceptionalError : Error
: this(exception.GetType().Name, exception.Message) : this(exception.GetType().Name, exception.Message)
{ {
Exception = exception; Exception = exception;
FillExtensionData(exception); ExtensionData = ExtractExtensionData(exception);
} }
internal ExceptionalError(string message, Exception exception) internal ExceptionalError(string message, Exception exception)
: this(exception.GetType().Name, message) : this(exception.GetType().Name, message)
{ {
Exception = exception; Exception = exception;
FillExtensionData(exception); ExtensionData = ExtractExtensionData(exception);
} }
[JsonConstructor] [JsonConstructor]
@@ -231,15 +210,28 @@ public sealed class ExceptionalError : Error
yield return this; yield return this;
} }
private void FillExtensionData(Exception exception) private static ImmutableDictionary<string, string>? ExtractExtensionData(Exception exception)
{ {
if (!(exception.Data?.Count > 0))
return null;
List<KeyValuePair<string, string>>? values = null;
foreach (var key in exception.Data.Keys) foreach (var key in exception.Data.Keys)
{ {
if (key is null) continue;
var value = exception.Data[key]; var value = exception.Data[key];
if (key is null || value is null) if (value is null) continue;
continue;
this.ExtensionData[key.ToString() ?? string.Empty] = value; var keyString = key.ToString();
var valueString = value.ToString();
if (string.IsNullOrEmpty(keyString) || string.IsNullOrEmpty(valueString)) continue;
values ??= [];
values.Add(new(keyString, valueString));
} }
return values?.ToImmutableDictionary();
} }
} }

View File

@@ -1,3 +1,5 @@
using System.Collections.Immutable;
namespace Railway.Tests.Errors; namespace Railway.Tests.Errors;
public class Serialization public class Serialization
@@ -8,9 +10,8 @@ public class Serialization
// Given // Given
Error many_errors = new ManyErrors(new Error[]{ Error many_errors = new ManyErrors(new Error[]{
new ExpectedError("err1", "msg1"){ new ExpectedError("err1", "msg1"){
ExtensionData = { ExtensionData = ImmutableDictionary<string, string>.Empty
["ext"] = "ext_value" .Add("ext", "ext_value"),
}
}, },
new ExceptionalError(new Exception("msg2")), new ExceptionalError(new Exception("msg2")),
}); });
@@ -18,7 +19,7 @@ public class Serialization
var result = JsonSerializer.Serialize(many_errors); var result = JsonSerializer.Serialize(many_errors);
// Then // Then
Assert.Equal( Assert.Equal(
expected: "[{\"$$err\":0,\"Type\":\"err1\",\"Message\":\"msg1\",\"ext\":\"ext_value\"},{\"$$err\":1,\"Type\":\"Exception\",\"Message\":\"msg2\"}]", expected: "[{\"$$err\":0,\"Type\":\"err1\",\"Message\":\"msg1\",\"ExtensionData\":{\"ext\":\"ext_value\"}},{\"$$err\":1,\"Type\":\"Exception\",\"Message\":\"msg2\"}]",
result); result);
} }
@@ -26,7 +27,7 @@ public class Serialization
public void WhenDeserializingManyErrors() public void WhenDeserializingManyErrors()
{ {
// Given // Given
var json = "[{\"$$err\":0,\"Type\":\"err1\",\"Message\":\"msg1\",\"ext\":\"ext_value\"},{\"$$err\":1,\"Type\":\"Exception\",\"Message\":\"msg2\"}]"; var json = "[{\"$$err\":0,\"Type\":\"err1\",\"Message\":\"msg1\",\"ExtensionData\":{\"ext1\":\"ext_value1\",\"ext2\":\"ext_value2\"}},{\"$$err\":1,\"Type\":\"Exception\",\"Message\":\"msg2\"}]";
// When // When
var result = JsonSerializer.Deserialize<Error[]>(json); var result = JsonSerializer.Deserialize<Error[]>(json);
// Then // Then
@@ -39,7 +40,10 @@ public class Serialization
result result
); );
Assert.Equal( Assert.Equal(
expected: "ext_value", expected: "ext_value1",
result[0].ExtensionData["ext"].ToString()); result[0]["ext1"]);
Assert.Equal(
expected: "ext_value2",
result[0]["ext2"]);
} }
} }