linkrs_api/api_core/
query_api_builder.rs1use crate::api_core::cost_profile::cost_config_for_profile;
9use crate::api_core::cost_profile::resolve_space_cost_configs;
10use crate::api_core::error::{CoreError, CoreResult};
11use crate::api_core::QueryApi;
12use linkrs_config::{RuntimeConfig, StorageCostProfile};
13use linkrs_core::metadata::SchemaManager;
14use linkrs_metrics::StatsManager;
15use linkrs_query::executor::streaming::pool::SharedScheduler;
16use linkrs_query::executor::streaming::query_registry::QueryRegistry;
17use linkrs_query::experimental_pipeline_extensions::ExtensionRegistry;
18use linkrs_query::optimizer::CostModelConfig;
19use linkrs_query::query_manager::QueryManager;
20use linkrs_query::OptimizerEngine;
21use linkrs_storage::StorageClient;
22#[cfg(feature = "vector")]
23use linkrs_sync::backend::VectorBackend;
24use parking_lot::RwLock;
25use std::collections::HashMap;
26use std::sync::Arc;
27
28impl<S: StorageClient + Clone + 'static> QueryApi<S> {
29 pub fn with_schema_manager(mut self, schema_manager: Arc<SchemaManager>) -> Self {
31 self.pipeline_manager = self.pipeline_manager.with_schema_manager(schema_manager);
32 self
33 }
34
35 pub fn with_sync_manager(mut self, sync_manager: Arc<linkrs_sync::SyncManager>) -> Self {
37 self.pipeline_manager = self.pipeline_manager.with_sync_manager(sync_manager);
38 self
39 }
40
41 pub fn with_optimizer_engine(
45 storage: Arc<RwLock<S>>,
46 stats_manager: Arc<StatsManager>,
47 optimizer_engine: Arc<OptimizerEngine>,
48 schema_manager: Option<Arc<SchemaManager>>,
49 ) -> Self {
50 let pipeline = Self::pipeline_with_engine(storage, stats_manager, optimizer_engine);
51 let pipeline = match schema_manager {
52 Some(sm) => pipeline.with_schema_manager(sm),
53 None => pipeline,
54 };
55 Self {
56 pipeline_manager: pipeline,
57 }
58 }
59
60 pub fn with_cost_config(mut self, config: CostModelConfig) -> Self {
67 let spaces = self
68 .pipeline_manager
69 .optimizer_engine()
70 .space_cost_configs();
71 let engine = OptimizerEngine::new(config);
72 engine.set_space_cost_configs(spaces);
73 self.pipeline_manager.set_optimizer_engine(Arc::new(engine));
74 self
75 }
76
77 pub fn with_cost_profile(
84 mut self,
85 profile: StorageCostProfile,
86 runtime: &RuntimeConfig,
87 ) -> Self {
88 let resolved = profile.resolve_for_runtime(runtime);
89 self = self.with_cost_config(cost_config_for_profile(resolved));
90 self.pipeline_manager
91 .set_default_cost_profile_label(format!("{resolved:?}"));
92 self
93 }
94
95 pub fn with_space_cost_profiles(
101 mut self,
102 profiles: &HashMap<String, StorageCostProfile>,
103 runtime: &RuntimeConfig,
104 ) -> Self {
105 let (configs, labels) = resolve_space_cost_configs(profiles, runtime);
106 self.pipeline_manager
107 .set_space_cost_configs(configs, labels);
108 self
109 }
110
111 pub fn with_default_cost_profile_label(mut self, label: String) -> Self {
117 self.pipeline_manager.set_default_cost_profile_label(label);
118 self
119 }
120
121 pub fn cost_config(&self) -> CostModelConfig {
123 *self.pipeline_manager.optimizer_engine().cost_config()
124 }
125
126 pub fn with_statistics_settings(mut self, sample_limit: usize, min_epoch_delta: u64) -> Self {
132 self.pipeline_manager = self
133 .pipeline_manager
134 .with_statistics_sample_limit(sample_limit)
135 .with_statistics_min_epoch_delta(min_epoch_delta);
136 self
137 }
138
139 pub fn statistics_sample_limit(&self) -> usize {
141 self.pipeline_manager.statistics_sample_limit()
142 }
143
144 pub fn with_password_history_depth(mut self, depth: usize) -> Self {
147 self.pipeline_manager = self.pipeline_manager.with_password_history_depth(depth);
148 self
149 }
150
151 pub fn statistics_min_epoch_delta(&self) -> u64 {
153 self.pipeline_manager.statistics_min_epoch_delta()
154 }
155
156 pub fn install_shared_scheduler(
159 &mut self,
160 shared_scheduler: Arc<SharedScheduler>,
161 query_registry: Arc<QueryRegistry>,
162 ) {
163 self.pipeline_manager
164 .set_shared_scheduler(Some(shared_scheduler));
165 self.pipeline_manager
166 .set_query_registry(Some(query_registry));
167 }
168
169 pub fn shared_scheduler(&self) -> Option<Arc<SharedScheduler>> {
171 self.pipeline_manager.shared_scheduler()
172 }
173
174 pub fn query_registry(&self) -> Option<Arc<QueryRegistry>> {
176 self.pipeline_manager.query_registry()
177 }
178
179 pub fn install_query_manager(&mut self, query_manager: Arc<QueryManager>) {
183 self.pipeline_manager.set_query_manager(Some(query_manager));
184 }
185
186 pub fn set_extensions(&mut self, extensions: Arc<ExtensionRegistry>) {
189 self.pipeline_manager.set_extensions(extensions);
190 }
191
192 pub fn extensions(&self) -> Arc<ExtensionRegistry> {
194 self.pipeline_manager.extensions()
195 }
196
197 pub fn collect_statistics(&self, space: &str, force: bool) -> CoreResult<()> {
202 self.pipeline_manager
203 .collect_statistics(space, force)
204 .map_err(CoreError::Internal)
205 .map(|_| ())
206 }
207
208 pub fn plan_cache_hit_rate(&self) -> f64 {
210 self.pipeline_manager.plan_cache_metrics().hit_rate()
211 }
212
213 pub fn plan_cache_len(&self) -> usize {
215 self.pipeline_manager.plan_cache().len()
216 }
217
218 #[cfg(feature = "vector")]
220 pub async fn with_vector_backend(
221 storage: Arc<RwLock<S>>,
222 stats_manager: Arc<StatsManager>,
223 backend: VectorBackend,
224 schema_manager: Option<Arc<SchemaManager>>,
225 ) -> CoreResult<Self> {
226 let optimizer_engine = Arc::new(OptimizerEngine::default());
227
228 let handle = tokio::runtime::Handle::current();
230 let vector_coordinator = Arc::new(
231 linkrs_sync::vector_sync::VectorSyncCoordinator::new_without_embedding(backend, handle),
232 );
233
234 let mut pipeline_manager =
236 Self::pipeline_with_engine(storage, stats_manager, optimizer_engine);
237
238 if let Some(sm) = schema_manager {
239 pipeline_manager = pipeline_manager
240 .with_schema_manager(sm)
241 .with_vector_coordinator(vector_coordinator);
242 } else {
243 pipeline_manager = pipeline_manager.with_vector_coordinator(vector_coordinator);
244 }
245
246 Ok(Self { pipeline_manager })
247 }
248}