reifydb_sub_server/
response.rs

1// Copyright (c) reifydb.com 2025
2// This file is licensed under the AGPL-3.0-or-later
3
4//! Response types and frame conversion for HTTP and WebSocket servers.
5
6use reifydb_core::Frame;
7use reifydb_type::{Type, Value};
8use serde::{Deserialize, Serialize};
9
10/// A response frame containing query/command results.
11#[derive(Debug, Clone, Serialize, Deserialize)]
12pub struct ResponseFrame {
13	pub row_numbers: Vec<u64>,
14	pub columns: Vec<ResponseColumn>,
15}
16
17/// A column in a response frame.
18#[derive(Debug, Clone, Serialize, Deserialize)]
19pub struct ResponseColumn {
20	pub namespace: Option<String>,
21	pub store: Option<String>,
22	pub name: String,
23	#[serde(rename = "type")]
24	pub r#type: Type,
25	pub data: Vec<String>,
26}
27
28/// Convert database result frames to response frames.
29///
30/// This function converts the internal `Frame` type to the serializable
31/// `ResponseFrame` type expected by clients.
32pub fn convert_frames(frames: Vec<Frame>) -> Vec<ResponseFrame> {
33	let mut result = Vec::new();
34
35	for frame in frames {
36		let row_numbers: Vec<u64> = frame.row_numbers.iter().map(|rn| rn.value()).collect();
37
38		let mut columns = Vec::new();
39
40		for column in frame.iter() {
41			let column_data: Vec<String> = column
42				.data
43				.iter()
44				.map(|value| match value {
45					Value::Undefined => "⟪undefined⟫".to_string(),
46					Value::Blob(b) => b.to_hex(),
47					_ => value.to_string(),
48				})
49				.collect();
50
51			columns.push(ResponseColumn {
52				namespace: column.namespace.clone(),
53				store: column.source.clone(),
54				name: column.name.clone(),
55				r#type: column.data.get_type(),
56				data: column_data,
57			});
58		}
59
60		result.push(ResponseFrame {
61			row_numbers,
62			columns,
63		});
64	}
65
66	result
67}