Skip to content

Commit

Permalink
feat: add tree structure (#509)
Browse files Browse the repository at this point in the history
That was a journey, but we got there.
  • Loading branch information
gadomski authored Nov 1, 2024
1 parent 8f1a6a7 commit 5ff0a4e
Show file tree
Hide file tree
Showing 26 changed files with 754 additions and 383 deletions.
3 changes: 2 additions & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ jobs:
name: Test stac
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os:
- ubuntu-latest
Expand All @@ -28,7 +29,7 @@ jobs:
- uses: actions/checkout@v4
- uses: Swatinem/rust-cache@v2
- name: Test
run: cargo test -p stac --all-features
run: cargo test -p stac -p stac-types --all-features
check-features-core:
name: Check stac features
runs-on: ubuntu-latest
Expand Down
1 change: 1 addition & 0 deletions crates/api/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ client = [
"dep:http",
"dep:reqwest",
"dep:tokio",
"stac-types/reqwest",
]
geo = ["dep:geo", "stac/geo"]

Expand Down
20 changes: 11 additions & 9 deletions crates/api/src/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use http::header::{HeaderName, USER_AGENT};
use reqwest::{header::HeaderMap, ClientBuilder, IntoUrl, Method, StatusCode};
use serde::{de::DeserializeOwned, Serialize};
use serde_json::{Map, Value};
use stac::{Collection, Href, Link, Links};
use stac::{Collection, Link, Links, SelfHref};
use std::pin::Pin;
use tokio::{
runtime::{Builder, Runtime},
Expand Down Expand Up @@ -170,13 +170,13 @@ impl Client {

async fn get<V>(&self, url: impl IntoUrl) -> Result<V>
where
V: DeserializeOwned + Href,
V: DeserializeOwned + SelfHref,
{
let url = url.into_url()?;
let mut value = self
.request::<(), V>(Method::GET, url.clone(), None, None)
.await?;
value.set_href(url);
*value.self_href_mut() = Some(url.into());
Ok(value)
}

Expand Down Expand Up @@ -243,7 +243,7 @@ impl Client {
} else {
None
};
self.request::<Map<String, Value>, R>(method, link.href, &link.body, headers)
self.request::<Map<String, Value>, R>(method, link.href.as_str(), &link.body, headers)
.await
}
}
Expand Down Expand Up @@ -404,7 +404,7 @@ mod tests {
let mut page_1_body: ItemCollection =
serde_json::from_str(include_str!("../mocks/search-page-1.json")).unwrap();
let mut next_link = page_1_body.link("next").unwrap().clone();
next_link.href = format!("{}/search", server.url());
next_link.href = format!("{}/search", server.url()).into();
page_1_body.set_link(next_link);
let page_1 = server
.mock("POST", "/search")
Expand Down Expand Up @@ -454,13 +454,14 @@ mod tests {
let mut page_1_body: ItemCollection =
serde_json::from_str(include_str!("../mocks/items-page-1.json")).unwrap();
let mut next_link = page_1_body.link("next").unwrap().clone();
let url: Url = next_link.href.parse().unwrap();
let url: Url = next_link.href.as_str().parse().unwrap();
let query = url.query().unwrap();
next_link.href = format!(
"{}/collections/sentinel-2-l2a/items?{}",
server.url(),
query
);
)
.into();
page_1_body.set_link(next_link);
let page_1 = server
.mock("GET", "/collections/sentinel-2-l2a/items?limit=1")
Expand Down Expand Up @@ -500,13 +501,14 @@ mod tests {
let mut page_body: ItemCollection =
serde_json::from_str(include_str!("../mocks/items-page-1.json")).unwrap();
let mut next_link = page_body.link("next").unwrap().clone();
let url: Url = next_link.href.parse().unwrap();
let url: Url = next_link.href.as_str().parse().unwrap();
let query = url.query().unwrap();
next_link.href = format!(
"{}/collections/sentinel-2-l2a/items?{}",
server.url(),
query
);
)
.into();
page_body.set_link(next_link);
page_body.items = vec![];
let page = server
Expand Down
10 changes: 5 additions & 5 deletions crates/api/src/collections.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
use serde::{Deserialize, Serialize};
use serde_json::{Map, Value};
use stac::{Collection, Link};
use stac_derive::{Href, Links};
use stac::{Collection, Href, Link};
use stac_derive::{Links, SelfHref};

/// Object containing an array of collections and an array of links.
#[derive(Debug, Serialize, Deserialize, Href, Links)]
#[derive(Debug, Serialize, Deserialize, SelfHref, Links)]
pub struct Collections {
/// The [Collection] objects in the [stac::Catalog].
pub collections: Vec<Collection>,
Expand All @@ -17,7 +17,7 @@ pub struct Collections {
pub additional_fields: Map<String, Value>,

#[serde(skip)]
href: Option<String>,
self_href: Option<Href>,
}

impl From<Vec<Collection>> for Collections {
Expand All @@ -26,7 +26,7 @@ impl From<Vec<Collection>> for Collections {
collections,
links: Vec::new(),
additional_fields: Map::new(),
href: None,
self_href: None,
}
}
}
10 changes: 5 additions & 5 deletions crates/api/src/item_collection.rs
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
use crate::{Item, Result};
use serde::{Deserialize, Serialize};
use serde_json::{Map, Value};
use stac::Link;
use stac_derive::{Href, Links};
use stac::{Href, Link};
use stac_derive::{Links, SelfHref};

/// 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, Links, Href)]
#[derive(Debug, Serialize, Deserialize, Default, Links, SelfHref)]
#[serde(tag = "type", rename = "FeatureCollection")]
pub struct ItemCollection {
/// A possibly-empty array of Item objects.
Expand Down Expand Up @@ -67,7 +67,7 @@ pub struct ItemCollection {
pub last: Option<Map<String, Value>>,

#[serde(skip)]
href: Option<String>,
self_href: Option<Href>,
}

/// The search-related metadata for the [ItemCollection].
Expand Down Expand Up @@ -114,7 +114,7 @@ impl ItemCollection {
prev: None,
first: None,
last: None,
href: None,
self_href: None,
})
}
}
Expand Down
2 changes: 1 addition & 1 deletion crates/cli/src/subcommand/serve.rs
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ impl Run for Args {
}
Value::Collection(mut collection) => {
if self.load_collection_items {
collection.make_relative_links_absolute()?;
collection.make_links_absolute()?;
for link in collection.iter_item_links() {
let href = link.href.to_string();
let input = input.with_href(href);
Expand Down
5 changes: 5 additions & 0 deletions crates/core/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,11 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
### Added

- `version` ([#476](https://github.com/stac-utils/stac-rs/pull/476))
- `Node` and friends ([#504](https://github.com/stac-utils/stac-rs/pull/504))

### Changed

- `make_links_absolute` instead of `make_relative_links_absolute`, `make_links_relative` instead of `make_absolute_links_relative` ([#504](https://github.com/stac-utils/stac-rs/pull/504))
- Permissive deserialization ([#505](https://github.com/stac-utils/stac-rs/pull/505))

### Removed
Expand Down
2 changes: 1 addition & 1 deletion crates/core/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ object-store-all = [
"object-store-gcp",
"object-store-http",
]
reqwest = ["dep:reqwest"]
reqwest = ["dep:reqwest", "stac-types/reqwest"]
reqwest-rustls = ["reqwest/rustls-tls"]
validate = ["dep:jsonschema", "dep:reqwest", "dep:tokio", "dep:fluent-uri"]
validate-blocking = ["validate", "tokio/rt"]
Expand Down
10 changes: 5 additions & 5 deletions crates/core/src/catalog.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use crate::{Error, Link, Result, Version, STAC_VERSION};
use crate::{Error, Href, Link, Result, Version, STAC_VERSION};
use serde::{Deserialize, Serialize};
use serde_json::{Map, Value};
use stac_derive::{Fields, Href, Links, Migrate};
use stac_derive::{Fields, Links, Migrate, SelfHref};

/// A STAC Catalog object represents a logical group of other `Catalog`,
/// [Collection](crate::Collection), and [Item](crate::Item) objects.
Expand All @@ -15,7 +15,7 @@ use stac_derive::{Fields, Href, Links, Migrate};
/// 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, Href, Migrate, Links, Fields)]
#[derive(Debug, Serialize, Deserialize, PartialEq, Clone, SelfHref, Migrate, Links, Fields)]
#[serde(tag = "type")]
pub struct Catalog {
/// The STAC version the `Catalog` implements.
Expand Down Expand Up @@ -51,7 +51,7 @@ pub struct Catalog {
pub additional_fields: Map<String, Value>,

#[serde(skip)]
href: Option<String>,
self_href: Option<Href>,
}

impl Catalog {
Expand All @@ -74,7 +74,7 @@ impl Catalog {
description: description.to_string(),
links: Vec::new(),
additional_fields: Map::new(),
href: None,
self_href: None,
}
}
}
Expand Down
21 changes: 9 additions & 12 deletions crates/core/src/collection.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
use crate::{
Asset, Assets, Bbox, Error, Href, Item, ItemAsset, Link, Links, Migrate, Result, Version,
STAC_VERSION,
Asset, Assets, Bbox, Error, Href, Item, ItemAsset, Link, Links, Migrate, Result, SelfHref,
Version, STAC_VERSION,
};
use chrono::{DateTime, Utc};
use serde::{Deserialize, Serialize};
use serde_json::{Map, Value};
use stac_derive::{Fields, Href, Links};
use stac_derive::{Fields, Links, SelfHref};
use std::collections::HashMap;

const DEFAULT_LICENSE: &str = "proprietary";
Expand All @@ -22,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, Href, Links, Fields)]
#[derive(Debug, Serialize, Deserialize, PartialEq, Clone, SelfHref, Links, Fields)]
#[serde(tag = "type")]
pub struct Collection {
/// The STAC version the `Collection` implements.
Expand Down Expand Up @@ -93,7 +93,7 @@ pub struct Collection {
pub additional_fields: Map<String, Value>,

#[serde(skip)]
href: Option<String>,
self_href: Option<Href>,
}

/// This object provides information about a provider.
Expand Down Expand Up @@ -184,7 +184,7 @@ impl Collection {
assets: HashMap::new(),
item_assets: HashMap::new(),
additional_fields: Map::new(),
href: None,
self_href: None,
}
}

Expand Down Expand Up @@ -249,11 +249,8 @@ impl Collection {
}

fn maybe_add_item_link(&mut self, item: &Item) -> Option<&Link> {
if let Some(href) = item
.href()
.or(item.self_link().map(|link| link.href.as_str()))
{
self.links.push(Link::item(href));
if let Some(href) = item.self_href().or(item.self_link().map(|link| &link.href)) {
self.links.push(Link::item(href.clone()));
self.links.last()
} else {
None
Expand Down Expand Up @@ -448,7 +445,7 @@ mod tests {
.unwrap()
);
let link = collection.link("item").unwrap();
assert_eq!(link.href, "examples/simple-item.json");
assert!(link.href.to_string().ends_with("simple-item.json"));
}
}

Expand Down
Loading

0 comments on commit 5ff0a4e

Please sign in to comment.