metabase_api_rs/repository/
database.rs1use crate::core::models::database::DatabaseMetadata;
7use crate::core::models::field::Field;
8use crate::core::models::{MetabaseId, SyncResult};
9use crate::repository::traits::{
10 FilterParams, PaginationParams, Repository, RepositoryError, RepositoryResult,
11};
12use crate::transport::http_provider_safe::{HttpProviderExt, HttpProviderSafe};
13use async_trait::async_trait;
14use serde_json::json;
15use std::sync::Arc;
16
17#[derive(Debug, Clone, Default)]
19pub struct DatabaseFilterParams {
20 pub engine: Option<String>,
21 pub native_permissions: Option<String>,
22}
23
24impl DatabaseFilterParams {
25 pub fn to_query_params(&self) -> Vec<(String, String)> {
27 let mut params = vec![];
28 if let Some(engine) = &self.engine {
29 params.push(("engine".to_string(), engine.clone()));
30 }
31 if let Some(permissions) = &self.native_permissions {
32 params.push(("native_permissions".to_string(), permissions.clone()));
33 }
34 params
35 }
36}
37
38#[async_trait]
40pub trait DatabaseRepository:
41 Repository<Entity = DatabaseMetadata, Id = MetabaseId> + Send + Sync
42{
43 async fn sync_database_schema(&self, id: &MetabaseId) -> RepositoryResult<SyncResult>;
45
46 async fn get_database_fields(&self, id: &MetabaseId) -> RepositoryResult<Vec<Field>>;
48
49 async fn get_database_schemas(&self, id: &MetabaseId) -> RepositoryResult<Vec<String>>;
51
52 async fn list_with_filters(
54 &self,
55 pagination: Option<PaginationParams>,
56 filters: Option<DatabaseFilterParams>,
57 ) -> RepositoryResult<Vec<DatabaseMetadata>>;
58}
59
60pub struct HttpDatabaseRepository {
62 http_provider: Arc<dyn HttpProviderSafe>,
63}
64
65impl HttpDatabaseRepository {
66 pub fn new(http_provider: Arc<dyn HttpProviderSafe>) -> Self {
68 Self { http_provider }
69 }
70}
71
72#[async_trait]
73impl Repository for HttpDatabaseRepository {
74 type Entity = DatabaseMetadata;
75 type Id = MetabaseId;
76
77 async fn get(&self, id: &Self::Id) -> RepositoryResult<Self::Entity> {
78 let path = format!("/api/database/{}/metadata", id.0);
79 self.http_provider
80 .get(&path)
81 .await
82 .map_err(|e| RepositoryError::Network(e.to_string()))
83 }
84
85 async fn list(
86 &self,
87 pagination: Option<PaginationParams>,
88 _filters: Option<FilterParams>,
89 ) -> RepositoryResult<Vec<Self::Entity>> {
90 let mut path = "/api/database".to_string();
92 let mut query_params = vec![];
93
94 if let Some(pagination) = pagination {
95 query_params.extend(pagination.to_query_params());
96 }
97
98 if !query_params.is_empty() {
99 let query_string = query_params
100 .iter()
101 .map(|(k, v)| format!("{}={}", k, v))
102 .collect::<Vec<_>>()
103 .join("&");
104 path = format!("{}?{}", path, query_string);
105 }
106
107 self.http_provider
108 .get(&path)
109 .await
110 .map_err(|e| RepositoryError::Network(e.to_string()))
111 }
112
113 async fn create(&self, _entity: &Self::Entity) -> RepositoryResult<Self::Entity> {
114 Err(RepositoryError::Other(
116 "Database creation not supported through API".to_string(),
117 ))
118 }
119
120 async fn update(
121 &self,
122 _id: &Self::Id,
123 _entity: &Self::Entity,
124 ) -> RepositoryResult<Self::Entity> {
125 Err(RepositoryError::Other(
127 "Database updates not supported through API".to_string(),
128 ))
129 }
130
131 async fn delete(&self, _id: &Self::Id) -> RepositoryResult<()> {
132 Err(RepositoryError::Other(
134 "Database deletion not supported through API".to_string(),
135 ))
136 }
137}
138
139#[async_trait]
140impl DatabaseRepository for HttpDatabaseRepository {
141 async fn sync_database_schema(&self, id: &MetabaseId) -> RepositoryResult<SyncResult> {
142 let path = format!("/api/database/{}/sync_schema", id.0);
143 self.http_provider
144 .post(&path, &json!({}))
145 .await
146 .map_err(|e| RepositoryError::Network(e.to_string()))
147 }
148
149 async fn get_database_fields(&self, id: &MetabaseId) -> RepositoryResult<Vec<Field>> {
150 let path = format!("/api/database/{}/fields", id.0);
151 self.http_provider
152 .get(&path)
153 .await
154 .map_err(|e| RepositoryError::Network(e.to_string()))
155 }
156
157 async fn get_database_schemas(&self, id: &MetabaseId) -> RepositoryResult<Vec<String>> {
158 let path = format!("/api/database/{}/schemas", id.0);
159 self.http_provider
160 .get(&path)
161 .await
162 .map_err(|e| RepositoryError::Network(e.to_string()))
163 }
164
165 async fn list_with_filters(
166 &self,
167 pagination: Option<PaginationParams>,
168 filters: Option<DatabaseFilterParams>,
169 ) -> RepositoryResult<Vec<DatabaseMetadata>> {
170 let mut path = "/api/database".to_string();
171 let mut query_params = vec![];
172
173 if let Some(pagination) = pagination {
174 query_params.extend(pagination.to_query_params());
175 }
176
177 if let Some(filters) = filters {
178 query_params.extend(filters.to_query_params());
179 }
180
181 if !query_params.is_empty() {
182 let query_string = query_params
183 .iter()
184 .map(|(k, v)| format!("{}={}", k, v))
185 .collect::<Vec<_>>()
186 .join("&");
187 path = format!("{}?{}", path, query_string);
188 }
189
190 self.http_provider
191 .get(&path)
192 .await
193 .map_err(|e| RepositoryError::Network(e.to_string()))
194 }
195}