Skip to main content

oxirs_gql/
lib.rs

1//! # OxiRS GraphQL - GraphQL Interface for RDF
2//!
3//! [![Version](https://img.shields.io/badge/version-0.2.4-blue)](https://github.com/cool-japan/oxirs/releases)
4//! [![docs.rs](https://docs.rs/oxirs-gql/badge.svg)](https://docs.rs/oxirs-gql)
5//!
6//! **Status**: Production Release (v0.2.4)
7//! **Stability**: Public APIs are stable. Production-ready with comprehensive testing.
8//!
9//! GraphQL interface for RDF data with automatic schema generation from ontologies.
10//! Enables modern GraphQL clients to query knowledge graphs with intuitive GraphQL syntax.
11//!
12//! ## Features
13//!
14//! - **Automatic Schema Generation** - Generate GraphQL schemas from RDF vocabularies
15//! - **GraphQL to SPARQL** - Transparent translation of GraphQL queries to SPARQL
16//! - **Type Mapping** - Map RDF classes to GraphQL types
17//! - **Query Support** - Full GraphQL query capabilities
18//! - **Subscriptions** - WebSocket-based subscriptions (experimental)
19//!
20//! ## See Also
21//!
22//! - [`oxirs-core`](https://docs.rs/oxirs-core) - RDF data model
23//! - [`oxirs-arq`](https://docs.rs/oxirs-arq) - SPARQL query engine
24
25use anyhow::Result;
26use oxirs_core::model::{
27    BlankNode, GraphName, Literal as OxiLiteral, NamedNode, Quad, Subject, Term, Variable,
28};
29use oxirs_core::ConcreteStore;
30use std::sync::{Arc, Mutex};
31
32// Re-export QueryResults for other modules
33pub use oxirs_core::query::QueryResults;
34
35// Module declarations are below after the main code
36
37/// RDF store wrapper for GraphQL integration
38pub struct RdfStore {
39    store: Arc<Mutex<ConcreteStore>>,
40}
41
42impl std::fmt::Debug for RdfStore {
43    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
44        f.debug_struct("RdfStore")
45            .field("store", &"Store { ... }")
46            .finish()
47    }
48}
49
50impl RdfStore {
51    pub fn new() -> Result<Self> {
52        Ok(Self {
53            store: Arc::new(Mutex::new(ConcreteStore::new()?)),
54        })
55    }
56
57    pub fn open<P: AsRef<std::path::Path>>(path: P) -> Result<Self> {
58        Ok(Self {
59            store: Arc::new(Mutex::new(ConcreteStore::open(path)?)),
60        })
61    }
62
63    /// Execute a SPARQL query and return results
64    pub fn query(&self, query: &str) -> Result<QueryResults> {
65        use oxirs_core::query::{QueryEngine, QueryResult};
66
67        let store = self
68            .store
69            .lock()
70            .map_err(|e| anyhow::anyhow!("Mutex lock error: {}", e))?;
71        let engine = QueryEngine::new();
72        let result = engine
73            .query(query, &*store)
74            .map_err(|e| anyhow::anyhow!("SPARQL query error: {}", e))?;
75
76        match result {
77            QueryResult::Select {
78                variables: _,
79                bindings,
80            } => {
81                let mut solutions = Vec::new();
82                for binding in bindings {
83                    let mut solution = oxirs_core::query::Solution::new();
84                    for (var_name, term) in binding {
85                        if let Ok(var) = oxirs_core::model::Variable::new(&var_name) {
86                            solution.bind(var, term);
87                        }
88                    }
89                    solutions.push(solution);
90                }
91                Ok(QueryResults::Solutions(solutions))
92            }
93            QueryResult::Ask(result) => Ok(QueryResults::Boolean(result)),
94            QueryResult::Construct(triples) => {
95                // Return triples directly (not quads)
96                Ok(QueryResults::Graph(triples))
97            }
98        }
99    }
100
101    /// Get count of triples in the store
102    pub fn triple_count(&self) -> Result<usize> {
103        let query = "SELECT (COUNT(*) as ?count) WHERE { ?s ?p ?o }";
104        if let QueryResults::Solutions(solutions) = self.query(query)? {
105            if let Some(solution) = solutions.first() {
106                let count_var = Variable::new("count")
107                    .map_err(|e| anyhow::anyhow!("Failed to create count variable: {}", e))?;
108                if let Some(Term::Literal(lit)) = solution.get(&count_var) {
109                    let count = lit.value().parse::<usize>().map_err(|e| {
110                        anyhow::anyhow!("Failed to parse count value '{}': {}", lit.value(), e)
111                    })?;
112                    return Ok(count);
113                }
114            }
115        }
116        Ok(0)
117    }
118
119    /// Get subjects with optional limit
120    pub fn get_subjects(&self, limit: Option<usize>) -> Result<Vec<String>> {
121        let limit_clause = match limit {
122            Some(l) => format!(" LIMIT {l}"),
123            None => String::new(),
124        };
125
126        let query = format!("SELECT DISTINCT ?s WHERE {{ ?s ?p ?o }}{limit_clause}");
127        let mut subjects = Vec::new();
128
129        let subject_var = Variable::new("s")
130            .map_err(|e| anyhow::anyhow!("Failed to create subject variable: {}", e))?;
131
132        if let QueryResults::Solutions(solutions) = self.query(&query)? {
133            for solution in &solutions {
134                if let Some(subject) = solution.get(&subject_var) {
135                    subjects.push(subject.to_string());
136                }
137            }
138        }
139
140        Ok(subjects)
141    }
142
143    /// Get predicates with optional limit
144    pub fn get_predicates(&self, limit: Option<usize>) -> Result<Vec<String>> {
145        let limit_clause = match limit {
146            Some(l) => format!(" LIMIT {l}"),
147            None => String::new(),
148        };
149
150        let query = format!("SELECT DISTINCT ?p WHERE {{ ?s ?p ?o }}{limit_clause}");
151        let mut predicates = Vec::new();
152
153        let predicate_var = Variable::new("p")
154            .map_err(|e| anyhow::anyhow!("Failed to create predicate variable: {}", e))?;
155
156        if let QueryResults::Solutions(solutions) = self.query(&query)? {
157            for solution in &solutions {
158                if let Some(predicate) = solution.get(&predicate_var) {
159                    predicates.push(predicate.to_string());
160                }
161            }
162        }
163
164        Ok(predicates)
165    }
166
167    /// Get objects with optional limit
168    pub fn get_objects(&self, limit: Option<usize>) -> Result<Vec<(String, String)>> {
169        let limit_clause = match limit {
170            Some(l) => format!(" LIMIT {l}"),
171            None => String::new(),
172        };
173
174        let query = format!("SELECT DISTINCT ?o WHERE {{ ?s ?p ?o }}{limit_clause}");
175        let mut objects = Vec::new();
176
177        let object_var = Variable::new("o")
178            .map_err(|e| anyhow::anyhow!("Failed to create object variable: {}", e))?;
179
180        if let QueryResults::Solutions(solutions) = self.query(&query)? {
181            for solution in &solutions {
182                if let Some(object) = solution.get(&object_var) {
183                    let object_type = match object {
184                        Term::NamedNode(_) => "IRI".to_string(),
185                        Term::BlankNode(_) => "BlankNode".to_string(),
186                        Term::Literal(_) => "Literal".to_string(),
187                        Term::Variable(_) => "Variable".to_string(),
188                        Term::QuotedTriple(_) => "QuotedTriple".to_string(),
189                    };
190                    objects.push((object.to_string(), object_type));
191                }
192            }
193        }
194
195        Ok(objects)
196    }
197
198    /// Insert a triple into the store
199    pub fn insert_triple(&mut self, subject: &str, predicate: &str, object: &str) -> Result<()> {
200        // Parse terms
201        let subject = if let Some(stripped) = subject.strip_prefix("_:") {
202            Subject::BlankNode(BlankNode::new(stripped)?)
203        } else {
204            Subject::NamedNode(NamedNode::new(subject)?)
205        };
206
207        let predicate = NamedNode::new(predicate)?;
208
209        let object = if object.starts_with("\"") && object.ends_with("\"") {
210            // It's a literal
211            let literal_value = &object[1..object.len() - 1];
212            Term::Literal(OxiLiteral::new_simple_literal(literal_value))
213        } else if let Some(stripped) = object.strip_prefix("_:") {
214            // It's a blank node
215            Term::BlankNode(BlankNode::new(stripped)?)
216        } else {
217            // It's a named node
218            Term::NamedNode(NamedNode::new(object)?)
219        };
220
221        let quad = Quad::new(subject, predicate, object, GraphName::DefaultGraph);
222        let store = self
223            .store
224            .lock()
225            .map_err(|e| anyhow::anyhow!("Mutex lock error: {}", e))?;
226        store.insert_quad(quad)?;
227        Ok(())
228    }
229
230    /// Insert a quad into the store
231    pub fn insert(&self, quad: &oxirs_core::model::Quad) -> Result<()> {
232        let store = self
233            .store
234            .lock()
235            .map_err(|e| anyhow::anyhow!("Mutex lock error: {}", e))?;
236        store.insert_quad(quad.clone())?;
237        Ok(())
238    }
239
240    /// Load data from a file
241    pub fn load_file<P: AsRef<std::path::Path>>(&mut self, path: P, format: &str) -> Result<()> {
242        use oxirs_core::parser::{Parser, RdfFormat};
243        use std::fs;
244
245        let format = match format.to_lowercase().as_str() {
246            "turtle" | "ttl" => RdfFormat::Turtle,
247            "ntriples" | "nt" => RdfFormat::NTriples,
248            "rdfxml" | "rdf" => RdfFormat::RdfXml,
249            "jsonld" | "json" => RdfFormat::JsonLd,
250            _ => return Err(anyhow::anyhow!("Unsupported format: {}", format)),
251        };
252
253        // Read file content
254        let content = fs::read_to_string(path)?;
255
256        // Parse content to quads
257        let parser = Parser::new(format);
258        let quads = parser.parse_str_to_quads(&content)?;
259
260        // Insert quads into store
261        let store = self
262            .store
263            .lock()
264            .map_err(|e| anyhow::anyhow!("Mutex lock error: {}", e))?;
265        for quad in quads {
266            store.insert_quad(quad)?;
267        }
268
269        Ok(())
270    }
271}
272
273/// Mock store for testing GraphQL functionality
274#[derive(Debug)]
275pub struct MockStore;
276
277impl MockStore {
278    pub fn new() -> Result<Self> {
279        Ok(Self)
280    }
281
282    pub fn open(_path: String) -> Result<Self> {
283        Ok(Self)
284    }
285}
286
287// Individual modules
288pub mod aggregation;
289pub mod ai;
290pub mod api_explorer;
291pub mod ast;
292pub mod auto_caching_strategies;
293pub mod custom_directives;
294pub mod custom_type_mappings;
295pub mod directive_registry;
296pub mod enhanced_errors;
297pub mod execution;
298pub mod federation;
299pub mod file_upload;
300pub mod graphiql_integration;
301pub mod historical_cost_estimator;
302pub mod horizontal_scaling;
303pub mod hybrid_optimizer;
304pub mod intelligent_federation_gateway;
305pub mod intelligent_query_cache;
306pub mod introspection;
307pub mod live_queries;
308pub mod mapping;
309pub mod ml_optimizer;
310pub mod optimizer;
311pub mod owl_enhanced_schema;
312pub mod pagination_filtering;
313pub mod parallel_field_resolver;
314pub mod parser;
315pub mod persisted_queries;
316pub mod playground_integration;
317pub mod quantum_optimizer;
318pub mod query_builder;
319pub mod query_debugger;
320pub mod query_prefetcher;
321pub mod rate_limiting;
322pub mod rdf_scalars;
323pub mod request_deduplication;
324pub mod resolvers;
325pub mod schema;
326pub mod schema_cache;
327pub mod schema_docs_generator;
328pub mod server;
329pub mod sse_subscriptions;
330pub mod subscriptions;
331pub mod types;
332pub mod validation;
333pub mod zero_trust_security;
334
335// v0.2.0 Operational Enhancements
336pub mod api_versioning;
337pub mod blue_green_deployment;
338pub mod canary_release;
339pub mod circuit_breaker;
340pub mod graphql_mesh;
341pub mod multi_region;
342pub mod performance_insights;
343pub mod schema_changelog;
344pub mod visual_schema_designer;
345
346// v0.3.0 Security & Integration Features
347pub mod content_security_policy;
348pub mod edge_caching;
349pub mod query_sanitization;
350pub mod response_streaming;
351pub mod webhook_support;
352
353// v0.4.0 Advanced Observability & Protocol Features
354pub mod cost_based_optimizer;
355pub mod incremental_execution;
356pub mod query_batching;
357pub mod query_plan_visualizer;
358pub mod query_result_streaming;
359
360// v0.5.0 Advanced Observability & Monitoring
361pub mod graphql_span_attributes;
362pub mod performance_anomaly_detector;
363pub mod performance_heatmap;
364pub mod query_pattern_analyzer;
365pub mod trace_correlation;
366pub mod trace_sampling;
367pub mod trace_visualization;
368pub mod tracing_exporters;
369
370// Advanced performance modules
371pub mod advanced_cache;
372pub mod advanced_security_system;
373pub mod ai_query_predictor;
374pub mod async_streaming;
375pub mod benchmarking;
376pub mod dataloader;
377pub mod neuromorphic_query_processor;
378pub mod performance;
379pub mod predictive_analytics;
380pub mod quantum_real_time_analytics;
381pub mod system_monitor;
382
383// Ultra-modern enterprise modules (July 5, 2025 enhancements)
384pub mod advanced_query_planner;
385pub mod advanced_subscriptions;
386pub mod ai_orchestration_engine;
387pub mod observability;
388
389// Production-ready features (November 2025)
390pub mod production;
391
392// v0.6.0 Enhanced Subscriptions, Multi-tenancy, and Query Caching
393pub mod cache;
394pub mod multitenancy;
395pub mod subscription;
396// v1.1.0 Enhanced tenant module with schema registry, query filter, rate limiter
397pub mod tenant;
398// v1.1.0 Apollo Federation v2 Subgraph Support
399pub mod federation_v2;
400
401// v1.2.0 GraphQL Schema Version Registry
402pub mod schema_registry;
403
404// v1.1.0 Relay Cursor-based Pagination
405pub mod cursor_pagination;
406
407// v1.2.0 GraphQL subscription lifecycle management
408pub mod subscription_manager;
409
410// v1.2.0 DataLoader / batch resolver for GraphQL N+1 resolution
411pub mod batch_resolver;
412
413// v1.5.0 GraphQL __schema / __type introspection engine
414pub mod type_introspection;
415
416// Organized module groups
417pub mod core;
418pub mod distributed_cache;
419pub mod docs;
420pub mod dynamic_query_planner;
421pub mod features;
422pub mod networking;
423pub mod rdf;
424
425// v1.6.0 Field-level resolver pipeline with middleware
426pub mod field_resolver;
427
428// v1.7.0 GraphQL query complexity analysis and limiting
429pub mod query_complexity;
430
431// v1.8.0 GraphQL error formatting, classification, and aggregation
432pub mod error_formatter;
433
434// v1.9.0 Custom GraphQL directive processing engine
435pub mod directive_processor;
436
437// v1.10.0 GraphQL pagination handler (Relay cursor spec)
438pub mod pagination_handler;
439
440// v1.11.0 GraphQL field-level validation rules engine
441pub mod field_validator;
442
443// v1.1.0 round 16 GraphQL enum type resolution and coercion
444pub mod enum_resolver;
445
446// v1.1.0 round 15 GraphQL argument type coercion and validation
447pub mod argument_coercer;
448
449// Juniper-based implementation with proper RDF integration (enabled)
450pub mod juniper_schema;
451pub mod juniper_server; // Complex Hyper v1 version - API issues fixed
452pub mod simple_juniper_server; // Simplified version
453
454// Juniper integration - comprehensive RDF GraphQL support
455pub use juniper_schema::{create_schema, GraphQLContext, Schema as JuniperSchema};
456pub use simple_juniper_server::{
457    start_graphql_server, start_graphql_server_with_config, GraphQLServerBuilder,
458    GraphQLServerConfig, JuniperGraphQLServer,
459};
460
461// Intelligent query caching
462pub use intelligent_query_cache::{
463    IntelligentCacheConfig, IntelligentQueryCache, QueryPattern, QueryUsageStats,
464};
465
466// Advanced Juniper server with full Hyper v1 support
467pub use juniper_server::{
468    start_graphql_server as start_advanced_graphql_server,
469    start_graphql_server_with_config as start_advanced_graphql_server_with_config,
470    GraphQLServerBuilder as AdvancedGraphQLServerBuilder,
471    GraphQLServerConfig as AdvancedGraphQLServerConfig,
472    JuniperGraphQLServer as AdvancedJuniperGraphQLServer,
473};
474
475#[cfg(test)]
476mod tests;
477
478/// GraphQL server configuration
479#[derive(Debug, Clone)]
480pub struct GraphQLConfig {
481    pub enable_introspection: bool,
482    pub enable_playground: bool,
483    pub max_query_depth: Option<usize>,
484    pub max_query_complexity: Option<usize>,
485    pub validation_config: validation::ValidationConfig,
486    pub enable_query_validation: bool,
487    pub distributed_cache_config: Option<distributed_cache::CacheConfig>,
488}
489
490impl Default for GraphQLConfig {
491    fn default() -> Self {
492        Self {
493            enable_introspection: true,
494            enable_playground: true,
495            max_query_depth: Some(10),
496            max_query_complexity: Some(1000),
497            validation_config: validation::ValidationConfig::default(),
498            enable_query_validation: true,
499            distributed_cache_config: None, // Disabled by default
500        }
501    }
502}
503
504/// Main GraphQL server
505pub struct GraphQLServer {
506    config: GraphQLConfig,
507    store: Arc<RdfStore>,
508    cache: Option<Arc<distributed_cache::GraphQLQueryCache>>,
509}
510
511impl GraphQLServer {
512    pub fn new(store: Arc<RdfStore>) -> Self {
513        Self {
514            config: GraphQLConfig::default(),
515            store,
516            cache: None,
517        }
518    }
519
520    pub fn new_with_mock(_store: Arc<MockStore>) -> Result<Self> {
521        // For backward compatibility during transition
522        let rdf_store = Arc::new(
523            RdfStore::new()
524                .map_err(|e| anyhow::anyhow!("Failed to create RDF store for mock: {}", e))?,
525        );
526        Ok(Self {
527            config: GraphQLConfig::default(),
528            store: rdf_store,
529            cache: None,
530        })
531    }
532
533    pub fn with_config(mut self, config: GraphQLConfig) -> Self {
534        self.config = config;
535        self
536    }
537
538    /// Enable distributed caching
539    pub async fn with_distributed_cache(
540        mut self,
541        cache_config: distributed_cache::CacheConfig,
542    ) -> Result<Self> {
543        let cache = Arc::new(distributed_cache::GraphQLQueryCache::new(cache_config).await?);
544        self.cache = Some(cache);
545        Ok(self)
546    }
547
548    /// Get cache statistics if caching is enabled
549    pub async fn get_cache_stats(&self) -> Option<distributed_cache::CacheStats> {
550        if let Some(cache) = &self.cache {
551            cache.get_stats().await.ok()
552        } else {
553            None
554        }
555    }
556
557    pub async fn start(&self, addr: &str) -> Result<()> {
558        tracing::info!("Starting GraphQL server on {}", addr);
559
560        // Create a basic schema with Query type
561        let mut schema = types::Schema::new();
562
563        // Add a Query type with more fields
564        let mut query_type = types::ObjectType::new("Query".to_string())
565            .with_description("The root query type for RDF data access".to_string())
566            .with_field(
567                "hello".to_string(),
568                types::FieldType::new(
569                    "hello".to_string(),
570                    types::GraphQLType::Scalar(types::BuiltinScalars::string()),
571                )
572                .with_description("A simple greeting message".to_string()),
573            )
574            .with_field(
575                "version".to_string(),
576                types::FieldType::new(
577                    "version".to_string(),
578                    types::GraphQLType::Scalar(types::BuiltinScalars::string()),
579                )
580                .with_description("OxiRS GraphQL version".to_string()),
581            )
582            .with_field(
583                "triples".to_string(),
584                types::FieldType::new(
585                    "triples".to_string(),
586                    types::GraphQLType::Scalar(types::BuiltinScalars::int()),
587                )
588                .with_description("Count of triples in the store".to_string()),
589            )
590            .with_field(
591                "subjects".to_string(),
592                types::FieldType::new(
593                    "subjects".to_string(),
594                    types::GraphQLType::List(Box::new(types::GraphQLType::Scalar(
595                        types::BuiltinScalars::string(),
596                    ))),
597                )
598                .with_description("List of subject IRIs".to_string())
599                .with_argument(
600                    "limit".to_string(),
601                    types::ArgumentType::new(
602                        "limit".to_string(),
603                        types::GraphQLType::Scalar(types::BuiltinScalars::int()),
604                    )
605                    .with_default_value(ast::Value::IntValue(10))
606                    .with_description("Maximum number of subjects to return".to_string()),
607                ),
608            )
609            .with_field(
610                "predicates".to_string(),
611                types::FieldType::new(
612                    "predicates".to_string(),
613                    types::GraphQLType::List(Box::new(types::GraphQLType::Scalar(
614                        types::BuiltinScalars::string(),
615                    ))),
616                )
617                .with_description("List of predicate IRIs".to_string())
618                .with_argument(
619                    "limit".to_string(),
620                    types::ArgumentType::new(
621                        "limit".to_string(),
622                        types::GraphQLType::Scalar(types::BuiltinScalars::int()),
623                    )
624                    .with_default_value(ast::Value::IntValue(10))
625                    .with_description("Maximum number of predicates to return".to_string()),
626                ),
627            )
628            .with_field(
629                "objects".to_string(),
630                types::FieldType::new(
631                    "objects".to_string(),
632                    types::GraphQLType::List(Box::new(types::GraphQLType::Scalar(
633                        types::BuiltinScalars::string(),
634                    ))),
635                )
636                .with_description("List of objects".to_string())
637                .with_argument(
638                    "limit".to_string(),
639                    types::ArgumentType::new(
640                        "limit".to_string(),
641                        types::GraphQLType::Scalar(types::BuiltinScalars::int()),
642                    )
643                    .with_default_value(ast::Value::IntValue(10))
644                    .with_description("Maximum number of objects to return".to_string()),
645                ),
646            )
647            .with_field(
648                "sparql".to_string(),
649                types::FieldType::new(
650                    "sparql".to_string(),
651                    types::GraphQLType::Scalar(types::BuiltinScalars::string()),
652                )
653                .with_description("Execute a raw SPARQL query".to_string())
654                .with_argument(
655                    "query".to_string(),
656                    types::ArgumentType::new(
657                        "query".to_string(),
658                        types::GraphQLType::NonNull(Box::new(types::GraphQLType::Scalar(
659                            types::BuiltinScalars::string(),
660                        ))),
661                    )
662                    .with_description("The SPARQL query to execute".to_string()),
663                ),
664            );
665
666        // Add introspection fields if enabled
667        if self.config.enable_introspection {
668            query_type = query_type
669                .with_field(
670                    "__schema".to_string(),
671                    types::FieldType::new(
672                        "__schema".to_string(),
673                        types::GraphQLType::NonNull(Box::new(types::GraphQLType::Scalar(
674                            types::ScalarType {
675                                name: "__Schema".to_string(),
676                                description: Some(
677                                    "A GraphQL Schema defines the capabilities of a GraphQL server"
678                                        .to_string(),
679                                ),
680                                serialize: |_| Ok(ast::Value::NullValue),
681                                parse_value: |_| Err(anyhow::anyhow!("Cannot parse __Schema")),
682                                parse_literal: |_| Err(anyhow::anyhow!("Cannot parse __Schema")),
683                            },
684                        ))),
685                    )
686                    .with_description("Access the current type schema of this server".to_string()),
687                )
688                .with_field(
689                    "__type".to_string(),
690                    types::FieldType::new(
691                        "__type".to_string(),
692                        types::GraphQLType::Scalar(types::ScalarType {
693                            name: "__Type".to_string(),
694                            description: Some(
695                                "A GraphQL Schema defines the capabilities of a GraphQL server"
696                                    .to_string(),
697                            ),
698                            serialize: |_| Ok(ast::Value::NullValue),
699                            parse_value: |_| Err(anyhow::anyhow!("Cannot parse __Type")),
700                            parse_literal: |_| Err(anyhow::anyhow!("Cannot parse __Type")),
701                        }),
702                    )
703                    .with_description("Request the type information of a single type".to_string())
704                    .with_argument(
705                        "name".to_string(),
706                        types::ArgumentType::new(
707                            "name".to_string(),
708                            types::GraphQLType::NonNull(Box::new(types::GraphQLType::Scalar(
709                                types::BuiltinScalars::string(),
710                            ))),
711                        )
712                        .with_description("The name of the type to introspect".to_string()),
713                    ),
714                );
715        }
716
717        schema.add_type(types::GraphQLType::Object(query_type));
718        schema.set_query_type("Query".to_string());
719
720        // Create the server with resolvers
721        let schema_clone = schema.clone();
722        let mut server = server::Server::new(schema.clone())
723            .with_playground(self.config.enable_playground)
724            .with_introspection(self.config.enable_introspection);
725
726        // Configure validation if enabled
727        if self.config.enable_query_validation {
728            server =
729                server.with_validation(self.config.validation_config.clone(), schema_clone.clone());
730        }
731
732        // Set up resolvers
733        let query_resolvers = resolvers::QueryResolvers::new(Arc::clone(&self.store));
734        server.add_resolver("Query".to_string(), query_resolvers.rdf_resolver());
735
736        // Add introspection resolver
737        let introspection_resolver = Arc::new(introspection::IntrospectionResolver::new(Arc::new(
738            schema_clone,
739        )));
740        server.add_resolver("__Schema".to_string(), introspection_resolver.clone());
741        server.add_resolver("__Type".to_string(), introspection_resolver.clone());
742        server.add_resolver("__Field".to_string(), introspection_resolver.clone());
743        server.add_resolver("__InputValue".to_string(), introspection_resolver.clone());
744        server.add_resolver("__EnumValue".to_string(), introspection_resolver.clone());
745        server.add_resolver("__Directive".to_string(), introspection_resolver);
746
747        // Parse the address
748        let socket_addr: std::net::SocketAddr = addr
749            .parse()
750            .map_err(|e| anyhow::anyhow!("Invalid address '{}': {}", addr, e))?;
751
752        server.start(socket_addr).await
753    }
754}
755
756// Comprehensive module declarations moved to top of file to avoid duplicates