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}