1use std::fmt;
9
10#[derive(Debug, Clone, PartialEq)]
14pub enum JsonValue {
15 Null,
16 Bool(bool),
17 Number(f64),
18 String(String),
19 Array(Vec<JsonValue>),
20 Object(Vec<(String, JsonValue)>),
21}
22
23impl JsonValue {
24 pub fn null() -> Self {
25 JsonValue::Null
26 }
27
28 pub fn bool(b: bool) -> Self {
29 JsonValue::Bool(b)
30 }
31
32 pub fn number(n: impl Into<f64>) -> Self {
33 JsonValue::Number(n.into())
34 }
35
36 pub fn string(s: impl Into<String>) -> Self {
37 JsonValue::String(s.into())
38 }
39
40 pub fn object<I, K>(entries: I) -> Self
41 where
42 I: IntoIterator<Item = (K, JsonValue)>,
43 K: Into<String>,
44 {
45 JsonValue::Object(entries.into_iter().map(|(k, v)| (k.into(), v)).collect())
46 }
47
48 pub fn array<I>(items: I) -> Self
49 where
50 I: IntoIterator<Item = JsonValue>,
51 {
52 JsonValue::Array(items.into_iter().collect())
53 }
54
55 pub fn as_object(&self) -> Option<&[(String, JsonValue)]> {
56 match self {
57 JsonValue::Object(entries) => Some(entries.as_slice()),
58 _ => None,
59 }
60 }
61
62 pub fn to_json_string(&self) -> String {
63 let mut out = String::new();
64 write_json(self, &mut out);
65 out
66 }
67}
68
69fn write_json(value: &JsonValue, out: &mut String) {
70 match value {
71 JsonValue::Null => out.push_str("null"),
72 JsonValue::Bool(b) => out.push_str(if *b { "true" } else { "false" }),
73 JsonValue::Number(n) => {
74 if n.fract() == 0.0 && n.is_finite() {
75 out.push_str(&format!("{}", *n as i64));
76 } else {
77 out.push_str(&format!("{n}"));
78 }
79 }
80 JsonValue::String(s) => {
81 out.push('"');
82 for c in s.chars() {
83 match c {
84 '"' => out.push_str("\\\""),
85 '\\' => out.push_str("\\\\"),
86 '\n' => out.push_str("\\n"),
87 '\r' => out.push_str("\\r"),
88 '\t' => out.push_str("\\t"),
89 c if (c as u32) < 0x20 => {
90 out.push_str(&format!("\\u{:04x}", c as u32));
91 }
92 c => out.push(c),
93 }
94 }
95 out.push('"');
96 }
97 JsonValue::Array(items) => {
98 out.push('[');
99 for (i, item) in items.iter().enumerate() {
100 if i > 0 {
101 out.push(',');
102 }
103 write_json(item, out);
104 }
105 out.push(']');
106 }
107 JsonValue::Object(entries) => {
108 out.push('{');
109 for (i, (k, v)) in entries.iter().enumerate() {
110 if i > 0 {
111 out.push(',');
112 }
113 write_json(&JsonValue::String(k.clone()), out);
114 out.push(':');
115 write_json(v, out);
116 }
117 out.push('}');
118 }
119 }
120}
121
122#[derive(Debug, Clone, PartialEq)]
125pub enum ValueOut {
126 Null,
127 Bool(bool),
128 Integer(i64),
129 Float(f64),
130 String(String),
131}
132
133impl fmt::Display for ValueOut {
134 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
135 match self {
136 ValueOut::Null => f.write_str("null"),
137 ValueOut::Bool(b) => write!(f, "{b}"),
138 ValueOut::Integer(n) => write!(f, "{n}"),
139 ValueOut::Float(n) => write!(f, "{n}"),
140 ValueOut::String(s) => write!(f, "{s}"),
141 }
142 }
143}
144
145#[derive(Debug, Clone)]
148pub struct QueryResult {
149 pub statement: String,
150 pub affected: u64,
151 pub columns: Vec<String>,
152 pub rows: Vec<Vec<(String, ValueOut)>>,
153}
154
155pub type Row = Vec<(String, ValueOut)>;
156
157#[derive(Debug, Clone, Default)]
158pub struct ListOptions<'a> {
159 pub filter: Option<&'a str>,
160 pub order_by: Option<&'a str>,
161 pub limit: Option<u64>,
162}
163
164impl<'a> ListOptions<'a> {
165 pub fn new() -> Self {
166 Self::default()
167 }
168
169 pub fn filter(mut self, filter: &'a str) -> Self {
170 self.filter = Some(filter);
171 self
172 }
173
174 pub fn order_by(mut self, order_by: &'a str) -> Self {
175 self.order_by = Some(order_by);
176 self
177 }
178
179 pub fn limit(mut self, limit: u64) -> Self {
180 self.limit = Some(limit);
181 self
182 }
183}
184
185#[derive(Debug, Clone)]
186pub struct ListResult {
187 pub items: Vec<Row>,
188 pub affected: u64,
189}
190
191#[derive(Debug, Clone, PartialEq, Eq)]
192pub struct DeleteResult {
193 pub affected: u64,
194 pub deleted: bool,
195}
196
197#[derive(Debug, Clone, PartialEq, Eq)]
198pub struct ExistsResult {
199 pub exists: bool,
200}
201
202#[derive(Debug, Clone, PartialEq)]
203pub struct DocumentItem {
204 pub rid: String,
205 pub fields: Row,
206}
207
208#[derive(Debug, Clone, PartialEq)]
209pub struct KvItem {
210 pub collection: String,
211 pub key: String,
212 pub value: ValueOut,
213}
214
215#[derive(Debug, Clone, PartialEq)]
216pub struct KvWatchEvent {
217 pub key: String,
218 pub op: String,
219 pub before: serde_json::Value,
220 pub after: serde_json::Value,
221 pub lsn: u64,
222 pub committed_at: u64,
223 pub dropped_event_count: u64,
224}
225
226#[cfg(any(feature = "redwire", feature = "http"))]
227impl QueryResult {
228 pub fn from_envelope(value: serde_json::Value) -> Self {
231 let Some(obj) = value.as_object() else {
232 return Self {
233 statement: String::new(),
234 affected: 0,
235 columns: Vec::new(),
236 rows: Vec::new(),
237 };
238 };
239 let result_obj = obj.get("result").and_then(|v| v.as_object()).unwrap_or(obj);
240 let statement = obj
241 .get("statement")
242 .or_else(|| obj.get("statement_type"))
243 .and_then(|v| v.as_str())
244 .unwrap_or("")
245 .to_string();
246 let affected = obj
247 .get("affected")
248 .or_else(|| obj.get("affected_rows"))
249 .and_then(|v| v.as_u64())
250 .unwrap_or(0);
251 let columns: Vec<String> = result_obj
252 .get("columns")
253 .and_then(|v| v.as_array())
254 .map(|cols| {
255 cols.iter()
256 .filter_map(|col| col.as_str().map(ToOwned::to_owned))
257 .collect::<Vec<_>>()
258 })
259 .unwrap_or_default();
260 let row_values = result_obj
261 .get("records")
262 .or_else(|| result_obj.get("rows"))
263 .and_then(|v| v.as_array());
264 let rows = row_values
265 .map(|records| {
266 records
267 .iter()
268 .map(|record| parse_record(record, &columns))
269 .collect()
270 })
271 .unwrap_or_default();
272 Self {
273 statement,
274 affected,
275 columns,
276 rows,
277 }
278 }
279}
280
281#[cfg(any(feature = "redwire", feature = "http"))]
282fn parse_record(record: &serde_json::Value, columns: &[String]) -> Vec<(String, ValueOut)> {
283 let Some(record_obj) = record.as_object() else {
284 return Vec::new();
285 };
286 let values = record_obj
287 .get("values")
288 .and_then(|v| v.as_object())
289 .unwrap_or(record_obj);
290 if columns.is_empty() {
291 return values
292 .iter()
293 .map(|(key, value)| (key.clone(), json_to_value_out(value)))
294 .collect();
295 }
296 columns
297 .iter()
298 .map(|column| {
299 (
300 column.clone(),
301 values
302 .get(column)
303 .map(json_to_value_out)
304 .unwrap_or(ValueOut::Null),
305 )
306 })
307 .collect()
308}
309
310#[cfg(any(feature = "redwire", feature = "http"))]
311fn json_to_value_out(value: &serde_json::Value) -> ValueOut {
312 match value {
313 serde_json::Value::Null => ValueOut::Null,
314 serde_json::Value::Bool(value) => ValueOut::Bool(*value),
315 serde_json::Value::Number(value) => {
316 if let Some(n) = value.as_i64() {
317 ValueOut::Integer(n)
318 } else if let Some(n) = value.as_f64() {
319 ValueOut::Float(n)
320 } else {
321 ValueOut::String(value.to_string())
322 }
323 }
324 serde_json::Value::String(value) => ValueOut::String(value.clone()),
325 serde_json::Value::Array(_) | serde_json::Value::Object(_) => {
326 ValueOut::String(value.to_string())
327 }
328 }
329}
330
331#[derive(Debug, Clone)]
332pub struct InsertResult {
333 pub affected: u64,
334 pub rid: Option<String>,
336 pub id: Option<String>,
338}
339
340#[derive(Debug, Clone, PartialEq, Eq)]
341pub struct BulkInsertResult {
342 pub affected: u64,
343 pub rids: Vec<String>,
345 pub ids: Vec<String>,
347}