Skip to main content

reifydb_routine/function/uuid/
v4.rs

1// SPDX-License-Identifier: Apache-2.0
2// Copyright (c) 2025 ReifyDB
3
4use reifydb_core::value::column::data::ColumnData;
5use reifydb_type::value::{r#type::Type, uuid::Uuid4};
6use uuid::{Builder, Uuid};
7
8use crate::function::{
9	ScalarFunction, ScalarFunctionContext,
10	error::{ScalarFunctionError, ScalarFunctionResult},
11	propagate_options,
12};
13
14pub struct UuidV4;
15
16impl UuidV4 {
17	pub fn new() -> Self {
18		Self
19	}
20}
21
22impl ScalarFunction for UuidV4 {
23	fn scalar(&self, ctx: ScalarFunctionContext) -> ScalarFunctionResult<ColumnData> {
24		if let Some(result) = propagate_options(self, &ctx) {
25			return result;
26		}
27
28		let row_count = ctx.row_count;
29
30		if ctx.columns.len() > 1 {
31			return Err(ScalarFunctionError::ArityMismatch {
32				function: ctx.fragment.clone(),
33				expected: 0,
34				actual: ctx.columns.len(),
35			});
36		}
37
38		if ctx.columns.is_empty() {
39			let mut data = Vec::with_capacity(row_count);
40			for _ in 0..row_count {
41				let bytes = ctx.runtime_context.rng.bytes_16();
42				let uuid = Uuid4::from(Builder::from_random_bytes(bytes).into_uuid());
43				data.push(uuid);
44			}
45			return Ok(ColumnData::uuid4(data));
46		}
47
48		let column = ctx.columns.get(0).unwrap();
49		match &column.data() {
50			ColumnData::Utf8 {
51				container,
52				..
53			} => {
54				let mut data = Vec::with_capacity(row_count);
55				for i in 0..row_count {
56					let s = &container[i];
57					let parsed = Uuid::parse_str(s).map_err(|e| {
58						ScalarFunctionError::ExecutionFailed {
59							function: ctx.fragment.clone(),
60							reason: format!("invalid UUID string '{}': {}", s, e),
61						}
62					})?;
63					if parsed.get_version_num() != 4 {
64						return Err(ScalarFunctionError::ExecutionFailed {
65							function: ctx.fragment.clone(),
66							reason: format!(
67								"expected UUID v4, got v{}",
68								parsed.get_version_num()
69							),
70						});
71					}
72					data.push(Uuid4::from(parsed));
73				}
74				Ok(ColumnData::uuid4(data))
75			}
76			other => Err(ScalarFunctionError::InvalidArgumentType {
77				function: ctx.fragment.clone(),
78				argument_index: 0,
79				expected: vec![Type::Utf8],
80				actual: other.get_type(),
81			}),
82		}
83	}
84
85	fn return_type(&self, _input_types: &[Type]) -> Type {
86		Type::Uuid4
87	}
88}