Documentation
¶
Overview ¶
Package postgis models the PostGIS spatial types as a small, catalog-driven value layer shared by the schema builder, the SQL compiler, and the postgis plugin.
The design mirrors how enums and composites are handled elsewhere: nothing here emits a whole statement. It answers three questions —
- is this column spatial, and which flavour (geometry vs geography)?
- how does a GraphQL input value become a single SQL parameter?
- what SQL expression reads or transforms such a value?
Everything else (filter surface, ordering, derived fields) is assembled from these pieces by callers.
The parameterization invariant ¶
PostGIS values are user data, so they must move through the parameter list exactly like any other value (see the FuzzFilter invariant: compiled SQL text is a pure function of the query *shape*). A geometry input is therefore always reduced to ONE text parameter plus a constructor whose shape depends only on the column type — never on the value:
ST_GeomFromGeoJSON($1) -- GeoJSON object input ST_GeomFromEWKT($1) -- WKT / EWKT string input
The choice between those two constructors is made from the Go type of the input (object vs string), which is part of the query shape as far as the fuzzer is concerned only if the same query text is reused — so callers pass the constructor through Value.SQL, which folds the decision into the expression and keeps the value itself in a parameter.
Index ¶
- Constants
- Variables
- func BBoxSQL(minX, minY, maxX, maxY string, srid int, f Flavour) string
- func DerivedSuffixes() []string
- func DistanceSQL(col, geom string) string
- func IsSpatial(pgType string) bool
- func KNNSQL(col, geom string) string
- func OpNames() []string
- func OpsDoc() string
- func OutputSQL(ref string) string
- func SimplifySQL(ref, tolerance string, f Flavour) string
- func TransformSQL(ref string, srid int, f Flavour) string
- type ArgKind
- type Derived
- type Flavour
- type Op
- type Value
Constants ¶
const TypeName = "GeoJSON"
TypeName is the GraphQL scalar every spatial column maps to. Values are GeoJSON objects on the way out and GeoJSON-or-WKT on the way in.
Variables ¶
var Deriveds = []Derived{ { Suffix: "Area", Type: "Float", Description: "Area of the geometry (ST_Area): square metres for geography, SRID units for geometry.", // contains filtered or unexported fields }, { Suffix: "Length", Type: "Float", Description: "Length/perimeter of the geometry (ST_Length): metres for geography, SRID units for geometry.", // contains filtered or unexported fields }, { Suffix: "Perimeter", Type: "Float", Description: "Perimeter of a polygonal geometry (ST_Perimeter).", // contains filtered or unexported fields }, { Suffix: "Centroid", Type: TypeName, GeoJSON: true, Description: "Centroid of the geometry (ST_Centroid), as GeoJSON.", // contains filtered or unexported fields }, { Suffix: "Envelope", Type: TypeName, GeoJSON: true, Description: "Bounding box of the geometry (ST_Envelope), as GeoJSON.", // contains filtered or unexported fields }, { Suffix: "Srid", Type: "Int", Description: "Spatial reference identifier of the value (ST_SRID).", // contains filtered or unexported fields }, { Suffix: "GeometryType", Type: "String", Description: "Geometry type name, e.g. ST_Point (ST_GeometryType).", // contains filtered or unexported fields }, { Suffix: "IsValid", Type: "Boolean", Description: "Whether the geometry is topologically valid (ST_IsValid).", // contains filtered or unexported fields }, }
Deriveds are the derived accessors generated for every spatial column.
Each is a pure function of the column, so they compile into the same single statement as an ordinary column read — no extra round trip.
var Ops = []Op{ { Name: "bboxIntersects", Arg: "BBoxInput", Index: true, Description: "Bounding boxes overlap (&&). Index-usable; the cheap first pass for viewport queries.", // contains filtered or unexported fields }, { Name: "bboxContains", Arg: "BBoxInput", Index: true, Description: "This column's bounding box contains the given box (~).", // contains filtered or unexported fields }, { Name: "bboxContainedBy", Arg: "BBoxInput", Index: true, Description: "This column's bounding box is contained by the given box (@).", // contains filtered or unexported fields }, { Name: "intersects", Arg: TypeName, Index: true, Description: "Geometries share any portion of space (ST_Intersects).", // contains filtered or unexported fields }, { Name: "disjoint", Arg: TypeName, Description: "Geometries share no space (ST_Disjoint). Cannot use an index.", // contains filtered or unexported fields }, { Name: "contains", Arg: TypeName, Index: true, Description: "This column's geometry contains the given geometry (ST_Contains).", // contains filtered or unexported fields }, { Name: "containsProperly", Arg: TypeName, Index: true, Description: "Contains with no boundary contact (ST_ContainsProperly).", // contains filtered or unexported fields }, { Name: "within", Arg: TypeName, Index: true, Description: "This column's geometry lies within the given geometry (ST_Within).", // contains filtered or unexported fields }, { Name: "covers", Arg: TypeName, Index: true, Description: "No point of the given geometry lies outside this column (ST_Covers).", // contains filtered or unexported fields }, { Name: "coveredBy", Arg: TypeName, Index: true, Description: "No point of this column lies outside the given geometry (ST_CoveredBy).", // contains filtered or unexported fields }, { Name: "crosses", Arg: TypeName, Index: true, Description: "Geometries cross (ST_Crosses).", // contains filtered or unexported fields }, { Name: "overlaps", Arg: TypeName, Index: true, Description: "Geometries overlap at the same dimension (ST_Overlaps).", // contains filtered or unexported fields }, { Name: "touches", Arg: TypeName, Index: true, Description: "Geometries touch at a boundary but interiors do not intersect (ST_Touches).", // contains filtered or unexported fields }, { Name: "equals", Arg: TypeName, Description: "Geometries are spatially equal, ignoring vertex order (ST_Equals).", // contains filtered or unexported fields }, { Name: "dwithin", Arg: "DWithinInput", Index: true, Description: "Within the given distance of the geometry (ST_DWithin). Distance is metres for geography, SRID units for geometry.", // contains filtered or unexported fields }, { Name: "beyond", Arg: "DWithinInput", Description: "Further than the given distance from the geometry (ST_DWithin negated).", // contains filtered or unexported fields }, { Name: "isNull", Arg: "Boolean", Description: "Test whether the column is null.", // contains filtered or unexported fields }, }
Ops is the spatial operator vocabulary exposed on every geometry and geography column.
Ordering matters only for schema readability: the index-usable bounding-box operators come first because they are the ones that stay fast on large tables, followed by the exact DE-9IM predicates.
Functions ¶
func BBoxSQL ¶
BBoxSQL renders a bounding box as ST_MakeEnvelope over four numeric parameters. The placeholders are supplied by the caller so the values stay in the parameter list; only the SRID (an integer read from the query shape) is inlined, matching how the rest of the compiler treats structural values.
func DerivedSuffixes ¶
func DerivedSuffixes() []string
DerivedSuffixes returns the accessor suffixes in declaration order.
func DistanceSQL ¶
DistanceSQL renders the ordering expression for distance-from-a-point sorts.
func KNNSQL ¶
KNNSQL renders the index-assisted nearest-neighbour operator (<->), which a GiST index can answer directly. Used for distance ordering because it is the operator PostGIS optimises for ORDER BY.
func OpsDoc ¶
func OpsDoc() string
String renders the operator vocabulary for documentation/debugging.
func OutputSQL ¶
OutputSQL renders a spatial column as the GeoJSON text the response carries.
ST_AsGeoJSON returns text, so the result is re-parsed into jsonb to embed it as a real JSON object rather than a JSON-encoded string. NULL propagates through both calls untouched.
func SimplifySQL ¶
SimplifySQL renders the per-field `simplify:` argument: drop vertices under the given tolerance (ST_SimplifyPreserveTopology, which never produces an invalid geometry). The tolerance is a placeholder supplied by the caller.
Types ¶
type Derived ¶
type Derived struct {
// Suffix is appended to the column's field name.
Suffix string
// Type is the SDL type of the generated field.
Type string
// Description documents the field.
Description string
// GeoJSON marks accessors returning a geometry (rendered as GeoJSON).
GeoJSON bool
// contains filtered or unexported fields
}
Derived is one computed spatial accessor exposed as a sibling field of a spatial column (e.g. `location` -> `locationArea`).
func DerivedBySuffix ¶
DerivedBySuffix looks up a derived accessor.
type Flavour ¶
type Flavour int
Flavour distinguishes the two spatial base types. They share an operator vocabulary but differ in units and in a few function names, so the compiler needs to keep them apart.
func FlavourOf ¶
FlavourOf classifies a canonical pg type name (array prefix already stripped by the caller, or not — both forms are accepted).
PostGIS installs its types into whichever schema the extension lives in, so classification is by type name rather than by schema: a `geometry` column is spatial whether the extension sits in public, postgis, or a tenant schema.
func (Flavour) MetresNative ¶
MetresNative reports whether distance/length arguments and results are in metres without an explicit cast. Geography is metres by definition; geometry is in whatever unit its SRID uses.
type Op ¶
type Op struct {
// Name is the GraphQL field name inside GeometryFilterOps.
Name string
// Arg is the SDL type of the operand.
Arg string
// Description documents the operator in the generated schema.
Description string
// Index reports whether the operator can use a GiST index directly.
// Index-usable operators are documented as such so users can tell the
// cheap ones from the exact-but-expensive ones.
Index bool
// contains filtered or unexported fields
}
Op describes one spatial filter operator: its GraphQL field name, the input shape it takes, and how it renders as SQL.
type Value ¶
type Value struct {
// Param is the single value handed to the driver: GeoJSON text or a
// WKT/EWKT string.
Param string
// Flavour is the target type the expression is cast to.
Flavour Flavour
// SRID, when non-zero, is applied with ST_SetSRID. GeoJSON is always
// WGS84 (4326) per RFC 7946 unless the value carries an explicit CRS;
// EWKT carries its own SRID so none is forced.
SRID int
// contains filtered or unexported fields
}
Value is a spatial input value reduced to exactly one SQL parameter plus the constructor that turns it back into a PostGIS value.
func Parse ¶
Parse converts a GraphQL input value into a Value.
Two input forms are accepted, both collapsing to a single parameter:
- a GeoJSON object ({"type":"Point","coordinates":[1,2]}), including Feature / FeatureCollection unwrapping, re-encoded as text;
- a WKT or EWKT string ("POINT(1 2)", "SRID=4326;POINT(1 2)").
The value is validated structurally so malformed input fails at compile time with a user-facing error rather than as a Postgres error mid-statement.
func (Value) SQL ¶
SQL renders the value expression given the placeholder for Param (e.g. "$3"). The result is a well-typed geometry/geography expression.
The placeholder is the ONLY value-derived part; the rest of the string is fixed by the column's type, preserving the compiled-SQL-is-a-pure-function- of-query-shape invariant.