Skip to main content

reifydb_compression/strategy/
none.rs

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