diff --git a/Railway/Error.cs b/Railway/Error.cs index 1b9c7d2..9396981 100644 --- a/Railway/Error.cs +++ b/Railway/Error.cs @@ -1,4 +1,5 @@ using System.Collections; +using System.Collections.Immutable; using System.Runtime.Serialization; using System.Text; @@ -10,8 +11,6 @@ namespace Just.Railway; [JsonDerivedType(typeof(ManyErrors))] public abstract class Error : IEquatable, IComparable { - private IDictionary? _extensionData; - protected internal Error(){} /// @@ -77,28 +76,8 @@ public abstract class Error : IEquatable, IComparable [Pure] public abstract string Type { get; } [Pure] public abstract string Message { get; } - [Pure, JsonExtensionData] public IDictionary ExtensionData - { - get => _extensionData ??= new Dictionary(); - init => _extensionData = value ?? new Dictionary(); - } - [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(); - _extensionData[name] = value; - } - } - } + [Pure, JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] public ImmutableDictionary? ExtensionData { get; init; } + [Pure] public string? this[string key] => ExtensionData?.TryGetValue(key, out var value) == true ? value : null; [Pure, JsonIgnore] public abstract int Count { get; } [Pure, JsonIgnore] public abstract bool IsEmpty { get; } @@ -199,13 +178,13 @@ public sealed class ExceptionalError : Error : this(exception.GetType().Name, exception.Message) { Exception = exception; - FillExtensionData(exception); + ExtensionData = ExtractExtensionData(exception); } internal ExceptionalError(string message, Exception exception) : this(exception.GetType().Name, message) { Exception = exception; - FillExtensionData(exception); + ExtensionData = ExtractExtensionData(exception); } [JsonConstructor] @@ -231,15 +210,28 @@ public sealed class ExceptionalError : Error yield return this; } - private void FillExtensionData(Exception exception) + private static ImmutableDictionary? ExtractExtensionData(Exception exception) { + if (!(exception.Data?.Count > 0)) + return null; + + List>? values = null; + foreach (var key in exception.Data.Keys) { + if (key is null) continue; + var value = exception.Data[key]; - if (key is null || value is null) - continue; - this.ExtensionData[key.ToString() ?? string.Empty] = value; + if (value is null) continue; + + 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(); } } diff --git a/Raliway.Tests/Errors/Serialization.cs b/Raliway.Tests/Errors/Serialization.cs index 19792b2..1d8e13f 100644 --- a/Raliway.Tests/Errors/Serialization.cs +++ b/Raliway.Tests/Errors/Serialization.cs @@ -1,3 +1,5 @@ +using System.Collections.Immutable; + namespace Railway.Tests.Errors; public class Serialization @@ -8,9 +10,8 @@ public class Serialization // Given Error many_errors = new ManyErrors(new Error[]{ new ExpectedError("err1", "msg1"){ - ExtensionData = { - ["ext"] = "ext_value" - } + ExtensionData = ImmutableDictionary.Empty + .Add("ext", "ext_value"), }, new ExceptionalError(new Exception("msg2")), }); @@ -18,7 +19,7 @@ public class Serialization var result = JsonSerializer.Serialize(many_errors); // Then 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); } @@ -26,7 +27,7 @@ public class Serialization public void WhenDeserializingManyErrors() { // 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 var result = JsonSerializer.Deserialize(json); // Then @@ -39,7 +40,10 @@ public class Serialization result ); Assert.Equal( - expected: "ext_value", - result[0].ExtensionData["ext"].ToString()); + expected: "ext_value1", + result[0]["ext1"]); + Assert.Equal( + expected: "ext_value2", + result[0]["ext2"]); } }