use geopackage::{BoundingBox, GeoPackage, Value};
fn main() -> Result<(), Box<dyn std::error::Error>> {
let args: Vec<String> = std::env::args().skip(1).collect();
let [path, layer_name, min_x, min_y, max_x, max_y] = args.as_slice() else {
eprintln!("usage: bbox_query <file.gpkg> <layer> <min_x> <min_y> <max_x> <max_y>");
std::process::exit(2);
};
let gpkg = GeoPackage::open_read_only(path)?;
let layer = gpkg.layer(layer_name)?;
let bbox = BoundingBox::new(
min_x.parse()?,
min_y.parse()?,
max_x.parse()?,
max_y.parse()?,
);
let indexed = layer.has_spatial_index()?;
println!(
"querying {layer_name} via {}",
if indexed { "RTree index" } else { "full scan" }
);
let matches = layer.features_in(bbox)?;
println!("{} features in bbox", matches.len());
for feature in matches.into_iter().take(10) {
let feature = feature?;
let kind = match feature.geometry()? {
Some(geometry) => format!("{:?}", geometry.geometry_type()),
None => "NULL".to_owned(),
};
let pk = layer.primary_key_column().unwrap_or("fid");
let attributes: Vec<String> = feature
.iter()
.filter(|(name, value)| *name != pk && !matches!(value, Value::Null))
.map(|(name, value)| format!("{name}={value:?}"))
.collect();
println!(" fid {} {kind} {}", feature.fid(), attributes.join(" "));
}
let with_geometry = layer.select("geom IS NOT NULL", &[])?;
println!("{} features have a geometry", with_geometry.len());
Ok(())
}