Skip to content

Commit 6533731

Browse files
Deserialize sort short forms (#4806) (#4829)
This commit updates SortFormatter to be able to deserialize sorts that specify only the field name as a string, or only specify a sort order value. Fixes #4797 Co-authored-by: Russ Cam <russ.cam@elastic.co>
1 parent 41959c3 commit 6533731

File tree

2 files changed

+113
-40
lines changed

2 files changed

+113
-40
lines changed

src/Nest/CommonOptions/Sorting/SortFormatter.cs

Lines changed: 67 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -22,55 +22,82 @@ public ISort Deserialize(ref JsonReader reader, IJsonFormatterResolver formatter
2222
{
2323
ISort sort = null;
2424

25-
var count = 0;
26-
while (reader.ReadIsInObject(ref count))
25+
switch (reader.GetCurrentJsonToken())
2726
{
28-
var sortProperty = reader.ReadPropertyNameSegmentRaw();
29-
if (SortFields.TryGetValue(sortProperty, out var value))
27+
case JsonToken.String:
3028
{
31-
switch (value)
29+
var sortProperty = reader.ReadString();
30+
sort = new FieldSort { Field = sortProperty };
31+
break;
32+
}
33+
case JsonToken.BeginObject:
34+
{
35+
var count = 0;
36+
while (reader.ReadIsInObject(ref count))
3237
{
33-
case 0:
34-
var propCount = 0;
35-
string field = null;
36-
var geoDistanceSegment = reader.ReadNextBlockSegment();
37-
var geoDistanceReader = new JsonReader(geoDistanceSegment.Array, geoDistanceSegment.Offset);
38-
IEnumerable<GeoLocation> points = null;
39-
while (geoDistanceReader.ReadIsInObject(ref propCount))
38+
var sortProperty = reader.ReadPropertyNameSegmentRaw();
39+
if (SortFields.TryGetValue(sortProperty, out var value))
40+
{
41+
switch (value)
4042
{
41-
var nameSegment = geoDistanceReader.ReadPropertyNameSegmentRaw();
42-
if (geoDistanceReader.GetCurrentJsonToken() == JsonToken.BeginArray)
43-
{
44-
field = nameSegment.Utf8String();
45-
points = formatterResolver.GetFormatter<IEnumerable<GeoLocation>>()
43+
case 0:
44+
var propCount = 0;
45+
string field = null;
46+
var geoDistanceSegment = reader.ReadNextBlockSegment();
47+
var geoDistanceReader = new JsonReader(geoDistanceSegment.Array, geoDistanceSegment.Offset);
48+
IEnumerable<GeoLocation> points = null;
49+
while (geoDistanceReader.ReadIsInObject(ref propCount))
50+
{
51+
var nameSegment = geoDistanceReader.ReadPropertyNameSegmentRaw();
52+
if (geoDistanceReader.GetCurrentJsonToken() == JsonToken.BeginArray)
53+
{
54+
field = nameSegment.Utf8String();
55+
points = formatterResolver.GetFormatter<IEnumerable<GeoLocation>>()
56+
.Deserialize(ref geoDistanceReader, formatterResolver);
57+
break;
58+
}
59+
60+
// skip value if not array
61+
geoDistanceReader.ReadNextBlock();
62+
}
63+
geoDistanceReader = new JsonReader(geoDistanceSegment.Array, geoDistanceSegment.Offset);
64+
var geoDistanceSort = formatterResolver.GetFormatter<GeoDistanceSort>()
4665
.Deserialize(ref geoDistanceReader, formatterResolver);
66+
geoDistanceSort.Field = field;
67+
geoDistanceSort.Points = points;
68+
sort = geoDistanceSort;
4769
break;
48-
}
49-
50-
// skip value if not array
51-
geoDistanceReader.ReadNextBlock();
70+
case 1:
71+
sort = formatterResolver.GetFormatter<ScriptSort>()
72+
.Deserialize(ref reader, formatterResolver);
73+
break;
74+
}
75+
}
76+
else
77+
{
78+
var field = sortProperty.Utf8String();
79+
FieldSort sortField;
80+
if (reader.GetCurrentJsonToken() == JsonToken.String)
81+
{
82+
var sortOrder = formatterResolver.GetFormatter<SortOrder>()
83+
.Deserialize(ref reader, formatterResolver);
84+
sortField = new FieldSort { Field = field, Order = sortOrder };
5285
}
53-
geoDistanceReader = new JsonReader(geoDistanceSegment.Array, geoDistanceSegment.Offset);
54-
var geoDistanceSort = formatterResolver.GetFormatter<GeoDistanceSort>()
55-
.Deserialize(ref geoDistanceReader, formatterResolver);
56-
geoDistanceSort.Field = field;
57-
geoDistanceSort.Points = points;
58-
sort = geoDistanceSort;
59-
break;
60-
case 1:
61-
sort = formatterResolver.GetFormatter<ScriptSort>()
62-
.Deserialize(ref reader, formatterResolver);
63-
break;
86+
else
87+
{
88+
sortField = formatterResolver.GetFormatter<FieldSort>()
89+
.Deserialize(ref reader, formatterResolver);
90+
sortField.Field = field;
91+
}
92+
93+
sort = sortField;
94+
}
6495
}
96+
97+
break;
6598
}
66-
else
67-
{
68-
var field = sortProperty.Utf8String();
69-
var sortField = formatterResolver.GetFormatter<FieldSort>()
70-
.Deserialize(ref reader, formatterResolver);
71-
sortField.Field = field;
72-
sort = sortField;
73-
}
99+
default:
100+
throw new JsonParsingException($"Cannot deserialize {nameof(ISort)} from {reader.GetCurrentJsonToken()}");
74101
}
75102

76103
return sort;
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
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.Text;
6+
using Elastic.Elasticsearch.Xunit.XunitPlumbing;
7+
using FluentAssertions;
8+
using Nest;
9+
using Tests.Core.Client;
10+
11+
namespace Tests.Reproduce
12+
{
13+
public class GitHubIssue4797
14+
{
15+
[U]
16+
public void DeserializeSortWithOnlyFieldAndOrder()
17+
{
18+
var json = @"
19+
{
20+
""sort"" : [
21+
{ ""post_date"" : {""order"" : ""asc""}},
22+
""user"",
23+
{ ""name"" : ""desc"" },
24+
{ ""age"" : ""desc"" },
25+
""_score""
26+
],
27+
""query"" : {
28+
""term"" : { ""user"" : ""kimchy"" }
29+
}
30+
}
31+
";
32+
33+
var bytes = Encoding.UTF8.GetBytes(json);
34+
var client = TestClient.FixedInMemoryClient(bytes);
35+
36+
using var stream = client.ConnectionSettings.MemoryStreamFactory.Create(bytes);
37+
var request = client.RequestResponseSerializer.Deserialize<SearchRequest>(stream);
38+
39+
request.Should().NotBeNull();
40+
request.Sort.Should().NotBeNull().And.HaveCount(5);
41+
request.Sort[1].SortKey.Should().Be("user");
42+
request.Sort[2].SortKey.Should().Be("name");
43+
request.Sort[2].Order.Should().Be(SortOrder.Descending);
44+
}
45+
}
46+
}

0 commit comments

Comments
 (0)