1use std::rc::Rc;
2
3use xee_interpreter::{
4 context::{self, StaticContext},
5 error::SpannedResult as Result,
6};
7use xee_xpath_compiler::parse;
8
9use crate::query::{
10 Convert, ManyQuery, ManyRecurseQuery, OneQuery, OneRecurseQuery, OptionQuery,
11 OptionRecurseQuery, SequenceQuery,
12};
13
14#[derive(Debug, Default)]
19pub struct Queries<'a> {
20 pub(crate) default_static_context_builder: context::StaticContextBuilder<'a>,
21}
22
23impl<'a> Queries<'a> {
24 pub fn new(default_static_context_builder: context::StaticContextBuilder<'a>) -> Self {
30 Self {
31 default_static_context_builder,
32 }
33 }
34
35 pub fn one<V, F>(&self, s: &str, convert: F) -> Result<OneQuery<V, F>>
41 where
42 F: Convert<V>,
43 {
44 self.one_with_context(s, convert, self.default_static_context_builder.build())
45 }
46
47 pub fn one_with_context<V, F>(
53 &self,
54 s: &str,
55 convert: F,
56 static_context: StaticContext,
57 ) -> Result<OneQuery<V, F>>
58 where
59 F: Convert<V>,
60 {
61 Ok(OneQuery {
62 program: Rc::new(parse(static_context, s)?),
63 convert,
64 phantom: std::marker::PhantomData,
65 })
66 }
67
68 pub fn one_recurse(&self, s: &str) -> Result<OneRecurseQuery> {
78 self.one_recurse_with_context(s, self.default_static_context_builder.build())
79 }
80
81 pub fn one_recurse_with_context(
84 &self,
85 s: &str,
86 static_context: context::StaticContext,
87 ) -> Result<OneRecurseQuery> {
88 Ok(OneRecurseQuery {
89 program: Rc::new(parse(static_context, s)?),
90 })
91 }
92
93 pub fn option<V, F>(&self, s: &str, convert: F) -> Result<OptionQuery<V, F>>
97 where
98 F: Convert<V>,
99 {
100 self.option_with_context(s, convert, self.default_static_context_builder.build())
101 }
102
103 pub fn option_with_context<V, F>(
106 &self,
107 s: &str,
108 convert: F,
109 static_context: context::StaticContext,
110 ) -> Result<OptionQuery<V, F>>
111 where
112 F: Convert<V>,
113 {
114 Ok(OptionQuery {
115 program: Rc::new(parse(static_context, s)?),
116 convert,
117 phantom: std::marker::PhantomData,
118 })
119 }
120
121 pub fn option_recurse(&self, s: &str) -> Result<OptionRecurseQuery> {
127 self.option_recurse_with_context(s, self.default_static_context_builder.build())
128 }
129
130 pub fn option_recurse_with_context(
133 &self,
134 s: &str,
135 static_context: context::StaticContext,
136 ) -> Result<OptionRecurseQuery> {
137 Ok(OptionRecurseQuery {
138 program: Rc::new(parse(static_context, s)?),
139 })
140 }
141
142 pub fn many<V, F>(&self, s: &str, convert: F) -> Result<ManyQuery<V, F>>
146 where
147 F: Convert<V>,
148 {
149 self.many_with_context(s, convert, self.default_static_context_builder.build())
150 }
151
152 pub fn many_with_context<V, F>(
155 &self,
156 s: &str,
157 convert: F,
158 static_context: context::StaticContext,
159 ) -> Result<ManyQuery<V, F>>
160 where
161 F: Convert<V>,
162 {
163 Ok(ManyQuery {
164 program: Rc::new(parse(static_context, s)?),
165 convert,
166 phantom: std::marker::PhantomData,
167 })
168 }
169
170 pub fn many_recurse(&self, s: &str) -> Result<ManyRecurseQuery> {
176 self.many_recurse_with_context(s, self.default_static_context_builder.build())
177 }
178
179 pub fn many_recurse_with_context(
182 &self,
183 s: &str,
184 static_context: context::StaticContext,
185 ) -> Result<ManyRecurseQuery> {
186 Ok(ManyRecurseQuery {
187 program: Rc::new(parse(static_context, s)?),
188 })
189 }
190
191 pub fn sequence(&self, s: &str) -> Result<SequenceQuery> {
196 self.sequence_with_context(s, self.default_static_context_builder.build())
197 }
198
199 pub fn sequence_with_context(
202 &self,
203 s: &str,
204 static_context: context::StaticContext,
205 ) -> Result<SequenceQuery> {
206 Ok(SequenceQuery {
207 program: Rc::new(parse(static_context, s)?),
208 })
209 }
210}
211
212#[cfg(test)]
213mod tests {
214
215 use iri_string::types::IriStr;
216
217 use crate::{query::Query, Documents};
218
219 use super::*;
220
221 #[test]
222 fn test_one_query() -> Result<()> {
223 let mut documents = Documents::new();
224 let uri: &IriStr = "http://example.com".try_into().unwrap();
225 let doc = documents.add_string(uri, "<root>foo</root>").unwrap();
226
227 let queries = Queries::default();
228 let q = queries.one("/root/string()", |_, item| {
229 Ok(item.try_into_value::<String>()?)
230 })?;
231
232 let r = q.execute(&mut documents, doc)?;
233 assert_eq!(r, "foo");
234 Ok(())
235 }
236}