more tests progress

This commit is contained in:
2026-03-12 17:46:38 -04:00
parent 5b183a1aba
commit 732034bbc7
10 changed files with 1661 additions and 544 deletions

View File

@ -24,61 +24,105 @@ impl Queryer {
stem_opt: Option<&str>,
filters: Option<&serde_json::Value>,
) -> crate::drop::Drop {
let filters_map: Option<&serde_json::Map<String, serde_json::Value>> =
filters.and_then(|f| f.as_object());
let filters_map = 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());
// 1. Process filters into structured $op keys and linear values
let (filter_keys, args) = match self.parse_filter_entries(filters_map) {
Ok(res) => res,
Err(msg) => {
return crate::drop::Drop::with_errors(vec![crate::drop::Error {
code: "FILTER_PARSE_FAILED".to_string(),
message: msg,
details: crate::drop::ErrorDetails {
path: schema_id.to_string(),
},
}]);
}
}
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());
match compiler.compile(schema_id, stem_opt, &filter_keys) {
Ok(compiled_sql) => {
self.cache.insert(cache_key.clone(), compiled_sql.clone());
compiled_sql
}
Err(e) => {
return crate::drop::Drop::with_errors(vec![crate::drop::Error {
code: "QUERY_COMPILATION_FAILED".to_string(),
message: e,
details: crate::drop::ErrorDetails {
path: schema_id.to_string(),
},
}]);
}
}
// 2. Fetch from cache or compile
let sql = match self.get_or_compile_sql(&cache_key, schema_id, stem_opt, &filter_keys) {
Ok(sql) => sql,
Err(drop) => return drop,
};
// 2. Prepare the execution arguments from the filters
let mut args: Vec<serde_json::Value> = Vec::new();
// 3. Execute via Database Executor
self.execute_sql(schema_id, &sql, &args)
}
fn parse_filter_entries(
&self,
filters_map: Option<&serde_json::Map<String, serde_json::Value>>,
) -> Result<(Vec<String>, Vec<serde_json::Value>), String> {
let mut filter_entries: Vec<(String, 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());
for (key, val) in fm {
if let Some(obj) = val.as_object() {
for (op, op_val) in obj {
if !op.starts_with('$') {
return Err(format!("Filter operator must start with '$', got: {}", op));
}
filter_entries.push((format!("{}:{}", key, op), op_val.clone()));
}
} else {
return Err(format!(
"Filter for field '{}' must be an object with operators like $eq, $in, etc.",
key
));
}
}
}
filter_entries.sort_by(|a, b| a.0.cmp(&b.0));
// 3. Execute via Database Executor
match self.db.query(&sql, Some(&args)) {
let filter_keys: Vec<String> = filter_entries.iter().map(|(k, _)| k.clone()).collect();
let args: Vec<serde_json::Value> = filter_entries.into_iter().map(|(_, v)| v).collect();
Ok((filter_keys, args))
}
fn get_or_compile_sql(
&self,
cache_key: &str,
schema_id: &str,
stem_opt: Option<&str>,
filter_keys: &[String],
) -> Result<String, crate::drop::Drop> {
if let Some(cached_sql) = self.cache.get(cache_key) {
return Ok(cached_sql.value().clone());
}
let compiler = compiler::SqlCompiler::new(self.db.clone());
match compiler.compile(schema_id, stem_opt, filter_keys) {
Ok(compiled_sql) => {
self
.cache
.insert(cache_key.to_string(), compiled_sql.clone());
Ok(compiled_sql)
}
Err(e) => Err(crate::drop::Drop::with_errors(vec![crate::drop::Error {
code: "QUERY_COMPILATION_FAILED".to_string(),
message: e,
details: crate::drop::ErrorDetails {
path: schema_id.to_string(),
},
}])),
}
}
fn execute_sql(
&self,
schema_id: &str,
sql: &str,
args: &[serde_json::Value],
) -> crate::drop::Drop {
match self.db.query(sql, Some(args)) {
Ok(serde_json::Value::Array(table)) => {
if table.is_empty() {
crate::drop::Drop::success_with_val(serde_json::Value::Null)
} else {
// We expect the query to return a single JSONB column, already unpacked from row[0]
crate::drop::Drop::success_with_val(table.first().unwrap().clone())
}
}