Skip to main content

nautilus_connector/
lib.rs

1#![forbid(unsafe_code)]
2//! Database executors and connection management for Nautilus ORM.
3//!
4//! This crate provides the execution layer for Nautilus, enabling SQL queries
5//! to be run against real databases. It defines the `Executor` trait and provides
6//! concrete implementations for supported databases.
7//!
8//! ## Architecture
9//!
10//! - `Executor` trait: Abstract interface for query execution
11//! - `Row`: Database result representation with hybrid access (positional + named)
12//! - `PgExecutor`: PostgreSQL implementation using sqlx
13//! - `MysqlExecutor`: MySQL implementation using sqlx
14//! - `SqliteExecutor`: SQLite implementation using sqlx
15//!
16//! ## Example
17//!
18//! ```rust,ignore
19//! use nautilus_connector::{execute_all, Executor, PgExecutor, ConnectorResult};
20//! use nautilus_dialect::{Dialect, PostgresDialect};
21//! use nautilus_core::select::SelectBuilder;
22//!
23//! #[tokio::main]
24//! async fn main() -> ConnectorResult<()> {
25//!     // Create executor
26//!     let executor = PgExecutor::new("postgres://localhost/mydb").await?;
27//!     let dialect = PostgresDialect;
28//!     
29//!     // Build query
30//!     let select = SelectBuilder::new("users")
31//!         .columns(vec!["id", "name"])
32//!         .build()?;
33//!     
34//!     // Render and execute
35//!     let sql = dialect.render_select(&select)?;
36//!     let rows = execute_all(&executor, &sql).await?;
37//!     
38//!     // Access results
39//!     for row in rows {
40//!         let id = row.get("id");
41//!         let name = row.get("name");
42//!         println!("User: {:?}, {:?}", id, name);
43//!     }
44//!     
45//!     Ok(())
46//! }
47//! ```
48
49#![warn(missing_docs)]
50
51/// Generate `execute_affected` for a pool-backed executor.
52///
53/// Each backend module defines its own `bind_value` function and exposes a
54/// `self.pool` field.  The method body is identical across all three backends
55/// (Postgres, MySQL, SQLite), so this macro produces it from a single source.
56macro_rules! impl_execute_affected {
57    () => {
58        /// Execute a mutation SQL and return the number of affected rows.
59        ///
60        /// Used when `return_data = false` — no `RETURNING` clause is emitted
61        /// so the affected-row count must come from the database result.
62        pub async fn execute_affected(
63            &self,
64            sql: &nautilus_dialect::Sql,
65        ) -> $crate::error::Result<usize> {
66            let mut query = sqlx::query(&sql.text);
67            for param in &sql.params {
68                query = bind_value(query, param)?;
69            }
70            let result = query
71                .execute(&self.pool)
72                .await
73                .map_err(|e| $crate::error::ConnectorError::database(e, "Mutation failed"))?;
74            Ok(result.rows_affected() as usize)
75        }
76    };
77}
78
79mod client;
80pub mod error;
81mod executor;
82mod from_row;
83mod mysql;
84mod mysql_stream;
85mod pool_options;
86mod postgres;
87mod postgres_stream;
88mod row;
89mod row_stream;
90mod single_row;
91mod sqlite;
92mod sqlite_stream;
93mod streaming;
94pub mod transaction;
95mod utils;
96mod value_hint;
97
98pub use client::Client;
99pub use error::{ConnectorError, Result as ConnectorResult, SqlxErrorKind};
100pub use executor::{execute_all, execute_one, execute_optional, Executor};
101pub use from_row::FromRow;
102pub use mysql::MysqlExecutor;
103pub use mysql_stream::MysqlRowStream;
104pub use pool_options::ConnectorPoolOptions;
105pub use postgres::PgExecutor;
106pub use postgres_stream::PgRowStream;
107pub use row::Row;
108pub use row_stream::RowStream;
109pub use sqlite::SqliteExecutor;
110pub use sqlite_stream::SqliteRowStream;
111pub use transaction::{IsolationLevel, TransactionExecutor, TransactionOptions};
112pub use value_hint::{
113    decode_row_with_hints, normalize_row_with_hints, normalize_rows_with_hints,
114    normalize_value_with_hint, ValueHint,
115};
116
117pub use nautilus_core::RowAccess;
118
119pub use nautilus_core::Column;
120pub use nautilus_core::FromValue;
121
122/// Internal decode entry points re-exported for the criterion benches only.
123/// Not part of the public connector API.
124#[doc(hidden)]
125pub mod bench {
126    /// Batch-decode sqlite rows through the same path the executors use.
127    pub fn decode_sqlite_rows(
128        rows: &[sqlx::sqlite::SqliteRow],
129    ) -> crate::error::Result<Vec<crate::Row>> {
130        crate::sqlite_stream::decode_rows(rows)
131    }
132}