1use 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}