vibesql/
lib.rs

1//! Python bindings for vibesql using PyO3
2//!
3//! This module provides Python bindings following DB-API 2.0 conventions
4//! to expose the Rust database library to Python for benchmarking and usage.
5//!
6//! # Module Organization
7//!
8//! The library is organized into focused modules:
9//!
10//! - **conversions**: Type conversions between Python and Rust SqlValue types
11//! - **connection**: Database connection management
12//! - **cursor**: Query cursor implementation and result fetching
13//! - **profiling**: Performance profiling utilities
14//!
15//! # Quick Start
16//!
17//! ```python
18//! import vibesql
19//!
20//! # Create a connection
21//! db = vibesql.connect()
22//!
23//! # Get a cursor
24//! cursor = db.cursor()
25//!
26//! # Execute a query
27//! cursor.execute("SELECT 1")
28//!
29//! # Fetch results
30//! result = cursor.fetchall()
31//! ```
32
33// Suppress PyO3 macro warnings
34#![allow(non_local_definitions)]
35
36mod connection;
37mod conversions;
38mod cursor;
39mod profiling;
40
41// Re-export public types for use in submodules
42pub use connection::Database;
43pub use cursor::Cursor;
44use pyo3::{exceptions::PyException, prelude::*};
45
46// Exception hierarchy following PEP 249
47pyo3::create_exception!(vibesql, Warning, PyException);
48pyo3::create_exception!(vibesql, Error, PyException);
49pyo3::create_exception!(vibesql, InterfaceError, Error);
50pyo3::create_exception!(vibesql, DatabaseError, Error);
51pyo3::create_exception!(vibesql, DataError, DatabaseError);
52pyo3::create_exception!(vibesql, OperationalError, DatabaseError);
53pyo3::create_exception!(vibesql, IntegrityError, DatabaseError);
54pyo3::create_exception!(vibesql, InternalError, DatabaseError);
55pyo3::create_exception!(vibesql, ProgrammingError, DatabaseError);
56pyo3::create_exception!(vibesql, NotSupportedError, DatabaseError);
57
58/// Factory function to create a database connection
59///
60/// Creates a new in-memory vibesql database and returns a connection object.
61/// Use this to obtain a Database instance for executing SQL statements.
62///
63/// # Returns
64/// A new Database connection
65///
66/// # Example
67/// ```python
68/// import vibesql
69/// db = vibesql.connect()
70/// cursor = db.cursor()
71/// ```
72#[pyfunction]
73fn connect() -> PyResult<Database> {
74    Ok(Database::new())
75}
76
77/// Enable performance profiling (prints detailed timing to stderr)
78///
79/// When enabled, profiling information is printed to stderr for each
80/// executed query, showing timing information for various stages of
81/// query execution.
82#[pyfunction]
83fn enable_profiling() {
84    profiling::enable_profiling();
85}
86
87/// Disable performance profiling
88///
89/// Stops printing profiling information to stderr.
90#[pyfunction]
91fn disable_profiling() {
92    profiling::disable_profiling();
93}
94
95/// Python module initialization
96///
97/// Registers all public types and functions with the Python module.
98#[pymodule]
99fn vibesql(m: &Bound<'_, PyModule>) -> PyResult<()> {
100    // DB-API 2.0 module-level attributes
101    m.add("apilevel", "2.0")?;
102    m.add("threadsafety", 1)?;
103    m.add("paramstyle", "qmark")?;
104
105    m.add_function(wrap_pyfunction!(connect, m)?)?;
106    m.add_function(wrap_pyfunction!(enable_profiling, m)?)?;
107    m.add_function(wrap_pyfunction!(disable_profiling, m)?)?;
108    m.add_class::<Database>()?;
109    m.add_class::<Cursor>()?;
110
111    // DB-API 2.0 exception hierarchy
112    m.add("Warning", m.py().get_type::<Warning>())?;
113    m.add("Error", m.py().get_type::<Error>())?;
114    m.add("InterfaceError", m.py().get_type::<InterfaceError>())?;
115    m.add("DatabaseError", m.py().get_type::<DatabaseError>())?;
116    m.add("DataError", m.py().get_type::<DataError>())?;
117    m.add("OperationalError", m.py().get_type::<OperationalError>())?;
118    m.add("IntegrityError", m.py().get_type::<IntegrityError>())?;
119    m.add("InternalError", m.py().get_type::<InternalError>())?;
120    m.add("ProgrammingError", m.py().get_type::<ProgrammingError>())?;
121    m.add("NotSupportedError", m.py().get_type::<NotSupportedError>())?;
122
123    Ok(())
124}