cherenkov_model_data/discovery/
query.rs1use super::{FilterOperator, SearchQuery, SearchSchema, ValueType};
4use anyhow::{Context, Result, ensure};
5use serde_json::Value;
6
7impl SearchSchema {
8 pub fn validate(&self, query: &SearchQuery) -> Result<()> {
11 query.page.validate(self.max_page_size)?;
12 ensure!(
13 self.text_search || query.text.is_none(),
14 "this store does not support text search"
15 );
16
17 for filter in &query.filters {
18 let field = self
19 .fields
20 .get(&filter.field)
21 .with_context(|| format!("unsupported search field {:?}", filter.field))?;
22
23 ensure!(
24 field.operators.contains(&filter.operator),
25 "unsupported operator {:?} for search field {:?}",
26 filter.operator,
27 filter.field
28 );
29 ensure!(
30 field.value_type.accepts(&filter.value, filter.operator),
31 "invalid value for search field {:?}: expected {:?}",
32 filter.field,
33 field.value_type
34 );
35 }
36
37 Ok(())
38 }
39}
40
41impl ValueType {
42 fn accepts(&self, value: &Value, operator: FilterOperator) -> bool {
44 if operator != FilterOperator::AnyOf {
45 return self.accepts_scalar(value);
46 }
47
48 value.as_array().is_some_and(|values| {
49 !values.is_empty() && values.iter().all(|value| self.accepts_scalar(value))
50 })
51 }
52
53 fn accepts_scalar(&self, value: &Value) -> bool {
55 match self {
56 Self::String => value.is_string(),
57 Self::Boolean => value.is_boolean(),
58 Self::Integer => value.is_i64() || value.is_u64(),
59 Self::Unsigned => value.is_u64(),
60 Self::Number => value.is_number(),
61 Self::Choice { values } => value
62 .as_str()
63 .is_some_and(|text| values.iter().any(|v| v == text)),
64 }
65 }
66}