use crate::{compiler::ir::IRQuery, error::Result};
#[derive(Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd)]
#[non_exhaustive]
pub enum QueryCardinality {
Single,
Multiple,
List,
}
impl QueryCardinality {
#[must_use]
pub const fn expected_hit_rate(&self) -> f64 {
match self {
Self::Single => 0.91,
Self::Multiple => 0.88,
Self::List => 0.60,
}
}
}
#[derive(Debug, Clone, Eq, PartialEq)]
pub struct QueryEntityProfile {
pub query_name: String,
pub entity_type: Option<String>,
pub cardinality: QueryCardinality,
}
impl QueryEntityProfile {
#[must_use]
pub const fn new(
query_name: String,
entity_type: Option<String>,
cardinality: QueryCardinality,
) -> Self {
Self {
query_name,
entity_type,
cardinality,
}
}
#[must_use]
pub const fn expected_hit_rate(&self) -> f64 {
self.cardinality.expected_hit_rate()
}
}
#[derive(Debug, Clone)]
pub struct QueryAnalyzer;
impl QueryAnalyzer {
#[must_use]
pub const fn new() -> Self {
Self
}
pub fn analyze_query(
&self,
query_def: &IRQuery,
query_str: &str,
) -> Result<QueryEntityProfile> {
let cardinality = self.classify_cardinality(query_str);
let entity_type = self.extract_entity_type(query_def);
Ok(QueryEntityProfile {
query_name: query_def.name.clone(),
entity_type,
cardinality,
})
}
pub(crate) fn classify_cardinality(&self, query_str: &str) -> QueryCardinality {
let query_lower = query_str.to_lowercase();
if query_lower.contains("where")
&& query_lower.contains("id")
&& query_lower.contains('=')
&& !query_lower.contains("in")
{
return QueryCardinality::Single;
}
if query_lower.contains("where") && query_lower.contains("in") {
return QueryCardinality::Multiple;
}
QueryCardinality::List
}
fn extract_entity_type(&self, query_def: &IRQuery) -> Option<String> {
if query_def.return_type.is_empty() {
return None;
}
let return_type = &query_def.return_type;
let base_type = if return_type.ends_with("[]") {
&return_type[..return_type.len() - 2]
} else {
return_type.as_str()
};
if base_type.is_empty() {
None
} else {
Some(base_type.to_string())
}
}
}
impl Default for QueryAnalyzer {
fn default() -> Self {
Self::new()
}
}