1use serde::{Deserialize, Serialize};
4use serde_json::{json, Value as JsonValue};
5use vibesql_types::SqlValue;
6
7#[derive(Debug, Clone, Serialize, Deserialize)]
9pub struct QueryRequest {
10 pub sql: String,
12 #[serde(default)]
14 pub params: Vec<JsonValue>,
15 #[serde(default)]
17 pub limit: Option<usize>,
18 #[serde(default)]
20 pub offset: Option<usize>,
21}
22
23impl QueryRequest {
24 pub fn to_sql_values(&self) -> Result<Vec<SqlValue>, String> {
26 self.params.iter().map(json_to_sql_value).collect()
27 }
28}
29
30#[derive(Debug, Clone, Serialize, Deserialize)]
32pub struct QueryResponse {
33 pub columns: Vec<String>,
35 pub rows: Vec<Vec<JsonValue>>,
37 pub row_count: usize,
39 #[serde(skip_serializing_if = "Option::is_none")]
41 pub total_count: Option<usize>,
42 #[serde(skip_serializing_if = "Option::is_none")]
44 pub offset: Option<usize>,
45 #[serde(skip_serializing_if = "Option::is_none")]
47 pub limit: Option<usize>,
48}
49
50#[derive(Debug, Clone, Serialize, Deserialize)]
52pub struct MutationResponse {
53 pub rows_affected: usize,
55}
56
57#[derive(Debug, Clone, Serialize, Deserialize)]
59pub struct TableInfo {
60 pub name: String,
62 pub columns: Vec<ColumnInfo>,
64}
65
66#[derive(Debug, Clone, Serialize, Deserialize)]
68pub struct ColumnInfo {
69 pub name: String,
71 pub data_type: String,
73 pub nullable: bool,
75 pub primary_key: bool,
77}
78
79#[derive(Debug, Clone, Serialize, Deserialize)]
81pub struct ErrorResponse {
82 pub error: String,
84 #[serde(skip_serializing_if = "Option::is_none")]
86 pub code: Option<String>,
87}
88
89impl ErrorResponse {
90 pub fn new(error: impl Into<String>) -> Self {
91 Self { error: error.into(), code: None }
92 }
93
94 pub fn with_code(error: impl Into<String>, code: impl Into<String>) -> Self {
95 Self { error: error.into(), code: Some(code.into()) }
96 }
97}
98
99#[derive(Debug, Clone, Serialize, Deserialize)]
101pub struct HealthResponse {
102 pub status: String,
103 pub version: String,
104}
105
106pub fn sql_value_to_json(val: &SqlValue) -> JsonValue {
108 match val {
109 SqlValue::Null => JsonValue::Null,
110 SqlValue::Boolean(b) => JsonValue::Bool(*b),
111 SqlValue::Integer(i) => json!(*i),
112 SqlValue::Smallint(i) => json!(*i as i64),
113 SqlValue::Bigint(i) => json!(*i),
114 SqlValue::Unsigned(u) => json!(*u),
115 SqlValue::Numeric(f) => {
116 if f.is_nan() || f.is_infinite() {
117 JsonValue::Null
118 } else {
119 json!(*f)
120 }
121 }
122 SqlValue::Float(f) => {
123 if f.is_nan() || f.is_infinite() {
124 JsonValue::Null
125 } else {
126 json!(*f as f64)
127 }
128 }
129 SqlValue::Real(f) => {
130 if f.is_nan() || f.is_infinite() {
131 JsonValue::Null
132 } else {
133 json!(*f as f64)
134 }
135 }
136 SqlValue::Double(f) => {
137 if f.is_nan() || f.is_infinite() {
138 JsonValue::Null
139 } else {
140 json!(*f)
141 }
142 }
143 SqlValue::Character(s) | SqlValue::Varchar(s) => JsonValue::String(s.to_string()),
144 SqlValue::Timestamp(ts) => JsonValue::String(format!("{:?}", ts)),
145 SqlValue::Date(d) => JsonValue::String(format!("{:?}", d)),
146 SqlValue::Time(t) => JsonValue::String(format!("{:?}", t)),
147 SqlValue::Interval(_) => JsonValue::Null, SqlValue::Vector(v) => json!(v), }
150}
151
152pub fn json_to_sql_value(val: &JsonValue) -> Result<SqlValue, String> {
154 match val {
155 JsonValue::Null => Ok(SqlValue::Null),
156 JsonValue::Bool(b) => Ok(SqlValue::Boolean(*b)),
157 JsonValue::Number(n) => {
158 if let Some(i) = n.as_i64() {
159 Ok(SqlValue::Integer(i))
160 } else if let Some(f) = n.as_f64() {
161 Ok(SqlValue::Numeric(f))
162 } else {
163 Err("Invalid number".to_string())
164 }
165 }
166 JsonValue::String(s) => Ok(SqlValue::Varchar(arcstr::ArcStr::from(s.clone()))),
167 JsonValue::Array(_) => Err("Arrays not yet supported".to_string()),
168 JsonValue::Object(_) => Err("Objects not yet supported".to_string()),
169 }
170}
171
172#[derive(Debug, Clone, Serialize, Deserialize)]
178pub struct BlobUploadResponse {
179 pub id: String,
181 pub size: i64,
183 pub content_type: String,
185 pub url: String,
187}
188
189#[derive(Debug, Clone, Serialize, Deserialize)]
191pub struct BlobMetadataResponse {
192 pub id: String,
194 pub size: i64,
196 pub content_type: String,
198 pub created_at: String,
200}
201
202#[derive(Debug, Clone, Serialize, Deserialize)]
208pub struct PartialUpdateFallbacks {
209 pub disabled: u64,
211 pub threshold_exceeded: u64,
213 pub row_count_mismatch: u64,
215 pub pk_mismatch: u64,
217 pub no_changes: u64,
219}
220
221#[derive(Debug, Clone, Serialize, Deserialize)]
223pub struct SubscriptionEfficiencyStats {
224 pub partial_update_efficiency: f64,
226 pub total_bytes_saved: u64,
228 pub fallbacks: PartialUpdateFallbacks,
230 pub partial_updates_sent: u64,
232 pub full_updates_sent: u64,
234}