Skip to main content

oxilean_codegen/graphql_backend/
functions.rs

1//! Auto-generated module
2//!
3//! 🤖 Generated with [SplitRS](https://github.com/cool-japan/splitrs)
4
5use super::types::{
6    GQLBackend, GQLBatchRequest, GQLCacheControl, GQLConnection, GQLDataloader, GQLDeferDirective,
7    GQLDeprecation, GQLDirective, GQLDirectiveLocation, GQLEnumDef, GQLEnumValue, GQLError,
8    GQLFederationExtension, GQLField, GQLFragment, GQLInputField, GQLInputObject, GQLInterface,
9    GQLIntrospectionQuery, GQLLiveQueryExtension, GQLMockDataGenerator, GQLObject, GQLOperation,
10    GQLPersistedQuery, GQLPersistedQueryStore, GQLQueryComplexity, GQLRateLimitDirective,
11    GQLResolverSignature, GQLResponse, GQLScalar, GQLSchema, GQLSchemaBuilder, GQLSchemaComparator,
12    GQLSchemaExtended, GQLSchemaRegistry, GQLSdlPrinter, GQLSelectionField, GQLStreamDirective,
13    GQLType, GQLTypeNameMap, GQLTypeSystemDocument, GQLUnion,
14};
15
16#[cfg(test)]
17mod tests {
18    use super::*;
19    pub(super) fn backend() -> GQLBackend {
20        GQLBackend
21    }
22    pub(super) fn simple_object() -> GQLObject {
23        GQLObject {
24            name: "User".to_string(),
25            fields: vec![
26                GQLField {
27                    name: "id".to_string(),
28                    ty: GQLType::NonNull(Box::new(GQLType::Scalar("ID".to_string()))),
29                    nullable: false,
30                    description: None,
31                    args: vec![],
32                },
33                GQLField {
34                    name: "name".to_string(),
35                    ty: GQLType::Scalar("String".to_string()),
36                    nullable: true,
37                    description: Some("The user's display name.".to_string()),
38                    args: vec![],
39                },
40            ],
41            implements: vec![],
42            description: None,
43        }
44    }
45    #[test]
46    pub(super) fn test_emit_scalar_type() {
47        let b = backend();
48        assert_eq!(b.emit_type(&GQLType::Scalar("Int".to_string())), "Int");
49        assert_eq!(
50            b.emit_type(&GQLType::Scalar("String".to_string())),
51            "String"
52        );
53    }
54    #[test]
55    pub(super) fn test_emit_list_type() {
56        let b = backend();
57        let ty = GQLType::List(Box::new(GQLType::Scalar("String".to_string())));
58        assert_eq!(b.emit_type(&ty), "[String]");
59    }
60    #[test]
61    pub(super) fn test_emit_nonnull_type() {
62        let b = backend();
63        let ty = GQLType::NonNull(Box::new(GQLType::Scalar("ID".to_string())));
64        assert_eq!(b.emit_type(&ty), "ID!");
65    }
66    #[test]
67    pub(super) fn test_emit_nonnull_list_type() {
68        let b = backend();
69        let ty = GQLType::NonNull(Box::new(GQLType::List(Box::new(GQLType::NonNull(
70            Box::new(GQLType::Scalar("Int".to_string())),
71        )))));
72        assert_eq!(b.emit_type(&ty), "[Int!]!");
73    }
74    #[test]
75    pub(super) fn test_emit_field_nonnull() {
76        let b = backend();
77        let field = GQLField {
78            name: "id".to_string(),
79            ty: GQLType::NonNull(Box::new(GQLType::Scalar("ID".to_string()))),
80            nullable: false,
81            description: None,
82            args: vec![],
83        };
84        let out = b.emit_field(&field);
85        assert!(out.contains("id: ID!"), "got: {}", out);
86    }
87    #[test]
88    pub(super) fn test_emit_field_nullable_with_description() {
89        let b = backend();
90        let field = GQLField {
91            name: "bio".to_string(),
92            ty: GQLType::Scalar("String".to_string()),
93            nullable: true,
94            description: Some("Short biography.".to_string()),
95            args: vec![],
96        };
97        let out = b.emit_field(&field);
98        assert!(out.contains("\"\"\"Short biography.\"\"\""));
99        assert!(out.contains("bio: String"));
100    }
101    #[test]
102    pub(super) fn test_emit_object_no_implements() {
103        let b = backend();
104        let obj = simple_object();
105        let out = b.emit_object(&obj);
106        assert!(out.starts_with("type User {"));
107        assert!(out.contains("id: ID!"));
108        assert!(out.contains("name: String"));
109        assert!(out.ends_with('}'));
110    }
111    #[test]
112    pub(super) fn test_emit_object_with_implements() {
113        let b = backend();
114        let obj = GQLObject {
115            name: "Admin".to_string(),
116            fields: vec![GQLField {
117                name: "role".to_string(),
118                ty: GQLType::Scalar("String".to_string()),
119                nullable: true,
120                description: None,
121                args: vec![],
122            }],
123            implements: vec!["Node".to_string(), "Actor".to_string()],
124            description: None,
125        };
126        let out = b.emit_object(&obj);
127        assert!(out.contains("type Admin implements Node & Actor {"));
128    }
129    #[test]
130    pub(super) fn test_emit_enum() {
131        let b = backend();
132        let e = GQLEnumDef {
133            name: "Status".to_string(),
134            values: vec![
135                GQLEnumValue {
136                    name: "ACTIVE".to_string(),
137                    description: None,
138                },
139                GQLEnumValue {
140                    name: "INACTIVE".to_string(),
141                    description: Some("Deactivated account.".to_string()),
142                },
143            ],
144        };
145        let out = b.emit_enum(&e);
146        assert!(out.starts_with("enum Status {"));
147        assert!(out.contains("ACTIVE"));
148        assert!(out.contains("INACTIVE"));
149        assert!(out.contains("\"\"\"Deactivated account.\"\"\""));
150    }
151    #[test]
152    pub(super) fn test_emit_schema_no_mutation() {
153        let b = backend();
154        let schema = GQLSchema {
155            types: vec![simple_object()],
156            query_type: "Query".to_string(),
157            mutation_type: None,
158        };
159        let out = b.emit_schema(&schema);
160        assert!(out.contains("schema {"));
161        assert!(out.contains("query: Query"));
162        assert!(!out.contains("mutation:"));
163        assert!(out.contains("type User {"));
164    }
165    #[test]
166    pub(super) fn test_emit_schema_with_mutation() {
167        let b = backend();
168        let schema = GQLSchema {
169            types: vec![simple_object()],
170            query_type: "Query".to_string(),
171            mutation_type: Some("Mutation".to_string()),
172        };
173        let out = b.emit_schema(&schema);
174        assert!(out.contains("mutation: Mutation"));
175    }
176    #[test]
177    pub(super) fn test_generate_resolver_stubs() {
178        let b = backend();
179        let schema = GQLSchema {
180            types: vec![simple_object()],
181            query_type: "Query".to_string(),
182            mutation_type: None,
183        };
184        let out = b.generate_resolver_stubs(&schema);
185        assert!(out.contains("fn resolve_user_id"));
186        assert!(out.contains("fn resolve_user_name"));
187        assert!(out.contains("todo!()"));
188    }
189    #[test]
190    pub(super) fn test_schema_from_triples() {
191        let b = backend();
192        let schema = b.schema_from_triples(
193            "Query",
194            &[("Query", "users", "String"), ("Query", "version", "String")],
195        );
196        assert_eq!(schema.query_type, "Query");
197        assert_eq!(schema.types.len(), 1);
198        assert_eq!(schema.types[0].name, "Query");
199        assert_eq!(schema.types[0].fields.len(), 2);
200    }
201    #[test]
202    pub(super) fn test_interface_and_union_type_emit() {
203        let b = backend();
204        let iface = GQLType::Interface("Node".to_string());
205        let union_ty = GQLType::Union("SearchResult".to_string());
206        assert_eq!(b.emit_type(&iface), "Node");
207        assert_eq!(b.emit_type(&union_ty), "SearchResult");
208    }
209}
210#[allow(dead_code)]
211pub(super) fn emit_gql_type(ty: &GQLType) -> String {
212    match ty {
213        GQLType::Scalar(s) => s.clone(),
214        GQLType::Object(o) => o.clone(),
215        GQLType::Interface(i) => i.clone(),
216        GQLType::Union(u) => u.clone(),
217        GQLType::Enum(e) => e.clone(),
218        GQLType::List(inner) => format!("[{}]", emit_gql_type(inner)),
219        GQLType::NonNull(inner) => format!("{}!", emit_gql_type(inner)),
220    }
221}
222#[allow(dead_code)]
223pub(super) fn ts_type(ty: &GQLType) -> &str {
224    match ty {
225        GQLType::Scalar(s) if s == "String" => "string",
226        GQLType::Scalar(s) if s == "Int" || s == "Float" => "number",
227        GQLType::Scalar(s) if s == "Boolean" => "boolean",
228        GQLType::Scalar(s) if s == "ID" => "string",
229        GQLType::NonNull(_inner) => "any",
230        GQLType::List(_inner) => "any[]",
231        _ => "any",
232    }
233}
234#[allow(dead_code)]
235pub(super) fn rust_type(ty: &GQLType) -> &str {
236    match ty {
237        GQLType::Scalar(s) if s == "String" || s == "ID" => "String",
238        GQLType::Scalar(s) if s == "Int" => "i64",
239        GQLType::Scalar(s) if s == "Float" => "f64",
240        GQLType::Scalar(s) if s == "Boolean" => "bool",
241        GQLType::NonNull(_) => "Box<dyn std::any::Any>",
242        _ => "serde_json::Value",
243    }
244}
245#[allow(dead_code)]
246pub(super) fn go_type(ty: &GQLType) -> &str {
247    match ty {
248        GQLType::Scalar(s) if s == "String" || s == "ID" => "string",
249        GQLType::Scalar(s) if s == "Int" => "int64",
250        GQLType::Scalar(s) if s == "Float" => "float64",
251        GQLType::Scalar(s) if s == "Boolean" => "bool",
252        _ => "interface{}",
253    }
254}
255#[allow(dead_code)]
256pub(super) fn py_type(ty: &GQLType) -> &str {
257    match ty {
258        GQLType::Scalar(s) if s == "String" || s == "ID" => "str",
259        GQLType::Scalar(s) if s == "Int" => "int",
260        GQLType::Scalar(s) if s == "Float" => "float",
261        GQLType::Scalar(s) if s == "Boolean" => "bool",
262        GQLType::List(_) => "list",
263        _ => "object",
264    }
265}
266#[cfg(test)]
267mod graphql_extended_tests {
268    use super::*;
269    #[test]
270    pub(super) fn test_directive_emit() {
271        let d = GQLDirective::new("auth")
272            .with_location(GQLDirectiveLocation::Field)
273            .with_location(GQLDirectiveLocation::Object);
274        let emitted = d.emit();
275        assert!(emitted.contains("directive @auth"));
276        assert!(emitted.contains("FIELD"));
277    }
278    #[test]
279    pub(super) fn test_union_emit() {
280        let mut u = GQLUnion::new("SearchResult");
281        u.add_member("User");
282        u.add_member("Post");
283        let s = u.emit();
284        assert!(s.contains("union SearchResult = User | Post"));
285    }
286    #[test]
287    pub(super) fn test_connection_type() {
288        let conn = GQLConnection::new("User");
289        let edge = conn.emit_edge_type();
290        let connection = conn.emit_connection_type();
291        assert!(edge.contains("type UserEdge"));
292        assert!(connection.contains("type UserConnection"));
293        assert!(connection.contains("pageInfo: PageInfo!"));
294    }
295    #[test]
296    pub(super) fn test_schema_emit() {
297        let mut schema = GQLSchemaExtended::new();
298        schema.set_query_type("Query");
299        let emitted = schema.emit();
300        assert!(emitted.contains("schema {"));
301        assert!(emitted.contains("query: Query"));
302    }
303    #[test]
304    pub(super) fn test_complexity_calculation() {
305        let limits = GQLQueryComplexity::default_limits();
306        let selections = vec![
307            GQLSelectionField::new("user"),
308            GQLSelectionField::new("posts"),
309        ];
310        let complexity = limits.calculate_selection_complexity(&selections, 0);
311        assert!(complexity >= 2);
312    }
313    #[test]
314    pub(super) fn test_scalar_emit() {
315        let scalar = GQLScalar::new("DateTime");
316        let s = scalar.emit();
317        assert_eq!(s, "scalar DateTime");
318    }
319    #[test]
320    pub(super) fn test_input_object() {
321        let mut inp = GQLInputObject::new("CreateUserInput");
322        inp.add_field(GQLInputField {
323            name: "email".to_string(),
324            ty: GQLType::NonNull(Box::new(GQLType::Scalar("String".to_string()))),
325            default_value: None,
326            description: None,
327            directives: Vec::new(),
328        });
329        let s = inp.emit();
330        assert!(s.contains("input CreateUserInput"));
331        assert!(s.contains("email:"));
332    }
333    #[test]
334    pub(super) fn test_operation_emit() {
335        let op = GQLOperation::query("GetUser");
336        let s = op.emit();
337        assert!(s.contains("query GetUser"));
338    }
339    #[test]
340    pub(super) fn test_registry() {
341        let mut registry = GQLSchemaRegistry::new();
342        registry.register("v1", GQLSchemaExtended::new());
343        assert!(registry.get("v1").is_some());
344        assert_eq!(registry.list_names().len(), 1);
345    }
346    #[test]
347    pub(super) fn test_deprecation() {
348        let dep = GQLDeprecation::new("oldField", "Use newField instead");
349        let d = dep.emit_directive();
350        assert!(d.contains("@deprecated"));
351        assert!(d.contains("Use newField instead"));
352    }
353    #[test]
354    pub(super) fn test_mock_generator() {
355        let mut gen = GQLMockDataGenerator::new(42);
356        let s = gen.generate_for_type(&GQLType::Scalar("String".to_string()));
357        assert!(s.contains("mock_string"));
358        let i = gen.generate_for_type(&GQLType::Scalar("Int".to_string()));
359        assert!(!i.is_empty());
360    }
361}
362#[cfg(test)]
363mod graphql_introspection_tests {
364    use super::*;
365    #[test]
366    pub(super) fn test_schema_builder() {
367        let schema = GQLSchemaBuilder::new()
368            .scalar(GQLScalar::new("DateTime"))
369            .query_type("Query")
370            .build();
371        assert_eq!(schema.scalars.len(), 1);
372        assert_eq!(schema.query_type, Some("Query".to_string()));
373    }
374    #[test]
375    pub(super) fn test_error_json() {
376        let err = GQLError::new("Not found").with_location(1, 5);
377        let json = err.emit_json();
378        assert!(json.contains("Not found"));
379        assert!(json.contains("\"line\":1"));
380    }
381    #[test]
382    pub(super) fn test_response_success() {
383        let r = GQLResponse::success("{\"user\":{\"id\":\"1\"}}");
384        assert!(r.is_success());
385    }
386    #[test]
387    pub(super) fn test_cache_control() {
388        let cc = GQLCacheControl::public(300);
389        let d = cc.emit_directive();
390        assert!(d.contains("maxAge: 300"));
391        assert!(d.contains("PUBLIC"));
392    }
393    #[test]
394    pub(super) fn test_federation_extension() {
395        let mut fed = GQLFederationExtension::new("products");
396        fed.add_key("id");
397        let dirs = fed.emit_key_directives();
398        assert!(dirs.contains("@key(fields: \"id\")"));
399    }
400    #[test]
401    pub(super) fn test_batch_request() {
402        let mut batch = GQLBatchRequest::new(3);
403        assert!(batch.add(GQLOperation::query("Q1")));
404        assert!(batch.add(GQLOperation::query("Q2")));
405        assert!(batch.add(GQLOperation::query("Q3")));
406        assert!(!batch.add(GQLOperation::query("Q4")));
407        assert_eq!(batch.operations.len(), 3);
408    }
409    #[test]
410    pub(super) fn test_dataloader_ts_emit() {
411        let loader = GQLDataloader::new("User");
412        let ts = loader.emit_ts_loader();
413        assert!(ts.contains("DataLoader"));
414        assert!(ts.contains("maxBatchSize: 100"));
415    }
416    #[test]
417    pub(super) fn test_rate_limit_directive() {
418        let rl = GQLRateLimitDirective::new(100, 60);
419        let emitted = rl.emit();
420        assert!(emitted.contains("@rateLimit"));
421        assert!(emitted.contains("limit: 100"));
422    }
423    #[test]
424    pub(super) fn test_type_system_document() {
425        let mut doc = GQLTypeSystemDocument::new();
426        doc.extend_type("Query", &["health: Boolean!"]);
427        let emitted = doc.emit();
428        assert!(emitted.contains("extend type Query"));
429        assert!(emitted.contains("health: Boolean!"));
430    }
431    #[test]
432    pub(super) fn test_introspection_query() {
433        let q = GQLIntrospectionQuery::full_introspection_query();
434        assert!(q.contains("__schema"));
435    }
436    #[test]
437    pub(super) fn test_live_query_extension() {
438        let mut lq = GQLLiveQueryExtension::new(500);
439        lq.add_key("user:1");
440        assert_eq!(lq.invalidation_keys.len(), 1);
441        let header = lq.emit_extension_header();
442        assert!(header.contains("@live"));
443    }
444    #[test]
445    pub(super) fn test_resolver_signature() {
446        let sig = GQLResolverSignature::new(
447            "User",
448            "posts",
449            GQLType::List(Box::new(GQLType::Object("Post".to_string()))),
450        );
451        let ts = sig.emit_ts_signature();
452        assert!(ts.contains("posts"));
453        assert!(ts.contains("async"));
454    }
455    #[test]
456    pub(super) fn test_interface_emit() {
457        let mut iface = GQLInterface::new("Node");
458        iface.add_field(GQLField {
459            name: "id".to_string(),
460            ty: GQLType::NonNull(Box::new(GQLType::Scalar("ID".to_string()))),
461            nullable: false,
462            description: None,
463            args: Vec::new(),
464        });
465        let s = iface.emit();
466        assert!(s.contains("interface Node"));
467        assert!(s.contains("id:"));
468    }
469    #[test]
470    pub(super) fn test_fragment_emit() {
471        let frag = GQLFragment::new("UserFields", "User");
472        let s = frag.emit();
473        assert!(s.contains("fragment UserFields on User"));
474    }
475}
476#[cfg(test)]
477mod graphql_advanced_tests {
478    use super::*;
479    #[test]
480    pub(super) fn test_persisted_query() {
481        let pq = GQLPersistedQuery::new("{ user { id name } }");
482        assert!(!pq.hash.is_empty());
483        let ext = pq.emit_apq_extension();
484        assert!(ext.contains("persistedQuery"));
485        assert!(ext.contains("sha256Hash"));
486    }
487    #[test]
488    pub(super) fn test_persisted_query_store() {
489        let mut store = GQLPersistedQueryStore::new();
490        let pq = GQLPersistedQuery::new("{ user { id } }");
491        let hash = pq.hash.clone();
492        store.register(pq);
493        assert_eq!(store.count(), 1);
494        assert!(store.lookup(&hash).is_some());
495    }
496    #[test]
497    pub(super) fn test_defer_directive() {
498        let defer = GQLDeferDirective::new().with_label("profile");
499        let s = defer.emit();
500        assert!(s.contains("@defer"));
501        assert!(s.contains("label: \"profile\""));
502    }
503    #[test]
504    pub(super) fn test_stream_directive() {
505        let stream = GQLStreamDirective::new(2);
506        let s = stream.emit();
507        assert!(s.contains("@stream"));
508        assert!(s.contains("initialCount: 2"));
509    }
510    #[test]
511    pub(super) fn test_schema_comparator_added() {
512        let mut old = GQLSchemaExtended::new();
513        let mut new_schema = GQLSchemaExtended::new();
514        new_schema.objects.push(GQLObject {
515            name: "User".to_string(),
516            fields: Vec::new(),
517            description: None,
518            implements: Vec::new(),
519        });
520        let cmp = GQLSchemaComparator::new(old, new_schema);
521        assert_eq!(cmp.added_types(), vec!["User".to_string()]);
522        assert!(!cmp.is_breaking_change());
523    }
524    #[test]
525    pub(super) fn test_schema_comparator_removed() {
526        let mut old = GQLSchemaExtended::new();
527        old.objects.push(GQLObject {
528            name: "User".to_string(),
529            fields: Vec::new(),
530            description: None,
531            implements: Vec::new(),
532        });
533        let new_schema = GQLSchemaExtended::new();
534        let cmp = GQLSchemaComparator::new(old, new_schema);
535        assert_eq!(cmp.removed_types(), vec!["User".to_string()]);
536        assert!(cmp.is_breaking_change());
537    }
538    #[test]
539    pub(super) fn test_schema_comparator_changelog() {
540        let mut old = GQLSchemaExtended::new();
541        let mut new_schema = GQLSchemaExtended::new();
542        old.objects.push(GQLObject {
543            name: "Deleted".to_string(),
544            fields: Vec::new(),
545            description: None,
546            implements: Vec::new(),
547        });
548        new_schema.objects.push(GQLObject {
549            name: "Added".to_string(),
550            fields: Vec::new(),
551            description: None,
552            implements: Vec::new(),
553        });
554        let cmp = GQLSchemaComparator::new(old, new_schema);
555        let log = cmp.generate_changelog();
556        assert!(log.contains("+ Added type: Added"));
557        assert!(log.contains("- Removed type: Deleted"));
558    }
559}
560#[cfg(test)]
561mod graphql_sdl_tests {
562    use super::*;
563    #[test]
564    pub(super) fn test_sdl_printer_object() {
565        let obj = GQLObject {
566            name: "User".to_string(),
567            fields: vec![GQLField {
568                name: "id".to_string(),
569                ty: GQLType::Scalar("ID".to_string()),
570                nullable: false,
571                description: None,
572                args: Vec::new(),
573            }],
574            description: None,
575            implements: Vec::new(),
576        };
577        let printer = GQLSdlPrinter::new();
578        let s = printer.print_object(&obj);
579        assert!(s.contains("type User {"));
580        assert!(s.contains("id:"));
581    }
582    #[test]
583    pub(super) fn test_type_name_map() {
584        let map = GQLTypeNameMap::new();
585        assert_eq!(map.lookup("Int"), Some(&"i32".to_string()));
586        assert_eq!(map.lookup("Boolean"), Some(&"bool".to_string()));
587        assert!(map.lookup("Unknown").is_none());
588    }
589    #[test]
590    pub(super) fn test_sdl_printer_schema() {
591        let mut schema = GQLSchemaExtended::new();
592        schema.scalars.push(GQLScalar::new("Date"));
593        schema.objects.push(GQLObject {
594            name: "Post".to_string(),
595            fields: vec![GQLField {
596                name: "title".to_string(),
597                ty: GQLType::Scalar("String".to_string()),
598                nullable: true,
599                description: None,
600                args: Vec::new(),
601            }],
602            description: None,
603            implements: Vec::new(),
604        });
605        let printer = GQLSdlPrinter::new();
606        let s = printer.print_schema(&schema);
607        assert!(s.contains("scalar Date"));
608        assert!(s.contains("type Post"));
609    }
610}
611#[allow(dead_code)]
612pub fn gql_type_name(ty: &GQLType) -> String {
613    match ty {
614        GQLType::Scalar(s)
615        | GQLType::Object(s)
616        | GQLType::Interface(s)
617        | GQLType::Union(s)
618        | GQLType::Enum(s) => s.clone(),
619        GQLType::List(inner) | GQLType::NonNull(inner) => gql_type_name(inner),
620    }
621}
622#[allow(dead_code)]
623pub fn is_builtin_scalar(name: &str) -> bool {
624    matches!(name, "Int" | "Float" | "String" | "Boolean" | "ID")
625}