realm_db_reader/column/
mod.rs

1use std::fmt::Debug;
2
3use crate::array::RealmRef;
4pub(crate) use crate::column::backlink::create_backlink_column;
5pub(crate) use crate::column::bool::create_bool_column;
6pub(crate) use crate::column::bool_optional::create_bool_null_column;
7use crate::column::bptree::BpTree;
8pub(crate) use crate::column::double::create_double_column;
9pub(crate) use crate::column::float::create_float_column;
10pub(crate) use crate::column::integer::create_int_column;
11pub(crate) use crate::column::integer_optional::create_int_null_column;
12pub(crate) use crate::column::link::create_link_column;
13pub(crate) use crate::column::linklist::create_linklist_column;
14pub(crate) use crate::column::string::create_string_column;
15pub(crate) use crate::column::subtable::create_subtable_column;
16pub(crate) use crate::column::timestamp::create_timestamp_column;
17use crate::index::Index;
18use crate::realm::Realm;
19use crate::table::ColumnAttributes;
20use crate::traits::{ArrayLike, Node, NodeWithContext};
21use crate::value::Value;
22use std::sync::Arc;
23
24mod backlink;
25mod bool;
26mod bool_optional;
27mod bptree;
28mod double;
29mod float;
30mod integer;
31mod integer_optional;
32mod link;
33mod linklist;
34mod string;
35mod subtable;
36mod timestamp;
37
38/// A column for a table.
39pub trait Column: Debug + Send {
40    /// Get the value for this column for the row with the given index.
41    fn get(&self, index: usize) -> crate::RealmResult<Value>;
42
43    /// Check whether the value at the given index is null. Note that some
44    /// column types are never null, see [`Value`] for details.
45    fn is_null(&self, index: usize) -> crate::RealmResult<bool>;
46
47    /// Get the total number of values in this column.
48    fn count(&self) -> crate::RealmResult<usize>;
49
50    /// Get whether this column is nullable. Note that some column types are
51    /// never null, see [`Value`] for details.
52    fn nullable(&self) -> bool;
53
54    /// Is this column indexed? If so, you can use
55    /// [`table.find_row_from_indexed_column`](crate::Table::find_row_from_indexed_column)
56    /// to find rows by a known value based on this column.
57    fn is_indexed(&self) -> bool;
58
59    /// Look up a value for this column in the index.
60    ///
61    /// Panics if this column is not indexed.
62    fn get_row_number_by_index(&self, lookup_value: &Value) -> crate::RealmResult<Option<usize>>;
63
64    /// Get the name of this column. All columns except backlinks are named.
65    fn name(&self) -> Option<&str>;
66}
67
68/// The definition of a column type, which includes the value type, leaf type, and B+Tree type.
69pub(crate) trait ColumnType {
70    type Value: Into<Value>;
71    type LeafContext: Copy + Debug;
72    type LeafType: ArrayLike<Self::Value, Self::LeafContext>;
73}
74
75struct ColumnImpl<T: ColumnType> {
76    tree: BpTree<T>,
77    index: Option<Index>,
78    attributes: ColumnAttributes,
79    name: Option<String>,
80}
81
82impl<T: ColumnType> Debug for ColumnImpl<T> {
83    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
84        f.debug_struct("ColumnImpl")
85            .field("tree", &self.tree)
86            .field("attributes", &self.attributes)
87            .field("name", &self.name)
88            .finish()
89    }
90}
91
92impl<T: ColumnType + Send> Column for ColumnImpl<T>
93where
94    Value: From<T::Value>,
95    <T as ColumnType>::LeafContext: Send,
96    <T as ColumnType>::LeafType: Send,
97{
98    fn get(&self, index: usize) -> crate::RealmResult<Value> {
99        Ok(Value::from(self.tree.get(index)?))
100    }
101
102    fn is_null(&self, index: usize) -> crate::RealmResult<bool> {
103        self.tree.is_null(index)
104    }
105
106    fn count(&self) -> crate::RealmResult<usize> {
107        self.tree.count()
108    }
109
110    fn nullable(&self) -> bool {
111        self.attributes.is_nullable()
112    }
113
114    fn is_indexed(&self) -> bool {
115        self.attributes.is_indexed()
116    }
117
118    fn get_row_number_by_index(&self, lookup_value: &Value) -> crate::RealmResult<Option<usize>> {
119        let Some(index) = &self.index else {
120            panic!("Column {:?} is not indexed", self.name());
121        };
122
123        index.find_first(lookup_value)
124    }
125
126    fn name(&self) -> Option<&str> {
127        self.name.as_deref()
128    }
129}
130
131impl<T: ColumnType> ColumnImpl<T> {
132    pub(crate) fn new(
133        realm: Arc<Realm>,
134        data_ref: RealmRef,
135        index_ref: Option<RealmRef>,
136        attributes: ColumnAttributes,
137        name: Option<String>,
138        context: T::LeafContext,
139    ) -> crate::RealmResult<Self> {
140        let tree = BpTree::from_ref_with_context(Arc::clone(&realm), data_ref, context)?;
141        let index = index_ref
142            .map(|ref_| Index::from_ref(realm, ref_))
143            .transpose()?;
144
145        Ok(Self {
146            tree,
147            index,
148            attributes,
149            name,
150        })
151    }
152}