From 3be24b26da8950023ba06edbd38b9264ec37e144 Mon Sep 17 00:00:00 2001 From: Charles Archibong Date: Fri, 26 Jun 2026 00:03:16 +0100 Subject: [PATCH 1/2] docs: Document GiST and SP-GiST indexes for geography fields Document the gist/spgist index types for geography fields, the gist default, and the type/mixing restrictions, mirroring the spatial index support added in serverpod#5392. Also correct the spatial filter operator name (dwithin -> distanceWithin) to match the API, and note the fixed SRID (Geography.defaultSrid) and SQLite limitations on geography fields. --- .../02-models/04-geography-fields.md | 10 +++++-- docs/06-concepts/06-database/04-indexing.md | 29 +++++++++++++++++-- docs/06-concepts/06-database/06-filter.md | 6 ++-- 3 files changed, 38 insertions(+), 7 deletions(-) diff --git a/docs/06-concepts/02-models/04-geography-fields.md b/docs/06-concepts/02-models/04-geography-fields.md index 5ee99582..f451f44e 100644 --- a/docs/06-concepts/02-models/04-geography-fields.md +++ b/docs/06-concepts/02-models/04-geography-fields.md @@ -4,16 +4,22 @@ description: Store geospatial data in Serverpod models using GeographyPoint, Geo # Geography fields -Geography types are used for storing geospatial data on the surface of the Earth. They are stored as PostGIS geography columns in PostgreSQL using the WGS 84 coordinate system (SRID 4326), which is the standard used by GPS. +Geography types are used for storing geospatial data on the surface of the Earth. They are stored as PostGIS geography columns in PostgreSQL using the WGS 84 coordinate system (SRID 4326), which is the standard used by GPS. The SRID is fixed to `4326`, available in Dart as `Geography.defaultSrid`; configuring a different SRID per column is not yet supported. + +Like other fields, geography fields can be made optional by appending `?` to the type, for example `location: GeographyPoint?`. All geography types support spatial filter operations such as proximity search, intersection, containment, and distance-based ordering. See the [Geography operators](../database/filter#geography-operators) section for details. -To ensure optimal performance with spatial queries, consider creating a GIST index on your geography fields. See the [Geography indexes](../database/indexing#geography-indexes) section for more details. +To ensure optimal performance with spatial queries, consider creating a spatial index on your geography fields. See the [Geography indexes](../database/indexing#geography-indexes) section for more details. :::info The usage of Geography fields requires the PostGIS PostgreSQL extension to be installed. To set up PostGIS in a new or existing project, see the [Upgrading to PostGIS support](../../upgrading/upgrade-to-postgis) guide. ::: +:::warning +Spatial operations are only supported on PostgreSQL. On SQLite, geography values are stored as text in EWKT format and round-trip through CRUD operations, but spatial query operations are not supported and throw at query time. +::: + ## GeographyPoint The `GeographyPoint` type stores a single geographic location defined by longitude and latitude. diff --git a/docs/06-concepts/06-database/04-indexing.md b/docs/06-concepts/06-database/04-indexing.md index ab1c3cac..619347d8 100644 --- a/docs/06-concepts/06-database/04-indexing.md +++ b/docs/06-concepts/06-database/04-indexing.md @@ -268,7 +268,12 @@ For more details on vector indexes and its configuration, refer to the [pgvector ### Geography indexes -Geography columns benefit from GIST (Generalized Search Tree) spatial indexes, which significantly improve the performance of spatial queries such as proximity searches, intersection tests, and containment checks. +Geography columns benefit from spatial indexes, which significantly improve the performance of spatial queries such as proximity searches, intersection tests, and containment checks. Two index types are available for geography fields: + +- `gist` - Generalized Search Tree, the default and the right choice for most workloads. +- `spgist` - Space-Partitioned Generalized Search Tree. + +If no `type` is specified for an index on a geography field, it defaults to `gist`. ```yaml class: Store @@ -282,6 +287,26 @@ indexes: type: gist ``` +Use `spgist` by setting the index `type` explicitly: + +```yaml +class: DeliveryZone +table: delivery_zone +fields: + name: String + boundary: GeographyPolygon +indexes: + delivery_zone_boundary_idx: + fields: boundary + type: spgist +``` + :::tip -A GIST index on a geography column accelerates all spatial operations (`intersects`, `dwithin`, `distance`, `contains`, `within`). For tables with many rows and frequent spatial queries, adding a GIST index is strongly recommended. +A spatial index accelerates all spatial operations (`intersects`, `distanceWithin`, `distance`, `contains`, `within`). For tables with many rows and frequent spatial queries, adding one is strongly recommended. +::: + +Geography fields only support the `gist` and `spgist` index types; any other type is rejected when generating migrations. An index may cover several geography columns, but geography and non-geography fields cannot be mixed in the same index. + +:::info +`spgist` indexes on the geography type require a recent version of PostGIS. If your PostgreSQL instance ships an older PostGIS, use `gist` instead. ::: diff --git a/docs/06-concepts/06-database/06-filter.md b/docs/06-concepts/06-database/06-filter.md index fb5a4a2c..7602623a 100644 --- a/docs/06-concepts/06-database/06-filter.md +++ b/docs/06-concepts/06-database/06-filter.md @@ -427,7 +427,7 @@ await Store.db.find( ); ``` -### dwithin +### distanceWithin Returns rows where the geography column is within a given distance (in metres) of the given geography value. Wraps `ST_DWithin`. @@ -436,7 +436,7 @@ var point = GeographyPoint(longitude: 2.35, latitude: 48.85); await Store.db.find( session, - where: (t) => t.location.dwithin(point, 1000), + where: (t) => t.location.distanceWithin(point, 1000), ); ``` @@ -496,5 +496,5 @@ await Store.db.find( ``` :::tip -For optimal performance with spatial queries, consider creating a GIST index on your geography fields. See the [Geography indexes](indexing#geography-indexes) section for more details. +For optimal performance with spatial queries, consider creating a spatial index on your geography fields. See the [Geography indexes](indexing#geography-indexes) section for more details. ::: From 1e1171e9cc39cd0b03bcbf395c8c5d50d54e9b18 Mon Sep 17 00:00:00 2001 From: Charles Archibong Date: Fri, 26 Jun 2026 00:20:40 +0100 Subject: [PATCH 2/2] docs: Quote exact validation errors for geography indexes Include the verbatim code-generation error strings for invalid geography index types and for mixing geography with non-geography fields, so the behaviour matches what serverpod#5392 emits. --- docs/06-concepts/06-database/04-indexing.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/06-concepts/06-database/04-indexing.md b/docs/06-concepts/06-database/04-indexing.md index 619347d8..bf3fe7da 100644 --- a/docs/06-concepts/06-database/04-indexing.md +++ b/docs/06-concepts/06-database/04-indexing.md @@ -305,7 +305,7 @@ indexes: A spatial index accelerates all spatial operations (`intersects`, `distanceWithin`, `distance`, `contains`, `within`). For tables with many rows and frequent spatial queries, adding one is strongly recommended. ::: -Geography fields only support the `gist` and `spgist` index types; any other type is rejected when generating migrations. An index may cover several geography columns, but geography and non-geography fields cannot be mixed in the same index. +Geography fields only support the `gist` and `spgist` index types. Specifying any other type fails code generation with `The "type" property must be one of: gist, spgist.` An index may cover several geography columns, but geography and non-geography fields cannot be mixed in the same index — doing so fails with `Mixing geography and non-geography fields in the same index is not allowed.` :::info `spgist` indexes on the geography type require a recent version of PostGIS. If your PostgreSQL instance ships an older PostGIS, use `gist` instead.