Skip to content

Commit

Permalink
Deserialize sort short forms
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
  • Loading branch information
russcam committed Jun 29, 2020
1 parent 3b239bf commit 58e4225
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 58e4225

Please sign in to comment.