1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140
use crate::search::*;
use crate::util::*;
/// Returns child documents joined to a specific parent document. You can use a join field mapping
/// to create parent-child relationships between documents in the same index.
///
/// To create has_parent query:
/// ```
/// # use elasticsearch_dsl::queries::*;
/// # use elasticsearch_dsl::queries::params::*;
/// # let query =
/// Query::has_parent("parent", Query::term("tag", "elasticsearch"));
/// ```
/// <https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-HasParent-query.html>
#[derive(Debug, Clone, PartialEq, Serialize)]
pub struct HasParentQuery {
#[serde(rename = "has_parent")]
inner: Inner,
}
#[derive(Debug, Clone, PartialEq, Serialize)]
struct Inner {
parent_type: String,
query: Box<Query>,
#[serde(skip_serializing_if = "ShouldSkip::should_skip")]
score: Option<bool>,
#[serde(skip_serializing_if = "ShouldSkip::should_skip")]
ignore_unmapped: Option<bool>,
#[serde(skip_serializing_if = "ShouldSkip::should_skip")]
boost: Option<Boost>,
#[serde(skip_serializing_if = "ShouldSkip::should_skip")]
_name: Option<String>,
}
impl Query {
/// Creates an instance of [`HasParentQuery`]
///
/// - `parent-type` - Name of the parent relationship mapped for the join field.
/// - `query` - Query you wish to run on parent documents of the `parent_type` field. If a
/// parent document matches the search, the query returns its child documents.
pub fn has_parent(parent_type: impl ToString, query: impl Into<Query>) -> HasParentQuery {
HasParentQuery {
inner: Inner {
parent_type: parent_type.to_string(),
query: Box::new(query.into()),
score: None,
ignore_unmapped: None,
boost: None,
_name: None,
},
}
}
}
impl HasParentQuery {
/// Indicates whether the relevance score of a matching parent document is aggregated into its
/// child documents. Defaults to `false`.
///
/// If `false`, Elasticsearch ignores the relevance score of the parent document. Elasticsearch
/// also assigns each child document a relevance score equal to the `query`'s `boost`, which
/// defaults to `1`.
///
/// If `true`, the relevance score of the matching parent document is aggregated into its child
/// documents' relevance scores.
pub fn score(mut self, score: bool) -> Self {
self.inner.score = Some(score);
self
}
/// Indicates whether to ignore an unmapped `parent_type` and not return any documents instead
/// of an error. Defaults to `false`.
///
/// If `false`, Elasticsearch returns an error if the `parent_type` is unmapped.
///
/// You can use this parameter to query multiple indices that may not contain the `parent_type`.
pub fn ignore_unmapped(mut self, ignore_unmapped: bool) -> Self {
self.inner.ignore_unmapped = Some(ignore_unmapped);
self
}
add_boost_and_name!();
}
impl ShouldSkip for HasParentQuery {
fn should_skip(&self) -> bool {
self.inner.parent_type.should_skip() || self.inner.query.should_skip()
}
}
#[cfg(test)]
mod tests {
use super::*;
test_serialization! {
with_required_fields(
Query::has_parent("parent", Query::term("tag", "elasticsearch")),
json!({
"has_parent": {
"parent_type": "parent",
"query": {
"term": {
"tag": {
"value": "elasticsearch"
}
}
}
}
})
);
with_all_fields(
Query::has_parent("parent", Query::term("tag", "elasticsearch"))
.boost(2)
.name("test")
.ignore_unmapped(true)
.score(true),
json!({
"has_parent": {
"parent_type": "parent",
"score": true,
"ignore_unmapped": true,
"query": {
"term": {
"tag": {
"value": "elasticsearch"
}
}
},
"boost": 2,
"_name": "test"
}
})
);
}
}