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