Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use a custom convertor for GeoOrientation to tolerate alternative options in Elasticsearch #3776 #3779

Merged
merged 7 commits into from
Jun 7, 2019
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,8 @@ internal sealed class InnerResolver : IJsonFormatterResolver
new TimeSpanToStringFormatter(),
new NullableTimeSpanToStringFormatter(),
new JsonNetCompatibleUriFormatter(),
new GeoOrientationFormatter(),
new NullableGeoOrientationFormatter(),
}, new IJsonFormatterResolver[0]),
BuiltinResolver.Instance, // Builtin primitives
ElasticsearchNetEnumResolver.Instance, // Specialized Enum handling
Expand Down
91 changes: 84 additions & 7 deletions src/Nest/Mapping/Types/Geo/GeoShape/GeoOrientation.cs
Original file line number Diff line number Diff line change
@@ -1,16 +1,93 @@
using System.Runtime.Serialization;
using Elasticsearch.Net;

using Elasticsearch.Net;

namespace Nest
{
[StringEnum]
public enum GeoOrientation
{
[EnumMember(Value = "cw")]
ClockWise,

[EnumMember(Value = "ccw")]
CounterClockWise
}

internal class GeoOrientationFormatter : IJsonFormatter<GeoOrientation>
{
public void Serialize(ref JsonWriter writer, GeoOrientation value, IJsonFormatterResolver formatterResolver)
{
switch (value)
{
case GeoOrientation.ClockWise:
writer.WriteString("cw");
break;
case GeoOrientation.CounterClockWise:
writer.WriteString("ccw");
break;
}
}

public GeoOrientation Deserialize(ref JsonReader reader, IJsonFormatterResolver formatterResolver)
{
if (reader.ReadIsNull())
{
// Default, complies with the OGC standard
return GeoOrientation.CounterClockWise;
}

var enumString = reader.ReadString();
switch (enumString.ToUpperInvariant())
{
case "LEFT":
case "CW":
case "CLOCKWISE":
return GeoOrientation.ClockWise;
}

// Default, complies with the OGC standard
return GeoOrientation.CounterClockWise;
}
}

internal class NullableGeoOrientationFormatter : IJsonFormatter<GeoOrientation?>
{
public void Serialize(ref JsonWriter writer, GeoOrientation? value, IJsonFormatterResolver formatterResolver)
{
if (!value.HasValue)
{
writer.WriteNull();
return;
}

switch (value)
{
case GeoOrientation.ClockWise:
writer.WriteString("cw");
break;
case GeoOrientation.CounterClockWise:
writer.WriteString("ccw");
break;
}
}

public GeoOrientation? Deserialize(ref JsonReader reader, IJsonFormatterResolver formatterResolver)
{
if (reader.ReadIsNull())
{
return null;
}

var enumString = reader.ReadString();

switch (enumString.ToUpperInvariant())
{
case "LEFT":
case "CW":
case "CLOCKWISE":
return GeoOrientation.ClockWise;
case "RIGHT":
case "CCW":
case "COUNTERCLOCKWISE":
return GeoOrientation.CounterClockWise;
default:
return null;
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
using System;
using System.Linq;
using Elasticsearch.Net;
using FluentAssertions;
using Nest;
using Tests.Core.Extensions;
using Tests.Core.ManagedElasticsearch.Clusters;
using Tests.Domain;
using Tests.Framework;
using Tests.Framework.Integration;

namespace Tests.Mapping.Types.Core.GeoShape
{
public class GeoShapeClusterMetadataApiTests : ApiIntegrationTestBase<WritableCluster, PutMappingResponse, IPutMappingRequest, PutMappingDescriptor<Project>,
PutMappingRequest<Project>>
{
public GeoShapeClusterMetadataApiTests(WritableCluster cluster, EndpointUsage usage) : base(cluster, usage) { }

protected override void IntegrationSetup(IElasticClient client, CallUniqueValues values)
{
foreach (var index in values.Values) client.Indices.Create(index, CreateIndexSettings).ShouldBeValid();
var indices = Infer.Indices(values.Values.Select(i => (IndexName)i));
client.Cluster.Health(null, f => f.WaitForStatus(WaitForStatus.Yellow).Index(indices))
.ShouldBeValid();
}

protected virtual ICreateIndexRequest CreateIndexSettings(CreateIndexDescriptor create) => create;

protected override bool ExpectIsValid => true;
protected override int ExpectStatusCode => 200;

protected override Func<PutMappingDescriptor<Project>, IPutMappingRequest> Fluent => f => f
.Index(CallIsolatedValue)
.Properties(FluentProperties);

private static Func<PropertiesDescriptor<Project>, IPromise<IProperties>> FluentProperties => f => f
.GeoShape(s => s
.Name(p => p.Location)
.Tree(GeoTree.Quadtree)
.Orientation(GeoOrientation.ClockWise)
.Strategy(GeoStrategy.Recursive)
.TreeLevels(3)
.PointsOnly()
.DistanceErrorPercentage(1.0)
.Coerce()
);

private static IProperties InitializerProperties => new Properties
{
{
"location", new GeoShapeProperty
{
Tree = GeoTree.Quadtree,
Orientation = GeoOrientation.ClockWise,
Strategy = GeoStrategy.Recursive,
TreeLevels = 3,
PointsOnly = true,
DistanceErrorPercentage = 1.0,
Coerce = true
}
}
};

protected override HttpMethod HttpMethod => HttpMethod.PUT;

protected override PutMappingRequest<Project> Initializer => new PutMappingRequest<Project>(CallIsolatedValue)
{
Properties = InitializerProperties
};

protected override string UrlPath => $"/{CallIsolatedValue}/_mapping";

protected override LazyResponses ClientUsage() => Calls(
(client, f) => client.Map(f),
(client, f) => client.MapAsync(f),
(client, r) => client.Map(r),
(client, r) => client.MapAsync(r)
);

protected override void ExpectResponse(PutMappingResponse response)
{
// Ensure metadata can be deserialised
var metadata = Client.Cluster.State(null, r => r.Metric(ClusterStateMetric.Metadata));
codebrain marked this conversation as resolved.
Show resolved Hide resolved
metadata.IsValid.Should().BeTrue();
}
}
}