polite/
lib.rs

1//! # Polite: SQLite × Polars Integration
2//!
3//! A Rust library that provides seamless integration between SQLite databases
4//! and Polars DataFrames using ConnectorX for efficient data transfer.
5//!
6//! ## Features
7//!
8//! - **Fast data loading**: Use ConnectorX to efficiently load SQLite query results into Polars DataFrames
9//! - **Easy data writing**: Save Polars DataFrames directly to SQLite tables
10//! - **Type preservation**: Automatic mapping between Polars and SQLite data types
11//! - **Simple API**: Minimal boilerplate for common database operations
12//!
13//! ## Quick Start
14//!
15//! ```rust
16//! use polite::{connect_sqlite, to_dataframe, from_dataframe};
17//! use polars::prelude::*;
18//!
19//! // Open a SQLite connection
20//! let conn = connect_sqlite(Some("data.db")).unwrap();
21//!
22//! // Load data from SQLite into a DataFrame
23//! let df = to_dataframe("data.db", "SELECT * FROM users").unwrap();
24//!
25//! // Save a DataFrame to SQLite
26//! from_dataframe(&conn, "new_table", &df).unwrap();
27//! ```
28//!
29//! ## Modules
30//!
31//! - [`dataframe`] - Functions for converting between DataFrames and SQLite
32//! - [`db`] - Database connection utilities
33//! - [`error`] - Custom error types
34
35mod connectorx;
36pub mod dataframe;
37pub mod db;
38pub mod error;
39pub(crate) mod types;
40
41// Re-export the main entrypoints at crate root
42pub use dataframe::{from_dataframe, to_dataframe};
43pub use db::{connect_sqlite, execute_query};
44pub use error::PoliteError;
45
46/// Common imports for polite users.
47///
48/// This prelude module re-exports the most commonly used items from polite,
49/// allowing users to quickly import everything they need with a single glob import.
50///
51/// # Examples
52///
53/// ```rust
54/// use polite::prelude::*;
55///
56/// // Now you have access to all the main functions:
57/// let conn = connect_sqlite(Some("data.db")).unwrap();
58/// let df = to_dataframe("data.db", "SELECT * FROM users").unwrap();
59/// from_dataframe(&conn, "backup_users", &df).unwrap();
60/// ```
61pub mod prelude {
62    pub use crate::{connect_sqlite, execute_query, from_dataframe, to_dataframe, PoliteError};
63
64    // Convenience functions from lib module:
65    pub use crate::{load_dataframe, save_dataframe};
66}
67
68/// Create a DataFrame from a SQLite file with error handling and logging.
69///
70/// This convenience function provides better error messages and optional logging
71/// compared to the raw `to_dataframe` function.
72///
73/// # Arguments
74///
75/// * `db_path` - Path to the SQLite database file
76/// * `sql` - SQL query to execute
77///
78/// # Examples
79///
80/// ```rust
81/// use polite::load_dataframe;
82///
83/// let df = load_dataframe("data.db", "SELECT id, name FROM users LIMIT 10")
84///     .expect("Failed to load data");
85///
86/// println!("Loaded {} rows", df.height());
87/// ```
88pub fn load_dataframe(db_path: &str, sql: &str) -> Result<polars::prelude::DataFrame, PoliteError> {
89    to_dataframe(db_path, sql).map_err(|e| PoliteError::Load {
90        db_path: db_path.to_string(),
91        source: Box::new(e),
92    })
93}
94
95/// Save a DataFrame to SQLite with automatic table creation and better error handling.
96///
97/// This convenience function handles connection creation and provides clearer error messages.
98///
99/// # Arguments
100///
101/// * `db_path` - Path to the SQLite database file (will be created if it doesn't exist)
102/// * `table_name` - Name of the table to create/insert into
103/// * `df` - The DataFrame to save
104///
105/// # Examples
106///
107/// ```rust
108/// use polite::save_dataframe;
109/// use polars::prelude::*;
110///
111/// let df = df! {
112///     "id" => [1, 2, 3],
113///     "name" => ["Alice", "Bob", "Charlie"],
114/// }.unwrap();
115///
116/// save_dataframe("output.db", "users", &df)
117///     .expect("Failed to save DataFrame");
118/// ```
119pub fn save_dataframe(
120    db_path: &str,
121    table_name: &str,
122    df: &polars::prelude::DataFrame,
123) -> Result<(), PoliteError> {
124    let conn = connect_sqlite(Some(db_path))?;
125
126    from_dataframe(&conn, table_name, df).map_err(|e| PoliteError::Save {
127        db_path: db_path.to_string(),
128        table_name: table_name.to_string(),
129        source: Box::new(e),
130    })?;
131
132    Ok(())
133}