Skip to main content

reifydb_engine/expression/cast/
uuid.rs

1// SPDX-License-Identifier: Apache-2.0
2// Copyright (c) 2025 ReifyDB
3
4use reifydb_core::value::column::data::ColumnData;
5use reifydb_type::{
6	error::{Error, TypeError},
7	fragment::{Fragment, LazyFragment},
8	value::{
9		container::{utf8::Utf8Container, uuid::UuidContainer},
10		r#type::Type,
11		uuid::{
12			Uuid4, Uuid7,
13			parse::{parse_uuid4, parse_uuid7},
14		},
15	},
16};
17
18use crate::{Result, error::CastError};
19
20pub fn to_uuid(data: &ColumnData, target: Type, lazy_fragment: impl LazyFragment) -> Result<ColumnData> {
21	match data {
22		ColumnData::Utf8 {
23			container,
24			..
25		} => from_text(container, target, lazy_fragment),
26		ColumnData::Uuid4(container) => from_uuid4(container, target, lazy_fragment),
27		ColumnData::Uuid7(container) => from_uuid7(container, target, lazy_fragment),
28		_ => {
29			let source_type = data.get_type();
30			Err(TypeError::UnsupportedCast {
31				from: source_type,
32				to: target,
33				fragment: lazy_fragment.fragment(),
34			}
35			.into())
36		}
37	}
38}
39
40#[inline]
41fn from_text(container: &Utf8Container, target: Type, lazy_fragment: impl LazyFragment) -> Result<ColumnData> {
42	match target {
43		Type::Uuid4 => to_uuid4(container, lazy_fragment),
44		Type::Uuid7 => to_uuid7(container, lazy_fragment),
45		_ => {
46			let source_type = Type::Utf8;
47			Err(TypeError::UnsupportedCast {
48				from: source_type,
49				to: target,
50				fragment: lazy_fragment.fragment(),
51			}
52			.into())
53		}
54	}
55}
56
57macro_rules! impl_to_uuid {
58	($fn_name:ident, $type:ty, $target_type:expr, $parse_fn:expr) => {
59		#[inline]
60		fn $fn_name(container: &Utf8Container, lazy_fragment: impl LazyFragment) -> Result<ColumnData> {
61			let mut out = ColumnData::with_capacity($target_type, container.len());
62			for idx in 0..container.len() {
63				if container.is_defined(idx) {
64					let val = &container[idx];
65					let temp_fragment = Fragment::internal(val.as_str());
66
67					let parsed = $parse_fn(temp_fragment).map_err(|mut e| {
68						// Get the original fragment for error reporting
69						let proper_fragment = lazy_fragment.fragment();
70
71						// Replace the error's origin with the proper RQL fragment
72						// This ensures the error shows "at col" not the actual value
73						e.0.with_fragment(proper_fragment.clone());
74
75						// Wrap in cast error with the original fragment
76						Error::from(CastError::InvalidUuid {
77							fragment: proper_fragment,
78							target: $target_type,
79							cause: e.0,
80						})
81					})?;
82
83					out.push::<$type>(parsed);
84				} else {
85					out.push_none();
86				}
87			}
88			Ok(out)
89		}
90	};
91}
92
93impl_to_uuid!(to_uuid4, Uuid4, Type::Uuid4, parse_uuid4);
94impl_to_uuid!(to_uuid7, Uuid7, Type::Uuid7, parse_uuid7);
95
96#[inline]
97fn from_uuid4(container: &UuidContainer<Uuid4>, target: Type, lazy_fragment: impl LazyFragment) -> Result<ColumnData> {
98	match target {
99		Type::Uuid4 => Ok(ColumnData::Uuid4(UuidContainer::new(container.data().to_vec()))),
100		_ => {
101			let source_type = Type::Uuid4;
102			Err(TypeError::UnsupportedCast {
103				from: source_type,
104				to: target,
105				fragment: lazy_fragment.fragment(),
106			}
107			.into())
108		}
109	}
110}
111
112#[inline]
113fn from_uuid7(container: &UuidContainer<Uuid7>, target: Type, lazy_fragment: impl LazyFragment) -> Result<ColumnData> {
114	match target {
115		Type::Uuid7 => Ok(ColumnData::Uuid7(UuidContainer::new(container.data().to_vec()))),
116		_ => {
117			let source_type = Type::Uuid7;
118			Err(TypeError::UnsupportedCast {
119				from: source_type,
120				to: target,
121				fragment: lazy_fragment.fragment(),
122			}
123			.into())
124		}
125	}
126}