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