vibesql/connection.rs
1//! Database connection implementation
2//!
3//! This module provides the Database class for establishing connections
4//! to the in-memory vibesql database following DB-API 2.0 conventions.
5
6use std::sync::Arc;
7
8use parking_lot::Mutex;
9use pyo3::prelude::*;
10
11use crate::cursor::Cursor;
12
13/// Database connection object
14///
15/// Represents a connection to an in-memory vibesql database.
16/// Follows DB-API 2.0 conventions for database connections.
17///
18/// # Example
19/// ```python
20/// db = vibesql.connect()
21/// cursor = db.cursor()
22/// cursor.execute("SELECT 1")
23/// ```
24#[pyclass]
25pub struct Database {
26 pub(crate) db: Arc<Mutex<vibesql_storage::Database>>,
27}
28
29#[pymethods]
30impl Database {
31 /// Create a new database connection
32 ///
33 /// # Returns
34 /// A new Database instance with an empty in-memory database.
35 #[new]
36 pub fn new() -> Self {
37 Database { db: Arc::new(Mutex::new(vibesql_storage::Database::new())) }
38 }
39
40 /// Create a cursor for executing queries
41 ///
42 /// # Returns
43 /// A new Cursor object for executing SQL statements and fetching results.
44 fn cursor(&self) -> PyResult<Cursor> {
45 Cursor::new(Arc::clone(&self.db))
46 }
47
48 /// Close the database connection
49 ///
50 /// For in-memory databases, this is a no-op but provided for DB-API 2.0 compatibility.
51 fn close(&self) -> PyResult<()> {
52 // In-memory database, no cleanup needed
53 Ok(())
54 }
55
56 /// Commit the current transaction
57 ///
58 /// For in-memory databases without transaction support, this is a no-op
59 /// but provided for DB-API 2.0 compatibility.
60 fn commit(&self) -> PyResult<()> {
61 // In-memory database, no transaction needed
62 Ok(())
63 }
64
65 /// Get version string
66 ///
67 /// # Returns
68 /// A string containing the version identifier.
69 fn version(&self) -> String {
70 "vibesql-py 0.1.0".to_string()
71 }
72
73 /// Save database to SQL dump file
74 ///
75 /// Generates a SQL dump file containing all schemas, tables, indexes,
76 /// roles, and data needed to recreate the current database state.
77 ///
78 /// # Arguments
79 /// * `path` - Path where the SQL dump file will be created
80 ///
81 /// # Example
82 /// ```python
83 /// db = vibesql.connect()
84 /// cursor = db.cursor()
85 /// cursor.execute("CREATE TABLE users (id INTEGER, name TEXT)")
86 /// cursor.execute("INSERT INTO users VALUES (1, 'Alice')")
87 /// db.save("mydata.vbsql")
88 /// ```
89 fn save(&self, path: &str) -> PyResult<()> {
90 // Use binary format to preserve sequences and column defaults (for AUTOINCREMENT)
91 self.db.lock().save(path).map_err(|e| {
92 pyo3::exceptions::PyIOError::new_err(format!("Failed to save database: {}", e))
93 })
94 }
95
96 /// Load database from binary file
97 ///
98 /// Creates a new Database instance by loading binary database file.
99 /// This preserves sequences and column defaults for AUTOINCREMENT support.
100 /// This is a static method that returns a new Database.
101 ///
102 /// # Arguments
103 /// * `path` - Path to the binary database file (.vbsql)
104 ///
105 /// # Returns
106 /// A new Database instance with the loaded state
107 ///
108 /// # Example
109 /// ```python
110 /// # Save a database
111 /// db1 = vibesql.connect()
112 /// cursor = db1.cursor()
113 /// cursor.execute("CREATE TABLE users (id INTEGER, name TEXT)")
114 /// db1.save("mydata.vbsql")
115 ///
116 /// # Load it later
117 /// db2 = vibesql.Database.load("mydata.vbsql")
118 /// cursor2 = db2.cursor()
119 /// cursor2.execute("SELECT * FROM users")
120 /// ```
121 #[staticmethod]
122 fn load(path: &str) -> PyResult<Database> {
123 // Use default format (compressed or uncompressed binary) to preserve
124 // sequences and column defaults (for AUTOINCREMENT)
125 let db = vibesql_storage::Database::load(path).map_err(|e| {
126 pyo3::exceptions::PyIOError::new_err(format!("Failed to load database: {}", e))
127 })?;
128 Ok(Database { db: Arc::new(Mutex::new(db)) })
129 }
130}