Skip to content

Commit 48326fb

Browse files
committed
CSHARP-683: added query builder support for GeoJson queries.
1 parent ed1ca15 commit 48326fb

File tree

3 files changed

+418
-0
lines changed

3 files changed

+418
-0
lines changed

MongoDB.Driver/Builders/QueryBuilder.cs

Lines changed: 306 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
using System.Linq;
1919
using System.Linq.Expressions;
2020
using MongoDB.Bson;
21+
using MongoDB.Driver.GeoJsonObjectModel;
2122
using MongoDB.Driver.Linq;
2223
using MongoDB.Driver.Linq.Utils;
2324

@@ -157,6 +158,31 @@ public static IMongoQuery Exists(string name)
157158
return new QueryDocument(name, new BsonDocument("$exists", true));
158159
}
159160

161+
/// <summary>
162+
/// Tests that a location element specified by name intersects with the geometry (see $geoIntersects).
163+
/// </summary>
164+
/// <typeparam name="TCoordinates">The type of the coordinates.</typeparam>
165+
/// <param name="name">The name.</param>
166+
/// <param name="geometry">The geometry.</param>
167+
/// <returns>An IMongoQuery.</returns>
168+
public static IMongoQuery GeoIntersects<TCoordinates>(string name, GeoJsonGeometry<TCoordinates> geometry)
169+
where TCoordinates : GeoJsonCoordinates
170+
{
171+
if (name == null)
172+
{
173+
throw new ArgumentNullException("name");
174+
}
175+
if (geometry == null)
176+
{
177+
throw new ArgumentNullException("geometry");
178+
}
179+
180+
var geoDoc = new BsonDocument("$geometry", BsonDocumentWrapper.Create(geometry));
181+
var condition = new BsonDocument("$geoIntersects", geoDoc);
182+
183+
return new QueryDocument(name, condition);
184+
}
185+
160186
/// <summary>
161187
/// Tests that the value of the named element is greater than some value (see $gt).
162188
/// </summary>
@@ -304,6 +330,65 @@ public static IMongoQuery Mod(string name, long modulus, long value)
304330
return new QueryDocument(name, condition);
305331
}
306332

333+
/// <summary>
334+
/// Tests that the value of the named element is near a point (see $near).
335+
/// </summary>
336+
/// <typeparam name="TCoordinates">The type of the coordinates.</typeparam>
337+
/// <param name="name">The name of the element to test.</param>
338+
/// <param name="point">The point.</param>
339+
/// <returns>An IMongoQuery.</returns>
340+
public static IMongoQuery Near<TCoordinates>(string name, GeoJsonPoint<TCoordinates> point)
341+
where TCoordinates : GeoJsonCoordinates
342+
{
343+
return Near(name, point, double.MaxValue);
344+
}
345+
346+
/// <summary>
347+
/// Tests that the value of the named element is near some location (see $near).
348+
/// </summary>
349+
/// <param name="name">The name of the element to test.</param>
350+
/// <param name="x">The x value of the origin.</param>
351+
/// <param name="y">The y value of the origin.</param>
352+
/// <param name="maxDistance">The max distance.</param>
353+
/// <returns>An IMongoQuery.</returns>
354+
public static IMongoQuery Near<TCoordinates>(string name, GeoJsonPoint<TCoordinates> point, double maxDistance)
355+
where TCoordinates : GeoJsonCoordinates
356+
{
357+
return Near(name, point, maxDistance, false);
358+
}
359+
360+
/// <summary>
361+
/// Tests that the value of the named element is near some location (see $near).
362+
/// </summary>
363+
/// <param name="name">The name of the element to test.</param>
364+
/// <param name="x">The x value of the origin.</param>
365+
/// <param name="y">The y value of the origin.</param>
366+
/// <param name="maxDistance">The max distance.</param>
367+
/// <param name="spherical">if set to <c>true</c> then the query will be translated to $nearSphere.</param>
368+
/// <returns>An IMongoQuery.</returns>
369+
public static IMongoQuery Near<TCoordinates>(string name, GeoJsonPoint<TCoordinates> point, double maxDistance, bool spherical)
370+
where TCoordinates : GeoJsonCoordinates
371+
{
372+
if (name == null)
373+
{
374+
throw new ArgumentNullException("name");
375+
}
376+
if (point == null)
377+
{
378+
throw new ArgumentNullException("point");
379+
}
380+
381+
var geoDoc = new BsonDocument("$geometry", BsonDocumentWrapper.Create(point));
382+
var op = spherical ? "$nearSphere" : "$near";
383+
var condition = new BsonDocument(op, geoDoc);
384+
if (maxDistance != double.MaxValue)
385+
{
386+
condition.Add("$maxDistance", maxDistance);
387+
}
388+
389+
return new QueryDocument(name, condition);
390+
}
391+
307392
/// <summary>
308393
/// Tests that the value of the named element is near some location (see $near).
309394
/// </summary>
@@ -606,6 +691,31 @@ public static IMongoQuery Where(BsonJavaScript javascript)
606691
return new QueryDocument("$where", javascript);
607692
}
608693

694+
/// <summary>
695+
/// Tests that the value of the named element is within the specified geometry (see $within).
696+
/// </summary>
697+
/// <typeparam name="TCoordinates">The type of the coordinates.</typeparam>
698+
/// <param name="name">The name of the element to test.</param>
699+
/// <param name="geometry">The geometry.</param>
700+
/// <returns>An IMongoQuery.</returns>
701+
public static IMongoQuery Within<TCoordinates>(string name, GeoJsonGeometry<TCoordinates> geometry)
702+
where TCoordinates : GeoJsonCoordinates
703+
{
704+
if (name == null)
705+
{
706+
throw new ArgumentNullException("name");
707+
}
708+
if (geometry == null)
709+
{
710+
throw new ArgumentNullException("geometry");
711+
}
712+
713+
var geoDoc = new BsonDocument("$geometry", BsonDocumentWrapper.Create(geometry));
714+
var condition = new BsonDocument("$within", geoDoc);
715+
716+
return new QueryDocument(name, condition);
717+
}
718+
609719
/// <summary>
610720
/// Tests that the value of the named element is within a circle (see $within and $center).
611721
/// </summary>
@@ -831,6 +941,20 @@ public static IMongoQuery Exists<TMember>(Expression<Func<TDocument, TMember>> m
831941
return new QueryBuilder<TDocument>().Exists(memberExpression);
832942
}
833943

944+
/// <summary>
945+
/// Tests that a location element specified by name intersects with the geometry (see $geoIntersects).
946+
/// </summary>
947+
/// <typeparam name="TMember">The type of the member.</typeparam>
948+
/// <typeparam name="TCoordinates">The type of the coordinates.</typeparam>
949+
/// <param name="memberExpression">The member expression.</param>
950+
/// <param name="geometry">The geometry.</param>
951+
/// <returns>An IMongoQuery.</returns>
952+
public static IMongoQuery GeoIntersects<TMember, TCoordinates>(Expression<Func<TDocument, TMember>> memberExpression, GeoJsonGeometry<TCoordinates> geometry)
953+
where TCoordinates : GeoJsonCoordinates
954+
{
955+
return new QueryBuilder<TDocument>().GeoIntersects(memberExpression, geometry);
956+
}
957+
834958
/// <summary>
835959
/// Tests that the value of the named element is greater than some value (see $gt).
836960
/// </summary>
@@ -997,6 +1121,51 @@ public static IMongoQuery Mod(Expression<Func<TDocument, IEnumerable<int>>> memb
9971121
return new QueryBuilder<TDocument>().Mod(memberExpression, modulus, value);
9981122
}
9991123

1124+
/// <summary>
1125+
/// Tests that the value of the named element is near a point (see $near).
1126+
/// </summary>
1127+
/// <typeparam name="TMember">The type of the member.</typeparam>
1128+
/// <typeparam name="TCoordinates">The type of the coordinates.</typeparam>
1129+
/// <param name="memberExpression">The member expression.</param>
1130+
/// <param name="point">The point.</param>
1131+
/// <returns>An IMongoQuery.</returns>
1132+
public static IMongoQuery Near<TMember, TCoordinates>(Expression<Func<TDocument, TMember>> memberExpression, GeoJsonPoint<TCoordinates> point)
1133+
where TCoordinates : GeoJsonCoordinates
1134+
{
1135+
return new QueryBuilder<TDocument>().Near(memberExpression, point);
1136+
}
1137+
1138+
/// <summary>
1139+
/// Tests that the value of the named element is near some location (see $near).
1140+
/// </summary>
1141+
/// <typeparam name="TMember">The member type.</typeparam>
1142+
/// <typeparam name="TCoordinates">The type of the coordinates.</typeparam>
1143+
/// <param name="memberExpression">The member expression representing the element to test.</param>
1144+
/// <param name="point">The point.</param>
1145+
/// <param name="maxDistance">The max distance.</param>
1146+
/// <returns>An IMongoQuery.</returns>
1147+
public static IMongoQuery Near<TMember, TCoordinates>(Expression<Func<TDocument, TMember>> memberExpression, GeoJsonPoint<TCoordinates> point, double maxDistance)
1148+
where TCoordinates : GeoJsonCoordinates
1149+
{
1150+
return new QueryBuilder<TDocument>().Near(memberExpression, point, maxDistance);
1151+
}
1152+
1153+
/// <summary>
1154+
/// Tests that the value of the named element is near some location (see $near).
1155+
/// </summary>
1156+
/// <typeparam name="TMember">The member type.</typeparam>
1157+
/// <typeparam name="TCoordinates">The type of the coordinates.</typeparam>
1158+
/// <param name="memberExpression">The member expression representing the element to test.</param>
1159+
/// <param name="point">The point.</param>
1160+
/// <param name="maxDistance">The max distance.</param>
1161+
/// <param name="spherical">if set to <c>true</c> [spherical].</param>
1162+
/// <returns>An IMongoQuery.</returns>
1163+
public static IMongoQuery Near<TMember, TCoordinates>(Expression<Func<TDocument, TMember>> memberExpression, GeoJsonPoint<TCoordinates> point, double maxDistance, bool spherical)
1164+
where TCoordinates : GeoJsonCoordinates
1165+
{
1166+
return new QueryBuilder<TDocument>().Near(memberExpression, point, maxDistance, spherical);
1167+
}
1168+
10001169
/// <summary>
10011170
/// Tests that the value of the named element is near some location (see $near).
10021171
/// </summary>
@@ -1144,6 +1313,20 @@ public static IMongoQuery Where(Expression<Func<TDocument, bool>> expression)
11441313
return new QueryBuilder<TDocument>().Where(expression);
11451314
}
11461315

1316+
/// <summary>
1317+
/// Tests that the value of the named element is within the specified geometry (see $within).
1318+
/// </summary>
1319+
/// <typeparam name="TMember">The type of the member.</typeparam>
1320+
/// <typeparam name="TCoordinates">The type of the coordinates.</typeparam>
1321+
/// <param name="memberExpression">The member expression.</param>
1322+
/// <param name="geometry">The geometry.</param>
1323+
/// <returns>An IMongoQuery.</returns>
1324+
public static IMongoQuery Within<TMember, TCoordinates>(Expression<Func<TDocument, TMember>> memberExpression, GeoJsonGeometry<TCoordinates> geometry)
1325+
where TCoordinates : GeoJsonCoordinates
1326+
{
1327+
return new QueryBuilder<TDocument>().Within(memberExpression, geometry);
1328+
}
1329+
11471330
/// <summary>
11481331
/// Tests that the value of the named element is within a circle (see $within and $center).
11491332
/// </summary>
@@ -1356,6 +1539,30 @@ public IMongoQuery Exists<TMember>(Expression<Func<TDocument, TMember>> memberEx
13561539
return Query.Exists(serializationInfo.ElementName);
13571540
}
13581541

1542+
/// <summary>
1543+
/// Tests that a location element specified by name intersects with the geometry (see $geoIntersects).
1544+
/// </summary>
1545+
/// <typeparam name="TMember">The type of the member.</typeparam>
1546+
/// <typeparam name="TCoordinates">The type of the coordinates.</typeparam>
1547+
/// <param name="memberExpression">The member expression.</param>
1548+
/// <param name="geometry">The geometry.</param>
1549+
/// <returns>An IMongoQuery.</returns>
1550+
public IMongoQuery GeoIntersects<TMember, TCoordinates>(Expression<Func<TDocument, TMember>> memberExpression, GeoJsonGeometry<TCoordinates> geometry)
1551+
where TCoordinates : GeoJsonCoordinates
1552+
{
1553+
if (memberExpression == null)
1554+
{
1555+
throw new ArgumentNullException("name");
1556+
}
1557+
if (geometry == null)
1558+
{
1559+
throw new ArgumentNullException("geometry");
1560+
}
1561+
1562+
var serializationInfo = _serializationInfoHelper.GetSerializationInfo(memberExpression);
1563+
return Query.GeoIntersects<TCoordinates>(serializationInfo.ElementName, geometry);
1564+
}
1565+
13591566
/// <summary>
13601567
/// Tests that the value of the named element is greater than some value (see $gt).
13611568
/// </summary>
@@ -1641,6 +1848,81 @@ public IMongoQuery Mod(Expression<Func<TDocument, IEnumerable<int>>> memberExpre
16411848
return Query.Mod(serializationInfo.ElementName, modulus, value);
16421849
}
16431850

1851+
/// <summary>
1852+
/// Tests that the value of the named element is near a point (see $near).
1853+
/// </summary>
1854+
/// <typeparam name="TMember">The type of the member.</typeparam>
1855+
/// <typeparam name="TCoordinates">The type of the coordinates.</typeparam>
1856+
/// <param name="memberExpression">The member expression.</param>
1857+
/// <param name="point">The point.</param>
1858+
/// <returns>An IMongoQuery.</returns>
1859+
public IMongoQuery Near<TMember, TCoordinates>(Expression<Func<TDocument, TMember>> memberExpression, GeoJsonPoint<TCoordinates> point)
1860+
where TCoordinates : GeoJsonCoordinates
1861+
{
1862+
if (memberExpression == null)
1863+
{
1864+
throw new ArgumentNullException("memberExpression");
1865+
}
1866+
if (point == null)
1867+
{
1868+
throw new ArgumentNullException("point");
1869+
}
1870+
1871+
var serializationInfo = _serializationInfoHelper.GetSerializationInfo(memberExpression);
1872+
return Query.Near(serializationInfo.ElementName, point);
1873+
}
1874+
1875+
/// <summary>
1876+
/// Tests that the value of the named element is near some location (see $near).
1877+
/// </summary>
1878+
/// <typeparam name="TMember">The member type.</typeparam>
1879+
/// <typeparam name="TCoordinates">The type of the coordinates.</typeparam>
1880+
/// <param name="memberExpression">The member expression.</param>
1881+
/// <param name="point">The point.</param>
1882+
/// <param name="maxDistance">The max distance.</param>
1883+
/// <returns>An IMongoQuery.</returns>
1884+
public IMongoQuery Near<TMember, TCoordinates>(Expression<Func<TDocument, TMember>> memberExpression, GeoJsonPoint<TCoordinates> point, double maxDistance)
1885+
where TCoordinates : GeoJsonCoordinates
1886+
{
1887+
if (memberExpression == null)
1888+
{
1889+
throw new ArgumentNullException("memberExpression");
1890+
}
1891+
if (point == null)
1892+
{
1893+
throw new ArgumentNullException("point");
1894+
}
1895+
1896+
var serializationInfo = _serializationInfoHelper.GetSerializationInfo(memberExpression);
1897+
return Query.Near(serializationInfo.ElementName, point, maxDistance);
1898+
}
1899+
1900+
/// <summary>
1901+
/// Tests that the value of the named element is near some location (see $near).
1902+
/// </summary>
1903+
/// <typeparam name="TMember">The member type.</typeparam>
1904+
/// <typeparam name="TCoordinates">The type of the coordinates.</typeparam>
1905+
/// <param name="memberExpression">The member expression.</param>
1906+
/// <param name="point">The point.</param>
1907+
/// <param name="maxDistance">The max distance.</param>
1908+
/// <param name="spherical">if set to <c>true</c> then the query will be translated to $nearSphere.</param>
1909+
/// <returns>An IMongoQuery.</returns>
1910+
public IMongoQuery Near<TMember, TCoordinates>(Expression<Func<TDocument, TMember>> memberExpression, GeoJsonPoint<TCoordinates> point, double maxDistance, bool spherical)
1911+
where TCoordinates : GeoJsonCoordinates
1912+
{
1913+
if (memberExpression == null)
1914+
{
1915+
throw new ArgumentNullException("memberExpression");
1916+
}
1917+
if (point == null)
1918+
{
1919+
throw new ArgumentNullException("point");
1920+
}
1921+
1922+
var serializationInfo = _serializationInfoHelper.GetSerializationInfo(memberExpression);
1923+
return Query.Near(serializationInfo.ElementName, point, maxDistance, spherical);
1924+
}
1925+
16441926
/// <summary>
16451927
/// Tests that the value of the named element is near some location (see $near).
16461928
/// </summary>
@@ -1896,6 +2178,30 @@ public IMongoQuery Where(Expression<Func<TDocument, bool>> expression)
18962178
return _predicateTranslator.BuildQuery(evaluatedExpression);
18972179
}
18982180

2181+
/// <summary>
2182+
/// Tests that the value of the named element is within the specified geometry (see $within).
2183+
/// </summary>
2184+
/// <typeparam name="TMember">The type of the member.</typeparam>
2185+
/// <typeparam name="TCoordinates">The type of the coordinates.</typeparam>
2186+
/// <param name="memberExpression">The member expression.</param>
2187+
/// <param name="geometry">The geometry.</param>
2188+
/// <returns>An IMongoQuery.</returns>
2189+
public IMongoQuery Within<TMember, TCoordinates>(Expression<Func<TDocument, TMember>> memberExpression, GeoJsonGeometry<TCoordinates> geometry)
2190+
where TCoordinates : GeoJsonCoordinates
2191+
{
2192+
if (memberExpression == null)
2193+
{
2194+
throw new ArgumentNullException("memberExpression");
2195+
}
2196+
if (geometry == null)
2197+
{
2198+
throw new ArgumentNullException("geometry");
2199+
}
2200+
2201+
var serializationInfo = _serializationInfoHelper.GetSerializationInfo(memberExpression);
2202+
return Query.Within(serializationInfo.ElementName, geometry);
2203+
}
2204+
18992205
/// <summary>
19002206
/// Tests that the value of the named element is within a circle (see $within and $center).
19012207
/// </summary>

0 commit comments

Comments
 (0)