-
-
Notifications
You must be signed in to change notification settings - Fork 56
feat(#305): add support for PostGIS operators #430
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
c4b4609
7356f88
e040f11
5a5ea0e
1ba0201
da0b210
c4fda7b
82415dc
9192d5f
001d36c
ffafedd
2195454
819f87a
3382b7c
6e044dc
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -1,6 +1,26 @@ | ||||||||||||||||||
| # Available operators | ||||||||||||||||||
| # Available Operators | ||||||||||||||||||
|
|
||||||||||||||||||
| | PostgreSQL operator | Register for DQL as | Implemented by | ||||||||||||||||||
| ## Operator Conflicts and Usage Notes | ||||||||||||||||||
|
|
||||||||||||||||||
| **⚠️ Important**: Some PostgreSQL operators have multiple meanings depending on the data types involved. This library provides specific DQL function names to avoid conflicts: | ||||||||||||||||||
|
|
||||||||||||||||||
| | Operator | Array/JSON Usage | Spatial Usage | Text/Pattern Usage | | ||||||||||||||||||
| |---|---|---|---| | ||||||||||||||||||
| | `@>` | `CONTAINS` (arrays contain elements) | Works automatically with geometry/geography | N/A | | ||||||||||||||||||
| | `<@` | `IS_CONTAINED_BY` (element in array) | Works automatically with geometry/geography | N/A | | ||||||||||||||||||
| | `@` | N/A | `SPATIAL_CONTAINED_BY` (bounding box contained) | N/A | | ||||||||||||||||||
| | `~` | N/A | `SPATIAL_CONTAINS` (bounding box contains) | `REGEXP` (text pattern matching) | | ||||||||||||||||||
| | `&&` | `OVERLAPS` (arrays/ranges overlap) | Works automatically with geometry/geography | N/A | | ||||||||||||||||||
|
|
||||||||||||||||||
| **Usage Guidelines:** | ||||||||||||||||||
| - **Arrays/JSON**: Use `CONTAINS`, `IS_CONTAINED_BY`, `OVERLAPS` for array and JSON operations | ||||||||||||||||||
| - **Spatial**: Use `SPATIAL_CONTAINS`, `SPATIAL_CONTAINED_BY` for explicit spatial bounding box operations | ||||||||||||||||||
| - **Text**: Use `REGEXP`, `IREGEXP` for pattern matching | ||||||||||||||||||
| - **Boolean operators**: All spatial operators return boolean values and **shall be used with `= TRUE` or `= FALSE` in DQL** | ||||||||||||||||||
|
|
||||||||||||||||||
| ## General Operators | ||||||||||||||||||
|
|
||||||||||||||||||
| | PostgreSQL operator | Register for DQL as | Implemented by | | ||||||||||||||||||
| |---|---|---| | ||||||||||||||||||
| | @> | CONTAINS | `MartinGeorgiev\Doctrine\ORM\Query\AST\Functions\Contains` | | ||||||||||||||||||
| | <@ | IS_CONTAINED_BY | `MartinGeorgiev\Doctrine\ORM\Query\AST\Functions\IsContainedBy` | | ||||||||||||||||||
|
|
@@ -24,9 +44,80 @@ | |||||||||||||||||
| | @@ | TSMATCH | `MartinGeorgiev\Doctrine\ORM\Query\AST\Functions\Tsmatch` | | ||||||||||||||||||
| | \|\| | STRCONCAT | `MartinGeorgiev\Doctrine\ORM\Query\AST\Functions\StrConcat` | | ||||||||||||||||||
|
|
||||||||||||||||||
| # Available functions | ||||||||||||||||||
| ## PostGIS Spatial Operators | ||||||||||||||||||
|
|
||||||||||||||||||
| **⚠️ Important**: Some operators have dual meanings for different data types. Use the specific DQL function names to avoid conflicts: | ||||||||||||||||||
|
|
||||||||||||||||||
| - **`@`**: Use `CONTAINS` for arrays/JSON, `SPATIAL_CONTAINED_BY` for geometry/geography | ||||||||||||||||||
| - **`~`**: Use `REGEXP` for text patterns, `SPATIAL_CONTAINS` for geometry/geography | ||||||||||||||||||
| - **`&&`**: Use `OVERLAPS` for arrays/JSON, spatial overlaps work automatically with geometry/geography | ||||||||||||||||||
|
|
||||||||||||||||||
| **📝 Compatibility Notes**: | ||||||||||||||||||
| - Most bounding box operators work primarily with **geometry** types | ||||||||||||||||||
| - **Geography** types have limited operator support (mainly `&&`, `<->`, `<@>`) | ||||||||||||||||||
| - **3D/n-dimensional operators** may require explicit type casting: `ST_GeomFromText('POINT Z(0 0 0)')` | ||||||||||||||||||
|
Comment on lines
+55
to
+58
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 💡 Verification agent ❓ Verification inconclusiveTighten compatibility notes for geography and remove likely-incorrect <@> reference. Geography reliably supports -- **Geography** types have limited operator support (mainly `&&`, `<->`, `<@>`)
+- **Geography** types have limited operator support (commonly `&&`, `<->` with KNN GiST/SP-GiST)Update geography compatibility notes
Please apply this change to docs/AVAILABLE-FUNCTIONS-AND-OPERATORS.md (around lines 55–58): - **Geography** types have limited operator support (mainly `&&`, `<->`, `<@>`)
+ **Geography** types have limited operator support (commonly `&&`, `<->` with KNN GiST/SP-GiST)📝 Committable suggestion
Suggested change
🧰 Tools🪛 LanguageTool[grammar] ~55-~55: There might be a mistake here. (QB_NEW_EN) [grammar] ~56-~56: There might be a mistake here. (QB_NEW_EN) [grammar] ~57-~57: There might be a mistake here. (QB_NEW_EN) 🤖 Prompt for AI Agents |
||||||||||||||||||
| - Some advanced operators (`&&&`, `<<#>>`) may not be available in all PostGIS versions | ||||||||||||||||||
|
|
||||||||||||||||||
| ### Bounding Box Operators | ||||||||||||||||||
|
|
||||||||||||||||||
| These operators work with geometry and geography bounding boxes. All return boolean values and **shall be used with `= TRUE` or `= FALSE` in DQL**. | ||||||||||||||||||
|
|
||||||||||||||||||
| | PostgreSQL operator | Register for DQL as | Description | Implemented by | | ||||||||||||||||||
| |---|---|---|---| | ||||||||||||||||||
| | &< | OVERLAPS_LEFT | Returns TRUE if A's bounding box overlaps or is to the left of B's | `MartinGeorgiev\Doctrine\ORM\Query\AST\Functions\OverlapsLeft` | | ||||||||||||||||||
| | &> | OVERLAPS_RIGHT | Returns TRUE if A's bounding box overlaps or is to the right of B's | `MartinGeorgiev\Doctrine\ORM\Query\AST\Functions\OverlapsRight` | | ||||||||||||||||||
| | << | STRICTLY_LEFT | Returns TRUE if A's bounding box is strictly to the left of B's | `MartinGeorgiev\Doctrine\ORM\Query\AST\Functions\StrictlyLeft` | | ||||||||||||||||||
| | >> | STRICTLY_RIGHT | Returns TRUE if A's bounding box is strictly to the right of B's | `MartinGeorgiev\Doctrine\ORM\Query\AST\Functions\StrictlyRight` | | ||||||||||||||||||
| | @ | SPATIAL_CONTAINED_BY | Returns TRUE if A's bounding box is contained by B's (**spatial version**) | `MartinGeorgiev\Doctrine\ORM\Query\AST\Functions\SpatialContainedBy` | | ||||||||||||||||||
| | ~ | SPATIAL_CONTAINS | Returns TRUE if A's bounding box contains B's (**spatial version**) | `MartinGeorgiev\Doctrine\ORM\Query\AST\Functions\SpatialContains` | | ||||||||||||||||||
| | ~= | SPATIAL_SAME | Returns TRUE if A's bounding box is the same as B's | `MartinGeorgiev\Doctrine\ORM\Query\AST\Functions\SpatialSame` | | ||||||||||||||||||
| | \|&> | OVERLAPS_ABOVE | Returns TRUE if A's bounding box overlaps or is above B's | `MartinGeorgiev\Doctrine\ORM\Query\AST\Functions\OverlapsAbove` | | ||||||||||||||||||
| | \|>> | STRICTLY_ABOVE | Returns TRUE if A's bounding box is strictly above B's | `MartinGeorgiev\Doctrine\ORM\Query\AST\Functions\StrictlyAbove` | | ||||||||||||||||||
| | &<\| | OVERLAPS_BELOW | Returns TRUE if A's bounding box overlaps or is below B's | `MartinGeorgiev\Doctrine\ORM\Query\AST\Functions\OverlapsBelow` | | ||||||||||||||||||
| | <<\| | STRICTLY_BELOW | Returns TRUE if A's bounding box is strictly below B's | `MartinGeorgiev\Doctrine\ORM\Query\AST\Functions\StrictlyBelow` | | ||||||||||||||||||
| | &&& | ND_OVERLAPS | Returns TRUE if A's n-D bounding box intersects B's n-D bounding box | `MartinGeorgiev\Doctrine\ORM\Query\AST\Functions\NDimensionalOverlaps` | | ||||||||||||||||||
|
|
||||||||||||||||||
| **Usage Examples:** | ||||||||||||||||||
| ```sql | ||||||||||||||||||
| -- Find geometries to the left of a reference point | ||||||||||||||||||
| SELECT e FROM Entity e WHERE STRICTLY_LEFT(e.geometry, 'POINT(0 0)') = TRUE | ||||||||||||||||||
|
|
||||||||||||||||||
| -- Find overlapping polygons | ||||||||||||||||||
| SELECT e FROM Entity e WHERE SPATIAL_CONTAINS(e.polygon, e.point) = TRUE | ||||||||||||||||||
|
|
||||||||||||||||||
| -- 3D spatial relationships | ||||||||||||||||||
| SELECT e FROM Entity e WHERE ND_OVERLAPS(e.geometry3d, 'POLYGON Z((0 0 0, 1 1 1, 2 2 2, 0 0 0))') = TRUE | ||||||||||||||||||
| ``` | ||||||||||||||||||
|
|
||||||||||||||||||
| ### Distance Operators | ||||||||||||||||||
|
|
||||||||||||||||||
| These operators calculate distances between geometries. All return numeric values. | ||||||||||||||||||
|
|
||||||||||||||||||
| | PostgreSQL operator | Register for DQL as | Description | Implemented by | | ||||||||||||||||||
| |---|---|---|---| | ||||||||||||||||||
| | <-> | GEOMETRY_DISTANCE | Returns the 2D distance between A and B geometries | `MartinGeorgiev\Doctrine\ORM\Query\AST\Functions\GeometryDistance` | | ||||||||||||||||||
| | <@> | DISTANCE | Returns distance between points (legacy operator) | `MartinGeorgiev\Doctrine\ORM\Query\AST\Functions\Distance` | | ||||||||||||||||||
| | \|=\| | TRAJECTORY_DISTANCE | Returns distance between trajectories at closest point of approach | `MartinGeorgiev\Doctrine\ORM\Query\AST\Functions\TrajectoryDistance` | | ||||||||||||||||||
| | <#> | BOUNDING_BOX_DISTANCE | Returns the 2D distance between A and B bounding boxes | `MartinGeorgiev\Doctrine\ORM\Query\AST\Functions\BoundingBoxDistance` | | ||||||||||||||||||
| | <<->> | ND_CENTROID_DISTANCE | Returns n-D distance between centroids of bounding boxes | `MartinGeorgiev\Doctrine\ORM\Query\AST\Functions\NDimensionalCentroidDistance` | | ||||||||||||||||||
| | <<#>> | ND_BOUNDING_BOX_DISTANCE | Returns the n-D distance between A and B bounding boxes | `MartinGeorgiev\Doctrine\ORM\Query\AST\Functions\NDimensionalBoundingBoxDistance` | | ||||||||||||||||||
|
|
||||||||||||||||||
| **Usage Examples:** | ||||||||||||||||||
| ```sql | ||||||||||||||||||
| -- Find nearest geometries | ||||||||||||||||||
| SELECT e, GEOMETRY_DISTANCE(e.geometry, 'POINT(0 0)') as distance | ||||||||||||||||||
| FROM Entity e ORDER BY distance LIMIT 10 | ||||||||||||||||||
|
|
||||||||||||||||||
| -- Bounding box distance for index optimization | ||||||||||||||||||
| SELECT e FROM Entity e WHERE BOUNDING_BOX_DISTANCE(e.geometry, 'POINT(0 0)') < 1000 | ||||||||||||||||||
|
|
||||||||||||||||||
| -- 3D distance calculations | ||||||||||||||||||
| SELECT ND_CENTROID_DISTANCE(e.geometry3d1, e.geometry3d2) as distance FROM Entity e | ||||||||||||||||||
| ``` | ||||||||||||||||||
|
|
||||||||||||||||||
| # Available Functions | ||||||||||||||||||
|
|
||||||||||||||||||
| | PostgreSQL functions | Register for DQL as | Implemented by | ||||||||||||||||||
| | PostgreSQL functions | Register for DQL as | Implemented by | | ||||||||||||||||||
| |---|---|---| | ||||||||||||||||||
| | all | ALL_OF | `MartinGeorgiev\Doctrine\ORM\Query\AST\Functions\All` | | ||||||||||||||||||
| | any | ANY_OF | `MartinGeorgiev\Doctrine\ORM\Query\AST\Functions\Any` | | ||||||||||||||||||
|
|
@@ -134,9 +225,9 @@ | |||||||||||||||||
| | width_bucket | WIDTH_BUCKET | `MartinGeorgiev\Doctrine\ORM\Query\AST\Functions\WidthBucket` | | ||||||||||||||||||
|
|
||||||||||||||||||
|
|
||||||||||||||||||
| # Bonus helpers | ||||||||||||||||||
| # Bonus Helpers | ||||||||||||||||||
|
|
||||||||||||||||||
| | PostgreSQL functions | Register for DQL as | Implemented by | ||||||||||||||||||
| | PostgreSQL functions | Register for DQL as | Implemented by | | ||||||||||||||||||
| |---|---|---| | ||||||||||||||||||
| | array | ARRAY | `MartinGeorgiev\Doctrine\ORM\Query\AST\Functions\Arr` | | ||||||||||||||||||
| | value = ANY(list of values) | IN_ARRAY | `MartinGeorgiev\Doctrine\ORM\Query\AST\Functions\InArray` | | ||||||||||||||||||
|
|
||||||||||||||||||
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -178,9 +178,87 @@ POLYGONZM((...)) => POLYGON ZM((...)) | |||||||||||||||||||||||||||||||||||||||||||||||||||||
| POINT Z (1 2 3) => POINT Z(1 2 3) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ``` | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ### Using PostGIS Spatial Operators in DQL | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
| PostGIS spatial operators allow you to perform spatial queries using bounding box relationships and distance calculations. **Important**: All spatial operators return boolean values and shall be used with `= TRUE` or `= FALSE` in DQL. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
| #### Bounding Box Spatial Relationships | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ```sql | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| -- Find geometries to the left of a reference point | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| SELECT e FROM Entity e WHERE STRICTLY_LEFT(e.geometry, 'POINT(0 0)') = TRUE | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
| -- Find geometries that spatially contain a point (bounding box level) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| SELECT e FROM Entity e WHERE SPATIAL_CONTAINS(e.polygon, 'POINT(1 1)') = TRUE | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
| -- Find geometries contained within a bounding box | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| SELECT e FROM Entity e WHERE SPATIAL_CONTAINED_BY(e.geometry, 'POLYGON((0 0, 10 10, 20 20, 0 0))') = TRUE | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
| -- Check if two geometries have the same bounding box | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| SELECT e FROM Entity e WHERE SPATIAL_SAME(e.geometry1, e.geometry2) = TRUE | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
| -- Vertical relationships | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| SELECT e FROM Entity e WHERE STRICTLY_ABOVE(e.geometry, 'LINESTRING(0 0, 5 0)') = TRUE | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| SELECT e FROM Entity e WHERE OVERLAPS_BELOW(e.geometry, 'POLYGON((0 5, 5 5, 5 10, 0 10, 0 5))') = TRUE | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
| -- 3D spatial relationships | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| SELECT e FROM Entity e WHERE ND_OVERLAPS(e.geometry3d, 'POLYGON Z((0 0 0, 1 1 1, 2 2 2, 0 0 0))') = TRUE | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ``` | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+183
to
+206
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Fix invalid/degenerate WKT in examples. POLYGON((0 0, 10 10, 20 20, 0 0)) is colinear and invalid. Provide valid rings; also prefer simple rectangles for clarity. The 3D polygon example is likewise degenerate. -SELECT e FROM Entity e WHERE SPATIAL_CONTAINED_BY(e.geometry, 'POLYGON((0 0, 10 10, 20 20, 0 0))') = TRUE
+SELECT e FROM Entity e WHERE SPATIAL_CONTAINED_BY(e.geometry, 'POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))') = TRUE
@@
-SELECT e FROM Entity e WHERE ND_OVERLAPS(e.geometry3d, 'POLYGON Z((0 0 0, 1 1 1, 2 2 2, 0 0 0))') = TRUE
+SELECT e FROM Entity e WHERE ND_OVERLAPS(e.geometry3d, 'POLYGON Z((0 0 0, 0 1 0, 1 1 0, 1 0 0, 0 0 0))') = TRUE📝 Committable suggestion
Suggested change
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
| #### Distance-Based Queries | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ```sql | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| -- Find the 10 nearest geometries to a point | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| SELECT e, GEOMETRY_DISTANCE(e.geometry, 'POINT(0 0)') as distance | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| FROM Entity e | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ORDER BY distance | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| LIMIT 10 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
| -- Find geometries within a specific distance (using bounding box distance for performance) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| SELECT e FROM Entity e WHERE BOUNDING_BOX_DISTANCE(e.geometry, 'POINT(0 0)') < 1000 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
| -- Calculate trajectory distances (for linestrings with measure values) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| SELECT TRAJECTORY_DISTANCE(e.trajectory1, e.trajectory2) as closest_approach | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| FROM Entity e | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| WHERE e.trajectory1 IS NOT NULL | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
| -- 3D distance calculations | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| SELECT e, ND_CENTROID_DISTANCE(e.geometry3d1, e.geometry3d2) as distance3d | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| FROM Entity e | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| WHERE ND_BOUNDING_BOX_DISTANCE(e.geometry3d1, e.geometry3d2) < 500 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ``` | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
| #### Operator Conflicts and Best Practices | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Some operators have different meanings for different data types. Use specific function names to avoid conflicts: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ```sql | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| -- ✅ CORRECT: Use specific function names | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| SELECT e FROM Entity e WHERE CONTAINS(e.tags, ARRAY['tag1']) = TRUE -- Array containment | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| SELECT e FROM Entity e WHERE SPATIAL_CONTAINS(e.polygon, e.point) = TRUE -- Spatial containment | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| SELECT e FROM Entity e WHERE REGEXP(e.text, 'pattern') = TRUE -- Text pattern matching | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
| -- ❌ AVOID: Ambiguous usage that might conflict | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| -- The @ and ~ operators have different meanings for arrays vs spatial data | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ``` | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
| #### Performance Tips | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ```sql | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| -- Use bounding box operators for initial filtering (they use spatial indexes) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| SELECT e FROM Entity e | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| WHERE OVERLAPS(e.geometry, 'POLYGON((0 0, 10 10, 20 20, 0 0))') = TRUE | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| AND ST_Intersects(e.geometry, 'POLYGON((0 0, 10 10, 20 20, 0 0))') -- Exact check | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
| -- Use distance operators for nearest neighbor queries | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| SELECT e FROM Entity e | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ORDER BY GEOMETRY_DISTANCE(e.geometry, 'POINT(0 0)') | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| LIMIT 10 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ``` | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
| For multi-item arrays, see [GEOMETRY-ARRAYS.md](./GEOMETRY-ARRAYS.md) for Doctrine DQL limitations and the suggested workarounds. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
| The library provides DBAL type support for PostGIS `geometry` and `geography` columns. Example usage: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| The library provides DBAL type support for PostGIS `geometry` and `geography` types. Example usage: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ```sql | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| CREATE TABLE places ( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,24 @@ | ||
| <?php | ||
|
|
||
| declare(strict_types=1); | ||
|
|
||
| namespace Fixtures\MartinGeorgiev\Doctrine\Entity; | ||
|
|
||
| use Doctrine\ORM\Mapping as ORM; | ||
| use MartinGeorgiev\Doctrine\DBAL\Types\ValueObject\WktSpatialData; | ||
|
|
||
| #[ORM\Entity()] | ||
| class ContainsGeometries extends Entity | ||
| { | ||
| #[ORM\Column(type: 'geometry')] | ||
| public WktSpatialData $geometry1; | ||
|
|
||
| #[ORM\Column(type: 'geometry')] | ||
| public WktSpatialData $geometry2; | ||
|
|
||
| #[ORM\Column(type: 'geography')] | ||
| public WktSpatialData $geography1; | ||
|
|
||
| #[ORM\Column(type: 'geography')] | ||
| public WktSpatialData $geography2; | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,29 @@ | ||
| <?php | ||
|
|
||
| declare(strict_types=1); | ||
|
|
||
| namespace MartinGeorgiev\Doctrine\ORM\Query\AST\Functions; | ||
|
|
||
| /** | ||
| * Implementation of PostGIS 2D bounding box distance operator (using <#>). | ||
| * | ||
| * Returns the 2D distance between A and B bounding boxes. | ||
| * This is useful for index-based distance queries. | ||
| * | ||
| * @see https://postgis.net/docs/reference.html#Operators_Distance | ||
| * @since 3.5 | ||
| * | ||
| * @author Martin Georgiev <martin.georgiev@gmail.com> | ||
| * | ||
| * @example Using it in DQL: "SELECT BOUNDING_BOX_DISTANCE(g1.geometry, g2.geometry) FROM Entity g1, Entity g2" | ||
| * Returns numeric distance value. | ||
| */ | ||
| class BoundingBoxDistance extends BaseFunction | ||
| { | ||
| protected function customizeFunction(): void | ||
| { | ||
| $this->setFunctionPrototype('(%s <#> %s)'); | ||
| $this->addNodeMapping('StringPrimary'); | ||
| $this->addNodeMapping('StringPrimary'); | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,33 @@ | ||
| <?php | ||
|
|
||
| declare(strict_types=1); | ||
|
|
||
| namespace MartinGeorgiev\Doctrine\ORM\Query\AST\Functions; | ||
|
|
||
| /** | ||
| * Implementation of PostGIS 2D distance between geometries operator (using <->). | ||
| * | ||
| * Returns the 2D distance between A and B geometries. | ||
| * This differs from BoundingBoxDistance (using <#>), which measures distance between | ||
| * bounding boxes only. The <-> operator is commonly used for KNN nearest-neighbor | ||
| * ordering, and on PostgreSQL 9.5+ with PostGIS 2.2+ it returns true geometry distance; | ||
| * on older stacks it behaved as a centroid-of-bounding-box distance approximation. | ||
| * | ||
| * @see https://postgis.net/docs/reference.html#Operators | ||
| * @see https://postgis.net/docs/geometry_distance_knn.html | ||
| * @since 3.5 | ||
| * | ||
| * @author Martin Georgiev <martin.georgiev@gmail.com> | ||
| * | ||
| * @example Using it in DQL: "SELECT GEOMETRY_DISTANCE(g1.geometry, g2.geometry) FROM Entity g1, Entity g2" | ||
| * Returns numeric distance value. | ||
| */ | ||
| class GeometryDistance extends BaseFunction | ||
| { | ||
| protected function customizeFunction(): void | ||
| { | ||
| $this->setFunctionPrototype('(%s <-> %s)'); | ||
| $this->addNodeMapping('StringPrimary'); | ||
| $this->addNodeMapping('StringPrimary'); | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,29 @@ | ||
| <?php | ||
|
|
||
| declare(strict_types=1); | ||
|
|
||
| namespace MartinGeorgiev\Doctrine\ORM\Query\AST\Functions; | ||
|
|
||
| /** | ||
| * Implementation of PostGIS n-D bounding box distance operator (using <<#>>). | ||
| * | ||
| * Returns the n-D distance between A and B bounding boxes. | ||
| * This operator works with multi-dimensional geometries. | ||
| * | ||
| * @see https://postgis.net/docs/reference.html#Operators_Distance | ||
| * @since 3.5 | ||
| * | ||
| * @author Martin Georgiev <martin.georgiev@gmail.com> | ||
| * | ||
| * @example Using it in DQL: "SELECT ND_BOUNDING_BOX_DISTANCE(g1.geometry, g2.geometry) FROM Entity g1, Entity g2" | ||
| * Returns numeric distance value. | ||
| */ | ||
| class NDimensionalBoundingBoxDistance extends BaseFunction | ||
| { | ||
| protected function customizeFunction(): void | ||
| { | ||
| $this->setFunctionPrototype('(%s <<#>> %s)'); | ||
| $this->addNodeMapping('StringPrimary'); | ||
| $this->addNodeMapping('StringPrimary'); | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,29 @@ | ||
| <?php | ||
|
|
||
| declare(strict_types=1); | ||
|
|
||
| namespace MartinGeorgiev\Doctrine\ORM\Query\AST\Functions; | ||
|
|
||
| /** | ||
| * Implementation of PostGIS n-D centroid distance operator (using <<->>). | ||
| * | ||
| * Returns the n-D distance between the centroids of A and B bounding boxes. | ||
| * This operator works with multi-dimensional geometries. | ||
| * | ||
| * @see https://postgis.net/docs/reference.html#Operators_Distance | ||
| * @since 3.5 | ||
| * | ||
| * @author Martin Georgiev <martin.georgiev@gmail.com> | ||
| * | ||
| * @example Using it in DQL: "SELECT ND_CENTROID_DISTANCE(g1.geometry, g2.geometry) FROM Entity g1, Entity g2" | ||
| * Returns numeric distance value. | ||
| */ | ||
| class NDimensionalCentroidDistance extends BaseFunction | ||
| { | ||
| protected function customizeFunction(): void | ||
| { | ||
| $this->setFunctionPrototype('(%s <<->> %s)'); | ||
| $this->addNodeMapping('StringPrimary'); | ||
| $this->addNodeMapping('StringPrimary'); | ||
| } | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Correct spatial-usage cells for @> and <@ (they don’t apply to PostGIS bbox semantics).
Listing them as “Works automatically with geometry/geography” is misleading; PostGIS uses
@and~for bbox contain/contained-by. Keep these N/A under Spatial.📝 Committable suggestion
🧰 Tools
🪛 LanguageTool
[grammar] ~9-~9: There might be a mistake here.
Context: ...atically with geometry/geography | N/A | |
<@|IS_CONTAINED_BY(element in a...(QB_NEW_EN)
[grammar] ~10-~10: There might be a mistake here.
Context: ...atically with geometry/geography | N/A | |
@| N/A |SPATIAL_CONTAINED_BY(bo...(QB_NEW_EN)
[grammar] ~11-
11: There might be a mistake here.Context: ...NED_BY
(bounding box contained) | N/A | || N/A |SPATIAL_CONTAINS` (boundi...(QB_NEW_EN)
[grammar] ~12-~12: There might be a mistake here.
Context: ...ns) |
REGEXP(text pattern matching) | |&&|OVERLAPS(arrays/ranges overl...(QB_NEW_EN)
🤖 Prompt for AI Agents