realm_db_reader/table/
mod.rs1mod column;
2mod header;
3mod row;
4
5use anyhow::{Ok, anyhow, bail};
6use tracing::{debug, instrument};
7
8use crate::array::Array;
9use crate::column::Column;
10pub(crate) use crate::table::column::ColumnAttributes;
11use crate::table::header::TableHeader;
12pub use crate::table::row::Row;
13use crate::value::Value;
14
15#[derive(Debug)]
17#[allow(unused)]
18pub struct Table {
19 header: TableHeader,
20 table_number: usize,
21}
22
23impl Table {
24 #[instrument(level = "debug")]
26 pub(crate) fn build(array: Array, table_number: usize) -> anyhow::Result<Self> {
27 let header_array = array.get_node(0)?.unwrap();
28 let data_array = array.get_node(1)?.unwrap();
29
30 Self::build_from(&header_array, data_array, table_number)
31 }
32
33 #[instrument(level = "debug")]
37 pub(crate) fn build_from(
38 header_array: &Array,
39 data_array: Array,
40 table_number: usize,
41 ) -> anyhow::Result<Self> {
42 let header = TableHeader::build(header_array, &data_array)?;
43
44 let result = Self {
45 header,
46 table_number,
47 };
48
49 debug!("data: {:?}", result);
50 Ok(result)
51 }
52}
53
54impl Table {
55 pub fn get_table_number(&self) -> usize {
60 self.table_number
61 }
62
63 pub fn get_column_specs(&self) -> &[Box<dyn Column>] {
65 self.header.get_columns()
66 }
67
68 pub fn get_column_spec(&self, column_number: usize) -> Option<&dyn Column> {
72 self.header.get_column(column_number)
73 }
74
75 #[instrument(level = "debug", skip(self), fields(header = ?self.header))]
77 pub fn row_count(&self) -> anyhow::Result<usize> {
78 let first_column = self
79 .header
80 .get_column(0)
81 .ok_or_else(|| anyhow::anyhow!("No column at index 0: can't load row count"))?;
82 first_column.count()
83 }
84
85 #[instrument(level = "debug", skip(self), fields(header = ?self.header))]
87 pub fn get_row<'a>(&'a self, row_number: usize) -> anyhow::Result<Row<'a>> {
88 let values = self.load_row(row_number)?;
89
90 Ok(Row::new(
91 values,
92 self.header
93 .get_columns()
94 .iter()
95 .filter_map(|c| c.name())
96 .map(|n| n.into())
97 .collect(),
98 ))
99 }
100
101 #[instrument(level = "debug", skip(self), fields(header = ?self.header))]
103 fn load_row(&self, row_number: usize) -> anyhow::Result<Vec<Value>> {
104 let column_count = self.header.column_count();
105 let mut values = Vec::with_capacity(column_count);
106 for column_number in 0..column_count {
107 tracing::info!("loading column {column_number} for row {row_number}");
108 values.push(self.load_column(column_number, row_number)?);
109 }
110
111 Ok(values)
112 }
113
114 #[instrument(level = "debug", skip(self), fields(header = ?self.header))]
122 pub fn find_row_number_from_indexed_column(
123 &self,
124 indexed_column_name: &str,
125 value: &Value,
126 ) -> anyhow::Result<Option<usize>> {
127 let column_spec = self
129 .header
130 .get_columns()
131 .iter()
132 .find(|col| col.name() == Some(indexed_column_name))
133 .ok_or_else(|| anyhow!("Column not found: {}", indexed_column_name))?;
134
135 if !column_spec.is_indexed() {
136 bail!(
137 "Column '{}' is not indexed, cannot perform lookup",
138 indexed_column_name
139 );
140 }
141
142 column_spec.get_row_number_by_index(value)
143 }
144
145 #[instrument(level = "debug", skip(self), fields(header = ?self.header))]
152 pub fn find_row_from_indexed_column<'a>(
153 &'a self,
154 indexed_column_name: &str,
155 value: &Value,
156 ) -> anyhow::Result<Option<Row<'a>>> {
157 let Some(row_number) =
158 self.find_row_number_from_indexed_column(indexed_column_name, value)?
159 else {
160 return Ok(None);
161 };
162
163 self.get_row(row_number).map(Some)
164 }
165
166 #[instrument(level = "debug", skip(self), fields(header = ?self.header))]
168 pub fn get_rows<'a>(&'a self) -> anyhow::Result<Vec<Row<'a>>> {
169 let row_count = self.row_count()?;
170 let mut rows = Vec::with_capacity(row_count);
171
172 for i in 0..row_count {
173 rows.push(self.get_row(i)?);
174 }
175
176 Ok(rows)
177 }
178
179 #[instrument(level = "debug", skip(self))]
183 fn load_column(&self, column_number: usize, row_number: usize) -> anyhow::Result<Value> {
184 let column_spec = self
185 .header
186 .get_column(column_number)
187 .unwrap_or_else(|| panic!("Invalid column number {column_number}"));
188 let value = column_spec.get(row_number)?;
189
190 debug!(
191 "Loaded column {column_number} at row {row_number}: {:?}",
192 value
193 );
194
195 Ok(value)
196 }
197}