Skip to main content

reifydb_codec/encoded/
date.rs

1// SPDX-License-Identifier: Apache-2.0
2// Copyright (c) 2026 ReifyDB
3
4use std::ptr;
5
6use reifydb_value::{
7	reifydb_assertions,
8	value::{date::Date, value_type::ValueType},
9};
10
11use crate::encoded::{row::EncodedRow, shape::RowShape};
12
13impl RowShape {
14	pub fn set_date(&self, row: &mut EncodedRow, index: usize, value: Date) {
15		let field = &self.fields()[index];
16		reifydb_assertions! {
17			assert!(
18				row.len() >= self.total_static_size(),
19				"row/shape size mismatch: row.len()={} < total_static_size()={}",
20				row.len(),
21				self.total_static_size()
22			);
23			assert_eq!(*field.constraint.get_type().inner_type(), ValueType::Date);
24		}
25		row.set_valid(index, true);
26		unsafe {
27			ptr::write_unaligned(
28				row.make_mut().as_mut_ptr().add(field.offset as usize) as *mut i32,
29				value.to_days_since_epoch(),
30			)
31		}
32	}
33
34	pub fn get_date(&self, row: &EncodedRow, index: usize) -> Date {
35		let field = &self.fields()[index];
36		reifydb_assertions! {
37			assert!(
38				row.len() >= self.total_static_size(),
39				"row/shape size mismatch: row.len()={} < total_static_size()={}",
40				row.len(),
41				self.total_static_size()
42			);
43			assert_eq!(*field.constraint.get_type().inner_type(), ValueType::Date);
44		}
45		unsafe {
46			Date::from_days_since_epoch(
47				(row.as_ptr().add(field.offset as usize) as *const i32).read_unaligned(),
48			)
49			.unwrap()
50		}
51	}
52
53	pub fn try_get_date(&self, row: &EncodedRow, index: usize) -> Option<Date> {
54		if row.is_defined(index) && self.fields()[index].constraint.get_type() == ValueType::Date {
55			Some(self.get_date(row, index))
56		} else {
57			None
58		}
59	}
60}
61
62#[cfg(test)]
63pub mod tests {
64	use reifydb_value::value::{date::Date, value_type::ValueType};
65
66	use crate::encoded::shape::RowShape;
67
68	#[test]
69	fn test_set_get_date() {
70		let shape = RowShape::testing(&[ValueType::Date]);
71		let mut row = shape.allocate();
72
73		let value = Date::new(2021, 1, 1).unwrap();
74		shape.set_date(&mut row, 0, value.clone());
75		assert_eq!(shape.get_date(&row, 0), value);
76	}
77
78	#[test]
79	fn test_try_get_date() {
80		let shape = RowShape::testing(&[ValueType::Date]);
81		let mut row = shape.allocate();
82
83		assert_eq!(shape.try_get_date(&row, 0), None);
84
85		let test_date = Date::from_ymd(2025, 1, 15).unwrap();
86		shape.set_date(&mut row, 0, test_date.clone());
87		assert_eq!(shape.try_get_date(&row, 0), Some(test_date));
88	}
89
90	#[test]
91	fn test_epoch() {
92		let shape = RowShape::testing(&[ValueType::Date]);
93		let mut row = shape.allocate();
94
95		let epoch = Date::default(); // Unix epoch
96		shape.set_date(&mut row, 0, epoch.clone());
97		assert_eq!(shape.get_date(&row, 0), epoch);
98	}
99
100	#[test]
101	fn test_various_dates() {
102		let shape = RowShape::testing(&[ValueType::Date]);
103
104		let test_dates = [
105			Date::new(1970, 1, 1).unwrap(),   // Unix epoch
106			Date::new(2000, 1, 1).unwrap(),   // Y2K
107			Date::new(2024, 2, 29).unwrap(),  // Leap year
108			Date::new(2025, 12, 31).unwrap(), // Future date
109		];
110
111		for date in test_dates {
112			let mut row = shape.allocate();
113			shape.set_date(&mut row, 0, date.clone());
114			assert_eq!(shape.get_date(&row, 0), date);
115		}
116	}
117
118	#[test]
119	fn test_boundaries() {
120		let shape = RowShape::testing(&[ValueType::Date]);
121
122		// Test various boundary dates that should work
123		let boundary_dates = [
124			Date::new(1900, 1, 1).unwrap(),
125			Date::new(1999, 12, 31).unwrap(),
126			Date::new(2000, 1, 1).unwrap(),
127			Date::new(2100, 12, 31).unwrap(),
128		];
129
130		for date in boundary_dates {
131			let mut row = shape.allocate();
132			shape.set_date(&mut row, 0, date.clone());
133			assert_eq!(shape.get_date(&row, 0), date);
134		}
135	}
136
137	#[test]
138	fn test_mixed_with_other_types() {
139		let shape = RowShape::testing(&[ValueType::Date, ValueType::Boolean, ValueType::Date, ValueType::Int4]);
140		let mut row = shape.allocate();
141
142		let date1 = Date::new(2025, 6, 15).unwrap();
143		let date2 = Date::new(1995, 3, 22).unwrap();
144
145		shape.set_date(&mut row, 0, date1.clone());
146		shape.set_bool(&mut row, 1, true);
147		shape.set_date(&mut row, 2, date2.clone());
148		shape.set_i32(&mut row, 3, 42);
149
150		assert_eq!(shape.get_date(&row, 0), date1);
151		assert_eq!(shape.get_bool(&row, 1), true);
152		assert_eq!(shape.get_date(&row, 2), date2);
153		assert_eq!(shape.get_i32(&row, 3), 42);
154	}
155
156	#[test]
157	fn test_undefined_handling() {
158		let shape = RowShape::testing(&[ValueType::Date, ValueType::Date]);
159		let mut row = shape.allocate();
160
161		let date = Date::new(2025, 7, 4).unwrap();
162		shape.set_date(&mut row, 0, date.clone());
163
164		assert_eq!(shape.try_get_date(&row, 0), Some(date));
165		assert_eq!(shape.try_get_date(&row, 1), None);
166
167		shape.set_none(&mut row, 0);
168		assert_eq!(shape.try_get_date(&row, 0), None);
169	}
170
171	#[test]
172	fn test_clone_consistency() {
173		let shape = RowShape::testing(&[ValueType::Date]);
174		let mut row = shape.allocate();
175
176		let original_date = Date::new(2023, 9, 15).unwrap();
177		shape.set_date(&mut row, 0, original_date.clone());
178
179		let retrieved_date = shape.get_date(&row, 0);
180		assert_eq!(retrieved_date, original_date);
181
182		// Verify that the retrieved date is functionally equivalent
183		assert_eq!(retrieved_date.to_days_since_epoch(), original_date.to_days_since_epoch());
184	}
185
186	#[test]
187	fn test_special_years() {
188		let shape = RowShape::testing(&[ValueType::Date]);
189
190		// Test leap years and century boundaries
191		let special_dates = [
192			Date::new(1600, 2, 29).unwrap(), // Leap year century
193			Date::new(1700, 2, 28).unwrap(), // Non-leap century
194			Date::new(1800, 2, 28).unwrap(), // Non-leap century
195			Date::new(1900, 2, 28).unwrap(), // Non-leap century
196			Date::new(2000, 2, 29).unwrap(), // Leap year century
197			Date::new(2024, 2, 29).unwrap(), // Recent leap year
198		];
199
200		for date in special_dates {
201			let mut row = shape.allocate();
202			shape.set_date(&mut row, 0, date.clone());
203			assert_eq!(shape.get_date(&row, 0), date);
204		}
205	}
206
207	#[test]
208	fn test_try_get_date_wrong_type() {
209		let shape = RowShape::testing(&[ValueType::Boolean]);
210		let mut row = shape.allocate();
211
212		shape.set_bool(&mut row, 0, true);
213
214		assert_eq!(shape.try_get_date(&row, 0), None);
215	}
216}