everruns_core/
session_sqldb.rs1use async_trait::async_trait;
8use chrono::{DateTime, Utc};
9use serde::{Deserialize, Serialize};
10
11use crate::typed_id::SessionId;
12
13#[derive(Debug, Clone, Serialize, Deserialize)]
15pub struct DatabaseInfo {
16 pub name: String,
17 pub size_bytes: i64,
18 pub page_count: i32,
19 pub created_at: DateTime<Utc>,
20 pub updated_at: DateTime<Utc>,
21}
22
23#[derive(Debug, Clone, Serialize, Deserialize)]
25pub struct SqlQueryResult {
26 pub columns: Vec<String>,
27 pub rows: Vec<Vec<serde_json::Value>>,
28 pub row_count: usize,
29 #[serde(skip_serializing_if = "std::ops::Not::not")]
31 pub truncated: bool,
32}
33
34#[derive(Debug, Clone, Serialize, Deserialize)]
36pub struct SqlExecuteResult {
37 pub rows_affected: u64,
38}
39
40#[derive(Debug, Clone, Serialize, Deserialize)]
42pub struct TableSchema {
43 pub name: String,
44 pub columns: Vec<ColumnSchema>,
45 pub row_count: i64,
46}
47
48#[derive(Debug, Clone, Serialize, Deserialize)]
50pub struct ColumnSchema {
51 pub name: String,
52 #[serde(rename = "type")]
53 pub column_type: String,
54 pub notnull: bool,
55 pub pk: bool,
56 pub default_value: Option<String>,
57}
58
59#[derive(Debug, thiserror::Error)]
64pub enum SessionSqlDbError {
65 #[error("database not found: {0}")]
66 DatabaseNotFound(String),
67
68 #[error("database already exists: {0}")]
69 DatabaseAlreadyExists(String),
70
71 #[error("invalid database name: {0}")]
72 InvalidDatabaseName(String),
73
74 #[error("database limit exceeded: {0}")]
75 LimitExceeded(String),
76
77 #[error("query error: {0}")]
78 QueryError(String),
79
80 #[error("query timeout after {0} seconds")]
81 QueryTimeout(u64),
82
83 #[error("result too large: {0}")]
84 ResultTooLarge(String),
85
86 #[error("operation blocked by authorizer: {0}")]
87 AuthorizerBlocked(String),
88
89 #[error("internal error: {0}")]
90 Internal(String),
91}
92
93impl SessionSqlDbError {
94 pub fn is_tool_error(&self) -> bool {
96 matches!(
97 self,
98 Self::DatabaseNotFound(_)
99 | Self::DatabaseAlreadyExists(_)
100 | Self::InvalidDatabaseName(_)
101 | Self::LimitExceeded(_)
102 | Self::QueryError(_)
103 | Self::QueryTimeout(_)
104 | Self::ResultTooLarge(_)
105 | Self::AuthorizerBlocked(_)
106 )
107 }
108}
109
110#[async_trait]
116pub trait SessionSqlDbStore: Send + Sync {
117 async fn create_database(
119 &self,
120 session_id: SessionId,
121 name: &str,
122 ) -> Result<DatabaseInfo, SessionSqlDbError>;
123
124 async fn list_databases(
126 &self,
127 session_id: SessionId,
128 ) -> Result<Vec<DatabaseInfo>, SessionSqlDbError>;
129
130 async fn get_database(
132 &self,
133 session_id: SessionId,
134 name: &str,
135 ) -> Result<Option<DatabaseInfo>, SessionSqlDbError>;
136
137 async fn delete_database(
139 &self,
140 session_id: SessionId,
141 name: &str,
142 ) -> Result<bool, SessionSqlDbError>;
143
144 async fn sql_execute(
146 &self,
147 session_id: SessionId,
148 db_name: &str,
149 sql: &str,
150 ) -> Result<SqlExecuteResult, SessionSqlDbError>;
151
152 async fn sql_query(
154 &self,
155 session_id: SessionId,
156 db_name: &str,
157 sql: &str,
158 ) -> Result<SqlQueryResult, SessionSqlDbError>;
159
160 async fn sql_schema(
162 &self,
163 session_id: SessionId,
164 db_name: &str,
165 table: Option<&str>,
166 ) -> Result<Vec<TableSchema>, SessionSqlDbError>;
167}