Skip to content

Commit ef5e577

Browse files
floberndkarl-sjogrenYohDeadfall
authored andcommitted
Community backports for 8.1.3 (#7793)
* DoubleWithFractionalPortionConverter and FloatWithFractionalPortionConverter should not fall through to always throw a JSONException for non NETCore builds (#7753) * Complted buckets JSON converter (#7738) * Boosted non-exhaustive enum deserialization (#7737) * Optimized `FieldConverter` (#7736) * Removed unused JsonIgnore (#7735) * Fixed the equality contract on Metrics type (#7733) * No allocations in ResponseItem IsValid prop (#7731) * Refactoring and tiny behavior fix for Ids (#7730) --------- Co-authored-by: Karl-Johan Sjögren <[email protected]> Co-authored-by: Yoh Deadfall <[email protected]>
1 parent b409fb5 commit ef5e577

25 files changed

+156
-100
lines changed

Diff for: src/Elastic.Clients.Elasticsearch/Api/ResponseItem.cs

+14-5
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22
// Elasticsearch B.V licenses this file to you under the Apache 2.0 License.
33
// See the LICENSE file in the project root for more information.
44

5+
using System;
6+
57
namespace Elastic.Clients.Elasticsearch.Core.Bulk;
68

79
public abstract partial class ResponseItem
@@ -15,12 +17,19 @@ public bool IsValid
1517
if (Error is not null)
1618
return false;
1719

18-
return Operation.ToLowerInvariant() switch
20+
var operation = Operation;
21+
22+
if (operation.Equals("delete", StringComparison.OrdinalIgnoreCase))
23+
return Status is 200 or 404;
24+
25+
if (operation.Equals("create", StringComparison.OrdinalIgnoreCase) ||
26+
operation.Equals("update", StringComparison.OrdinalIgnoreCase) ||
27+
operation.Equals("index", StringComparison.OrdinalIgnoreCase))
1928
{
20-
"delete" => Status == 200 || Status == 404,
21-
"update" or "index" or "create" => Status == 200 || Status == 201,
22-
_ => false,
23-
};
29+
return Status is 200 or 201;
30+
}
31+
32+
return false;
2433
}
2534
}
2635
}
+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
// Licensed to Elasticsearch B.V under one or more agreements.
2+
// Elasticsearch B.V licenses this file to you under the Apache 2.0 License.
3+
// See the LICENSE file in the project root for more information.
4+
5+
namespace Elastic.Clients.Elasticsearch.Core;
6+
7+
internal interface IEnumStruct<TSelf> where TSelf : struct, IEnumStruct<TSelf>
8+
{
9+
// TODO: Can be made static when targeting .NET 7 and higher
10+
TSelf Create(string value);
11+
}

Diff for: src/Elastic.Clients.Elasticsearch/Core/Infer/Field/Field.cs

-1
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,6 @@ public Field(PropertyInfo property, double? boost = null, string format = null)
7373
/// </remarks>
7474
public string? Format { get; set; }
7575

76-
[JsonIgnore]
7776
internal bool CachableExpression { get; }
7877

7978
/// <summary>

Diff for: src/Elastic.Clients.Elasticsearch/Core/Infer/Field/FieldConverter.cs

+18-23
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,9 @@ namespace Elastic.Clients.Elasticsearch;
1212

1313
internal sealed class FieldConverter : JsonConverter<Field>
1414
{
15+
private static readonly JsonEncodedText FieldProperty = JsonEncodedText.Encode("field");
16+
private static readonly JsonEncodedText FormatProperty = JsonEncodedText.Encode("format");
17+
1518
private IElasticsearchClientSettings _settings;
1619

1720
public override void WriteAsPropertyName(Utf8JsonWriter writer, Field value, JsonSerializerOptions options)
@@ -48,19 +51,19 @@ private static Field ReadObjectField(ref Utf8JsonReader reader)
4851
{
4952
if (reader.TokenType == JsonTokenType.PropertyName)
5053
{
51-
var propertyName = reader.GetString();
52-
reader.Read();
53-
54-
switch (propertyName)
54+
if (reader.ValueTextEquals(FieldProperty.EncodedUtf8Bytes))
55+
{
56+
reader.Read();
57+
field = reader.GetString();
58+
}
59+
else if (reader.ValueTextEquals(FormatProperty.EncodedUtf8Bytes))
60+
{
61+
reader.Read();
62+
format = reader.GetString();
63+
}
64+
else
5565
{
56-
case "field":
57-
field = reader.GetString();
58-
break;
59-
case "format":
60-
format = reader.GetString();
61-
break;
62-
default:
63-
throw new JsonException("Unexpected property while reading `Field`.");
66+
throw new JsonException($"Unexpected property while reading `{nameof(Field)}`.");
6467
}
6568
}
6669
}
@@ -70,19 +73,13 @@ private static Field ReadObjectField(ref Utf8JsonReader reader)
7073
return new Field(field, format);
7174
}
7275

73-
throw new JsonException("Unable to read `Field` from JSON.");
76+
throw new JsonException($"Unable to read `{nameof(Field)}` from JSON.");
7477
}
7578

7679
public override void Write(Utf8JsonWriter writer, Field value, JsonSerializerOptions options)
7780
{
7881
InitializeSettings(options);
7982

80-
if (value is null)
81-
{
82-
writer.WriteNullValue();
83-
return;
84-
}
85-
8683
var fieldName = _settings.Inferrer.Field(value);
8784

8885
if (string.IsNullOrEmpty(value.Format))
@@ -92,10 +89,8 @@ public override void Write(Utf8JsonWriter writer, Field value, JsonSerializerOpt
9289
else
9390
{
9491
writer.WriteStartObject();
95-
writer.WritePropertyName("field");
96-
writer.WriteStringValue(fieldName);
97-
writer.WritePropertyName("format");
98-
writer.WriteStringValue(value.Format);
92+
writer.WriteString(FieldProperty, fieldName);
93+
writer.WriteString(FormatProperty, value.Format);
9994
writer.WriteEndObject();
10095
}
10196
}

Diff for: src/Elastic.Clients.Elasticsearch/Core/Infer/Id/Ids.cs

+1-41
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@
66
using System.Collections.Generic;
77
using System.Diagnostics;
88
using System.Linq;
9-
using System.Text.Json;
109
using System.Text.Json.Serialization;
1110
using Elastic.Transport;
1211

@@ -22,7 +21,7 @@ public partial class Ids : IUrlParameter, IEquatable<Ids>
2221

2322
public Ids(IList<Id> ids) => _ids = ids;
2423

25-
public Ids(IEnumerable<string> ids) => _ids = ids?.Select(i => new Id(i)).ToList();
24+
public Ids(IEnumerable<string> ids) => _ids = ids.Select(i => new Id(i)).ToList();
2625

2726
public Ids(string value)
2827
{
@@ -84,42 +83,3 @@ public override int GetHashCode()
8483

8584
public static bool operator !=(Ids left, Ids right) => !Equals(left, right);
8685
}
87-
88-
internal sealed class IdsConverter : JsonConverter<Ids>
89-
{
90-
public override Ids? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
91-
{
92-
if (reader.TokenType != JsonTokenType.StartArray)
93-
throw new JsonException($"Unexpected JSON token. Expected {JsonTokenType.StartArray} but read {reader.TokenType}");
94-
95-
var ids = new List<Id>();
96-
97-
while (reader.Read() && reader.TokenType != JsonTokenType.EndArray)
98-
{
99-
var id = JsonSerializer.Deserialize<Id>(ref reader, options);
100-
101-
if (id is not null)
102-
ids.Add(id);
103-
}
104-
105-
return new Ids(ids);
106-
}
107-
108-
public override void Write(Utf8JsonWriter writer, Ids value, JsonSerializerOptions options)
109-
{
110-
if (value is null)
111-
{
112-
writer.WriteNullValue();
113-
return;
114-
}
115-
116-
writer.WriteStartArray();
117-
118-
foreach (var id in value.IdsToSerialize)
119-
{
120-
JsonSerializer.Serialize<Id>(writer, id, options);
121-
}
122-
123-
writer.WriteEndArray();
124-
}
125-
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
// Licensed to Elasticsearch B.V under one or more agreements.
2+
// Elasticsearch B.V licenses this file to you under the Apache 2.0 License.
3+
// See the LICENSE file in the project root for more information.
4+
5+
using System;
6+
using System.Collections.Generic;
7+
using System.Text.Json;
8+
using System.Text.Json.Serialization;
9+
10+
namespace Elastic.Clients.Elasticsearch;
11+
12+
internal sealed class IdsConverter : JsonConverter<Ids>
13+
{
14+
public override Ids? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
15+
{
16+
if (reader.TokenType != JsonTokenType.StartArray)
17+
throw new JsonException($"Unexpected JSON token. Expected {JsonTokenType.StartArray} but read {reader.TokenType}");
18+
19+
var ids = new List<Id>();
20+
21+
while (reader.Read() && reader.TokenType != JsonTokenType.EndArray)
22+
{
23+
var id = JsonSerializer.Deserialize<Id>(ref reader, options);
24+
25+
if (id is not null)
26+
ids.Add(id);
27+
}
28+
29+
return new Ids(ids);
30+
}
31+
32+
public override void Write(Utf8JsonWriter writer, Ids value, JsonSerializerOptions options)
33+
{
34+
if (value is null)
35+
{
36+
writer.WriteNullValue();
37+
return;
38+
}
39+
40+
writer.WriteStartArray();
41+
42+
foreach (var id in value.IdsToSerialize)
43+
{
44+
JsonSerializer.Serialize<Id>(writer, id, options);
45+
}
46+
47+
writer.WriteEndArray();
48+
}
49+
}

Diff for: src/Elastic.Clients.Elasticsearch/Core/Infer/Metric/Metrics.cs

+12-4
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44

55
using System;
66
using System.Collections.Generic;
7-
using System.Linq;
87
using Elastic.Transport;
98

109
namespace Elastic.Clients.Elasticsearch;
@@ -53,8 +52,8 @@ public bool Equals(Metrics other)
5352
{
5453
if (other is null) return false;
5554

56-
// Equality is true when the metrics names in both instances are equal, regardless of their order in the set.
57-
return Values.OrderBy(t => t).SequenceEqual(other.Values.OrderBy(t => t));
55+
// Equality is true when both instances have the same metric names.
56+
return Values.SetEquals(other.Values);
5857
}
5958

6059
string IUrlParameter.GetString(ITransportConfiguration settings) => GetString();
@@ -71,7 +70,16 @@ private string GetString()
7170
}
7271

7372
/// <inheritdoc />
74-
public override int GetHashCode() => Values != null ? Values.GetHashCode() : 0;
73+
public override int GetHashCode()
74+
{
75+
// Lifting the minimal target framework to .NET Standard 2.1
76+
// would be the best solution ever due to the HashCode type.
77+
var hashCode = 0;
78+
foreach (var metric in Values)
79+
hashCode = (hashCode * 397) ^ metric.GetHashCode();
80+
81+
return hashCode;
82+
}
7583

7684
public static bool operator ==(Metrics left, Metrics right) => Equals(left, right);
7785
public static bool operator !=(Metrics left, Metrics right) => !Equals(left, right);

Diff for: src/Elastic.Clients.Elasticsearch/Serialization/DoubleWithFractionalPortionConverter.cs

+1
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@ public override void Write(Utf8JsonWriter writer, double value, JsonSerializerOp
7575
if (bytes.Length < utf8bytes.Length)
7676
{
7777
bytes.CopyTo(utf8bytes);
78+
return;
7879
}
7980
}
8081
catch

Diff for: src/Elastic.Clients.Elasticsearch/Serialization/EnumStructConverter.cs

+5-11
Original file line numberDiff line numberDiff line change
@@ -3,24 +3,18 @@
33
// See the LICENSE file in the project root for more information.
44

55
using System;
6-
using System.Reflection;
76
using System.Text.Json;
87
using System.Text.Json.Serialization;
8+
using Elastic.Clients.Elasticsearch.Core;
99

1010
namespace Elastic.Clients.Elasticsearch.Serialization;
1111

12-
internal sealed class EnumStructConverter<T> : JsonConverter<T> where T : new()
12+
internal sealed class EnumStructConverter<T> : JsonConverter<T> where T : struct, IEnumStruct<T>
1313
{
14-
public override T? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
14+
public override T Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
1515
{
1616
var value = reader.GetString();
17-
18-
var instance = (T)Activator.CreateInstance(
19-
typeof(T),
20-
BindingFlags.Instance | BindingFlags.NonPublic,
21-
args: new object[] { value }, // TODO: Perf - Review use of ArrayPool
22-
binder: null,
23-
culture: null)!;
17+
var instance = default(T).Create(value);
2418

2519
return instance;
2620
}
@@ -30,7 +24,7 @@ public override void Write(Utf8JsonWriter writer, T value, JsonSerializerOptions
3024
var enumValue = value.ToString();
3125

3226
if (!string.IsNullOrEmpty(enumValue))
33-
writer.WriteStringValue(value.ToString());
27+
writer.WriteStringValue(enumValue);
3428
else
3529
writer.WriteNullValue();
3630
}

Diff for: src/Elastic.Clients.Elasticsearch/Serialization/FloatWithFractionalPortionConverter.cs

+1
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@ public override void Write(Utf8JsonWriter writer, float value, JsonSerializerOpt
7575
if (bytes.Length < utf8bytes.Length)
7676
{
7777
bytes.CopyTo(utf8bytes);
78+
return;
7879
}
7980
}
8081
catch

Diff for: src/Elastic.Clients.Elasticsearch/Serialization/UnionConverter.cs

+21-12
Original file line numberDiff line numberDiff line change
@@ -122,12 +122,6 @@ private class DerivedUnionConverterInner<TType, TItem1, TItem2> : JsonConverter<
122122
public override void Write(Utf8JsonWriter writer, TType value,
123123
JsonSerializerOptions options)
124124
{
125-
if (value is null)
126-
{
127-
writer.WriteNullValue();
128-
return;
129-
}
130-
131125
if (value.Item1 is not null)
132126
{
133127
JsonSerializer.Serialize(writer, value.Item1, value.Item1.GetType(), options);
@@ -214,15 +208,30 @@ private class BucketsConverter<TBucket> : JsonConverter<Buckets<TBucket>>
214208
{
215209
public override Buckets<TBucket>? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
216210
{
217-
// TODO - Read ahead to establish the type - For now, hardcoded for lists
211+
return reader.TokenType switch
212+
{
213+
JsonTokenType.Null => null,
214+
JsonTokenType.StartArray => new(JsonSerializer.Deserialize<IReadOnlyCollection<TBucket>>(ref reader, options)),
215+
JsonTokenType.StartObject => new(JsonSerializer.Deserialize<IReadOnlyDictionary<string, TBucket>>(ref reader, options)),
216+
_ => throw new JsonException("Invalid bucket type")
217+
};
218+
}
218219

219-
var bucketType = typeToConvert.GetGenericArguments()[0];
220+
public override void Write(Utf8JsonWriter writer, Buckets<TBucket> value, JsonSerializerOptions options)
221+
{
222+
if (value.Item1 is { } item1)
223+
{
224+
JsonSerializer.Serialize(writer, item1, options);
225+
return;
226+
}
220227

221-
var item = JsonSerializer.Deserialize(ref reader, typeof(IReadOnlyCollection<TBucket>), options);
228+
if (value.Item2 is { } item2)
229+
{
230+
JsonSerializer.Serialize(writer, item2, options);
231+
return;
232+
}
222233

223-
return (Buckets<TBucket>)Activator.CreateInstance(typeof(Buckets<>).MakeGenericType(bucketType), item);
234+
writer.WriteNullValue();
224235
}
225-
226-
public override void Write(Utf8JsonWriter writer, Buckets<TBucket> value, JsonSerializerOptions options) => throw new NotImplementedException();
227236
}
228237
}

Diff for: src/Elastic.Clients.Elasticsearch/_Generated/Types/Enums/Enums.Aggregations.g.cs

+1
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
using System.Text.Json.Serialization;
2323
using System.Runtime.Serialization;
2424
using Elastic.Transport;
25+
using Elastic.Clients.Elasticsearch.Core;
2526
using Elastic.Clients.Elasticsearch.Serialization;
2627

2728
namespace Elastic.Clients.Elasticsearch.Aggregations;

Diff for: src/Elastic.Clients.Elasticsearch/_Generated/Types/Enums/Enums.Analysis.g.cs

+1
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
using System.Text.Json.Serialization;
2323
using System.Runtime.Serialization;
2424
using Elastic.Transport;
25+
using Elastic.Clients.Elasticsearch.Core;
2526
using Elastic.Clients.Elasticsearch.Serialization;
2627

2728
namespace Elastic.Clients.Elasticsearch.Analysis;

0 commit comments

Comments
 (0)