alopex_sql/catalog/mod.rs
1//! Catalog module for the Alopex SQL dialect.
2//!
3//! This module provides metadata management for tables and indexes.
4//!
5//! # Components
6//!
7//! - [`TableMetadata`]: Table schema information
8//! - [`ColumnMetadata`]: Column schema information
9//! - [`IndexMetadata`]: Index schema information
10//! - [`Catalog`]: Trait for catalog implementations
11//! - [`MemoryCatalog`]: In-memory catalog implementation
12//!
13//! # Example
14//!
15//! ```
16//! use alopex_sql::catalog::{Catalog, MemoryCatalog, TableMetadata, ColumnMetadata, IndexMetadata};
17//! use alopex_sql::planner::types::ResolvedType;
18//! use alopex_sql::ast::ddl::IndexMethod;
19//!
20//! // Create an in-memory catalog
21//! let mut catalog = MemoryCatalog::new();
22//!
23//! // Create a table
24//! let columns = vec![
25//! ColumnMetadata::new("id", ResolvedType::Integer).with_primary_key(true),
26//! ColumnMetadata::new("name", ResolvedType::Text).with_not_null(true),
27//! ];
28//! let table = TableMetadata::new("users", columns);
29//! catalog.create_table(table).unwrap();
30//!
31//! // Check table existence
32//! assert!(catalog.table_exists("users"));
33//! assert!(catalog.get_table("users").is_some());
34//!
35//! // Create an index (index_id is assigned by catalog in production)
36//! let index = IndexMetadata::new(1, "idx_users_name", "users", vec!["name".into()])
37//! .with_method(IndexMethod::BTree);
38//! catalog.create_index(index).unwrap();
39//!
40//! // Query indexes
41//! assert!(catalog.index_exists("idx_users_name"));
42//! assert_eq!(catalog.get_indexes_for_table("users").len(), 1);
43//! ```
44
45mod index;
46mod memory;
47pub mod persistent;
48mod table;
49
50#[cfg(test)]
51mod tests;
52
53pub use index::IndexMetadata;
54pub use memory::MemoryCatalog;
55pub use persistent::TxnCatalogView;
56pub use persistent::{CatalogError, CatalogOverlay, PersistentCatalog};
57pub use table::{
58 ColumnMetadata, Compression, RowIdMode, StorageOptions, StorageType, TableMetadata,
59};
60
61use crate::planner::PlannerError;
62
63/// Trait for catalog implementations.
64///
65/// A catalog manages metadata for tables and indexes. This trait abstracts
66/// the storage mechanism, allowing both in-memory and persistent implementations.
67///
68/// # Design Notes
69///
70/// - Read methods take `&self` and return references or copies
71/// - Write methods take `&mut self` and return `Result<(), PlannerError>`
72/// - The `Planner` only uses read methods; `Executor` performs writes
73/// - ID generation is done via `next_table_id()` / `next_index_id()` at execute time
74///
75/// # Error Handling
76///
77/// - `create_table`: Returns `TableAlreadyExists` if table exists
78/// - `drop_table`: Returns `TableNotFound` if table doesn't exist
79/// - `create_index`: Returns `IndexAlreadyExists` if index exists
80/// - `drop_index`: Returns `IndexNotFound` if index doesn't exist
81pub trait Catalog {
82 /// Create a new table in the catalog.
83 ///
84 /// # Errors
85 ///
86 /// Returns `PlannerError::TableAlreadyExists` if a table with the same name exists.
87 fn create_table(&mut self, table: TableMetadata) -> Result<(), PlannerError>;
88
89 /// Get a table by name.
90 ///
91 /// Returns `None` if the table doesn't exist.
92 fn get_table(&self, name: &str) -> Option<&TableMetadata>;
93
94 /// Drop a table from the catalog.
95 ///
96 /// # Errors
97 ///
98 /// Returns `PlannerError::TableNotFound` if the table doesn't exist.
99 fn drop_table(&mut self, name: &str) -> Result<(), PlannerError>;
100
101 /// Create a new index in the catalog.
102 ///
103 /// # Errors
104 ///
105 /// Returns `PlannerError::IndexAlreadyExists` if an index with the same name exists.
106 fn create_index(&mut self, index: IndexMetadata) -> Result<(), PlannerError>;
107
108 /// Get an index by name.
109 ///
110 /// Returns `None` if the index doesn't exist.
111 fn get_index(&self, name: &str) -> Option<&IndexMetadata>;
112
113 /// Get all indexes for a table.
114 ///
115 /// Returns an empty vector if the table has no indexes.
116 fn get_indexes_for_table(&self, table: &str) -> Vec<&IndexMetadata>;
117
118 /// Drop an index from the catalog.
119 ///
120 /// # Errors
121 ///
122 /// Returns `PlannerError::IndexNotFound` if the index doesn't exist.
123 fn drop_index(&mut self, name: &str) -> Result<(), PlannerError>;
124
125 /// Check if a table exists.
126 fn table_exists(&self, name: &str) -> bool;
127
128 /// Check if an index exists.
129 fn index_exists(&self, name: &str) -> bool;
130
131 /// Generate the next unique table ID.
132 ///
133 /// Called by the Executor when creating a new table.
134 /// IDs start from 1 and increment monotonically.
135 fn next_table_id(&mut self) -> u32;
136
137 /// Generate the next unique index ID.
138 ///
139 /// Called by the Executor when creating a new index.
140 /// IDs start from 1 and increment monotonically.
141 fn next_index_id(&mut self) -> u32;
142}