mod check;
pub mod config;
mod execute;
mod statement_cache;
mod stream;
pub use check::ModelCheckResult;
pub use config::{
CheckMode, DangerousDmlPolicy, PgClientConfig, SelectWithoutLimitPolicy, SqlPolicy,
StatementCacheConfig,
};
pub use statement_cache::StmtCacheStats;
use crate::check::SchemaRegistry;
use crate::checked_client::ModelRegistration;
#[cfg(feature = "tracing")]
use crate::monitor::TracingSqlHook;
use crate::monitor::{
CompositeHook, LoggingMonitor, QueryHook, QueryMonitor, QueryStats, StatsMonitor,
};
use statement_cache::StatementCache;
use std::sync::Arc;
#[cfg(test)]
mod tests;
pub struct PgClient<C> {
client: C,
registry: Arc<SchemaRegistry>,
stats: Arc<StatsMonitor>,
logging_monitor: Option<LoggingMonitor>,
custom_monitor: Option<Arc<dyn QueryMonitor>>,
hook: Option<Arc<dyn QueryHook>>,
#[cfg(feature = "tracing")]
tracing_sql_hook: Option<TracingSqlHook>,
statement_cache: Option<StatementCache>,
config: PgClientConfig,
}
impl<C> PgClient<C> {
pub fn new(client: C) -> Self {
Self::with_config(client, PgClientConfig::default())
}
pub fn with_config(client: C, config: PgClientConfig) -> Self {
#[cfg(feature = "check")]
let mut registry = SchemaRegistry::with_parse_cache_capacity(config.parse_cache_capacity);
#[cfg(not(feature = "check"))]
let mut registry = SchemaRegistry::new();
for reg in inventory::iter::<ModelRegistration> {
(reg.register_fn)(&mut registry);
}
let logging_monitor = if config.logging_enabled {
let mut monitor = LoggingMonitor::new();
if let Some(min) = config.log_min_duration {
monitor = monitor.min_duration(min);
}
Some(monitor)
} else {
None
};
let statement_cache = (config.statement_cache.enabled
&& config.statement_cache.capacity > 0)
.then(|| StatementCache::new(config.statement_cache.capacity));
Self {
client,
registry: Arc::new(registry),
stats: Arc::new(StatsMonitor::new()),
logging_monitor,
custom_monitor: None,
hook: None,
#[cfg(feature = "tracing")]
tracing_sql_hook: None,
statement_cache,
config,
}
}
pub fn new_empty(client: C) -> Self {
Self {
client,
registry: Arc::new(SchemaRegistry::new()),
stats: Arc::new(StatsMonitor::new()),
logging_monitor: None,
custom_monitor: None,
hook: None,
#[cfg(feature = "tracing")]
tracing_sql_hook: None,
statement_cache: None,
config: PgClientConfig::default(),
}
}
pub fn with_monitor<M: QueryMonitor + 'static>(mut self, monitor: M) -> Self {
self.custom_monitor = Some(Arc::new(monitor));
self
}
pub fn with_monitor_arc(mut self, monitor: Arc<dyn QueryMonitor>) -> Self {
self.custom_monitor = Some(monitor);
self
}
pub fn with_hook<H: QueryHook + 'static>(mut self, hook: H) -> Self {
self.hook = Some(Arc::new(hook));
self
}
pub fn with_hook_arc(mut self, hook: Arc<dyn QueryHook>) -> Self {
self.hook = Some(hook);
self
}
pub fn add_hook<H: QueryHook + 'static>(self, hook: H) -> Self {
self.add_hook_arc(Arc::new(hook))
}
pub fn add_hook_arc(mut self, hook: Arc<dyn QueryHook>) -> Self {
self.hook = Some(match self.hook.take() {
None => hook,
Some(existing) => Arc::new(CompositeHook::new().add_arc(existing).add_arc(hook)),
});
self
}
pub fn registry(&self) -> &SchemaRegistry {
&self.registry
}
pub fn stats(&self) -> QueryStats {
self.stats.stats()
}
pub fn reset_stats(&self) {
self.stats.reset();
}
pub fn stmt_cache_stats(&self) -> Option<StmtCacheStats> {
self.statement_cache.as_ref().map(|c| c.stats())
}
pub fn inner(&self) -> &C {
&self.client
}
pub fn into_inner(self) -> C {
self.client
}
pub fn config(&self) -> &PgClientConfig {
&self.config
}
#[cfg(feature = "tracing")]
pub fn with_tracing_sql(mut self) -> Self {
self.tracing_sql_hook = Some(TracingSqlHook::new());
self
}
#[cfg(feature = "tracing")]
pub fn with_tracing_sql_hook(mut self, hook: TracingSqlHook) -> Self {
self.tracing_sql_hook = Some(hook);
self
}
}