Skip to main content

sift_query_sqlx/execution/
config.rs

1use super::*;
2
3impl PgSiftQuery {
4    #[must_use]
5    pub fn new(pool: PgPool) -> Self {
6        Self {
7            pool,
8            policy: QueryPolicy::default(),
9            execution: PgExecutionPolicy::default(),
10            renderer: PgRenderer,
11            parallel_gate: Arc::new(Semaphore::new(16)),
12            scan_gate: Arc::new(Semaphore::new(4)),
13            scan_wait_gate: Arc::new(Semaphore::new(16)),
14            shape_cache: None,
15            extensions: crate::enrichment::PgExtensions::default(),
16            observers: crate::observe::Observers::default(),
17        }
18    }
19
20    pub fn with_policy(
21        pool: PgPool,
22        policy: QueryPolicy,
23        execution: PgExecutionPolicy,
24    ) -> Result<Self, ConfigError> {
25        if execution.timeout.is_zero() || execution.max_parallel_queries == 0 {
26            return Err(ConfigError::Invalid(
27                "PostgreSQL timeout and parallel query limit must be greater than zero".to_owned(),
28            ));
29        }
30        if execution.shape_cache_capacity > 16_384 {
31            return Err(ConfigError::Invalid(
32                "PostgreSQL shape cache capacity cannot exceed 16384".to_owned(),
33            ));
34        }
35        let parallel_gate = Arc::new(Semaphore::new(execution.max_parallel_queries));
36        let shape_cache = if execution.shape_cache_capacity > 0 {
37            Some(Arc::new(crate::QueryShapeCache::new(
38                execution.shape_cache_capacity,
39            )?))
40        } else {
41            None
42        };
43        Ok(Self {
44            pool,
45            policy,
46            execution,
47            renderer: PgRenderer,
48            parallel_gate,
49            scan_gate: Arc::new(Semaphore::new(4)),
50            scan_wait_gate: Arc::new(Semaphore::new(16)),
51            shape_cache,
52            extensions: crate::enrichment::PgExtensions::default(),
53            observers: crate::observe::Observers::default(),
54        })
55    }
56
57    #[must_use]
58    pub fn shape_cache_stats(&self) -> Option<ShapeCacheStats> {
59        self.shape_cache.as_ref().map(|cache| cache.stats())
60    }
61
62    pub fn clear_shape_cache(&self) {
63        if let Some(cache) = &self.shape_cache {
64            cache.clear();
65        }
66    }
67
68    /// Configures a separate active/waiting scan budget shared by instance clones.
69    pub fn with_scan_concurrency(
70        mut self,
71        active: usize,
72        waiting: usize,
73    ) -> Result<Self, ConfigError> {
74        if active == 0 || active > 1024 || waiting > 16_384 {
75            return Err(ConfigError::Invalid(
76                "invalid scan concurrency budget".to_owned(),
77            ));
78        }
79        self.scan_gate = Arc::new(Semaphore::new(active));
80        self.scan_wait_gate = Arc::new(Semaphore::new(waiting));
81        Ok(self)
82    }
83
84    #[must_use]
85    pub fn with_partition_resolver<R>(mut self, resolver: R) -> Self
86    where
87        R: PartitionResolver + 'static,
88    {
89        self.extensions.set_partition_resolver(Arc::new(resolver));
90        self
91    }
92
93    #[must_use]
94    pub fn with_sql_interceptor<I>(mut self, interceptor: I) -> Self
95    where
96        I: SqlInterceptor + 'static,
97    {
98        self.extensions.push_sql_interceptor(Arc::new(interceptor));
99        self
100    }
101
102    #[must_use]
103    pub fn with_result_filter<F>(mut self, filter: F) -> Self
104    where
105        F: ResultFilter + 'static,
106    {
107        self.extensions.push_result_filter(Arc::new(filter));
108        self
109    }
110
111    #[must_use]
112    pub fn with_page_enricher<E>(mut self, enricher: E) -> Self
113    where
114        E: crate::PageEnricher + 'static,
115    {
116        self.extensions.push_page_enricher(Arc::new(enricher));
117        self
118    }
119
120    #[must_use]
121    pub fn query_builder<E: SearchEntity>(&self) -> QueryBuilder<'_, E> {
122        QueryBuilder::new(&self.policy)
123    }
124}