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}