Skip to main content

rustolio_web/hooks/
query.rs

1//
2// SPDX-License-Identifier: MPL-2.0
3//
4// Copyright (c) 2026 Tobias Binnewies. All rights reserved.
5//
6// This Source Code Form is subject to the terms of the Mozilla Public
7// License, v. 2.0. If a copy of the MPL was not distributed with this
8// file, You can obtain one at http://mozilla.org/MPL/2.0/.
9//
10
11use std::{rc::Rc, str::FromStr};
12
13use crate::prelude::*;
14
15use super::SignalBase;
16
17#[derive(Debug, PartialEq, Eq)]
18pub struct QuerySignal<T> {
19    key: Signal<Rc<str>>,
20    signal: Signal<T>,
21}
22
23// Impl `Clone` and `Copy` manually to avoid requiring `T: Clone + Copy`
24impl<T> Clone for QuerySignal<T> {
25    fn clone(&self) -> Self {
26        *self
27    }
28}
29impl<T> Copy for QuerySignal<T> {}
30
31impl<T> SignalBase<T> for QuerySignal<T> {
32    fn base(&self) -> Signal<T> {
33        self.signal.base()
34    }
35}
36impl<T> SignalGetter<T> for QuerySignal<T> where T: Clone + 'static {}
37impl<T> SignalSetter<T> for QuerySignal<T> where T: PartialEq + 'static {}
38impl<T> SignalUpdater<T> for QuerySignal<T> where T: 'static {}
39
40impl<T> QuerySignal<T> {
41    /// Removed the stored key-value pair from local storage.
42    /// It will be rewritten on the next signal update.
43    ///
44    /// The current signal value stays the same.
45    pub fn remove(&self) -> rustolio_utils::Result<()> {
46        url()?.search_params().delete(&self.key.peek());
47        Ok(())
48    }
49}
50
51impl<T> QuerySignal<T>
52where
53    T: ToString + FromStr + Clone + 'static,
54{
55    pub fn new(key: impl ToString, fallback: T) -> rustolio_utils::Result<Self> {
56        let key: Signal<Rc<str>> = Signal::new(key.to_string().into());
57
58        let stored_value = url()?
59            .search_params()
60            .get(&key.peek())
61            .and_then(|v| T::from_str(&v).ok())
62            .unwrap_or(fallback);
63
64        let signal = Signal::always_mutable(stored_value);
65        Effect::new_result(move || {
66            let key = key.peek();
67            let value = signal.value().to_string();
68
69            let url = url()?;
70            url.search_params().set(&key, &value);
71            url.push_to_history()?;
72
73            Ok(())
74        });
75
76        Ok(Self { signal, key })
77    }
78}