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::{ColumnWithName, buffer::ColumnBuffer, columns::Columns};
5use reifydb_type::value::{r#type::Type, uuid::Uuid4};
6use uuid::{Builder, Uuid};
7
8use crate::routine::{Function, FunctionKind, Routine, RoutineInfo, context::FunctionContext, error::RoutineError};
9
10pub struct UuidV4 {
11	info: RoutineInfo,
12}
13
14impl Default for UuidV4 {
15	fn default() -> Self {
16		Self::new()
17	}
18}
19
20impl UuidV4 {
21	pub fn new() -> Self {
22		Self {
23			info: RoutineInfo::new("uuid::v4"),
24		}
25	}
26}
27
28impl<'a> Routine<FunctionContext<'a>> for UuidV4 {
29	fn info(&self) -> &RoutineInfo {
30		&self.info
31	}
32
33	fn return_type(&self, _input_types: &[Type]) -> Type {
34		Type::Uuid4
35	}
36
37	fn execute(&self, ctx: &mut FunctionContext<'a>, args: &Columns) -> Result<Columns, RoutineError> {
38		if args.len() > 1 {
39			return Err(RoutineError::FunctionArityMismatch {
40				function: ctx.fragment.clone(),
41				expected: 0,
42				actual: args.len(),
43			});
44		}
45
46		if args.is_empty() {
47			let bytes = ctx.runtime_context.rng.bytes_16();
48			let uuid = Uuid4::from(Builder::from_random_bytes(bytes).into_uuid());
49			let result_data = ColumnBuffer::uuid4(vec![uuid]);
50			return Ok(Columns::new(vec![ColumnWithName::new(ctx.fragment.clone(), result_data)]));
51		}
52
53		let column = &args[0];
54		let (data, bitvec) = column.unwrap_option();
55		let row_count = data.len();
56
57		match data {
58			ColumnBuffer::Utf8 {
59				container,
60				..
61			} => {
62				let mut result = Vec::with_capacity(row_count);
63				for i in 0..row_count {
64					let s = container.get(i).unwrap();
65					let parsed = Uuid::parse_str(s).map_err(|e| {
66						RoutineError::FunctionExecutionFailed {
67							function: ctx.fragment.clone(),
68							reason: format!("invalid UUID string '{}': {}", s, e),
69						}
70					})?;
71					if parsed.get_version_num() != 4 {
72						return Err(RoutineError::FunctionExecutionFailed {
73							function: ctx.fragment.clone(),
74							reason: format!(
75								"expected UUID v4, got v{}",
76								parsed.get_version_num()
77							),
78						});
79					}
80					result.push(Uuid4::from(parsed));
81				}
82				let result_data = ColumnBuffer::uuid4(result);
83				let final_data = match bitvec {
84					Some(bv) => ColumnBuffer::Option {
85						inner: Box::new(result_data),
86						bitvec: bv.clone(),
87					},
88					None => result_data,
89				};
90				Ok(Columns::new(vec![ColumnWithName::new(ctx.fragment.clone(), final_data)]))
91			}
92			other => Err(RoutineError::FunctionInvalidArgumentType {
93				function: ctx.fragment.clone(),
94				argument_index: 0,
95				expected: vec![Type::Utf8],
96				actual: other.get_type(),
97			}),
98		}
99	}
100}
101
102impl Function for UuidV4 {
103	fn kinds(&self) -> &[FunctionKind] {
104		&[FunctionKind::Scalar]
105	}
106}