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
use crate::search::*;
use crate::util::*;
use crate::Set;

/// The [parent-join](https://www.elastic.co/guide/en/elasticsearch/reference/current/parent-join.html)
/// and [nested](https://www.elastic.co/guide/en/elasticsearch/reference/current/nested.html)
/// features allow the return of documents that have matches in a different scope. In the
/// parent/child case, parent documents are returned based on matches in child documents or
/// child documents are returned based on matches in parent documents. In the nested case,
/// documents are returned based on matches in nested inner objects.
///
/// In both cases, the actual matches in the different scopes that caused a document to be
/// returned are hidden. In many cases, it’s very useful to know which inner nested objects
/// (in the case of nested) or children/parent documents (in the case of parent/child) caused
/// certain information to be returned. The inner hits feature can be used for this. This
/// feature returns per search hit in the search response additional nested hits that caused a
/// search hit to match in a different scope.
///
/// Inner hits can be used by defining an `inner_hits` definition on a `nested`, `has_child`
/// or `has_parent` query and filter.
///
/// <https://www.elastic.co/guide/en/elasticsearch/reference/current/inner-hits.html>
#[derive(Debug, Default, Clone, PartialEq, Serialize)]
pub struct InnerHits {
    #[serde(skip_serializing_if = "ShouldSkip::should_skip")]
    _source: Option<SourceFilter>,

    #[serde(skip_serializing_if = "ShouldSkip::should_skip")]
    name: Option<String>,

    #[serde(skip_serializing_if = "ShouldSkip::should_skip")]
    from: Option<u64>,

    #[serde(skip_serializing_if = "ShouldSkip::should_skip")]
    size: Option<u64>,

    #[serde(skip_serializing_if = "ShouldSkip::should_skip")]
    sort: SortCollection,

    #[serde(skip_serializing_if = "ShouldSkip::should_skip")]
    highlight: Option<Highlight>,

    #[serde(skip_serializing_if = "ShouldSkip::should_skip")]
    docvalue_fields: Set<String>,

    #[serde(skip_serializing_if = "ShouldSkip::should_skip")]
    collapse: Option<InnerHitsCollapse>,
}

#[derive(Debug, Default, Clone, PartialEq, Serialize)]
struct InnerHitsCollapse {
    field: String,
}

impl InnerHits {
    /// Creates a new instance of [InnerHits](InnerHits)
    pub fn new() -> Self {
        Default::default()
    }

    /// Indicates which source fields are returned for matching documents
    pub fn source<T>(mut self, source: T) -> Self
    where
        T: Into<SourceFilter>,
    {
        self._source = Some(source.into());
        self
    }

    /// Inner hit name, useful when multiple `inner_hits` exist in a single search request
    pub fn name<T>(mut self, name: T) -> Self
    where
        T: ToString,
    {
        self.name = Some(name.to_string());
        self
    }

    /// Starting document offset.
    ///
    /// Defaults to `0`.
    pub fn from(mut self, from: u64) -> Self {
        self.from = Some(from);
        self
    }

    /// The number of hits to return.
    ///
    /// Defaults to `10`.
    pub fn size(mut self, size: u64) -> Self {
        self.size = Some(size);
        self
    }

    /// A collection of sorting fields
    pub fn sort<T>(mut self, sort: T) -> Self
    where
        T: IntoIterator,
        T::Item: Into<Sort>,
    {
        self.sort.extend(sort);
        self
    }

    /// Highlight
    pub fn highlight<T>(mut self, highlight: T) -> Self
    where
        T: Into<Highlight>,
    {
        self.highlight = Some(highlight.into());
        self
    }

    /// A collection of docvalue fields
    pub fn docvalue_fields<T>(mut self, docvalue_fields: T) -> Self
    where
        T: IntoIterator,
        T::Item: ToString,
    {
        self.docvalue_fields
            .extend(docvalue_fields.into_iter().map(|x| x.to_string()));
        self
    }

    /// A field to collapse by
    pub fn collapse<T>(mut self, collapse: T) -> Self
    where
        T: ToString,
    {
        self.collapse = Some(InnerHitsCollapse {
            field: collapse.to_string(),
        });
        self
    }
}