Skip to main content

gluex_rcdb/
context.rs

1use std::ops::{Bound, RangeBounds};
2
3use gluex_core::{
4    constants::{MAX_RUN_NUMBER, MIN_RUN_NUMBER},
5    run_periods::RunPeriod,
6    RunNumber,
7};
8
9use crate::conditions::{Expr, IntoExprList};
10
11/// Describes how runs should be selected when fetching condition values.
12#[derive(Debug, Clone, PartialEq, Eq)]
13pub enum RunSelection {
14    /// Return conditions for every run stored in RCDB.
15    All,
16    /// Return conditions only for the exact run numbers in the list.
17    Runs(Vec<RunNumber>),
18    /// Return conditions for every run within the inclusive range.
19    Range {
20        /// Inclusive start run number.
21        start: RunNumber,
22        /// Inclusive end run number.
23        end: RunNumber,
24    },
25}
26
27impl RunSelection {
28    /// True when no runs will be returned.
29    #[must_use]
30    pub fn is_empty(&self) -> bool {
31        matches!(self, RunSelection::Runs(r) if r.is_empty())
32    }
33}
34
35/// Lightweight request context describing run selection.
36#[derive(Debug, Clone)]
37pub struct RCDBContext {
38    selection: RunSelection,
39    filters: Vec<Expr>,
40}
41
42impl Default for RCDBContext {
43    fn default() -> Self {
44        Self {
45            selection: RunSelection::All,
46            filters: Vec::new(),
47        }
48    }
49}
50
51impl RCDBContext {
52    /// Builds a context that selects every run.
53    #[must_use]
54    pub fn new() -> Self {
55        Self::default()
56    }
57
58    /// Restricts the context to a single run period.
59    #[must_use]
60    pub fn with_run_period(mut self, run_period: RunPeriod) -> Self {
61        self.selection = RunSelection::Range {
62            start: run_period.min_run(),
63            end: run_period.max_run(),
64        };
65        self
66    }
67
68    /// Restricts the context to a single run number.
69    #[must_use]
70    pub fn with_run(mut self, run: RunNumber) -> Self {
71        self.selection = RunSelection::Runs(vec![run]);
72        self
73    }
74
75    /// Restricts the context to the provided run numbers.
76    #[must_use]
77    pub fn with_runs(mut self, runs: impl IntoIterator<Item = RunNumber>) -> Self {
78        let mut run_list: Vec<RunNumber> = runs.into_iter().collect();
79        run_list.sort_unstable();
80        run_list.dedup();
81        self.selection = RunSelection::Runs(run_list);
82        self
83    }
84
85    /// Restricts the context to the inclusive range described by the [`RangeBounds`] passed as `run_range`.
86    #[must_use]
87    pub fn with_run_range(mut self, run_range: impl RangeBounds<RunNumber>) -> Self {
88        let start = match run_range.start_bound() {
89            Bound::Included(&s) => s,
90            Bound::Excluded(&s) => s.saturating_add(1),
91            Bound::Unbounded => MIN_RUN_NUMBER,
92        };
93        let end = match run_range.end_bound() {
94            Bound::Included(&e) => e,
95            Bound::Excluded(&e) => e.saturating_sub(1),
96            Bound::Unbounded => MAX_RUN_NUMBER,
97        };
98        if start > end {
99            self.selection = RunSelection::Runs(Vec::new());
100        } else {
101            self.selection = RunSelection::Range { start, end };
102        }
103        self
104    }
105
106    /// Adds one or more predicate expressions that must all evaluate to true.
107    #[must_use]
108    pub fn filter(mut self, filters: impl IntoExprList) -> Self {
109        self.filters.extend(filters.into_list());
110        self
111    }
112
113    /// Returns the run selection strategy for this context.
114    #[must_use]
115    pub fn selection(&self) -> &RunSelection {
116        &self.selection
117    }
118
119    /// Returns the [`RunNumber`] values when the context is scoped to explicit runs.
120    #[must_use]
121    pub fn runs(&self) -> Option<&[RunNumber]> {
122        if let RunSelection::Runs(runs) = &self.selection {
123            Some(runs)
124        } else {
125            None
126        }
127    }
128
129    /// Returns the current [`Expr`] filters specified by this context.
130    #[must_use]
131    pub fn filters(&self) -> &[Expr] {
132        &self.filters
133    }
134}