use nodedb_query::geo_functions::GEO_FUNCTIONS;
use crate::functions::registry::{FunctionCategory::Scalar, FunctionMeta};
use super::super::super::helpers::V0_1_0;
use super::arg_shape::{arg_types, return_type};
use super::triggers::search_trigger;
pub(in crate::functions::builtins::scalars) fn spatial_functions() -> Vec<FunctionMeta> {
let mut registrations = Vec::new();
for spec in GEO_FUNCTIONS {
let (min_args, max_args) = spec.args.arity();
let trigger = search_trigger(spec.canonical);
for name in spec.names() {
registrations.push(FunctionMeta {
name,
category: Scalar,
min_args,
max_args,
search_trigger: trigger,
return_type: return_type(spec.returns),
arg_types: arg_types(spec.args),
since: V0_1_0,
volatility: nodedb_types::Volatility::Immutable,
});
}
}
registrations
}
#[cfg(test)]
mod tests {
use super::*;
use crate::functions::registry::FunctionRegistry;
#[test]
fn every_catalog_spelling_is_registered() {
let registry = FunctionRegistry::new();
for spec in GEO_FUNCTIONS {
for name in spec.names() {
assert!(
registry.lookup(name).is_some(),
"'{name}' is in the geo catalog but not registered for planning"
);
}
}
}
#[test]
fn every_spelling_of_a_function_registers_identically() {
let registry = FunctionRegistry::new();
for spec in GEO_FUNCTIONS {
let Some(canonical) = registry.lookup(spec.canonical) else {
panic!("'{}' must be registered", spec.canonical);
};
for alias in spec.aliases {
let Some(other) = registry.lookup(alias) else {
panic!("'{alias}' must be registered");
};
assert_eq!(
(other.min_args, other.max_args),
(canonical.min_args, canonical.max_args),
"'{alias}' and '{}' disagree on arity",
spec.canonical
);
assert_eq!(
other.return_type, canonical.return_type,
"'{alias}' and '{}' disagree on return type",
spec.canonical
);
assert_eq!(
other.search_trigger, canonical.search_trigger,
"'{alias}' and '{}' disagree on search routing",
spec.canonical
);
}
}
}
#[test]
fn standard_accessor_names_are_registered() {
let registry = FunctionRegistry::new();
for name in [
"st_astext",
"st_asgeojson",
"st_x",
"st_y",
"st_geometrytype",
"st_npoints",
"st_isvalid",
"st_srid",
"st_area",
"st_centroid",
"st_length",
"st_perimeter",
] {
assert!(
registry.lookup(name).is_some(),
"'{name}' must be registered"
);
}
}
#[test]
fn constructors_are_registered_as_scalars() {
let registry = FunctionRegistry::new();
for name in [
"st_point",
"st_makepoint",
"st_geomfromtext",
"st_geomfromgeojson",
"st_geomfromwkb",
"st_makeline",
"st_makepolygon",
"st_makeenvelope",
] {
let Some(meta) = registry.lookup(name) else {
panic!("'{name}' must be registered");
};
assert_eq!(meta.category, Scalar);
assert_eq!(
meta.return_type,
Some(nodedb_types::columnar::ColumnType::Geometry),
"'{name}' must be typed as returning a geometry"
);
}
}
}