mod executor;
mod parser;
pub use executor::*;
pub use parser::*;
use axum::{extract::State, routing::post, Json, Router};
use serde::{Deserialize, Serialize};
use crate::error::Result;
use crate::state::AppState;
pub fn router() -> Router<AppState> {
Router::new()
.route("/sparql", post(execute_sparql))
.route("/api/v1/sparql", post(execute_sparql))
}
#[derive(Debug, Deserialize)]
pub struct SparqlRequest {
pub query: String,
pub default_graph: Option<String>,
pub named_graphs: Option<Vec<String>>,
}
#[derive(Debug, Serialize)]
pub struct SparqlResponse {
pub result_type: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub variables: Option<Vec<String>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub bindings: Option<Vec<serde_json::Value>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub boolean: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub triple_count: Option<usize>,
pub execution_time_ms: u64,
}
pub async fn execute_sparql(
State(state): State<AppState>,
Json(req): Json<SparqlRequest>,
) -> Result<Json<SparqlResponse>> {
let start = std::time::Instant::now();
let parsed = parse_sparql(&req.query)?;
let graph = state.graph.read().await;
let result = execute_query(&graph, &parsed)?;
let execution_time_ms = start.elapsed().as_millis() as u64;
Ok(Json(SparqlResponse {
result_type: result.result_type,
variables: result.variables,
bindings: result.bindings,
boolean: result.boolean,
triple_count: result.triple_count,
execution_time_ms,
}))
}
#[derive(Debug)]
pub struct SparqlResult {
pub result_type: String,
pub variables: Option<Vec<String>>,
pub bindings: Option<Vec<serde_json::Value>>,
pub boolean: Option<bool>,
pub triple_count: Option<usize>,
}