use std::collections::HashMap;
use indexmap::IndexMap;
use serde::{Deserialize, Serialize};
use super::argument::{ArgumentDefinition, AutoParams};
use crate::schema::{
field_type::DeprecationInfo, graphql_type_defs::default_jsonb_column,
security_config::InjectedParamSource,
};
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Default)]
#[serde(rename_all = "snake_case")]
#[non_exhaustive]
pub enum CursorType {
#[default]
Int64,
Uuid,
}
pub(super) fn is_default_cursor_type(ct: &CursorType) -> bool {
*ct == CursorType::Int64
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct QueryDefinition {
pub name: String,
pub return_type: String,
#[serde(default)]
pub returns_list: bool,
#[serde(default)]
pub nullable: bool,
#[serde(default)]
pub arguments: Vec<ArgumentDefinition>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub sql_source: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub description: Option<String>,
#[serde(default)]
pub auto_params: AutoParams,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub deprecation: Option<DeprecationInfo>,
#[serde(default = "default_jsonb_column")]
pub jsonb_column: String,
#[serde(default, skip_serializing_if = "std::ops::Not::not")]
pub relay: bool,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub relay_cursor_column: Option<String>,
#[serde(default, skip_serializing_if = "is_default_cursor_type")]
pub relay_cursor_type: CursorType,
#[serde(default, skip_serializing_if = "IndexMap::is_empty")]
pub inject_params: IndexMap<String, InjectedParamSource>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub cache_ttl_seconds: Option<u64>,
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub additional_views: Vec<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub requires_role: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub rest_path: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub rest_method: Option<String>,
#[serde(default, skip_serializing_if = "HashMap::is_empty")]
pub native_columns: HashMap<String, String>,
}
impl QueryDefinition {
#[must_use]
pub fn new(name: impl Into<String>, return_type: impl Into<String>) -> Self {
Self {
name: name.into(),
return_type: return_type.into(),
returns_list: false,
nullable: false,
arguments: Vec::new(),
sql_source: None,
description: None,
auto_params: AutoParams::default(),
deprecation: None,
jsonb_column: "data".to_string(),
relay: false,
relay_cursor_column: None,
relay_cursor_type: CursorType::Int64,
inject_params: IndexMap::new(),
cache_ttl_seconds: None,
additional_views: Vec::new(),
requires_role: None,
rest_path: None,
rest_method: None,
native_columns: HashMap::new(),
}
}
#[must_use]
pub const fn returning_list(mut self) -> Self {
self.returns_list = true;
self
}
#[must_use]
pub fn with_sql_source(mut self, source: impl Into<String>) -> Self {
self.sql_source = Some(source.into());
self
}
#[must_use]
pub fn deprecated(mut self, reason: Option<String>) -> Self {
self.deprecation = Some(DeprecationInfo { reason });
self
}
#[must_use]
pub const fn is_deprecated(&self) -> bool {
self.deprecation.is_some()
}
#[must_use]
pub fn deprecation_reason(&self) -> Option<&str> {
self.deprecation.as_ref().and_then(|d| d.reason.as_deref())
}
}
impl Default for QueryDefinition {
fn default() -> Self {
Self::new("", "")
}
}