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}