diff --git a/src/Elastic.Clients.Elasticsearch/_Generated/Types/Core/Context.Converters.g.cs b/src/Elastic.Clients.Elasticsearch/_Generated/Types/Core/Context.Converters.g.cs index 10a7d6440eb..d426428ec23 100644 --- a/src/Elastic.Clients.Elasticsearch/_Generated/Types/Core/Context.Converters.g.cs +++ b/src/Elastic.Clients.Elasticsearch/_Generated/Types/Core/Context.Converters.g.cs @@ -27,7 +27,7 @@ public sealed partial class ContextConverter : System.Text.Json.Serialization.Js { public override Elastic.Clients.Elasticsearch.Core.Search.Context Read(ref System.Text.Json.Utf8JsonReader reader, System.Type typeToConvert, System.Text.Json.JsonSerializerOptions options) { - var selector = static (ref System.Text.Json.Utf8JsonReader r, System.Text.Json.JsonSerializerOptions o) => JsonUnionSelector.ByPropertyOfT1(ref r, o, "dummy"); + var selector = static (ref System.Text.Json.Utf8JsonReader r, System.Text.Json.JsonSerializerOptions o) => JsonUnionSelector.Match(ref r, o, static (ref System.Text.Json.Utf8JsonReader r, System.Text.Json.JsonSerializerOptions o) => JsonUnionSelector.MatchTokenTypes(ref r, o, Elastic.Clients.Elasticsearch.Serialization.JsonTokenTypes.StartObject | Elastic.Clients.Elasticsearch.Serialization.JsonTokenTypes.StartArray, static (ref System.Text.Json.Utf8JsonReader r, System.Text.Json.JsonSerializerOptions o) => JsonUnionSelector.T2(ref r, o)), static (ref System.Text.Json.Utf8JsonReader r, System.Text.Json.JsonSerializerOptions o) => JsonUnionSelector.T1(ref r, o)); return selector(ref reader, options) switch { Elastic.Clients.Elasticsearch.UnionTag.T1 => new Elastic.Clients.Elasticsearch.Core.Search.Context(reader.ReadValue(options, null)), diff --git a/src/Elastic.Clients.Elasticsearch/_Shared/Next/JsonReaderExtensions.cs b/src/Elastic.Clients.Elasticsearch/_Shared/Next/JsonReaderExtensions.cs index 4dfffcc7df4..98fa0bee058 100644 --- a/src/Elastic.Clients.Elasticsearch/_Shared/Next/JsonReaderExtensions.cs +++ b/src/Elastic.Clients.Elasticsearch/_Shared/Next/JsonReaderExtensions.cs @@ -474,6 +474,9 @@ public static KeyValuePair ReadKeyValuePairValue(thi public static List? ReadSingleOrManyCollectionValue(this ref Utf8JsonReader reader, JsonSerializerOptions options, JsonReadFunc? readElement) { + // TODO: Allow passing a selector function to distinguish between single or many in complex scenarios + // (e.g. when the single element can be an array, see: GeoLocation). + if (reader.TokenType is JsonTokenType.Null) { return null; diff --git a/src/Elastic.Clients.Elasticsearch/_Shared/Next/JsonUnionSelector.cs b/src/Elastic.Clients.Elasticsearch/_Shared/Next/JsonUnionSelector.cs index c26a4d51ed1..32c24291900 100644 --- a/src/Elastic.Clients.Elasticsearch/_Shared/Next/JsonUnionSelector.cs +++ b/src/Elastic.Clients.Elasticsearch/_Shared/Next/JsonUnionSelector.cs @@ -3,7 +3,6 @@ // See the LICENSE file in the project root for more information. using System; -using System.Collections.Generic; using System.Text.Json; namespace Elastic.Clients.Elasticsearch.Serialization; @@ -38,47 +37,77 @@ internal enum JsonTokenTypes internal static class JsonUnionSelector { - public static UnionTag ByTokenType(ref Utf8JsonReader reader, JsonSerializerOptions options, JsonTokenTypes first, JsonTokenTypes second) + /// + /// A selector function that always returns . + /// + /// A reference to the instance. + /// The to use. + /// A static value of . + public static UnionTag None(ref Utf8JsonReader reader, JsonSerializerOptions options) + { + _ = reader; + _ = options; + return UnionTag.None; + } + + /// + /// A selector function that always returns . + /// + /// A reference to the instance. + /// The to use. + /// A static value of . + public static UnionTag T1(ref Utf8JsonReader reader, JsonSerializerOptions options) { _ = reader; _ = options; + return UnionTag.T1; + } - if (((int)first & (1 << (int)reader.TokenType)) is not 0) + /// + /// A selector function that always returns . + /// + /// A reference to the instance. + /// The to use. + /// A static value of . + public static UnionTag T2(ref Utf8JsonReader reader, JsonSerializerOptions options) + { + _ = reader; + _ = options; + return UnionTag.T2; + } + + // We avoid using a `params` array for performance reasons. Create `Match()` overloads with additional parameters as needed. + public static UnionTag Match(ref Utf8JsonReader reader, JsonSerializerOptions options, JsonUnionSelectorFunc case1, JsonUnionSelectorFunc case2) + { + if (case1(ref reader, options) is var tag1 and not UnionTag.None) { - return UnionTag.T1; + return tag1; } - if (((int)second & (1 << (int)reader.TokenType)) is not 0) + if (case2(ref reader, options) is var tag2 and not UnionTag.None) { - return UnionTag.T2; + return tag2; } return UnionTag.None; } - public static UnionTag ByPropertyOfT1(ref Utf8JsonReader reader, JsonSerializerOptions options, string name) + public static UnionTag MatchTokenTypes(ref Utf8JsonReader reader, JsonSerializerOptions options, JsonTokenTypes types, JsonUnionSelectorFunc next) { - reader.ValidateToken(JsonTokenType.StartObject); - - var internalReader = reader; - - while (internalReader.Read() && (internalReader.TokenType is JsonTokenType.PropertyName)) + if (((int)types & (1 << (int)reader.TokenType)) is not 0) { - if (internalReader.ValueTextEquals(name)) - { - return UnionTag.T1; - } - - internalReader.Read(); - internalReader.Skip(); + return next(ref reader, options); } - return UnionTag.T2; + return UnionTag.None; } - public static UnionTag ByPropertyOfT2(ref Utf8JsonReader reader, JsonSerializerOptions options, string name) + public static UnionTag MatchProperty(ref Utf8JsonReader reader, JsonSerializerOptions options, string name, UnionTag result) { - reader.ValidateToken(JsonTokenType.StartObject); + if (reader.TokenType is not JsonTokenType.StartObject) + { + return UnionTag.None; + } var internalReader = reader; @@ -86,13 +115,68 @@ public static UnionTag ByPropertyOfT2(ref Utf8JsonReader reader, JsonSerializerO { if (internalReader.ValueTextEquals(name)) { - return UnionTag.T2; + return result; } internalReader.Read(); internalReader.Skip(); } - return UnionTag.T1; + return UnionTag.None; + } + + /// + /// A selector function that selects a union variant based on the current JSON token type. + /// + /// A reference to the instance. + /// The to use. + /// The JSON token types that resolve to . + /// The JSON token types that resolve to . + /// + /// Either or if the current token type of matches one + /// of the provided JSON token types or , if not. + /// + public static UnionTag ByTokenType(ref Utf8JsonReader reader, JsonSerializerOptions options, JsonTokenTypes first, JsonTokenTypes second) + { + return Match(ref reader, options, + (ref r, o) => MatchTokenTypes(ref r, o, first, T1), + (ref r, o) => MatchTokenTypes(ref r, o, second, T2) + ); + } + + /// + /// A selector function that selects a union variant based on the current JSON token type. + /// + /// A reference to the instance. + /// The to use. + /// The property name to look for. + /// + /// if the points to an object that contains a property of the given + /// or , if not. + /// + public static UnionTag ByPropertyOfT1(ref Utf8JsonReader reader, JsonSerializerOptions options, string name) + { + return Match(ref reader, options, + (ref r, o) => MatchProperty(ref r, o, name, UnionTag.T1), + T2 + ); + } + + /// + /// A selector function that selects a union variant based on the current JSON token type. + /// + /// A reference to the instance. + /// The to use. + /// The property name to look for. + /// + /// if the points to an object that contains a property of the given + /// or , if not. + /// + public static UnionTag ByPropertyOfT2(ref Utf8JsonReader reader, JsonSerializerOptions options, string name) + { + return Match(ref reader, options, + (ref r, o) => MatchProperty(ref r, o, name, UnionTag.T2), + T1 + ); } }