stac_server/backend/
mod.rs

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