flams_router_dashboard/
query.rs1use flams_router_base::maybe_lazy;
2use ftml_dom::utils::css::inject_css;
3use leptos::prelude::*;
4
5#[server(QueryApi,
6 prefix="/api/backend",
7 endpoint="query",
8 input=server_fn::codec::PostUrl,
9 output=server_fn::codec::Json
10)]
11#[cfg_attr(
12 feature = "ssr",
13 tracing::instrument(level = "info", name = "query", target = "query", skip_all)
14)]
15pub async fn query_api(
16 query: String,
17 decode_uris: Option<bool>,
18) -> Result<flams_backend_types::sparql::SparqlResult, ServerFnError<String>> {
19 use flams_math_archives::backend::GlobalBackend;
20 use flams_math_archives::triple_store::sparql::QueryResult;
21 use flams_system::TokioEngine;
22 tracing::info!("Query: {query} (decode_uris: {decode_uris:?}");
23 let decode_uris = decode_uris.unwrap_or(true);
24 let r = tokio::task::spawn_blocking(move || {
25 GlobalBackend
26 .triple_store()
27 .query_str::<TokioEngine>(&query)
28 .map(|q| QueryResult::into_json(q, decode_uris))
29 })
30 .await; match r {
32 Ok(Ok(r)) => Ok(r),
33 Ok(Err(e)) => Err(ServerFnError::WrappedServerError(e.to_string())),
35 Err(e) => Err(ServerFnError::WrappedServerError(e.to_string())),
36 }
37}
38
39const QUERY: &str = r"SELECT ?x ?y WHERE {
40 ?x rdf:type ulo:declaration .
41 ?y rdf:type ulo:notation .
42 ?y ulo:notation-for ?x.
43}";
44
45maybe_lazy!(Query = query());
46
47fn query() -> AnyView {
48 use ftml_component_utils::Checkbox;
49 use ftml_component_utils::{Code, Input, Text};
50 use leptos::form::ActionForm;
51 inject_css("flams-query", include_str!("query.css"));
52
53 let action = ServerAction::<QueryApi>::new();
54 let rf = NodeRef::<leptos::html::Div>::new();
55 let pretty_print = RwSignal::new(false);
56 let result = Memo::new(move |_| {
57 action.value().get().map(|result| match result {
58 Ok(r) => {
59 if pretty_print.get() {
60 serde_json::to_string_pretty(&r).map_or_else(|e| format!("Error: {e}"), |v| format!("{v:#}"))
62 } else {
63 serde_json::to_string(&r).expect("infallible?")
64 }
65 }
66 Err(e) => format!("Error: {e}"),
67 })
68 });
69 let uri = RwSignal::new(String::new());
70
71 view! {
72 <div>
73 <h1>Query</h1>
74 <p>"Note that FTML URIs need to be partially URL-encoded to be valid RDF-IRIs"</p>
75 <div>
76 <Text>"Encode URI: "</Text>
77 <Input value=uri/>
78 <Code>{
79 move || {
80 ftml_uris::rdf_encode(&uri.get()).unwrap_or_else(|| "(invalid URI)".to_string())
81 }
82 }</Code>
83 </div>
84 <ActionForm action>
85 <span class="flams-query-container">
86 <textarea name="query" class="flams-query-inner">{QUERY.to_string()}</textarea>
87 </span>
88 <br/><input type="submit" value="Query"/>
89 </ActionForm>
90 <Checkbox checked=pretty_print label="pretty printed"/>
91 <div node_ref=rf style="text-align:left;margin:10px;font-family:monospace;white-space:pre;border:var(--strokeWidthThickest) solid var(--colorNeutralStroke1);text-wrap:pretty;">
92 {move || result.get().unwrap_or_default()}
93 </div>
94 </div>
95 }.into_any()
96}