use fraiseql_core::schema::FieldType;
use serde_json::{Value, json};
use super::super::resource::{HttpMethod, RestRoute};
pub(super) const BRACKET_OPERATORS_DESC: &str = "eq, ne, gt, gte, lt, lte, in, nin, like, ilike, is_null, contains, icontains, startswith, endswith";
pub(super) fn field_type_to_json_schema(ft: &FieldType) -> Value {
match ft {
FieldType::Int => json!({ "type": "integer" }),
FieldType::Float => json!({ "type": "number" }),
FieldType::Boolean => json!({ "type": "boolean" }),
FieldType::Id | FieldType::Uuid => json!({ "type": "string", "format": "uuid" }),
FieldType::DateTime => json!({ "type": "string", "format": "date-time" }),
FieldType::Date => json!({ "type": "string", "format": "date" }),
FieldType::Time => json!({ "type": "string", "format": "time" }),
FieldType::Json => json!({ "type": "object" }),
FieldType::Decimal => json!({ "type": "string", "format": "decimal" }),
FieldType::Vector => json!({ "type": "array", "items": { "type": "number" } }),
FieldType::Scalar(name) => scalar_to_json_schema(name),
FieldType::List(inner) => {
json!({ "type": "array", "items": field_type_to_json_schema(inner) })
},
FieldType::Object(name) | FieldType::Enum(name) | FieldType::Input(name) => {
json!({ "$ref": format!("#/components/schemas/{name}") })
},
FieldType::Interface(name) | FieldType::Union(name) => {
json!({ "type": "object", "description": format!("See {name}") })
},
_ => json!({ "type": "string" }),
}
}
pub(super) fn scalar_to_json_schema(name: &str) -> Value {
match name {
"Email" => json!({ "type": "string", "format": "email" }),
"URL" | "Uri" => json!({ "type": "string", "format": "uri" }),
"PhoneNumber" => json!({ "type": "string", "format": "phone" }),
_ => json!({ "type": "string" }),
}
}
pub(super) const fn method_to_string(method: HttpMethod) -> &'static str {
match method {
HttpMethod::Get => "get",
HttpMethod::Post => "post",
HttpMethod::Put => "put",
HttpMethod::Patch => "patch",
HttpMethod::Delete => "delete",
}
}
pub(super) fn should_have_prefer_header(route: &RestRoute) -> bool {
match route.method {
HttpMethod::Get => {
!route.path.contains('{')
},
HttpMethod::Post | HttpMethod::Patch | HttpMethod::Delete => true,
HttpMethod::Put => false,
}
}
pub(super) fn capitalize(s: &str) -> String {
let mut chars = s.chars();
match chars.next() {
None => String::new(),
Some(c) => c.to_uppercase().to_string() + chars.as_str(),
}
}
pub(super) fn to_snake(s: &str) -> String {
let mut result = String::new();
for (i, c) in s.chars().enumerate() {
if c.is_uppercase() {
if i > 0 {
result.push('_');
}
result.extend(c.to_lowercase());
} else {
result.push(c);
}
}
result
}
pub(super) fn extract_action(mutation_name: &str, type_name: &str) -> String {
let lower_type = type_name.to_lowercase();
let lower_name = mutation_name.to_lowercase();
if let Some(prefix) = lower_name.strip_suffix(&lower_type) {
if !prefix.is_empty() {
return prefix.trim_end_matches('_').replace('_', "-");
}
}
if let Some(suffix) = lower_name.strip_prefix(&lower_type) {
let trimmed = suffix.trim_start_matches('_');
if !trimmed.is_empty() {
return trimmed.replace('_', "-");
}
}
to_snake(mutation_name).replace('_', "-")
}