Skip to main content

mant_engine/query/
validation.rs

1//! Full requests compose independent loading and query-view validation.
2use super::{
3    EntryProjection, LoadPolicy, MAX_NODE_SELECTORS, MAX_SEMANTIC_ENTRY_CHARS, QueryError,
4    QueryRequest, QueryValidationError, QueryView, ScopeTextError, SearchQuery,
5    validate_scope_text, validate_search_query,
6};
7
8/// Validate the complete request before local I/O.
9///
10/// # Errors
11/// Returns the originating loading or query-view validation error.
12pub fn validate_query_request(
13    request: &QueryRequest,
14    policy: LoadPolicy,
15) -> Result<(), QueryError> {
16    super::validate_load_spec(super::adapter::load_spec(&request.input), policy)?;
17    validate_query_view(&request.view).map_err(QueryError::QueryValidation)
18}
19
20pub(super) fn validate_query_view(view: &QueryView) -> Result<(), QueryValidationError> {
21    match view {
22        QueryView::Excerpt { selectors } => {
23            if selectors.is_empty() {
24                return Err(QueryValidationError::EmptySelection);
25            }
26            if selectors.len() > MAX_NODE_SELECTORS {
27                return Err(QueryValidationError::TooManySelections {
28                    maximum: MAX_NODE_SELECTORS,
29                });
30            }
31            for selector in selectors {
32                selector
33                    .validate()
34                    .map_err(|_| QueryValidationError::InvalidContentSelector)?;
35            }
36        }
37        QueryView::Explain { entry, options } => {
38            validate_scope_text(entry, MAX_SEMANTIC_ENTRY_CHARS).map_err(|error| {
39                if error == ScopeTextError::Empty {
40                    QueryValidationError::EmptyEntry
41                } else {
42                    QueryValidationError::InvalidViewSelector {
43                        field: "semantic entry",
44                        error,
45                    }
46                }
47            })?;
48            mant_query::validate_explanation_query(&mant_protocol::ExplanationQuery {
49                entry: entry.clone(),
50                options: *options,
51            })
52            .map_err(QueryValidationError::InvalidExplanation)?;
53        }
54        QueryView::Search {
55            pattern,
56            syntax,
57            case,
58            scope,
59            word,
60            context_lines,
61            limit,
62            offset,
63        } => validate_search_query(&SearchQuery {
64            pattern: pattern.clone(),
65            syntax: *syntax,
66            case: *case,
67            scope: *scope,
68            word: *word,
69            context_lines: *context_lines,
70            limit: *limit,
71            offset: *offset,
72        })
73        .map_err(QueryValidationError::InvalidSearch)?,
74        QueryView::Outline {
75            entries,
76            root,
77            references,
78        } => {
79            references
80                .validate()
81                .map_err(QueryValidationError::InvalidReferenceProjection)?;
82            if let Some(selector) = root {
83                selector
84                    .validate()
85                    .map_err(|_| QueryValidationError::InvalidContentSelector)?;
86            }
87            if let EntryProjection::Kinds { kinds } = entries
88                && (kinds.is_empty() || kinds.len() > 9)
89            {
90                return Err(QueryValidationError::InvalidEntryKinds);
91            }
92        }
93        QueryView::Full {} => {}
94    }
95    Ok(())
96}