Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
61 changes: 42 additions & 19 deletions src/Database/Adapter/MariaDB.php
Original file line number Diff line number Diff line change
Expand Up @@ -1352,6 +1352,47 @@ public function deleteDocument(string $collection, string $id): bool
return $deleted;
}

/**
* Handle distance spatial queries
*
* @param Query $query
* @param array<string, mixed> $binds
* @param string $attribute
* @param string $alias
* @param string $placeholder
* @return string
*/
protected function handleDistanceSpatialQueries(Query $query, array &$binds, string $attribute, string $alias, string $placeholder): string
{
$distanceParams = $query->getValues()[0];
$binds[":{$placeholder}_0"] = $this->convertArrayToWKT($distanceParams[0]);
$binds[":{$placeholder}_1"] = $distanceParams[1];

$useMeters = isset($distanceParams[2]) && $distanceParams[2] === true;

switch ($query->getMethod()) {
case Query::TYPE_DISTANCE_EQUAL:
$operator = '=';
break;
case Query::TYPE_DISTANCE_NOT_EQUAL:
$operator = '!=';
break;
case Query::TYPE_DISTANCE_GREATER_THAN:
$operator = '>';
break;
case Query::TYPE_DISTANCE_LESS_THAN:
$operator = '<';
break;
default:
throw new DatabaseException('Unknown spatial query method: ' . $query->getMethod());
}

if ($useMeters) {
return "ST_DISTANCE_SPHERE({$alias}.{$attribute}, ST_GeomFromText(:{$placeholder}_0), 6371000) {$operator} :{$placeholder}_1";
}
return "ST_Distance({$alias}.{$attribute}, ST_GeomFromText(:{$placeholder}_0)) {$operator} :{$placeholder}_1";
}
Comment on lines +1365 to +1394
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Verification agent

🧩 Analysis chain

Meters path likely POINT-only on MariaDB; avoid magic number and verify SRID handling

  • ST_Distance_Sphere in MariaDB is generally POINT-only. Distance queries on LINESTRING/POLYGON with $useMeters=true will likely error. Either restrict meters-based distance to VAR_POINT in validation (preferred), or throw a clear DatabaseException here when attribute type isn’t a point.
  • 6371000 is a magic number. Consider extracting an EARTH_RADIUS_METERS constant (e.g., Database::EARTH_RADIUS_METERS) to keep adapters in sync.
  • SRID is not set on either side for MariaDB. If your stored geometries are lon/lat (WGS84), consider passing SRID explicitly to ST_GeomFromText (and, if supported, setting SRID on the column expression) for consistency with other adapters. Verify MariaDB’s setter semantics first.

Apply if acceptable:

-        if ($useMeters) {
-            return "ST_DISTANCE_SPHERE({$alias}.{$attribute}, ST_GeomFromText(:{$placeholder}_0), 6371000) {$operator} :{$placeholder}_1";
-        }
-        return "ST_Distance({$alias}.{$attribute}, ST_GeomFromText(:{$placeholder}_0)) {$operator} :{$placeholder}_1";
+        if ($useMeters) {
+            $attr = "{$alias}.{$attribute}"; // optionally: ST_SRID({$alias}.{$attribute}, " . Database::SRID . ")
+            $geom = "ST_GeomFromText(:{$placeholder}_0, " . Database::SRID . ")"; // explicit SRID if inputs are WGS84
+            return "ST_Distance_Sphere({$attr}, {$geom}, " . (defined('Utopia\\Database\\Database::EARTH_RADIUS_METERS') ? Database::EARTH_RADIUS_METERS : 6371000) . ") {$operator} :{$placeholder}_1";
+        }
+        // keep unitless behavior when meters=false
+        return "ST_Distance({$alias}.{$attribute}, ST_GeomFromText(:{$placeholder}_0)) {$operator} :{$placeholder}_1";

I can add a point-only validator path for MariaDB distance-with-meters and introduce Database::EARTH_RADIUS_METERS. Want me to open a follow-up PR?


🌐 Web query:

Does MariaDB support ST_Distance_Sphere(point, point, radius)? Is it restricted to POINT geometries, and from which versions?

💡 Result:

Short answer: Yes. MariaDB provides ST_DISTANCE_SPHERE(g1,g2[,r]) (returns spherical distance in meters, optional radius). It accepts POINT or MULTIPOINT geometries (not arbitrary geometry types). The function was added in the 10.2/10.3/10.4/10.5 branches (backports): available starting in 10.2.38, 10.3.29, 10.4.19 and 10.5.10 (and in later releases such as 10.6+). [1][2]

Sources:

  • MariaDB ST_DISTANCE_SPHERE docs. [1]
  • MariaDB release/change history / SKySQL doc listing versions added. [2]

Validate supported geometries, extract Earth-radius constant, and set SRID explicitly

  • ST_Distance_Sphere only accepts POINT and MULTIPOINT (introduced in MariaDB 10.2.38/10.3.29/10.4.19/10.5.10+); invoking it on other geometry types will error—validate the column type before using $useMeters or throw a clear DatabaseException. (mariadb.com)
  • Replace the magic number 6371000 with a shared constant (e.g., Database::EARTH_RADIUS_METERS) to keep adapters in sync.
  • Pass an explicit SRID to ST_GeomFromText and, if supported, apply it to the column expression for WGS84 consistency.
🤖 Prompt for AI Agents
In src/Database/Adapter/MariaDB.php around lines 1365–1394, validate the target
column geometry type before using ST_DISTANCE_SPHERE (only allow POINT or
MULTIPOINT) and throw a DatabaseException with a clear message if it’s
unsupported; replace the magic 6371000 with a shared constant (e.g.,
Database::EARTH_RADIUS_METERS) and pass an explicit SRID (use WGS84 4326) to
ST_GeomFromText, and where possible apply the same SRID to the column expression
so both operands share the WGS84 SRID; implement the column-type check by
querying the column metadata (or using the adapter’s schema info) and branch to
either the meters-enabled ST_DISTANCE_SPHERE path or the SRID-aware ST_Distance
path accordingly.


/**
* Handle spatial queries
*
Expand All @@ -1374,28 +1415,10 @@ protected function handleSpatialQueries(Query $query, array &$binds, string $att
return "NOT ST_Crosses({$alias}.{$attribute}, ST_GeomFromText(:{$placeholder}_0))";

case Query::TYPE_DISTANCE_EQUAL:
$distanceParams = $query->getValues()[0];
$binds[":{$placeholder}_0"] = $this->convertArrayToWKT($distanceParams[0]);
$binds[":{$placeholder}_1"] = $distanceParams[1];
return "ST_Distance({$alias}.{$attribute}, ST_GeomFromText(:{$placeholder}_0)) = :{$placeholder}_1";

case Query::TYPE_DISTANCE_NOT_EQUAL:
$distanceParams = $query->getValues()[0];
$binds[":{$placeholder}_0"] = $this->convertArrayToWKT($distanceParams[0]);
$binds[":{$placeholder}_1"] = $distanceParams[1];
return "ST_Distance({$alias}.{$attribute}, ST_GeomFromText(:{$placeholder}_0)) != :{$placeholder}_1";

case Query::TYPE_DISTANCE_GREATER_THAN:
$distanceParams = $query->getValues()[0];
$binds[":{$placeholder}_0"] = $this->convertArrayToWKT($distanceParams[0]);
$binds[":{$placeholder}_1"] = $distanceParams[1];
return "ST_Distance({$alias}.{$attribute}, ST_GeomFromText(:{$placeholder}_0)) > :{$placeholder}_1";

case Query::TYPE_DISTANCE_LESS_THAN:
$distanceParams = $query->getValues()[0];
$binds[":{$placeholder}_0"] = $this->convertArrayToWKT($distanceParams[0]);
$binds[":{$placeholder}_1"] = $distanceParams[1];
return "ST_Distance({$alias}.{$attribute}, ST_GeomFromText(:{$placeholder}_0)) < :{$placeholder}_1";
return $this->handleDistanceSpatialQueries($query, $binds, $attribute, $alias, $placeholder);

case Query::TYPE_INTERSECTS:
$binds[":{$placeholder}_0"] = $this->convertArrayToWKT($query->getValues()[0]);
Expand Down
46 changes: 46 additions & 0 deletions src/Database/Adapter/MySQL.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
use Utopia\Database\Exception as DatabaseException;
use Utopia\Database\Exception\Dependency as DependencyException;
use Utopia\Database\Exception\Timeout as TimeoutException;
use Utopia\Database\Query;

class MySQL extends MariaDB
{
Expand Down Expand Up @@ -78,6 +79,51 @@ public function getSizeOfCollectionOnDisk(string $collection): int
return $size;
}

/**
* Handle distance spatial queries
*
* @param Query $query
* @param array<string, mixed> $binds
* @param string $attribute
* @param string $alias
* @param string $placeholder
* @return string
*/
protected function handleDistanceSpatialQueries(Query $query, array &$binds, string $attribute, string $alias, string $placeholder): string
{
$distanceParams = $query->getValues()[0];
$binds[":{$placeholder}_0"] = $this->convertArrayToWKT($distanceParams[0]);
$binds[":{$placeholder}_1"] = $distanceParams[1];

$useMeters = isset($distanceParams[2]) && $distanceParams[2] === true;

switch ($query->getMethod()) {
case Query::TYPE_DISTANCE_EQUAL:
$operator = '=';
break;
case Query::TYPE_DISTANCE_NOT_EQUAL:
$operator = '!=';
break;
case Query::TYPE_DISTANCE_GREATER_THAN:
$operator = '>';
break;
case Query::TYPE_DISTANCE_LESS_THAN:
$operator = '<';
break;
default:
throw new DatabaseException('Unknown spatial query method: ' . $query->getMethod());
}

if ($useMeters) {
$attr = "ST_SRID({$alias}.{$attribute}, " . Database::SRID . ")";
$geom = "ST_GeomFromText(:{$placeholder}_0, " . Database::SRID . ")";
return "ST_Distance({$attr}, {$geom}, 'metre') {$operator} :{$placeholder}_1";
}

// Without meters, use default behavior
return "ST_Distance({$alias}.{$attribute}, ST_GeomFromText(:{$placeholder}_0)) {$operator} :{$placeholder}_1";
}

public function getSupportForIndexArray(): bool
{
/**
Expand Down
96 changes: 62 additions & 34 deletions src/Database/Adapter/Postgres.php
Original file line number Diff line number Diff line change
Expand Up @@ -1452,6 +1452,53 @@ public function getConnectionId(): string
return $stmt->fetchColumn();
}

/**
* Handle distance spatial queries
*
* @param Query $query
* @param array<string, mixed> $binds
* @param string $attribute
* @param string $alias
* @param string $placeholder
* @return string
*/
protected function handleDistanceSpatialQueries(Query $query, array &$binds, string $attribute, string $alias, string $placeholder): string
{
$distanceParams = $query->getValues()[0];
$binds[":{$placeholder}_0"] = $this->convertArrayToWKT($distanceParams[0]);
$binds[":{$placeholder}_1"] = $distanceParams[1];

$meters = isset($distanceParams[2]) && $distanceParams[2] === true;

switch ($query->getMethod()) {
case Query::TYPE_DISTANCE_EQUAL:
$operator = '=';
break;
case Query::TYPE_DISTANCE_NOT_EQUAL:
$operator = '!=';
break;
case Query::TYPE_DISTANCE_GREATER_THAN:
$operator = '>';
break;
case Query::TYPE_DISTANCE_LESS_THAN:
$operator = '<';
break;
default:
throw new DatabaseException('Unknown spatial query method: ' . $query->getMethod());
}

if ($meters) {
// Transform both attribute and input geometry to 3857 (meters) for distance calculation
$attr = "ST_Transform({$alias}.{$attribute}, 3857)";
$geom = "ST_Transform(ST_GeomFromText(:{$placeholder}_0, " . Database::SRID . "), 3857)";
return "ST_Distance({$attr}, {$geom}) {$operator} :{$placeholder}_1";
}

// Without meters, use the original SRID (e.g., 4326)
return "ST_Distance({$alias}.{$attribute}, ST_GeomFromText(:{$placeholder}_0, " . Database::SRID . ")) {$operator} :{$placeholder}_1";
}
Comment on lines +1490 to +1499
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Use geography for meter-accurate distances instead of 3857 transforms

EPSG:3857 introduces scale distortion; casting to geography provides meter-accurate results and aligns with MariaDB/MySQL semantics.

-        if ($meters) {
-            // Transform both attribute and input geometry to 3857 (meters) for distance calculation
-            $attr = "ST_Transform({$alias}.{$attribute}, 3857)";
-            $geom = "ST_Transform(ST_GeomFromText(:{$placeholder}_0, " . Database::SRID . "), 3857)";
-            return "ST_Distance({$attr}, {$geom}) {$operator} :{$placeholder}_1";
-        }
+        if ($meters) {
+            // Accurate geodesic distance in meters
+            return "ST_Distance({$alias}.{$attribute}::geography, ST_GeomFromText(:{$placeholder}_0, " . Database::SRID . ")::geography) {$operator} :{$placeholder}_1";
+        }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if ($meters) {
// Transform both attribute and input geometry to 3857 (meters) for distance calculation
$attr = "ST_Transform({$alias}.{$attribute}, 3857)";
$geom = "ST_Transform(ST_GeomFromText(:{$placeholder}_0, " . Database::SRID . "), 3857)";
return "ST_Distance({$attr}, {$geom}) {$operator} :{$placeholder}_1";
}
// Without meters, use the original SRID (e.g., 4326)
return "ST_Distance({$alias}.{$attribute}, ST_GeomFromText(:{$placeholder}_0, " . Database::SRID . ")) {$operator} :{$placeholder}_1";
}
if ($meters) {
// Accurate geodesic distance in meters
return "ST_Distance({$alias}.{$attribute}::geography, ST_GeomFromText(:{$placeholder}_0, " . Database::SRID . ")::geography) {$operator} :{$placeholder}_1";
}
// Without meters, use the original SRID (e.g., 4326)
return "ST_Distance({$alias}.{$attribute}, ST_GeomFromText(:{$placeholder}_0, " . Database::SRID . ")) {$operator} :{$placeholder}_1";
}
🤖 Prompt for AI Agents
In src/Database/Adapter/Postgres.php around lines 1490 to 1499, the current
implementation projects geometries to EPSG:3857 for meter calculations which can
introduce distortion; instead, cast both the stored attribute and the input
geometry to PostGIS geography and call ST_Distance on those geography types so
distances are meter-accurate and consistent with MariaDB/MySQL semantics. Update
the meters branch to stop using ST_Transform(..., 3857) and instead cast the
attribute and the ST_GeomFromText(...) (using Database::SRID) to ::geography,
then compute ST_Distance between them; keep the alias, attribute name,
placeholders and the operator/parameter placeholder unchanged. Ensure the
non-meters branch remains using the original SRID as before.



/**
* Handle spatial queries
*
Expand All @@ -1474,60 +1521,41 @@ protected function handleSpatialQueries(Query $query, array &$binds, string $att
return "NOT ST_Crosses({$alias}.{$attribute}, ST_GeomFromText(:{$placeholder}_0))";

case Query::TYPE_DISTANCE_EQUAL:
$distanceParams = $query->getValues()[0];
$binds[":{$placeholder}_0"] = $this->convertArrayToWKT($distanceParams[0]);
$binds[":{$placeholder}_1"] = $distanceParams[1];
return "ST_DWithin({$alias}.{$attribute}, ST_GeomFromText(:{$placeholder}_0), :{$placeholder}_1)";

case Query::TYPE_DISTANCE_NOT_EQUAL:
$distanceParams = $query->getValues()[0];
$binds[":{$placeholder}_0"] = $this->convertArrayToWKT($distanceParams[0]);
$binds[":{$placeholder}_1"] = $distanceParams[1];
return "NOT ST_DWithin({$alias}.{$attribute}, ST_GeomFromText(:{$placeholder}_0), :{$placeholder}_1)";

case Query::TYPE_DISTANCE_GREATER_THAN:
$distanceParams = $query->getValues()[0];
$binds[":{$placeholder}_0"] = $this->convertArrayToWKT($distanceParams[0]);
$binds[":{$placeholder}_1"] = $distanceParams[1];
return "ST_Distance({$alias}.{$attribute}, ST_GeomFromText(:{$placeholder}_0)) > :{$placeholder}_1";

case Query::TYPE_DISTANCE_LESS_THAN:
$distanceParams = $query->getValues()[0];
$binds[":{$placeholder}_0"] = $this->convertArrayToWKT($distanceParams[0]);
$binds[":{$placeholder}_1"] = $distanceParams[1];
return "ST_Distance({$alias}.{$attribute}, ST_GeomFromText(:{$placeholder}_0)) < :{$placeholder}_1";

return $this->handleDistanceSpatialQueries($query, $binds, $attribute, $alias, $placeholder);
case Query::TYPE_EQUAL:
$binds[":{$placeholder}_0"] = $this->convertArrayToWKT($query->getValues()[0]);
return "ST_Equals({$alias}.{$attribute}, ST_GeomFromText(:{$placeholder}_0))";
return "ST_Equals({$alias}.{$attribute}, ST_GeomFromText(:{$placeholder}_0, " . Database::SRID . "))";

case Query::TYPE_NOT_EQUAL:
$binds[":{$placeholder}_0"] = $this->convertArrayToWKT($query->getValues()[0]);
return "NOT ST_Equals({$alias}.{$attribute}, ST_GeomFromText(:{$placeholder}_0))";
return "NOT ST_Equals({$alias}.{$attribute}, ST_GeomFromText(:{$placeholder}_0, " . Database::SRID . "))";

case Query::TYPE_INTERSECTS:
$binds[":{$placeholder}_0"] = $this->convertArrayToWKT($query->getValues()[0]);
return "ST_Intersects({$alias}.{$attribute}, ST_GeomFromText(:{$placeholder}_0))";
return "ST_Intersects({$alias}.{$attribute}, ST_GeomFromText(:{$placeholder}_0, " . Database::SRID . "))";

case Query::TYPE_NOT_INTERSECTS:
$binds[":{$placeholder}_0"] = $this->convertArrayToWKT($query->getValues()[0]);
return "NOT ST_Intersects({$alias}.{$attribute}, ST_GeomFromText(:{$placeholder}_0))";
return "NOT ST_Intersects({$alias}.{$attribute}, ST_GeomFromText(:{$placeholder}_0, " . Database::SRID . "))";

case Query::TYPE_OVERLAPS:
$binds[":{$placeholder}_0"] = $this->convertArrayToWKT($query->getValues()[0]);
return "ST_Overlaps({$alias}.{$attribute}, ST_GeomFromText(:{$placeholder}_0))";
return "ST_Overlaps({$alias}.{$attribute}, ST_GeomFromText(:{$placeholder}_0, " . Database::SRID . "))";

case Query::TYPE_NOT_OVERLAPS:
$binds[":{$placeholder}_0"] = $this->convertArrayToWKT($query->getValues()[0]);
return "NOT ST_Overlaps({$alias}.{$attribute}, ST_GeomFromText(:{$placeholder}_0))";
return "NOT ST_Overlaps({$alias}.{$attribute}, ST_GeomFromText(:{$placeholder}_0, " . Database::SRID . "))";

case Query::TYPE_TOUCHES:
$binds[":{$placeholder}_0"] = $this->convertArrayToWKT($query->getValues()[0]);
return "ST_Touches({$alias}.{$attribute}, ST_GeomFromText(:{$placeholder}_0))";
return "ST_Touches({$alias}.{$attribute}, ST_GeomFromText(:{$placeholder}_0, " . Database::SRID . "))";

case Query::TYPE_NOT_TOUCHES:
$binds[":{$placeholder}_0"] = $this->convertArrayToWKT($query->getValues()[0]);
return "NOT ST_Touches({$alias}.{$attribute}, ST_GeomFromText(:{$placeholder}_0))";
return "NOT ST_Touches({$alias}.{$attribute}, ST_GeomFromText(:{$placeholder}_0, " . Database::SRID . "))";

case Query::TYPE_CONTAINS:
case Query::TYPE_NOT_CONTAINS:
Expand All @@ -1536,8 +1564,8 @@ protected function handleSpatialQueries(Query $query, array &$binds, string $att
$isNot = $query->getMethod() === Query::TYPE_NOT_CONTAINS;
$binds[":{$placeholder}_0"] = $this->convertArrayToWKT($query->getValues()[0]);
return $isNot
? "NOT ST_Covers({$alias}.{$attribute}, ST_GeomFromText(:{$placeholder}_0))"
: "ST_Covers({$alias}.{$attribute}, ST_GeomFromText(:{$placeholder}_0))";
? "NOT ST_Covers({$alias}.{$attribute}, ST_GeomFromText(:{$placeholder}_0, " . Database::SRID . "))"
: "ST_Covers({$alias}.{$attribute}, ST_GeomFromText(:{$placeholder}_0, " . Database::SRID . "))";

default:
throw new DatabaseException('Unknown spatial query method: ' . $query->getMethod());
Expand Down Expand Up @@ -1716,15 +1744,15 @@ protected function getSQLType(string $type, int $size, bool $signed = true, bool
case Database::VAR_DATETIME:
return 'TIMESTAMP(3)';


// in all other DB engines, 4326 is the default SRID
case Database::VAR_POINT:
return 'GEOMETRY(POINT)';
return 'GEOMETRY(POINT,' . Database::SRID . ')';

case Database::VAR_LINESTRING:
return 'GEOMETRY(LINESTRING)';
return 'GEOMETRY(LINESTRING,' . Database::SRID . ')';

case Database::VAR_POLYGON:
return 'GEOMETRY(POLYGON)';
return 'GEOMETRY(POLYGON,' . Database::SRID . ')';

default:
throw new DatabaseException('Unknown Type: ' . $type . '. Must be one of ' . Database::VAR_STRING . ', ' . Database::VAR_INTEGER . ', ' . Database::VAR_FLOAT . ', ' . Database::VAR_BOOLEAN . ', ' . Database::VAR_DATETIME . ', ' . Database::VAR_RELATIONSHIP . ', ' . Database::VAR_POINT . ', ' . Database::VAR_LINESTRING . ', ' . Database::VAR_POLYGON);
Expand Down
7 changes: 6 additions & 1 deletion src/Database/Database.php
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,9 @@ class Database
public const BIG_INT_MAX = PHP_INT_MAX;
public const DOUBLE_MAX = PHP_FLOAT_MAX;

// Global SRID for geographic coordinates (WGS84)
public const SRID = 4326;

// Relationship Types
public const VAR_RELATIONSHIP = 'relationship';

Expand Down Expand Up @@ -7133,7 +7136,9 @@ private function processRelationshipQueries(
protected function encodeSpatialData(mixed $value, string $type): string
{
$validator = new Spatial($type);
$validator->isValid($value);
if (!$validator->isValid($value)) {
throw new StructureException($validator->getDescription());
}

switch ($type) {
case self::VAR_POINT:
Expand Down
20 changes: 12 additions & 8 deletions src/Database/Query.php
Original file line number Diff line number Diff line change
Expand Up @@ -903,11 +903,12 @@ public function setOnArray(bool $bool): void
* @param string $attribute
* @param array<mixed> $values
* @param int|float $distance
* @param bool $meters
* @return Query
*/
public static function distanceEqual(string $attribute, array $values, int|float $distance): self
public static function distanceEqual(string $attribute, array $values, int|float $distance, bool $meters = false): self
{
return new self(self::TYPE_DISTANCE_EQUAL, $attribute, [[$values,$distance]]);
return new self(self::TYPE_DISTANCE_EQUAL, $attribute, [[$values,$distance,$meters]]);
}

/**
Expand All @@ -916,11 +917,12 @@ public static function distanceEqual(string $attribute, array $values, int|float
* @param string $attribute
* @param array<mixed> $values
* @param int|float $distance
* @param bool $meters
* @return Query
*/
public static function distanceNotEqual(string $attribute, array $values, int|float $distance): self
public static function distanceNotEqual(string $attribute, array $values, int|float $distance, bool $meters = false): self
{
return new self(self::TYPE_DISTANCE_NOT_EQUAL, $attribute, [[$values,$distance]]);
return new self(self::TYPE_DISTANCE_NOT_EQUAL, $attribute, [[$values,$distance,$meters]]);
}

/**
Expand All @@ -929,11 +931,12 @@ public static function distanceNotEqual(string $attribute, array $values, int|fl
* @param string $attribute
* @param array<mixed> $values
* @param int|float $distance
* @param bool $meters
* @return Query
*/
public static function distanceGreaterThan(string $attribute, array $values, int|float $distance): self
public static function distanceGreaterThan(string $attribute, array $values, int|float $distance, bool $meters = false): self
{
return new self(self::TYPE_DISTANCE_GREATER_THAN, $attribute, [[$values,$distance]]);
return new self(self::TYPE_DISTANCE_GREATER_THAN, $attribute, [[$values,$distance, $meters]]);
}

/**
Expand All @@ -942,11 +945,12 @@ public static function distanceGreaterThan(string $attribute, array $values, int
* @param string $attribute
* @param array<mixed> $values
* @param int|float $distance
* @param bool $meters
* @return Query
*/
public static function distanceLessThan(string $attribute, array $values, int|float $distance): self
public static function distanceLessThan(string $attribute, array $values, int|float $distance, bool $meters = false): self
{
return new self(self::TYPE_DISTANCE_LESS_THAN, $attribute, [[$values,$distance]]);
return new self(self::TYPE_DISTANCE_LESS_THAN, $attribute, [[$values,$distance,$meters]]);
}

/**
Expand Down
2 changes: 1 addition & 1 deletion src/Database/Validator/Query/Filter.php
Original file line number Diff line number Diff line change
Expand Up @@ -263,7 +263,7 @@ public function isValid($value): bool
case Query::TYPE_DISTANCE_NOT_EQUAL:
case Query::TYPE_DISTANCE_GREATER_THAN:
case Query::TYPE_DISTANCE_LESS_THAN:
if (count($value->getValues()) !== 1 || !is_array($value->getValues()[0]) || count($value->getValues()[0]) !== 2) {
if (count($value->getValues()) !== 1 || !is_array($value->getValues()[0]) || count($value->getValues()[0]) !== 3) {
$this->message = 'Distance query requires [[geometry, distance]] parameters';
return false;
}
Expand Down
Loading