stac_server/backend/
mod.rs

1#[cfg(feature = "duckdb")]
2mod duckdb;
3mod memory;
4#[cfg(feature = "pgstac")]
5mod pgstac;
6
7use crate::Result;
8#[cfg(feature = "duckdb")]
9pub use duckdb::DuckdbBackend;
10pub use memory::MemoryBackend;
11#[cfg(feature = "pgstac")]
12pub use pgstac::PgstacBackend;
13use stac::{Collection, Item};
14use stac_api::{ItemCollection, Items, Search};
15use std::future::Future;
16
17/// Storage backend for a STAC API.
18pub trait Backend: Clone + Sync + Send + 'static {
19    /// Returns true if this backend has item search capabilities.
20    ///
21    /// # Examples
22    ///
23    /// ```
24    /// use stac_server::{MemoryBackend, Backend};
25    ///
26    /// assert!(MemoryBackend::new().has_item_search());
27    /// ```
28    fn has_item_search(&self) -> bool;
29
30    /// Returns true if this backend has [filter](https://github.com/stac-api-extensions/filter) capabilities.
31    ///
32    /// # Examples
33    ///
34    /// ```
35    /// use stac_server::{MemoryBackend, Backend};
36    ///
37    /// assert!(!MemoryBackend::new().has_filter());
38    /// ```
39    fn has_filter(&self) -> bool;
40
41    /// Returns all collections.
42    ///
43    /// # Examples
44    ///
45    /// ```
46    /// use stac_server::{MemoryBackend, Backend};
47    /// let backend = MemoryBackend::new();
48    /// # tokio_test::block_on(async {
49    /// let collections = backend.collections().await.unwrap();
50    /// assert!(collections.is_empty());
51    /// # })
52    /// ```
53    fn collections(&self) -> impl Future<Output = Result<Vec<Collection>>> + Send;
54
55    /// Returns a single collection.
56    ///
57    /// # Examples
58    ///
59    /// ```
60    /// use stac_server::{MemoryBackend, Backend};
61    /// let backend = MemoryBackend::new();
62    /// # tokio_test::block_on(async {
63    /// let collection = backend.collection("does-not-exist").await.unwrap();
64    /// assert!(collection.is_none());
65    /// # })
66    /// ```
67    fn collection(&self, id: &str) -> impl Future<Output = Result<Option<Collection>>> + Send;
68
69    /// Adds a collection.
70    ///
71    /// # Examples
72    ///
73    /// ```
74    /// use stac::Collection;
75    /// use stac_server::{MemoryBackend, Backend};
76    ///
77    /// let mut backend = MemoryBackend::new();
78    /// # tokio_test::block_on(async {
79    /// backend.add_collection(Collection::new("an-id", "a description")).await.unwrap();
80    /// # })
81    /// ```
82    fn add_collection(&mut self, collection: Collection)
83    -> impl Future<Output = Result<()>> + Send;
84
85    /// Adds an item.
86    ///
87    /// If the item doesn't have its `collection` field set, or a collection
88    /// with that id does not exist in the backend, throws an error.
89    ///
90    /// # Examples
91    ///
92    /// ```
93    /// use stac::{Collection, Item};
94    /// use stac_server::{MemoryBackend, Backend};
95    ///
96    /// let mut backend = MemoryBackend::new();
97    /// # tokio_test::block_on(async {
98    /// assert!(backend.add_item(Item::new("item-id")).await.is_err());
99    ///
100    /// backend.add_collection(Collection::new("collection-id", "a description")).await.unwrap();
101    /// backend.add_item(Item::new("item-id").collection("collection-id")).await.unwrap();
102    /// # })
103    /// ```
104    fn add_item(&mut self, item: Item) -> impl Future<Output = Result<()>> + Send;
105
106    /// Adds multiple items.
107    fn add_items(&mut self, items: Vec<Item>) -> impl Future<Output = Result<()>> + Send {
108        tracing::debug!("adding {} items using naïve loading", items.len());
109        async move {
110            for item in items {
111                self.add_item(item).await?;
112            }
113            Ok(())
114        }
115    }
116
117    /// Retrieves items for a given collection.
118    ///
119    /// # Examples
120    ///
121    /// ```
122    /// use stac::{Collection, Item};
123    /// use stac_api::Items;
124    /// use stac_server::{MemoryBackend, Backend};
125    ///
126    /// let mut backend = MemoryBackend::new();
127    /// # tokio_test::block_on(async {
128    /// backend.add_collection(Collection::new("collection-id", "a description")).await.unwrap();
129    /// backend.add_item(Item::new("item-id").collection("collection-id")).await.unwrap();
130    /// let items = backend.items("collection-id", Items::default()).await.unwrap();
131    /// # })
132    /// ```
133    fn items(
134        &self,
135        collection_id: &str,
136        items: Items,
137    ) -> impl Future<Output = Result<Option<ItemCollection>>> + Send;
138
139    /// Retrieves an item from a collection.
140    ///
141    /// # Examples
142    ///
143    /// ```
144    /// use stac::{Collection, Item};
145    /// use stac_server::{MemoryBackend, Backend};
146    ///
147    /// let mut backend = MemoryBackend::new();
148    /// # tokio_test::block_on(async {
149    /// backend.add_collection(Collection::new("collection-id", "a description")).await.unwrap();
150    /// backend.add_item(Item::new("item-id").collection("collection-id")).await.unwrap();
151    /// let item = backend.item("collection-id", "item-id").await.unwrap().unwrap();
152    /// # })
153    /// ```
154    fn item(
155        &self,
156        collection_id: &str,
157        item_id: &str,
158    ) -> impl Future<Output = Result<Option<Item>>> + Send;
159
160    /// Searches a backend.
161    ///
162    /// # Examples
163    ///
164    /// ```
165    /// use stac_api::Search;
166    /// use stac_server::{MemoryBackend, Backend};
167    ///
168    /// let mut backend = MemoryBackend::new();
169    /// # tokio_test::block_on(async {
170    /// let item_collection = backend.search(Search::default()).await.unwrap();
171    /// # })
172    /// ```
173    fn search(&self, search: Search) -> impl Future<Output = Result<ItemCollection>> + Send;
174}