bbox_feature_server/datasource/
mod.rs1use crate::config::{CollectionSourceCfg, ConfiguredCollectionCfg};
4use crate::error::{Error, Result};
5use crate::filter_params::FilterParams;
6use crate::inventory::FeatureCollection;
7use async_trait::async_trait;
8use bbox_core::config::{DatasourceCfg, NamedDatasourceCfg};
9use bbox_core::ogcapi::{CoreExtent, CoreFeature, Queryables};
10use bbox_core::NamedObjectStore;
11use dyn_clone::{clone_trait_object, DynClone};
12use std::env;
13
14pub mod gpkg;
15pub mod postgis;
16
17#[async_trait]
18pub trait CollectionDatasource {
19 async fn setup_collection(
20 &mut self,
21 cfg: &ConfiguredCollectionCfg,
22 extent: Option<CoreExtent>,
23 ) -> Result<FeatureCollection>;
24}
25
26#[async_trait]
27pub trait AutoscanCollectionDatasource {
28 async fn collections(&mut self) -> Result<Vec<FeatureCollection>>;
29}
30
31#[async_trait]
32pub trait CollectionSource: DynClone + Sync + Send {
33 async fn items(&self, filter: &FilterParams) -> Result<ItemsResult>;
34 async fn item(&self, collection_id: &str, feature_id: &str) -> Result<Option<CoreFeature>>;
35 async fn queryables(&self, collection_id: &str) -> Result<Option<Queryables>>;
36}
37
38clone_trait_object!(CollectionSource);
39
40#[derive(Default)]
42pub struct Datasources {
43 pg_datasources: NamedObjectStore<postgis::Datasource>,
44 gpkg_datasources: NamedObjectStore<gpkg::Datasource>,
45}
46
47impl Datasources {
48 pub async fn create(datasources: &Vec<NamedDatasourceCfg>) -> Result<Self> {
49 let mut ds_handler = Datasources::default();
51 for named_ds in datasources {
52 let envar = env::var(format!("BBOX_DATASOURCE_{}", &named_ds.name.to_uppercase())).ok();
55 match &named_ds.datasource {
56 DatasourceCfg::Postgis(cfg) => {
57 let ds = postgis::Datasource::from_config(cfg, envar)
58 .await
59 .map_err(|e| Error::DatasourceSetupError(e.to_string()))?;
60 ds_handler.pg_datasources.add(&named_ds.name, ds);
61 }
62 DatasourceCfg::Gpkg(cfg) => {
63 let ds = gpkg::Datasource::from_config(cfg).await?;
64 ds_handler.gpkg_datasources.add(&named_ds.name, ds);
65 }
66 _ => { }
67 }
68 }
69 Ok(ds_handler)
70 }
71 pub async fn setup_collection(
72 &mut self,
73 collection: &ConfiguredCollectionCfg,
74 ) -> Result<FeatureCollection> {
75 match &collection.source {
76 CollectionSourceCfg::Postgis(cfg) => {
77 let source = self
78 .pg_datasources
79 .get_or_default_mut(cfg.datasource.as_deref())
80 .ok_or(Error::DatasourceNotFound(
81 cfg.datasource
82 .as_ref()
83 .unwrap_or(&"(default)".to_string())
84 .clone(),
85 ))?;
86 source.setup_collection(collection, None).await
87 }
88 CollectionSourceCfg::Gpkg(ref cfg) => {
89 let source = self
90 .gpkg_datasources
91 .get_or_default_mut(cfg.datasource.as_deref())
92 .ok_or(Error::DatasourceNotFound(
93 cfg.datasource
94 .as_ref()
95 .unwrap_or(&"(default)".to_string())
96 .clone(),
97 ))?;
98 source.setup_collection(collection, None).await
99 }
100 }
101 }
102}
103
104#[derive(Debug)]
105pub struct ItemsResult {
106 pub features: Vec<CoreFeature>,
107 pub number_matched: u64,
108 pub number_returned: u64,
109}