Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
2 changes: 1 addition & 1 deletion build/scripts/Commandline.fsx
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ Execution hints can be provided anywhere on the command line
- skiptests : skip running tests as part of the target chain
- skipdocs : skip generating documentation
- seed:<N> : provide a seed to run the tests with.
- random:<K><:B> : sets random K to bool B if if B is ommitted will default to true
- random:<K><:B> : sets random K to bool B if if B is omitted will default to true
K can be: sourceserializer, typedkeys or oldconnection (only valid on windows)
"""

Expand Down
64 changes: 29 additions & 35 deletions src/Nest/QueryDsl/Geo/GeoLocation.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@

namespace Nest
{

/// <summary>
/// Represents a Latitude/Longitude as a 2 dimensional point that gets serialized as { lat, lon }
/// </summary>
Expand All @@ -18,18 +17,16 @@ public class GeoLocation : IEquatable<GeoLocation>, IFormattable
/// Latitude
/// </summary>
[JsonProperty("lat")]
public double Latitude => _latitude;
private readonly double _latitude;
public double Latitude { get; }

/// <summary>
/// Longitude
/// </summary>
[JsonProperty("lon")]
public double Longitude => _longitude;
private readonly double _longitude;
public double Longitude { get; }

/// <summary>
/// Represents a Latitude/Longitude as a 2 dimensional point.
/// Represents a Latitude/Longitude as a 2 dimensional point.
/// </summary>
/// <param name="latitude">Value between -90 and 90</param>
/// <param name="longitude">Value between -180 and 180</param>
Expand All @@ -42,32 +39,26 @@ public GeoLocation(double latitude, double longitude)
if (!IsValidLongitude(longitude))
throw new ArgumentOutOfRangeException(string.Format(CultureInfo.InvariantCulture,
"Invalid longitude '{0}'. Valid values are between -180 and 180", longitude));
_latitude = latitude;
_longitude = longitude;
Latitude = latitude;
Longitude = longitude;
}

/// <summary>
/// True if <paramref name="latitude"/> is a valid latitude. Otherwise false.
/// </summary>
/// <param name="latitude"></param>
/// <returns></returns>
public static bool IsValidLatitude(double latitude)
{
return latitude >= -90 && latitude <= 90;
}
public static bool IsValidLatitude(double latitude) => latitude >= -90 && latitude <= 90;

/// <summary>
/// True if <paramref name="longitude"/> is a valid longitude. Otherwise false.
/// </summary>
/// <param name="longitude"></param>
/// <returns></returns>
public static bool IsValidLongitude(double longitude)
{
return longitude >= -180 && longitude <= 180;
}
public static bool IsValidLongitude(double longitude) => longitude >= -180 && longitude <= 180;

/// <summary>
/// Try to create a <see cref="GeoLocation"/>.
/// Try to create a <see cref="GeoLocation"/>.
/// Return <value>null</value> if either <paramref name="latitude"/> or <paramref name="longitude"/> are invalid.
/// </summary>
/// <param name="latitude">Value between -90 and 90</param>
Expand All @@ -80,18 +71,17 @@ public static GeoLocation TryCreate(double latitude, double longitude)
return null;
}

public override string ToString()
{
return _latitude.ToString("#0.0#######", CultureInfo.InvariantCulture) + "," + _longitude.ToString("#0.0#######", CultureInfo.InvariantCulture);
}
public override string ToString() =>
Latitude.ToString("#0.0#######", CultureInfo.InvariantCulture) + "," +
Longitude.ToString("#0.0#######", CultureInfo.InvariantCulture);

public bool Equals(GeoLocation other)
{
if (ReferenceEquals(null, other))
return false;
if (ReferenceEquals(this, other))
return true;
return _latitude.Equals(other._latitude) && _longitude.Equals(other._longitude);
return Latitude.Equals(other.Latitude) && Longitude.Equals(other.Longitude);
}

public override bool Equals(object obj)
Expand All @@ -106,7 +96,7 @@ public override bool Equals(object obj)
}

public override int GetHashCode() =>
unchecked((_latitude.GetHashCode() * 397) ^ _longitude.GetHashCode());
unchecked((Latitude.GetHashCode() * 397) ^ Longitude.GetHashCode());

public string ToString(string format, IFormatProvider formatProvider) => ToString();

Expand All @@ -117,21 +107,18 @@ public static implicit operator GeoLocation(string latLon)

var parts = latLon.Split(',');
if (parts.Length != 2) throw new ArgumentException("Invalid format: string must be in the form of lat,lon");
double lat;
if (!double.TryParse(parts[0], NumberStyles.Any, CultureInfo.InvariantCulture, out lat))
if (!double.TryParse(parts[0], NumberStyles.Any, CultureInfo.InvariantCulture, out var lat))
throw new ArgumentException("Invalid latitude value");
double lon;
if (!double.TryParse(parts[1], NumberStyles.Any, CultureInfo.InvariantCulture, out lon))
if (!double.TryParse(parts[1], NumberStyles.Any, CultureInfo.InvariantCulture, out var lon))
throw new ArgumentException("Invalid longitude value");
return new GeoLocation(lat, lon);
}

public static implicit operator GeoLocation(double[] lonLat)
{
if (lonLat.Length != 2)
return null;

return new GeoLocation(lonLat[1], lonLat[0]);
return lonLat.Length != 2
? null
: new GeoLocation(lonLat[1], lonLat[0]);
}
}

Expand All @@ -141,14 +128,21 @@ public static implicit operator GeoLocation(double[] lonLat)
[JsonConverter(typeof(GeoCoordinateJsonConverter))]
public class GeoCoordinate : GeoLocation
{
public GeoCoordinate(double latitude, double longitude) : base(latitude, longitude)
{
}
/// <summary>
/// Creates a new instance of <see cref="GeoCoordinate"/>
/// </summary>
public GeoCoordinate(double latitude, double longitude) : base(latitude, longitude) { }

/// <summary>
/// Creates a new instance of <see cref="GeoCoordinate"/> from a pair of coordinates
/// in the order Latitude then Longitude.
/// </summary>
public static implicit operator GeoCoordinate(double[] coordinates)
{
if (coordinates == null || coordinates.Length != 2)
throw new ArgumentOutOfRangeException(nameof(coordinates), "Can not create a GeoCoordinate from an array that does not have two doubles");
throw new ArgumentOutOfRangeException(
nameof(coordinates),
$"Can not create a {nameof(GeoCoordinate)} from an array that does not have two doubles");

return new GeoCoordinate(coordinates[0], coordinates[1]);
}
Expand Down
5 changes: 1 addition & 4 deletions src/Nest/QueryDsl/Geo/Shape/Envelope/EnvelopeGeoShape.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,8 @@ public class EnvelopeGeoShape : GeoShapeBase, IEnvelopeGeoShape
{
public EnvelopeGeoShape() : this(null) { }

public EnvelopeGeoShape(IEnumerable<GeoCoordinate> coordinates)
: base("envelope")
{
public EnvelopeGeoShape(IEnumerable<GeoCoordinate> coordinates) : base("envelope") =>
this.Coordinates = coordinates;
}

public IEnumerable<GeoCoordinate> Coordinates { get; set; }
}
Expand Down
134 changes: 124 additions & 10 deletions src/Nest/QueryDsl/Geo/Shape/GeoShapeBase.cs
Original file line number Diff line number Diff line change
@@ -1,30 +1,144 @@
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Linq;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;

namespace Nest
{
[ContractJsonConverterAttribute(typeof(GeoShapeConverter))]
public interface IGeoShape
{
/// <summary>
/// The type of geo shape
/// </summary>
[JsonProperty("type")]
string Type { get; }

/// <summary>
/// Will ignore an unmapped field and will not match any documents for this query.
/// This can be useful when querying multiple indexes which might have different mappings.
/// </summary>
[JsonProperty("ignore_unmapped")]
bool? IgnoreUnmapped { get; set; }
}

public abstract class GeoShapeBase : IGeoShape
{
protected GeoShapeBase(string type)
{
this.Type = type;
}
protected GeoShapeBase(string type) => this.Type = type;

/// <inheritdoc />
public string Type { get; protected set; }

/// <summary>
/// Will ignore an unmapped field and will not match any documents for this query.
/// This can be useful when querying multiple indexes which might have different mappings.
/// </summary>
[JsonProperty("ignore_unmapped")]
/// <inheritdoc />
public bool? IgnoreUnmapped { get; set; }
}

internal class GeoShapeConverter : JsonConverter
{
public override bool CanWrite => false;

public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) =>
throw new NotSupportedException();

public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
if (reader.TokenType == JsonToken.Null)
return null;

var shape = JObject.Load(reader);
return ReadJToken(shape, serializer);
}

internal static object ReadJToken(JToken shape, JsonSerializer serializer)
{
var type = shape["type"];
var typeName = type?.Value<string>();
switch (typeName)
{
case "circle":
var radius = shape["radius"];
return ParseCircleGeoShape(shape, serializer, radius);
case "envelope":
return ParseEnvelopeGeoShape(shape, serializer);
case "linestring":
return ParseLineStringGeoShape(shape, serializer);
case "multilinestring":
return ParseMultiLineStringGeoShape(shape, serializer);
case "point":
return ParsePointGeoShape(shape, serializer);
case "multipoint":
return ParseMultiPointGeoShape(shape, serializer);
case "polygon":
return ParsePolygonGeoShape(shape, serializer);
case "multipolygon":
return ParseMultiPolygonGeoShape(shape, serializer);
case "geometrycollection":
return ParseGeometryCollection(shape, serializer);
default:
return null;
}
}

public override bool CanConvert(Type objectType) => typeof(IGeoShape).IsAssignableFrom(objectType) ||
typeof(IGeometryCollection).IsAssignableFrom(objectType);

private static GeometryCollection ParseGeometryCollection(JToken shape, JsonSerializer serializer)
{
if (!(shape["geometries"] is JArray geometries))
return new GeometryCollection { Geometries = Enumerable.Empty<IGeoShape>() };

var geoShapes = new List<IGeoShape>(geometries.Count);
for (var index = 0; index < geometries.Count; index++)
{
var geometry = geometries[index];
if (ReadJToken(geometry, serializer) is IGeoShape innerShape)
geoShapes.Add(innerShape);
}

return new GeometryCollection { Geometries = geoShapes };
}

private static MultiPolygonGeoShape ParseMultiPolygonGeoShape(JToken shape, JsonSerializer serializer) =>
new MultiPolygonGeoShape
{
Coordinates = GetCoordinates<IEnumerable<IEnumerable<IEnumerable<GeoCoordinate>>>>(shape, serializer)
};

private static PolygonGeoShape ParsePolygonGeoShape(JToken shape, JsonSerializer serializer) =>
new PolygonGeoShape {Coordinates = GetCoordinates<IEnumerable<IEnumerable<GeoCoordinate>>>(shape, serializer)};

private static MultiPointGeoShape ParseMultiPointGeoShape(JToken shape, JsonSerializer serializer) =>
new MultiPointGeoShape {Coordinates = GetCoordinates<IEnumerable<GeoCoordinate>>(shape, serializer)};

private static PointGeoShape ParsePointGeoShape(JToken shape, JsonSerializer serializer) =>
new PointGeoShape {Coordinates = GetCoordinates<GeoCoordinate>(shape, serializer)};

private static MultiLineStringGeoShape ParseMultiLineStringGeoShape(JToken shape, JsonSerializer serializer) =>
new MultiLineStringGeoShape
{
Coordinates = GetCoordinates<IEnumerable<IEnumerable<GeoCoordinate>>>(shape, serializer)
};

private static LineStringGeoShape ParseLineStringGeoShape(JToken shape, JsonSerializer serializer) =>
new LineStringGeoShape {Coordinates = GetCoordinates<IEnumerable<GeoCoordinate>>(shape, serializer)};

private static EnvelopeGeoShape ParseEnvelopeGeoShape(JToken shape, JsonSerializer serializer) =>
new EnvelopeGeoShape {Coordinates = GetCoordinates<IEnumerable<GeoCoordinate>>(shape, serializer)};

private static CircleGeoShape ParseCircleGeoShape(JToken shape, JsonSerializer serializer, JToken radius) =>
new CircleGeoShape
{
Coordinates = GetCoordinates<GeoCoordinate>(shape, serializer),
Radius = radius?.Value<string>()
};

private static T GetCoordinates<T>(JToken shape, JsonSerializer serializer)
{
var coordinates = shape["coordinates"];
return coordinates != null
? coordinates.ToObject<T>(serializer)
: default(T);
}
}
}
Loading