diff --git a/Cargo.toml b/Cargo.toml index d6ddd226..015edf81 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -98,3 +98,4 @@ webpki-roots = "0.26.8" [patch.crates-io] duckdb = { git = "https://github.com/duckdb/duckdb-rs", rev = "5eeb1f01c278790ce1e2d24045f0096e9e2528e4" } libduckdb-sys = { git = "https://github.com/duckdb/duckdb-rs", rev = "5eeb1f01c278790ce1e2d24045f0096e9e2528e4" } +geoarrow = { git = "https://github.com/geoarrow/geoarrow-rs/", rev = "2cd0d623e4b9f1ac3bc5ff6563ccce689a47c641" } diff --git a/crates/core/src/geoarrow/mod.rs b/crates/core/src/geoarrow/mod.rs index 021b749b..0e3b844e 100644 --- a/crates/core/src/geoarrow/mod.rs +++ b/crates/core/src/geoarrow/mod.rs @@ -29,6 +29,12 @@ const DATETIME_COLUMNS: [&str; 8] = [ "unpublished", ]; +/// The stac-geoparquet version metadata key. +pub const VERSION_KEY: &str = "stac:geoparquet_version"; + +/// The stac-geoparquet version. +pub const VERSION: &str = "1.0.0"; + /// Converts an [ItemCollection] to a [Table]. /// /// Any invalid attributes in the items (e.g. top-level attributes that conflict @@ -103,7 +109,8 @@ pub fn to_table(item_collection: impl Into) -> Result { schema_builder.push(field.clone()); } } - let metadata = schema.metadata; + let mut metadata = schema.metadata; + let _ = metadata.insert(VERSION_KEY.to_string(), VERSION.into()); let schema = Arc::new(schema_builder.finish().with_metadata(metadata)); let mut decoder = ReaderBuilder::new(schema.clone()).build_decoder()?; decoder.serialize(&values)?; @@ -138,11 +145,18 @@ pub fn to_table(item_collection: impl Into) -> Result
{ /// # } /// ``` pub fn from_table(table: Table) -> Result { - json::from_table(table)? + let version = table.schema().metadata.get(VERSION_KEY).cloned(); + let mut item_collection = json::from_table(table)? .into_iter() .map(|item| serde_json::from_value(Value::Object(item)).map_err(Error::from)) .collect::>>() - .map(ItemCollection::from) + .map(ItemCollection::from)?; + if let Some(version) = version { + let _ = item_collection + .additional_fields + .insert(VERSION_KEY.to_string(), version.into()); + } + Ok(item_collection) } /// Converts a geometry column to geoarrow native type. @@ -217,7 +231,8 @@ mod tests { #[test] fn to_table() { let item: Item = crate::read("examples/simple-item.json").unwrap(); - let _ = super::to_table(vec![item]).unwrap(); + let table = super::to_table(vec![item]).unwrap(); + assert_eq!(table.schema().metadata["stac:geoparquet_version"], "1.0.0"); } #[test] diff --git a/crates/core/src/geoparquet/feature.rs b/crates/core/src/geoparquet/feature.rs index a9d3124d..87fd1728 100644 --- a/crates/core/src/geoparquet/feature.rs +++ b/crates/core/src/geoparquet/feature.rs @@ -1,10 +1,12 @@ use super::{FromGeoparquet, IntoGeoparquet}; +use crate::geoarrow::{VERSION, VERSION_KEY}; use crate::{Error, Item, ItemCollection, Result, Value}; use bytes::Bytes; use geoarrow::io::parquet::{GeoParquetRecordBatchReaderBuilder, GeoParquetWriterOptions}; use parquet::{ basic::Compression, file::{properties::WriterProperties, reader::ChunkReader}, + format::KeyValue, }; use std::{fs::File, io::Write, path::Path}; @@ -61,9 +63,12 @@ where /// use stac::Item; /// use parquet::basic::Compression; /// +/// # #[cfg(feature = "geoparquet-compression")] +/// # { /// let item: Item = stac::read("examples/simple-item.json").unwrap(); /// let mut cursor = Cursor::new(Vec::new()); /// stac::geoparquet::into_writer_with_compression(&mut cursor, vec![item], Compression::SNAPPY).unwrap(); +/// # } /// ``` pub fn into_writer_with_compression( writer: W, @@ -76,6 +81,10 @@ where let mut options = GeoParquetWriterOptions::default(); let writer_properties = WriterProperties::builder() .set_compression(compression) + .set_key_value_metadata(Some(vec![KeyValue { + key: VERSION_KEY.to_string(), + value: Some(VERSION.to_string()), + }])) .build(); options.writer_properties = Some(writer_properties); into_writer_with_options(writer, item_collection, &options) @@ -213,6 +222,10 @@ mod tests { let bytes = Bytes::from(cursor.into_inner()); let item_collection = super::from_reader(bytes).unwrap(); assert_eq!(item_collection.items[0], item); + assert_eq!( + item_collection.additional_fields["stac:geoparquet_version"], + "1.0.0" + ) } #[test]