Skip to content

Commit e6e2ce0

Browse files
feat: Add functionality to recursively convert proto Values to native
1 parent 74d12e6 commit e6e2ce0

File tree

2 files changed

+243
-22
lines changed

2 files changed

+243
-22
lines changed

Nitric.Sdk/Document/DocumentRef.cs

Lines changed: 33 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ namespace Nitric.Api.Document
2828
public readonly Key<T> Key;
2929
private readonly CollectionRef<T> collection;
3030

31+
protected DocumentRef() { }
3132
internal DocumentRef(
3233
DocumentServiceClient documentClient,
3334
CollectionRef<T> collection,
@@ -93,34 +94,44 @@ public CollectionRef<T> Collection(string name)
9394
}
9495

9596
//Utility function to convert a struct document to its generic counterpart
96-
private T DocumentToGeneric(Struct content)
97+
protected T DocumentToGeneric(Struct content)
9798
{
9899
T doc = new T();
99100
foreach (var kv in content.Fields)
100101
{
101-
switch (kv.Value.KindCase)
102-
{
103-
case Value.KindOneofCase.StringValue:
104-
doc.Add(kv.Key, kv.Value.StringValue);
105-
break;
106-
case Value.KindOneofCase.BoolValue:
107-
doc.Add(kv.Key, kv.Value.BoolValue);
108-
break;
109-
case Value.KindOneofCase.ListValue:
110-
doc.Add(kv.Key, kv.Value.ListValue);
111-
break;
112-
case Value.KindOneofCase.NumberValue:
113-
doc.Add(kv.Key, kv.Value.NumberValue);
114-
break;
115-
case Value.KindOneofCase.StructValue:
116-
doc.Add(kv.Key, kv.Value.StructValue);
117-
break;
118-
case Value.KindOneofCase.NullValue:
119-
doc.Add(kv.Key, kv.Value.NullValue);
120-
break;
121-
}
102+
doc.Add(kv.Key, UnwrapValue(kv.Value));
122103
}
123104
return doc;
124105
}
106+
private object UnwrapValue(Value value)
107+
{
108+
switch (value.KindCase)
109+
{
110+
case Value.KindOneofCase.StringValue:
111+
return value.StringValue;
112+
case Value.KindOneofCase.BoolValue:
113+
return value.BoolValue;
114+
case Value.KindOneofCase.NumberValue:
115+
return value.NumberValue;
116+
case Value.KindOneofCase.NullValue:
117+
return null;
118+
case Value.KindOneofCase.StructValue:
119+
Dictionary<string, object> unwrappedStruct = new Dictionary<string, object>();
120+
foreach (var kv in value.StructValue.Fields)
121+
{
122+
unwrappedStruct.Add(kv.Key, UnwrapValue(kv.Value));
123+
}
124+
return unwrappedStruct;
125+
case Value.KindOneofCase.ListValue:
126+
List<object> unwrappedList = new List<object>();
127+
foreach (Value v in value.ListValue.Values)
128+
{
129+
unwrappedList.Add(UnwrapValue(v));
130+
}
131+
return unwrappedList;
132+
default:
133+
throw new ArgumentException("Provide proto-value");
134+
}
135+
}
125136
}
126137
}
Lines changed: 210 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,210 @@
1+
using System;
2+
using System.Linq;
3+
using System.Collections.Generic;
4+
using Nitric.Api.Document;
5+
using Microsoft.VisualStudio.TestTools.UnitTesting;
6+
using Google.Protobuf.WellKnownTypes;
7+
namespace Nitric.Test.Api.Document
8+
{
9+
[TestClass]
10+
public class DocumentToGenericTest : DocumentRef<Dictionary<string, object>>
11+
{
12+
public string ToAssertableString(IDictionary<string, object> dictionary)
13+
{
14+
var pairStrings = dictionary.OrderBy(p => p.Key)
15+
.Select(p => p.Key + ": " + string.Join(", ", p.Value));
16+
return string.Join("; ", pairStrings);
17+
}
18+
[TestMethod]
19+
public void TestStructWithScalars()
20+
{
21+
var expected = new Dictionary<string, object>();
22+
expected.Add("string", "string");
23+
expected.Add("null", null);
24+
expected.Add("number", 1.0);
25+
expected.Add("boolean", true);
26+
27+
var genericStruct = new Struct();
28+
genericStruct.Fields.Add("string", Value.ForString("string"));
29+
genericStruct.Fields.Add("null", Value.ForNull());
30+
genericStruct.Fields.Add("number", Value.ForNumber(1.0));
31+
genericStruct.Fields.Add("boolean", Value.ForBool(true));
32+
33+
var genericDict = DocumentToGeneric(genericStruct);
34+
35+
Assert.AreEqual(ToAssertableString(expected), ToAssertableString(genericDict));
36+
}
37+
[TestMethod]
38+
public void TestStructWithList()
39+
{
40+
List<object> expectedList = new List<object>();
41+
expectedList.Add("string");
42+
expectedList.Add(null);
43+
expectedList.Add(1.0);
44+
expectedList.Add(true);
45+
46+
var expected = new Dictionary<string, object>();
47+
expected.Add("list", expectedList);
48+
49+
Value[] actualList = new Value[] {
50+
Value.ForString("string"),
51+
Value.ForNull(),
52+
Value.ForNumber(1),
53+
Value.ForBool(true),
54+
};
55+
56+
var genericStruct = new Struct();
57+
genericStruct.Fields.Add("list", Value.ForList(actualList));
58+
59+
var genericDict = DocumentToGeneric(genericStruct);
60+
61+
Assert.AreEqual(ToAssertableString(expected), ToAssertableString(genericDict));
62+
}
63+
[TestMethod]
64+
public void TestStructWithStruct()
65+
{
66+
var expected = new Struct();
67+
expected.Fields.Add("string", Value.ForString("string"));
68+
expected.Fields.Add("boolean", Value.ForBool(true));
69+
expected.Fields.Add("number", Value.ForNumber(1.0));
70+
expected.Fields.Add("null", Value.ForNull());
71+
72+
var genericStruct = new Struct();
73+
genericStruct.Fields.Add("struct", Value.ForStruct(expected));
74+
75+
var genericDict = DocumentToGeneric(genericStruct);
76+
77+
var fields = new Dictionary<string, object>();
78+
fields.Add("string", "string");
79+
fields.Add("boolean", true);
80+
fields.Add("number", 1.0);
81+
fields.Add("null", null);
82+
83+
var expectedResponse = new Dictionary<string, object>();
84+
expectedResponse.Add("struct", fields);
85+
86+
Assert.AreEqual(ToAssertableString(expectedResponse), ToAssertableString(genericDict));
87+
}
88+
[TestMethod]
89+
public void TestStructWithNestedLists()
90+
{
91+
List<object> nestedList2 = new List<object>();
92+
nestedList2.Add("string");
93+
nestedList2.Add(null);
94+
nestedList2.Add(1.0);
95+
nestedList2.Add(true);
96+
97+
List<object> nestedList1 = new List<object>();
98+
nestedList1.Add(nestedList2);
99+
nestedList1.Add(nestedList2);
100+
nestedList1.Add(nestedList2);
101+
102+
List<object> expectedList = new List<object>();
103+
expectedList.Add(nestedList1);
104+
expectedList.Add(nestedList1);
105+
expectedList.Add(nestedList1);
106+
107+
var expected = new Dictionary<string, object>();
108+
expected.Add("list", expectedList);
109+
110+
Value[] actualNestedList2 = new Value[]
111+
{
112+
Value.ForString("string"),
113+
Value.ForNull(),
114+
Value.ForNumber(1),
115+
Value.ForBool(true),
116+
};
117+
Value[] actualNestedList1 = new Value[]
118+
{
119+
Value.ForList(actualNestedList2),
120+
Value.ForList(actualNestedList2),
121+
Value.ForList(actualNestedList2),
122+
};
123+
Value[] actualList = new Value[]
124+
{
125+
Value.ForList(actualNestedList1),
126+
Value.ForList(actualNestedList1),
127+
Value.ForList(actualNestedList1),
128+
};
129+
130+
var genericStruct = new Struct();
131+
genericStruct.Fields.Add("list", Value.ForList(actualList));
132+
133+
var genericDict = DocumentToGeneric(genericStruct);
134+
135+
Assert.AreEqual(ToAssertableString(expected), ToAssertableString(genericDict));
136+
}
137+
[TestMethod]
138+
public void TestStructWithNestedListAndNestedStructs()
139+
{
140+
141+
Value[] nestedList3 = new Value[]
142+
{
143+
Value.ForString("string"),
144+
Value.ForNull(),
145+
Value.ForNumber(1),
146+
Value.ForBool(true),
147+
};
148+
149+
Value[] nestedList2 = new Value[]
150+
{
151+
Value.ForList(nestedList3),
152+
Value.ForList(nestedList3),
153+
Value.ForList(nestedList3),
154+
};
155+
156+
var nestedStruct1 = new Struct();
157+
nestedStruct1.Fields.Add("struct-list", Value.ForList(nestedList2));
158+
159+
List<object> nestedList1 = new List<object>();
160+
nestedList1.Add(nestedStruct1);
161+
nestedList1.Add(nestedStruct1);
162+
nestedList1.Add(nestedStruct1);
163+
164+
List<object> expectedList = new List<object>();
165+
expectedList.Add(nestedList1);
166+
expectedList.Add(nestedList1);
167+
expectedList.Add(nestedList1);
168+
169+
var expected = new Dictionary<string, object>();
170+
expected.Add("list", expectedList);
171+
172+
Value[] actualNestedList3 = new Value[]
173+
{
174+
Value.ForString("string"),
175+
Value.ForNull(),
176+
Value.ForNumber(1),
177+
Value.ForBool(true),
178+
};
179+
Value[] actualNestedList2 = new Value[]
180+
{
181+
Value.ForList(actualNestedList3),
182+
Value.ForList(actualNestedList3),
183+
Value.ForList(actualNestedList3),
184+
};
185+
186+
var actualNestedStruct1 = new Struct();
187+
actualNestedStruct1.Fields.Add("struct-list", Value.ForList(actualNestedList2));
188+
189+
Value[] actualNestedList1 = new Value[]
190+
{
191+
Value.ForStruct(actualNestedStruct1),
192+
Value.ForStruct(actualNestedStruct1),
193+
Value.ForStruct(actualNestedStruct1),
194+
};
195+
Value[] actualList = new Value[]
196+
{
197+
Value.ForList(actualNestedList1),
198+
Value.ForList(actualNestedList1),
199+
Value.ForList(actualNestedList1),
200+
};
201+
202+
var genericStruct = new Struct();
203+
genericStruct.Fields.Add("list", Value.ForList(actualList));
204+
205+
var genericDict = DocumentToGeneric(genericStruct);
206+
207+
Assert.AreEqual(ToAssertableString(expected), ToAssertableString(genericDict));
208+
}
209+
}
210+
}

0 commit comments

Comments
 (0)