query test progress
This commit is contained in:
@ -1,15 +1,83 @@
|
||||
pub struct Queryer {
|
||||
// To be implemented
|
||||
}
|
||||
use crate::database::Database;
|
||||
use std::sync::Arc;
|
||||
|
||||
impl Default for Queryer {
|
||||
fn default() -> Self {
|
||||
Self::new()
|
||||
}
|
||||
pub mod compiler;
|
||||
|
||||
use dashmap::DashMap;
|
||||
|
||||
pub struct Queryer {
|
||||
pub db: Arc<Database>,
|
||||
cache: DashMap<String, String>,
|
||||
}
|
||||
|
||||
impl Queryer {
|
||||
pub fn new() -> Self {
|
||||
Self {}
|
||||
pub fn new(db: Arc<Database>) -> Self {
|
||||
Self {
|
||||
db,
|
||||
cache: DashMap::new(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Entrypoint to execute a dynamically compiled query based on a schema
|
||||
pub fn query(
|
||||
&self,
|
||||
schema_id: &str,
|
||||
stem_opt: Option<&str>,
|
||||
filters: Option<&serde_json::Value>,
|
||||
) -> Result<serde_json::Value, String> {
|
||||
let filters_map: Option<&serde_json::Map<String, serde_json::Value>> =
|
||||
filters.and_then(|f| f.as_object());
|
||||
|
||||
// Generate Permutation Cache Key: schema_id + sorted filter keys
|
||||
let mut filter_keys: Vec<String> = Vec::new();
|
||||
if let Some(fm) = filters_map {
|
||||
for key in fm.keys() {
|
||||
filter_keys.push(key.clone());
|
||||
}
|
||||
}
|
||||
filter_keys.sort();
|
||||
|
||||
let stem_key = stem_opt.unwrap_or("/");
|
||||
let cache_key = format!("{}(Stem:{}):{}", schema_id, stem_key, filter_keys.join(","));
|
||||
|
||||
let sql = if let Some(cached_sql) = self.cache.get(&cache_key) {
|
||||
cached_sql.value().clone()
|
||||
} else {
|
||||
// Compile the massive base SQL string
|
||||
let compiler = compiler::SqlCompiler::new(self.db.clone());
|
||||
let compiled_sql = compiler.compile(schema_id, stem_opt, &filter_keys)?;
|
||||
self.cache.insert(cache_key.clone(), compiled_sql.clone());
|
||||
compiled_sql
|
||||
};
|
||||
|
||||
// 2. Prepare the execution arguments from the filters
|
||||
let mut args: Vec<serde_json::Value> = Vec::new();
|
||||
|
||||
if let Some(fm) = filters_map {
|
||||
for (_i, key) in filter_keys.iter().enumerate() {
|
||||
if let Some(val) = fm.get(key) {
|
||||
args.push(val.clone());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 3. Execute via Database Executor
|
||||
let fetched = match self.db.query(&sql, Some(&args)) {
|
||||
Ok(serde_json::Value::Array(table)) => {
|
||||
if table.is_empty() {
|
||||
Ok(serde_json::Value::Null)
|
||||
} else {
|
||||
// We expect the query to return a single JSONB column, already unpacked from row[0]
|
||||
Ok(table.first().unwrap().clone())
|
||||
}
|
||||
}
|
||||
Ok(other) => Err(format!(
|
||||
"Expected array from generic query, got: {:?}",
|
||||
other
|
||||
)),
|
||||
Err(e) => Err(format!("SPI error in queryer: {}", e)),
|
||||
}?;
|
||||
|
||||
Ok(fetched)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user