use crate::{
db::{WhereClause, WhereOperator},
error::{FraiseQLError, Result},
};
pub const AUTO_PARAM_NAMES: &[&str] = &[
"where", "limit", "offset", "orderBy", "first", "last", "after", "before",
];
pub fn inject_param_where_clause(
col: &str,
value: serde_json::Value,
native_columns: &std::collections::HashMap<String, String>,
) -> WhereClause {
if let Some(pg_type) = native_columns.get(col) {
WhereClause::NativeField {
column: crate::utils::to_snake_case(col),
pg_cast: pg_type_to_cast(pg_type).to_string(),
operator: WhereOperator::Eq,
value,
}
} else {
WhereClause::Field {
path: vec![crate::utils::to_snake_case(col)],
operator: WhereOperator::Eq,
value,
}
}
}
pub fn pg_type_to_cast(data_type: &str) -> &'static str {
crate::runtime::native_columns::pg_type_to_cast(data_type)
}
pub fn compute_projection_reduction(projected_field_count: usize) -> u32 {
const BASELINE_FIELD_COUNT: usize = 20;
let requested = projected_field_count.min(BASELINE_FIELD_COUNT);
let saved = BASELINE_FIELD_COUNT.saturating_sub(requested);
#[allow(clippy::cast_possible_truncation)] let percent = ((saved * 100) / BASELINE_FIELD_COUNT) as u32;
percent.clamp(10, 90)
}
pub fn combine_explicit_arg_where(
existing: Option<WhereClause>,
defined_args: &[crate::schema::ArgumentDefinition],
provided_args: &std::collections::HashMap<String, serde_json::Value>,
native_columns: &std::collections::HashMap<String, String>,
) -> Option<WhereClause> {
let explicit_conditions: Vec<WhereClause> = defined_args
.iter()
.filter(|arg| !AUTO_PARAM_NAMES.contains(&arg.name.as_str()))
.filter_map(|arg| {
provided_args.get(&arg.name).map(|value| {
if let Some(pg_type) = native_columns.get(&arg.name) {
WhereClause::NativeField {
column: crate::utils::to_snake_case(&arg.name),
pg_cast: pg_type_to_cast(pg_type).to_string(),
operator: WhereOperator::Eq,
value: value.clone(),
}
} else {
WhereClause::Field {
path: vec![crate::utils::to_snake_case(&arg.name)],
operator: WhereOperator::Eq,
value: value.clone(),
}
}
})
})
.collect();
if explicit_conditions.is_empty() {
return existing;
}
let mut all_conditions = Vec::new();
if let Some(prev) = existing {
all_conditions.push(prev);
}
all_conditions.extend(explicit_conditions);
match all_conditions.len() {
1 => Some(all_conditions.remove(0)),
_ => Some(WhereClause::And(all_conditions)),
}
}
pub fn enforce_max_page_size(
value: Option<u32>,
max: Option<u32>,
arg_name: &str,
) -> Result<Option<u32>> {
if let (Some(v), Some(m)) = (value, max) {
if v > m {
return Err(FraiseQLError::Validation {
message: format!("`{arg_name}` {v} exceeds the maximum page size of {m}"),
path: Some(arg_name.to_string()),
});
}
}
Ok(value)
}
#[cfg(test)]
#[path = "query_params_tests.rs"]
mod query_params_tests;