akar_processor/physical/
index_lookup.rs1use crate::physical::common::store_value_in_vector;
8use crate::physical::types::{OperatorResult, PhysicalOperatorExec};
9use akar_common::types::Value;
10use akar_common::vector::{DataChunk, ValueVector};
11use akar_storage::table::TableCatalog;
12use std::sync::Arc;
13
14pub struct PhysicalIndexLookup {
20 pub table_name: String,
21 pub table_id: u64,
22 pub key_value: Value,
24 pub table_catalog: Arc<TableCatalog>,
25}
26
27impl PhysicalOperatorExec for PhysicalIndexLookup {
28 fn operator_type(&self) -> &str {
29 "index_lookup"
30 }
31
32 fn execute(&self, _input: Vec<DataChunk>) -> OperatorResult {
33 let node_table = self
34 .table_catalog
35 .get_node_table_by_name(&self.table_name)
36 .ok_or_else(|| format!("Node table '{}' not found for IndexLookup", self.table_name))?;
37
38 let row_ids = node_table.lookup_by_pk_range(
40 Some(&self.key_value),
41 true, Some(&self.key_value),
43 true, 1, );
46
47 if row_ids.is_empty() {
48 return Ok(vec![DataChunk::new(vec![], vec![])]);
49 }
50
51 let row_id = row_ids[0] as usize;
52 let num_cols = node_table.columns.len();
53
54 let mut fields = Vec::with_capacity(num_cols);
55 let mut field_types = Vec::with_capacity(num_cols);
56 let mut field_names = Vec::with_capacity(num_cols);
57
58 for col_idx in 0..num_cols {
59 let val = node_table.get_value(row_id, col_idx).cloned().unwrap_or(Value::Null);
60
61 let phys_type = val.physical_type();
62 let mut v = ValueVector::new(phys_type, 1);
63 v.resize(1);
64 if matches!(val, Value::Null) {
65 v.set_null(0, true);
66 } else {
67 store_value_in_vector(&mut v, 0, &val)?;
68 }
69 fields.push(akar_common::arrow_vector::ArrowVector::from_legacy(&v).array);
70 field_types.push(phys_type);
71 field_names.push(node_table.columns[col_idx].name.clone());
72 }
73
74 drop(node_table);
75
76 Ok(vec![DataChunk {
77 fields,
78 field_types,
79 size: 1,
80 field_names,
81 sel_vector: None,
82 }])
83 }
84}