Skip to content

Commit

Permalink
feat: add stac-types and stac-derive (#507)
Browse files Browse the repository at this point in the history
* refactor: add stac-types and stac-derive

* fix: add fields

* fix: broken docs links
  • Loading branch information
gadomski authored Oct 31, 2024
1 parent fb9ff3f commit b0e591c
Show file tree
Hide file tree
Showing 33 changed files with 249 additions and 262 deletions.
8 changes: 7 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,21 @@ members = [
"crates/api",
"crates/cli",
"crates/core",
"crates/derive",
"crates/duckdb",
"crates/extensions",
"crates/pgstac",
"python",
"crates/server",
"crates/types",
"python",
]
default-members = [
"crates/api",
"crates/cli",
"crates/core",
"crates/derive",
"crates/extensions",
"crates/types",
]

[workspace.package]
Expand Down Expand Up @@ -70,8 +74,10 @@ serde_json = "1.0"
serde_urlencoded = "0.7.1"
stac = { version = "0.10.2", path = "crates/core" }
stac-api = { version = "0.6.1", path = "crates/api" }
stac-derive = { version = "0.1.0", path = "crates/derive" }
stac-duckdb = { version = "0.0.2", path = "crates/duckdb" }
stac-server = { version = "0.3.1", path = "crates/server" }
stac-types = { version = "0.1.0", path = "crates/types" }
syn = "2.0"
tempfile = "3.13"
thiserror = "1.0"
Expand Down
2 changes: 2 additions & 0 deletions crates/api/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@ serde.workspace = true
serde_json.workspace = true
serde_urlencoded.workspace = true
stac.workspace = true
stac-derive.workspace = true
stac-types.workspace = true
thiserror.workspace = true
tracing.workspace = true
tokio = { workspace = true, optional = true }
Expand Down
27 changes: 3 additions & 24 deletions crates/api/src/collections.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
use serde::{Deserialize, Serialize};
use serde_json::{Map, Value};
use stac::{Collection, Href, Link, Links};
use stac::{Collection, Link};
use stac_derive::{Href, Links};

/// Object containing an array of collections and an array of links.
#[derive(Debug, Serialize, Deserialize)]
#[derive(Debug, Serialize, Deserialize, Href, Links)]
pub struct Collections {
/// The [Collection] objects in the [stac::Catalog].
pub collections: Vec<Collection>,
Expand All @@ -29,25 +30,3 @@ impl From<Vec<Collection>> for Collections {
}
}
}

impl Href for Collections {
fn href(&self) -> Option<&str> {
self.href.as_deref()
}
fn set_href(&mut self, href: impl ToString) {
self.href = Some(href.to_string());
}
fn clear_href(&mut self) {
self.href = None;
}
}

impl Links for Collections {
fn links(&self) -> &[Link] {
&self.links
}

fn links_mut(&mut self) -> &mut Vec<Link> {
&mut self.links
}
}
26 changes: 3 additions & 23 deletions crates/api/src/item_collection.rs
Original file line number Diff line number Diff line change
@@ -1,15 +1,16 @@
use crate::{Item, Result};
use serde::{Deserialize, Serialize};
use serde_json::{Map, Value};
use stac::{Href, Link, Links};
use stac::Link;
use stac_derive::{Href, Links};

/// The return value of the `/items` and `/search` endpoints.
///
/// This might be a [stac::ItemCollection], but if the [fields
/// extension](https://github.com/stac-api-extensions/fields) is used, it might
/// not be. Defined by the [itemcollection
/// fragment](https://github.com/radiantearth/stac-api-spec/blob/main/fragments/itemcollection/README.md).
#[derive(Debug, Serialize, Deserialize, Default)]
#[derive(Debug, Serialize, Deserialize, Default, Links, Href)]
#[serde(tag = "type", rename = "FeatureCollection")]
pub struct ItemCollection {
/// A possibly-empty array of Item objects.
Expand Down Expand Up @@ -118,27 +119,6 @@ impl ItemCollection {
}
}

impl Href for ItemCollection {
fn set_href(&mut self, href: impl ToString) {
self.href = Some(href.to_string());
}
fn clear_href(&mut self) {
self.href = None;
}
fn href(&self) -> Option<&str> {
self.href.as_deref()
}
}

impl Links for ItemCollection {
fn links(&self) -> &[Link] {
&self.links
}
fn links_mut(&mut self) -> &mut Vec<Link> {
&mut self.links
}
}

impl From<Vec<Item>> for ItemCollection {
fn from(items: Vec<Item>) -> Self {
ItemCollection {
Expand Down
1 change: 1 addition & 0 deletions crates/cli/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ stac = { workspace = true, features = [
stac-api = { workspace = true, features = ["client"] }
stac-duckdb = { workspace = true, optional = true }
stac-server = { workspace = true, features = ["axum"] }
stac-types.workspace = true
thiserror.workspace = true
tokio = { workspace = true, features = [
"macros",
Expand Down
4 changes: 4 additions & 0 deletions crates/cli/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,10 @@ pub enum Error {
#[error(transparent)]
StacServer(#[from] stac_server::Error),

/// [stac_types::Error]
#[error(transparent)]
StacTypes(#[from] stac_types::Error),

/// [tokio::sync::mpsc::error::SendError]
#[error(transparent)]
TokioSend(#[from] tokio::sync::mpsc::error::SendError<Value>),
Expand Down
3 changes: 2 additions & 1 deletion crates/core/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -61,12 +61,13 @@ geoarrow = { workspace = true, optional = true }
geojson.workspace = true
jsonschema = { workspace = true, optional = true }
log.workspace = true
mime.workspace = true
object_store = { workspace = true, optional = true }
parquet = { workspace = true, optional = true }
reqwest = { workspace = true, features = ["json", "blocking"], optional = true }
serde = { workspace = true, features = ["derive"] }
serde_json = { workspace = true, features = ["preserve_order"] }
stac-derive.workspace = true
stac-types.workspace = true
thiserror.workspace = true
tokio = { workspace = true, optional = true }
tracing.workspace = true
Expand Down
14 changes: 3 additions & 11 deletions crates/core/src/asset.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
use crate::{Band, DataType, Fields, Statistics};
use crate::{Band, DataType, Statistics};
use serde::{Deserialize, Serialize};
use serde_json::{Map, Value};
use stac_derive::Fields;
use std::collections::HashMap;

/// An Asset is an object that contains a URI to data associated with the [Item](crate::Item) that can be downloaded or streamed.
#[derive(Debug, Serialize, Deserialize, PartialEq, Clone)]
#[derive(Debug, Serialize, Deserialize, PartialEq, Clone, Fields)]
pub struct Asset {
/// URI to the asset object.
///
Expand Down Expand Up @@ -159,15 +160,6 @@ impl Asset {
}
}

impl Fields for Asset {
fn fields(&self) -> &Map<String, Value> {
&self.additional_fields
}
fn fields_mut(&mut self) -> &mut Map<String, Value> {
&mut self.additional_fields
}
}

impl From<String> for Asset {
fn from(value: String) -> Self {
Asset::new(value)
Expand Down
39 changes: 3 additions & 36 deletions crates/core/src/catalog.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use crate::{Error, Fields, Href, Link, Links, Migrate, Result, Version, STAC_VERSION};
use crate::{Error, Link, Result, Version, STAC_VERSION};
use serde::{Deserialize, Serialize};
use serde_json::{Map, Value};
use stac_derive::{Fields, Href, Links, Migrate};

/// A STAC Catalog object represents a logical group of other `Catalog`,
/// [Collection](crate::Collection), and [Item](crate::Item) objects.
Expand All @@ -14,7 +15,7 @@ use serde_json::{Map, Value};
/// A `Catalog` object will typically be the entry point into a STAC catalog.
/// Their purpose is discovery: to be browsed by people or be crawled by clients
/// to build a searchable index.
#[derive(Debug, Serialize, Deserialize, PartialEq, Clone)]
#[derive(Debug, Serialize, Deserialize, PartialEq, Clone, Href, Migrate, Links, Fields)]
#[serde(tag = "type")]
pub struct Catalog {
/// The STAC version the `Catalog` implements.
Expand Down Expand Up @@ -78,29 +79,6 @@ impl Catalog {
}
}

impl Href for Catalog {
fn href(&self) -> Option<&str> {
self.href.as_deref()
}

fn set_href(&mut self, href: impl ToString) {
self.href = Some(href.to_string())
}

fn clear_href(&mut self) {
self.href = None;
}
}

impl Links for Catalog {
fn links(&self) -> &[Link] {
&self.links
}
fn links_mut(&mut self) -> &mut Vec<Link> {
&mut self.links
}
}

impl TryFrom<Catalog> for Map<String, Value> {
type Error = Error;
fn try_from(catalog: Catalog) -> Result<Self> {
Expand All @@ -119,17 +97,6 @@ impl TryFrom<Map<String, Value>> for Catalog {
}
}

impl Fields for Catalog {
fn fields(&self) -> &Map<String, Value> {
&self.additional_fields
}
fn fields_mut(&mut self) -> &mut Map<String, Value> {
&mut self.additional_fields
}
}

impl Migrate for Catalog {}

#[cfg(test)]
mod tests {
use super::Catalog;
Expand Down
39 changes: 4 additions & 35 deletions crates/core/src/collection.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
use crate::{
Asset, Assets, Bbox, Error, Fields, Href, Item, ItemAsset, Link, Links, Migrate, Result,
Version, STAC_VERSION,
Asset, Assets, Bbox, Error, Href, Item, ItemAsset, Link, Links, Migrate, Result, Version,
STAC_VERSION,
};
use chrono::{DateTime, Utc};
use serde::{Deserialize, Serialize};
use serde_json::{Map, Value};
use stac_derive::{Fields, Href, Links};
use std::collections::HashMap;

const DEFAULT_LICENSE: &str = "proprietary";
Expand All @@ -21,7 +22,7 @@ const DEFAULT_LICENSE: &str = "proprietary";
/// A STAC `Collection` is represented in JSON format. Any JSON object that
/// contains all the required fields is a valid STAC `Collection` and also a valid
/// STAC `Catalog`.
#[derive(Debug, Serialize, Deserialize, PartialEq, Clone)]
#[derive(Debug, Serialize, Deserialize, PartialEq, Clone, Href, Links, Fields)]
#[serde(tag = "type")]
pub struct Collection {
/// The STAC version the `Collection` implements.
Expand Down Expand Up @@ -288,29 +289,6 @@ impl Collection {
}
}

impl Href for Collection {
fn href(&self) -> Option<&str> {
self.href.as_deref()
}

fn set_href(&mut self, href: impl ToString) {
self.href = Some(href.to_string())
}

fn clear_href(&mut self) {
self.href = None;
}
}

impl Links for Collection {
fn links(&self) -> &[Link] {
&self.links
}
fn links_mut(&mut self) -> &mut Vec<Link> {
&mut self.links
}
}

impl Provider {
/// Creates a new provider with the given name.
///
Expand Down Expand Up @@ -386,15 +364,6 @@ impl Assets for Collection {
}
}

impl Fields for Collection {
fn fields(&self) -> &Map<String, Value> {
&self.additional_fields
}
fn fields_mut(&mut self) -> &mut Map<String, Value> {
&mut self.additional_fields
}
}

impl TryFrom<Collection> for Map<String, Value> {
type Error = Error;
fn try_from(collection: Collection) -> Result<Self> {
Expand Down
29 changes: 5 additions & 24 deletions crates/core/src/error.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
use crate::Version;
use thiserror::Error;

/// Error enum for crate-specific errors.
Expand Down Expand Up @@ -41,16 +40,6 @@ pub enum Error {
#[error("invalid attribute name: {0}")]
InvalidAttribute(String),

/// Returned when a STAC object has the wrong type field.
#[error("incorrect type: expected={expected}, actual={actual}")]
IncorrectType {
/// The actual type field on the object.
actual: String,

/// The expected value.
expected: String,
},

/// This vector is not a valid bounding box.
#[error("invalid bbox: {0:?}")]
InvalidBbox(Vec<f64>),
Expand All @@ -63,18 +52,10 @@ pub enum Error {
#[error("no \"{0}\" field in the JSON object")]
MissingField(&'static str),

/// There is not an href, when an href is required.
#[error("no href")]
NoHref,

/// There are no items, when items are required.
#[error("no items")]
NoItems,

/// This is not a JSON object.
#[error("json value is not an object")]
NotAnObject(serde_json::Value),

/// [object_store::Error]
#[error(transparent)]
#[cfg(feature = "object-store")]
Expand Down Expand Up @@ -103,6 +84,10 @@ pub enum Error {
#[error(transparent)]
SerdeJson(#[from] serde_json::Error),

/// [stac_types::Error]
#[error(transparent)]
StacTypes(#[from] stac_types::Error),

/// [tokio::task::JoinError]
#[error(transparent)]
#[cfg(feature = "validate")]
Expand All @@ -116,10 +101,6 @@ pub enum Error {
#[error("unknown \"type\": {0}")]
UnknownType(String),

/// Unsupported migration.
#[error("unsupported migration: {0} to {1}")]
UnsupportedMigration(Version, Version),

/// Unsupported file format.
#[error("unsupported format: {0}")]
UnsupportedFormat(String),
Expand All @@ -130,7 +111,7 @@ pub enum Error {

/// [url::ParseError]
#[error(transparent)]
Url(#[from] url::ParseError),
UrlParse(#[from] url::ParseError),

/// A list of validation errors.
#[error("{} validation error(s)", .0.len())]
Expand Down
Loading

0 comments on commit b0e591c

Please sign in to comment.