Skip to main content

reifydb_compression/strategy/
none.rs

1// SPDX-License-Identifier: AGPL-3.0-or-later
2// Copyright (c) 2025 ReifyDB
3
4use reifydb_core::value::column::{
5	compressed::{CompressedColumn, CompressionType},
6	data::ColumnData,
7};
8use reifydb_type::{
9	error,
10	error::{diagnostic, diagnostic::serde::serde_serialize_error},
11};
12
13use crate::ColumnCompressor;
14
15pub struct NoneCompressor {}
16
17impl ColumnCompressor for NoneCompressor {
18	fn compress(&self, data: &ColumnData) -> reifydb_type::Result<CompressedColumn> {
19		let serialized = postcard::to_stdvec(data).map_err(|e| error!(serde_serialize_error(e.to_string())))?;
20
21		let uncompressed_size = serialized.len();
22
23		Ok(CompressedColumn {
24			data: serialized,
25			compression: CompressionType::None,
26			uncompressed_size,
27			none_count: data.none_count(),
28			row_count: data.len(),
29		})
30	}
31
32	fn decompress(&self, compressed: &CompressedColumn) -> reifydb_type::Result<ColumnData> {
33		assert_eq!(compressed.compression, CompressionType::None);
34
35		let result: ColumnData = postcard::from_bytes(&compressed.data)
36			.map_err(|e| error!(diagnostic::serde::serde_deserialize_error(e.to_string())))?;
37
38		Ok(result)
39	}
40}
41
42#[cfg(test)]
43pub mod tests {
44	use reifydb_core::value::column::{compressed::CompressionType, data::ColumnData};
45
46	use super::*;
47
48	#[test]
49	fn test_compress_decompress_bool() {
50		let compressor = NoneCompressor {};
51
52		let data = ColumnData::bool_optional([Some(true), Some(false), None, Some(true), None]);
53
54		let compressed = compressor.compress(&data).unwrap();
55		assert_eq!(compressed.compression, CompressionType::None);
56		assert_eq!(compressed.row_count, 5);
57		assert_eq!(compressed.none_count, 2);
58		assert_eq!(compressed.uncompressed_size, compressed.data.len());
59
60		let decompressed = compressor.decompress(&compressed).unwrap();
61		assert_eq!(data, decompressed);
62	}
63
64	#[test]
65	fn test_compress_decompress_int() {
66		let compressor = NoneCompressor {};
67
68		let data = ColumnData::int4_optional([
69			Some(42),
70			Some(-100),
71			None,
72			Some(0),
73			Some(i32::MAX),
74			Some(i32::MIN),
75		]);
76
77		let compressed = compressor.compress(&data).unwrap();
78		assert_eq!(compressed.compression, CompressionType::None);
79		assert_eq!(compressed.row_count, 6);
80		assert_eq!(compressed.none_count, 1);
81
82		let decompressed = compressor.decompress(&compressed).unwrap();
83		assert_eq!(data, decompressed);
84	}
85
86	#[test]
87	fn test_compress_decompress_string() {
88		let compressor = NoneCompressor {};
89
90		let data = ColumnData::utf8_optional([
91			Some("hello".to_string()),
92			Some("world".to_string()),
93			None,
94			Some("".to_string()),
95			Some("a very long string with special chars: 特殊文字 🎉".to_string()),
96		]);
97
98		let compressed = compressor.compress(&data).unwrap();
99		assert_eq!(compressed.compression, CompressionType::None);
100		assert_eq!(compressed.row_count, 5);
101		assert_eq!(compressed.none_count, 1);
102
103		let decompressed = compressor.decompress(&compressed).unwrap();
104		assert_eq!(data, decompressed);
105	}
106
107	#[test]
108	fn test_empty_column() {
109		let compressor = NoneCompressor {};
110
111		let data = ColumnData::int4_with_capacity(0);
112
113		let compressed = compressor.compress(&data).unwrap();
114		assert_eq!(compressed.row_count, 0);
115		assert_eq!(compressed.none_count, 0);
116
117		let decompressed = compressor.decompress(&compressed).unwrap();
118		assert_eq!(data, decompressed);
119	}
120
121	#[test]
122	fn test_all_undefined() {
123		let compressor = NoneCompressor {};
124
125		let data = ColumnData::float8_optional([None, None, None, None]);
126
127		let compressed = compressor.compress(&data).unwrap();
128		assert_eq!(compressed.row_count, 4);
129		assert_eq!(compressed.none_count, 4);
130
131		let decompressed = compressor.decompress(&compressed).unwrap();
132		assert_eq!(data, decompressed);
133	}
134
135	#[test]
136	fn test_various_numeric_types() {
137		let compressor = NoneCompressor {};
138
139		let data_i8 = ColumnData::int8_optional([Some(i64::MAX), Some(i64::MIN), None]);
140		let compressed = compressor.compress(&data_i8).unwrap();
141		let decompressed = compressor.decompress(&compressed).unwrap();
142		assert_eq!(data_i8, decompressed);
143
144		let data_u4 = ColumnData::uint4_optional([Some(u32::MAX), Some(0), None]);
145		let compressed = compressor.compress(&data_u4).unwrap();
146		let decompressed = compressor.decompress(&compressed).unwrap();
147		assert_eq!(data_u4, decompressed);
148
149		let data_f4 = ColumnData::float4_optional([Some(3.14), Some(-0.0), None, Some(f32::INFINITY)]);
150		let compressed = compressor.compress(&data_f4).unwrap();
151		let decompressed = compressor.decompress(&compressed).unwrap();
152		assert_eq!(data_f4, decompressed);
153	}
154
155	#[test]
156	fn test_round_trip_preserves_data() {
157		let compressor = NoneCompressor {};
158
159		let bool_data = ColumnData::bool([true, false, true]);
160		let compressed = compressor.compress(&bool_data).unwrap();
161		let decompressed = compressor.decompress(&compressed).unwrap();
162		assert_eq!(bool_data, decompressed);
163
164		let int_data = ColumnData::int4([1, 2, 3, 4, 5]);
165		let compressed = compressor.compress(&int_data).unwrap();
166		let decompressed = compressor.decompress(&compressed).unwrap();
167		assert_eq!(int_data, decompressed);
168
169		let string_data = ColumnData::utf8(["hello", "world", "test"]);
170		let compressed = compressor.compress(&string_data).unwrap();
171		let decompressed = compressor.decompress(&compressed).unwrap();
172		assert_eq!(string_data, decompressed);
173	}
174}