Skip to main content

clickhouse_native_client/column/
map.rs

1//! Map column implementation.
2//!
3//! ClickHouse `Map(K, V)` is stored internally as `Array(Tuple(K, V))`.
4//! This module wraps `ColumnArray` with the appropriate tuple element type.
5
6use super::{
7    Column,
8    ColumnArray,
9    ColumnRef,
10};
11use crate::{
12    types::Type,
13    Error,
14    Result,
15};
16use bytes::BytesMut;
17use std::sync::Arc;
18
19/// Column for `Map(K, V)` type, stored internally as `Array(Tuple(K, V))`.
20pub struct ColumnMap {
21    type_: Type,
22    data: ColumnRef, // Array of Tuple(key, value)
23}
24
25impl ColumnMap {
26    /// Create a new empty map column for the given `Map` type.
27    ///
28    /// # Panics
29    ///
30    /// Panics if `type_` is not `Type::Map`.
31    pub fn new(type_: Type) -> Self {
32        // Extract key and value types from Map type
33        let (key_type, value_type) = match &type_ {
34            Type::Map { key_type, value_type } => {
35                (key_type.as_ref().clone(), value_type.as_ref().clone())
36            }
37            _ => panic!("ColumnMap requires Map type"),
38        };
39
40        // Create the underlying Array(Tuple(K, V)) type
41        let tuple_type =
42            Type::Tuple { item_types: vec![key_type, value_type] };
43        let array_type = Type::Array { item_type: Box::new(tuple_type) };
44
45        // Create the array column with the correct type
46        let data: ColumnRef = Arc::new(ColumnArray::new(array_type));
47
48        Self { type_, data }
49    }
50
51    /// Create from existing array data
52    pub fn from_array(type_: Type, data: ColumnRef) -> Self {
53        Self { type_, data }
54    }
55
56    /// Get a reference to the data column as a specific type
57    ///
58    /// # Example
59    /// ```ignore
60    /// let col: ColumnMap = /* ... */;
61    /// let data: &ColumnArray = col.data();
62    /// ```
63    pub fn data<T: Column + 'static>(&self) -> &T {
64        self.data
65            .as_any()
66            .downcast_ref::<T>()
67            .expect("Failed to downcast data column to requested type")
68    }
69
70    /// Get mutable reference to the data column as a specific type
71    ///
72    /// # Example
73    /// ```ignore
74    /// let mut col: ColumnMap = /* ... */;
75    /// let data_mut: &mut ColumnArray = col.data_mut();
76    /// ```
77    pub fn data_mut<T: Column + 'static>(&mut self) -> &mut T {
78        Arc::get_mut(&mut self.data)
79            .expect("Cannot get mutable reference to shared data column")
80            .as_any_mut()
81            .downcast_mut::<T>()
82            .expect("Failed to downcast data column to requested type")
83    }
84
85    /// Get the data column as a `ColumnRef` (`Arc<dyn Column>`)
86    pub fn data_ref(&self) -> ColumnRef {
87        self.data.clone()
88    }
89
90    /// Get the underlying array column as ColumnArray if possible
91    pub fn as_array(&self) -> Option<&ColumnArray> {
92        self.data.as_any().downcast_ref::<ColumnArray>()
93    }
94
95    /// Get map at index as a column reference
96    /// The returned column is a Tuple(K, V) array
97    pub fn at(&self, index: usize) -> Result<ColumnRef> {
98        // Delegate to the array's slice functionality
99        self.data.slice(index, 1)
100    }
101
102    /// Returns the number of map entries (rows) in this column.
103    pub fn len(&self) -> usize {
104        self.data.size()
105    }
106
107    /// Returns `true` if the column contains no entries.
108    pub fn is_empty(&self) -> bool {
109        self.data.size() == 0
110    }
111}
112
113impl Column for ColumnMap {
114    fn column_type(&self) -> &Type {
115        &self.type_
116    }
117
118    fn size(&self) -> usize {
119        self.data.size()
120    }
121
122    fn clear(&mut self) {
123        // Create a new empty column
124        let new_col = ColumnMap::new(self.type_.clone());
125        self.data = new_col.data;
126    }
127
128    fn reserve(&mut self, _new_cap: usize) {
129        // Reserve not supported through ColumnRef without downcasting
130        // This is a limitation of the wrapper approach
131    }
132
133    fn append_column(&mut self, other: ColumnRef) -> Result<()> {
134        let _other =
135            other.as_any().downcast_ref::<ColumnMap>().ok_or_else(|| {
136                Error::TypeMismatch {
137                    expected: self.type_.name(),
138                    actual: other.column_type().name(),
139                }
140            })?;
141
142        // Append not easily supported through ColumnRef
143        Err(Error::Protocol(
144            "append_column not fully supported for Map".to_string(),
145        ))
146    }
147
148    fn load_prefix(&mut self, buffer: &mut &[u8], rows: usize) -> Result<()> {
149        // Delegate to underlying array's load_prefix
150        // CRITICAL: This ensures nested LowCardinality columns in Map values
151        // have their key_version read before load_from_buffer is called
152        let data_mut = Arc::get_mut(&mut self.data).ok_or_else(|| {
153            Error::Protocol(
154                "Cannot load prefix for shared map column".to_string(),
155            )
156        })?;
157        data_mut.load_prefix(buffer, rows)
158    }
159
160    fn load_from_buffer(
161        &mut self,
162        buffer: &mut &[u8],
163        rows: usize,
164    ) -> Result<()> {
165        // Create a new column with correct array type and load into it
166        let mut new_col = ColumnMap::new(self.type_.clone());
167
168        // Get mutable access to the underlying array
169        if let Some(array) = Arc::get_mut(&mut new_col.data) {
170            if let Some(array_mut) =
171                array.as_any_mut().downcast_mut::<ColumnArray>()
172            {
173                array_mut.load_from_buffer(buffer, rows)?;
174                self.data = new_col.data;
175                return Ok(());
176            }
177        }
178
179        Err(Error::Protocol(
180            "Failed to load Map column from buffer".to_string(),
181        ))
182    }
183
184    fn save_prefix(&self, buffer: &mut BytesMut) -> Result<()> {
185        // Delegate to underlying array's save_prefix
186        // CRITICAL: This ensures nested LowCardinality columns in Map values
187        // have their key_version written before save_to_buffer is called
188        self.data.save_prefix(buffer)
189    }
190
191    fn save_to_buffer(&self, buffer: &mut BytesMut) -> Result<()> {
192        self.data.save_to_buffer(buffer)
193    }
194
195    fn clone_empty(&self) -> ColumnRef {
196        Arc::new(ColumnMap::new(self.type_.clone()))
197    }
198
199    fn slice(&self, begin: usize, len: usize) -> Result<ColumnRef> {
200        // Get the sliced array
201        let sliced_data = self.data.slice(begin, len)?;
202
203        // ColumnMap wraps the sliced array directly
204        // We store it as ColumnRef in a new ColumnMap structure
205        Ok(Arc::new(ColumnMap {
206            type_: self.type_.clone(),
207            data: sliced_data,
208        }))
209    }
210
211    fn as_any(&self) -> &dyn std::any::Any {
212        self
213    }
214
215    fn as_any_mut(&mut self) -> &mut dyn std::any::Any {
216        self
217    }
218}
219
220// Note: ColumnArray doesn't implement Clone, so we need to work around this
221impl Clone for ColumnMap {
222    fn clone(&self) -> Self {
223        Self { type_: self.type_.clone(), data: self.data.clone() }
224    }
225}
226
227#[cfg(test)]
228#[cfg_attr(coverage_nightly, coverage(off))]
229mod tests {
230    use super::*;
231    use crate::types::TypeCode;
232
233    #[test]
234    fn test_map_creation() {
235        // Map(String, UInt32)
236        let map_type = Type::Map {
237            key_type: Box::new(Type::Simple(TypeCode::String)),
238            value_type: Box::new(Type::Simple(TypeCode::UInt32)),
239        };
240
241        let col = ColumnMap::new(map_type);
242        assert_eq!(col.len(), 0);
243        assert!(col.is_empty());
244    }
245
246    #[test]
247    fn test_map_underlying_array() {
248        let map_type = Type::Map {
249            key_type: Box::new(Type::Simple(TypeCode::String)),
250            value_type: Box::new(Type::Simple(TypeCode::UInt32)),
251        };
252
253        let col = ColumnMap::new(map_type);
254        let array = col.as_array();
255
256        // The underlying array should be empty
257        assert!(array.is_some());
258        assert_eq!(array.unwrap().size(), 0);
259    }
260
261    #[test]
262    fn test_map_clone() {
263        let map_type = Type::Map {
264            key_type: Box::new(Type::Simple(TypeCode::String)),
265            value_type: Box::new(Type::Simple(TypeCode::UInt32)),
266        };
267
268        let col1 = ColumnMap::new(map_type);
269        let col2 = col1.clone();
270
271        assert_eq!(col1.len(), col2.len());
272    }
273}