tablo_test/protocol/ignored.rs
1//! Reads a table's ignored-filters banner: each entry's `data-ignored-filter` names the filter as
2//! the request spelled it, and its `data-ignored` names why.
3
4use tablo_core::dom::ignored;
5
6use super::dom::{attr_value, tags_where};
7
8/// A requested filter the table did not apply.
9#[derive(Debug, Clone, PartialEq, Eq)]
10pub struct IgnoredFilter {
11 /// The filter's parameters as the request spelled them, such as `f.status=draft`.
12 pub filter: String,
13 /// Why the table ignored it.
14 pub reason: IgnoredReason,
15}
16
17/// Why a table ignored a requested filter, as the banner's `data-ignored` names it.
18#[derive(Debug, Clone, Copy, PartialEq, Eq)]
19#[non_exhaustive]
20pub enum IgnoredReason {
21 /// The table declares no filter of that name.
22 Unknown,
23 /// The filter selects nothing by the value, or refuses it, as it refuses a key naming a
24 /// record the user may not see: the two read alike.
25 Invalid,
26 /// The request carried more filters, values or bytes than the table reads.
27 Dropped,
28}
29
30/// The filters the banner of `html` lists as ignored, in its order; empty without a banner.
31///
32/// # Panics
33///
34/// When an entry names no reason this version knows: a renderer that drops `data-ignored`'s
35/// value would otherwise read as any reason.
36pub fn ignored_filters(html: &str) -> Vec<IgnoredFilter> {
37 tags_where(html, |_, attrs| {
38 attr_value(attrs, "data-ignored-filter").is_some()
39 })
40 .into_iter()
41 .filter_map(|(_, attrs, _)| {
42 let filter = attr_value(&attrs, "data-ignored-filter")?;
43 let reason = match attr_value(&attrs, "data-ignored").as_deref() {
44 Some(ignored::UNKNOWN) => IgnoredReason::Unknown,
45 Some(ignored::INVALID) => IgnoredReason::Invalid,
46 Some(ignored::DROPPED) => IgnoredReason::Dropped,
47 other => panic!("the ignored filter names no known reason: {other:?}"),
48 };
49 Some(IgnoredFilter { filter, reason })
50 })
51 .collect()
52}