diff --git a/quickwit/quickwit-query/src/query_ast/bool_query.rs b/quickwit/quickwit-query/src/query_ast/bool_query.rs index e8f3dc9819a..b63a80493bf 100644 --- a/quickwit/quickwit-query/src/query_ast/bool_query.rs +++ b/quickwit/quickwit-query/src/query_ast/bool_query.rs @@ -30,9 +30,9 @@ use crate::InvalidQuery; /// - named queries /// /// Edge cases of BooleanQuery are not obvious, -/// and different beahvior could be justified. +/// and different behavior could be justified. /// -/// Here we aligne ourselves with Elasticsearch. +/// Here we align ourselves with Elasticsearch. /// A boolean query is to be interpreted like a filtering predicate /// over the set of documents. /// diff --git a/quickwit/quickwit-serve/src/elasticsearch_api/model/search_query_params.rs b/quickwit/quickwit-serve/src/elasticsearch_api/model/search_query_params.rs index 7165343266e..8dbada5d23e 100644 --- a/quickwit/quickwit-serve/src/elasticsearch_api/model/search_query_params.rs +++ b/quickwit/quickwit-serve/src/elasticsearch_api/model/search_query_params.rs @@ -77,6 +77,13 @@ pub struct SearchQueryParams { #[serde(serialize_with = "to_simple_list")] #[serde(deserialize_with = "from_simple_list")] #[serde(default)] + /// Additional filters to be applied to the query. + /// Useful for permissions and other use cases. + /// This is not part of the official Elasticsearch API. + pub extra_filters: Option>, + #[serde(serialize_with = "to_simple_list")] + #[serde(deserialize_with = "from_simple_list")] + #[serde(default)] pub filter_path: Option>, #[serde(default)] pub force_synthetic_source: Option, diff --git a/quickwit/quickwit-serve/src/elasticsearch_api/rest_handler.rs b/quickwit/quickwit-serve/src/elasticsearch_api/rest_handler.rs index b2930fe3052..60e9acae877 100644 --- a/quickwit/quickwit-serve/src/elasticsearch_api/rest_handler.rs +++ b/quickwit/quickwit-serve/src/elasticsearch_api/rest_handler.rs @@ -38,7 +38,7 @@ use quickwit_proto::search::{ }; use quickwit_proto::types::IndexUid; use quickwit_proto::ServiceErrorCode; -use quickwit_query::query_ast::{QueryAst, UserInputQuery}; +use quickwit_query::query_ast::{BoolQuery, QueryAst, UserInputQuery}; use quickwit_query::BooleanOperand; use quickwit_search::{list_all_splits, resolve_index_patterns, SearchError, SearchService}; use serde::{Deserialize, Serialize}; @@ -210,7 +210,7 @@ fn build_request_for_es_api( let default_operator = search_params.default_operator.unwrap_or(BooleanOperand::Or); // The query string, if present, takes priority over what can be in the request // body. - let query_ast = if let Some(q) = &search_params.q { + let mut query_ast = if let Some(q) = &search_params.q { let user_text_query = UserInputQuery { user_text: q.to_string(), default_fields: None, @@ -224,6 +224,28 @@ fn build_request_for_es_api( } else { QueryAst::MatchAll }; + + if let Some(extra_filters) = &search_params.extra_filters { + let queries: Vec = extra_filters + .iter() + .map(|query| { + let user_text_query = UserInputQuery { + user_text: query.to_string(), + default_fields: None, + default_operator, + }; + QueryAst::UserInput(user_text_query) + }) + .collect(); + + query_ast = QueryAst::Bool(BoolQuery { + must: vec![query_ast], + must_not: vec![], + should: vec![], + filter: queries, + }); + } + let aggregation_request: Option = if search_body.aggs.is_empty() { None } else { diff --git a/quickwit/rest-api-tests/scenarii/es_compatibility/0023-extra_filters.yaml b/quickwit/rest-api-tests/scenarii/es_compatibility/0023-extra_filters.yaml new file mode 100644 index 00000000000..721469658ca --- /dev/null +++ b/quickwit/rest-api-tests/scenarii/es_compatibility/0023-extra_filters.yaml @@ -0,0 +1,45 @@ +# Extra filters are additional filters that are applied to the query. Useful for permissions and other use cases. +json: + query: + match_all: {} +params: + extra_filters: "type:PushEvent" +expected: + hits: + total: + value: 60 +--- # 2 extra filters +json: + query: + match_all: {} +params: + extra_filters: "type:PushEvent,actor.login:jadonk" +expected: + hits: + total: + value: 2 +--- # Test mixing +json: + query: + query_string: + query: "type:PushEvent" +params: + extra_filters: "actor.login:jadonk" +expected: + hits: + total: + value: 2 +--- # Test mixing +json: + query: + query_string: + query: "type:PushEvent" +params: + extra_filters: "type:PushEvent,actor.login:jadonk" +expected: + hits: + total: + value: 2 + + +