reifydb_client/
session.rs

1// Copyright (c) reifydb.com 2025
2// This file is licensed under the MIT
3
4use num_bigint;
5use reifydb_type::{
6	Blob, Date, DateTime, Decimal, Error, IdentityId, Int, RowNumber, Time, Uint, Uuid7, err, parse_uuid4,
7	parse_uuid7, util::hex,
8};
9
10use crate::{
11	OrderedF32, OrderedF64, Type, Value,
12	domain::{Frame, FrameColumn},
13};
14
15/// Result type for command operations
16#[derive(Debug)]
17pub struct CommandResult {
18	pub frames: Vec<Frame>,
19}
20
21/// Result type for query operations
22#[derive(Debug)]
23pub struct QueryResult {
24	pub frames: Vec<Frame>,
25}
26
27// Helper functions for parsing responses - made public for ws module
28pub fn parse_command_response(response: crate::Response) -> Result<CommandResult, Error> {
29	match response.payload {
30		crate::ResponsePayload::Command(cmd_response) => Ok(CommandResult {
31			frames: convert_command_response(cmd_response),
32		}),
33		crate::ResponsePayload::Err(err) => {
34			err!(err.diagnostic)
35		}
36		other => {
37			println!("Unexpected execute response: {:?}", other);
38			panic!("Unexpected execute response type")
39		}
40	}
41}
42
43pub fn parse_query_response(response: crate::Response) -> Result<QueryResult, Error> {
44	match response.payload {
45		crate::ResponsePayload::Query(query_response) => {
46			let frames = convert_query_response(query_response);
47			Ok(QueryResult {
48				frames,
49			})
50		}
51		crate::ResponsePayload::Err(err) => {
52			err!(err.diagnostic)
53		}
54		other => {
55			println!("Unexpected execute response: {:?}", other);
56			panic!("Unexpected execute response type")
57		}
58	}
59}
60
61pub fn convert_command_response(payload: crate::CommandResponse) -> Vec<Frame> {
62	let mut result = Vec::new();
63
64	for frame in payload.frames {
65		let columns = frame
66			.columns
67			.into_iter()
68			.map(|col| FrameColumn {
69				namespace: col.namespace,
70				store: col.store,
71				name: col.name,
72				r#type: col.r#type,
73				data: convert_column_values(col.r#type, col.data),
74			})
75			.collect();
76
77		result.push(Frame::new(frame.row_numbers, columns))
78	}
79
80	result
81}
82
83pub fn convert_query_response(payload: crate::QueryResponse) -> Vec<Frame> {
84	let mut result = Vec::new();
85
86	for frame in payload.frames {
87		let columns = frame
88			.columns
89			.into_iter()
90			.map(|col| FrameColumn {
91				namespace: col.namespace,
92				store: col.store,
93				name: col.name,
94				r#type: col.r#type,
95				data: convert_column_values(col.r#type, col.data),
96			})
97			.collect();
98
99		result.push(Frame::new(frame.row_numbers, columns))
100	}
101
102	result
103}
104
105fn convert_column_values(target: Type, data: Vec<String>) -> Vec<Value> {
106	data.into_iter().map(|s| parse_value_from_string(&s, &target)).collect()
107}
108
109fn parse_value_from_string(s: &str, value_type: &Type) -> Value {
110	if s == "⟪undefined⟫" {
111		return Value::Undefined;
112	}
113
114	match value_type {
115		Type::Undefined => Value::Undefined,
116		Type::Boolean => match s {
117			"true" => Value::Boolean(true),
118			"false" => Value::Boolean(false),
119			_ => Value::Undefined,
120		},
121		Type::Float4 => s
122			.parse::<f32>()
123			.ok()
124			.and_then(|f| OrderedF32::try_from(f).ok())
125			.map(Value::Float4)
126			.unwrap_or(Value::Undefined),
127		Type::Float8 => s
128			.parse::<f64>()
129			.ok()
130			.and_then(|f| OrderedF64::try_from(f).ok())
131			.map(Value::Float8)
132			.unwrap_or(Value::Undefined),
133		Type::Int1 => s.parse::<i8>().map(Value::Int1).unwrap_or(Value::Undefined),
134		Type::Int2 => s.parse::<i16>().map(Value::Int2).unwrap_or(Value::Undefined),
135		Type::Int4 => s.parse::<i32>().map(Value::Int4).unwrap_or(Value::Undefined),
136		Type::Int8 => s.parse::<i64>().map(Value::Int8).unwrap_or(Value::Undefined),
137		Type::Int16 => s.parse::<i128>().map(Value::Int16).unwrap_or(Value::Undefined),
138		Type::Uint1 => s.parse::<u8>().map(Value::Uint1).unwrap_or(Value::Undefined),
139		Type::Uint2 => s.parse::<u16>().map(Value::Uint2).unwrap_or(Value::Undefined),
140		Type::Uint4 => s.parse::<u32>().map(Value::Uint4).unwrap_or(Value::Undefined),
141		Type::Uint8 => s.parse::<u64>().map(Value::Uint8).unwrap_or(Value::Undefined),
142		Type::Uint16 => s.parse::<u128>().map(Value::Uint16).unwrap_or(Value::Undefined),
143		Type::Utf8 => Value::Utf8(s.to_string()),
144		Type::Date => {
145			// Parse date from ISO format (YYYY-MM-DD)
146			let parts: Vec<&str> = s.split('-').collect();
147			if parts.len() == 3 {
148				let year = parts[0].parse::<i32>().unwrap_or(1970);
149				let month = parts[1].parse::<u32>().unwrap_or(1);
150				let day = parts[2].parse::<u32>().unwrap_or(1);
151				Date::from_ymd(year, month, day).map(Value::Date).unwrap_or(Value::Undefined)
152			} else {
153				Value::Undefined
154			}
155		}
156		Type::DateTime => {
157			// Try parsing as timestamp first
158			if let Ok(timestamp) = s.parse::<i64>() {
159				DateTime::from_timestamp(timestamp).map(Value::DateTime).unwrap_or(Value::Undefined)
160			} else {
161				// For now, store as string - proper RFC3339
162				// parsing would need chrono
163				Value::Utf8(s.to_string())
164			}
165		}
166		Type::Time => {
167			// Parse time from HH:MM:SS.nnnnnnnnn format
168			let parts: Vec<&str> = s.split(':').collect();
169			if parts.len() >= 3 {
170				let hour = parts[0].parse::<u32>().unwrap_or(0);
171				let min = parts[1].parse::<u32>().unwrap_or(0);
172
173				// Handle seconds and nanoseconds
174				let sec_parts: Vec<&str> = parts[2].split('.').collect();
175				let sec = sec_parts[0].parse::<u32>().unwrap_or(0);
176
177				let nano = if sec_parts.len() > 1 {
178					let frac_str = sec_parts[1];
179					let padded = if frac_str.len() < 9 {
180						format!("{:0<9}", frac_str)
181					} else {
182						frac_str[..9].to_string()
183					};
184					padded.parse::<u32>().unwrap_or(0)
185				} else {
186					0
187				};
188
189				Time::from_hms_nano(hour, min, sec, nano).map(Value::Time).unwrap_or(Value::Undefined)
190			} else {
191				Value::Undefined
192			}
193		}
194		Type::Duration => {
195			// For now, store as string - proper ISO 8601 duration
196			// parsing would need additional logic
197			Value::Utf8(s.to_string())
198		}
199		Type::RowNumber => {
200			if let Ok(id) = s.parse::<u64>() {
201				Value::RowNumber(RowNumber::new(id))
202			} else {
203				Value::Undefined
204			}
205		}
206		Type::Uuid4 => {
207			// Try to parse UUID
208			if let Ok(uuid) = parse_uuid4(s) {
209				Value::Uuid4(uuid)
210			} else {
211				Value::Undefined
212			}
213		}
214		Type::Uuid7 => {
215			// Try to parse UUID
216			if let Ok(uuid) = parse_uuid7(s) {
217				Value::Uuid7(uuid)
218			} else {
219				Value::Undefined
220			}
221		}
222		Type::IdentityId => {
223			// Try to parse UUID for IdentityId
224			if let Ok(uuid) = parse_uuid7(s) {
225				Value::IdentityId(IdentityId::from(Uuid7::from(uuid)))
226			} else {
227				Value::Undefined
228			}
229		}
230		Type::Blob => {
231			// Parse hex string (assuming 0x prefix)
232			if s.starts_with("0x") {
233				if let Ok(bytes) = hex::decode(&s[2..]) {
234					Value::Blob(Blob::new(bytes))
235				} else {
236					Value::Undefined
237				}
238			} else {
239				Value::Undefined
240			}
241		}
242		Type::Int => s
243			.parse::<num_bigint::BigInt>()
244			.ok()
245			.map(|big_int| Value::Int(Int::from(big_int)))
246			.unwrap_or(Value::Undefined),
247		Type::Uint => s
248			.parse::<num_bigint::BigInt>()
249			.ok()
250			.map(|big_int| Value::Uint(Uint::from(big_int)))
251			.unwrap_or(Value::Undefined),
252		Type::Decimal {
253			..
254		} => {
255			// Parse as Decimal
256			if let Ok(decimal) = s.parse::<Decimal>() {
257				Value::Decimal(decimal)
258			} else {
259				Value::Undefined
260			}
261		}
262		Type::Any => Value::Undefined,
263	}
264}