Skip to main content

oxihuman_export/
graphql_export.rs

1// Copyright (C) 2026 COOLJAPAN OU (Team KitaSan)
2// SPDX-License-Identifier: Apache-2.0
3#![allow(dead_code)]
4
5//! GraphQL query/mutation text export.
6
7/// GraphQL operation type.
8#[allow(dead_code)]
9#[derive(Debug, Clone, Copy, PartialEq, Eq)]
10pub enum GqlOpType {
11    Query,
12    Mutation,
13    Subscription,
14}
15
16impl GqlOpType {
17    fn as_str(self) -> &'static str {
18        match self {
19            GqlOpType::Query => "query",
20            GqlOpType::Mutation => "mutation",
21            GqlOpType::Subscription => "subscription",
22        }
23    }
24}
25
26/// A GraphQL variable definition.
27#[allow(dead_code)]
28#[derive(Debug, Clone)]
29pub struct GqlVar {
30    pub name: String,
31    pub gql_type: String,
32}
33
34/// A GraphQL operation stub.
35#[allow(dead_code)]
36#[derive(Debug, Clone)]
37pub struct GqlOperation {
38    pub op_type: GqlOpType,
39    pub name: String,
40    pub variables: Vec<GqlVar>,
41    pub selection: String,
42}
43
44/// Build a new GraphQL query.
45#[allow(dead_code)]
46pub fn new_query(name: &str, selection: &str) -> GqlOperation {
47    GqlOperation {
48        op_type: GqlOpType::Query,
49        name: name.to_string(),
50        variables: Vec::new(),
51        selection: selection.to_string(),
52    }
53}
54
55/// Build a new GraphQL mutation.
56#[allow(dead_code)]
57pub fn new_mutation(name: &str, selection: &str) -> GqlOperation {
58    GqlOperation {
59        op_type: GqlOpType::Mutation,
60        name: name.to_string(),
61        variables: Vec::new(),
62        selection: selection.to_string(),
63    }
64}
65
66/// Add a variable to an operation.
67#[allow(dead_code)]
68pub fn add_variable(op: &mut GqlOperation, name: &str, gql_type: &str) {
69    op.variables.push(GqlVar {
70        name: name.to_string(),
71        gql_type: gql_type.to_string(),
72    });
73}
74
75/// Serialize a GraphQL operation to text.
76#[allow(dead_code)]
77pub fn serialize_gql(op: &GqlOperation) -> String {
78    let vars = if op.variables.is_empty() {
79        String::new()
80    } else {
81        let parts: Vec<String> = op
82            .variables
83            .iter()
84            .map(|v| format!("${}: {}", v.name, v.gql_type))
85            .collect();
86        format!("({})", parts.join(", "))
87    };
88    format!(
89        "{} {}{} {{\n  {}\n}}",
90        op.op_type.as_str(),
91        op.name,
92        vars,
93        op.selection
94    )
95}
96
97/// Variable count.
98#[allow(dead_code)]
99pub fn var_count(op: &GqlOperation) -> usize {
100    op.variables.len()
101}
102
103#[cfg(test)]
104mod tests {
105    use super::*;
106
107    #[test]
108    fn query_op_type() {
109        let op = new_query("GetUser", "id name");
110        assert_eq!(op.op_type, GqlOpType::Query);
111    }
112
113    #[test]
114    fn mutation_op_type() {
115        let op = new_mutation("CreateUser", "id");
116        assert_eq!(op.op_type, GqlOpType::Mutation);
117    }
118
119    #[test]
120    fn serialize_contains_query_keyword() {
121        let op = new_query("GetUser", "id name");
122        let s = serialize_gql(&op);
123        assert!(s.starts_with("query"));
124    }
125
126    #[test]
127    fn serialize_contains_name() {
128        let op = new_query("GetUser", "id name");
129        let s = serialize_gql(&op);
130        assert!(s.contains("GetUser"));
131    }
132
133    #[test]
134    fn serialize_contains_selection() {
135        let op = new_query("X", "id name email");
136        let s = serialize_gql(&op);
137        assert!(s.contains("id name email"));
138    }
139
140    #[test]
141    fn add_variable_increases_count() {
142        let mut op = new_query("X", "id");
143        add_variable(&mut op, "userId", "ID!");
144        assert_eq!(var_count(&op), 1);
145    }
146
147    #[test]
148    fn variable_in_output() {
149        let mut op = new_query("GetUser", "id");
150        add_variable(&mut op, "userId", "ID!");
151        let s = serialize_gql(&op);
152        assert!(s.contains("$userId: ID!"));
153    }
154
155    #[test]
156    fn no_vars_no_parens() {
157        let op = new_query("X", "id");
158        let s = serialize_gql(&op);
159        assert!(!s.contains('('));
160    }
161
162    #[test]
163    fn mutation_keyword_in_output() {
164        let op = new_mutation("CreateUser", "id");
165        let s = serialize_gql(&op);
166        assert!(s.starts_with("mutation"));
167    }
168
169    #[test]
170    fn subscription_keyword() {
171        let op = GqlOperation {
172            op_type: GqlOpType::Subscription,
173            name: "OnUpdate".to_string(),
174            variables: Vec::new(),
175            selection: "id".to_string(),
176        };
177        assert!(serialize_gql(&op).starts_with("subscription"));
178    }
179
180    #[test]
181    fn braces_in_output() {
182        let op = new_query("X", "id");
183        let s = serialize_gql(&op);
184        assert!(s.contains('{') && s.contains('}'));
185    }
186}