Skip to content

Commit

Permalink
feat: add a property to a json object (#50)
Browse files Browse the repository at this point in the history
  • Loading branch information
Seddryck authored Sep 3, 2024
1 parent 7515d70 commit 0bc0ed0
Show file tree
Hide file tree
Showing 4 changed files with 137 additions and 3 deletions.
87 changes: 87 additions & 0 deletions Streamistry.Core/JsonObjectPropertyAppender.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Text;
using System.Text.Json.Nodes;
using System.Threading.Tasks;
using Json.More;
using Json.Path;


namespace Streamistry;
public class JsonObjectPropertyAppender<TInputMain, TInputSecondary> : Zipper<TInputMain, TInputSecondary, TInputMain>
where TInputMain : JsonNode
where TInputSecondary : JsonNode
{

public JsonObjectPropertyAppender(IChainablePort<TInputMain> mainUpstream, IChainablePort<TInputSecondary> secondUpstream, string path)
: base(mainUpstream, secondUpstream, (x, y) => AppendProperty(x, y, path))
{ }

private static TInputMain? AppendProperty(TInputMain? main, TInputSecondary? secondary, string path)
{
if (main is null)
return null;
if (secondary is null)
return main;
var segments = path.Split('.');
AddOrReplaceProperty(main, string.Join('.',segments.Take(segments.Length - 1)), path.Split('.').Last(), secondary);
return main;
}

private static void AddOrReplaceProperty(JsonNode root, string jsonPath, string propertyName, JsonNode value)
{
var path = JsonPath.Parse(jsonPath);
var result = path.Evaluate(root);

if (result.Matches != null && result.Matches.Count > 0)
{
foreach (var match in result.Matches)
{
if (match.Value is JsonObject jsonObject)
jsonObject[propertyName] = value;
}
}
else
{
CreatePathAndAddProperty(root, jsonPath, propertyName, value);
}
}

private static void CreatePathAndAddProperty(JsonNode root, string jsonPath, string propertyName, JsonNode value)
{
var segments = jsonPath.TrimStart('$').Split('.', StringSplitOptions.RemoveEmptyEntries);
JsonNode current = root;

foreach (var segment in segments)
{
if (current is JsonObject obj)
{
if (!obj.ContainsKey(segment))
{
var newObject = new JsonObject();
obj[segment] = newObject;
current = newObject;
}
else
{
current = obj[segment]!;
}
}
else
{
throw new InvalidOperationException("Invalid path or JSON structure.");
}
}

if (current is JsonObject finalObj)
{
finalObj[propertyName] = value;
}
else
{
throw new InvalidOperationException("Final path segment is not an object.");
}
}
}
15 changes: 15 additions & 0 deletions Streamistry.Core/JsonValueMapper.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.Json.Nodes;
using System.Threading.Tasks;

namespace Streamistry;
public class JsonValueMapper<TInput> : Mapper<TInput, JsonValue>
{
public JsonValueMapper(IChainablePort<TInput> upstream, Func<TInput?, string>? toString = null)
: base(upstream, value => toString is null ? JsonValue.Create(value) : JsonValue.Create(toString.Invoke(value)))
{
}
}
32 changes: 32 additions & 0 deletions Streamistry.Testing/JsonObjectPropertyAppenderTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.Json.Nodes;
using System.Threading.Tasks;
using NUnit.Framework;
using Streamistry.Pipes.Parsers;
using Streamistry.Pipes.Sinks;
using Streamistry.Pipes.Sources;

namespace Streamistry.Testing;
public class JsonObjectPropertyAppenderTests
{
[Test]
public void X()
{
var persons = new EnumerableSource<string>([
JsonTests.JsonFirst, JsonTests.JsonSecond, JsonTests.JsonThird]);
var birthdates = new EnumerableSource<DateOnly>([new DateOnly(1879, 3, 14), new DateOnly(1856, 7, 10), new DateOnly(1903, 12, 28)]);
var pipeline = new Pipeline([persons, birthdates]);
var personObject = new JsonObjectParser(persons);
var birthdateValue = new JsonValueMapper<DateOnly>(birthdates, date => date.ToString("yyyy-MM-dd"));
var appender = new JsonObjectPropertyAppender<JsonObject, JsonValue>(personObject, birthdateValue, "$.user.birthdate");
var sink = new MemorySink<JsonObject>(appender);
pipeline.Start();

Assert.That(sink.State.Count, Is.EqualTo(3));
Assert.That(sink.State.First()!["user"]!["birthdate"], Is.Not.Null);
Assert.That(sink.State.First()!["user"]!["birthdate"]!.GetValue<string>(), Is.EqualTo("1879-03-14"));
}
}
6 changes: 3 additions & 3 deletions Streamistry.Testing/JsonTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
namespace Streamistry.Testing;
public class JsonTests
{
private const string JsonFirst = @"
public const string JsonFirst = @"
{
""user"": {
""name"": ""Albert Einstein"",
Expand All @@ -27,7 +27,7 @@ public class JsonTests
}
}";

private const string JsonSecond = @"
public const string JsonSecond = @"
{
""user"": {
""name"": ""Nikola Tesla"",
Expand All @@ -39,7 +39,7 @@ public class JsonTests
}
}";

private const string JsonThird = @"
public const string JsonThird = @"
{
""user"": {
""name"": ""John von Neumann"",
Expand Down

0 comments on commit 0bc0ed0

Please sign in to comment.