acme_proxy/cli/window.rs
1//! The `--limit`/`--offset` window every paged listing takes.
2//!
3//! Every listing in the binary pages — `account`, `order` (both queries),
4//! `audit`, `jobs`, `eab`, `upstream order`, `admin user` and `admin session` —
5//! and every one of them wants the same default, the same two clamps and the
6//! same envelope under `--json`. That envelope is
7//! [`crate::cli::render::json_page`]; this is the window that produced it.
8
9/// Default rows per page.
10///
11/// There is deliberately no "everything" spelling, and `--limit 0` is not a way
12/// around it: `orders` and `audit_log` each grow a row per issuance for the
13/// life of the deployment, so on a year-old CA an unwindowed listing is a
14/// terminal full of scrollback and a table loaded into memory. Page with
15/// `--offset`; the `N of M row(s)` footer is what says there is more.
16pub const DEFAULT_LIMIT: i64 = 50;
17
18/// A resolved window, clamped into something a query can be handed.
19#[derive(Debug, Clone, Copy, PartialEq, Eq)]
20pub struct Window {
21 pub limit: i64,
22 pub offset: i64,
23}
24
25impl Window {
26 /// Clamps a caller's window rather than refusing it.
27 ///
28 /// A `--limit 0` or a negative offset is nonsense rather than an attack, and
29 /// answering with the smallest usable page is more useful than an error;
30 /// passed through to SQL, `LIMIT -1` means *no limit* in SQLite, which is
31 /// the one answer a window must never accidentally give.
32 ///
33 /// Deliberately **not** clamped to `admin.page_size_max`: that key is a
34 /// ceiling on what an HTTP caller may ask the server for, and this front end
35 /// answers to a shell on the host. There is no upper bound on the offset
36 /// either, unlike `webadmin::handlers::paging`, because nothing here
37 /// computes `offset + limit` — a terminal has no "next page" link to place.
38 #[must_use]
39 pub fn resolve(limit: i64, offset: i64) -> Self {
40 Self {
41 limit: limit.max(1),
42 offset: offset.max(0),
43 }
44 }
45}
46
47#[cfg(test)]
48mod tests {
49 use super::*;
50
51 #[test]
52 fn a_nonsense_window_is_clamped_rather_than_refused() {
53 for (limit, expected) in [(50, 50), (1, 1), (0, 1), (-5, 1)] {
54 assert_eq!(Window::resolve(limit, 0).limit, expected, "limit={limit}");
55 }
56 for (offset, expected) in [(0, 0), (7, 7), (-7, 0)] {
57 assert_eq!(
58 Window::resolve(50, offset).offset,
59 expected,
60 "offset={offset}"
61 );
62 }
63 }
64}