Skip to main content

reifydb_core/value/column/data/
extend.rs

1// SPDX-License-Identifier: AGPL-3.0-or-later
2// Copyright (c) 2025 ReifyDB
3
4use std::mem;
5
6use reifydb_type::{Result, storage::DataBitVec, util::bitvec::BitVec};
7
8use crate::{
9	return_internal_error,
10	value::column::{ColumnData, data::with_container},
11};
12
13impl ColumnData {
14	pub fn extend(&mut self, other: ColumnData) -> Result<()> {
15		match (&mut *self, other) {
16			// Same type extensions
17			(ColumnData::Bool(l), ColumnData::Bool(r)) => l.extend(&r)?,
18			(ColumnData::Float4(l), ColumnData::Float4(r)) => l.extend(&r)?,
19			(ColumnData::Float8(l), ColumnData::Float8(r)) => l.extend(&r)?,
20			(ColumnData::Int1(l), ColumnData::Int1(r)) => l.extend(&r)?,
21			(ColumnData::Int2(l), ColumnData::Int2(r)) => l.extend(&r)?,
22			(ColumnData::Int4(l), ColumnData::Int4(r)) => l.extend(&r)?,
23			(ColumnData::Int8(l), ColumnData::Int8(r)) => l.extend(&r)?,
24			(ColumnData::Int16(l), ColumnData::Int16(r)) => l.extend(&r)?,
25			(ColumnData::Uint1(l), ColumnData::Uint1(r)) => l.extend(&r)?,
26			(ColumnData::Uint2(l), ColumnData::Uint2(r)) => l.extend(&r)?,
27			(ColumnData::Uint4(l), ColumnData::Uint4(r)) => l.extend(&r)?,
28			(ColumnData::Uint8(l), ColumnData::Uint8(r)) => l.extend(&r)?,
29			(ColumnData::Uint16(l), ColumnData::Uint16(r)) => l.extend(&r)?,
30			(
31				ColumnData::Utf8 {
32					container: l,
33					..
34				},
35				ColumnData::Utf8 {
36					container: r,
37					..
38				},
39			) => l.extend(&r)?,
40			(ColumnData::Date(l), ColumnData::Date(r)) => l.extend(&r)?,
41			(ColumnData::DateTime(l), ColumnData::DateTime(r)) => l.extend(&r)?,
42			(ColumnData::Time(l), ColumnData::Time(r)) => l.extend(&r)?,
43			(ColumnData::Duration(l), ColumnData::Duration(r)) => l.extend(&r)?,
44			(ColumnData::IdentityId(l), ColumnData::IdentityId(r)) => l.extend(&r)?,
45			(ColumnData::Uuid4(l), ColumnData::Uuid4(r)) => l.extend(&r)?,
46			(ColumnData::Uuid7(l), ColumnData::Uuid7(r)) => l.extend(&r)?,
47			(
48				ColumnData::Blob {
49					container: l,
50					..
51				},
52				ColumnData::Blob {
53					container: r,
54					..
55				},
56			) => l.extend(&r)?,
57			(
58				ColumnData::Int {
59					container: l,
60					..
61				},
62				ColumnData::Int {
63					container: r,
64					..
65				},
66			) => l.extend(&r)?,
67			(
68				ColumnData::Uint {
69					container: l,
70					..
71				},
72				ColumnData::Uint {
73					container: r,
74					..
75				},
76			) => l.extend(&r)?,
77			(
78				ColumnData::Decimal {
79					container: l,
80					..
81				},
82				ColumnData::Decimal {
83					container: r,
84					..
85				},
86			) => l.extend(&r)?,
87			(ColumnData::DictionaryId(l), ColumnData::DictionaryId(r)) => l.extend(&r)?,
88
89			// Option + Option: extend inner + bitvec
90			(
91				ColumnData::Option {
92					inner: l_inner,
93					bitvec: l_bitvec,
94				},
95				ColumnData::Option {
96					inner: r_inner,
97					bitvec: r_bitvec,
98				},
99			) => {
100				if l_inner.get_type() == r_inner.get_type() {
101					// Same inner type: normal extend
102					l_inner.extend(*r_inner)?;
103				} else if DataBitVec::count_ones(&r_bitvec) == 0 {
104					// Right is all-none with different type: extend left inner with defaults
105					let r_len = r_inner.len();
106					with_container!(l_inner.as_mut(), |c| {
107						for _ in 0..r_len {
108							c.push_default();
109						}
110					});
111				} else if DataBitVec::count_ones(l_bitvec) == 0 {
112					// Left is all-none with different type: replace left inner type to match
113					// right's
114					let l_len = l_inner.len();
115					let r_type = r_inner.get_type();
116					let (mut new_inner, _) =
117						ColumnData::none_typed(r_type, l_len).into_unwrap_option();
118					new_inner.extend(*r_inner)?;
119					**l_inner = new_inner;
120				} else {
121					// Type mismatch with both having defined values
122					return_internal_error!("column type mismatch in Option extend");
123				}
124				DataBitVec::extend_from(l_bitvec, &r_bitvec);
125			}
126
127			// Option + bare: extend inner with bare data, extend bitvec with all-true
128			(
129				ColumnData::Option {
130					inner,
131					bitvec,
132				},
133				other,
134			) => {
135				let other_len = other.len();
136				if inner.get_type() != other.get_type() && DataBitVec::count_ones(bitvec) == 0 {
137					// Left is all-none with different type: replace inner type to match bare data
138					let l_len = inner.len();
139					let r_type = other.get_type();
140					let (mut new_inner, _) =
141						ColumnData::none_typed(r_type, l_len).into_unwrap_option();
142					new_inner.extend(other)?;
143					**inner = new_inner;
144				} else {
145					inner.extend(other)?;
146				}
147				for _ in 0..other_len {
148					DataBitVec::push(bitvec, true);
149				}
150			}
151
152			// bare + Option: promote bare to Option, then extend
153			(
154				_,
155				ColumnData::Option {
156					inner: r_inner,
157					bitvec: r_bitvec,
158				},
159			) => {
160				let l_len = self.len();
161				let r_len = r_inner.len();
162				let mut l_bitvec = BitVec::repeat(l_len, true);
163				DataBitVec::extend_from(&mut l_bitvec, &r_bitvec);
164				let inner = mem::replace(self, ColumnData::bool(vec![]));
165				let mut boxed_inner = Box::new(inner);
166
167				if boxed_inner.get_type() != r_inner.get_type()
168					&& DataBitVec::count_ones(&r_bitvec) == 0
169				{
170					// Right is all-none with different type: extend left with defaults
171					with_container!(boxed_inner.as_mut(), |c| {
172						for _ in 0..r_len {
173							c.push_default();
174						}
175					});
176				} else {
177					boxed_inner.extend(*r_inner)?;
178				}
179
180				*self = ColumnData::Option {
181					inner: boxed_inner,
182					bitvec: l_bitvec,
183				};
184			}
185
186			// Type mismatch
187			(_, _) => {
188				return_internal_error!("column type mismatch");
189			}
190		}
191
192		Ok(())
193	}
194}