use proc_macro2::TokenStream;
use quote::{format_ident, quote};
use syn::LitStr;
use crate::codegen::schema::SchemaContext;
pub(super) fn collect_field_query_methods(
schema: &SchemaContext,
) -> (Vec<TokenStream>, Vec<TokenStream>, Vec<TokenStream>) {
let mut where_methods = Vec::new();
let mut order_by_methods = Vec::new();
let mut distinct_methods = Vec::new();
for field in &schema.fields {
let field_name_str = field.name.as_str();
let where_method_name = format_ident!("where_{}", field_name_str);
let order_by_method_name = format_ident!("order_by_{}", field_name_str);
let field_type_str = field.field_type.as_str();
let field_name_lit = LitStr::new(field_name_str, proc_macro2::Span::call_site());
let where_method = if field_type_str.starts_with("record<") && field_type_str.ends_with('>')
{
quote! {
pub fn #where_method_name(mut self, predicate: valence::RecordPredicate) -> Self {
self.inner = self.inner.where_record(#field_name_lit.to_string(), predicate);
self
}
}
} else {
match field_type_str {
"integer" => quote! {
pub fn #where_method_name(mut self, predicate: valence::IntPredicate) -> Self {
self.inner = self.inner.where_int(#field_name_lit.to_string(), predicate);
self
}
},
"string" | "text" => quote! {
pub fn #where_method_name(mut self, predicate: valence::StringPredicate) -> Self {
self.inner = self.inner.where_string(#field_name_lit.to_string(), predicate);
self
}
},
"datetime" => quote! {
pub fn #where_method_name(mut self, predicate: valence::DateTimePredicate) -> Self {
self.inner = self.inner.where_datetime(#field_name_lit.to_string(), predicate);
self
}
},
_ => quote! {
pub fn #where_method_name(mut self, predicate: valence::StringPredicate) -> Self {
self.inner = self.inner.where_string(#field_name_lit.to_string(), predicate);
self
}
},
}
};
where_methods.push(where_method);
if field.nullable {
let where_is_none_method = format_ident!("where_{}_is_none", field_name_str);
let where_is_some_method = format_ident!("where_{}_is_some", field_name_str);
let field_name_lit = LitStr::new(field_name_str, proc_macro2::Span::call_site());
where_methods.push(quote! {
pub fn #where_is_none_method(mut self) -> Self {
self.inner = self.inner.where_null(#field_name_lit.to_string(), valence::NullPredicate::IsNone);
self
}
pub fn #where_is_some_method(mut self) -> Self {
self.inner = self.inner.where_null(#field_name_lit.to_string(), valence::NullPredicate::IsSome);
self
}
});
}
let field_name_lit = LitStr::new(field_name_str, proc_macro2::Span::call_site());
order_by_methods.push(quote! {
pub fn #order_by_method_name(mut self, direction: valence::SortDirection) -> Self {
self.inner = self.inner.order_by(#field_name_lit.to_string(), direction);
self
}
});
let is_record = field_type_str.starts_with("record<") && field_type_str.ends_with('>');
let is_string_like = matches!(field_type_str, "string" | "text")
|| (!is_record
&& !matches!(
field_type_str,
"integer" | "float" | "decimal" | "boolean" | "datetime" | "json"
));
if is_string_like {
let distinct_method_name = format_ident!("distinct_{}", field_name_str);
let field_name_lit = LitStr::new(field_name_str, proc_macro2::Span::call_site());
distinct_methods.push(quote! {
pub async fn #distinct_method_name(self) -> valence::Result<Vec<String>> {
self.inner.distinct_values(#field_name_lit, self.valence).await
}
});
}
}
(where_methods, order_by_methods, distinct_methods)
}