-
Notifications
You must be signed in to change notification settings - Fork 228
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Closes #2384
- Loading branch information
Showing
9 changed files
with
164 additions
and
64 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
93 changes: 93 additions & 0 deletions
93
...pressionTranslators/Internal/NpgsqlNetTopologySuiteAggregateMethodCallTranslatorPlugin.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,93 @@ | ||
using NetTopologySuite.Algorithm; | ||
using NetTopologySuite.Geometries.Utilities; | ||
using NetTopologySuite.Operation.Union; | ||
|
||
// ReSharper disable once CheckNamespace | ||
namespace Npgsql.EntityFrameworkCore.PostgreSQL.Query.ExpressionTranslators.Internal; | ||
|
||
public class NpgsqlNetTopologySuiteAggregateMethodCallTranslatorPlugin : IAggregateMethodCallTranslatorPlugin | ||
{ | ||
public NpgsqlNetTopologySuiteAggregateMethodCallTranslatorPlugin( | ||
IRelationalTypeMappingSource typeMappingSource, | ||
ISqlExpressionFactory sqlExpressionFactory) | ||
{ | ||
if (sqlExpressionFactory is not NpgsqlSqlExpressionFactory npgsqlSqlExpressionFactory) | ||
{ | ||
throw new ArgumentException($"Must be an {nameof(NpgsqlSqlExpressionFactory)}", nameof(sqlExpressionFactory)); | ||
} | ||
|
||
Translators = new IAggregateMethodCallTranslator[] | ||
{ | ||
new NpgsqlNetTopologySuiteAggregateMethodTranslator(npgsqlSqlExpressionFactory, typeMappingSource) | ||
}; | ||
} | ||
|
||
public virtual IEnumerable<IAggregateMethodCallTranslator> Translators { get; } | ||
} | ||
|
||
public class NpgsqlNetTopologySuiteAggregateMethodTranslator : IAggregateMethodCallTranslator | ||
{ | ||
private static readonly MethodInfo GeometryCombineMethod | ||
= typeof(GeometryCombiner).GetRuntimeMethod(nameof(GeometryCombiner.Combine), new[] { typeof(IEnumerable<Geometry>) })!; | ||
|
||
private static readonly MethodInfo ConvexHullMethod | ||
= typeof(ConvexHull).GetRuntimeMethod(nameof(ConvexHull.Create), new[] { typeof(IEnumerable<Geometry>) })!; | ||
|
||
private static readonly MethodInfo UnionMethod | ||
= typeof(UnaryUnionOp).GetRuntimeMethod(nameof(UnaryUnionOp.Union), new[] { typeof(IEnumerable<Geometry>) })!; | ||
|
||
private readonly NpgsqlSqlExpressionFactory _sqlExpressionFactory; | ||
private readonly IRelationalTypeMappingSource _typeMappingSource; | ||
|
||
public NpgsqlNetTopologySuiteAggregateMethodTranslator( | ||
NpgsqlSqlExpressionFactory sqlExpressionFactory, | ||
IRelationalTypeMappingSource typeMappingSource) | ||
{ | ||
_sqlExpressionFactory = sqlExpressionFactory; | ||
_typeMappingSource = typeMappingSource; | ||
} | ||
|
||
public virtual SqlExpression? Translate( | ||
MethodInfo method, EnumerableExpression source, IReadOnlyList<SqlExpression> arguments, | ||
IDiagnosticsLogger<DbLoggerCategory.Query> logger) | ||
{ | ||
if (source.Selector is not SqlExpression sqlExpression | ||
|| (method != GeometryCombineMethod && method != UnionMethod && method != ConvexHullMethod)) | ||
{ | ||
return null; | ||
} | ||
|
||
var resultTypeMapping = _typeMappingSource.FindMapping(typeof(Geometry), sqlExpression.TypeMapping?.StoreType ?? "geometry"); | ||
|
||
if (method == GeometryCombineMethod || method == UnionMethod) | ||
{ | ||
return _sqlExpressionFactory.AggregateFunction( | ||
method == GeometryCombineMethod ? "ST_Collect" : "ST_Union", | ||
new[] { sqlExpression }, | ||
source, | ||
nullable: true, | ||
argumentsPropagateNullability: new[] { false }, | ||
typeof(Geometry), | ||
resultTypeMapping); | ||
} | ||
|
||
// PostGIS has no built-in aggregate convex hull, but we can simply apply ST_Collect beforehand as recommended in the docs | ||
// https://postgis.net/docs/ST_ConvexHull.html | ||
return _sqlExpressionFactory.Function( | ||
"ST_ConvexHull", | ||
new[] | ||
{ | ||
_sqlExpressionFactory.Function( | ||
"ST_Collect", | ||
new[] { sqlExpression }, | ||
nullable: true, | ||
argumentsPropagateNullability: new[] { false }, | ||
typeof(Geometry), | ||
resultTypeMapping) | ||
}, | ||
nullable: true, | ||
argumentsPropagateNullability: new[] { true }, | ||
typeof(Geometry), | ||
resultTypeMapping); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.