baobao_codegen/adapters/
database.rs

1//! Database adapter abstraction.
2//!
3//! This module defines the [`DatabaseAdapter`] trait for abstracting database
4//! connection and pool code generation (sqlx, diesel, bun:sqlite, etc.).
5
6use baobao_core::DatabaseType;
7
8use super::cli::{Dependency, ImportSpec};
9use crate::builder::CodeFragment;
10
11/// Pool configuration options.
12#[derive(Debug, Clone, Default)]
13pub struct PoolConfig {
14    /// Maximum number of connections
15    pub max_connections: Option<u32>,
16    /// Minimum number of connections
17    pub min_connections: Option<u32>,
18    /// Connection acquire timeout in seconds
19    pub acquire_timeout: Option<u64>,
20    /// Idle connection timeout in seconds
21    pub idle_timeout: Option<u64>,
22    /// Maximum connection lifetime in seconds
23    pub max_lifetime: Option<u64>,
24}
25
26impl PoolConfig {
27    /// Check if any pool options are configured.
28    pub fn has_config(&self) -> bool {
29        self.max_connections.is_some()
30            || self.min_connections.is_some()
31            || self.acquire_timeout.is_some()
32            || self.idle_timeout.is_some()
33            || self.max_lifetime.is_some()
34    }
35}
36
37/// SQLite-specific configuration options.
38#[derive(Debug, Clone, Default)]
39pub struct SqliteConfig {
40    /// Direct file path (takes precedence over env var)
41    pub path: Option<String>,
42    /// Create database if it doesn't exist
43    pub create_if_missing: Option<bool>,
44    /// Open in read-only mode
45    pub read_only: Option<bool>,
46    /// Journal mode (wal, delete, truncate, persist, memory, off)
47    pub journal_mode: Option<String>,
48    /// Synchronous mode (off, normal, full, extra)
49    pub synchronous: Option<String>,
50    /// Busy timeout in milliseconds
51    pub busy_timeout: Option<u64>,
52    /// Enable foreign key constraints
53    pub foreign_keys: Option<bool>,
54}
55
56impl SqliteConfig {
57    /// Check if any SQLite options are configured.
58    pub fn has_config(&self) -> bool {
59        self.create_if_missing.is_some()
60            || self.read_only.is_some()
61            || self.journal_mode.is_some()
62            || self.synchronous.is_some()
63            || self.busy_timeout.is_some()
64            || self.foreign_keys.is_some()
65    }
66}
67
68/// Info needed to generate pool initialization.
69#[derive(Debug, Clone)]
70pub struct PoolInitInfo {
71    /// Field name in the context struct
72    pub field_name: String,
73    /// Database type
74    pub db_type: DatabaseType,
75    /// Environment variable for connection string
76    pub env_var: String,
77    /// Pool configuration
78    pub pool_config: PoolConfig,
79    /// SQLite-specific config (only for SQLite)
80    pub sqlite_config: Option<SqliteConfig>,
81    /// Whether initialization is async
82    pub is_async: bool,
83}
84
85/// Info for generating database-specific options.
86#[derive(Debug, Clone)]
87pub struct DatabaseOptionsInfo {
88    /// Database type
89    pub db_type: DatabaseType,
90    /// SQLite configuration
91    pub sqlite: Option<SqliteConfig>,
92}
93
94/// Trait for database adapters.
95///
96/// Implement this trait to support a specific database library (sqlx, diesel, etc.).
97pub trait DatabaseAdapter {
98    /// Adapter name for identification.
99    fn name(&self) -> &'static str;
100
101    /// Dependencies required for a specific database type.
102    fn dependencies(&self, db_type: DatabaseType) -> Vec<Dependency>;
103
104    /// The type name for a connection/pool.
105    fn pool_type(&self, db_type: DatabaseType) -> &'static str;
106
107    /// Generate pool/connection initialization code.
108    fn generate_pool_init(&self, info: &PoolInitInfo) -> Vec<CodeFragment>;
109
110    /// Generate database-specific options (e.g., SQLite connect options).
111    fn generate_options(&self, info: &DatabaseOptionsInfo) -> Option<Vec<CodeFragment>>;
112
113    /// Imports needed for database code.
114    fn imports(&self, db_type: DatabaseType) -> Vec<ImportSpec>;
115
116    /// Whether this adapter requires async initialization.
117    fn requires_async(&self, db_type: DatabaseType) -> bool;
118}