#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Kind {
Blob,
Text,
Int,
I64,
Real,
Bool,
OptReal,
OptI64,
OptBlob,
TextOrInt,
}
pub struct FnEntry {
pub sql_name: &'static str,
pub export: &'static str,
pub args: &'static [Kind],
pub ret: Kind,
pub feature: Option<&'static str>,
}
macro_rules! entry {
($sql:literal, $export:literal, [$($arg:ident),*], $ret:ident, $feature:expr) => {
FnEntry {
sql_name: $sql,
export: $export,
args: &[$(Kind::$arg),*],
ret: Kind::$ret,
feature: $feature,
}
};
}
pub const FUNCTIONS: &[FnEntry] = &[
entry!("ST_GeomFromText", "stGeomFromText", [Text], Blob, None),
entry!(
"ST_GeomFromText",
"stGeomFromTextSrid",
[Text, Int],
Blob,
None
),
entry!("ST_GeomFromWKB", "stGeomFromWkb", [Blob], Blob, None),
entry!(
"ST_GeomFromWKB",
"stGeomFromWkbSrid",
[Blob, Int],
Blob,
None
),
entry!("ST_GeomFromGPB", "stGeomFromGpb", [Blob], Blob, None),
entry!("ST_AsText", "stAsText", [Blob], Text, None),
entry!("ST_AsBinary", "stAsBinary", [Blob], Blob, None),
entry!("ST_AsGPB", "stAsGpb", [Blob], Blob, None),
entry!("ST_SetSRID", "stSetSrid", [Blob, Int], Blob, None),
entry!("ST_SRID", "stSrid", [Blob], Int, None),
entry!("ST_Intersects", "stIntersects", [Blob, Blob], Bool, None),
entry!("ST_Contains", "stContains", [Blob, Blob], Bool, None),
entry!("ST_Within", "stWithin", [Blob, Blob], Bool, None),
entry!("ST_Disjoint", "stDisjoint", [Blob, Blob], Bool, None),
entry!("ST_Touches", "stTouches", [Blob, Blob], Bool, None),
entry!("ST_Crosses", "stCrosses", [Blob, Blob], Bool, None),
entry!("ST_Overlaps", "stOverlaps", [Blob, Blob], Bool, None),
entry!("ST_Equals", "stEquals", [Blob, Blob], Bool, None),
entry!("ST_Covers", "stCovers", [Blob, Blob], Bool, None),
entry!("ST_CoveredBy", "stCoveredBy", [Blob, Blob], Bool, None),
entry!("ST_Relate", "stRelate", [Blob, Blob], Text, None),
entry!(
"ST_Relate",
"stRelatePattern",
[Blob, Blob, Text],
Bool,
None
),
entry!("ST_Distance", "stDistance", [Blob, Blob], OptReal, None),
entry!("ST_DWithin", "stDwithin", [Blob, Blob, Real], Bool, None),
entry!("ST_MinX", "stMinX", [Blob], OptReal, None),
entry!("ST_MaxX", "stMaxX", [Blob], OptReal, None),
entry!("ST_MinY", "stMinY", [Blob], OptReal, None),
entry!("ST_MaxY", "stMaxY", [Blob], OptReal, None),
entry!("ST_IsEmpty", "stIsEmpty", [Blob], Bool, None),
entry!(
"ST_Transform",
"stTransform",
[Blob, Int],
Blob,
Some("transform")
),
entry!("ST_AsGeoJSON", "stAsGeojson", [Blob], Text, Some("geojson")),
entry!(
"ST_AsGeoJSON",
"stAsGeojsonDigits",
[Blob, Int],
Text,
Some("geojson")
),
entry!(
"ST_GeomFromGeoJSON",
"stGeomFromGeojson",
[Text],
Blob,
Some("geojson")
),
entry!(
"h3_latlng_to_cell",
"h3LatlngToCell",
[Blob, Int],
I64,
Some("h3")
),
entry!(
"h3_cell_to_parent",
"h3CellToParent",
[I64, Int],
I64,
Some("h3")
),
entry!(
"h3_cell_to_string",
"h3CellToString",
[I64],
Text,
Some("h3")
),
entry!(
"h3_string_to_cell",
"h3StringToCell",
[Text],
I64,
Some("h3")
),
entry!("ST_MakePoint", "stMakePoint", [Real, Real], Blob, None),
entry!("ST_Point", "stPoint", [Real, Real], Blob, None),
entry!("ST_Point", "stPointSrid", [Real, Real, Int], Blob, None),
entry!(
"ST_MakeEnvelope",
"stMakeEnvelope",
[Real, Real, Real, Real],
Blob,
None
),
entry!(
"ST_MakeEnvelope",
"stMakeEnvelopeSrid",
[Real, Real, Real, Real, Int],
Blob,
None
),
entry!(
"GPKG_IsAssignable",
"gpkgIsAssignable",
[Text, Text],
Bool,
None
),
entry!(
"ST_ClosestPoint",
"stClosestPoint",
[Blob, Blob],
OptBlob,
None
),
entry!(
"ST_LineInterpolatePoint",
"stLineInterpolatePoint",
[Blob, Real],
Blob,
None
),
entry!(
"ST_LineLocatePoint",
"stLineLocatePoint",
[Blob, Blob],
Real,
None
),
entry!(
"ST_HausdorffDistance",
"stHausdorffDistance",
[Blob, Blob],
Real,
None
),
entry!(
"ST_FrechetDistance",
"stFrechetDistance",
[Blob, Blob],
Real,
None
),
entry!("ST_Azimuth", "stAzimuth", [Blob, Blob], OptReal, None),
entry!(
"ST_Intersection",
"stIntersection",
[Blob, Blob],
Blob,
Some("overlay")
),
entry!(
"ST_Difference",
"stDifference",
[Blob, Blob],
Blob,
Some("overlay")
),
entry!(
"ST_SymDifference",
"stSymDifference",
[Blob, Blob],
Blob,
Some("overlay")
),
entry!("ST_Union", "stUnion", [Blob, Blob], Blob, Some("overlay")),
entry!("ST_Buffer", "stBuffer", [Blob, Real], Blob, Some("overlay")),
entry!("ST_MakeValid", "stMakeValid", [Blob], Blob, Some("overlay")),
entry!(
"ST_Buffer",
"stBufferOpts",
[Blob, Real, TextOrInt],
Blob,
Some("overlay")
),
entry!(
"ST_AsMVTGeom",
"stAsMvtGeom",
[Blob, Blob],
OptBlob,
Some("mvt")
),
entry!(
"ST_AsMVTGeom",
"stAsMvtGeomExtent",
[Blob, Blob, Int],
OptBlob,
Some("mvt")
),
entry!(
"ST_AsMVTGeom",
"stAsMvtGeomBuffer",
[Blob, Blob, Int, Int],
OptBlob,
Some("mvt")
),
entry!(
"ST_AsMVTGeom",
"stAsMvtGeomClip",
[Blob, Blob, Int, Int, Int],
OptBlob,
Some("mvt")
),
entry!("ST_ConvexHull", "stConvexHull", [Blob], Blob, None),
entry!("ST_PointOnSurface", "stPointOnSurface", [Blob], Blob, None),
entry!("ST_SimplifyVW", "stSimplifyVw", [Blob, Real], Blob, None),
entry!(
"ST_ChaikinSmoothing",
"stChaikinSmoothing",
[Blob],
Blob,
None
),
entry!(
"ST_ChaikinSmoothing",
"stChaikinSmoothingN",
[Blob, Int],
Blob,
None
),
entry!(
"ST_RemoveRepeatedPoints",
"stRemoveRepeatedPoints",
[Blob],
Blob,
None
),
entry!(
"ST_OrientedEnvelope",
"stOrientedEnvelope",
[Blob],
Blob,
None
),
entry!("ST_Rotate", "stRotate", [Blob, Real], Blob, None),
entry!(
"ST_Rotate",
"stRotateXY",
[Blob, Real, Real, Real],
Blob,
None
),
entry!(
"ST_Translate",
"stTranslate",
[Blob, Real, Real],
Blob,
None
),
entry!("ST_Scale", "stScale", [Blob, Real, Real], Blob, None),
entry!("ST_Area", "stArea", [Blob], Real, None),
entry!("ST_NPoints", "stNPoints", [Blob], Int, None),
entry!("ST_Perimeter", "stPerimeter", [Blob], Real, None),
entry!("ST_GeometryType", "stGeometryType", [Blob], Text, None),
entry!("ST_NumGeometries", "stNumGeometries", [Blob], Int, None),
entry!("ST_GeometryN", "stGeometryN", [Blob, Int], OptBlob, None),
entry!("ST_StartPoint", "stStartPoint", [Blob], OptBlob, None),
entry!("ST_EndPoint", "stEndPoint", [Blob], OptBlob, None),
entry!("ST_PointN", "stPointN", [Blob, Int], OptBlob, None),
entry!("ST_Reverse", "stReverse", [Blob], Blob, None),
entry!("ST_Length", "stLength", [Blob], Real, None),
entry!("ST_Centroid", "stCentroid", [Blob], Blob, None),
entry!("ST_Envelope", "stEnvelope", [Blob], Blob, None),
entry!("ST_X", "stX", [Blob], OptReal, None),
entry!("ST_Y", "stY", [Blob], OptReal, None),
entry!("ST_NumPoints", "stNumPoints", [Blob], OptI64, None),
entry!("ST_IsValid", "stIsValid", [Blob], Bool, None),
entry!("ST_Simplify", "stSimplify", [Blob, Real], Blob, None),
];
pub struct AggEntry {
pub sql_name: &'static str,
pub ctor_export: &'static str,
pub args: &'static [Kind],
pub feature: Option<&'static str>,
}
pub const AGGREGATES: &[AggEntry] = &[
AggEntry {
sql_name: "ST_Union",
ctor_export: "UnionAgg",
args: &[Kind::Blob],
feature: Some("overlay"),
},
AggEntry {
sql_name: "ST_AsMVT",
ctor_export: "MvtAgg",
args: &[Kind::Blob],
feature: Some("mvt"),
},
AggEntry {
sql_name: "ST_AsMVT",
ctor_export: "MvtAgg",
args: &[Kind::Blob, Kind::Text],
feature: Some("mvt"),
},
AggEntry {
sql_name: "ST_AsMVT",
ctor_export: "MvtAgg",
args: &[Kind::Blob, Kind::Text, Kind::Int],
feature: Some("mvt"),
},
AggEntry {
sql_name: "ST_AsMVT",
ctor_export: "MvtAgg",
args: &[Kind::Blob, Kind::Text, Kind::Int, Kind::Text],
feature: Some("mvt"),
},
];
pub fn active_aggregates() -> impl Iterator<Item = &'static AggEntry> {
AGGREGATES.iter().filter(|e| match e.feature {
None => true,
Some("transform") => cfg!(feature = "transform"),
Some("h3") => cfg!(feature = "h3"),
Some("geojson") => cfg!(feature = "geojson"),
Some("overlay") => cfg!(feature = "overlay"),
Some("mvt") => cfg!(feature = "mvt"),
Some(_) => false,
})
}
pub const STUB_ARITIES: &[(&str, &[i32])] = &[
("ST_MakeValid", &[1]),
("ST_Intersection", &[2]),
("ST_Difference", &[2]),
("ST_SymDifference", &[2]),
("ST_Union", &[1, 2]),
("ST_Buffer", &[2, 3]),
("ST_AsMVTGeom", &[2, 3, 4, 5]),
("ST_AsMVT", &[1, 2, 3, 4]),
("ST_Transform", &[2]),
("ST_AsGeoJSON", &[1, 2]),
("ST_GeomFromGeoJSON", &[1]),
("h3_latlng_to_cell", &[2]),
("h3_cell_to_parent", &[2]),
("h3_cell_to_string", &[1]),
("h3_string_to_cell", &[1]),
];
pub const DEFAULT_STUB_ARITIES: &[i32] = &[1, 2];
pub fn stub_arities(name: &str) -> &'static [i32] {
STUB_ARITIES
.iter()
.find(|(n, _)| *n == name)
.map(|(_, a)| *a)
.unwrap_or(DEFAULT_STUB_ARITIES)
}
pub fn active_functions() -> impl Iterator<Item = &'static FnEntry> {
FUNCTIONS.iter().filter(|e| match e.feature {
None => true,
Some("transform") => cfg!(feature = "transform"),
Some("h3") => cfg!(feature = "h3"),
Some("geojson") => cfg!(feature = "geojson"),
Some("overlay") => cfg!(feature = "overlay"),
Some("mvt") => cfg!(feature = "mvt"),
Some(_) => false,
})
}
pub fn active_stubs() -> Vec<&'static super::stubs::Stub> {
let mut stubs: Vec<&'static super::stubs::Stub> = super::stubs::STUBS.iter().collect();
if !cfg!(feature = "transform") {
stubs.extend(super::stubs::TRANSFORM_OFF.iter());
}
if !cfg!(feature = "h3") {
stubs.extend(super::stubs::H3_OFF.iter());
}
if !cfg!(feature = "geojson") {
stubs.extend(super::stubs::GEOJSON_OFF.iter());
}
if !cfg!(feature = "overlay") {
stubs.extend(super::stubs::OVERLAY_OFF.iter());
}
if !cfg!(feature = "mvt") {
stubs.extend(super::stubs::MVT_OFF.iter());
}
stubs
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn export_names_are_unique() {
let mut exports: Vec<_> = FUNCTIONS.iter().map(|e| e.export).collect();
exports.sort_unstable();
let len = exports.len();
exports.dedup();
assert_eq!(exports.len(), len);
}
#[test]
fn sql_name_arity_pairs_are_unique() {
let mut pairs: Vec<_> = FUNCTIONS
.iter()
.map(|e| (e.sql_name.to_ascii_lowercase(), e.args.len()))
.collect();
pairs.sort();
let len = pairs.len();
pairs.dedup();
assert_eq!(pairs.len(), len);
}
#[test]
fn i64_functions_are_exactly_the_h3_family() {
let uses_i64: Vec<_> = FUNCTIONS
.iter()
.filter(|e| e.args.contains(&Kind::I64) || matches!(e.ret, Kind::I64))
.map(|e| e.sql_name)
.collect();
assert_eq!(
uses_i64,
[
"h3_latlng_to_cell",
"h3_cell_to_parent",
"h3_cell_to_string",
"h3_string_to_cell"
]
);
}
}