Skip to content

Commit

Permalink
feat(csharp): add discriminator for deserialization (#2678)
Browse files Browse the repository at this point in the history
  • Loading branch information
morganleroi authored Feb 9, 2024
1 parent bd5b3a0 commit b36a3a6
Show file tree
Hide file tree
Showing 4 changed files with 34 additions and 35 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -22,16 +22,4 @@ internal static class JsonConfig
ConstructorHandling = ConstructorHandling.AllowNonPublicDefaultConstructor,
MissingMemberHandling = MissingMemberHandling.Ignore,
};

// When DeserializeOneOfSettings is used, we set MissingMemberHandling to Error to throw an exception if a property is missing
public static readonly JsonSerializerSettings DeserializeOneOfSettings = new()
{
Formatting = Formatting.None,
NullValueHandling = NullValueHandling.Ignore,
ContractResolver = Resolver,
ReferenceLoopHandling = ReferenceLoopHandling.Ignore,
DateParseHandling = DateParseHandling.DateTime,
ConstructorHandling = ConstructorHandling.AllowNonPublicDefaultConstructor,
MissingMemberHandling = MissingMemberHandling.Error,
};
}
8 changes: 6 additions & 2 deletions playground/csharp/Playground/Model/TestObject.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
using System.Runtime.Serialization;
using Algolia.Search.Models.Search;

public class TestObject : Hit
{
public string? value { get; set; }
public string? otherValue { get; set; }
[DataMember(Name = "value")]
public string? Value { get; set; }

[DataMember(Name = "otherValue")]
public string? OtherValue { get; set; }
}
27 changes: 15 additions & 12 deletions playground/csharp/Playground/Playgrounds/Search.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
using System.Diagnostics;
using Algolia.Search.Clients;
using Algolia.Search.Exceptions;
using Algolia.Search.Models.Common;
Expand Down Expand Up @@ -28,7 +27,7 @@ public static async Task Run(Configuration configuration)


var loggerFactory = LoggerFactory.Create(i => i.AddFilter("Algolia", LogLevel.Information)
.AddConsole());
.AddConsole());

var client = new SearchClient(searchConfig, loggerFactory);

Expand Down Expand Up @@ -75,7 +74,8 @@ await PlaygroundHelper.Start(
Console.WriteLine("--- Browse all objects, one page `BrowseAsync` ---");
var r = await client.BrowseAsync<TestObject>(defaultIndex,
new BrowseParams(new BrowseParamsObject { HitsPerPage = 100 }));
r.Hits.ForEach(h => Console.WriteLine($" - Record ObjectID: {h.ObjectID}"));
r.Hits.ForEach(h => Console.WriteLine($" - Record ObjectID: {h.ObjectID}, {h.AdditionalProperties.Count}"));


// Browse Helper, to fetch all pages
Console.WriteLine("--- Browse all objects, all pages `BrowseObjectsAsync` ---");
Expand All @@ -102,14 +102,13 @@ await PlaygroundHelper.Start(

var getObjResults = await client.GetObjectsAsync<TestObject>(new GetObjectsParams(getObjRequests));
getObjResults.Results.ForEach(t =>
Console.WriteLine($" - Record ObjectID: {t.ObjectID} - Property `otherValue`: {t.otherValue}"));
Console.WriteLine($" - Record ObjectID: {t.ObjectID} - Property `otherValue`: {t.OtherValue}"));

// Search single index
Console.WriteLine("--- Search single index `SearchSingleIndexAsync` ---");
var t = await client.SearchSingleIndexAsync<TestObject>(defaultIndex);
t.Hits.ForEach(h => Console.WriteLine($" - Record ObjectID: {h.ObjectID}"));

// Search
Console.WriteLine("--- Search multiple indices `SearchAsync` ---");
var searchQueries = new List<SearchQuery>
{
Expand All @@ -122,7 +121,8 @@ await PlaygroundHelper.Start(
{
if (result.IsSearchResponse())
{
Console.WriteLine($"Record with Hits: ObjectID = {result.AsSearchResponse().Hits.First().ObjectID}");
Console.WriteLine(
$"Record with Hits: ObjectID = {result.AsSearchResponse().Hits.First().ObjectID}, {result.AsSearchResponse().Hits.First().AdditionalProperties.Count}");
}
else if (result.IsSearchForFacetValuesResponse())
{
Expand Down Expand Up @@ -189,7 +189,7 @@ await PlaygroundHelper.Start("Deleting API Key", async () =>
},
}).ConfigureAwait(false);

await PlaygroundHelper.Start("Creating new Synonyms - Async TaskID: `{synonymsResponse.TaskID}`", async () =>
await PlaygroundHelper.Start($"Creating new Synonyms - Async TaskID: `{synonymsResponse.TaskID}`", async () =>
await client.WaitForTaskAsync(defaultIndex, synonymsResponse.TaskID), "New Synonyms has been created !");

// Search Synonyms
Expand All @@ -198,13 +198,16 @@ await PlaygroundHelper.Start("Deleting API Key", async () =>
.SearchSynonymsAsync(defaultIndex,
new SearchSynonymsParams { Query = "", Type = SynonymType.Onewaysynonym, HitsPerPage = 1 })
.ConfigureAwait(false);
Console.WriteLine(searchSynonymsAsync.Hits.Count);

searchSynonymsAsync.Hits.ForEach(s => Console.WriteLine("Found :" + string.Join(',', s.Synonyms)));

// Browse Synonyms
// var configuredTaskAwaitable = await client
// .BrowseSynonymsAsync("test-csharp-new-client", SynonymType.Onewaysynonym, new SearchSynonymsParams { Query = "" })
// .ConfigureAwait(false);
// configuredTaskAwaitable.ToList().ForEach(s => Console.WriteLine("Found :" + string.Join(',', s.Synonyms)));
Console.WriteLine("--- Browse Synonyms `BrowseSynonymsAsync` ---");
var configuredTaskAwaitable = await client
.BrowseSynonymsAsync("test-csharp-new-client",
new SearchSynonymsParams { Query = "", Type = SynonymType.Onewaysynonym })
.ConfigureAwait(false);
configuredTaskAwaitable.ToList().ForEach(s => Console.WriteLine("Found :" + string.Join(',', s.Synonyms)));

// Add Rule
Console.WriteLine("--- Create new Rule `SaveRulesAsync` ---");
Expand Down
22 changes: 13 additions & 9 deletions templates/csharp/modelOneOf.mustache
Original file line number Diff line number Diff line change
Expand Up @@ -150,16 +150,20 @@
{{/discriminator}}
{{/useOneOfDiscriminatorLookup}}
{{#vendorExtensions}}
var jToken = JToken.Parse(jsonString);
{{#composedSchemas.oneOf}}
try
{
return new {{classname}}{{#x-has-child-generic}}<T>{{/x-has-child-generic}}(JsonConvert.DeserializeObject<{{{datatypeWithEnum}}}{{#vendorExtensions.x-has-child-generic}}<T>{{/vendorExtensions.x-has-child-generic}}>(jsonString, JsonConfig.DeserializeOneOfSettings));
}
catch (Exception exception)
{
// deserialization failed, try the next one
System.Diagnostics.Debug.WriteLine($"Failed to deserialize `{jsonString}` into {{{datatypeWithEnum}}}: {exception}");
}
if (jToken.Type == JTokenType.{{#isModel}}Object{{#vendorExtensions.x-discriminator-fields}} && jToken["{{{.}}}"] != null{{/vendorExtensions.x-discriminator-fields}}{{/isModel}}{{#isEnumRef}}String{{/isEnumRef}}{{#isArray}}Array{{/isArray}}{{#isInteger}}Integer{{/isInteger}}{{#isLong}}Integer{{/isLong}}{{#isDouble}}Float{{/isDouble}}{{#isBoolean}}Boolean{{/isBoolean}}{{#isString}}String{{/isString}}{{^isEnumRef}}{{^isModel}}{{^isArray}}{{^isInteger}}{{^isLong}}{{^isDouble}}{{^isBoolean}}{{^isString}}Object{{/isString}}{{/isBoolean}}{{/isDouble}}{{/isLong}}{{/isInteger}}{{/isArray}}{{/isModel}}{{/isEnumRef}})
{
try
{
return new {{classname}}{{#x-has-child-generic}}<T>{{/x-has-child-generic}}(JsonConvert.DeserializeObject<{{{datatypeWithEnum}}}{{#vendorExtensions.x-has-child-generic}}<T>{{/vendorExtensions.x-has-child-generic}}>(jsonString, JsonConfig.AlgoliaJsonSerializerSettings));
}
catch (Exception exception)
{
// deserialization failed, try the next one
System.Diagnostics.Debug.WriteLine($"Failed to deserialize `{jsonString}` into {{{datatypeWithEnum}}}: {exception}");
}
}
{{/composedSchemas.oneOf}}
{{/vendorExtensions}}

Expand Down

0 comments on commit b36a3a6

Please sign in to comment.