Skip to content

Commit

Permalink
Deserialize sort short forms (#4806) (#4829)
Browse files Browse the repository at this point in the history
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 <[email protected]>
  • Loading branch information
github-actions[bot] and russcam authored Jun 30, 2020
1 parent 41959c3 commit 6533731
Show file tree
Hide file tree
Showing 2 changed files with 113 additions and 40 deletions.
107 changes: 67 additions & 40 deletions src/Nest/CommonOptions/Sorting/SortFormatter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,55 +22,82 @@ public ISort Deserialize(ref JsonReader reader, IJsonFormatterResolver formatter
{
ISort sort = null;

var count = 0;
while (reader.ReadIsInObject(ref count))
switch (reader.GetCurrentJsonToken())
{
var sortProperty = reader.ReadPropertyNameSegmentRaw();
if (SortFields.TryGetValue(sortProperty, out var value))
case JsonToken.String:
{
switch (value)
var sortProperty = reader.ReadString();
sort = new FieldSort { Field = sortProperty };
break;
}
case JsonToken.BeginObject:
{
var count = 0;
while (reader.ReadIsInObject(ref count))
{
case 0:
var propCount = 0;
string field = null;
var geoDistanceSegment = reader.ReadNextBlockSegment();
var geoDistanceReader = new JsonReader(geoDistanceSegment.Array, geoDistanceSegment.Offset);
IEnumerable<GeoLocation> points = null;
while (geoDistanceReader.ReadIsInObject(ref propCount))
var sortProperty = reader.ReadPropertyNameSegmentRaw();
if (SortFields.TryGetValue(sortProperty, out var value))
{
switch (value)
{
var nameSegment = geoDistanceReader.ReadPropertyNameSegmentRaw();
if (geoDistanceReader.GetCurrentJsonToken() == JsonToken.BeginArray)
{
field = nameSegment.Utf8String();
points = formatterResolver.GetFormatter<IEnumerable<GeoLocation>>()
case 0:
var propCount = 0;
string field = null;
var geoDistanceSegment = reader.ReadNextBlockSegment();
var geoDistanceReader = new JsonReader(geoDistanceSegment.Array, geoDistanceSegment.Offset);
IEnumerable<GeoLocation> points = null;
while (geoDistanceReader.ReadIsInObject(ref propCount))
{
var nameSegment = geoDistanceReader.ReadPropertyNameSegmentRaw();
if (geoDistanceReader.GetCurrentJsonToken() == JsonToken.BeginArray)
{
field = nameSegment.Utf8String();
points = formatterResolver.GetFormatter<IEnumerable<GeoLocation>>()
.Deserialize(ref geoDistanceReader, formatterResolver);
break;
}

// skip value if not array
geoDistanceReader.ReadNextBlock();
}
geoDistanceReader = new JsonReader(geoDistanceSegment.Array, geoDistanceSegment.Offset);
var geoDistanceSort = formatterResolver.GetFormatter<GeoDistanceSort>()
.Deserialize(ref geoDistanceReader, formatterResolver);
geoDistanceSort.Field = field;
geoDistanceSort.Points = points;
sort = geoDistanceSort;
break;
}

// skip value if not array
geoDistanceReader.ReadNextBlock();
case 1:
sort = formatterResolver.GetFormatter<ScriptSort>()
.Deserialize(ref reader, formatterResolver);
break;
}
}
else
{
var field = sortProperty.Utf8String();
FieldSort sortField;
if (reader.GetCurrentJsonToken() == JsonToken.String)
{
var sortOrder = formatterResolver.GetFormatter<SortOrder>()
.Deserialize(ref reader, formatterResolver);
sortField = new FieldSort { Field = field, Order = sortOrder };
}
geoDistanceReader = new JsonReader(geoDistanceSegment.Array, geoDistanceSegment.Offset);
var geoDistanceSort = formatterResolver.GetFormatter<GeoDistanceSort>()
.Deserialize(ref geoDistanceReader, formatterResolver);
geoDistanceSort.Field = field;
geoDistanceSort.Points = points;
sort = geoDistanceSort;
break;
case 1:
sort = formatterResolver.GetFormatter<ScriptSort>()
.Deserialize(ref reader, formatterResolver);
break;
else
{
sortField = formatterResolver.GetFormatter<FieldSort>()
.Deserialize(ref reader, formatterResolver);
sortField.Field = field;
}

sort = sortField;
}
}

break;
}
else
{
var field = sortProperty.Utf8String();
var sortField = formatterResolver.GetFormatter<FieldSort>()
.Deserialize(ref reader, formatterResolver);
sortField.Field = field;
sort = sortField;
}
default:
throw new JsonParsingException($"Cannot deserialize {nameof(ISort)} from {reader.GetCurrentJsonToken()}");
}

return sort;
Expand Down
46 changes: 46 additions & 0 deletions tests/Tests.Reproduce/GitHubIssue4797.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
// Licensed to Elasticsearch B.V under one or more agreements.
// Elasticsearch B.V licenses this file to you under the Apache 2.0 License.
// See the LICENSE file in the project root for more information

using System.Text;
using Elastic.Elasticsearch.Xunit.XunitPlumbing;
using FluentAssertions;
using Nest;
using Tests.Core.Client;

namespace Tests.Reproduce
{
public class GitHubIssue4797
{
[U]
public void DeserializeSortWithOnlyFieldAndOrder()
{
var json = @"
{
""sort"" : [
{ ""post_date"" : {""order"" : ""asc""}},
""user"",
{ ""name"" : ""desc"" },
{ ""age"" : ""desc"" },
""_score""
],
""query"" : {
""term"" : { ""user"" : ""kimchy"" }
}
}
";

var bytes = Encoding.UTF8.GetBytes(json);
var client = TestClient.FixedInMemoryClient(bytes);

using var stream = client.ConnectionSettings.MemoryStreamFactory.Create(bytes);
var request = client.RequestResponseSerializer.Deserialize<SearchRequest>(stream);

request.Should().NotBeNull();
request.Sort.Should().NotBeNull().And.HaveCount(5);
request.Sort[1].SortKey.Should().Be("user");
request.Sort[2].SortKey.Should().Be("name");
request.Sort[2].Order.Should().Be(SortOrder.Descending);
}
}
}

0 comments on commit 6533731

Please sign in to comment.