1use std::{
5 hash::Hash,
6 ops::{Index, IndexMut},
7};
8
9use indexmap::IndexMap;
10use reifydb_codec::row::{
11 bytes::EncodedBytes,
12 shape::{RowFamily, RowShape},
13};
14use reifydb_value::{
15 Result,
16 fragment::Fragment,
17 reifydb_assertions,
18 value::{
19 Value,
20 constraint::Constraint,
21 datetime::{CREATED_AT_COLUMN_NAME, DateTime, TIME_COLUMN_NAME, UPDATED_AT_COLUMN_NAME},
22 partition::Partition,
23 row_number::{ROW_NUMBER_COLUMN_NAME, RowNumber},
24 system_columns::{RowStamps, SystemColumns},
25 value_type::ValueType,
26 },
27};
28use serde::{Deserialize, Serialize};
29
30use crate::{
31 interface::catalog::column::Column as CatalogColumn,
32 return_internal_error,
33 row::Row,
34 value::column::{ColumnBuffer, ColumnWithName, data::Column, headers::ColumnHeaders},
35};
36
37#[derive(Debug, Clone, Serialize, Deserialize)]
38pub struct Columns {
39 pub system: SystemColumns,
40 pub columns: Vec<ColumnBuffer>,
41 pub names: Vec<Fragment>,
42}
43
44impl Columns {
45 #[inline]
46 pub fn row_numbers(&self) -> &[RowNumber] {
47 self.system.row_numbers()
48 }
49
50 #[inline]
51 pub fn partitions(&self) -> &[Partition] {
52 self.system.partitions()
53 }
54
55 #[inline]
56 pub fn created_at(&self) -> &[DateTime] {
57 self.system.created_at()
58 }
59
60 #[inline]
61 pub fn updated_at(&self) -> &[DateTime] {
62 self.system.updated_at()
63 }
64
65 #[inline]
66 pub fn time(&self) -> &[DateTime] {
67 self.system.time()
68 }
69
70 pub fn system_column(&self, name: &str) -> Option<ColumnBuffer> {
71 let name = name.strip_prefix('#').unwrap_or(name);
72 let row_count = self.row_count();
73
74 if name == ROW_NUMBER_COLUMN_NAME && self.row_numbers().len() == row_count {
75 let values: Vec<u64> = self.row_numbers().iter().map(|r| r.value()).collect();
76 return Some(ColumnBuffer::uint8(values));
77 }
78 if name == CREATED_AT_COLUMN_NAME && self.created_at().len() == row_count {
79 return Some(ColumnBuffer::datetime(self.created_at().to_vec()));
80 }
81 if name == UPDATED_AT_COLUMN_NAME && self.updated_at().len() == row_count {
82 return Some(ColumnBuffer::datetime(self.updated_at().to_vec()));
83 }
84 if name == TIME_COLUMN_NAME && self.time().len() == row_count {
85 return Some(ColumnBuffer::datetime(self.time().to_vec()));
86 }
87 None
88 }
89}
90
91#[derive(Debug, Clone, Copy)]
92pub struct ColumnRef<'a> {
93 name: &'a Fragment,
94 data: &'a ColumnBuffer,
95}
96
97impl Index<usize> for Columns {
98 type Output = ColumnBuffer;
99
100 fn index(&self, index: usize) -> &Self::Output {
101 &self.columns[index]
102 }
103}
104
105impl IndexMut<usize> for Columns {
106 fn index_mut(&mut self, index: usize) -> &mut Self::Output {
107 &mut self.columns[index]
108 }
109}
110
111impl<'a> ColumnRef<'a> {
112 pub fn new(name: &'a Fragment, data: &'a ColumnBuffer) -> Self {
113 Self {
114 name,
115 data,
116 }
117 }
118
119 pub fn name(&self) -> &'a Fragment {
120 self.name
121 }
122
123 pub fn data(&self) -> &'a ColumnBuffer {
124 self.data
125 }
126
127 pub fn get_type(&self) -> ValueType {
128 self.data.get_type()
129 }
130
131 pub fn column(&self) -> Column {
132 Column::from_column_buffer(self.data.clone())
133 }
134
135 pub fn with_new_data(&self, data: ColumnBuffer) -> ColumnWithName {
136 ColumnWithName::new(self.name.clone(), data)
137 }
138}
139
140fn value_to_buffer(value: Value) -> ColumnBuffer {
141 match value {
142 Value::None {
143 inner,
144 } => ColumnBuffer::none_typed(inner, 1),
145 Value::Boolean(v) => ColumnBuffer::bool([v]),
146 Value::Float4(v) => ColumnBuffer::float4([v.into()]),
147 Value::Float8(v) => ColumnBuffer::float8([v.into()]),
148 Value::Int1(v) => ColumnBuffer::int1([v]),
149 Value::Int2(v) => ColumnBuffer::int2([v]),
150 Value::Int4(v) => ColumnBuffer::int4([v]),
151 Value::Int8(v) => ColumnBuffer::int8([v]),
152 Value::Int16(v) => ColumnBuffer::int16([v]),
153 Value::Utf8(v) => ColumnBuffer::utf8([v]),
154 Value::Uint1(v) => ColumnBuffer::uint1([v]),
155 Value::Uint2(v) => ColumnBuffer::uint2([v]),
156 Value::Uint4(v) => ColumnBuffer::uint4([v]),
157 Value::Uint8(v) => ColumnBuffer::uint8([v]),
158 Value::Uint16(v) => ColumnBuffer::uint16([v]),
159 Value::Date(v) => ColumnBuffer::date([v]),
160 Value::DateTime(v) => ColumnBuffer::datetime([v]),
161 Value::Time(v) => ColumnBuffer::time([v]),
162 Value::Duration(v) => ColumnBuffer::duration([v]),
163 Value::IdentityId(v) => ColumnBuffer::identity_id([v]),
164 Value::Uuid4(v) => ColumnBuffer::uuid4([v]),
165 Value::Uuid7(v) => ColumnBuffer::uuid7([v]),
166 Value::Blob(v) => ColumnBuffer::blob([v]),
167 Value::Int(v) => ColumnBuffer::int(vec![v]),
168 Value::Uint(v) => ColumnBuffer::uint(vec![v]),
169 Value::Decimal(v) => ColumnBuffer::decimal(vec![v]),
170 Value::DictionaryId(v) => ColumnBuffer::dictionary_id(vec![v]),
171 Value::Any(v) => ColumnBuffer::any(vec![*v]),
172 Value::Type(v) => ColumnBuffer::any(vec![Value::Type(v)]),
173 Value::List(v) => ColumnBuffer::any(vec![Value::List(v)]),
174 Value::Record(v) => ColumnBuffer::any(vec![Value::Record(v)]),
175 Value::Tuple(v) => ColumnBuffer::any(vec![Value::Tuple(v)]),
176 }
177}
178
179impl Columns {
180 pub fn scalar_value(&self) -> Value {
181 reifydb_assertions! {
182 assert_eq!(self.len(), 1, "scalar_value() requires exactly 1 column, got {}", self.len());
183 assert_eq!(
184 self.row_count(),
185 1,
186 "scalar_value() requires exactly 1 row, got {}",
187 self.row_count()
188 );
189 }
190 self.columns[0].get_value(0)
191 }
192
193 pub fn new(columns: Vec<ColumnWithName>) -> Self {
194 let n = columns.first().map_or(0, |c| c.data.len());
195 assert!(columns.iter().all(|c| c.data.len() == n));
196
197 let mut names = Vec::with_capacity(columns.len());
198 let mut buffers = Vec::with_capacity(columns.len());
199 for c in columns {
200 names.push(c.name);
201 buffers.push(c.data);
202 }
203
204 Self {
205 system: SystemColumns::empty(),
206 columns: buffers,
207 names,
208 }
209 }
210
211 pub fn with_system(columns: Vec<ColumnWithName>, system: SystemColumns) -> Self {
212 let n = columns.first().map_or(0, |c| c.data.len());
213 assert!(columns.iter().all(|c| c.data.len() == n));
214 system.assert_invariants(n, "Columns::with_system");
215
216 let mut names = Vec::with_capacity(columns.len());
217 let mut buffers = Vec::with_capacity(columns.len());
218 for c in columns {
219 names.push(c.name);
220 buffers.push(c.data);
221 }
222
223 Self {
224 system,
225 columns: buffers,
226 names,
227 }
228 }
229
230 pub fn single_row<'b>(rows: impl IntoIterator<Item = (&'b str, Value)>) -> Columns {
231 let mut names = Vec::new();
232 let mut buffers = Vec::new();
233 for (name, value) in rows {
234 names.push(Fragment::internal(name));
235 buffers.push(value_to_buffer(value));
236 }
237 Self {
238 system: SystemColumns::empty(),
239 columns: buffers,
240 names,
241 }
242 }
243
244 pub fn with_row_numbers(mut self, row_numbers: Vec<RowNumber>) -> Self {
245 let n = row_numbers.len();
246 self.system = SystemColumns::new(
247 row_numbers,
248 self.system.partitions().to_vec(),
249 self.system.created_at().to_vec(),
250 self.system.updated_at().to_vec(),
251 self.system.time().to_vec(),
252 );
253 self.system.assert_invariants(n, "Columns::with_row_numbers");
254 self
255 }
256
257 pub fn from_catalog_columns(cols: &[CatalogColumn]) -> Self {
258 let mut names = Vec::with_capacity(cols.len());
259 let mut buffers = Vec::with_capacity(cols.len());
260 for col in cols {
261 names.push(Fragment::internal(&col.name));
262 buffers.push(ColumnBuffer::with_capacity(col.constraint.get_type(), 0));
263 }
264 Self {
265 system: SystemColumns::empty(),
266 columns: buffers,
267 names,
268 }
269 }
270
271 pub fn apply_headers(&mut self, headers: &ColumnHeaders) {
272 let n = self.len();
273 let names = &mut self.names;
274 for (i, name) in headers.columns.iter().enumerate() {
275 if i < n {
276 names[i] = name.clone();
277 }
278 }
279 }
280}
281
282impl Columns {
283 pub fn number(&self) -> RowNumber {
284 assert_eq!(self.row_count(), 1, "number() requires exactly 1 row, got {}", self.row_count());
285 if self.row_numbers().is_empty() {
286 RowNumber(0)
287 } else {
288 self.row_numbers()[0]
289 }
290 }
291
292 pub fn shape(&self) -> (usize, usize) {
293 let row_count = if !self.row_numbers().is_empty() {
294 self.row_numbers().len()
295 } else {
296 self.columns.first().map(|c| c.len()).unwrap_or(0)
297 };
298 (row_count, self.len())
299 }
300
301 pub fn heap_size(&self) -> usize {
302 let data: usize = self.columns.iter().map(|c| c.heap_size()).sum();
303 let names: usize = self.names.iter().map(|n| n.text().len()).sum();
304 data + names + self.system.heap_size()
305 }
306
307 pub fn len(&self) -> usize {
308 self.columns.len()
309 }
310
311 pub fn is_empty(&self) -> bool {
312 self.columns.is_empty()
313 }
314
315 pub fn iter(&self) -> impl Iterator<Item = ColumnRef<'_>> + '_ {
316 self.names.iter().zip(self.columns.iter()).map(|(n, d)| ColumnRef::new(n, d))
317 }
318
319 pub fn first(&self) -> Option<ColumnRef<'_>> {
320 self.get(0)
321 }
322
323 pub fn last(&self) -> Option<ColumnRef<'_>> {
324 let n = self.len();
325 if n == 0 {
326 None
327 } else {
328 self.get(n - 1)
329 }
330 }
331
332 pub fn get(&self, index: usize) -> Option<ColumnRef<'_>> {
333 if index < self.len() {
334 Some(ColumnRef::new(&self.names[index], &self.columns[index]))
335 } else {
336 None
337 }
338 }
339
340 pub fn name_at(&self, index: usize) -> &Fragment {
341 &self.names[index]
342 }
343
344 pub fn data_at(&self, index: usize) -> &ColumnBuffer {
345 &self.columns[index]
346 }
347
348 pub fn data_at_mut(&mut self, index: usize) -> &mut ColumnBuffer {
349 &mut self.columns[index]
350 }
351
352 pub fn row(&self, i: usize) -> Vec<Value> {
353 self.columns.iter().map(|c| c.get_value(i)).collect()
354 }
355
356 pub fn column(&self, name: &str) -> Option<ColumnRef<'_>> {
357 self.names.iter().position(|n| n.text() == name).and_then(|i| self.get(i))
358 }
359
360 pub fn row_count(&self) -> usize {
361 if !self.row_numbers().is_empty() {
362 self.row_numbers().len()
363 } else {
364 self.columns.first().map_or(0, |col| col.len())
365 }
366 }
367
368 pub fn has_rows(&self) -> bool {
369 self.row_count() > 0
370 }
371
372 pub fn is_scalar(&self) -> bool {
373 self.len() == 1 && self.row_count() == 1
374 }
375
376 pub fn get_row(&self, index: usize) -> Vec<Value> {
377 self.columns.iter().map(|col| col.get_value(index)).collect()
378 }
379
380 #[track_caller]
381 pub fn assert_invariants(&self, ctx: &str) {
382 let n = self.columns.first().map_or(0, |c| c.len());
383 for (i, col) in self.columns.iter().enumerate() {
384 assert_eq!(
385 col.len(),
386 n,
387 "{ctx}: Columns column[{i}] has length {} but columns[0] has length {n}",
388 col.len(),
389 );
390 }
391 self.system.assert_invariants(n, ctx);
392 }
393}
394
395impl Columns {
396 pub fn from_rows(names: &[&str], result_rows: &[Vec<Value>]) -> Self {
397 let column_count = names.len();
398
399 let mut name_vec: Vec<Fragment> = names.iter().map(Fragment::internal).collect();
400 let mut buffers: Vec<ColumnBuffer> =
401 (0..column_count).map(|_| ColumnBuffer::none_typed(ValueType::Boolean, 0)).collect();
402
403 for row in result_rows {
404 assert_eq!(row.len(), column_count, "row length does not match column count");
405 for (i, value) in row.iter().enumerate() {
406 buffers[i].push_value(value.clone());
407 }
408 }
409
410 let _ = &mut name_vec;
411 Self {
412 system: SystemColumns::empty(),
413 columns: buffers,
414 names: name_vec,
415 }
416 }
417
418 pub fn from_encoded_bytes(shape: &RowShape, ids: &[RowNumber], bytes_slice: &[EncodedBytes]) -> Self {
419 assert_eq!(ids.len(), bytes_slice.len(), "ids length must match rows length");
420 let fields = shape.fields();
421 let row_count = bytes_slice.len();
422
423 let mut columns_vec: Vec<ColumnWithName> = Vec::with_capacity(fields.len());
424 for field in fields.iter() {
425 let mut data = ColumnBuffer::with_capacity(field.constraint.get_type(), row_count);
426 if field.constraint.get_type() == ValueType::DictionaryId
427 && let ColumnBuffer::DictionaryId(container) = &mut data
428 && let Some(Constraint::Dictionary(dict_id, _)) = field.constraint.constraint()
429 {
430 container.set_dictionary_id(*dict_id);
431 }
432 columns_vec.push(ColumnWithName {
433 name: Fragment::internal(&field.name),
434 data,
435 });
436 }
437
438 for encoded in bytes_slice {
439 for (i, _) in fields.iter().enumerate() {
440 push_keeping_option(&mut columns_vec[i].data, shape.get_value(encoded, i));
441 }
442 }
443
444 let row_numbers: Vec<RowNumber> = ids.to_vec();
445 let (created_at, updated_at): (Vec<DateTime>, Vec<DateTime>) = match shape.family() {
446 RowFamily::Pod => (Vec::new(), Vec::new()),
447 _ => (
448 bytes_slice.iter().map(|r| shape.created_at(r)).collect(),
449 bytes_slice.iter().map(|r| shape.updated_at(r)).collect(),
450 ),
451 };
452 let time: Vec<DateTime> = bytes_slice.iter().filter_map(|r| shape.time(r)).collect();
453
454 Self::with_system(
455 columns_vec,
456 SystemColumns::new(row_numbers, Vec::new(), created_at, updated_at, time),
457 )
458 }
459}
460
461impl Columns {
462 pub fn empty() -> Self {
463 Self {
464 system: SystemColumns::empty(),
465 columns: Vec::new(),
466 names: Vec::new(),
467 }
468 }
469}
470
471impl Default for Columns {
472 fn default() -> Self {
473 Self::empty()
474 }
475}
476
477impl Columns {
478 pub fn extract_by_indices(&self, indices: &[usize]) -> Columns {
479 if indices.is_empty() {
480 return Columns::empty();
481 }
482
483 let mut new_buffers: Vec<ColumnBuffer> = Vec::with_capacity(self.columns.len());
484 for col in self.columns.iter() {
485 let mut new_data = col.empty_like(indices.len());
486 for &idx in indices {
487 push_keeping_option(&mut new_data, col.get_value(idx));
488 }
489 new_buffers.push(new_data);
490 }
491
492 Columns {
493 system: self.system.permute(indices),
494 columns: new_buffers,
495 names: self.names.clone(),
496 }
497 }
498
499 pub fn extract_row(&self, index: usize) -> Columns {
500 self.extract_by_indices(&[index])
501 }
502
503 pub fn append(&mut self, source: Columns) -> Result<()> {
504 if source.row_count() == 0 {
505 return Ok(());
506 }
507 if self.columns.is_empty() {
508 *self = source;
509 return Ok(());
510 }
511
512 self.validate_append_compatibility(&source)?;
513 self.system.extend(&source.system)?;
514 self.extend_data_columns(source.columns)?;
515 Ok(())
516 }
517
518 #[inline]
519 fn validate_append_compatibility(&self, source: &Columns) -> Result<()> {
520 if self.columns.len() != source.columns.len() {
521 return_internal_error!(
522 "Columns::append: column count mismatch (self={}, source={})",
523 self.columns.len(),
524 source.columns.len()
525 );
526 }
527 Ok(())
528 }
529
530 #[inline]
531 fn extend_data_columns(&mut self, source_columns: Vec<ColumnBuffer>) -> Result<()> {
532 let dest_cols = &mut self.columns;
533 reifydb_assertions! {
534 let dest_len = dest_cols.len();
535 let src_len = source_columns.len();
536 assert!(
537 dest_len == src_len,
538 "append extends destination columns by source index, so a source with more columns than \
539 the destination would index dest_cols out of bounds and panic mid-append, leaving self \
540 partially extended (dest_len={dest_len}, src_len={src_len})"
541 );
542 }
543 for (i, src_col) in source_columns.into_iter().enumerate() {
544 dest_cols[i].extend(src_col)?;
545 }
546 Ok(())
547 }
548
549 pub fn concat(batches: Vec<Columns>) -> Result<Option<Columns>> {
550 let mut iter = batches.into_iter();
551 let mut merged = match iter.next() {
552 Some(first) => first,
553 None => return Ok(None),
554 };
555 for cols in iter {
556 merged.append(cols)?;
557 }
558 if merged.row_count() == 0 {
559 return Ok(None);
560 }
561 Ok(Some(merged))
562 }
563
564 pub fn remove_row(&mut self, row_number: RowNumber) -> bool {
565 let pos = self.row_numbers().iter().position(|&r| r == row_number);
566 let Some(idx) = pos else {
567 return false;
568 };
569
570 let kept_indices: Vec<usize> = (0..self.row_count()).filter(|&i| i != idx).collect();
571 *self = self.extract_by_indices(&kept_indices);
572 true
573 }
574
575 pub fn project_by_names(&self, names: &[String]) -> Columns {
576 let mut new_names = Vec::new();
577 let mut new_buffers = Vec::new();
578
579 for name in names {
580 if let Some(pos) = self.names.iter().position(|n| n.text() == name.as_str()) {
581 new_names.push(self.names[pos].clone());
582 new_buffers.push(self.columns[pos].clone());
583 }
584 }
585
586 if new_buffers.is_empty() {
587 return Columns::empty();
588 }
589
590 Columns {
591 system: self.system.clone(),
592 columns: new_buffers,
593 names: new_names,
594 }
595 }
596
597 pub fn partition_by_keys<K: Hash + Eq + Clone>(&self, keys: &[K]) -> IndexMap<K, Columns> {
598 assert_eq!(keys.len(), self.row_count(), "keys length must match row count");
599
600 let mut key_to_indices: IndexMap<K, Vec<usize>> = IndexMap::new();
601 for (idx, key) in keys.iter().enumerate() {
602 key_to_indices.entry(key.clone()).or_default().push(idx);
603 }
604
605 key_to_indices.into_iter().map(|(key, indices)| (key, self.extract_by_indices(&indices))).collect()
606 }
607
608 pub fn from_row(row: &Row) -> Self {
609 let mut out = Columns::empty();
610 out.reset_from_row(row);
611 out
612 }
613
614 pub fn reset_from_row(&mut self, row: &Row) {
615 let field_count = row.shape.fields().len();
616
617 self.system.clear();
618 self.columns.clear();
619 self.names.clear();
620
621 self.columns.reserve(field_count);
622 self.names.reserve(field_count);
623
624 let (created_at, updated_at) = match row.shape.family() {
625 RowFamily::Pod | RowFamily::Operator => (None, None),
626 _ => (Some(row.shape.created_at(&row.encoded)), Some(row.shape.updated_at(&row.encoded))),
627 };
628
629 self.system.push(RowStamps {
630 row_number: Some(row.number),
631 partition: None,
632 created_at,
633 updated_at,
634 time: row.shape.time(&row.encoded),
635 });
636
637 for (idx, field) in row.shape.fields().iter().enumerate() {
638 let value = row.shape.get_value(&row.encoded, idx);
639
640 let column_type = if matches!(value, Value::None { .. }) {
641 field.constraint.get_type()
642 } else {
643 value.get_type()
644 };
645
646 let mut data = if column_type.is_option() {
647 ColumnBuffer::none_typed(column_type.clone(), 0)
648 } else {
649 ColumnBuffer::with_capacity(column_type.clone(), 1)
650 };
651 data.push_value(value);
652
653 if column_type == ValueType::DictionaryId
654 && let ColumnBuffer::DictionaryId(container) = &mut data
655 && let Some(Constraint::Dictionary(dict_id, _)) = field.constraint.constraint()
656 {
657 container.set_dictionary_id(*dict_id);
658 }
659
660 let name = row.shape.get_field_name(idx).expect("RowShape missing name for field");
661
662 self.names.push(Fragment::internal(name));
663 self.columns.push(data);
664 }
665 }
666}
667
668fn push_keeping_option(buffer: &mut ColumnBuffer, value: Value) {
669 match buffer {
670 ColumnBuffer::Option {
671 inner,
672 bitvec,
673 } if !matches!(value, Value::None { .. }) => {
674 inner.push_value(value);
675 bitvec.push(true);
676 }
677 data => data.push_value(value),
678 }
679}
680
681#[cfg(test)]
682pub mod tests {
683 use std::str::FromStr;
684
685 use reifydb_value::value::{
686 blob::Blob,
687 constraint::{bytes::MaxBytes, precision::Precision, scale::Scale},
688 date::Date,
689 datetime::DateTime,
690 decimal::Decimal,
691 dictionary::{DictionaryEntryId, DictionaryId},
692 duration::Duration,
693 identity::IdentityId,
694 int::Int,
695 time::Time,
696 uint::Uint,
697 uuid::{Uuid4, Uuid7},
698 };
699 use uuid::{Timestamp, Uuid};
700
701 use super::*;
702
703 fn uuid7_at(a: u64, b: u16) -> Uuid7 {
704 Uuid7::from(Uuid::new_v7(Timestamp::from_gregorian_time(a, b)))
705 }
706
707 fn assert_extract_preserves_values(buffer: ColumnBuffer, indices: &[usize]) {
710 let original = Columns::new(vec![ColumnWithName::new("c", buffer)]);
711 let extracted = original.extract_by_indices(indices);
712
713 assert_eq!(extracted.len(), 1, "column count must be preserved");
714 assert_eq!(extracted.row_count(), indices.len(), "row count must equal number of indices");
715
716 let src = original.data_at(0);
717 let dst = extracted.data_at(0);
718 assert_eq!(dst.get_type(), src.get_type(), "value type must be preserved");
719 for (j, &idx) in indices.iter().enumerate() {
720 assert_eq!(
721 dst.get_value(j),
722 src.get_value(idx),
723 "value at extracted row {j} must equal source row {idx}"
724 );
725 }
726 }
727
728 #[test]
729 fn extract_by_indices_preserves_bool_values() {
730 assert_extract_preserves_values(ColumnBuffer::bool([true, false, true, false]), &[3, 1, 2]);
731 }
732
733 #[test]
734 fn extract_by_indices_preserves_float4_values() {
735 assert_extract_preserves_values(ColumnBuffer::float4([1.0f32, 2.5, -3.0, 4.25]), &[3, 1, 2]);
736 }
737
738 #[test]
739 fn extract_by_indices_preserves_float8_values() {
740 assert_extract_preserves_values(ColumnBuffer::float8([1.0f64, 2.5, -3.0, 4.25]), &[3, 1, 2]);
741 }
742
743 #[test]
744 fn extract_by_indices_preserves_int1_values() {
745 assert_extract_preserves_values(ColumnBuffer::int1([-1i8, 2, -3, 4]), &[3, 1, 2]);
746 }
747
748 #[test]
749 fn extract_by_indices_preserves_int2_values() {
750 assert_extract_preserves_values(ColumnBuffer::int2([-1i16, 2, -3, 4]), &[3, 1, 2]);
751 }
752
753 #[test]
754 fn extract_by_indices_preserves_int4_values() {
755 assert_extract_preserves_values(ColumnBuffer::int4([-1i32, 2, -3, 4]), &[3, 1, 2]);
756 }
757
758 #[test]
759 fn extract_by_indices_preserves_int8_values() {
760 assert_extract_preserves_values(ColumnBuffer::int8([-1i64, 2, -3, 4]), &[3, 1, 2]);
761 }
762
763 #[test]
764 fn extract_by_indices_preserves_int16_values() {
765 assert_extract_preserves_values(ColumnBuffer::int16([-1i128, 2, -3, 4]), &[3, 1, 2]);
766 }
767
768 #[test]
769 fn extract_by_indices_preserves_uint1_values() {
770 assert_extract_preserves_values(ColumnBuffer::uint1([1u8, 2, 3, 4]), &[3, 1, 2]);
771 }
772
773 #[test]
774 fn extract_by_indices_preserves_uint2_values() {
775 assert_extract_preserves_values(ColumnBuffer::uint2([1u16, 2, 3, 4]), &[3, 1, 2]);
776 }
777
778 #[test]
779 fn extract_by_indices_preserves_uint4_values() {
780 assert_extract_preserves_values(ColumnBuffer::uint4([1u32, 2, 3, 4]), &[3, 1, 2]);
781 }
782
783 #[test]
784 fn extract_by_indices_preserves_uint8_values() {
785 assert_extract_preserves_values(ColumnBuffer::uint8([1u64, 2, 3, 4]), &[3, 1, 2]);
786 }
787
788 #[test]
789 fn extract_by_indices_preserves_uint16_values() {
790 assert_extract_preserves_values(ColumnBuffer::uint16([1u128, 2, 3, 4]), &[3, 1, 2]);
791 }
792
793 #[test]
794 fn extract_by_indices_preserves_utf8_values() {
795 assert_extract_preserves_values(ColumnBuffer::utf8(["a", "bb", "ccc", "dddd"]), &[3, 1, 2]);
796 }
797
798 #[test]
799 fn extract_by_indices_preserves_date_values() {
800 let data = [
801 Date::from_ymd(2025, 1, 1).unwrap(),
802 Date::from_ymd(2025, 6, 15).unwrap(),
803 Date::from_ymd(2024, 12, 31).unwrap(),
804 Date::from_ymd(2000, 2, 29).unwrap(),
805 ];
806 assert_extract_preserves_values(ColumnBuffer::date(data), &[3, 1, 2]);
807 }
808
809 #[test]
810 fn extract_by_indices_preserves_datetime_values() {
811 let data = [
812 DateTime::from_epoch_secs(1000).unwrap(),
813 DateTime::from_epoch_secs(2000).unwrap(),
814 DateTime::from_epoch_secs(3000).unwrap(),
815 DateTime::from_epoch_secs(4000).unwrap(),
816 ];
817 assert_extract_preserves_values(ColumnBuffer::datetime(data), &[3, 1, 2]);
818 }
819
820 #[test]
821 fn extract_by_indices_preserves_time_values() {
822 let data = [
823 Time::from_hms(0, 0, 0).unwrap(),
824 Time::from_hms(12, 30, 45).unwrap(),
825 Time::from_hms(23, 59, 59).unwrap(),
826 Time::from_hms(6, 15, 0).unwrap(),
827 ];
828 assert_extract_preserves_values(ColumnBuffer::time(data), &[3, 1, 2]);
829 }
830
831 #[test]
832 fn extract_by_indices_preserves_duration_values() {
833 let data = [
834 Duration::from_days(1).unwrap(),
835 Duration::from_days(7).unwrap(),
836 Duration::from_days(30).unwrap(),
837 Duration::from_days(365).unwrap(),
838 ];
839 assert_extract_preserves_values(ColumnBuffer::duration(data), &[3, 1, 2]);
840 }
841
842 #[test]
843 fn extract_by_indices_preserves_identity_id_values() {
844 let data = [IdentityId::root(), IdentityId::system(), IdentityId::anonymous(), IdentityId::root()];
845 assert_extract_preserves_values(ColumnBuffer::identity_id(data), &[3, 1, 2]);
846 }
847
848 #[test]
849 fn extract_by_indices_preserves_uuid4_values() {
850 let data = [Uuid4::generate(), Uuid4::generate(), Uuid4::generate(), Uuid4::generate()];
851 assert_extract_preserves_values(ColumnBuffer::uuid4(data), &[3, 1, 2]);
852 }
853
854 #[test]
855 fn extract_by_indices_preserves_uuid7_values() {
856 let data = [uuid7_at(1, 1), uuid7_at(1, 2), uuid7_at(2, 1), uuid7_at(2, 2)];
857 assert_extract_preserves_values(ColumnBuffer::uuid7(data), &[3, 1, 2]);
858 }
859
860 #[test]
861 fn extract_by_indices_preserves_blob_values() {
862 let data = [
863 Blob::new(vec![1]),
864 Blob::new(vec![2, 3]),
865 Blob::new(vec![4, 5, 6]),
866 Blob::new(vec![7, 8, 9, 10]),
867 ];
868 assert_extract_preserves_values(ColumnBuffer::blob(data), &[3, 1, 2]);
869 }
870
871 #[test]
872 fn extract_by_indices_preserves_int_values() {
873 let data = [Int::from(-1i64), Int::from(2i64), Int::from(-3i64), Int::from(4i64)];
874 assert_extract_preserves_values(ColumnBuffer::int(data), &[3, 1, 2]);
875 }
876
877 #[test]
878 fn extract_by_indices_preserves_uint_values() {
879 let data = [Uint::from(1u64), Uint::from(2u64), Uint::from(3u64), Uint::from(4u64)];
880 assert_extract_preserves_values(ColumnBuffer::uint(data), &[3, 1, 2]);
881 }
882
883 #[test]
884 fn extract_by_indices_preserves_decimal_values() {
885 let data = [
886 Decimal::from_str("1.50").unwrap(),
887 Decimal::from_str("2.25").unwrap(),
888 Decimal::from_str("-3.75").unwrap(),
889 Decimal::from_str("4.00").unwrap(),
890 ];
891 assert_extract_preserves_values(ColumnBuffer::decimal(data), &[3, 1, 2]);
892 }
893
894 #[test]
895 fn extract_by_indices_preserves_any_values() {
896 let data = [Value::Int4(1), Value::Utf8("two".to_string()), Value::Boolean(true), Value::none()];
897 assert_extract_preserves_values(ColumnBuffer::any(data), &[3, 1, 2]);
898 }
899
900 #[test]
901 fn extract_by_indices_preserves_dictionary_id_values() {
902 let data = [
903 DictionaryEntryId::U2(10),
904 DictionaryEntryId::U2(20),
905 DictionaryEntryId::U2(30),
906 DictionaryEntryId::U2(40),
907 ];
908 assert_extract_preserves_values(ColumnBuffer::dictionary_id(data), &[3, 1, 2]);
909 }
910
911 #[test]
912 fn extract_by_indices_preserves_option_values_including_none() {
913 let mut buffer = ColumnBuffer::with_capacity(ValueType::Option(Box::new(ValueType::Int4)), 0);
914 buffer.push_value(Value::Int4(1));
915 buffer.push_value(Value::none());
916 buffer.push_value(Value::Int4(3));
917 buffer.push_value(Value::none());
918 assert_extract_preserves_values(buffer, &[3, 1, 2, 0]);
919 }
920
921 #[test]
922 fn extract_by_indices_empty_indices_yields_empty_columns() {
923 let original = Columns::new(vec![ColumnWithName::int4("c", [1, 2, 3])]);
924 let extracted = original.extract_by_indices(&[]);
925 assert_eq!(extracted.row_count(), 0);
926 assert!(extracted.is_empty());
927 }
928
929 #[test]
930 fn extract_by_indices_full_identity_reproduces_all_rows() {
931 assert_extract_preserves_values(ColumnBuffer::int4([10, 20, 30, 40]), &[0, 1, 2, 3]);
932 }
933
934 #[test]
935 fn heap_size_grows_with_row_count() {
936 let small = Columns::new(vec![ColumnWithName::int4("c", [1i32, 2, 3, 4])]);
937 let large = Columns::new(vec![ColumnWithName::int4("c", 0..4000i32)]);
938 assert!(
939 large.heap_size() > small.heap_size() + 4000,
940 "heap_size must scale with the number of buffered rows (small={}, large={})",
941 small.heap_size(),
942 large.heap_size()
943 );
944 }
945
946 #[test]
947 fn heap_size_counts_utf8_payload_not_just_row_count() {
948 let short = Columns::new(vec![ColumnWithName::new("c", ColumnBuffer::utf8(["a", "b", "c"]))]);
951 let long_value = "x".repeat(4096);
952 let long = Columns::new(vec![ColumnWithName::new(
953 "c",
954 ColumnBuffer::utf8([long_value.clone(), long_value.clone(), long_value.clone()]),
955 )]);
956 assert_eq!(short.row_count(), long.row_count(), "same row count is the point of the test");
957 assert!(
958 long.heap_size() >= short.heap_size() + 3 * 4096,
959 "heap_size must account for utf8 payload bytes (short={}, long={})",
960 short.heap_size(),
961 long.heap_size()
962 );
963 }
964
965 #[test]
966 fn extract_by_indices_duplicate_index_duplicates_row() {
967 let original = Columns::new(vec![ColumnWithName::int4("c", [10, 20, 30])]);
968 let extracted = original.extract_by_indices(&[1, 1, 1]);
969 assert_eq!(extracted.row_count(), 3);
970 assert_eq!(extracted.data_at(0).get_value(0), Value::Int4(20));
971 assert_eq!(extracted.data_at(0).get_value(1), Value::Int4(20));
972 assert_eq!(extracted.data_at(0).get_value(2), Value::Int4(20));
973 }
974
975 #[test]
976 fn extract_by_indices_extracts_multiple_columns_consistently() {
977 let original = Columns::new(vec![
978 ColumnWithName::int4("id", [1, 2, 3, 4]),
979 ColumnWithName::utf8(
980 "name",
981 ["a".to_string(), "b".to_string(), "c".to_string(), "d".to_string()],
982 ),
983 ColumnWithName::bool("flag", [true, false, true, false]),
984 ]);
985 let extracted = original.extract_by_indices(&[2, 0]);
986
987 assert_eq!(extracted.len(), 3);
988 assert_eq!(extracted.row_count(), 2);
989 assert_eq!(extracted.column("id").unwrap().data().get_value(0), Value::Int4(3));
990 assert_eq!(extracted.column("id").unwrap().data().get_value(1), Value::Int4(1));
991 assert_eq!(extracted.column("name").unwrap().data().get_value(0), Value::Utf8("c".to_string()));
992 assert_eq!(extracted.column("name").unwrap().data().get_value(1), Value::Utf8("a".to_string()));
993 assert_eq!(extracted.column("flag").unwrap().data().get_value(0), Value::Boolean(true));
994 assert_eq!(extracted.column("flag").unwrap().data().get_value(1), Value::Boolean(true));
995 }
996
997 #[test]
998 fn extract_by_indices_extracts_system_columns_in_order() {
999 let columns = vec![ColumnWithName::int4("id", [10, 20, 30, 40])];
1000 let row_numbers = vec![RowNumber::from(1), RowNumber::from(2), RowNumber::from(3), RowNumber::from(4)];
1001 let created_at = vec![
1002 DateTime::from_epoch_secs(1000).unwrap(),
1003 DateTime::from_epoch_secs(2000).unwrap(),
1004 DateTime::from_epoch_secs(3000).unwrap(),
1005 DateTime::from_epoch_secs(4000).unwrap(),
1006 ];
1007 let updated_at = vec![
1008 DateTime::from_epoch_secs(1100).unwrap(),
1009 DateTime::from_epoch_secs(2200).unwrap(),
1010 DateTime::from_epoch_secs(3300).unwrap(),
1011 DateTime::from_epoch_secs(4400).unwrap(),
1012 ];
1013 let time = created_at.clone();
1014 let original = Columns::with_system(
1015 columns,
1016 SystemColumns::new(row_numbers, Vec::new(), created_at, updated_at, time),
1017 );
1018
1019 let extracted = original.extract_by_indices(&[3, 0]);
1020
1021 let rns: Vec<RowNumber> = extracted.row_numbers().iter().cloned().collect();
1022 assert_eq!(rns, vec![RowNumber::from(4), RowNumber::from(1)], "row_numbers must follow indices");
1023 assert_eq!(
1024 extracted.created_at().iter().cloned().collect::<Vec<_>>(),
1025 vec![DateTime::from_epoch_secs(4000).unwrap(), DateTime::from_epoch_secs(1000).unwrap()],
1026 "created_at must follow indices"
1027 );
1028 assert_eq!(
1029 extracted.updated_at().iter().cloned().collect::<Vec<_>>(),
1030 vec![DateTime::from_epoch_secs(4400).unwrap(), DateTime::from_epoch_secs(1100).unwrap()],
1031 "updated_at must follow indices"
1032 );
1033 }
1034
1035 #[test]
1041 fn extract_by_indices_preserves_dictionary_id_metadata() {
1042 let mut buffer = ColumnBuffer::dictionary_id([
1043 DictionaryEntryId::U2(10),
1044 DictionaryEntryId::U2(20),
1045 DictionaryEntryId::U2(30),
1046 ]);
1047 match &mut buffer {
1048 ColumnBuffer::DictionaryId(container) => container.set_dictionary_id(DictionaryId(42)),
1049 _ => unreachable!("dictionary_id factory must build a DictionaryId buffer"),
1050 }
1051
1052 let original = Columns::new(vec![ColumnWithName::new("token", buffer)]);
1053 let extracted = original.extract_by_indices(&[2, 0]);
1054
1055 match extracted.data_at(0) {
1056 ColumnBuffer::DictionaryId(container) => {
1057 assert_eq!(
1058 container.dictionary_id(),
1059 Some(DictionaryId(42)),
1060 "dictionary_id metadata must survive extraction"
1061 );
1062 }
1063 other => panic!("expected DictionaryId buffer, got {:?}", other.get_type()),
1064 }
1065 }
1066
1067 #[test]
1068 fn extract_by_indices_preserves_utf8_max_bytes_metadata() {
1069 let mut buffer = ColumnBuffer::utf8(["a", "bb", "ccc"]);
1070 match &mut buffer {
1071 ColumnBuffer::Utf8 {
1072 max_bytes,
1073 ..
1074 } => *max_bytes = MaxBytes::new(255),
1075 _ => unreachable!(),
1076 }
1077
1078 let original = Columns::new(vec![ColumnWithName::new("c", buffer)]);
1079 let extracted = original.extract_by_indices(&[2, 0]);
1080
1081 match extracted.data_at(0) {
1082 ColumnBuffer::Utf8 {
1083 max_bytes,
1084 ..
1085 } => assert_eq!(*max_bytes, MaxBytes::new(255), "Utf8 max_bytes must survive extraction"),
1086 other => panic!("expected Utf8 buffer, got {:?}", other.get_type()),
1087 }
1088 }
1089
1090 #[test]
1091 fn extract_by_indices_preserves_blob_max_bytes_metadata() {
1092 let mut buffer = ColumnBuffer::blob([Blob::new(vec![1]), Blob::new(vec![2, 3]), Blob::new(vec![4])]);
1093 match &mut buffer {
1094 ColumnBuffer::Blob {
1095 max_bytes,
1096 ..
1097 } => *max_bytes = MaxBytes::new(1024),
1098 _ => unreachable!(),
1099 }
1100
1101 let original = Columns::new(vec![ColumnWithName::new("c", buffer)]);
1102 let extracted = original.extract_by_indices(&[2, 0]);
1103
1104 match extracted.data_at(0) {
1105 ColumnBuffer::Blob {
1106 max_bytes,
1107 ..
1108 } => assert_eq!(*max_bytes, MaxBytes::new(1024), "Blob max_bytes must survive extraction"),
1109 other => panic!("expected Blob buffer, got {:?}", other.get_type()),
1110 }
1111 }
1112
1113 #[test]
1114 fn extract_by_indices_preserves_int_max_bytes_metadata() {
1115 let mut buffer = ColumnBuffer::int([Int::from(1i64), Int::from(2i64), Int::from(3i64)]);
1116 match &mut buffer {
1117 ColumnBuffer::Int {
1118 max_bytes,
1119 ..
1120 } => *max_bytes = MaxBytes::new(16),
1121 _ => unreachable!(),
1122 }
1123
1124 let original = Columns::new(vec![ColumnWithName::new("c", buffer)]);
1125 let extracted = original.extract_by_indices(&[2, 0]);
1126
1127 match extracted.data_at(0) {
1128 ColumnBuffer::Int {
1129 max_bytes,
1130 ..
1131 } => assert_eq!(*max_bytes, MaxBytes::new(16), "Int max_bytes must survive extraction"),
1132 other => panic!("expected Int buffer, got {:?}", other.get_type()),
1133 }
1134 }
1135
1136 #[test]
1137 fn extract_by_indices_preserves_uint_max_bytes_metadata() {
1138 let mut buffer = ColumnBuffer::uint([Uint::from(1u64), Uint::from(2u64), Uint::from(3u64)]);
1139 match &mut buffer {
1140 ColumnBuffer::Uint {
1141 max_bytes,
1142 ..
1143 } => *max_bytes = MaxBytes::new(8),
1144 _ => unreachable!(),
1145 }
1146
1147 let original = Columns::new(vec![ColumnWithName::new("c", buffer)]);
1148 let extracted = original.extract_by_indices(&[2, 0]);
1149
1150 match extracted.data_at(0) {
1151 ColumnBuffer::Uint {
1152 max_bytes,
1153 ..
1154 } => assert_eq!(*max_bytes, MaxBytes::new(8), "Uint max_bytes must survive extraction"),
1155 other => panic!("expected Uint buffer, got {:?}", other.get_type()),
1156 }
1157 }
1158
1159 #[test]
1160 fn extract_by_indices_preserves_decimal_precision_and_scale_metadata() {
1161 let mut buffer = ColumnBuffer::decimal([
1162 Decimal::from_str("1.50").unwrap(),
1163 Decimal::from_str("2.25").unwrap(),
1164 Decimal::from_str("3.75").unwrap(),
1165 ]);
1166 match &mut buffer {
1167 ColumnBuffer::Decimal {
1168 precision,
1169 scale,
1170 ..
1171 } => {
1172 *precision = Precision::new(10);
1173 *scale = Scale::new(2);
1174 }
1175 _ => unreachable!(),
1176 }
1177
1178 let original = Columns::new(vec![ColumnWithName::new("c", buffer)]);
1179 let extracted = original.extract_by_indices(&[2, 0]);
1180
1181 match extracted.data_at(0) {
1182 ColumnBuffer::Decimal {
1183 precision,
1184 scale,
1185 ..
1186 } => {
1187 assert_eq!(*precision, Precision::new(10), "Decimal precision must survive extraction");
1188 assert_eq!(*scale, Scale::new(2), "Decimal scale must survive extraction");
1189 }
1190 other => panic!("expected Decimal buffer, got {:?}", other.get_type()),
1191 }
1192 }
1193
1194 #[test]
1195 fn test_single_row_temporal_types() {
1196 let date = Date::from_ymd(2025, 1, 15).unwrap();
1197 let datetime = DateTime::from_epoch_secs(1642694400).unwrap();
1198 let time = Time::from_hms(14, 30, 45).unwrap();
1199 let duration = Duration::from_days(30).unwrap();
1200
1201 let columns = Columns::single_row([
1202 ("date_col", Value::Date(date.clone())),
1203 ("datetime_col", Value::DateTime(datetime.clone())),
1204 ("time_col", Value::Time(time.clone())),
1205 ("interval_col", Value::Duration(duration.clone())),
1206 ]);
1207
1208 assert_eq!(columns.len(), 4);
1209 assert_eq!(columns.shape(), (1, 4));
1210
1211 assert_eq!(columns.column("date_col").unwrap().data().get_value(0), Value::Date(date));
1212 assert_eq!(columns.column("datetime_col").unwrap().data().get_value(0), Value::DateTime(datetime));
1213 assert_eq!(columns.column("time_col").unwrap().data().get_value(0), Value::Time(time));
1214 assert_eq!(columns.column("interval_col").unwrap().data().get_value(0), Value::Duration(duration));
1215 }
1216
1217 #[test]
1218 fn test_single_row_mixed_types() {
1219 let date = Date::from_ymd(2025, 7, 15).unwrap();
1220 let time = Time::from_hms(9, 15, 30).unwrap();
1221
1222 let columns = Columns::single_row([
1223 ("bool_col", Value::Boolean(true)),
1224 ("int_col", Value::Int4(42)),
1225 ("str_col", Value::Utf8("hello".to_string())),
1226 ("date_col", Value::Date(date.clone())),
1227 ("time_col", Value::Time(time.clone())),
1228 ("none_col", Value::none()),
1229 ]);
1230
1231 assert_eq!(columns.len(), 6);
1232 assert_eq!(columns.shape(), (1, 6));
1233
1234 assert_eq!(columns.column("bool_col").unwrap().data().get_value(0), Value::Boolean(true));
1235 assert_eq!(columns.column("int_col").unwrap().data().get_value(0), Value::Int4(42));
1236 assert_eq!(columns.column("str_col").unwrap().data().get_value(0), Value::Utf8("hello".to_string()));
1237 assert_eq!(columns.column("date_col").unwrap().data().get_value(0), Value::Date(date));
1238 assert_eq!(columns.column("time_col").unwrap().data().get_value(0), Value::Time(time));
1239 assert_eq!(columns.column("none_col").unwrap().data().get_value(0), Value::none());
1240 }
1241
1242 #[test]
1243 fn test_single_row_none_of_int4_is_int4_typed() {
1244 let columns = Columns::single_row([("n", Value::none_of(ValueType::Int4))]);
1247 match columns.column("n").unwrap().data().get_value(0) {
1248 Value::None {
1249 inner,
1250 } => assert_eq!(inner, ValueType::Int4),
1251 other => panic!("expected Value::None, got {other:?}"),
1252 }
1253 }
1254
1255 #[test]
1256 fn test_single_row_none_of_utf8_is_utf8_typed() {
1257 let columns = Columns::single_row([("n", Value::none_of(ValueType::Utf8))]);
1258 match columns.column("n").unwrap().data().get_value(0) {
1259 Value::None {
1260 inner,
1261 } => assert_eq!(inner, ValueType::Utf8),
1262 other => panic!("expected Value::None, got {other:?}"),
1263 }
1264 }
1265
1266 #[test]
1267 fn test_single_row_bare_none_is_any_typed() {
1268 let columns = Columns::single_row([("n", Value::none())]);
1269 match columns.column("n").unwrap().data().get_value(0) {
1270 Value::None {
1271 inner,
1272 } => assert_eq!(inner, ValueType::Any),
1273 other => panic!("expected Value::None, got {other:?}"),
1274 }
1275 }
1276
1277 #[test]
1278 fn test_single_row_none_of_nested_option_collapses_to_base_type() {
1279 let inner_ty = ValueType::Option(Box::new(ValueType::Duration));
1282 let columns = Columns::single_row([("n", Value::none_of(inner_ty))]);
1283 match columns.column("n").unwrap().data().get_value(0) {
1284 Value::None {
1285 inner,
1286 } => assert_eq!(inner, ValueType::Duration),
1287 other => panic!("expected Value::None, got {other:?}"),
1288 }
1289 }
1290
1291 #[test]
1292 fn test_single_row_none_of_boolean_is_boolean_typed() {
1293 let columns = Columns::single_row([("n", Value::none_of(ValueType::Boolean))]);
1296 match columns.column("n").unwrap().data().get_value(0) {
1297 Value::None {
1298 inner,
1299 } => assert_eq!(inner, ValueType::Boolean),
1300 other => panic!("expected Value::None, got {other:?}"),
1301 }
1302 }
1303
1304 #[test]
1305 fn test_single_row_normal_column_names_work() {
1306 let columns = Columns::single_row([("normal_column", Value::Int4(42))]);
1307 assert_eq!(columns.len(), 1);
1308 assert_eq!(columns.column("normal_column").unwrap().data().get_value(0), Value::Int4(42));
1309 }
1310
1311 #[test]
1312 fn with_row_numbers_leaves_an_absent_sidecar_absent() {
1313 let columns = Columns::new(vec![ColumnWithName::new("v", ColumnBuffer::int4([1, 2, 3]))])
1315 .with_row_numbers(vec![RowNumber(1), RowNumber(2), RowNumber(3)]);
1316
1317 assert_eq!(columns.system.row_numbers().len(), 3);
1318 assert!(columns.system.time().is_empty(), "#time must stay absent");
1319 assert!(columns.system.created_at().is_empty(), "created_at must stay absent");
1320 assert!(columns.system.updated_at().is_empty(), "updated_at must stay absent");
1321 }
1322
1323 #[test]
1324 fn with_row_numbers_keeps_a_populated_sidecar() {
1325 let stamps = vec![DateTime::from_nanos(10), DateTime::from_nanos(20)];
1326 let columns = Columns::with_system(
1327 vec![ColumnWithName::new("v", ColumnBuffer::int4([1, 2]))],
1328 SystemColumns::new(
1329 vec![RowNumber(7), RowNumber(8)],
1330 Vec::new(),
1331 Vec::new(),
1332 Vec::new(),
1333 stamps.clone(),
1334 ),
1335 )
1336 .with_row_numbers(vec![RowNumber(1), RowNumber(2)]);
1337
1338 assert_eq!(columns.system.time(), stamps.as_slice());
1339 assert_eq!(columns.system.row_numbers(), &[RowNumber(1), RowNumber(2)]);
1340 }
1341
1342 #[test]
1343 #[should_panic(expected = "Columns::with_row_numbers")]
1344 fn with_row_numbers_panics_on_a_partial_sidecar() {
1345 let columns = Columns::with_system(
1347 vec![ColumnWithName::new("v", ColumnBuffer::int4([1, 2, 3]))],
1348 SystemColumns::new(
1349 vec![RowNumber(1), RowNumber(2), RowNumber(3)],
1350 Vec::new(),
1351 Vec::new(),
1352 Vec::new(),
1353 vec![DateTime::from_nanos(10), DateTime::from_nanos(20), DateTime::from_nanos(30)],
1354 ),
1355 );
1356
1357 let _ = columns.with_row_numbers(vec![RowNumber(1), RowNumber(2)]);
1358 }
1359}