Skip to content

Commit

Permalink
re-add NoGeometry type
Browse files Browse the repository at this point in the history
  • Loading branch information
davetimmins committed Jun 4, 2020
1 parent 05711d2 commit 09fc810
Show file tree
Hide file tree
Showing 6 changed files with 103 additions and 35 deletions.
25 changes: 25 additions & 0 deletions src/Anywhere.ArcGIS/Common/IGeometry.cs
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,31 @@ public interface IGeometry : ICloneable
IGeoJsonGeometry ToGeoJson();
}

public class NoGeometry : IGeometry
{
public SpatialReference SpatialReference { get; set; }

public object Clone()
{
return new NoGeometry();
}

public Point GetCenter()
{
return null;
}

public Extent GetExtent()
{
return null;
}

public IGeoJsonGeometry ToGeoJson()
{
return null;
}
}

/// <summary>
/// Spatial reference used for operations. If WKT is set then other properties are nulled
/// </summary>
Expand Down
4 changes: 2 additions & 2 deletions src/Anywhere.ArcGIS/Extensions/FeatureCollectionExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ public static FeatureCollection<IGeoJsonGeometry> ToFeatureCollection<TGeometry>
}

var featureCollection = new FeatureCollection<IGeoJsonGeometry> { Features = new List<GeoJsonFeature<IGeoJsonGeometry>>() };
if (features.First().Geometry.SpatialReference != null)
if (features?.First()?.Geometry?.SpatialReference != null)
{
featureCollection.CoordinateReferenceSystem = new Crs
{
Expand All @@ -76,7 +76,7 @@ public static FeatureCollection<IGeoJsonGeometry> ToFeatureCollection<TGeometry>

foreach (var feature in features)
{
var geoJsonGeometry = feature.Geometry.ToGeoJson();
var geoJsonGeometry = feature?.Geometry?.ToGeoJson();
if (geoJsonGeometry == null)
{
continue;
Expand Down
6 changes: 3 additions & 3 deletions src/Anywhere.ArcGIS/Operation/GeometryServerOperation.cs
Original file line number Diff line number Diff line change
Expand Up @@ -161,8 +161,8 @@ public GeometryOperation(IEndpoint endpoint,
{
Geometries = new GeometryCollection<T> { Geometries = new List<T>(features.Select(f => f.Geometry)) };

if (Geometries.Geometries.First().SpatialReference == null && features.First().Geometry.SpatialReference != null)
Geometries.Geometries.First().SpatialReference = new SpatialReference { Wkid = features.First().Geometry.SpatialReference.Wkid };
if (Geometries.Geometries.First()?.SpatialReference == null && features?.First()?.Geometry?.SpatialReference != null)
Geometries.Geometries.First().SpatialReference = new SpatialReference { Wkid = features?.First()?.Geometry?.SpatialReference?.Wkid };
}
OutputSpatialReference = outputSpatialReference;
}
Expand All @@ -177,7 +177,7 @@ public GeometryOperation(IEndpoint endpoint,
/// Taken from the spatial reference of the first geometry, if that is null then assumed to be using Wgs84
/// </summary>
[DataMember(Name = "inSR")]
public SpatialReference InputSpatialReference { get { return Geometries.Geometries.First().SpatialReference ?? SpatialReference.WGS84; } }
public SpatialReference InputSpatialReference { get { return Geometries.Geometries.First()?.SpatialReference ?? SpatialReference.WGS84; } }

/// <summary>
/// The spatial reference of the returned geometry.
Expand Down
3 changes: 2 additions & 1 deletion src/Anywhere.ArcGIS/Operation/Query.cs
Original file line number Diff line number Diff line change
Expand Up @@ -433,7 +433,8 @@ public static class GeometryTypes
{ typeof(MultiPoint), () => GeometryTypes.MultiPoint },
{ typeof(Extent), () => GeometryTypes.Envelope },
{ typeof(Polygon), () => GeometryTypes.Polygon },
{ typeof(Polyline), () => GeometryTypes.Polyline }
{ typeof(Polyline), () => GeometryTypes.Polyline },
{ typeof(NoGeometry), () => string.Empty }
};

public readonly static Dictionary<string, Func<Type>> ToTypeMap = new Dictionary<string, Func<Type>>
Expand Down
83 changes: 54 additions & 29 deletions src/Anywhere.ArcGIS/PortalGatewayBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -67,8 +67,8 @@ public static async Task<PortalGatewayBase> Create(
new ServerFederatedWithPortalTokenProvider(info.AuthenticationInfo.TokenServicesUrl.Replace("/generateToken", ""), username, password, serializer: serializer, httpClientFunc: httpClientFunc),
info.AuthenticationInfo.TokenServicesUrl.Replace("/generateToken", ""),
gateway.RootUrl,
referer: info.AuthenticationInfo.TokenServicesUrl.Replace("/sharing/rest/generateToken", "/rest"),
serializer: serializer,
referer: info.AuthenticationInfo.TokenServicesUrl.Replace("/sharing/rest/generateToken", "/rest"),
serializer: serializer,
httpClientFunc: httpClientFunc);
}
else
Expand Down Expand Up @@ -214,12 +214,12 @@ public TimeSpan HttpRequestTimeout
/// <returns>The legend descriptions details</returns>
public virtual Task<LegendsDescriptionResponse> DescribeLegends(IEndpoint mapServiceEndpoint, CancellationToken ct = default(CancellationToken))
{
if (mapServiceEndpoint == null)
{
throw new ArgumentNullException(nameof(mapServiceEndpoint));
}
if (mapServiceEndpoint == null)
{
throw new ArgumentNullException(nameof(mapServiceEndpoint));
}

return DescribeLegends(new LegendsDescription(mapServiceEndpoint), ct);
return DescribeLegends(new LegendsDescription(mapServiceEndpoint), ct);
}

/// <summary>
Expand All @@ -228,22 +228,22 @@ public TimeSpan HttpRequestTimeout
/// <returns>The legend descriptions details</returns>
public virtual Task<LegendsDescriptionResponse> DescribeLegends(LegendsDescription legendDescriptionRequest, CancellationToken ct = default(CancellationToken))
{
if (legendDescriptionRequest == null)
{
throw new ArgumentNullException(nameof(legendDescriptionRequest));
}
if (legendDescriptionRequest == null)
{
throw new ArgumentNullException(nameof(legendDescriptionRequest));
}

return Get<LegendsDescriptionResponse, LegendsDescription>(legendDescriptionRequest, ct);
return Get<LegendsDescriptionResponse, LegendsDescription>(legendDescriptionRequest, ct);
}

/// <summary>
/// The feature resource represents a single feature in a layer in a map service.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="layerFeature"></param>
/// <param name="ct"></param>
/// <returns></returns>
public virtual Task<LayerFeatureResponse<T>> GetFeature<T>(LayerFeature layerFeature, CancellationToken ct = default(CancellationToken))
/// <summary>
/// The feature resource represents a single feature in a layer in a map service.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="layerFeature"></param>
/// <param name="ct"></param>
/// <returns></returns>
public virtual Task<LayerFeatureResponse<T>> GetFeature<T>(LayerFeature layerFeature, CancellationToken ct = default(CancellationToken))
where T : IGeometry
{
return Get<LayerFeatureResponse<T>, LayerFeature>(layerFeature, ct);
Expand All @@ -262,6 +262,22 @@ public TimeSpan HttpRequestTimeout
return Get<QueryResponse<T>, Query>(queryOptions, ct);
}

/// <summary>
/// Call the query operation
/// </summary>
/// <param name="queryOptions">Query filter parameters</param>
/// <param name="ct">Optional cancellation token to cancel pending request</param>
/// <returns>The matching features for the query</returns>
public virtual Task<QueryResponse<NoGeometry>> Query(Query queryOptions, CancellationToken ct = default(CancellationToken))
{
if (queryOptions != null)
{
queryOptions.ReturnGeometry = false;
}

return Get<QueryResponse<NoGeometry>, Query>(queryOptions, ct);
}

public virtual async Task<QueryResponse<T>> BatchQuery<T>(Query queryOptions, CancellationToken ct = default(CancellationToken))
where T : IGeometry
{
Expand Down Expand Up @@ -302,8 +318,8 @@ public TimeSpan HttpRequestTimeout
{
oidList = oidList.Concat(innerResult.Features.Select(x => x.ObjectID.ToString()));
result.Features = result.Features.Concat(innerResult.Features);
exceeded = result.ExceededTransferLimit.HasValue
&& innerResult.ExceededTransferLimit.HasValue
exceeded = result.ExceededTransferLimit.HasValue
&& innerResult.ExceededTransferLimit.HasValue
&& innerResult.ExceededTransferLimit.Value;
}
else
Expand Down Expand Up @@ -394,7 +410,10 @@ public TimeSpan HttpRequestTimeout
if (ct.IsCancellationRequested) return null;

var result = features.UpdateGeometries(projected.Geometries);
if (result.First().Geometry.SpatialReference == null) result.First().Geometry.SpatialReference = outputSpatialReference;
if (result.First().Geometry.SpatialReference == null)
{
result.First().Geometry.SpatialReference = outputSpatialReference;
}
return result;
}

Expand All @@ -406,7 +425,10 @@ public TimeSpan HttpRequestTimeout
if (ct.IsCancellationRequested) return null;

var result = operation.Features.UpdateGeometries<T>(projected.Geometries);
if (result.First().Geometry.SpatialReference == null) result.First().Geometry.SpatialReference = operation.OutputSpatialReference;
if (result.First().Geometry.SpatialReference == null)
{
result.First().Geometry.SpatialReference = operation.OutputSpatialReference;
}
return result;
}

Expand Down Expand Up @@ -452,7 +474,10 @@ public TimeSpan HttpRequestTimeout
if (ct.IsCancellationRequested) return null;

var result = features.UpdateGeometries<T>(simplified.Geometries);
if (result.First().Geometry.SpatialReference == null) result.First().Geometry.SpatialReference = spatialReference;
if (result.First().Geometry.SpatialReference == null)
{
result.First().Geometry.SpatialReference = spatialReference;
}
return result;
}

Expand Down Expand Up @@ -617,7 +642,7 @@ public virtual async Task<FileInfo> DownloadExportMapToLocal(ExportMapResponse e
{
throw new ArgumentNullException(nameof(exportMapResponse));
}

if (string.IsNullOrWhiteSpace(exportMapResponse.ImageUrl))
{
throw new ArgumentNullException(nameof(exportMapResponse.ImageUrl));
Expand Down Expand Up @@ -680,7 +705,7 @@ protected async Task<T> Get<T, TRequest>(TRequest requestObject, CancellationTok

var endpoint = requestObject.Endpoint;
var url = endpoint.BuildAbsoluteUrl(RootUrl) + AsRequestQueryString(Serializer, requestObject);

var token = await CheckGenerateToken(ct).ConfigureAwait(false);
if (ct.IsCancellationRequested)
{
Expand Down Expand Up @@ -710,11 +735,11 @@ protected async Task<T> Get<T, TRequest>(TRequest requestObject, CancellationTok
}

if (url.Length > MaximumGetRequestLength)
{
{
_logger.DebugFormat("Url length {0} is greater than maximum configured {1}, switching to POST.", url.Length, MaximumGetRequestLength);
return await Post<T, TRequest>(requestObject, ct).ConfigureAwait(false);
}

_logger.DebugFormat("GET {0}", uri.AbsoluteUri);
requestObject.BeforeRequest?.Invoke();

Expand Down
17 changes: 17 additions & 0 deletions tests/Anywhere.ArcGIS.Test.Integration/ArcGISGatewayTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -596,6 +596,23 @@ public async Task CanQueryForIds()
Assert.True(resultFiltered.ObjectIds.Count() == queryFiltered.ObjectIds.Count);
}

[Fact]
public async Task CanQueryWithNoGeometryResponse()
{
var gateway = new PortalGateway("http://services.arcgisonline.com/arcgis/");

var query = new Query(@"/Specialty/Soil_Survey_Map/MapServer/2");
var result = await IntegrationTestFixture.TestPolicy.Execute(() =>
{
return gateway.Query(query);
});

Assert.NotNull(result);
Assert.Null(result.Error);
Assert.NotNull(result.Features);
Assert.True(result.Features.All(x => x.Geometry == null));
}

/// <summary>
/// Performs unfiltered query, then filters by Extent and Polygon to SE quadrant of globe and verifies both filtered
/// results contain same number of features as each other, and that both filtered resultsets contain fewer features than unfiltered resultset.
Expand Down

0 comments on commit 09fc810

Please sign in to comment.