palimpsest_sql/
catalog.rs1use std::collections::BTreeMap;
8
9use crate::SqlError;
10
11#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
13pub enum ColumnType {
14 Bool,
16 Int,
18 Float,
20 Text,
22 Timestamp,
24 Unknown,
26}
27
28impl ColumnType {
29 #[must_use]
31 pub const fn is_numeric(self) -> bool {
32 matches!(self, Self::Int | Self::Float)
33 }
34
35 #[must_use]
39 pub fn is_compatible_with(self, other: Self) -> bool {
40 matches!((self, other), (Self::Unknown, _) | (_, Self::Unknown))
41 || self == other
42 || (self.is_numeric() && other.is_numeric())
43 }
44}
45
46#[derive(Debug, Clone, PartialEq, Eq)]
48pub struct ColumnSchema {
49 pub name: String,
51 pub ty: ColumnType,
53}
54
55impl ColumnSchema {
56 #[must_use]
58 pub fn new(name: impl Into<String>, ty: ColumnType) -> Self {
59 Self {
60 name: name.into(),
61 ty,
62 }
63 }
64}
65
66#[derive(Debug, Clone, PartialEq, Eq)]
68pub struct TableSchema {
69 pub name: String,
71 pub columns: Vec<ColumnSchema>,
73}
74
75impl TableSchema {
76 #[must_use]
78 pub fn new(name: impl Into<String>, columns: Vec<ColumnSchema>) -> Self {
79 Self {
80 name: name.into(),
81 columns,
82 }
83 }
84
85 #[must_use]
87 pub fn column(&self, name: &str) -> Option<&ColumnSchema> {
88 self.columns.iter().find(|column| column.name == name)
89 }
90}
91
92#[derive(Debug, Clone, Default, PartialEq, Eq)]
94pub struct Catalog {
95 tables: BTreeMap<String, TableSchema>,
96}
97
98impl Catalog {
99 #[must_use]
101 pub fn new(tables: impl IntoIterator<Item = TableSchema>) -> Self {
102 Self {
103 tables: tables
104 .into_iter()
105 .map(|table| (table.name.clone(), table))
106 .collect(),
107 }
108 }
109
110 #[must_use]
112 pub fn table(&self, name: &str) -> Option<&TableSchema> {
113 self.tables.get(name)
114 }
115
116 pub fn require_table(&self, name: &str) -> Result<&TableSchema, SqlError> {
122 self.table(name)
123 .ok_or_else(|| SqlError::UnknownTable(name.to_owned()))
124 }
125
126 pub fn tables(&self) -> impl Iterator<Item = &TableSchema> {
128 self.tables.values()
129 }
130
131 #[must_use]
133 pub fn demo() -> Self {
134 let post_columns = vec![
135 ColumnSchema::new("id", ColumnType::Int),
136 ColumnSchema::new("author_id", ColumnType::Int),
137 ColumnSchema::new("created_at", ColumnType::Timestamp),
138 ColumnSchema::new("title", ColumnType::Text),
139 ColumnSchema::new("published", ColumnType::Bool),
140 ];
141
142 Self::new([
143 TableSchema::new("posts", post_columns.clone()),
144 TableSchema::new("archived_posts", post_columns),
145 TableSchema::new(
146 "authors",
147 vec![
148 ColumnSchema::new("id", ColumnType::Int),
149 ColumnSchema::new("name", ColumnType::Text),
150 ],
151 ),
152 TableSchema::new(
153 "comments",
154 vec![
155 ColumnSchema::new("id", ColumnType::Int),
156 ColumnSchema::new("post_id", ColumnType::Int),
157 ColumnSchema::new("author_id", ColumnType::Int),
158 ColumnSchema::new("body", ColumnType::Text),
159 ],
160 ),
161 ])
162 }
163}