Skip to main content

bsql_core/
lib.rs

1#![forbid(unsafe_code)]
2
3//! Runtime support for bsql.
4//!
5//! This crate provides the types that `bsql::query!` generated code depends on:
6//! error types, connection pool, and the executor trait.
7//!
8//! You should not depend on this crate directly — use [`bsql`] instead.
9
10pub mod error;
11pub mod executor;
12pub mod listener;
13pub mod pool;
14pub mod singleflight;
15#[cfg(feature = "sqlite")]
16pub mod sqlite_pool;
17pub mod stream;
18pub mod transaction;
19pub mod types;
20pub mod util;
21
22/// Re-export bsql_driver_postgres types used by generated code.
23/// Users do not need to depend on bsql-driver directly.
24pub mod driver {
25    pub use bsql_driver_postgres::arena::{acquire_arena, release_arena};
26    pub use bsql_driver_postgres::hash_sql;
27    pub use bsql_driver_postgres::{Arena, Encode, PgDataRow, QueryResult, Row};
28
29    // Scalar decode functions for generated inline raw-bytes code
30    pub use bsql_driver_postgres::codec::decode_str;
31
32    // Array decode functions for generated code
33    pub use bsql_driver_postgres::codec::{
34        decode_array_bool, decode_array_bytea, decode_array_f32, decode_array_f64,
35        decode_array_i16, decode_array_i32, decode_array_i64, decode_array_str,
36    };
37
38    // Feature-gated decode functions for generated code
39    #[cfg(feature = "decimal")]
40    pub use bsql_driver_postgres::codec::decode_numeric_decimal;
41    #[cfg(feature = "uuid")]
42    pub use bsql_driver_postgres::codec::decode_uuid_type;
43    #[cfg(feature = "chrono")]
44    pub use bsql_driver_postgres::codec::{
45        decode_date_chrono, decode_time_chrono, decode_timestamptz_chrono,
46    };
47    #[cfg(feature = "time")]
48    pub use bsql_driver_postgres::codec::{
49        decode_date_time, decode_time_time, decode_timestamptz_time,
50    };
51}
52
53/// Re-export bsql_driver_sqlite types used by generated SQLite code.
54#[cfg(feature = "sqlite")]
55pub mod driver_sqlite {
56    pub use bsql_driver_sqlite::codec::SqliteEncode;
57    pub use bsql_driver_sqlite::conn::SqliteConnection;
58    pub use bsql_driver_sqlite::ffi::{StepResult, StmtHandle};
59    pub use bsql_driver_sqlite::pool::ParamValue;
60    pub use bsql_driver_sqlite::SqliteError;
61    pub use smallvec::{smallvec, SmallVec};
62
63    // Arena types for arena-backed fetch_all
64    pub use bsql_arena::{acquire_arena, Arena, ArenaRows, ValidatedRows};
65
66    /// SQLite NULL type indicator (matches `SQLITE_NULL` = 5).
67    /// Re-exported here so generated code does not need a direct libsqlite3-sys dep.
68    pub const SQLITE_NULL: i32 = 5;
69}
70
71// --- Helper macros for async/sync conditional code generation ---
72//
73// These macros are used by `bsql::query!` generated code to conditionally
74// add/remove `async` and `.await` based on whether the `async` feature is
75// enabled. The cfg check happens here in bsql-core (where the feature is
76// defined), not in the user's crate.
77
78/// Conditionally adds `.await` when the `async` feature is enabled.
79/// In sync mode, passes the expression through unchanged.
80#[cfg(feature = "async")]
81#[macro_export]
82#[doc(hidden)]
83macro_rules! __bsql_call {
84    ($expr:expr) => {
85        $expr.await
86    };
87}
88
89/// Conditionally adds `.await` when the `async` feature is enabled.
90/// In sync mode, passes the expression through unchanged.
91#[cfg(not(feature = "async"))]
92#[macro_export]
93#[doc(hidden)]
94macro_rules! __bsql_call {
95    ($expr:expr) => {
96        $expr
97    };
98}
99
100/// Conditionally adds `async` keyword to function definitions.
101/// In sync mode, emits a regular `fn`.
102#[cfg(feature = "async")]
103#[macro_export]
104#[doc(hidden)]
105macro_rules! __bsql_fn {
106    ($(#[$meta:meta])* pub fn $($rest:tt)*) => {
107        $(#[$meta])* pub async fn $($rest)*
108    };
109}
110
111/// Conditionally adds `async` keyword to function definitions.
112/// In sync mode, emits a regular `fn`.
113#[cfg(not(feature = "async"))]
114#[macro_export]
115#[doc(hidden)]
116macro_rules! __bsql_fn {
117    ($(#[$meta:meta])* pub fn $($rest:tt)*) => {
118        $(#[$meta])* pub fn $($rest)*
119    };
120}
121
122pub use error::{BsqlError, BsqlResult};
123pub use executor::{Executor, OwnedResult};
124pub use listener::{Listener, Notification};
125pub use pool::{Pool, PoolBuilder, PoolConnection, PoolStatus};
126#[cfg(feature = "sqlite")]
127pub use sqlite_pool::{SqlitePool, SqliteStreamingQuery, SqliteTransaction};
128pub use stream::QueryStream;
129pub use transaction::{IsolationLevel, Transaction};
130
131/// Hash a string using rapidhash. Used by singleflight, statement naming,
132/// and offline cache keys. Not part of the public API.
133#[doc(hidden)]
134pub fn rapid_hash_str(s: &str) -> u64 {
135    use std::hash::{Hash, Hasher};
136    let mut hasher = rapidhash::quality::RapidHasher::default();
137    s.hash(&mut hasher);
138    hasher.finish()
139}
140
141#[cfg(test)]
142mod tests {
143    use super::*;
144
145    #[test]
146    fn rapid_hash_str_deterministic() {
147        let h1 = rapid_hash_str("SELECT 1");
148        let h2 = rapid_hash_str("SELECT 1");
149        assert_eq!(h1, h2);
150    }
151
152    #[test]
153    fn rapid_hash_str_different_inputs_differ() {
154        let h1 = rapid_hash_str("SELECT 1");
155        let h2 = rapid_hash_str("SELECT 2");
156        assert_ne!(h1, h2);
157    }
158
159    #[test]
160    fn rapid_hash_str_empty_string() {
161        let h = rapid_hash_str("");
162        // Should not panic, and the hash should be consistent
163        assert_eq!(h, rapid_hash_str(""));
164    }
165}