dioxus_query/
query.rs

1use core::fmt;
2use std::{
3    cell::{Ref, RefCell},
4    collections::{HashMap, HashSet},
5    future::Future,
6    hash::Hash,
7    mem,
8    rc::Rc,
9    sync::{Arc, Mutex},
10    time::Duration,
11};
12
13use dioxus::prelude::*;
14use dioxus::signals::CopyValue;
15use dioxus_core::{
16    provide_root_context, spawn_forever, use_drop, ReactiveContext, SuspendedFuture, Task,
17};
18use futures_util::stream::{FuturesUnordered, StreamExt};
19use tokio::sync::Notify;
20#[cfg(not(target_family = "wasm"))]
21use tokio::time;
22#[cfg(not(target_family = "wasm"))]
23use tokio::time::Instant;
24#[cfg(target_family = "wasm")]
25use wasmtimer::tokio as time;
26#[cfg(target_family = "wasm")]
27use web_time::Instant;
28
29pub trait QueryCapability
30where
31    Self: 'static + Clone + PartialEq + Hash + Eq,
32{
33    type Ok;
34    type Err;
35    type Keys: Hash + PartialEq + Clone;
36
37    /// Query logic.
38    fn run(&self, keys: &Self::Keys) -> impl Future<Output = Result<Self::Ok, Self::Err>>;
39
40    /// Implement a custom logic to check if this query should be invalidated or not given a [QueryCapability::Keys].
41    fn matches(&self, _keys: &Self::Keys) -> bool {
42        true
43    }
44}
45
46pub enum QueryStateData<Q: QueryCapability> {
47    /// Has not loaded yet.
48    Pending,
49    /// Is loading and may not have a previous settled value.
50    Loading { res: Option<Result<Q::Ok, Q::Err>> },
51    /// Is not loading and has a settled value.
52    Settled {
53        res: Result<Q::Ok, Q::Err>,
54        settlement_instant: Instant,
55    },
56}
57
58impl<Q: QueryCapability> TryFrom<QueryStateData<Q>> for Result<Q::Ok, Q::Err> {
59    type Error = ();
60
61    fn try_from(value: QueryStateData<Q>) -> Result<Self, Self::Error> {
62        match value {
63            QueryStateData::Loading { res: Some(res) } => Ok(res),
64            QueryStateData::Settled { res, .. } => Ok(res),
65            _ => Err(()),
66        }
67    }
68}
69
70impl<Q> fmt::Debug for QueryStateData<Q>
71where
72    Q: QueryCapability,
73    Q::Ok: fmt::Debug,
74    Q::Err: fmt::Debug,
75{
76    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
77        match self {
78            Self::Pending => f.write_str("Pending"),
79            Self::Loading { res } => write!(f, "Loading {{ {res:?} }}"),
80            Self::Settled { res, .. } => write!(f, "Settled {{ {res:?} }}"),
81        }
82    }
83}
84
85impl<Q: QueryCapability> QueryStateData<Q> {
86    /// Check if the state is [QueryStateData::Settled] and [Result::Ok].
87    pub fn is_ok(&self) -> bool {
88        matches!(self, QueryStateData::Settled { res: Ok(_), .. })
89    }
90
91    /// Check if the state is [QueryStateData::Settled] and [Result::Err].
92    pub fn is_err(&self) -> bool {
93        matches!(self, QueryStateData::Settled { res: Err(_), .. })
94    }
95
96    /// Check if the state is [QueryStateData::Loading].
97    pub fn is_loading(&self) -> bool {
98        matches!(self, QueryStateData::Loading { .. })
99    }
100
101    /// Check if the state is [QueryStateData::Pending].
102    pub fn is_pending(&self) -> bool {
103        matches!(self, QueryStateData::Pending)
104    }
105
106    /// Check if the state is stale or not, where stale means outdated.
107    pub fn is_stale(&self, query: &Query<Q>) -> bool {
108        match self {
109            QueryStateData::Pending => true,
110            QueryStateData::Loading { .. } => true,
111            QueryStateData::Settled {
112                settlement_instant, ..
113            } => Instant::now().duration_since(*settlement_instant) >= query.stale_time,
114        }
115    }
116
117    /// Get the value as an [Option].
118    pub fn ok(&self) -> Option<&Q::Ok> {
119        match self {
120            Self::Settled { res: Ok(res), .. } => Some(res),
121            Self::Loading { res: Some(Ok(res)) } => Some(res),
122            _ => None,
123        }
124    }
125
126    /// Get the value as an [Result] if possible, otherwise it will panic.
127    pub fn unwrap(&self) -> &Result<Q::Ok, Q::Err> {
128        match self {
129            Self::Loading { res: Some(v) } => v,
130            Self::Settled { res, .. } => res,
131            _ => unreachable!(),
132        }
133    }
134
135    fn into_loading(self) -> QueryStateData<Q> {
136        match self {
137            QueryStateData::Pending => QueryStateData::Loading { res: None },
138            QueryStateData::Loading { res } => QueryStateData::Loading { res },
139            QueryStateData::Settled { res, .. } => QueryStateData::Loading { res: Some(res) },
140        }
141    }
142}
143pub struct QueriesStorage<Q: QueryCapability> {
144    storage: CopyValue<HashMap<Query<Q>, QueryData<Q>>>,
145}
146
147impl<Q: QueryCapability> Copy for QueriesStorage<Q> {}
148
149impl<Q: QueryCapability> Clone for QueriesStorage<Q> {
150    fn clone(&self) -> Self {
151        *self
152    }
153}
154
155struct QuerySuspenseData {
156    notifier: Arc<Notify>,
157    task: Task,
158}
159
160pub struct QueryData<Q: QueryCapability> {
161    state: Rc<RefCell<QueryStateData<Q>>>,
162    reactive_contexts: Arc<Mutex<HashSet<ReactiveContext>>>,
163
164    suspense_task: Rc<RefCell<Option<QuerySuspenseData>>>,
165    interval_task: Rc<RefCell<Option<(Duration, Task)>>>,
166    clean_task: Rc<RefCell<Option<Task>>>,
167}
168
169impl<Q: QueryCapability> Clone for QueryData<Q> {
170    fn clone(&self) -> Self {
171        Self {
172            state: self.state.clone(),
173            reactive_contexts: self.reactive_contexts.clone(),
174
175            suspense_task: self.suspense_task.clone(),
176            interval_task: self.interval_task.clone(),
177            clean_task: self.clean_task.clone(),
178        }
179    }
180}
181
182impl<Q: QueryCapability> QueriesStorage<Q> {
183    fn new_in_root() -> Self {
184        Self {
185            storage: CopyValue::new_in_scope(HashMap::default(), ScopeId::ROOT),
186        }
187    }
188
189    fn insert_or_get_query(&mut self, query: Query<Q>) -> QueryData<Q> {
190        let query_clone = query.clone();
191        let mut storage = self.storage.write();
192
193        let query_data = storage.entry(query).or_insert_with(|| QueryData {
194            state: Rc::new(RefCell::new(QueryStateData::Pending)),
195            reactive_contexts: Arc::default(),
196            suspense_task: Rc::default(),
197            interval_task: Rc::default(),
198            clean_task: Rc::default(),
199        });
200        let query_data_clone = query_data.clone();
201
202        // Cancel clean task
203        if let Some(clean_task) = query_data.clean_task.take() {
204            clean_task.cancel();
205        }
206
207        // Start an interval task if necessary
208        // If multiple queries subscribers use different intervals the interval task
209        // will run using the shortest interval
210        let interval = query_clone.interval_time;
211        let interval_enabled = query_clone.interval_time != Duration::MAX;
212        let interval_task = &mut *query_data.interval_task.borrow_mut();
213
214        let create_interval_task = match interval_task {
215            None if interval_enabled => true,
216            Some((current_interval, current_interval_task)) if interval_enabled => {
217                let new_interval_is_shorter = *current_interval > interval;
218                if new_interval_is_shorter {
219                    current_interval_task.cancel();
220                    *interval_task = None;
221                }
222                new_interval_is_shorter
223            }
224            _ => false,
225        };
226        if create_interval_task {
227            let task = spawn_forever(async move {
228                loop {
229                    // Wait as long as the stale time is configured
230                    time::sleep(interval).await;
231
232                    // Run the query
233                    QueriesStorage::<Q>::run_queries(&[(&query_clone, &query_data_clone)]).await;
234                }
235            });
236            *interval_task = Some((interval, task));
237        }
238
239        query_data.clone()
240    }
241
242    fn update_tasks(&mut self, query: Query<Q>) {
243        let mut storage_clone = self.storage;
244        let mut storage = self.storage.write();
245
246        let query_data = storage.get_mut(&query).unwrap();
247
248        // Cancel interval task
249        if let Some((_, interval_task)) = query_data.interval_task.take() {
250            interval_task.cancel();
251        }
252
253        // Spawn clean up task if there no more reactive contexts
254        if query_data.reactive_contexts.lock().unwrap().is_empty() {
255            *query_data.clean_task.borrow_mut() = Some(spawn_forever(async move {
256                // Wait as long as the stale time is configured
257                time::sleep(query.clean_time).await;
258
259                // Finally clear the query
260                let mut storage = storage_clone.write();
261                storage.remove(&query);
262            }));
263        }
264    }
265
266    pub async fn get(get_query: GetQuery<Q>) -> QueryReader<Q> {
267        let query: Query<Q> = get_query.into();
268
269        let mut storage = match try_consume_context::<QueriesStorage<Q>>() {
270            Some(storage) => storage,
271            None => provide_root_context(QueriesStorage::<Q>::new_in_root()),
272        };
273
274        let query_data = storage
275            .storage
276            .write()
277            .entry(query.clone())
278            .or_insert_with(|| QueryData {
279                state: Rc::new(RefCell::new(QueryStateData::Pending)),
280                reactive_contexts: Arc::default(),
281                suspense_task: Rc::default(),
282                interval_task: Rc::default(),
283                clean_task: Rc::default(),
284            })
285            .clone();
286
287        // Run the query if the value is stale
288        if query_data.state.borrow().is_stale(&query) {
289            // Set to Loading
290            let res = mem::replace(&mut *query_data.state.borrow_mut(), QueryStateData::Pending)
291                .into_loading();
292            *query_data.state.borrow_mut() = res;
293            for reactive_context in query_data.reactive_contexts.lock().unwrap().iter() {
294                reactive_context.mark_dirty();
295            }
296
297            // Run
298            let res = query.query.run(&query.keys).await;
299
300            // Set to Settled
301            *query_data.state.borrow_mut() = QueryStateData::Settled {
302                res,
303                settlement_instant: Instant::now(),
304            };
305            for reactive_context in query_data.reactive_contexts.lock().unwrap().iter() {
306                reactive_context.mark_dirty();
307            }
308
309            // Notify the suspense task if any
310            if let Some(suspense_task) = &*query_data.suspense_task.borrow() {
311                suspense_task.notifier.notify_waiters();
312            };
313        }
314
315        // Spawn clean up task if there no more reactive contexts
316        if query_data.reactive_contexts.lock().unwrap().is_empty() {
317            *query_data.clean_task.borrow_mut() = Some(spawn_forever(async move {
318                // Wait as long as the stale time is configured
319                time::sleep(query.clean_time).await;
320
321                // Finally clear the query
322                let mut storage = storage.storage.write();
323                storage.remove(&query);
324            }));
325        }
326
327        QueryReader {
328            state: query_data.state,
329        }
330    }
331
332    pub async fn invalidate_all() {
333        let storage = consume_context::<QueriesStorage<Q>>();
334
335        // Get all the queries
336        let matching_queries = storage
337            .storage
338            .read()
339            .clone()
340            .into_iter()
341            .collect::<Vec<_>>();
342        let matching_queries = matching_queries
343            .iter()
344            .map(|(q, d)| (q, d))
345            .collect::<Vec<_>>();
346
347        // Invalidate the queries
348        Self::run_queries(&matching_queries).await
349    }
350
351    pub async fn invalidate_matching(matching_keys: Q::Keys) {
352        let storage = consume_context::<QueriesStorage<Q>>();
353
354        // Get those queries that match
355        let mut matching_queries = Vec::new();
356        for (query, data) in storage.storage.read().iter() {
357            if query.query.matches(&matching_keys) {
358                matching_queries.push((query.clone(), data.clone()));
359            }
360        }
361        let matching_queries = matching_queries
362            .iter()
363            .map(|(q, d)| (q, d))
364            .collect::<Vec<_>>();
365
366        // Invalidate the queries
367        Self::run_queries(&matching_queries).await
368    }
369
370    async fn run_queries(queries: &[(&Query<Q>, &QueryData<Q>)]) {
371        let tasks = FuturesUnordered::new();
372
373        for (query, query_data) in queries {
374            // Set to Loading
375            let res = mem::replace(&mut *query_data.state.borrow_mut(), QueryStateData::Pending)
376                .into_loading();
377            *query_data.state.borrow_mut() = res;
378            for reactive_context in query_data.reactive_contexts.lock().unwrap().iter() {
379                reactive_context.mark_dirty();
380            }
381
382            tasks.push(Box::pin(async move {
383                // Run
384                let res = query.query.run(&query.keys).await;
385
386                // Set to settled
387                *query_data.state.borrow_mut() = QueryStateData::Settled {
388                    res,
389                    settlement_instant: Instant::now(),
390                };
391                for reactive_context in query_data.reactive_contexts.lock().unwrap().iter() {
392                    reactive_context.mark_dirty();
393                }
394
395                // Notify the suspense task if any
396                if let Some(suspense_task) = &*query_data.suspense_task.borrow() {
397                    suspense_task.notifier.notify_waiters();
398                };
399            }));
400        }
401
402        tasks.count().await;
403    }
404}
405
406pub struct GetQuery<Q: QueryCapability> {
407    query: Q,
408    keys: Q::Keys,
409
410    stale_time: Duration,
411    clean_time: Duration,
412}
413
414impl<Q: QueryCapability> GetQuery<Q> {
415    pub fn new(keys: Q::Keys, query: Q) -> Self {
416        Self {
417            query,
418            keys,
419            stale_time: Duration::ZERO,
420            clean_time: Duration::ZERO,
421        }
422    }
423    /// For how long is the data considered stale. If a query subscriber is mounted and the data is stale, it will re run the query.
424    ///
425    /// Defaults to [Duration::ZERO], meaning it is marked stale immediately.
426    pub fn stale_time(self, stale_time: Duration) -> Self {
427        Self { stale_time, ..self }
428    }
429
430    /// For how long the data is kept cached after there are no more query subscribers.
431    ///
432    /// Defaults to [Duration::ZERO], meaning it clears automatically.
433    pub fn clean_time(self, clean_time: Duration) -> Self {
434        Self { clean_time, ..self }
435    }
436}
437
438impl<Q: QueryCapability> From<GetQuery<Q>> for Query<Q> {
439    fn from(value: GetQuery<Q>) -> Self {
440        Query {
441            query: value.query,
442            keys: value.keys,
443
444            enabled: true,
445
446            stale_time: value.stale_time,
447            clean_time: value.clean_time,
448            interval_time: Duration::MAX,
449        }
450    }
451}
452#[derive(PartialEq, Clone)]
453pub struct Query<Q: QueryCapability> {
454    query: Q,
455    keys: Q::Keys,
456
457    enabled: bool,
458
459    stale_time: Duration,
460    clean_time: Duration,
461    interval_time: Duration,
462}
463
464impl<Q: QueryCapability> Eq for Query<Q> {}
465impl<Q: QueryCapability> Hash for Query<Q> {
466    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
467        self.query.hash(state);
468        self.keys.hash(state);
469
470        self.enabled.hash(state);
471
472        self.stale_time.hash(state);
473        self.clean_time.hash(state);
474
475        // Intentionally left out as intervals can vary from one query subscriber to another
476        // self.interval_time.hash(state);
477    }
478}
479
480impl<Q: QueryCapability> Query<Q> {
481    pub fn new(keys: Q::Keys, query: Q) -> Self {
482        Self {
483            query,
484            keys,
485            enabled: true,
486            stale_time: Duration::ZERO,
487            clean_time: Duration::from_secs(5 * 60),
488            interval_time: Duration::MAX,
489        }
490    }
491
492    /// Enable or disable this query so that it doesnt automatically run.
493    ///
494    /// Defaults to `true`.
495    pub fn enable(self, enabled: bool) -> Self {
496        Self { enabled, ..self }
497    }
498
499    /// For how long is the data considered stale. If a query subscriber is mounted and the data is stale, it will re run the query
500    /// otherwise it return the cached data.
501    ///
502    /// Defaults to [Duration::ZERO], meaning it is marked stale immediately after it has been used.
503    pub fn stale_time(self, stale_time: Duration) -> Self {
504        Self { stale_time, ..self }
505    }
506
507    /// For how long the data is kept cached after there are no more query subscribers.
508    ///
509    /// Defaults to `5min`, meaning it clears automatically after 5 minutes of no subscribers to it.
510    pub fn clean_time(self, clean_time: Duration) -> Self {
511        Self { clean_time, ..self }
512    }
513
514    /// Every how often the query reruns.
515    ///
516    /// Defaults to [Duration::MAX], meaning it never re runs automatically.
517    ///
518    /// **Note**: If multiple subscribers of the same query use different intervals, only the shortest one will be used.
519    pub fn interval_time(self, interval_time: Duration) -> Self {
520        Self {
521            interval_time,
522            ..self
523        }
524    }
525}
526
527pub struct QueryReader<Q: QueryCapability> {
528    state: Rc<RefCell<QueryStateData<Q>>>,
529}
530
531impl<Q: QueryCapability> QueryReader<Q> {
532    pub fn state(&self) -> Ref<QueryStateData<Q>> {
533        self.state.borrow()
534    }
535
536    /// Get the result of the query.
537    ///
538    /// **This method will panic if the query is not settled.**
539    pub fn as_settled(&self) -> Ref<Result<Q::Ok, Q::Err>> {
540        Ref::map(self.state.borrow(), |state| match state {
541            QueryStateData::Settled { res, .. } => res,
542            _ => panic!("Query is not settled."),
543        })
544    }
545}
546
547pub struct UseQuery<Q: QueryCapability> {
548    query: Signal<Query<Q>>,
549}
550
551impl<Q: QueryCapability> Clone for UseQuery<Q> {
552    fn clone(&self) -> Self {
553        *self
554    }
555}
556
557impl<Q: QueryCapability> Copy for UseQuery<Q> {}
558
559impl<Q: QueryCapability> UseQuery<Q> {
560    /// Read the [Query] state.
561    ///
562    /// This **will** automatically subscribe.
563    /// If you want a **non-subscribing** method have a look at [UseQuery::peek].
564    pub fn read(&self) -> QueryReader<Q> {
565        let storage = consume_context::<QueriesStorage<Q>>();
566        let query_data = storage
567            .storage
568            .peek_unchecked()
569            .get(&self.query.peek())
570            .cloned()
571            .unwrap();
572
573        // Subscribe if possible
574        if let Some(reactive_context) = ReactiveContext::current() {
575            reactive_context.subscribe(query_data.reactive_contexts);
576        }
577
578        QueryReader {
579            state: query_data.state,
580        }
581    }
582
583    /// Read the [Query] state.
584    ///
585    /// This **will not** automatically subscribe.
586    /// If you want a **subscribing** method have a look at [UseQuery::read].
587    pub fn peek(&self) -> QueryReader<Q> {
588        let storage = consume_context::<QueriesStorage<Q>>();
589        let query_data = storage
590            .storage
591            .peek_unchecked()
592            .get(&self.query.peek())
593            .cloned()
594            .unwrap();
595
596        QueryReader {
597            state: query_data.state,
598        }
599    }
600
601    /// Suspend this query until it has been **settled**.
602    ///
603    /// This **will** automatically subscribe.
604    pub fn suspend(&self) -> Result<Result<Q::Ok, Q::Err>, RenderError>
605    where
606        Q::Ok: Clone,
607        Q::Err: Clone,
608    {
609        let storage = consume_context::<QueriesStorage<Q>>();
610        let mut storage = storage.storage.write_unchecked();
611        let query_data = storage.get_mut(&self.query.peek()).unwrap();
612
613        // Subscribe if possible
614        if let Some(reactive_context) = ReactiveContext::current() {
615            reactive_context.subscribe(query_data.reactive_contexts.clone());
616        }
617
618        let state = &*query_data.state.borrow();
619        match state {
620            QueryStateData::Pending | QueryStateData::Loading { res: None } => {
621                let suspense_task_clone = query_data.suspense_task.clone();
622                let mut suspense_task = query_data.suspense_task.borrow_mut();
623                let QuerySuspenseData { task, .. } = suspense_task.get_or_insert_with(|| {
624                    let notifier = Arc::new(Notify::new());
625                    let task = spawn({
626                        let notifier = notifier.clone();
627                        async move {
628                            notifier.notified().await;
629                            let _ = suspense_task_clone.borrow_mut().take();
630                        }
631                    });
632                    QuerySuspenseData { notifier, task }
633                });
634                Err(RenderError::Suspended(SuspendedFuture::new(*task)))
635            }
636            QueryStateData::Settled { res, .. } | QueryStateData::Loading { res: Some(res) } => {
637                Ok(res.clone())
638            }
639        }
640    }
641
642    /// Invalidate this query and await its result.
643    ///
644    /// For a `sync` version use [UseQuery::invalidate].
645    pub async fn invalidate_async(&self) -> QueryReader<Q> {
646        let storage = consume_context::<QueriesStorage<Q>>();
647
648        let query = self.query.peek().clone();
649        let query_data = storage
650            .storage
651            .peek_unchecked()
652            .get(&query)
653            .cloned()
654            .unwrap();
655
656        // Run the query
657        QueriesStorage::run_queries(&[(&query, &query_data)]).await;
658
659        QueryReader {
660            state: query_data.state.clone(),
661        }
662    }
663
664    /// Invalidate this query in the background.
665    ///
666    /// For an `async` version use [UseQuery::invalidate_async].
667    pub fn invalidate(&self) {
668        let storage = consume_context::<QueriesStorage<Q>>();
669
670        let query = self.query.peek().clone();
671        let query_data = storage
672            .storage
673            .peek_unchecked()
674            .get(&query)
675            .cloned()
676            .unwrap();
677
678        // Run the query
679        spawn(async move { QueriesStorage::run_queries(&[(&query, &query_data)]).await });
680    }
681}
682
683/// Queries are used to get data asynchronously (e.g external resources such as HTTP APIs), which can later be cached or refreshed.
684///
685/// Important concepts:
686///
687/// ### Stale time
688/// This is how long will a value that is cached, considered to be recent enough.
689/// So in other words, if a value is stale it means that its outdated and therefore it should be refreshed.
690///
691/// By default the stale time is `0ms`, so if a value is cached and a new query subscriber
692/// is interested in this value, it will get refreshed automatically.
693///
694/// See [Query::stale_time].
695///
696/// ### Clean time
697/// This is how long will a value kept cached after there are no more subscribers of that query.
698///
699/// Imagine there is `Subscriber 1` of a query, the data is requested and cached.
700/// But after some seconds the `Subscriber 1` is unmounted, but the data is not cleared as the default clean time is `5min`.
701/// A few seconds later the `Subscriber 1` gets mounted again, it requests the data again but this time it is returned directly from the cache.
702///
703/// See [Query::clean_time].
704///
705/// ### Interval time
706/// This is how often do you want a query to be refreshed in the background automatically.
707/// By default it never refreshes automatically.
708///
709/// See [Query::interval_time].
710pub fn use_query<Q: QueryCapability>(query: Query<Q>) -> UseQuery<Q> {
711    let mut storage = match try_consume_context::<QueriesStorage<Q>>() {
712        Some(storage) => storage,
713        None => provide_root_context(QueriesStorage::<Q>::new_in_root()),
714    };
715
716    let mut make_query = |query: &Query<Q>, mut prev_query: Option<Query<Q>>| {
717        let query_data = storage.insert_or_get_query(query.clone());
718
719        // Update the query tasks if there has been a change in the query
720        if let Some(prev_query) = prev_query.take() {
721            storage.update_tasks(prev_query);
722        }
723
724        // Immediately run the query if enabled and the value is stale
725        if query.enabled && query_data.state.borrow().is_stale(query) {
726            let query = query.clone();
727            spawn(async move {
728                QueriesStorage::run_queries(&[(&query, &query_data)]).await;
729            });
730        }
731    };
732
733    let mut current_query = use_hook(|| {
734        make_query(&query, None);
735        Signal::new(query.clone())
736    });
737
738    if *current_query.read() != query {
739        let prev = mem::replace(&mut *current_query.write(), query.clone());
740        make_query(&query, Some(prev));
741    }
742
743    // Update the query tasks when the scope is dropped
744    use_drop({
745        move || {
746            storage.update_tasks(current_query.peek().clone());
747        }
748    });
749
750    UseQuery {
751        query: current_query,
752    }
753}