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