Skip to main content

sift_query_core/policy/
limits.rs

1use crate::ConfigError;
2
3/// Runtime query limits. Entity limits can only make paging values stricter.
4#[derive(Debug, Clone, PartialEq, Eq)]
5pub struct QueryLimits {
6    pub max_raw_query_bytes: usize,
7    pub max_raw_items: usize,
8    pub max_key_bytes: usize,
9    pub max_value_bytes: usize,
10    pub max_decoded_bytes: usize,
11    pub max_conditions: usize,
12    pub max_values_per_condition: usize,
13    pub max_logical_values: usize,
14    pub max_bind_slots: usize,
15    pub max_sort_fields: usize,
16    pub max_group_expr_bytes: usize,
17    pub max_group_depth: usize,
18    pub max_group_nodes: usize,
19    pub max_cursor_bytes: usize,
20    pub max_filter_steps: usize,
21    pub max_filter_items: usize,
22    pub max_filter_bytes: usize,
23    /// Total wall-clock budget for trusted synchronous filters; checked after each step.
24    pub max_filter_micros: u64,
25    pub max_page_size: u32,
26    pub max_offset: u64,
27    pub timeout_ms: u64,
28}
29
30impl Default for QueryLimits {
31    fn default() -> Self {
32        Self {
33            max_raw_query_bytes: 64 * 1024,
34            max_raw_items: 128,
35            max_key_bytes: 160,
36            max_value_bytes: 4 * 1024,
37            max_decoded_bytes: 256 * 1024,
38            max_conditions: 32,
39            max_values_per_condition: 100,
40            max_logical_values: 512,
41            max_bind_slots: 512,
42            max_sort_fields: 5,
43            max_group_expr_bytes: 256,
44            max_group_depth: 8,
45            max_group_nodes: 64,
46            max_cursor_bytes: 1024,
47            max_filter_steps: 8,
48            max_filter_items: 256,
49            max_filter_bytes: 512 * 1024,
50            max_filter_micros: 10_000,
51            max_page_size: 100,
52            max_offset: 20_000,
53            timeout_ms: 5_000,
54        }
55    }
56}
57
58/// Absolute library guardrails. Ordinary configuration cannot exceed these values.
59#[derive(Debug, Clone, Default, PartialEq, Eq)]
60pub struct QueryHardLimits(pub QueryLimits);
61
62pub(super) fn ensure_within_hard_limits(
63    limits: &QueryLimits,
64    hard: &QueryLimits,
65) -> Result<(), ConfigError> {
66    let within = limits.max_raw_query_bytes <= hard.max_raw_query_bytes
67        && limits.max_raw_items <= hard.max_raw_items
68        && limits.max_key_bytes <= hard.max_key_bytes
69        && limits.max_value_bytes <= hard.max_value_bytes
70        && limits.max_decoded_bytes <= hard.max_decoded_bytes
71        && limits.max_conditions <= hard.max_conditions
72        && limits.max_values_per_condition <= hard.max_values_per_condition
73        && limits.max_logical_values <= hard.max_logical_values
74        && limits.max_bind_slots <= hard.max_bind_slots
75        && limits.max_sort_fields <= hard.max_sort_fields
76        && limits.max_group_expr_bytes <= hard.max_group_expr_bytes
77        && limits.max_group_depth <= hard.max_group_depth
78        && limits.max_group_nodes <= hard.max_group_nodes
79        && limits.max_cursor_bytes <= hard.max_cursor_bytes
80        && limits.max_filter_steps <= hard.max_filter_steps
81        && limits.max_filter_items <= hard.max_filter_items
82        && limits.max_filter_bytes <= hard.max_filter_bytes
83        && limits.max_filter_micros <= hard.max_filter_micros
84        && limits.max_page_size <= hard.max_page_size
85        && limits.max_offset <= hard.max_offset
86        && limits.timeout_ms <= hard.timeout_ms;
87    if within {
88        Ok(())
89    } else {
90        Err(ConfigError::Invalid(
91            "ordinary policy cannot exceed hard limits".to_owned(),
92        ))
93    }
94}