Skip to main content

valence_core/
query_compiler_registry.rs

1//! Registry mapping [`DatabaseBackend::engine_id`](crate::backend::DatabaseBackend::engine_id) to query compilers.
2
3use std::collections::HashMap;
4use std::sync::{Arc, OnceLock};
5
6use crate::error::{Error, Result};
7use crate::known_engines::KnownEngines;
8use crate::query::QueryCore;
9use crate::query_compiler::QueryCompiler;
10use crate::CompiledQuery;
11
12/// Resolves a [`QueryCompiler`] for a storage engine slug.
13#[derive(Clone)]
14pub struct QueryCompilerRegistry {
15    compilers: HashMap<&'static str, Arc<dyn QueryCompiler>>,
16}
17
18impl std::fmt::Debug for QueryCompilerRegistry {
19    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
20        f.debug_struct("QueryCompilerRegistry")
21            .field("engines", &self.compilers.keys().collect::<Vec<_>>())
22            .finish()
23    }
24}
25
26impl Default for QueryCompilerRegistry {
27    fn default() -> Self {
28        Self {
29            compilers: HashMap::new(),
30        }
31    }
32}
33
34impl QueryCompilerRegistry {
35    /// Build a registry from Cargo feature-enabled compilers.
36    #[must_use]
37    pub fn with_enabled_features() -> Self {
38        let mut registry = Self::default();
39        registry.register_builtins();
40        registry
41    }
42
43    fn register_builtins(&mut self) {
44        #[cfg(feature = "compiler-sql")]
45        {
46            let sql: Arc<dyn QueryCompiler> = Arc::new(crate::backend::SqlQueryCompiler);
47            self.register(KnownEngines::SQLITE, Arc::clone(&sql));
48            self.register(KnownEngines::POSTGRES, Arc::clone(&sql));
49            self.register(KnownEngines::INMEMORY_MEM, sql);
50        }
51        #[cfg(feature = "compiler-surreal")]
52        {
53            self.register(
54                KnownEngines::SURREALDB,
55                Arc::new(crate::backend::SurrealQueryCompiler) as Arc<dyn QueryCompiler>,
56            );
57        }
58        #[cfg(feature = "compiler-mongodb")]
59        {
60            self.register(
61                KnownEngines::MONGODB,
62                Arc::new(crate::backend::MongoQueryCompiler) as Arc<dyn QueryCompiler>,
63            );
64        }
65        #[cfg(feature = "compiler-redis")]
66        {
67            self.register(
68                KnownEngines::REDIS,
69                Arc::new(crate::backend::RedisQueryCompiler) as Arc<dyn QueryCompiler>,
70            );
71        }
72        #[cfg(feature = "compiler-indradb")]
73        {
74            self.register(
75                KnownEngines::INDRADB,
76                Arc::new(crate::backend::IndraQueryCompiler) as Arc<dyn QueryCompiler>,
77            );
78        }
79    }
80
81    /// Register a compiler for an open engine slug.
82    pub fn register(&mut self, engine_id: &'static str, compiler: Arc<dyn QueryCompiler>) {
83        self.compilers.insert(engine_id, compiler);
84    }
85
86    /// Look up a compiler by engine id.
87    pub fn get(&self, engine_id: &str) -> Option<&Arc<dyn QueryCompiler>> {
88        self.compilers.get(engine_id)
89    }
90
91    /// Compile `core` for `engine_id`, or return a clear error when the feature is disabled.
92    pub fn compile(&self, engine_id: &str, core: &QueryCore) -> Result<CompiledQuery> {
93        let compiler = self.get(engine_id).ok_or_else(|| {
94            Error::Internal(format!(
95                "no query compiler registered for engine `{engine_id}` — enable the matching \
96                 valence-core `compiler-*` / valence facade feature"
97            ))
98        })?;
99        compiler.compile(core)
100    }
101}
102
103static GLOBAL_REGISTRY: OnceLock<QueryCompilerRegistry> = OnceLock::new();
104
105/// Global registry populated from enabled compiler features.
106pub fn global_compiler_registry() -> &'static QueryCompilerRegistry {
107    GLOBAL_REGISTRY.get_or_init(QueryCompilerRegistry::with_enabled_features)
108}
109
110/// Compile `core` for the given backend engine id.
111pub fn compile_for_engine(engine_id: &str, core: &QueryCore) -> Result<CompiledQuery> {
112    global_compiler_registry().compile(engine_id, core)
113}