Skip to main content

reifydb_codec/json/
from.rs

1// SPDX-License-Identifier: Apache-2.0
2// Copyright (c) 2026 ReifyDB
3
4use reifydb_value::{
5	fragment::Fragment,
6	util::bitvec::BitVec,
7	value::{
8		Value,
9		blob::Blob,
10		container::{
11			blob::BlobContainer, bool::BoolContainer, identity_id::IdentityIdContainer,
12			number::NumberContainer, temporal::TemporalContainer, utf8::Utf8Container, uuid::UuidContainer,
13		},
14		date::Date,
15		datetime::DateTime,
16		decimal::{Decimal, parse::parse_decimal},
17		diff_type::DiffType,
18		duration::Duration,
19		frame::{column::FrameColumn, data::FrameColumnData, frame::Frame},
20		identity::IdentityId,
21		int::{Int, parse::parse_int},
22		ordered_f32::OrderedF32,
23		ordered_f64::OrderedF64,
24		row_number::RowNumber,
25		system_columns::SystemColumns,
26		temporal::parse::{
27			date::parse_date, datetime::parse_datetime, duration::parse_duration, time::parse_time,
28		},
29		time::Time,
30		uint::{Uint, parse::parse_uint},
31		uuid::{
32			Uuid4, Uuid7,
33			parse::{parse_uuid4, parse_uuid7},
34		},
35		value_type::ValueType,
36	},
37};
38use serde_json::{Error, Value as JsonValue, from_str, from_value};
39
40use crate::{
41	error::DecodeError,
42	json::{is_none_marker, none_marker_depth, types::ResponseFrame},
43	tag::peel_options,
44};
45
46pub fn frames_from_json(json: &str) -> Result<Vec<Frame>, Error> {
47	let response_frames: Vec<ResponseFrame> = from_str(json)?;
48	Ok(response_frames.into_iter().map(response_frame_to_frame).collect())
49}
50
51pub fn convert_envelope_response(body: JsonValue) -> Vec<Frame> {
52	let frames_value = match body {
53		JsonValue::Object(ref map) => map.get("frames"),
54		_ => None,
55	};
56
57	let response_frames: Vec<ResponseFrame> = match frames_value {
58		Some(v) => from_value(v.clone()).unwrap_or_default(),
59		None => return Vec::new(),
60	};
61
62	response_frames.into_iter().map(response_frame_to_frame).collect()
63}
64
65fn response_frame_to_frame(frame: ResponseFrame) -> Frame {
66	let columns = frame
67		.columns
68		.into_iter()
69		.map(|col| FrameColumn {
70			name: col.name,
71			data: convert_column_to_data(col.r#type.0, col.payload),
72		})
73		.collect();
74
75	let row_numbers = frame.row_numbers.into_iter().map(RowNumber::new).collect();
76	let created_at = frame.created_at.iter().filter_map(|s| parse_datetime(Fragment::internal(s)).ok()).collect();
77	let updated_at = frame.updated_at.iter().filter_map(|s| parse_datetime(Fragment::internal(s)).ok()).collect();
78	let time = frame.time.iter().filter_map(|s| parse_datetime(Fragment::internal(s)).ok()).collect();
79
80	Frame {
81		system: SystemColumns::new(row_numbers, Vec::new(), created_at, updated_at, time),
82		columns,
83		op: frame.op.and_then(DiffType::from_u8),
84	}
85}
86
87pub fn parse_value(ty: &ValueType, text: &str) -> Result<Value, DecodeError> {
88	let (base, depth) = peel_options(ty);
89	match none_marker_depth(text) {
90		Some(_) if depth == 0 => Err(DecodeError::InvalidData(format!("none marker for non-Option type {ty}"))),
91		Some(wrapped) if wrapped >= depth => Err(DecodeError::InvalidData(format!(
92			"none marker depth {wrapped} exceeds the {depth} Option layers of type {ty}"
93		))),
94		Some(wrapped) => Ok(Value::None {
95			inner: strip_options(ty, wrapped + 1),
96		}),
97		None => parse_base(base, text)
98			.ok_or_else(|| DecodeError::InvalidData(format!("cannot parse '{text}' as {ty}"))),
99	}
100}
101
102fn strip_options(ty: &ValueType, layers: u32) -> ValueType {
103	let mut inner = ty;
104	for _ in 0..layers {
105		if let ValueType::Option(next) = inner {
106			inner = next;
107		}
108	}
109	inner.clone()
110}
111
112fn parse_base(base: &ValueType, text: &str) -> Option<Value> {
113	match base {
114		ValueType::Boolean => text.parse().ok().map(Value::Boolean),
115		ValueType::Float4 => parse_float4(text).map(Value::Float4),
116		ValueType::Float8 => parse_float8(text).map(Value::Float8),
117		ValueType::Int1 => text.parse().ok().map(Value::Int1),
118		ValueType::Int2 => text.parse().ok().map(Value::Int2),
119		ValueType::Int4 => text.parse().ok().map(Value::Int4),
120		ValueType::Int8 => text.parse().ok().map(Value::Int8),
121		ValueType::Int16 => text.parse().ok().map(Value::Int16),
122		ValueType::Utf8 => Some(Value::Utf8(text.to_string())),
123		ValueType::Uint1 => text.parse().ok().map(Value::Uint1),
124		ValueType::Uint2 => text.parse().ok().map(Value::Uint2),
125		ValueType::Uint4 => text.parse().ok().map(Value::Uint4),
126		ValueType::Uint8 => text.parse().ok().map(Value::Uint8),
127		ValueType::Uint16 => text.parse().ok().map(Value::Uint16),
128		ValueType::Date => parse_date_text(text).map(Value::Date),
129		ValueType::DateTime => parse_datetime_text(text).map(Value::DateTime),
130		ValueType::Time => parse_time_text(text).map(Value::Time),
131		ValueType::Duration => parse_duration_text(text).map(Value::Duration),
132		ValueType::Uuid4 => parse_uuid4_text(text).map(Value::Uuid4),
133		ValueType::Uuid7 => parse_uuid7_text(text).map(Value::Uuid7),
134		ValueType::IdentityId => parse_identity_id(text).map(Value::IdentityId),
135		ValueType::Blob => parse_blob(text).map(Value::Blob),
136		ValueType::Int => parse_int_text(text).map(Value::Int),
137		ValueType::Uint => parse_uint_text(text).map(Value::Uint),
138		ValueType::Decimal => parse_decimal_text(text).map(Value::Decimal),
139		ValueType::Option(inner) => parse_base(inner, text),
140		ValueType::Any
141		| ValueType::DictionaryId
142		| ValueType::List(_)
143		| ValueType::Record(_)
144		| ValueType::Tuple(_) => Some(Value::Utf8(text.to_string())),
145	}
146}
147
148fn parse_float4(text: &str) -> Option<OrderedF32> {
149	OrderedF32::try_from(text.parse::<f32>().ok()?).ok()
150}
151
152fn parse_float8(text: &str) -> Option<OrderedF64> {
153	OrderedF64::try_from(text.parse::<f64>().ok()?).ok()
154}
155
156fn parse_date_text(text: &str) -> Option<Date> {
157	parse_date(Fragment::internal(text)).ok()
158}
159
160fn parse_datetime_text(text: &str) -> Option<DateTime> {
161	parse_datetime(Fragment::internal(text))
162		.ok()
163		.or_else(|| DateTime::from_epoch_secs(text.parse::<i64>().ok()?).ok())
164}
165
166fn parse_time_text(text: &str) -> Option<Time> {
167	parse_time(Fragment::internal(text)).ok()
168}
169
170fn parse_duration_text(text: &str) -> Option<Duration> {
171	parse_duration(Fragment::internal(text)).ok()
172}
173
174fn parse_uuid4_text(text: &str) -> Option<Uuid4> {
175	parse_uuid4(Fragment::internal(text)).ok()
176}
177
178fn parse_uuid7_text(text: &str) -> Option<Uuid7> {
179	parse_uuid7(Fragment::internal(text)).ok()
180}
181
182fn parse_identity_id(text: &str) -> Option<IdentityId> {
183	parse_uuid7_text(text).map(IdentityId::from)
184}
185
186fn parse_blob(text: &str) -> Option<Blob> {
187	Blob::from_hex(Fragment::internal(text)).ok()
188}
189
190fn parse_int_text(text: &str) -> Option<Int> {
191	parse_int(Fragment::internal(text)).ok()
192}
193
194fn parse_uint_text(text: &str) -> Option<Uint> {
195	parse_uint(Fragment::internal(text)).ok()
196}
197
198fn parse_decimal_text(text: &str) -> Option<Decimal> {
199	parse_decimal(Fragment::internal(text)).ok()
200}
201
202fn cells<T: Clone>(data: Vec<String>, placeholder: T, parse: impl Fn(&str) -> Option<T>) -> Vec<T> {
203	data.into_iter()
204		.map(|s| {
205			if is_none_marker(&s) {
206				placeholder.clone()
207			} else {
208				parse(&s).unwrap_or_else(|| placeholder.clone())
209			}
210		})
211		.collect()
212}
213
214pub fn convert_column_to_data(target: ValueType, data: Vec<String>) -> FrameColumnData {
215	match target {
216		ValueType::Option(_) => {
217			let (base, depth) = peel_options(&target);
218			let depth = depth as usize;
219			let mut layers = vec![vec![true; data.len()]; depth];
220			for (row, payload) in data.iter().enumerate() {
221				if let Some(wrapped) = none_marker_depth(payload) {
222					let first_undefined = (wrapped as usize).min(depth - 1);
223					for layer in &mut layers[first_undefined..] {
224						layer[row] = false;
225					}
226				}
227			}
228			let base = convert_column_to_data(base.clone(), data);
229			layers.into_iter().rev().fold(base, |inner, layer| FrameColumnData::Option {
230				inner: Box::new(inner),
231				bitvec: BitVec::from_slice(&layer),
232			})
233		}
234		ValueType::Boolean => FrameColumnData::Bool(BoolContainer::new(cells(data, false, |s| s.parse().ok()))),
235		ValueType::Float4 => {
236			FrameColumnData::Float4(NumberContainer::new(cells(data, 0.0f32, |s| s.parse().ok())))
237		}
238		ValueType::Float8 => {
239			FrameColumnData::Float8(NumberContainer::new(cells(data, 0.0f64, |s| s.parse().ok())))
240		}
241		ValueType::Int1 => FrameColumnData::Int1(NumberContainer::new(cells(data, 0i8, |s| s.parse().ok()))),
242		ValueType::Int2 => FrameColumnData::Int2(NumberContainer::new(cells(data, 0i16, |s| s.parse().ok()))),
243		ValueType::Int4 => FrameColumnData::Int4(NumberContainer::new(cells(data, 0i32, |s| s.parse().ok()))),
244		ValueType::Int8 => FrameColumnData::Int8(NumberContainer::new(cells(data, 0i64, |s| s.parse().ok()))),
245		ValueType::Int16 => {
246			FrameColumnData::Int16(NumberContainer::new(cells(data, 0i128, |s| s.parse().ok())))
247		}
248		ValueType::Uint1 => FrameColumnData::Uint1(NumberContainer::new(cells(data, 0u8, |s| s.parse().ok()))),
249		ValueType::Uint2 => FrameColumnData::Uint2(NumberContainer::new(cells(data, 0u16, |s| s.parse().ok()))),
250		ValueType::Uint4 => FrameColumnData::Uint4(NumberContainer::new(cells(data, 0u32, |s| s.parse().ok()))),
251		ValueType::Uint8 => FrameColumnData::Uint8(NumberContainer::new(cells(data, 0u64, |s| s.parse().ok()))),
252		ValueType::Uint16 => {
253			FrameColumnData::Uint16(NumberContainer::new(cells(data, 0u128, |s| s.parse().ok())))
254		}
255		ValueType::Date => FrameColumnData::Date(TemporalContainer::new(cells(
256			data,
257			Date::from_ymd(1970, 1, 1).unwrap(),
258			parse_date_text,
259		))),
260		ValueType::DateTime => FrameColumnData::DateTime(TemporalContainer::new(cells(
261			data,
262			DateTime::from_epoch_secs(0).unwrap(),
263			parse_datetime_text,
264		))),
265		ValueType::Time => FrameColumnData::Time(TemporalContainer::new(cells(
266			data,
267			Time::from_hms(0, 0, 0).unwrap(),
268			parse_time_text,
269		))),
270		ValueType::Duration => FrameColumnData::Duration(TemporalContainer::new(cells(
271			data,
272			Duration::zero(),
273			parse_duration_text,
274		))),
275		ValueType::Uuid4 => FrameColumnData::Uuid4(UuidContainer::new(cells(
276			data,
277			parse_uuid4_text("00000000-0000-4000-8000-000000000000").unwrap(),
278			parse_uuid4_text,
279		))),
280		ValueType::Uuid7 => FrameColumnData::Uuid7(UuidContainer::new(cells(
281			data,
282			parse_uuid7_text("00000000-0000-7000-8000-000000000000").unwrap(),
283			parse_uuid7_text,
284		))),
285		ValueType::IdentityId => FrameColumnData::IdentityId(IdentityIdContainer::new(cells(
286			data,
287			parse_identity_id("00000000-0000-7000-8000-000000000000").unwrap(),
288			parse_identity_id,
289		))),
290		ValueType::Blob => {
291			FrameColumnData::Blob(BlobContainer::new(cells(data, Blob::new(vec![]), parse_blob)))
292		}
293		ValueType::Int => FrameColumnData::Int(NumberContainer::new(cells(data, Int::zero(), parse_int_text))),
294		ValueType::Uint => {
295			FrameColumnData::Uint(NumberContainer::new(cells(data, Uint::zero(), parse_uint_text)))
296		}
297		ValueType::Decimal => {
298			FrameColumnData::Decimal(NumberContainer::new(cells(data, Decimal::zero(), parse_decimal_text)))
299		}
300		ValueType::Utf8
301		| ValueType::Any
302		| ValueType::DictionaryId
303		| ValueType::List(_)
304		| ValueType::Record(_)
305		| ValueType::Tuple(_) => {
306			FrameColumnData::Utf8(Utf8Container::new(cells(data, String::new(), |s| Some(s.to_string()))))
307		}
308	}
309}