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