Skip to content

Commit a59356b

Browse files
authored
refactor: add key value pair json encoder (#104)
1 parent bd804b6 commit a59356b

File tree

5 files changed

+205
-2
lines changed

5 files changed

+205
-2
lines changed
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
using System.Text.Json;
2+
3+
namespace AzureAppConfigurationEmulator.Common;
4+
5+
public interface IKeyValuePairJsonEncoder
6+
{
7+
JsonDocument Encode(
8+
IEnumerable<KeyValuePair<string, string?>> pairs,
9+
string? prefix = null,
10+
string? separator = null);
11+
}
Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
using System.Text.Json;
2+
using System.Text.Json.Nodes;
3+
4+
namespace AzureAppConfigurationEmulator.Common;
5+
6+
public class KeyValuePairJsonEncoder : IKeyValuePairJsonEncoder
7+
{
8+
public JsonDocument Encode(
9+
IEnumerable<KeyValuePair<string, string?>> pairs,
10+
string? prefix = null,
11+
string? separator = null)
12+
{
13+
JsonNode root = new JsonObject();
14+
15+
foreach (var (key, value) in pairs)
16+
{
17+
var keys = key.Split(separator).ToList();
18+
19+
if (!string.IsNullOrEmpty(prefix))
20+
{
21+
if (keys[0] == prefix)
22+
{
23+
keys.RemoveAt(0);
24+
}
25+
else if (keys[0].StartsWith(prefix))
26+
{
27+
keys[0] = keys[0][prefix.Length..];
28+
}
29+
}
30+
31+
var current = root;
32+
33+
for (var i = 0; i < keys.Count; i++)
34+
{
35+
if (int.TryParse(keys[i], out var index))
36+
{
37+
if (i == keys.Count - 1)
38+
{
39+
current.AsArray().Insert(index, value);
40+
41+
break;
42+
}
43+
44+
if (current.AsArray().ElementAtOrDefault(index) is not { } next)
45+
{
46+
if (int.TryParse(keys[i + 1], out _))
47+
{
48+
next = new JsonArray();
49+
}
50+
else
51+
{
52+
next = new JsonObject();
53+
}
54+
55+
current.AsArray().Insert(index, next);
56+
}
57+
58+
current = next;
59+
}
60+
else
61+
{
62+
if (i == keys.Count - 1)
63+
{
64+
current[keys[i]] = value;
65+
66+
break;
67+
}
68+
69+
if (current[keys[i]] is not { } next)
70+
{
71+
if (int.TryParse(keys[i + 1], out _))
72+
{
73+
next = new JsonArray();
74+
}
75+
else
76+
{
77+
next = new JsonObject();
78+
}
79+
80+
current[keys[i]] = next;
81+
}
82+
83+
current = next;
84+
}
85+
}
86+
}
87+
88+
return root.Deserialize<JsonDocument>()!;
89+
}
90+
}

src/AzureAppConfigurationEmulator/Program.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,7 @@
8787
builder.Services.AddSingleton<IDbParameterFactory, SqliteDbParameterFactory>();
8888
builder.Services.AddSingleton<IEventGridEventFactory, HttpContextEventGridEventFactory>();
8989
builder.Services.AddSingleton<IKeyValuePairJsonDecoder, KeyValuePairJsonDecoder>();
90+
builder.Services.AddSingleton<IKeyValuePairJsonEncoder, KeyValuePairJsonEncoder>();
9091

9192
var app = builder.Build();
9293

tests/AzureAppConfigurationEmulator.Tests/Common/KeyValuePairJsonDecoderTests.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ public void SetUp()
1515
}
1616

1717
[TestCaseSource(nameof(Decode_KeyValuePairs_DocumentAndPrefixAndSeparator_TestCases))]
18-
public void Decode_KeyValuePairs_DocumentAndPrefixAndSeparator(string json, string? prefix, string? separator, IDictionary<string, string?> expected)
18+
public void Decode_KeyValuePairs_DocumentAndPrefixAndSeparator(string json, string? prefix, string? separator, IEnumerable<KeyValuePair<string, string?>> expected)
1919
{
2020
// Arrange
2121
using var document = JsonDocument.Parse(json);
@@ -24,7 +24,7 @@ public void Decode_KeyValuePairs_DocumentAndPrefixAndSeparator(string json, stri
2424
var settings = Decoder.Decode(document, prefix, separator);
2525

2626
// Assert
27-
Assert.That(settings.ToDictionary(), Is.EqualTo(expected));
27+
Assert.That(settings, Is.EqualTo(expected));
2828
}
2929

3030
// ReSharper disable once InconsistentNaming
Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
using System.Text.Json;
2+
using AzureAppConfigurationEmulator.Common;
3+
using NUnit.Framework;
4+
5+
namespace AzureAppConfigurationEmulator.Tests.Common;
6+
7+
public class KeyValuePairJsonEncoderTests
8+
{
9+
private KeyValuePairJsonEncoder Encoder { get; set; }
10+
11+
[SetUp]
12+
public void SetUp()
13+
{
14+
Encoder = new KeyValuePairJsonEncoder();
15+
}
16+
17+
[TestCaseSource(nameof(Encode_Document_KeyValuePairsAndPrefixAndSeparator_TestCases))]
18+
public void Encode_Document_KeyValuePairsAndPrefixAndSeparator(IEnumerable<KeyValuePair<string, string?>> pairs, string? prefix, string? separator, string expected)
19+
{
20+
// Act
21+
using var document = Encoder.Encode(pairs, prefix, separator);
22+
23+
// Assert
24+
Assert.That(JsonSerializer.Serialize(document), Is.EqualTo(expected));
25+
}
26+
27+
// ReSharper disable once InconsistentNaming
28+
private static object[] Encode_Document_KeyValuePairsAndPrefixAndSeparator_TestCases =
29+
[
30+
new object?[]
31+
{
32+
new Dictionary<string, string?> { { "TestKey", "TestValue" } },
33+
null,
34+
null,
35+
"{\"TestKey\":\"TestValue\"}"
36+
},
37+
new object?[]
38+
{
39+
new Dictionary<string, string?> { { "TestPrefixTestKey", "TestValue" } },
40+
"TestPrefix",
41+
null,
42+
"{\"TestKey\":\"TestValue\"}"
43+
},
44+
new object?[]
45+
{
46+
new Dictionary<string, string?> { { "TestKey", "TestValue" } },
47+
null,
48+
".",
49+
"{\"TestKey\":\"TestValue\"}"
50+
},
51+
new object?[]
52+
{
53+
new Dictionary<string, string?> { { "TestPrefix.TestKey", "TestValue" } },
54+
"TestPrefix",
55+
".",
56+
"{\"TestKey\":\"TestValue\"}"
57+
},
58+
new object?[]
59+
{
60+
new Dictionary<string, string?> { { "TestOuterKey.TestInnerKey", "TestValue" } },
61+
null,
62+
".",
63+
"{\"TestOuterKey\":{\"TestInnerKey\":\"TestValue\"}}"
64+
},
65+
new object?[]
66+
{
67+
new Dictionary<string, string?> { { "TestPrefix.TestOuterKey.TestInnerKey", "TestValue" } },
68+
"TestPrefix",
69+
".",
70+
"{\"TestOuterKey\":{\"TestInnerKey\":\"TestValue\"}}"
71+
},
72+
new object?[]
73+
{
74+
new Dictionary<string, string?> { { "TestKey.0", "TestValue" } },
75+
null,
76+
".",
77+
"{\"TestKey\":[\"TestValue\"]}"
78+
},
79+
new object?[]
80+
{
81+
new Dictionary<string, string?> { { "TestPrefix.TestKey.0", "TestValue" } },
82+
"TestPrefix",
83+
".",
84+
"{\"TestKey\":[\"TestValue\"]}"
85+
},
86+
new object?[]
87+
{
88+
new Dictionary<string, string?> { { "TestOuterKey.0.TestInnerKey", "TestValue" } },
89+
null,
90+
".",
91+
"{\"TestOuterKey\":[{\"TestInnerKey\":\"TestValue\"}]}"
92+
},
93+
new object?[]
94+
{
95+
new Dictionary<string, string?> { { "TestPrefix.TestOuterKey.0.TestInnerKey", "TestValue" } },
96+
"TestPrefix",
97+
".",
98+
"{\"TestOuterKey\":[{\"TestInnerKey\":\"TestValue\"}]}"
99+
}
100+
];
101+
}

0 commit comments

Comments
 (0)