Skip to main content

reifydb_engine/expression/cast/
temporal.rs

1// SPDX-License-Identifier: Apache-2.0
2// Copyright (c) 2025 ReifyDB
3
4use reifydb_core::value::column::buffer::ColumnBuffer;
5use reifydb_type::{
6	error::{Error, TypeError},
7	fragment::{Fragment, LazyFragment},
8	value::{
9		container::utf8::Utf8Container,
10		date::Date,
11		datetime::DateTime,
12		duration::Duration,
13		temporal::parse::{
14			date::parse_date, datetime::parse_datetime, duration::parse_duration, time::parse_time,
15		},
16		time::Time,
17		r#type::Type,
18	},
19};
20
21use crate::{Result, error::CastError};
22
23pub fn to_temporal(data: &ColumnBuffer, target: Type, lazy_fragment: impl LazyFragment) -> Result<ColumnBuffer> {
24	if let ColumnBuffer::Utf8 {
25		container,
26		..
27	} = data
28	{
29		match target {
30			Type::Date => to_date(container, lazy_fragment),
31			Type::DateTime => to_datetime(container, lazy_fragment),
32			Type::Time => to_time(container, lazy_fragment),
33			Type::Duration => to_duration(container, lazy_fragment),
34			_ => {
35				let shape_type = data.get_type();
36				Err(TypeError::UnsupportedCast {
37					from: shape_type,
38					to: target,
39					fragment: lazy_fragment.fragment(),
40				}
41				.into())
42			}
43		}
44	} else {
45		let shape_type = data.get_type();
46		Err(TypeError::UnsupportedCast {
47			from: shape_type,
48			to: target,
49			fragment: lazy_fragment.fragment(),
50		}
51		.into())
52	}
53}
54
55macro_rules! impl_to_temporal {
56	($fn_name:ident, $type:ty, $target_type:expr, $parse_fn:expr) => {
57		#[inline]
58		fn $fn_name(container: &Utf8Container, lazy_fragment: impl LazyFragment) -> Result<ColumnBuffer> {
59			let mut out = ColumnBuffer::with_capacity($target_type, container.len());
60			for idx in 0..container.len() {
61				if container.is_defined(idx) {
62					let val = container.get(idx).unwrap();
63
64					let temp_fragment = Fragment::internal(val);
65
66					let parsed = $parse_fn(temp_fragment).map_err(|mut e| {
67						let proper_fragment = lazy_fragment.fragment();
68
69						if let Fragment::Internal {
70							text: error_text,
71						} = &e.0.fragment
72						{
73							if let Fragment::Statement {
74								text: source_text,
75								..
76							} = &proper_fragment
77							{
78								if &**source_text == val
79									|| source_text.contains(&format!("\"{}\"", val))
80								{
81									let offset =
82										val.find(&**error_text).unwrap_or(0);
83									e.0.fragment = proper_fragment
84										.sub_fragment(offset, error_text.len());
85								} else {
86									e.0.fragment = proper_fragment.clone();
87								}
88							} else {
89								e.0.fragment = proper_fragment.clone();
90							}
91						}
92
93						Error::from(CastError::InvalidTemporal {
94							fragment: e.0.fragment.clone(),
95							target: $target_type,
96							cause: e.diagnostic(),
97						})
98					})?;
99
100					out.push::<$type>(parsed);
101				} else {
102					out.push_none();
103				}
104			}
105			Ok(out)
106		}
107	};
108}
109
110impl_to_temporal!(to_date, Date, Type::Date, parse_date);
111impl_to_temporal!(to_datetime, DateTime, Type::DateTime, parse_datetime);
112impl_to_temporal!(to_time, Time, Type::Time, parse_time);
113impl_to_temporal!(to_duration, Duration, Type::Duration, parse_duration);