1use crate::config::OutputConfig;
8use crate::output::{OutputError, StreamingWriter};
9use cqlite_core::query::{QueryMetadata, QueryResult, QueryRow};
10use cqlite_core::Value;
11use serde_json::{json, Map, Value as JsonValue};
12use std::error::Error as StdError;
13use std::io::Write;
14
15use super::value_fmt::ValueFormatter;
16
17#[allow(dead_code)]
19pub struct JSONWriter;
20
21impl JSONWriter {
22 #[allow(dead_code)]
49 pub fn write(result: &QueryResult, config: &OutputConfig) -> Result<String, Box<dyn StdError>> {
50 let mut rows_json = Vec::new();
51
52 let rows_to_display = if let Some(limit) = config.limit {
54 &result.rows[..result.rows.len().min(limit)]
55 } else {
56 &result.rows
57 };
58
59 for row in rows_to_display {
60 let mut row_obj = Map::new();
62
63 for col in &result.metadata.columns {
65 let value_opt = row.values.get(&col.name);
66 let json_value = match value_opt {
67 Some(value) => Self::value_to_json(value),
68 None => JsonValue::Null,
69 };
70 row_obj.insert(col.name.clone(), json_value);
71 }
72
73 rows_json.push(JsonValue::Object(row_obj));
74 }
75
76 serde_json::to_string_pretty(&rows_json).map_err(|e| e.into())
78 }
79
80 #[allow(dead_code)]
84 fn value_to_json(value: &Value) -> JsonValue {
85 match value {
86 Value::Null => JsonValue::Null,
87 Value::Boolean(b) => JsonValue::Bool(*b),
88 Value::Integer(i) => JsonValue::Number((*i).into()),
89 Value::BigInt(i) => JsonValue::Number((*i).into()),
90 Value::Counter(c) => JsonValue::Number((*c).into()),
91 Value::TinyInt(i) => JsonValue::Number((*i as i64).into()),
92 Value::SmallInt(i) => JsonValue::Number((*i as i64).into()),
93 Value::Float(f) => serde_json::Number::from_f64(*f)
94 .map(JsonValue::Number)
95 .unwrap_or(JsonValue::Null),
96 Value::Float32(f) => serde_json::Number::from_f64(*f as f64)
97 .map(JsonValue::Number)
98 .unwrap_or(JsonValue::Null),
99 Value::Text(s) => JsonValue::String(s.clone()),
100 Value::Blob(_) => JsonValue::String(ValueFormatter::format_value(value)),
102 Value::Timestamp(_) => JsonValue::String(ValueFormatter::format_value(value)),
104 Value::Date(_) => JsonValue::String(ValueFormatter::format_value(value)),
106 Value::Time(_) => JsonValue::String(ValueFormatter::format_value(value)),
108 Value::Uuid(uuid) => {
109 let uuid_str = format!(
111 "{:02x}{:02x}{:02x}{:02x}-{:02x}{:02x}-{:02x}{:02x}-{:02x}{:02x}-{:02x}{:02x}{:02x}{:02x}{:02x}{:02x}",
112 uuid[0], uuid[1], uuid[2], uuid[3],
113 uuid[4], uuid[5],
114 uuid[6], uuid[7],
115 uuid[8], uuid[9],
116 uuid[10], uuid[11], uuid[12], uuid[13], uuid[14], uuid[15]
117 );
118 JsonValue::String(uuid_str)
119 }
120 Value::Varint(_) => JsonValue::String(ValueFormatter::format_value(value)),
122 Value::Decimal { .. } => JsonValue::String(ValueFormatter::format_value(value)),
124 Value::Duration { .. } => JsonValue::String(ValueFormatter::format_value(value)),
126 Value::Json(j) => j.clone(),
127 Value::List(list) => {
128 let json_list: Vec<JsonValue> = list.iter().map(Self::value_to_json).collect();
129 JsonValue::Array(json_list)
130 }
131 Value::Set(set) => {
132 let json_list: Vec<JsonValue> = set.iter().map(Self::value_to_json).collect();
133 JsonValue::Array(json_list)
134 }
135 Value::Map(map) => {
136 let entries: Vec<JsonValue> = map
139 .iter()
140 .map(|(k, v)| {
141 json!({
142 "key": Self::value_to_json(k),
143 "value": Self::value_to_json(v)
144 })
145 })
146 .collect();
147 JsonValue::Array(entries)
148 }
149 Value::Tuple(tuple) => {
150 let json_list: Vec<JsonValue> = tuple.iter().map(Self::value_to_json).collect();
151 JsonValue::Array(json_list)
152 }
153 Value::Udt(udt) => {
154 let mut udt_obj = Map::new();
155 udt_obj.insert(
156 "_type".to_string(),
157 JsonValue::String(udt.type_name.clone()),
158 );
159
160 for field in &udt.fields {
162 let field_json = match &field.value {
163 Some(value) => Self::value_to_json(value),
164 None => JsonValue::Null,
165 };
166 udt_obj.insert(field.name.clone(), field_json);
167 }
168
169 JsonValue::Object(udt_obj)
170 }
171 Value::Frozen(boxed_value) => Self::value_to_json(boxed_value),
172 Value::Tombstone(info) => {
173 json!({
174 "type": "tombstone",
175 "deletion_time": info.deletion_time,
176 "tombstone_type": format!("{:?}", info.tombstone_type),
177 "ttl": info.ttl
178 })
179 }
180 Value::Inet(bytes) => {
181 if bytes.len() == 4 {
183 JsonValue::String(format!(
184 "{}.{}.{}.{}",
185 bytes[0], bytes[1], bytes[2], bytes[3]
186 ))
187 } else if bytes.len() == 16 {
188 use std::net::Ipv6Addr;
190 let mut octets = [0u8; 16];
191 octets.copy_from_slice(bytes);
192 let addr = Ipv6Addr::from(octets);
193 JsonValue::String(addr.to_string())
194 } else {
195 use base64::Engine;
197 let engine = base64::engine::general_purpose::STANDARD;
198 JsonValue::String(engine.encode(bytes))
199 }
200 }
201 }
202 }
203}
204
205pub struct StreamingJSONWriter<W: Write> {
239 writer: W,
241 columns: Vec<String>,
243 rows_written: u64,
245 first_row: bool,
247 pretty: bool,
249}
250
251impl<W: Write> StreamingJSONWriter<W> {
252 pub fn new(output: W) -> Self {
254 Self {
255 writer: output,
256 columns: Vec::new(),
257 rows_written: 0,
258 first_row: true,
259 pretty: true,
260 }
261 }
262
263 #[allow(dead_code)]
265 pub fn compact(output: W) -> Self {
266 Self {
267 writer: output,
268 columns: Vec::new(),
269 rows_written: 0,
270 first_row: true,
271 pretty: false,
272 }
273 }
274
275 #[allow(dead_code)]
277 fn row_to_json(&self, row: &QueryRow) -> JsonValue {
278 let mut row_obj = Map::new();
279
280 for col in &self.columns {
282 let value_opt = row.values.get(col);
283 let json_value = match value_opt {
284 Some(value) => JSONWriter::value_to_json(value),
285 None => JsonValue::Null,
286 };
287 row_obj.insert(col.clone(), json_value);
288 }
289
290 JsonValue::Object(row_obj)
291 }
292}
293
294impl<W: Write + Send> StreamingWriter for StreamingJSONWriter<W> {
295 fn write_header(&mut self, metadata: &QueryMetadata) -> Result<(), OutputError> {
296 self.columns = metadata.columns.iter().map(|c| c.name.clone()).collect();
298
299 if self.pretty {
301 writeln!(self.writer, "[").map_err(OutputError::Io)?;
302 } else {
303 write!(self.writer, "[").map_err(OutputError::Io)?;
304 }
305
306 Ok(())
307 }
308
309 fn write_chunk(&mut self, rows: &[QueryRow]) -> Result<usize, OutputError> {
310 for row in rows {
311 let json_obj = self.row_to_json(row);
312
313 if !self.first_row {
315 if self.pretty {
316 writeln!(self.writer, ",").map_err(OutputError::Io)?;
317 } else {
318 write!(self.writer, ",").map_err(OutputError::Io)?;
319 }
320 }
321 self.first_row = false;
322
323 if self.pretty {
325 let json_str = serde_json::to_string_pretty(&json_obj).map_err(|e| {
326 OutputError::Io(std::io::Error::new(std::io::ErrorKind::Other, e))
327 })?;
328 for line in json_str.lines() {
330 write!(self.writer, " {}", line).map_err(OutputError::Io)?;
331 writeln!(self.writer).map_err(OutputError::Io)?;
332 }
333 } else {
334 let json_str = serde_json::to_string(&json_obj).map_err(|e| {
335 OutputError::Io(std::io::Error::new(std::io::ErrorKind::Other, e))
336 })?;
337 write!(self.writer, "{}", json_str).map_err(OutputError::Io)?;
338 }
339
340 self.rows_written += 1;
341 }
342
343 Ok(rows.len())
344 }
345
346 fn finalize(&mut self) -> Result<(), OutputError> {
347 if self.pretty {
349 writeln!(self.writer, "]").map_err(OutputError::Io)?;
350 } else {
351 write!(self.writer, "]").map_err(OutputError::Io)?;
352 }
353
354 self.writer.flush().map_err(OutputError::Io)
355 }
356
357 fn rows_written(&self) -> u64 {
358 self.rows_written
359 }
360}
361
362#[cfg(test)]
363mod tests {
364 use super::*;
365 use cqlite_core::query::ColumnInfo;
366 use cqlite_core::{RowKey, Value};
367 use std::collections::HashMap;
368
369 fn default_config() -> OutputConfig {
370 OutputConfig::default()
371 }
372
373 #[test]
374 fn test_deterministic_key_ordering() {
375 let mut result = QueryResult::new();
377
378 result.metadata.columns = vec![
380 ColumnInfo::new(
381 "c".to_string(),
382 cqlite_core::types::DataType::Integer,
383 false,
384 0,
385 ),
386 ColumnInfo::new(
387 "b".to_string(),
388 cqlite_core::types::DataType::Integer,
389 false,
390 1,
391 ),
392 ColumnInfo::new(
393 "a".to_string(),
394 cqlite_core::types::DataType::Integer,
395 false,
396 2,
397 ),
398 ];
399
400 let mut values = HashMap::new();
402 values.insert("a".to_string(), Value::Integer(1));
403 values.insert("b".to_string(), Value::Integer(2));
404 values.insert("c".to_string(), Value::Integer(3));
405
406 let row = QueryRow::with_values(RowKey::new(vec![1]), values);
407 result.rows.push(row);
408
409 let json_str = JSONWriter::write(&result, &default_config()).unwrap();
411
412 let parsed: Vec<serde_json::Value> = serde_json::from_str(&json_str).unwrap();
414 assert_eq!(parsed.len(), 1);
415
416 let row_obj = parsed[0].as_object().unwrap();
417
418 let keys: Vec<&String> = row_obj.keys().collect();
420 assert_eq!(keys, vec!["c", "b", "a"], "Keys must be in column order");
421
422 assert!(
424 json_str.find("\"c\"").unwrap() < json_str.find("\"b\"").unwrap(),
425 "Key 'c' must appear before 'b' in JSON string"
426 );
427 assert!(
428 json_str.find("\"b\"").unwrap() < json_str.find("\"a\"").unwrap(),
429 "Key 'b' must appear before 'a' in JSON string"
430 );
431 }
432
433 #[test]
434 fn test_null_values() {
435 let mut result = QueryResult::new();
436 result.metadata.columns = vec![ColumnInfo::new(
437 "nullable_col".to_string(),
438 cqlite_core::types::DataType::Text,
439 true,
440 0,
441 )];
442
443 let values = HashMap::new(); let row = QueryRow::with_values(RowKey::new(vec![1]), values);
446 result.rows.push(row);
447
448 let json_str = JSONWriter::write(&result, &default_config()).unwrap();
449 assert!(
450 json_str.contains("null"),
451 "Missing values should be JSON null"
452 );
453 }
454
455 #[test]
456 fn test_value_types() {
457 let mut result = QueryResult::new();
458 result.metadata.columns = vec![
459 ColumnInfo::new(
460 "int_col".to_string(),
461 cqlite_core::types::DataType::Integer,
462 false,
463 0,
464 ),
465 ColumnInfo::new(
466 "text_col".to_string(),
467 cqlite_core::types::DataType::Text,
468 false,
469 1,
470 ),
471 ColumnInfo::new(
472 "bool_col".to_string(),
473 cqlite_core::types::DataType::Boolean,
474 false,
475 2,
476 ),
477 ];
478
479 let mut values = HashMap::new();
480 values.insert("int_col".to_string(), Value::Integer(42));
481 values.insert("text_col".to_string(), Value::Text("hello".to_string()));
482 values.insert("bool_col".to_string(), Value::Boolean(true));
483
484 let row = QueryRow::with_values(RowKey::new(vec![1]), values);
485 result.rows.push(row);
486
487 let json_str = JSONWriter::write(&result, &default_config()).unwrap();
488
489 assert!(json_str.contains("42"));
491 assert!(json_str.contains("\"hello\""));
492 assert!(json_str.contains("true"));
493 }
494
495 #[test]
496 fn test_empty_result() {
497 let result = QueryResult::new();
498 let json_str = JSONWriter::write(&result, &default_config()).unwrap();
499
500 let parsed: Vec<serde_json::Value> = serde_json::from_str(&json_str).unwrap();
502 assert_eq!(parsed.len(), 0);
503 }
504
505 #[test]
506 fn test_multiple_rows() {
507 let mut result = QueryResult::new();
508 result.metadata.columns = vec![ColumnInfo::new(
509 "id".to_string(),
510 cqlite_core::types::DataType::Integer,
511 false,
512 0,
513 )];
514
515 for i in 1..=3 {
517 let mut values = HashMap::new();
518 values.insert("id".to_string(), Value::Integer(i));
519 let row = QueryRow::with_values(RowKey::new(vec![i as u8]), values);
520 result.rows.push(row);
521 }
522
523 let json_str = JSONWriter::write(&result, &default_config()).unwrap();
524 let parsed: Vec<serde_json::Value> = serde_json::from_str(&json_str).unwrap();
525 assert_eq!(parsed.len(), 3);
526 }
527
528 #[test]
529 fn test_config_limit() {
530 let mut result = QueryResult::new();
531 result.metadata.columns = vec![ColumnInfo::new(
532 "id".to_string(),
533 cqlite_core::types::DataType::Integer,
534 false,
535 0,
536 )];
537
538 for i in 1..=10 {
540 let mut values = HashMap::new();
541 values.insert("id".to_string(), Value::Integer(i));
542 let row = QueryRow::with_values(RowKey::new(vec![i as u8]), values);
543 result.rows.push(row);
544 }
545
546 let config = OutputConfig {
548 color_enabled: true,
549 limit: Some(3),
550 page_size: None,
551 target: crate::output::OutputTarget::Stdout,
552 overwrite: false,
553 };
554 let json_str = JSONWriter::write(&result, &config).unwrap();
555 let parsed: Vec<serde_json::Value> = serde_json::from_str(&json_str).unwrap();
556
557 assert_eq!(parsed.len(), 3, "Limit should restrict output to 3 rows");
559 }
560
561 #[test]
562 fn test_uuid_formatting() {
563 let uuid_bytes = [
564 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66,
565 0x77, 0x88,
566 ];
567
568 let json_val = JSONWriter::value_to_json(&Value::Uuid(uuid_bytes));
569 let uuid_str = json_val.as_str().unwrap();
570
571 assert_eq!(uuid_str, "12345678-9abc-def0-1122-334455667788");
573 }
574
575 #[test]
576 fn test_list_value() {
577 let list_value = Value::List(vec![
578 Value::Integer(1),
579 Value::Integer(2),
580 Value::Integer(3),
581 ]);
582
583 let json_val = JSONWriter::value_to_json(&list_value);
584 assert!(json_val.is_array());
585
586 let array = json_val.as_array().unwrap();
587 assert_eq!(array.len(), 3);
588 assert_eq!(array[0], serde_json::json!(1));
589 assert_eq!(array[1], serde_json::json!(2));
590 assert_eq!(array[2], serde_json::json!(3));
591 }
592
593 #[test]
594 fn test_map_value() {
595 let map_value = Value::Map(vec![
596 (Value::Text("key1".to_string()), Value::Integer(1)),
597 (Value::Text("key2".to_string()), Value::Integer(2)),
598 ]);
599
600 let json_val = JSONWriter::value_to_json(&map_value);
601 assert!(json_val.is_array());
602
603 let array = json_val.as_array().unwrap();
604 assert_eq!(array.len(), 2);
605
606 let entry1 = array[0].as_object().unwrap();
608 assert_eq!(entry1.get("key").unwrap().as_str().unwrap(), "key1");
609 assert_eq!(entry1.get("value").unwrap().as_i64().unwrap(), 1);
610 }
611
612 #[test]
615 fn test_blob_formatting() {
616 let blob = Value::Blob(vec![0xDE, 0xAD, 0xBE, 0xEF]);
617 let json_val = JSONWriter::value_to_json(&blob);
618 assert_eq!(json_val.as_str().unwrap(), "0xdeadbeef");
620 }
621
622 #[test]
623 fn test_timestamp_formatting() {
624 let timestamp = Value::Timestamp(1673778645123);
626 let json_val = JSONWriter::value_to_json(×tamp);
627 let formatted = json_val.as_str().unwrap();
628 assert!(formatted.starts_with("2023-01-15"));
630 assert!(formatted.contains("10:30:45"));
631 assert!(formatted.ends_with("+0000"));
632 }
633
634 #[test]
635 fn test_date_formatting() {
636 let date = Value::Date(19358);
638 let json_val = JSONWriter::value_to_json(&date);
639 assert_eq!(json_val.as_str().unwrap(), "2023-01-01");
641 }
642
643 #[test]
644 fn test_time_formatting() {
645 let nanos =
647 14 * 3600 * 1_000_000_000 + 30 * 60 * 1_000_000_000 + 45 * 1_000_000_000 + 123_456_789;
648 let time = Value::Time(nanos);
649 let json_val = JSONWriter::value_to_json(&time);
650 assert_eq!(json_val.as_str().unwrap(), "14:30:45.123456789");
652 }
653
654 #[test]
655 fn test_varint_formatting() {
656 let varint = Value::Varint(vec![0x01, 0x00]); let json_val = JSONWriter::value_to_json(&varint);
658 assert_eq!(json_val.as_str().unwrap(), "256");
660 }
661
662 #[test]
663 fn test_decimal_formatting() {
664 let decimal = Value::Decimal {
666 scale: 2,
667 unscaled: vec![0x30, 0x39],
668 };
669 let json_val = JSONWriter::value_to_json(&decimal);
670 let formatted = json_val.as_str().unwrap();
672 assert!(formatted.contains('.'));
673 }
674
675 #[test]
676 fn test_duration_formatting() {
677 let duration = Value::Duration {
678 months: 2,
679 days: 15,
680 nanos: 123456789,
681 };
682 let json_val = JSONWriter::value_to_json(&duration);
683 assert_eq!(json_val.as_str().unwrap(), "2mo15d123456789ns");
685 }
686}