elasticctl_api/search/
mod.rs1pub mod dataview;
4pub mod dsl;
5pub mod esql;
6
7use elasticctl_core::{Result, Transport};
8
9pub struct SearchRequest {
10 pub index: Option<String>,
11 pub data_view: Option<String>,
12 pub limit: Option<usize>,
13}
14
15pub fn has_source(query: &str) -> bool {
16 matches!(
17 query
18 .split_whitespace()
19 .next()
20 .unwrap_or_default()
21 .to_ascii_lowercase()
22 .as_str(),
23 "from" | "row" | "show" | "metrics"
24 )
25}
26
27pub fn prepend_from(query: &str, pattern: &str) -> String {
28 if has_source(query) {
29 query.to_string()
30 } else {
31 let q = query.trim_start();
32 let sep = if q.starts_with('|') { "" } else { "| " };
33 format!("FROM {pattern} {sep}{q}")
34 }
35}
36
37pub fn rewrite_from(query: &str, pattern: &str) -> String {
42 let trimmed = query.trim_start();
43 let leading = &query[..query.len() - trimmed.len()];
44 let word_end = trimmed.find(char::is_whitespace).unwrap_or(trimmed.len());
45 let word = &trimmed[..word_end];
46 if word.eq_ignore_ascii_case("from") {
47 let after = &trimmed[word_end..];
48 let source_end = after.find('|').unwrap_or(after.len());
49 let pipeline = &after[source_end..];
50 if pipeline.is_empty() {
51 format!("{leading}FROM {pattern}")
52 } else {
53 format!("{leading}FROM {pattern} {pipeline}")
54 }
55 } else if word.eq_ignore_ascii_case("row")
56 || word.eq_ignore_ascii_case("show")
57 || word.eq_ignore_ascii_case("metrics")
58 {
59 query.to_string()
60 } else {
61 prepend_from(query, pattern)
62 }
63}
64
65pub async fn resolve_esql_query(t: &Transport, query: &str, req: &SearchRequest) -> Result<String> {
68 match (&req.index, &req.data_view) {
69 (Some(i), _) => Ok(rewrite_from(query, i)),
70 (_, Some(dv)) => Ok(rewrite_from(query, &dataview::resolve(t, dv).await?)),
71 _ => {
72 if has_source(query) {
73 Ok(query.to_string())
74 } else {
75 Ok(prepend_from(
76 query,
77 &dataview::default_alerts_index(t).await?,
78 ))
79 }
80 }
81 }
82}
83
84pub async fn resolve_dsl_index(t: &Transport, req: &SearchRequest) -> Result<String> {
87 match (&req.index, &req.data_view) {
88 (Some(i), _) => Ok(i.clone()),
89 (_, Some(dv)) => dataview::resolve(t, dv).await,
90 _ => dataview::default_alerts_index(t).await,
91 }
92}