Skip to main content

vantage_vista/
query.rs

1//! [`VistaQuery`]: the clauses applied to a Vista, as a plain value.
2
3use ciborium::Value as CborValue;
4
5use crate::{filter::FilterOp, sort::SortDirection};
6
7mod key;
8
9/// `column <op> value`. Equality is [`FilterOp::Eq`].
10#[derive(Clone, Debug, PartialEq)]
11#[non_exhaustive]
12pub struct Condition {
13    pub column: String,
14    pub op: FilterOp,
15    pub value: CborValue,
16}
17
18impl Condition {
19    pub fn new(column: impl Into<String>, op: FilterOp, value: impl Into<CborValue>) -> Self {
20        Self {
21            column: column.into(),
22            op,
23            value: value.into(),
24        }
25    }
26}
27
28/// Every clause applied through a [`Vista`](crate::Vista): its conditions,
29/// search and order, plus the keys of its driver-native conditions
30/// ([`NativeCondition::key`](crate::NativeCondition::key)). A native
31/// condition itself is opaque, so only its key is recorded, and a
32/// `VistaQuery` that holds native keys can't be re-applied to another Vista.
33#[derive(Clone, Debug, Default, PartialEq)]
34#[non_exhaustive]
35pub struct VistaQuery {
36    pub conditions: Vec<Condition>,
37    pub search: Option<String>,
38    pub order: Option<(String, SortDirection)>,
39    pub native: Vec<String>,
40}
41
42impl VistaQuery {
43    pub fn new() -> Self {
44        Self::default()
45    }
46
47    pub fn with_condition(mut self, condition: Condition) -> Self {
48        self.conditions.push(condition);
49        self
50    }
51
52    pub fn with_search(mut self, text: impl Into<String>) -> Self {
53        self.search = Some(text.into());
54        self
55    }
56
57    pub fn with_order(mut self, column: impl Into<String>, dir: SortDirection) -> Self {
58        self.order = Some((column.into(), dir));
59        self
60    }
61
62    /// No clause of any kind, order included.
63    pub fn is_empty(&self) -> bool {
64        self.conditions.is_empty()
65            && self.search.is_none()
66            && self.order.is_none()
67            && self.native.is_empty()
68    }
69
70    /// Whether a clause limits which rows are in the set. Order doesn't.
71    pub(crate) fn narrows(&self) -> bool {
72        !self.conditions.is_empty() || self.search.is_some() || !self.native.is_empty()
73    }
74
75    /// A stable string identifying this query, for cache identity. The same
76    /// clauses give the same key whatever order the conditions (or native
77    /// conditions) were added in, and different clauses give different keys:
78    /// every part is length-prefixed and every value type-tagged, so no
79    /// column name, text or value can be mistaken for a separator. Combine it
80    /// with the Vista's name to key a cache across tables.
81    pub fn key(&self) -> String {
82        key::render(self)
83    }
84}