Skip to content

Commit

Permalink
Merge pull request #136 from nhibernate/feature/spatial-restriction-c…
Browse files Browse the repository at this point in the history
…riteria

Implement missing spatial restriction criteria
  • Loading branch information
peetw authored Jan 21, 2024
2 parents 5c8a953 + 5a92850 commit cd1c446
Show file tree
Hide file tree
Showing 40 changed files with 9,156 additions and 2,927 deletions.
26 changes: 26 additions & 0 deletions NHibernate.Spatial.MsSql/Dialect/MsSql2012FunctionRegistration.cs
Original file line number Diff line number Diff line change
Expand Up @@ -413,6 +413,9 @@ public SqlString GetSpatialRelationString(object geometry, SpatialRelation relat
case SpatialRelation.CoveredBy:
return GetSpatialRelationString(anotherGeometry, SpatialRelation.Covers, geometry, criterion);

case SpatialRelation.EqualsExact:
throw new NotSupportedException($"{relation} not supported by SQL Server");

default:
// NOTE: Cast is only required if "geometry" is passed in as a parameter
// directly, rather than as a column name. This is because parameter
Expand All @@ -434,6 +437,29 @@ public SqlString GetSpatialRelationString(object geometry, SpatialRelation relat
}
}

public SqlString GetSpatialRelationString(object geometry, SpatialRelation relation, object anotherGeometry, object parameter, bool criterion)
{
switch (relation)
{
case SpatialRelation.IsWithinDistance:
return new SqlStringBuilder()
.Add("CASE WHEN ")
.AddObject(geometry)
.Add(".STDistance(")
.AddObject(anotherGeometry)
.Add(")")
.Add(" <= ")
.Add(parameter.ToString())
.Add(" THEN 1 ELSE 0 END")
.Add(criterion ? " = 1" : "")
.ToSqlString();
case SpatialRelation.Relate:
return GetSpatialRelateString(geometry, anotherGeometry, parameter, true, criterion);
default:
throw new ArgumentOutOfRangeException(nameof(relation), relation, "Unsupported spatial relation");
}
}

public SqlString GetSpatialFilterString(string tableAlias, string geometryColumnName, string primaryKeyColumnName, string tableName, Parameter parameter)
{
return new SqlStringBuilder(6)
Expand Down
5 changes: 5 additions & 0 deletions NHibernate.Spatial.MsSql/Dialect/MsSql2012SpatialDialect.cs
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,11 @@ public SqlString GetSpatialRelationString(object geometry, SpatialRelation relat
return worker.GetSpatialRelationString(geometry, relation, anotherGeometry, criterion);
}

public SqlString GetSpatialRelationString(object geometry, SpatialRelation relation, object anotherGeometry, object parameter, bool criterion)
{
return worker.GetSpatialRelationString(geometry, relation, anotherGeometry, parameter, criterion);
}

public SqlString GetSpatialFilterString(string tableAlias, string geometryColumnName, string primaryKeyColumnName, string tableName, Parameter parameter)
{
return worker.GetSpatialFilterString(tableAlias, geometryColumnName, primaryKeyColumnName, tableName, parameter);
Expand Down
23 changes: 23 additions & 0 deletions NHibernate.Spatial.MySQL/Dialect/MySQL57SpatialDialect.cs
Original file line number Diff line number Diff line change
Expand Up @@ -331,6 +331,9 @@ public SqlString GetSpatialRelationString(object geometry, SpatialRelation relat
case SpatialRelation.CoveredBy:
return GetSpatialRelationString(anotherGeometry, SpatialRelation.Covers, geometry, criterion);

case SpatialRelation.EqualsExact:
throw new NotSupportedException($"{relation} not supported by SQL Server");

default:
return new SqlStringBuilder(6)
.Add(SpatialDialect.IsoPrefix)
Expand All @@ -344,6 +347,26 @@ public SqlString GetSpatialRelationString(object geometry, SpatialRelation relat
}
}

public SqlString GetSpatialRelationString(object geometry, SpatialRelation relation, object anotherGeometry, object parameter, bool criterion)
{
switch (relation)
{
case SpatialRelation.IsWithinDistance:
return new SqlStringBuilder()
.Add(SpatialDialect.IsoPrefix)
.Add("Distance(")
.AddObject(geometry)
.Add(", ")
.AddObject(anotherGeometry)
.Add(")")
.Add(" <= ")
.Add(parameter.ToString())
.ToSqlString();
default:
throw new ArgumentOutOfRangeException(nameof(relation), relation, "Unsupported spatial relation");
}
}

public SqlString GetSpatialRelateString(object geometry, object anotherGeometry, object pattern, bool isStringPattern, bool criterion)
{
var builder = new SqlStringBuilder();
Expand Down
43 changes: 43 additions & 0 deletions NHibernate.Spatial.PostGis/Dialect/PostGis20Dialect.cs
Original file line number Diff line number Diff line change
Expand Up @@ -320,6 +320,16 @@ public SqlString GetSpatialRelationString(object geometry, SpatialRelation relat
case SpatialRelation.CoveredBy:
return GetSpatialRelationString(anotherGeometry, SpatialRelation.Covers, geometry, criterion);

case SpatialRelation.EqualsExact:
return new SqlStringBuilder()
.Add(SpatialDialect.IsoPrefix)
.Add("OrderingEquals(")
.AddObject(geometry)
.Add(", ")
.AddObject(anotherGeometry)
.Add(")")
.ToSqlString();

default:
return new SqlStringBuilder(6)
.Add(SpatialDialect.IsoPrefix)
Expand All @@ -335,6 +345,39 @@ public SqlString GetSpatialRelationString(object geometry, SpatialRelation relat
}
}

public SqlString GetSpatialRelationString(object geometry, SpatialRelation relation, object anotherGeometry, object parameter, bool criterion)
{
switch (relation)
{
case SpatialRelation.IsWithinDistance:
return new SqlStringBuilder()
.Add(SpatialDialect.IsoPrefix)
.Add("DWithin")
.Add("(")
.AddObject(geometry)
.Add(", ")
.AddObject(anotherGeometry)
.Add(", ")
.Add(parameter.ToString())
.Add(")")
.ToSqlString();
case SpatialRelation.Relate:
return new SqlStringBuilder()
.Add(SpatialDialect.IsoPrefix)
.Add(relation.ToString())
.Add("(")
.AddObject(geometry)
.Add(", ")
.AddObject(anotherGeometry)
.Add(", '")
.Add(parameter.ToString())
.Add("')")
.ToSqlString();
default:
throw new ArgumentOutOfRangeException(nameof(relation), relation, "Unsupported spatial relation");
}
}

public SqlString GetSpatialRelateString(object geometry, object anotherGeometry, object pattern, bool isStringPattern, bool criterion)
{
var builder = new SqlStringBuilder();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -107,9 +107,9 @@ public AbstractCriterion Eq(object value)
/// <summary>
/// Apply a "eq exact" constraint to the named property
/// </summary>
public AbstractCriterion EqExact(object value, double tolerance)
public AbstractCriterion EqExact(object value)
{
return Process(SpatialRestrictions.EqExact(propertyName, value, tolerance));
return Process(SpatialRestrictions.EqExact(propertyName, value));
}

/// <summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -101,9 +101,9 @@ public TReturn Eq(object value)
/// <summary>
/// Apply a "eq exact" constraint to the named property
/// </summary>
public TReturn EqExact(object value, double tolerance)
public TReturn EqExact(object value)
{
return Add(SpatialRestrictions.EqExact(propertyName, value, tolerance));
return Add(SpatialRestrictions.EqExact(propertyName, value));
}

/// <summary>
Expand Down
23 changes: 23 additions & 0 deletions NHibernate.Spatial/Criterion/SpatialProjections.cs
Original file line number Diff line number Diff line change
Expand Up @@ -246,6 +246,17 @@ public static SpatialProjection Equals(string propertyName, string anotherProper
return new SpatialRelationProjection(propertyName, SpatialRelation.Equals, anotherPropertyName);
}

/// <summary>
/// Determines whether the specified geometry property is exactly equal to another geometry property.
/// </summary>
/// <param name="propertyName">Name of the property.</param>
/// <param name="anotherPropertyName">Name of another property.</param>
/// <returns></returns>
public static SpatialProjection EqualsExact(string propertyName, string anotherPropertyName)
{
return new SpatialRelationProjection(propertyName, SpatialRelation.EqualsExact, anotherPropertyName);
}

/// <summary>
/// Determines whether the specified geometry property intersects another geometry property.
/// </summary>
Expand All @@ -257,6 +268,18 @@ public static SpatialProjection Intersects(string propertyName, string anotherPr
return new SpatialRelationProjection(propertyName, SpatialRelation.Intersects, anotherPropertyName);
}

/// <summary>
/// Determines whether the specified geometry property is within a given distance of another geometry.
/// </summary>
/// <param name="propertyName">Name of the property.</param>
/// <param name="anotherPropertyName">Name of another property.</param>
/// <param name="distance">The distance.</param>
/// <returns></returns>
public static SpatialProjection IsWithinDistance(string propertyName, string anotherPropertyName, double distance)
{
return new SpatialRelationProjection(propertyName, SpatialRelation.IsWithinDistance, anotherPropertyName, distance);
}

/// <summary>
/// Determines whether the specified geometry property overlaps another geometry property.
/// </summary>
Expand Down
23 changes: 23 additions & 0 deletions NHibernate.Spatial/Criterion/SpatialProjectionsLambda.cs
Original file line number Diff line number Diff line change
Expand Up @@ -258,6 +258,17 @@ public static SpatialProjection Equals<T>(Expression<Func<T, object>> expression
return Equals(GetPropertyName(expression), GetPropertyName(anotherExpression));
}

/// <summary>
/// Determines whether the specified geometry property is exactly equal to another geometry property.
/// </summary>
/// <param name="expression">Name of the property.</param>
/// <param name="anotherExpression">Name of another property.</param>
/// <returns></returns>
public static SpatialProjection EqualsExact<T>(Expression<Func<T, object>> expression, Expression<Func<T, object>> anotherExpression)
{
return EqualsExact(GetPropertyName(expression), GetPropertyName(anotherExpression));
}

/// <summary>
/// Determines whether the specified geometry property intersects another geometry property.
/// </summary>
Expand All @@ -269,6 +280,18 @@ public static SpatialProjection Intersects<T>(Expression<Func<T, object>> expres
return Intersects(GetPropertyName(expression), GetPropertyName(anotherExpression));
}

/// <summary>
/// Determines whether the specified geometry property is within a given distance of another geometry.
/// </summary>
/// <param name="expression">Name of the property.</param>
/// <param name="anotherExpression">Name of another property.</param>
/// <param name="distance">The distance.</param>
/// <returns></returns>
public static SpatialProjection IsWithinDistance<T>(Expression<Func<T, object>> expression, Expression<Func<T, object>> anotherExpression, double distance)
{
return IsWithinDistance(GetPropertyName(expression), GetPropertyName(anotherExpression), distance);
}

/// <summary>
/// Determines whether the specified geometry property overlaps another geometry property.
/// </summary>
Expand Down
55 changes: 38 additions & 17 deletions NHibernate.Spatial/Criterion/SpatialRelationCriterion.cs
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,23 @@ namespace NHibernate.Spatial.Criterion
[Serializable]
public class SpatialRelationCriterion : AbstractCriterion
{
private readonly string propertyName;
private readonly SpatialRelation relation;
private readonly object anotherGeometry;
private readonly string _propertyName;
private readonly SpatialRelation _relation;
private readonly object _anotherGeometry;
private readonly object _parameter;

/// <summary>
/// Initializes a new instance of the <see cref="SpatialRelationCriterion"/> class.
/// </summary>
/// <param name="propertyName">Name of the property.</param>
/// <param name="relation">The relation.</param>
/// <param name="anotherGeometry">Another geometry.</param>
/// <param name="parameter">Additional parameter value</param>
public SpatialRelationCriterion(string propertyName, SpatialRelation relation, object anotherGeometry, object parameter)
: this(propertyName, relation, anotherGeometry)
{
_parameter = parameter;
}

/// <summary>
/// Initializes a new instance of the <see cref="SpatialRelationCriterion"/> class.
Expand All @@ -44,9 +58,9 @@ public class SpatialRelationCriterion : AbstractCriterion
/// <param name="anotherGeometry">Another geometry.</param>
public SpatialRelationCriterion(string propertyName, SpatialRelation relation, object anotherGeometry)
{
this.propertyName = propertyName;
this.relation = relation;
this.anotherGeometry = anotherGeometry;
_propertyName = propertyName;
_relation = relation;
_anotherGeometry = anotherGeometry;
}

/// <summary>
Expand All @@ -59,9 +73,9 @@ public SpatialRelationCriterion(string propertyName, SpatialRelation relation, o
/// </returns>
public override TypedValue[] GetTypedValues(ICriteria criteria, ICriteriaQuery criteriaQuery)
{
if (anotherGeometry is Geometry)
if (_anotherGeometry is Geometry)
{
return new[] { criteriaQuery.GetTypedValue(criteria, propertyName, anotherGeometry) };
return new[] { criteriaQuery.GetTypedValue(criteria, _propertyName, _anotherGeometry) };
}
return Array.Empty<TypedValue>();
}
Expand All @@ -81,9 +95,8 @@ public override IProjection[] GetProjections()
/// </returns>
public override SqlString ToSqlString(ICriteria criteria, ICriteriaQuery criteriaQuery)
{
//criteriaQuery.AddUsedTypedValues(GetTypedValues(criteria, criteriaQuery));
var spatialDialect = (ISpatialDialect) criteriaQuery.Factory.Dialect;
string[] columns1 = GetColumnNames(criteria, criteriaQuery, propertyName);
string[] columns1 = GetColumnNames(criteria, criteriaQuery, _propertyName);

var builder = new SqlStringBuilder(10*columns1.Length);
for (int i = 0; i < columns1.Length; i++)
Expand All @@ -92,17 +105,25 @@ public override SqlString ToSqlString(ICriteria criteria, ICriteriaQuery criteri
{
builder.Add(" AND ");
}
if (anotherGeometry is Geometry)

object anotherGeometry;
if (_anotherGeometry is Geometry)
{
var parameters = criteriaQuery.NewQueryParameter(GetTypedValues(criteria, criteriaQuery)[0]).ToArray();
builder.Add(spatialDialect.GetSpatialRelationString(columns1[i], relation, parameters.Single(), true));
anotherGeometry = parameters.Single();
}
else
{
string[] columns2 = GetColumnNames(criteria, criteriaQuery, (string) anotherGeometry);
builder.Add(spatialDialect.GetSpatialRelationString(columns1[i], relation, columns2[i], true));
string[] columns2 = GetColumnNames(criteria, criteriaQuery, (string) _anotherGeometry);
anotherGeometry = columns2[i];
}

var spatialRelationString = _parameter == null
? spatialDialect.GetSpatialRelationString(columns1[i], _relation, anotherGeometry, true)
: spatialDialect.GetSpatialRelationString(columns1[i], _relation, anotherGeometry, _parameter, true);
builder.Add(spatialRelationString);
}

return builder.ToSqlString();
}

Expand All @@ -119,11 +140,11 @@ public override SqlString ToSqlString(ICriteria criteria, ICriteriaQuery criteri
public override string ToString()
{
return new StringBuilder()
.Append(relation)
.Append(_relation)
.Append("(")
.Append(propertyName)
.Append(_propertyName)
.Append(", ")
.Append(anotherGeometry is Geometry ? "<Geometry>" : anotherGeometry.ToString())
.Append(_anotherGeometry is Geometry ? "<Geometry>" : _anotherGeometry.ToString())
.Append(")")
.ToString();
}
Expand Down
Loading

0 comments on commit cd1c446

Please sign in to comment.