Skip to content

Commit 6640d76

Browse files
authored
Merge pull request #322 from Turnerj/dynamic-getter-setter
Add TrySetValue and TryGetValue
2 parents 95305ee + e02677e commit 6640d76

File tree

5 files changed

+265
-1
lines changed

5 files changed

+265
-1
lines changed

Source/Common/JsonLdObject.cs

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
namespace Schema.NET
22
{
33
using System;
4+
using System.Collections.Generic;
45
using System.Runtime.Serialization;
56
using Newtonsoft.Json;
67

@@ -45,6 +46,39 @@ public class JsonLdObject : IEquatable<JsonLdObject>
4546
[DataMember(Name = "@id", Order = 2)]
4647
public virtual Uri? Id { get; set; }
4748

49+
/// <summary>
50+
/// Attempts to set the Schema.org <paramref name="property"/> on the current object with the specified <paramref name="value"/>.
51+
/// </summary>
52+
/// <param name="property">The property to set the value on.</param>
53+
/// <param name="value">The value to set on the property</param>
54+
/// <returns><see langword="true"/> when the value has successfully been set; otherwise, <see langword="false"/>.</returns>
55+
public virtual bool TrySetValue(string property, IEnumerable<object> value) => false;
56+
57+
/// <summary>
58+
/// Attempts to retrieve the value for <paramref name="property"/>.
59+
/// </summary>
60+
/// <param name="property">The property to get the value from.</param>
61+
/// <param name="result">The value on the property.</param>
62+
/// <returns><see langword="true"/> when the value has successfully been retrieved; otherwise, <see langword="false"/>.</returns>
63+
public virtual bool TryGetValue(string property, out IValues? result)
64+
{
65+
result = default;
66+
return false;
67+
}
68+
69+
/// <summary>
70+
/// Attempts to retrieve the <typeparamref name="TValue"/> from <paramref name="property"/>.
71+
/// </summary>
72+
/// <typeparam name="TValue">The type of value you want to retrieve.</typeparam>
73+
/// <param name="property">The property to get the value from.</param>
74+
/// <param name="result">The value on the property.</param>
75+
/// <returns><see langword="true"/> when the value has successfully been retrieved; otherwise, <see langword="false"/>.</returns>
76+
public virtual bool TryGetValue<TValue>(string property, out OneOrMany<TValue> result)
77+
{
78+
result = default;
79+
return false;
80+
}
81+
4882
/// <inheritdoc/>
4983
public bool Equals(JsonLdObject? other)
5084
{

Tests/Schema.NET.Test/ThingTest.cs

Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -199,6 +199,135 @@ public void ToStringWithNullAssignedProperty_ReturnsExpectedJsonLd()
199199
Assert.Equal(expectedJson, thing.ToString());
200200
}
201201

202+
[Fact]
203+
public void TrySetValue_ValidProperty()
204+
{
205+
var thing = new Thing();
206+
207+
Assert.True(thing.TrySetValue("Name", new[] { "TestName" }));
208+
Assert.Equal("TestName", thing.Name);
209+
}
210+
211+
[Fact]
212+
public void TrySetValue_InvalidProperty()
213+
{
214+
var thing = new Thing();
215+
216+
Assert.False(thing.TrySetValue("InvalidName", new[] { "TestName" }));
217+
}
218+
219+
[Fact]
220+
public void TrySetValue_CaseInsensitive()
221+
{
222+
var thing = new Thing();
223+
224+
Assert.True(thing.TrySetValue("name", new[] { "TestName" }));
225+
Assert.Equal("TestName", thing.Name);
226+
}
227+
228+
[Fact]
229+
public void TryGetValue_ValidProperty_OneOrMany()
230+
{
231+
var thing = new Thing
232+
{
233+
Name = "TestName",
234+
};
235+
236+
Assert.True(thing.TryGetValue("Name", out var result));
237+
var name = Assert.Single(result);
238+
Assert.Equal("TestName", name);
239+
}
240+
241+
[Fact]
242+
public void TryGetValue_ValidProperty_Values()
243+
{
244+
var thing = new Thing
245+
{
246+
Identifier = new Uri("https://example.org/test-identifier"),
247+
};
248+
249+
Assert.True(thing.TryGetValue("Identifier", out var result));
250+
var identifier = Assert.Single(result);
251+
Assert.Equal(new Uri("https://example.org/test-identifier"), identifier);
252+
}
253+
254+
[Fact]
255+
public void TryGetValue_InvalidProperty_InvalidName()
256+
{
257+
var thing = new Thing();
258+
259+
Assert.False(thing.TryGetValue("InvalidName", out _));
260+
}
261+
262+
[Fact]
263+
public void TryGetValue_CaseInsensitive()
264+
{
265+
var thing = new Thing
266+
{
267+
Name = "TestName",
268+
};
269+
270+
Assert.True(thing.TryGetValue("name", out var result));
271+
var name = Assert.Single(result);
272+
Assert.Equal("TestName", name);
273+
}
274+
275+
[Fact]
276+
public void TryGetValue_Generic_ValidProperty_OneOrMany()
277+
{
278+
var thing = new Thing
279+
{
280+
Name = "TestName",
281+
};
282+
283+
Assert.True(thing.TryGetValue<string>("Name", out var result));
284+
Assert.Equal("TestName", result);
285+
}
286+
287+
[Fact]
288+
public void TryGetValue_Generic_ValidProperty_Values()
289+
{
290+
var thing = new Thing
291+
{
292+
Identifier = new Uri("https://example.org/test-identifier"),
293+
};
294+
295+
Assert.True(thing.TryGetValue<Uri>("Identifier", out var result));
296+
var identifier = Assert.Single(result);
297+
Assert.Equal(new Uri("https://example.org/test-identifier"), identifier);
298+
}
299+
300+
[Fact]
301+
public void TryGetValue_Generic_InvalidProperty_InvalidName()
302+
{
303+
var thing = new Thing();
304+
305+
Assert.False(thing.TryGetValue<string>("InvalidName", out _));
306+
}
307+
308+
[Fact]
309+
public void TryGetValue_Generic_InvalidProperty_InvalidType()
310+
{
311+
var thing = new Thing
312+
{
313+
Name = "TestName",
314+
};
315+
316+
Assert.False(thing.TryGetValue<Uri>("Name", out _));
317+
}
318+
319+
[Fact]
320+
public void TryGetValue_Generic_CaseInsensitive()
321+
{
322+
var thing = new Thing
323+
{
324+
Name = "TestName",
325+
};
326+
327+
Assert.True(thing.TryGetValue<string>("name", out var result));
328+
Assert.Equal("TestName", result);
329+
}
330+
202331
private static void CompareEqual<T>(T a, T? b)
203332
{
204333
Assert.NotNull(a);

Tools/Schema.NET.Tool/GeneratorModels/GeneratorSchemaProperty.cs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,11 +28,13 @@ public GeneratorSchemaProperty(GeneratorSchemaClass @class, string jsonName, str
2828

2929
public ICollection<GeneratorSchemaPropertyType> Types { get; } = new List<GeneratorSchemaPropertyType>();
3030

31+
public IEnumerable<string> CSharpTypes => this.Types.SelectMany(x => x.CSharpTypeStrings);
32+
3133
public string PropertyTypeString
3234
{
3335
get
3436
{
35-
var propertyTypes = this.Types.SelectMany(x => x.CSharpTypeStrings).ToArray();
37+
var propertyTypes = this.CSharpTypes.ToArray();
3638
var propertyTypesString = string.Join(", ", propertyTypes);
3739
if (propertyTypes.Length == 1)
3840
{

Tools/Schema.NET.Tool/SchemaSourceGenerator.cs

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,7 @@ private static string RenderClass(GeneratorSchemaClass schemaClass)
9393
$@"namespace Schema.NET
9494
{{
9595
using System;
96+
using System.Collections.Generic;
9697
using System.Runtime.Serialization;
9798
using Newtonsoft.Json;
9899
@@ -126,6 +127,81 @@ public partial interface I{schemaClass.Name}{interfaceImplements}
126127
[JsonConverter(typeof({property.JsonConverterType}))]
127128
public{GetAccessModifier(property)} {property.PropertyTypeString} {property.Name} {{ get; set; }}")}
128129

130+
/// <inheritdoc/>
131+
public override bool TrySetValue(string property, IEnumerable<object> value)
132+
{{
133+
if (string.IsNullOrWhiteSpace(property))
134+
{{
135+
return false;
136+
}}
137+
138+
var success = false;
139+
{SourceUtility.RenderItems(allProperties, property => $@"if (""{property.Name}"".Equals(property, StringComparison.OrdinalIgnoreCase))
140+
{{
141+
this.{property.Name} = new(value);
142+
success = true;
143+
}}
144+
else ")}
145+
{{
146+
success = base.TrySetValue(property, value);
147+
}}
148+
149+
return success;
150+
}}
151+
152+
/// <inheritdoc/>
153+
public override bool TryGetValue<TValue>(string property, out OneOrMany<TValue> result)
154+
{{
155+
if (string.IsNullOrWhiteSpace(property))
156+
{{
157+
result = default;
158+
return false;
159+
}}
160+
161+
var success = false;
162+
{SourceUtility.RenderItems(allProperties, property => $@"if (""{property.Name}"".Equals(property, StringComparison.OrdinalIgnoreCase))
163+
{{
164+
{SourceUtility.RenderItems(property.CSharpTypes, (propertyType, index) => $@"if (typeof({propertyType}) == typeof(TValue))
165+
{{
166+
result = (OneOrMany<TValue>)(IValues)this.{property.Name}{(property.CSharpTypes.Count() > 1 ? $".Value{index + 1}" : string.Empty)};
167+
success = true;
168+
}}
169+
else ")}
170+
{{
171+
result = default;
172+
}}
173+
}}
174+
else ")}
175+
{{
176+
success = base.TryGetValue(property, out result);
177+
}}
178+
179+
return success;
180+
}}
181+
182+
/// <inheritdoc/>
183+
public override bool TryGetValue(string property, out IValues result)
184+
{{
185+
if (string.IsNullOrWhiteSpace(property))
186+
{{
187+
result = default;
188+
return false;
189+
}}
190+
191+
var success = false;
192+
{SourceUtility.RenderItems(allProperties, property => $@"if (""{property.Name}"".Equals(property, StringComparison.OrdinalIgnoreCase))
193+
{{
194+
result = (IValues)this.{property.Name};
195+
success = true;
196+
}}
197+
else ")}
198+
{{
199+
success = base.TryGetValue(property, out result);
200+
}}
201+
202+
return success;
203+
}}
204+
129205
/// <inheritdoc/>
130206
public bool Equals({schemaClass.Name} other)
131207
{{

Tools/Schema.NET.Tool/SourceUtility.cs

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,29 @@ public static string RenderItems<T>(IEnumerable<T> items, Func<T, string> action
4242
return stringBuilder.ToString();
4343
}
4444

45+
public static string RenderItems<T>(IEnumerable<T> items, Func<T, int, string> action)
46+
{
47+
if (items is null)
48+
{
49+
throw new ArgumentNullException(nameof(items));
50+
}
51+
52+
if (action is null)
53+
{
54+
throw new ArgumentNullException(nameof(action));
55+
}
56+
57+
var stringBuilder = new StringBuilder();
58+
var i = 0;
59+
foreach (var item in items)
60+
{
61+
stringBuilder.Append(action(item, i));
62+
i++;
63+
}
64+
65+
return stringBuilder.ToString();
66+
}
67+
4568
public static string RenderDoc(int indent, string? text)
4669
{
4770
if (text == null)

0 commit comments

Comments
 (0)