quill_sql/catalog/
schema.rs1use super::column::{Column, ColumnRef};
2use crate::catalog::DataType;
3use crate::error::QuillSQLError;
4use crate::error::QuillSQLResult;
5use crate::utils::table_ref::TableReference;
6use std::sync::{Arc, LazyLock};
7
8pub type SchemaRef = Arc<Schema>;
9
10pub static EMPTY_SCHEMA_REF: LazyLock<SchemaRef> = LazyLock::new(|| Arc::new(Schema::empty()));
11pub static INSERT_OUTPUT_SCHEMA_REF: LazyLock<SchemaRef> = LazyLock::new(|| {
12 Arc::new(Schema::new(vec![Column::new(
13 "insert_rows",
14 DataType::Int32,
15 false,
16 )]))
17});
18pub static UPDATE_OUTPUT_SCHEMA_REF: LazyLock<SchemaRef> = LazyLock::new(|| {
19 Arc::new(Schema::new(vec![Column::new(
20 "update_rows",
21 DataType::Int32,
22 false,
23 )]))
24});
25pub static DELETE_OUTPUT_SCHEMA_REF: LazyLock<SchemaRef> = LazyLock::new(|| {
26 Arc::new(Schema::new(vec![Column::new(
27 "delete_rows",
28 DataType::Int32,
29 false,
30 )]))
31});
32
33#[derive(Debug, Clone, Eq, PartialEq)]
34pub struct Schema {
35 pub columns: Vec<ColumnRef>,
36}
37
38impl Schema {
39 pub fn new(columns: Vec<Column>) -> Self {
40 Self::new_with_check(columns.into_iter().map(Arc::new).collect())
41 }
42
43 fn new_with_check(columns: Vec<ColumnRef>) -> Self {
44 for (idx1, col1) in columns.iter().enumerate() {
45 for col2 in columns.iter().skip(idx1 + 1) {
46 match (&col1.relation, &col2.relation) {
47 (Some(rel1), Some(rel2)) => {
48 assert!(!(rel1.resolved_eq(rel2) && col1.name == col2.name));
49 }
50 (None, None) => {
51 if col1.name == col2.name {
52 assert_eq!(col1.relation, col2.relation);
53 }
54 }
55 (Some(_), None) | (None, Some(_)) => {}
56 }
57 }
58 }
59 Self { columns }
60 }
61
62 pub fn empty() -> Self {
63 Self { columns: vec![] }
64 }
65
66 pub fn try_merge(schemas: impl IntoIterator<Item = Self>) -> QuillSQLResult<Self> {
67 let mut columns = Vec::new();
68 for schema in schemas {
69 columns.extend(schema.columns);
70 }
71 Ok(Self::new_with_check(columns))
72 }
73
74 pub fn project(&self, indices: &[usize]) -> QuillSQLResult<Schema> {
75 let new_columns = indices
76 .iter()
77 .map(|i| self.column_with_index(*i))
78 .collect::<QuillSQLResult<Vec<ColumnRef>>>()?;
79 Ok(Schema::new_with_check(new_columns))
80 }
81
82 pub fn column_with_name(
83 &self,
84 relation: Option<&TableReference>,
85 name: &str,
86 ) -> QuillSQLResult<ColumnRef> {
87 let index = self.index_of(relation, name)?;
88 Ok(self.columns[index].clone())
89 }
90
91 pub fn column_with_index(&self, index: usize) -> QuillSQLResult<ColumnRef> {
92 self.columns
93 .get(index)
94 .cloned()
95 .ok_or_else(|| QuillSQLError::Plan(format!("Unable to get column with index {index}")))
96 }
97
98 pub fn index_of(&self, relation: Option<&TableReference>, name: &str) -> QuillSQLResult<usize> {
100 let (idx, _) = self
101 .columns
102 .iter()
103 .enumerate()
104 .find(|(_, col)| {
105 let name_matches = col.name.eq_ignore_ascii_case(name);
106 match (relation, &col.relation) {
107 (Some(rel), Some(col_rel)) => name_matches && rel.resolved_eq(col_rel),
108 (Some(_), None) => false,
109 (None, Some(_)) | (None, None) => name_matches,
110 }
111 })
112 .ok_or_else(|| QuillSQLError::Plan(format!("Unable to get column named \"{name}\"")))?;
113 Ok(idx)
114 }
115
116 pub fn column_count(&self) -> usize {
117 self.columns.len()
118 }
119}