Skip to main content

ic_query/sns/report/model/requests/proposals/
mod.rs

1//! Module: sns::report::model::requests::proposals
2//!
3//! Responsibility: request DTOs for SNS proposal reports.
4//! Does not own: command option parsing, live proposal fetches, or rendering.
5//! Boundary: carries validated proposal inputs into SNS report builders.
6
7use super::lookup::SnsLookupRequest;
8use crate::report::SortDirection;
9use crate::sns::report::{
10    SnsProposalEligibilityFilter, SnsProposalStatusFilter, SnsProposalTopicFilter, SnsProposalsSort,
11};
12use std::path::{Path, PathBuf};
13use thiserror::Error as ThisError;
14
15///
16/// SnsProposalCollection
17///
18/// Acquisition route for a bounded live proposal view or a complete-cache view.
19///
20
21#[derive(Clone, Debug, Eq, PartialEq)]
22pub enum SnsProposalCollection {
23    /// One bounded Governance response.
24    Live,
25    /// Complete snapshot, refreshing only when absent under the existing policy.
26    Cached {
27        /// Caller-selected managed cache root.
28        cache_root: PathBuf,
29    },
30}
31
32///
33/// SnsProposalViewError
34///
35/// A caller selected a filter requiring complete cached proposal evidence.
36///
37
38#[derive(Clone, Copy, Debug, Eq, PartialEq, ThisError)]
39#[error("`--status decided` requires a complete proposal cache")]
40pub struct SnsProposalViewError;
41
42///
43/// SnsProposalRequest
44///
45/// Request accepted by the direct SNS proposal detail report builder.
46///
47
48#[derive(Clone, Debug, Eq, PartialEq)]
49pub struct SnsProposalRequest {
50    /// SNS target, explicit endpoint, network and caller clock.
51    pub lookup: SnsLookupRequest,
52    pub proposal_id: u64,
53    pub cache_root: Option<PathBuf>,
54}
55
56impl SnsProposalRequest {
57    #[must_use]
58    pub const fn new(lookup: SnsLookupRequest, proposal_id: u64) -> Self {
59        Self {
60            lookup,
61            proposal_id,
62            cache_root: None,
63        }
64    }
65}
66
67///
68/// SnsProposalsRequest
69///
70/// Request accepted by the bounded SNS proposal listing report builder.
71///
72
73#[derive(Clone, Debug, Eq, PartialEq)]
74pub struct SnsProposalsRequest {
75    /// SNS target, explicit endpoint, network and caller clock.
76    pub lookup: SnsLookupRequest,
77    pub limit: u32,
78    pub before_proposal_id: Option<u64>,
79    status: SnsProposalStatusFilter,
80    pub topic: SnsProposalTopicFilter,
81    pub eligibility: SnsProposalEligibilityFilter,
82    pub proposer_neuron_id: Option<String>,
83    pub query: Option<String>,
84    pub sort: SnsProposalsSort,
85    pub sort_direction: SortDirection,
86    collection: SnsProposalCollection,
87}
88
89impl SnsProposalsRequest {
90    #[must_use]
91    pub fn new(lookup: SnsLookupRequest, limit: u32) -> Self {
92        Self {
93            lookup,
94            limit,
95            before_proposal_id: None,
96            status: SnsProposalStatusFilter::default(),
97            topic: SnsProposalTopicFilter::default(),
98            eligibility: SnsProposalEligibilityFilter::default(),
99            proposer_neuron_id: None,
100            query: None,
101            sort: SnsProposalsSort::default(),
102            sort_direction: SortDirection::default(),
103            collection: SnsProposalCollection::Live,
104        }
105    }
106
107    /// Admit a status filter for the selected acquisition route.
108    pub fn with_status(
109        mut self,
110        status: SnsProposalStatusFilter,
111    ) -> Result<Self, SnsProposalViewError> {
112        if status == SnsProposalStatusFilter::Decided
113            && matches!(self.collection, SnsProposalCollection::Live)
114        {
115            return Err(SnsProposalViewError);
116        }
117        self.status = status;
118        Ok(self)
119    }
120
121    #[must_use]
122    pub const fn with_sort(mut self, sort: SnsProposalsSort) -> Self {
123        self.sort = sort;
124        self.sort_direction = sort.default_direction();
125        self
126    }
127
128    #[must_use]
129    pub fn with_cache_root(mut self, cache_root: impl Into<PathBuf>) -> Self {
130        self.collection = SnsProposalCollection::Cached {
131            cache_root: cache_root.into(),
132        };
133        self
134    }
135
136    /// Admitted acquisition route.
137    #[must_use]
138    pub const fn collection(&self) -> &SnsProposalCollection {
139        &self.collection
140    }
141
142    /// Caller-selected status admitted for this acquisition route.
143    #[must_use]
144    pub const fn status(&self) -> SnsProposalStatusFilter {
145        self.status
146    }
147
148    /// Root for complete-cache views, absent for bounded live acquisition.
149    #[must_use]
150    pub fn cache_root(&self) -> Option<&Path> {
151        match &self.collection {
152            SnsProposalCollection::Live => None,
153            SnsProposalCollection::Cached { cache_root } => Some(cache_root),
154        }
155    }
156}
157
158#[cfg(test)]
159mod tests;