flusso_query/handles/
nested.rs1use std::marker::PhantomData;
6
7use serde_json::{Map, Value};
8
9use super::{Sort, exists_q, match_all_value};
10use crate::query::{AsQuery, Query, Root};
11
12fn nested_value(path: &str, query: Value) -> Value {
14 let mut body = Map::new();
15 body.insert("path".to_string(), Value::String(path.to_string()));
16 body.insert("query".to_string(), query);
17 let mut outer = Map::new();
18 outer.insert("nested".to_string(), Value::Object(body));
19 Value::Object(outer)
20}
21
22fn bool_value(clause: &str, items: Vec<Value>) -> Value {
24 let mut body = Map::new();
25 body.insert(clause.to_string(), Value::Array(items));
26 let mut outer = Map::new();
27 outer.insert("bool".to_string(), Value::Object(body));
28 Value::Object(outer)
29}
30
31#[derive(Debug, Clone)]
36pub struct Nested<E = Root, C = serde_json::Value> {
37 path: String,
38 _marker: PhantomData<fn() -> (E, C)>,
39}
40
41impl<E, C> Nested<E, C> {
42 pub fn at(path: impl Into<String>) -> Self {
43 Self {
44 path: path.into(),
45 _marker: PhantomData,
46 }
47 }
48
49 pub fn any(&self, query: impl AsQuery<C>) -> Query<E> {
51 let inner = query
52 .into_query()
53 .map_or_else(match_all_value, |q| q.to_value());
54 Query::leaf(nested_value(&self.path, inner))
55 }
56
57 pub fn all(&self, query: impl AsQuery<C>) -> Query<E> {
59 let inner = query
60 .into_query()
61 .map_or_else(match_all_value, |q| q.to_value());
62 let fails = bool_value("must_not", vec![inner]);
63 let nested = nested_value(&self.path, fails);
64 Query::leaf(bool_value("must_not", vec![nested]))
65 }
66
67 pub fn exists(&self) -> Query<E> {
69 exists_q(&self.path)
70 }
71
72 pub fn matching(&self, query: impl AsQuery<C>) -> NestedProjection {
75 NestedProjection {
76 path: self.path.clone(),
77 query: query.into_query().map(|q| q.to_value()),
78 sort: Vec::new(),
79 size: None,
80 from: None,
81 }
82 }
83
84 pub fn project(&self) -> NestedProjection {
86 NestedProjection {
87 path: self.path.clone(),
88 query: None,
89 sort: Vec::new(),
90 size: None,
91 from: None,
92 }
93 }
94}
95
96#[derive(Debug, Clone)]
98pub struct NestedProjection {
99 path: String,
100 query: Option<Value>,
101 sort: Vec<Sort>,
102 size: Option<u64>,
103 from: Option<u64>,
104}
105
106impl NestedProjection {
107 #[must_use]
109 pub fn sort(mut self, sort: Sort) -> Self {
110 self.sort.push(sort);
111 self
112 }
113
114 #[must_use]
116 pub fn size(mut self, size: u64) -> Self {
117 self.size = Some(size);
118 self
119 }
120
121 #[must_use]
123 pub fn from(mut self, from: u64) -> Self {
124 self.from = Some(from);
125 self
126 }
127
128 pub(crate) fn path(&self) -> &str {
129 &self.path
130 }
131
132 pub(crate) fn to_value(&self) -> Value {
135 let query = self.query.clone().unwrap_or_else(match_all_value);
136 let mut inner_hits = Map::new();
137 inner_hits.insert("name".to_string(), Value::String(self.path.clone()));
138 if let Some(size) = self.size {
139 inner_hits.insert("size".to_string(), Value::from(size));
140 }
141 if let Some(from) = self.from {
142 inner_hits.insert("from".to_string(), Value::from(from));
143 }
144 if !self.sort.is_empty() {
145 let keys = self.sort.iter().map(Sort::to_value).collect();
146 inner_hits.insert("sort".to_string(), Value::Array(keys));
147 }
148 let mut nested = Map::new();
149 nested.insert("path".to_string(), Value::String(self.path.clone()));
150 nested.insert("query".to_string(), query);
151 nested.insert("inner_hits".to_string(), Value::Object(inner_hits));
152 let mut outer = Map::new();
153 outer.insert("nested".to_string(), Value::Object(nested));
154 Value::Object(outer)
155 }
156}