Skip to content

Commit 6728310

Browse files
committed
Implement IsWithinDistance spatial restriction criteria #61
1 parent 5c8a953 commit 6728310

File tree

18 files changed

+331
-50
lines changed

18 files changed

+331
-50
lines changed

NHibernate.Spatial.MsSql/Dialect/MsSql2012FunctionRegistration.cs

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -434,6 +434,27 @@ public SqlString GetSpatialRelationString(object geometry, SpatialRelation relat
434434
}
435435
}
436436

437+
public SqlString GetSpatialRelationString(object geometry, SpatialRelation relation, object anotherGeometry, object parameter, bool criterion)
438+
{
439+
switch (relation)
440+
{
441+
case SpatialRelation.IsWithinDistance:
442+
return new SqlStringBuilder()
443+
.Add("CASE WHEN ")
444+
.AddObject(geometry)
445+
.Add(".STDistance(")
446+
.AddObject(anotherGeometry)
447+
.Add(")")
448+
.Add(" <= ")
449+
.Add(parameter.ToString())
450+
.Add(" THEN 1 ELSE 0 END")
451+
.Add(criterion ? " = 1" : "")
452+
.ToSqlString();
453+
default:
454+
throw new ArgumentOutOfRangeException(nameof(relation), relation, "Unsupported spatial relation");
455+
}
456+
}
457+
437458
public SqlString GetSpatialFilterString(string tableAlias, string geometryColumnName, string primaryKeyColumnName, string tableName, Parameter parameter)
438459
{
439460
return new SqlStringBuilder(6)

NHibernate.Spatial.MsSql/Dialect/MsSql2012SpatialDialect.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,11 @@ public SqlString GetSpatialRelationString(object geometry, SpatialRelation relat
7676
return worker.GetSpatialRelationString(geometry, relation, anotherGeometry, criterion);
7777
}
7878

79+
public SqlString GetSpatialRelationString(object geometry, SpatialRelation relation, object anotherGeometry, object parameter, bool criterion)
80+
{
81+
return worker.GetSpatialRelationString(geometry, relation, anotherGeometry, parameter, criterion);
82+
}
83+
7984
public SqlString GetSpatialFilterString(string tableAlias, string geometryColumnName, string primaryKeyColumnName, string tableName, Parameter parameter)
8085
{
8186
return worker.GetSpatialFilterString(tableAlias, geometryColumnName, primaryKeyColumnName, tableName, parameter);

NHibernate.Spatial.MySQL/Dialect/MySQL57SpatialDialect.cs

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -344,6 +344,26 @@ public SqlString GetSpatialRelationString(object geometry, SpatialRelation relat
344344
}
345345
}
346346

347+
public SqlString GetSpatialRelationString(object geometry, SpatialRelation relation, object anotherGeometry, object parameter, bool criterion)
348+
{
349+
switch (relation)
350+
{
351+
case SpatialRelation.IsWithinDistance:
352+
return new SqlStringBuilder()
353+
.Add(SpatialDialect.IsoPrefix)
354+
.Add("Distance(")
355+
.AddObject(geometry)
356+
.Add(", ")
357+
.AddObject(anotherGeometry)
358+
.Add(")")
359+
.Add(" <= ")
360+
.Add(parameter.ToString())
361+
.ToSqlString();
362+
default:
363+
throw new ArgumentOutOfRangeException(nameof(relation), relation, "Unsupported spatial relation");
364+
}
365+
}
366+
347367
public SqlString GetSpatialRelateString(object geometry, object anotherGeometry, object pattern, bool isStringPattern, bool criterion)
348368
{
349369
var builder = new SqlStringBuilder();

NHibernate.Spatial.PostGis/Dialect/PostGis20Dialect.cs

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -335,6 +335,27 @@ public SqlString GetSpatialRelationString(object geometry, SpatialRelation relat
335335
}
336336
}
337337

338+
public SqlString GetSpatialRelationString(object geometry, SpatialRelation relation, object anotherGeometry, object parameter, bool criterion)
339+
{
340+
switch (relation)
341+
{
342+
case SpatialRelation.IsWithinDistance:
343+
return new SqlStringBuilder()
344+
.Add(SpatialDialect.IsoPrefix)
345+
.Add("DWithin")
346+
.Add("(")
347+
.AddObject(geometry)
348+
.Add(", ")
349+
.AddObject(anotherGeometry)
350+
.Add(", ")
351+
.Add(parameter.ToString())
352+
.Add(")")
353+
.ToSqlString();
354+
default:
355+
throw new ArgumentOutOfRangeException(nameof(relation), relation, "Unsupported spatial relation");
356+
}
357+
}
358+
338359
public SqlString GetSpatialRelateString(object geometry, object anotherGeometry, object pattern, bool isStringPattern, bool criterion)
339360
{
340361
var builder = new SqlStringBuilder();

NHibernate.Spatial/Criterion/SpatialProjections.cs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -257,6 +257,18 @@ public static SpatialProjection Intersects(string propertyName, string anotherPr
257257
return new SpatialRelationProjection(propertyName, SpatialRelation.Intersects, anotherPropertyName);
258258
}
259259

260+
/// <summary>
261+
/// Determines whether the specified geometry property is within a given distance of another geometry.
262+
/// </summary>
263+
/// <param name="propertyName">Name of the property.</param>
264+
/// <param name="anotherPropertyName">Name of another property.</param>
265+
/// <param name="distance">The distance.</param>
266+
/// <returns></returns>
267+
public static SpatialProjection IsWithinDistance(string propertyName, string anotherPropertyName, double distance)
268+
{
269+
return new SpatialRelationProjection(propertyName, SpatialRelation.IsWithinDistance, anotherPropertyName, distance);
270+
}
271+
260272
/// <summary>
261273
/// Determines whether the specified geometry property overlaps another geometry property.
262274
/// </summary>

NHibernate.Spatial/Criterion/SpatialProjectionsLambda.cs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -269,6 +269,18 @@ public static SpatialProjection Intersects<T>(Expression<Func<T, object>> expres
269269
return Intersects(GetPropertyName(expression), GetPropertyName(anotherExpression));
270270
}
271271

272+
/// <summary>
273+
/// Determines whether the specified geometry property is within a given distance of another geometry.
274+
/// </summary>
275+
/// <param name="expression">Name of the property.</param>
276+
/// <param name="anotherExpression">Name of another property.</param>
277+
/// <param name="distance">The distance.</param>
278+
/// <returns></returns>
279+
public static SpatialProjection IsWithinDistance<T>(Expression<Func<T, object>> expression, Expression<Func<T, object>> anotherExpression, double distance)
280+
{
281+
return IsWithinDistance(GetPropertyName(expression), GetPropertyName(anotherExpression), distance);
282+
}
283+
272284
/// <summary>
273285
/// Determines whether the specified geometry property overlaps another geometry property.
274286
/// </summary>

NHibernate.Spatial/Criterion/SpatialRelationCriterion.cs

Lines changed: 38 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -32,9 +32,23 @@ namespace NHibernate.Spatial.Criterion
3232
[Serializable]
3333
public class SpatialRelationCriterion : AbstractCriterion
3434
{
35-
private readonly string propertyName;
36-
private readonly SpatialRelation relation;
37-
private readonly object anotherGeometry;
35+
private readonly string _propertyName;
36+
private readonly SpatialRelation _relation;
37+
private readonly object _anotherGeometry;
38+
private readonly object _parameter;
39+
40+
/// <summary>
41+
/// Initializes a new instance of the <see cref="SpatialRelationCriterion"/> class.
42+
/// </summary>
43+
/// <param name="propertyName">Name of the property.</param>
44+
/// <param name="relation">The relation.</param>
45+
/// <param name="anotherGeometry">Another geometry.</param>
46+
/// <param name="parameter">Additional parameter value</param>
47+
public SpatialRelationCriterion(string propertyName, SpatialRelation relation, object anotherGeometry, object parameter)
48+
: this(propertyName, relation, anotherGeometry)
49+
{
50+
_parameter = parameter;
51+
}
3852

3953
/// <summary>
4054
/// Initializes a new instance of the <see cref="SpatialRelationCriterion"/> class.
@@ -44,9 +58,9 @@ public class SpatialRelationCriterion : AbstractCriterion
4458
/// <param name="anotherGeometry">Another geometry.</param>
4559
public SpatialRelationCriterion(string propertyName, SpatialRelation relation, object anotherGeometry)
4660
{
47-
this.propertyName = propertyName;
48-
this.relation = relation;
49-
this.anotherGeometry = anotherGeometry;
61+
_propertyName = propertyName;
62+
_relation = relation;
63+
_anotherGeometry = anotherGeometry;
5064
}
5165

5266
/// <summary>
@@ -59,9 +73,9 @@ public SpatialRelationCriterion(string propertyName, SpatialRelation relation, o
5973
/// </returns>
6074
public override TypedValue[] GetTypedValues(ICriteria criteria, ICriteriaQuery criteriaQuery)
6175
{
62-
if (anotherGeometry is Geometry)
76+
if (_anotherGeometry is Geometry)
6377
{
64-
return new[] { criteriaQuery.GetTypedValue(criteria, propertyName, anotherGeometry) };
78+
return new[] { criteriaQuery.GetTypedValue(criteria, _propertyName, _anotherGeometry) };
6579
}
6680
return Array.Empty<TypedValue>();
6781
}
@@ -81,9 +95,8 @@ public override IProjection[] GetProjections()
8195
/// </returns>
8296
public override SqlString ToSqlString(ICriteria criteria, ICriteriaQuery criteriaQuery)
8397
{
84-
//criteriaQuery.AddUsedTypedValues(GetTypedValues(criteria, criteriaQuery));
8598
var spatialDialect = (ISpatialDialect) criteriaQuery.Factory.Dialect;
86-
string[] columns1 = GetColumnNames(criteria, criteriaQuery, propertyName);
99+
string[] columns1 = GetColumnNames(criteria, criteriaQuery, _propertyName);
87100

88101
var builder = new SqlStringBuilder(10*columns1.Length);
89102
for (int i = 0; i < columns1.Length; i++)
@@ -92,17 +105,25 @@ public override SqlString ToSqlString(ICriteria criteria, ICriteriaQuery criteri
92105
{
93106
builder.Add(" AND ");
94107
}
95-
if (anotherGeometry is Geometry)
108+
109+
object anotherGeometry;
110+
if (_anotherGeometry is Geometry)
96111
{
97112
var parameters = criteriaQuery.NewQueryParameter(GetTypedValues(criteria, criteriaQuery)[0]).ToArray();
98-
builder.Add(spatialDialect.GetSpatialRelationString(columns1[i], relation, parameters.Single(), true));
113+
anotherGeometry = parameters.Single();
99114
}
100115
else
101116
{
102-
string[] columns2 = GetColumnNames(criteria, criteriaQuery, (string) anotherGeometry);
103-
builder.Add(spatialDialect.GetSpatialRelationString(columns1[i], relation, columns2[i], true));
117+
string[] columns2 = GetColumnNames(criteria, criteriaQuery, (string) _anotherGeometry);
118+
anotherGeometry = columns2[i];
104119
}
120+
121+
var spatialRelationString = _parameter == null
122+
? spatialDialect.GetSpatialRelationString(columns1[i], _relation, anotherGeometry, true)
123+
: spatialDialect.GetSpatialRelationString(columns1[i], _relation, anotherGeometry, _parameter, true);
124+
builder.Add(spatialRelationString);
105125
}
126+
106127
return builder.ToSqlString();
107128
}
108129

@@ -119,11 +140,11 @@ public override SqlString ToSqlString(ICriteria criteria, ICriteriaQuery criteri
119140
public override string ToString()
120141
{
121142
return new StringBuilder()
122-
.Append(relation)
143+
.Append(_relation)
123144
.Append("(")
124-
.Append(propertyName)
145+
.Append(_propertyName)
125146
.Append(", ")
126-
.Append(anotherGeometry is Geometry ? "<Geometry>" : anotherGeometry.ToString())
147+
.Append(_anotherGeometry is Geometry ? "<Geometry>" : _anotherGeometry.ToString())
127148
.Append(")")
128149
.ToString();
129150
}

NHibernate.Spatial/Criterion/SpatialRelationProjection.cs

Lines changed: 22 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,22 @@ namespace NHibernate.Spatial.Criterion
2929
[Serializable]
3030
public class SpatialRelationProjection : SpatialProjection
3131
{
32-
private readonly SpatialRelation relation;
33-
private readonly string anotherPropertyName;
32+
private readonly SpatialRelation _relation;
33+
private readonly string _anotherPropertyName;
34+
private readonly object _parameter;
35+
36+
/// <summary>
37+
/// Initializes a new instance of the <see cref="SpatialRelationProjection"/> class.
38+
/// </summary>
39+
/// <param name="propertyName">Name of the property.</param>
40+
/// <param name="relation">The relation.</param>
41+
/// <param name="anotherPropertyName">Name of another property.</param>
42+
/// <param name="parameter">Additional parameter value</param>
43+
public SpatialRelationProjection(string propertyName, SpatialRelation relation, string anotherPropertyName, object parameter)
44+
: this(propertyName, relation, anotherPropertyName)
45+
{
46+
_parameter = parameter;
47+
}
3448

3549
/// <summary>
3650
/// Initializes a new instance of the <see cref="SpatialRelationProjection"/> class.
@@ -41,8 +55,8 @@ public class SpatialRelationProjection : SpatialProjection
4155
public SpatialRelationProjection(string propertyName, SpatialRelation relation, string anotherPropertyName)
4256
: base(propertyName)
4357
{
44-
this.relation = relation;
45-
this.anotherPropertyName = anotherPropertyName;
58+
_relation = relation;
59+
_anotherPropertyName = anotherPropertyName;
4660
}
4761

4862
/// <summary>
@@ -67,8 +81,10 @@ public override SqlString ToSqlString(ICriteria criteria, int position, ICriteri
6781
{
6882
var spatialDialect = (ISpatialDialect) criteriaQuery.Factory.Dialect;
6983
string column1 = criteriaQuery.GetColumn(criteria, propertyName);
70-
string column2 = criteriaQuery.GetColumn(criteria, anotherPropertyName);
71-
var sqlString = spatialDialect.GetSpatialRelationString(column1, relation, column2, false);
84+
string column2 = criteriaQuery.GetColumn(criteria, _anotherPropertyName);
85+
var sqlString = _parameter == null
86+
? spatialDialect.GetSpatialRelationString(column1, _relation, column2, false)
87+
: spatialDialect.GetSpatialRelationString(column1, _relation, column2, _parameter, false);
7288
return new SqlStringBuilder()
7389
.Add(sqlString)
7490
.Add(" as y")

NHibernate.Spatial/Criterion/SpatialRestrictions.cs

Lines changed: 12 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,18 @@ public static SpatialRelationCriterion Intersects(string propertyName, object an
165165
return new SpatialRelationCriterion(propertyName, SpatialRelation.Intersects, anotherGeometry);
166166
}
167167

168+
/// <summary>
169+
/// Determines whether the specified geometry property is within a given distance of another geometry.
170+
/// </summary>
171+
/// <param name="propertyName">Name of the property.</param>
172+
/// <param name="anotherGeometry">Another geometry.</param>
173+
/// <param name="distance">The distance.</param>
174+
/// <returns></returns>
175+
public static SpatialRelationCriterion IsWithinDistance(string propertyName, object anotherGeometry, double distance)
176+
{
177+
return new SpatialRelationCriterion(propertyName, SpatialRelation.IsWithinDistance, anotherGeometry, distance);
178+
}
179+
168180
/// <summary>
169181
/// Determines whether the specified geometry property overlaps another geometry.
170182
/// </summary>
@@ -211,19 +223,6 @@ public static SpatialRelationCriterion Within(string propertyName, object anothe
211223
return new SpatialRelationCriterion(propertyName, SpatialRelation.Within, anotherGeometry);
212224
}
213225

214-
/// <summary>
215-
/// Determines whether the specified geometry property is within a givin distance of another geometry.
216-
/// </summary>
217-
/// <param name="propertyName">Name of the property.</param>
218-
/// <param name="anotherGeometry">Another geometry.</param>
219-
/// <param name="distance">The distance.</param>
220-
/// <returns></returns>
221-
public static SpatialRelationCriterion IsWithinDistance(string propertyName, object anotherGeometry, double distance)
222-
{
223-
// TODO: Implement
224-
throw new NotImplementedException();
225-
}
226-
227226
// TODO :
228227
//Distance
229228
//RelatePattern

NHibernate.Spatial/Dialect/ISpatialDialect.cs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,21 @@ public interface ISpatialDialect
101101
/// a SQL spatial relation expression</returns>
102102
SqlString GetSpatialRelationString(object geometry, SpatialRelation relation, object anotherGeometry, bool criterion);
103103

104+
/// <summary>
105+
/// It builds a SQL spatial relation expression.
106+
/// </summary>
107+
/// <remarks>
108+
/// One parameter placeholder must be added to the SqlString.
109+
/// </remarks>
110+
/// <param name="geometry">SQL expression returning a geometry</param>
111+
/// <param name="relation">Spatial relation</param>
112+
/// <param name="anotherGeometry">A string SQL geometry expression or a Parameter.Placeholder</param>
113+
/// <param name="parameter">Additional parameter value</param>
114+
/// <param name="criterion"></param>
115+
/// <returns>A <c>SqlString</c> object containing
116+
/// a SQL spatial relation expression</returns>
117+
SqlString GetSpatialRelationString(object geometry, SpatialRelation relation, object anotherGeometry, object parameter, bool criterion);
118+
104119
/// <summary>
105120
/// It builds a SQL spatial filter expression.
106121
/// </summary>

0 commit comments

Comments
 (0)