use serde::{de::DeserializeOwned, Deserialize, Serialize}; #[derive(Debug, Clone, Serialize, Deserialize)] pub struct DatabaseInfo { pub name: String, } #[derive(Debug, Clone, Serialize, Deserialize)] pub struct TableInfo { pub name: String, pub table_type: String, pub comment: Option, pub parent_schema: Option, pub parent_name: Option, } #[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] #[serde(rename_all = "SCREAMING_SNAKE_CASE")] pub enum ObjectSourceKind { View, MaterializedView, Procedure, Function, Trigger, Sequence, Package, PackageBody, Type, TypeBody, } #[derive(Debug, Clone, Serialize, Deserialize, Default)] pub struct ColumnInfo { pub name: String, pub data_type: String, pub is_nullable: bool, pub column_default: Option, pub is_primary_key: bool, pub extra: Option, pub comment: Option, pub numeric_precision: Option, pub numeric_scale: Option, pub character_maximum_length: Option, #[serde(default, skip_serializing_if = "Option::is_none")] pub enum_values: Option>, #[serde(default, skip_serializing_if = "Option::is_none")] pub character_set: Option, #[serde(default, skip_serializing_if = "Option::is_none")] pub collation: Option, } #[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] #[serde(rename_all = "snake_case")] pub enum CompletionAssistantObjectKind { Database, Schema, Table, View, Routine, Procedure, Function, Column, Sequence, } impl CompletionAssistantObjectKind { pub fn is_table_like(&self) -> bool { matches!(self, Self::Table | Self::View) } } #[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] #[serde(rename_all = "snake_case")] pub enum CompletionAssistantCandidateKind { Database, Schema, Table, View, Procedure, Function, Column, Sequence, Object, } #[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] #[serde(rename_all = "snake_case")] pub enum CompletionAssistantMatchMode { Prefix, Contains, } #[derive(Debug, Clone, Serialize, Deserialize)] pub struct CompletionAssistantRequest { pub connection_id: String, pub database: String, pub schema: Option, #[serde(default)] pub object_kinds: Vec, #[serde(default)] pub mask: String, #[serde(default)] pub case_sensitive: bool, #[serde(default)] pub global_search: bool, pub max_results: Option, #[serde(default)] pub search_in_comments: bool, #[serde(default)] pub search_in_definitions: bool, pub parent_schema: Option, pub parent_name: Option, pub match_mode: Option, } #[derive(Debug, Clone, Serialize, Deserialize)] pub struct CompletionAssistantCandidate { pub name: String, pub kind: CompletionAssistantCandidateKind, pub database: Option, pub schema: Option, pub parent_schema: Option, pub parent_name: Option, pub comment: Option, pub data_type: Option, pub signature: Option, } #[derive(Debug, Clone, Serialize, Deserialize)] pub struct CompletionAssistantResponse { pub candidates: Vec, pub incomplete: bool, pub fallback_used: bool, } #[derive(Debug, Clone, Serialize, Deserialize)] pub struct QueryResult { pub columns: Vec, #[serde(default)] pub column_types: Vec, #[serde(default)] pub column_sortables: Vec, pub rows: Vec>, pub affected_rows: u64, pub execution_time_ms: u128, #[serde(default)] pub truncated: bool, #[serde(default)] pub session_id: Option, #[serde(default)] pub has_more: bool, #[serde(default, skip_serializing_if = "Option::is_none")] pub elasticsearch_raw_body: Option, } #[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] pub struct AttachedDatabaseConfig { pub name: String, pub path: String, } #[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] pub struct DuckDbWorkerRequest { pub id: String, pub method: DuckDbWorkerMethod, #[serde(default)] pub params: serde_json::Value, } impl DuckDbWorkerRequest { #[cfg(test)] pub fn new(id: impl Into, method: DuckDbWorkerMethod, params: impl Serialize) -> Result { let params = serde_json::to_value(params).map_err(|error| error.to_string())?; Ok(Self { id: id.into(), method, params }) } pub fn parse_params(&self) -> Result { serde_json::from_value(self.params.clone()).map_err(|error| { DuckDbWorkerError::new("invalid_params", format!("Invalid params for {:?}: {error}", self.method)) }) } } #[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq)] #[serde(rename_all = "snake_case")] pub enum DuckDbWorkerMethod { Connect, Execute, ListDatabases, ListSchemas, ListTables, ListColumns, GetTableDdl, CompletionAssistant, GetObjectSource, AttachDatabase, Cancel, Shutdown, } #[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] pub struct DuckDbWorkerResponse { pub id: String, pub ok: bool, #[serde(skip_serializing_if = "Option::is_none")] pub result: Option, #[serde(skip_serializing_if = "Option::is_none")] pub error: Option, } impl DuckDbWorkerResponse { pub fn ok(id: impl Into, result: impl Serialize) -> Self { match serde_json::to_value(result) { Ok(result) => Self { id: id.into(), ok: true, result: Some(result), error: None }, Err(error) => Self::err(id, DuckDbWorkerError::new("serialization_failed", error.to_string())), } } pub fn ok_empty(id: impl Into) -> Self { Self { id: id.into(), ok: true, result: None, error: None } } pub fn err(id: impl Into, error: DuckDbWorkerError) -> Self { Self { id: id.into(), ok: false, result: None, error: Some(error) } } } #[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] pub struct DuckDbWorkerError { pub code: String, pub message: String, } impl DuckDbWorkerError { pub fn new(code: impl Into, message: impl Into) -> Self { Self { code: code.into(), message: message.into() } } pub fn from_message(code: &'static str, error: impl ToString) -> Self { Self::new(code, error.to_string()) } } impl From for DuckDbWorkerError { fn from(message: String) -> Self { Self::new("duckdb_worker_error", message) } } impl From<&str> for DuckDbWorkerError { fn from(message: &str) -> Self { Self::new("duckdb_worker_error", message) } } #[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] #[serde(rename_all = "camelCase")] pub struct DuckDbWorkerConnectParams { pub path: String, #[serde(default)] pub attached_databases: Vec, #[serde(default)] pub init_script: Option, } #[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] #[serde(rename_all = "camelCase")] pub struct DuckDbWorkerExecuteParams { pub sql: String, #[serde(default)] pub database: Option, #[serde(default)] pub max_rows: Option, } #[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] #[serde(rename_all = "camelCase")] pub struct DuckDbWorkerDatabaseParams { pub database: String, } #[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] #[serde(rename_all = "camelCase")] pub struct DuckDbWorkerTableParams { pub database: String, pub schema: String, } #[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] #[serde(rename_all = "camelCase")] pub struct DuckDbWorkerColumnParams { pub database: String, pub schema: String, pub table: String, } #[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] #[serde(rename_all = "camelCase")] pub struct DuckDbWorkerObjectSourceParams { pub database: String, pub schema: String, pub name: String, pub object_type: ObjectSourceKind, }