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 an iterator over the columns that make up this table's primary key.
54    pub fn primary_key_columns(&self) -> impl ExactSizeIterator<Item = &Column> + '_ {
55        self.primary_key
56            .columns
57            .iter()
58            .map(|column_id| &self.columns[column_id.index])
59    }
60
61    /// Returns the column identified by `id`.
62    ///
63    /// Only the column's `index` field is used; the `table` component is ignored.
64    ///
65    /// # Panics
66    ///
67    /// Panics if the column index is out of bounds.
68    pub fn column(&self, id: impl Into<ColumnId>) -> &Column {
69        &self.columns[id.into().index]
70    }
71
72    /// Resolves a single-step [`Projection`](stmt::Projection) to a column.
73    ///
74    /// # Panics
75    ///
76    /// Panics if the projection is empty or contains more than one step.
77    pub fn resolve(&self, projection: &stmt::Projection) -> &Column {
78        let [first, rest @ ..] = projection.as_slice() else {
79            panic!("need at most one path step")
80        };
81        assert!(rest.is_empty());
82
83        &self.columns[*first]
84    }
85
86    pub(crate) fn new(id: TableId, name: String) -> Self {
87        Self {
88            id,
89            name,
90            columns: vec![],
91            primary_key: PrimaryKey {
92                columns: vec![],
93                index: IndexId {
94                    table: id,
95                    index: 0,
96                },
97            },
98            indices: vec![],
99        }
100    }
101}
102
103impl TableId {
104    pub(crate) fn placeholder() -> Self {
105        Self(usize::MAX)
106    }
107}
108
109impl fmt::Debug for TableId {
110    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
111        write!(fmt, "TableId({})", self.0)
112    }
113}