Skip to main content

edgebase_admin/
d1.rs

1//! D1Client — D1 database access for server-side use.
2
3use std::collections::HashMap;
4use std::sync::Arc;
5
6use serde_json::Value;
7
8use crate::generated::admin_api_core::GeneratedAdminApi;
9use edgebase_core::error::Error;
10use edgebase_core::http_client::HttpClient;
11
12/// Client for a user-defined D1 database.
13pub struct D1Client {
14    http: Arc<HttpClient>,
15    pub(crate) database: String,
16}
17
18impl D1Client {
19    pub(crate) fn new(http: Arc<HttpClient>, database: &str) -> Self {
20        Self {
21            http,
22            database: database.to_string(),
23        }
24    }
25
26    fn core(&self) -> GeneratedAdminApi<'_> {
27        GeneratedAdminApi::new(&self.http)
28    }
29
30    /// Execute a SQL query. Use ? placeholders for bind parameters.
31    /// All SQL is allowed (DDL included).
32    pub async fn exec(&self, query: &str, params: &[Value]) -> Result<Vec<HashMap<String, Value>>, Error> {
33        let body = serde_json::json!({
34            "query": query,
35            "params": params,
36        });
37        let res: serde_json::Value = self.core().execute_d1_query(&self.database, &body).await?;
38        if let Some(results) = res.get("results").and_then(|v: &serde_json::Value| v.as_array()) {
39            Ok(results
40                .iter()
41                .filter_map(|v: &serde_json::Value| {
42                    v.as_object()
43                        .map(|o: &serde_json::Map<String, serde_json::Value>| o.iter().map(|(k, v): (&String, &serde_json::Value)| (k.clone(), v.clone())).collect::<HashMap<String, serde_json::Value>>())
44                })
45                .collect())
46        } else {
47            Ok(vec![])
48        }
49    }
50
51    /// Alias for exec() to match SDK parity across runtimes.
52    pub async fn query(&self, query: &str, params: &[Value]) -> Result<Vec<HashMap<String, Value>>, Error> {
53        self.exec(query, params).await
54    }
55}