Skip to content

Commit

Permalink
Support minDistance and maxDistance options for and operators
Browse files Browse the repository at this point in the history
  • Loading branch information
alcaeus committed Nov 23, 2023
1 parent ec7520e commit d256f9f
Show file tree
Hide file tree
Showing 4 changed files with 211 additions and 12 deletions.
8 changes: 4 additions & 4 deletions lib/Doctrine/ODM/MongoDB/Query/Builder.php
Original file line number Diff line number Diff line change
Expand Up @@ -991,9 +991,9 @@ public function mul($value): self
* @param float|array<string, mixed>|Point $x
* @param float $y
*/
public function near($x, $y = null): self
public function near($x, $y = null, ?float $minDistance = null, ?float $maxDistance = null): self
{
$this->expr->near($x, $y);
$this->expr->near($x, $y, $minDistance, $maxDistance);

return $this;
}
Expand All @@ -1011,9 +1011,9 @@ public function near($x, $y = null): self
* @param float|array<string, mixed>|Point $x
* @param float $y
*/
public function nearSphere($x, $y = null): self
public function nearSphere($x, $y = null, ?float $minDistance = null, ?float $maxDistance = null): self
{
$this->expr->nearSphere($x, $y);
$this->expr->nearSphere($x, $y, $minDistance, $maxDistance);

return $this;
}
Expand Down
47 changes: 41 additions & 6 deletions lib/Doctrine/ODM/MongoDB/Query/Expr.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
use MongoDB\BSON\Binary;
use MongoDB\BSON\Javascript;

use function array_filter;
use function array_key_exists;
use function array_map;
use function array_merge;
Expand Down Expand Up @@ -822,17 +823,34 @@ public function mul($value): self
* @param float|array<string, mixed>|Point $x
* @param float $y
*/
public function near($x, $y = null): self
public function near($x, $y = null, ?float $minDistance = null, ?float $maxDistance = null): self
{
if ($x instanceof Point) {
$x = $x->jsonSerialize();
}

if (is_array($x)) {
return $this->operator('$near', ['$geometry' => $x]);
return $this->operator(
'$near',
array_filter([
'$geometry' => $x,
'$minDistance' => $minDistance,
'$maxDistance' => $maxDistance,
]),
);
}

$this->operator('$near', [$x, $y]);

if ($minDistance !== null) {
$this->operator('$minDistance', $minDistance);
}

return $this->operator('$near', [$x, $y]);
if ($maxDistance !== null) {
$this->operator('$maxDistance', $maxDistance);
}

return $this;
}

/**
Expand All @@ -848,17 +866,34 @@ public function near($x, $y = null): self
* @param float|array<string, mixed>|Point $x
* @param float $y
*/
public function nearSphere($x, $y = null): self
public function nearSphere($x, $y = null, ?float $minDistance = null, ?float $maxDistance = null): self
{
if ($x instanceof Point) {
$x = $x->jsonSerialize();
}

if (is_array($x)) {
return $this->operator('$nearSphere', ['$geometry' => $x]);
return $this->operator(
'$nearSphere',
array_filter([
'$geometry' => $x,
'$minDistance' => $minDistance,
'$maxDistance' => $maxDistance,
]),
);
}

$this->operator('$nearSphere', [$x, $y]);

if ($minDistance !== null) {
$this->operator('$minDistance', $minDistance);
}

return $this->operator('$nearSphere', [$x, $y]);
if ($maxDistance !== null) {
$this->operator('$maxDistance', $maxDistance);
}

return $this;
}

/**
Expand Down
4 changes: 2 additions & 2 deletions tests/Doctrine/ODM/MongoDB/Tests/Query/BuilderTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -504,8 +504,8 @@ public static function provideProxiedExprMethods(): array
'type()' => ['type', [7]],
'all()' => ['all', [['value1', 'value2']]],
'mod()' => ['mod', [2, 0]],
'near()' => ['near', [1, 2]],
'nearSphere()' => ['nearSphere', [1, 2]],
'near()' => ['near', [1, 2], null, 5, 10],
'nearSphere()' => ['nearSphere', [1, 2], null, 5, 10],
'geoIntersects()' => ['geoIntersects', [self::createGeometry()]],
'geoWithin()' => ['geoWithin', [self::createGeometry()]],
'geoWithinBox()' => ['geoWithinBox', [1, 2, 3, 4]],
Expand Down
164 changes: 164 additions & 0 deletions tests/Doctrine/ODM/MongoDB/Tests/Query/ExprTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -422,6 +422,64 @@ public function testNearWithGeoJsonPoint($point, array $expected): void
self::assertEquals(['$near' => $expected], $expr->getQuery());
}

public function testNearWithGeoJsonPointAndMinDistance(): void
{
$expr = $this->createExpr();

$coordinates = [1, 2];
$point = new Point($coordinates);

self::assertSame($expr, $expr->near($point, null, 5));
self::assertEquals(
[
'$near' => [
'$geometry' => ['type' => 'Point', 'coordinates' => $coordinates],
'$minDistance' => 5,
],
],
$expr->getQuery(),
);
}

public function testNearWithGeoJsonPointAndMaxDistance(): void
{
$expr = $this->createExpr();

$coordinates = [1, 2];
$point = new Point($coordinates);

self::assertSame($expr, $expr->near($point, null, null, 10));
self::assertEquals(
[
'$near' => [
'$geometry' => ['type' => 'Point', 'coordinates' => $coordinates],
'$maxDistance' => 10,
],
],
$expr->getQuery(),
);
}

public function testNearWithGeoJsonPointAndMinAndMaxDistance(): void
{
$expr = $this->createExpr();

$coordinates = [1, 2];
$point = new Point($coordinates);

self::assertSame($expr, $expr->near($point, null, 5, 10));
self::assertEquals(
[
'$near' => [
'$geometry' => ['type' => 'Point', 'coordinates' => $coordinates],
'$minDistance' => 5,
'$maxDistance' => 10,
],
],
$expr->getQuery(),
);
}

public function testNearWithLegacyCoordinates(): void
{
$expr = $this->createExpr();
Expand All @@ -430,6 +488,30 @@ public function testNearWithLegacyCoordinates(): void
self::assertEquals(['$near' => [1, 2]], $expr->getQuery());
}

public function testNearWithLegacyCoordinatesAndMinDistance(): void
{
$expr = $this->createExpr();

self::assertSame($expr, $expr->near(1, 2, 5));
self::assertEquals(['$near' => [1, 2], '$minDistance' => 5], $expr->getQuery());
}

public function testNearWithLegacyCoordinatesAndMaxDistance(): void
{
$expr = $this->createExpr();

self::assertSame($expr, $expr->near(1, 2, null, 10));
self::assertEquals(['$near' => [1, 2], '$maxDistance' => 10], $expr->getQuery());
}

public function testNearWithLegacyCoordinatesAndMinAndMaxDistance(): void
{
$expr = $this->createExpr();

self::assertSame($expr, $expr->near(1, 2, 5, 10));
self::assertEquals(['$near' => [1, 2], '$minDistance' => 5, '$maxDistance' => 10], $expr->getQuery());
}

/**
* @param Point|array<string, mixed> $point
* @param array<string, mixed> $expected
Expand All @@ -443,6 +525,64 @@ public function testNearSphereWithGeoJsonPoint($point, array $expected): void
self::assertEquals(['$nearSphere' => $expected], $expr->getQuery());
}

public function testNearSphereWithGeoJsonPointAndMinDistance(): void
{
$expr = $this->createExpr();

$coordinates = [1, 2];
$point = new Point($coordinates);

self::assertSame($expr, $expr->nearSphere($point, null, 5));
self::assertEquals(
[
'$nearSphere' => [
'$geometry' => ['type' => 'Point', 'coordinates' => $coordinates],
'$minDistance' => 5,
],
],
$expr->getQuery(),
);
}

public function testNearSphereWithGeoJsonPointAndMaxDistance(): void
{
$expr = $this->createExpr();

$coordinates = [1, 2];
$point = new Point($coordinates);

self::assertSame($expr, $expr->nearSphere($point, null, null, 10));
self::assertEquals(
[
'$nearSphere' => [
'$geometry' => ['type' => 'Point', 'coordinates' => $coordinates],
'$maxDistance' => 10,
],
],
$expr->getQuery(),
);
}

public function testNearSphereWithGeoJsonPointAndMinAndMaxDistance(): void
{
$expr = $this->createExpr();

$coordinates = [1, 2];
$point = new Point($coordinates);

self::assertSame($expr, $expr->nearSphere($point, null, 5, 10));
self::assertEquals(
[
'$nearSphere' => [
'$geometry' => ['type' => 'Point', 'coordinates' => $coordinates],
'$minDistance' => 5,
'$maxDistance' => 10,
],
],
$expr->getQuery(),
);
}

public function testNearSphereWithLegacyCoordinates(): void
{
$expr = $this->createExpr();
Expand All @@ -451,6 +591,30 @@ public function testNearSphereWithLegacyCoordinates(): void
self::assertEquals(['$nearSphere' => [1, 2]], $expr->getQuery());
}

public function testNearSphereWithLegacyCoordinatesAndMinDistance(): void
{
$expr = $this->createExpr();

self::assertSame($expr, $expr->nearSphere(1, 2, 5));
self::assertEquals(['$nearSphere' => [1, 2], '$minDistance' => 5], $expr->getQuery());
}

public function testNearSphereWithLegacyCoordinatesAndMaxDistance(): void
{
$expr = $this->createExpr();

self::assertSame($expr, $expr->nearSphere(1, 2, null, 10));
self::assertEquals(['$nearSphere' => [1, 2], '$maxDistance' => 10], $expr->getQuery());
}

public function testNearSphereWithLegacyCoordinatesAndMinAndMaxDistance(): void
{
$expr = $this->createExpr();

self::assertSame($expr, $expr->nearSphere(1, 2, 5, 10));
self::assertEquals(['$nearSphere' => [1, 2], '$minDistance' => 5, '$maxDistance' => 10], $expr->getQuery());
}

public function testPullWithValue(): void
{
$expr = $this->createExpr();
Expand Down

0 comments on commit d256f9f

Please sign in to comment.