Skip to main content

toasty_core/schema/db/
table.rs

1use super::{Column, ColumnId, Index, IndexId, PrimaryKey};
2use crate::stmt;
3
4use std::fmt;
5
6/// A database table with its columns, primary key, and indices.
7///
8/// # Examples
9///
10/// ```ignore
11/// use toasty_core::schema::db::{Table, TableId};
12///
13/// let table = Table::new(TableId(0), "users".to_string());
14/// assert_eq!(table.name, "users");
15/// assert!(table.columns.is_empty());
16/// ```
17#[derive(Debug, Clone)]
18#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
19pub struct Table {
20    /// Uniquely identifies a table within the schema.
21    pub id: TableId,
22
23    /// Name of the table as it appears in the database.
24    pub name: String,
25
26    /// The table's columns, in order.
27    pub columns: Vec<Column>,
28
29    /// The table's primary key definition.
30    pub primary_key: PrimaryKey,
31
32    /// Secondary indices on this table.
33    pub indices: Vec<Index>,
34}
35
36/// Uniquely identifies a table within a [`Schema`](super::Schema).
37///
38/// The inner `usize` is a zero-based index into [`Schema::tables`](super::Schema::tables).
39///
40/// # Examples
41///
42/// ```ignore
43/// use toasty_core::schema::db::TableId;
44///
45/// let id = TableId(0);
46/// assert_eq!(id.0, 0);
47/// ```
48#[derive(PartialEq, Eq, Clone, Copy, Hash)]
49#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
50pub struct TableId(pub usize);
51
52impl Table {
53    /// Returns the `i`-th column of this table's primary key.
54    ///
55    /// # Panics
56    ///
57    /// Panics if `i` is out of bounds for the primary key column list.
58    pub fn primary_key_column(&self, i: usize) -> &Column {
59        &self.columns[self.primary_key.columns[i].index]
60    }
61
62    /// Returns an iterator over the columns that make up this table's primary key.
63    pub fn primary_key_columns(&self) -> impl ExactSizeIterator<Item = &Column> + '_ {
64        self.primary_key
65            .columns
66            .iter()
67            .map(|column_id| &self.columns[column_id.index])
68    }
69
70    /// Returns the column identified by `id`.
71    ///
72    /// Only the column's `index` field is used; the `table` component is ignored.
73    ///
74    /// # Panics
75    ///
76    /// Panics if the column index is out of bounds.
77    pub fn column(&self, id: impl Into<ColumnId>) -> &Column {
78        &self.columns[id.into().index]
79    }
80
81    /// Resolves a single-step [`Projection`](stmt::Projection) to a column.
82    ///
83    /// # Panics
84    ///
85    /// Panics if the projection is empty or contains more than one step.
86    pub fn resolve(&self, projection: &stmt::Projection) -> &Column {
87        let [first, rest @ ..] = projection.as_slice() else {
88            panic!("need at most one path step")
89        };
90        assert!(rest.is_empty());
91
92        &self.columns[*first]
93    }
94
95    pub(crate) fn new(id: TableId, name: String) -> Self {
96        Self {
97            id,
98            name,
99            columns: vec![],
100            primary_key: PrimaryKey {
101                columns: vec![],
102                index: IndexId {
103                    table: id,
104                    index: 0,
105                },
106            },
107            indices: vec![],
108        }
109    }
110}
111
112impl TableId {
113    pub(crate) fn placeholder() -> Self {
114        Self(usize::MAX)
115    }
116}
117
118impl fmt::Debug for TableId {
119    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
120        write!(fmt, "TableId({})", self.0)
121    }
122}