From b89e4d330551f41026e96abee170a64e0aa35b24 Mon Sep 17 00:00:00 2001 From: Eric St-Georges Date: Sat, 16 Mar 2019 08:26:39 -0400 Subject: [PATCH 1/5] Added new NTS translations Added Geometry.Buffer(double, int) Added Geometry.InteriorPoint Added Geometry.OgcGeometryType Added Geometry.Union() --- ...lNetTopologySuiteMemberTranslatorPlugin.cs | 29 ++++++++++- ...TopologySuiteMethodCallTranslatorPlugin.cs | 6 ++- .../Query/SpatialQueryNpgsqlGeographyTest.cs | 11 ++++ .../Query/SpatialQueryNpgsqlGeometryTest.cs | 52 ++++++++++++++++++- 4 files changed, 92 insertions(+), 6 deletions(-) diff --git a/src/EFCore.PG.NTS/Query/ExpressionTranslators/Internal/NpgsqlNetTopologySuiteMemberTranslatorPlugin.cs b/src/EFCore.PG.NTS/Query/ExpressionTranslators/Internal/NpgsqlNetTopologySuiteMemberTranslatorPlugin.cs index 7bb1d0959..31ebb2ba6 100644 --- a/src/EFCore.PG.NTS/Query/ExpressionTranslators/Internal/NpgsqlNetTopologySuiteMemberTranslatorPlugin.cs +++ b/src/EFCore.PG.NTS/Query/ExpressionTranslators/Internal/NpgsqlNetTopologySuiteMemberTranslatorPlugin.cs @@ -86,9 +86,34 @@ public Expression Translate(MemberExpression e) return new SqlFunctionExpression("ST_NumInteriorRings", typeof(int), new[] { e.Expression }); case "NumPoints": return new SqlFunctionExpression("ST_NumPoints", typeof(int), new[] { e.Expression }); + case "OgcGeometryType": + { + var whenThenList = new List + { + new CaseWhenClause(Expression.Constant("ST_CircularString"), Expression.Constant(OgcGeometryType.CircularString)), + new CaseWhenClause(Expression.Constant("ST_CompoundCurve"), Expression.Constant(OgcGeometryType.CompoundCurve)), + new CaseWhenClause(Expression.Constant("ST_CurvePolygon"), Expression.Constant(OgcGeometryType.CurvePolygon)), + new CaseWhenClause(Expression.Constant("ST_GeometryCollection"), Expression.Constant(OgcGeometryType.GeometryCollection)), + new CaseWhenClause(Expression.Constant("ST_LineString"), Expression.Constant(OgcGeometryType.LineString)), + new CaseWhenClause(Expression.Constant("ST_MultiCurve"), Expression.Constant(OgcGeometryType.MultiCurve)), + new CaseWhenClause(Expression.Constant("ST_MultiLineString"), Expression.Constant(OgcGeometryType.MultiLineString)), + new CaseWhenClause(Expression.Constant("ST_MultiPoint"), Expression.Constant(OgcGeometryType.MultiPoint)), + new CaseWhenClause(Expression.Constant("ST_MultiPolygon"), Expression.Constant(OgcGeometryType.MultiPolygon)), + new CaseWhenClause(Expression.Constant("ST_MultiSurface"), Expression.Constant(OgcGeometryType.MultiSurface)), + new CaseWhenClause(Expression.Constant("ST_Point"), Expression.Constant(OgcGeometryType.Point)), + new CaseWhenClause(Expression.Constant("ST_Polygon"), Expression.Constant(OgcGeometryType.Polygon)), + new CaseWhenClause(Expression.Constant("ST_PolyhedralSurface"), Expression.Constant(OgcGeometryType.PolyhedralSurface)), + new CaseWhenClause(Expression.Constant("ST_Tin"), Expression.Constant(OgcGeometryType.TIN)) + }; + + return new CaseExpression( + new SqlFunctionExpression("ST_GeometryType", typeof(string), new[] { e.Expression }), + whenThenList.ToArray()); + } case "PointOnSurface": - return new SqlFunctionExpression("ST_PointOnSurface", typeof(IPoint), new[] { e.Expression }); - case "SRID": + case "InteriorPoint": + return new SqlFunctionExpression("ST_PointOnSurface", typeof(IGeometry), new[] { e.Expression }); + case "SRID": return new SqlFunctionExpression("ST_SRID", typeof(int), new[] { e.Expression }); case "StartPoint": return new SqlFunctionExpression("ST_StartPoint", typeof(IPoint), new[] { e.Expression }); diff --git a/src/EFCore.PG.NTS/Query/ExpressionTranslators/Internal/NpgsqlNetTopologySuiteMethodCallTranslatorPlugin.cs b/src/EFCore.PG.NTS/Query/ExpressionTranslators/Internal/NpgsqlNetTopologySuiteMethodCallTranslatorPlugin.cs index 1d3a030cc..725659eae 100644 --- a/src/EFCore.PG.NTS/Query/ExpressionTranslators/Internal/NpgsqlNetTopologySuiteMethodCallTranslatorPlugin.cs +++ b/src/EFCore.PG.NTS/Query/ExpressionTranslators/Internal/NpgsqlNetTopologySuiteMethodCallTranslatorPlugin.cs @@ -42,8 +42,10 @@ public virtual Expression Translate(MethodCallExpression e, IDiagnosticsLogger Task.CompletedTask; public override Task IsValid(bool isAsync) => Task.CompletedTask; public override Task Item(bool isAsync) => Task.CompletedTask; + public override Task InteriorPoint(bool isAsync) => Task.CompletedTask; public override Task LineString_Count(bool isAsync) => Task.CompletedTask; public override Task M(bool isAsync) => Task.CompletedTask; public override Task NumGeometries(bool isAsync) => Task.CompletedTask; public override Task NumInteriorRings(bool isAsync) => Task.CompletedTask; public override Task NumPoints(bool isAsync) => Task.CompletedTask; + public override Task OgcGeometryType(bool isAsync) => Task.CompletedTask; public override Task Overlaps(bool isAsync) => Task.CompletedTask; public override Task PointOnSurface(bool isAsync) => Task.CompletedTask; public override Task Relate(bool isAsync) => Task.CompletedTask; diff --git a/test/EFCore.PG.FunctionalTests/Query/SpatialQueryNpgsqlGeometryTest.cs b/test/EFCore.PG.FunctionalTests/Query/SpatialQueryNpgsqlGeometryTest.cs index a133f4c63..a53e23c72 100644 --- a/test/EFCore.PG.FunctionalTests/Query/SpatialQueryNpgsqlGeometryTest.cs +++ b/test/EFCore.PG.FunctionalTests/Query/SpatialQueryNpgsqlGeometryTest.cs @@ -59,6 +59,15 @@ public override async Task Buffer(bool isAsync) FROM ""PolygonEntity"" AS e"); } + public override async Task Buffer_quadrantSegments(bool isAsync) + { + await base.Buffer_quadrantSegments(isAsync); + + AssertSql( + @"SELECT e.""Id"", ST_Buffer(e.""Polygon"", 1.0, 8) AS ""Buffer"" +FROM ""PolygonEntity"" AS e"); + } + public override async Task Centroid(bool isAsync) { await base.Centroid(isAsync); @@ -248,6 +257,15 @@ public override async Task GetPointN(bool isAsync) FROM ""LineStringEntity"" AS e"); } + public override async Task InteriorPoint(bool isAsync) + { + await base.InteriorPoint(isAsync); + + AssertSql( + @"SELECT e.""Id"", ST_PointOnSurface(e.""Polygon"") AS ""InteriorPoint"", e.""Polygon"" +FROM ""PolygonEntity"" AS e"); + } + public override async Task Intersection(bool isAsync) { await base.Intersection(isAsync); @@ -393,6 +411,30 @@ public override async Task NumPoints(bool isAsync) FROM ""LineStringEntity"" AS e"); } + public override async Task OgcGeometryType(bool isAsync) + { + await base.OgcGeometryType(isAsync); + + AssertSql( + @"SELECT e.""Id"", CASE ST_GeometryType(e.""Point"") + WHEN 'ST_CircularString' THEN 8 + WHEN 'ST_CompoundCurve' THEN 9 + WHEN 'ST_CurvePolygon' THEN 10 + WHEN 'ST_GeometryCollection' THEN 7 + WHEN 'ST_LineString' THEN 2 + WHEN 'ST_MultiCurve' THEN 11 + WHEN 'ST_MultiLineString' THEN 5 + WHEN 'ST_MultiPoint' THEN 4 + WHEN 'ST_MultiPolygon' THEN 6 + WHEN 'ST_MultiSurface' THEN 12 + WHEN 'ST_Point' THEN 1 + WHEN 'ST_Polygon' THEN 3 + WHEN 'ST_PolyhedralSurface' THEN 15 + WHEN 'ST_Tin' THEN 16 +END AS ""OgcGeometryType"" +FROM ""PointEntity"" AS e"); + } + public override async Task Overlaps(bool isAsync) { await base.Overlaps(isAsync); @@ -508,8 +550,14 @@ 1 1 FROM ""PolygonEntity"" AS e"); } - [ConditionalTheory(Skip="ST_Union() with only one parameter is an aggregate function in PostGIS")] - public override Task Union_void(bool isAsync) => null; + public override async Task Union_void(bool isAsync) + { + await base.Union_void(isAsync); + + AssertSql( + @"SELECT e.""Id"", ST_UnaryUnion(e.""MultiLineString"") AS ""Union"" +FROM ""MultiLineStringEntity"" AS e"); + } public override async Task Within(bool isAsync) { From b7e75b88b200117c5a58342dab9fb146973d28f5 Mon Sep 17 00:00:00 2001 From: Yoh Deadfall Date: Sun, 17 Mar 2019 17:13:16 -0400 Subject: [PATCH 2/5] Update src/EFCore.PG.NTS/Query/ExpressionTranslators/Internal/NpgsqlNetTopologySuiteMemberTranslatorPlugin.cs Fixed indentation Co-Authored-By: EricStG --- .../Internal/NpgsqlNetTopologySuiteMemberTranslatorPlugin.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/EFCore.PG.NTS/Query/ExpressionTranslators/Internal/NpgsqlNetTopologySuiteMemberTranslatorPlugin.cs b/src/EFCore.PG.NTS/Query/ExpressionTranslators/Internal/NpgsqlNetTopologySuiteMemberTranslatorPlugin.cs index 31ebb2ba6..32b351b21 100644 --- a/src/EFCore.PG.NTS/Query/ExpressionTranslators/Internal/NpgsqlNetTopologySuiteMemberTranslatorPlugin.cs +++ b/src/EFCore.PG.NTS/Query/ExpressionTranslators/Internal/NpgsqlNetTopologySuiteMemberTranslatorPlugin.cs @@ -113,7 +113,7 @@ public Expression Translate(MemberExpression e) case "PointOnSurface": case "InteriorPoint": return new SqlFunctionExpression("ST_PointOnSurface", typeof(IGeometry), new[] { e.Expression }); - case "SRID": + case "SRID": return new SqlFunctionExpression("ST_SRID", typeof(int), new[] { e.Expression }); case "StartPoint": return new SqlFunctionExpression("ST_StartPoint", typeof(IPoint), new[] { e.Expression }); From 9c298a5e78e1c8c33d31cb3d90a438ca1207cce7 Mon Sep 17 00:00:00 2001 From: Eric St-Georges Date: Mon, 18 Mar 2019 17:07:21 -0400 Subject: [PATCH 3/5] Moved the collection to a static member and removed extra call to ToArray --- ...lNetTopologySuiteMemberTranslatorPlugin.cs | 40 +++++++++---------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/src/EFCore.PG.NTS/Query/ExpressionTranslators/Internal/NpgsqlNetTopologySuiteMemberTranslatorPlugin.cs b/src/EFCore.PG.NTS/Query/ExpressionTranslators/Internal/NpgsqlNetTopologySuiteMemberTranslatorPlugin.cs index 32b351b21..7230a0185 100644 --- a/src/EFCore.PG.NTS/Query/ExpressionTranslators/Internal/NpgsqlNetTopologySuiteMemberTranslatorPlugin.cs +++ b/src/EFCore.PG.NTS/Query/ExpressionTranslators/Internal/NpgsqlNetTopologySuiteMemberTranslatorPlugin.cs @@ -1,4 +1,4 @@ -using System.Collections.Generic; +using System.Collections.Generic; using System.Linq.Expressions; using GeoAPI.Geometries; using Microsoft.EntityFrameworkCore.Query.Expressions; @@ -18,6 +18,24 @@ public class NpgsqlNetTopologySuiteMemberTranslatorPlugin : IMemberTranslatorPlu public class NpgsqlGeometryMemberTranslator : IMemberTranslator { + private static readonly CaseWhenClause[] _ogcGeometryTypeWhenThenList = new[] + { + new CaseWhenClause(Expression.Constant("ST_CircularString"), Expression.Constant(OgcGeometryType.CircularString)), + new CaseWhenClause(Expression.Constant("ST_CompoundCurve"), Expression.Constant(OgcGeometryType.CompoundCurve)), + new CaseWhenClause(Expression.Constant("ST_CurvePolygon"), Expression.Constant(OgcGeometryType.CurvePolygon)), + new CaseWhenClause(Expression.Constant("ST_GeometryCollection"), Expression.Constant(OgcGeometryType.GeometryCollection)), + new CaseWhenClause(Expression.Constant("ST_LineString"), Expression.Constant(OgcGeometryType.LineString)), + new CaseWhenClause(Expression.Constant("ST_MultiCurve"), Expression.Constant(OgcGeometryType.MultiCurve)), + new CaseWhenClause(Expression.Constant("ST_MultiLineString"), Expression.Constant(OgcGeometryType.MultiLineString)), + new CaseWhenClause(Expression.Constant("ST_MultiPoint"), Expression.Constant(OgcGeometryType.MultiPoint)), + new CaseWhenClause(Expression.Constant("ST_MultiPolygon"), Expression.Constant(OgcGeometryType.MultiPolygon)), + new CaseWhenClause(Expression.Constant("ST_MultiSurface"), Expression.Constant(OgcGeometryType.MultiSurface)), + new CaseWhenClause(Expression.Constant("ST_Point"), Expression.Constant(OgcGeometryType.Point)), + new CaseWhenClause(Expression.Constant("ST_Polygon"), Expression.Constant(OgcGeometryType.Polygon)), + new CaseWhenClause(Expression.Constant("ST_PolyhedralSurface"), Expression.Constant(OgcGeometryType.PolyhedralSurface)), + new CaseWhenClause(Expression.Constant("ST_Tin"), Expression.Constant(OgcGeometryType.TIN)) + }; + public Expression Translate(MemberExpression e) { var declaringType = e.Member.DeclaringType; @@ -88,27 +106,9 @@ public Expression Translate(MemberExpression e) return new SqlFunctionExpression("ST_NumPoints", typeof(int), new[] { e.Expression }); case "OgcGeometryType": { - var whenThenList = new List - { - new CaseWhenClause(Expression.Constant("ST_CircularString"), Expression.Constant(OgcGeometryType.CircularString)), - new CaseWhenClause(Expression.Constant("ST_CompoundCurve"), Expression.Constant(OgcGeometryType.CompoundCurve)), - new CaseWhenClause(Expression.Constant("ST_CurvePolygon"), Expression.Constant(OgcGeometryType.CurvePolygon)), - new CaseWhenClause(Expression.Constant("ST_GeometryCollection"), Expression.Constant(OgcGeometryType.GeometryCollection)), - new CaseWhenClause(Expression.Constant("ST_LineString"), Expression.Constant(OgcGeometryType.LineString)), - new CaseWhenClause(Expression.Constant("ST_MultiCurve"), Expression.Constant(OgcGeometryType.MultiCurve)), - new CaseWhenClause(Expression.Constant("ST_MultiLineString"), Expression.Constant(OgcGeometryType.MultiLineString)), - new CaseWhenClause(Expression.Constant("ST_MultiPoint"), Expression.Constant(OgcGeometryType.MultiPoint)), - new CaseWhenClause(Expression.Constant("ST_MultiPolygon"), Expression.Constant(OgcGeometryType.MultiPolygon)), - new CaseWhenClause(Expression.Constant("ST_MultiSurface"), Expression.Constant(OgcGeometryType.MultiSurface)), - new CaseWhenClause(Expression.Constant("ST_Point"), Expression.Constant(OgcGeometryType.Point)), - new CaseWhenClause(Expression.Constant("ST_Polygon"), Expression.Constant(OgcGeometryType.Polygon)), - new CaseWhenClause(Expression.Constant("ST_PolyhedralSurface"), Expression.Constant(OgcGeometryType.PolyhedralSurface)), - new CaseWhenClause(Expression.Constant("ST_Tin"), Expression.Constant(OgcGeometryType.TIN)) - }; - return new CaseExpression( new SqlFunctionExpression("ST_GeometryType", typeof(string), new[] { e.Expression }), - whenThenList.ToArray()); + _ogcGeometryTypeWhenThenList); } case "PointOnSurface": case "InteriorPoint": From 09cc780b0cbf8d45cbf8ded2e6ebf4085b721ea0 Mon Sep 17 00:00:00 2001 From: Eric St-Georges Date: Tue, 19 Mar 2019 08:48:14 -0400 Subject: [PATCH 4/5] Removed unnecessary brackets --- .../Internal/NpgsqlNetTopologySuiteMemberTranslatorPlugin.cs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/EFCore.PG.NTS/Query/ExpressionTranslators/Internal/NpgsqlNetTopologySuiteMemberTranslatorPlugin.cs b/src/EFCore.PG.NTS/Query/ExpressionTranslators/Internal/NpgsqlNetTopologySuiteMemberTranslatorPlugin.cs index 7230a0185..387703f40 100644 --- a/src/EFCore.PG.NTS/Query/ExpressionTranslators/Internal/NpgsqlNetTopologySuiteMemberTranslatorPlugin.cs +++ b/src/EFCore.PG.NTS/Query/ExpressionTranslators/Internal/NpgsqlNetTopologySuiteMemberTranslatorPlugin.cs @@ -105,11 +105,9 @@ public Expression Translate(MemberExpression e) case "NumPoints": return new SqlFunctionExpression("ST_NumPoints", typeof(int), new[] { e.Expression }); case "OgcGeometryType": - { return new CaseExpression( - new SqlFunctionExpression("ST_GeometryType", typeof(string), new[] { e.Expression }), + new SqlFunctionExpression("ST_GeometryType", typeof(string), new[] { e.Expression }), _ogcGeometryTypeWhenThenList); - } case "PointOnSurface": case "InteriorPoint": return new SqlFunctionExpression("ST_PointOnSurface", typeof(IGeometry), new[] { e.Expression }); From c752d124161ed30d9eb9c89e29bc0d33a05a1afa Mon Sep 17 00:00:00 2001 From: Eric St-Georges Date: Sun, 31 Mar 2019 14:11:17 -0400 Subject: [PATCH 5/5] PR review feedback: Reduced ST_Buffer case statements in NpgsqlGeometryMethodTranslator to one Removed superflous private modifier --- .../NpgsqlNetTopologySuiteMemberTranslatorPlugin.cs | 2 +- .../NpgsqlNetTopologySuiteMethodCallTranslatorPlugin.cs | 7 +++---- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/src/EFCore.PG.NTS/Query/ExpressionTranslators/Internal/NpgsqlNetTopologySuiteMemberTranslatorPlugin.cs b/src/EFCore.PG.NTS/Query/ExpressionTranslators/Internal/NpgsqlNetTopologySuiteMemberTranslatorPlugin.cs index 387703f40..473b95cb5 100644 --- a/src/EFCore.PG.NTS/Query/ExpressionTranslators/Internal/NpgsqlNetTopologySuiteMemberTranslatorPlugin.cs +++ b/src/EFCore.PG.NTS/Query/ExpressionTranslators/Internal/NpgsqlNetTopologySuiteMemberTranslatorPlugin.cs @@ -18,7 +18,7 @@ public class NpgsqlNetTopologySuiteMemberTranslatorPlugin : IMemberTranslatorPlu public class NpgsqlGeometryMemberTranslator : IMemberTranslator { - private static readonly CaseWhenClause[] _ogcGeometryTypeWhenThenList = new[] + static readonly CaseWhenClause[] _ogcGeometryTypeWhenThenList = new[] { new CaseWhenClause(Expression.Constant("ST_CircularString"), Expression.Constant(OgcGeometryType.CircularString)), new CaseWhenClause(Expression.Constant("ST_CompoundCurve"), Expression.Constant(OgcGeometryType.CompoundCurve)), diff --git a/src/EFCore.PG.NTS/Query/ExpressionTranslators/Internal/NpgsqlNetTopologySuiteMethodCallTranslatorPlugin.cs b/src/EFCore.PG.NTS/Query/ExpressionTranslators/Internal/NpgsqlNetTopologySuiteMethodCallTranslatorPlugin.cs index 725659eae..91de01ce0 100644 --- a/src/EFCore.PG.NTS/Query/ExpressionTranslators/Internal/NpgsqlNetTopologySuiteMethodCallTranslatorPlugin.cs +++ b/src/EFCore.PG.NTS/Query/ExpressionTranslators/Internal/NpgsqlNetTopologySuiteMethodCallTranslatorPlugin.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Linq; using System.Linq.Expressions; using System.Reflection; using GeoAPI.Geometries; @@ -42,10 +43,8 @@ public virtual Expression Translate(MethodCallExpression e, IDiagnosticsLogger