use super::types::RustType;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum FunctionKind {
Query,
Mutation,
Job,
Cron,
Workflow,
}
impl FunctionKind {
pub fn as_str(&self) -> &'static str {
match self {
FunctionKind::Query => "query",
FunctionKind::Mutation => "mutation",
FunctionKind::Job => "job",
FunctionKind::Cron => "cron",
FunctionKind::Workflow => "workflow",
}
}
pub fn is_client_callable(&self) -> bool {
matches!(self, FunctionKind::Query | FunctionKind::Mutation)
}
}
impl std::fmt::Display for FunctionKind {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.as_str())
}
}
#[derive(Debug, Clone)]
pub struct FunctionArg {
pub name: String,
pub rust_type: RustType,
pub doc: Option<String>,
}
impl FunctionArg {
pub fn new(name: impl Into<String>, rust_type: RustType) -> Self {
Self {
name: name.into(),
rust_type,
doc: None,
}
}
}
#[derive(Debug, Clone)]
pub struct FunctionDef {
pub name: String,
pub kind: FunctionKind,
pub args: Vec<FunctionArg>,
pub return_type: RustType,
pub doc: Option<String>,
pub is_async: bool,
}
impl FunctionDef {
pub fn new(name: impl Into<String>, kind: FunctionKind, return_type: RustType) -> Self {
Self {
name: name.into(),
kind,
args: Vec::new(),
return_type,
doc: None,
is_async: true,
}
}
pub fn query(name: impl Into<String>, return_type: RustType) -> Self {
Self::new(name, FunctionKind::Query, return_type)
}
pub fn mutation(name: impl Into<String>, return_type: RustType) -> Self {
Self::new(name, FunctionKind::Mutation, return_type)
}
pub fn with_arg(mut self, arg: FunctionArg) -> Self {
self.args.push(arg);
self
}
pub fn with_doc(mut self, doc: impl Into<String>) -> Self {
self.doc = Some(doc.into());
self
}
pub fn ts_name(&self) -> String {
to_camel_case(&self.name)
}
}
fn to_camel_case(s: &str) -> String {
let mut result = String::new();
let mut capitalize_next = false;
for c in s.chars() {
if c == '_' {
capitalize_next = true;
} else if capitalize_next {
result.push(c.to_uppercase().next().unwrap_or(c));
capitalize_next = false;
} else {
result.push(c);
}
}
result
}
#[cfg(test)]
#[allow(clippy::unwrap_used, clippy::indexing_slicing)]
mod tests {
use super::*;
#[test]
fn test_function_def_query() {
let func = FunctionDef::query("get_user", RustType::Custom("User".to_string()))
.with_arg(FunctionArg::new("id", RustType::Uuid))
.with_doc("Get a user by ID");
assert_eq!(func.name, "get_user");
assert_eq!(func.kind, FunctionKind::Query);
assert_eq!(func.args.len(), 1);
assert_eq!(func.ts_name(), "getUser");
}
#[test]
fn test_function_def_mutation() {
let func = FunctionDef::mutation("create_user", RustType::Custom("User".to_string()));
assert_eq!(func.kind, FunctionKind::Mutation);
}
#[test]
fn test_to_camel_case() {
assert_eq!(to_camel_case("get_user"), "getUser");
assert_eq!(to_camel_case("create_project_task"), "createProjectTask");
assert_eq!(to_camel_case("getUser"), "getUser");
}
}