drive/query/
vote_poll_contestant_votes_query.rs

1#[cfg(feature = "verify")]
2use super::ContractLookupFn;
3use crate::drive::votes::paths::VotePollPaths;
4#[cfg(any(feature = "server", feature = "verify"))]
5use crate::drive::votes::resolved::vote_polls::contested_document_resource_vote_poll::resolve::ContestedDocumentResourceVotePollResolver;
6use crate::drive::votes::resolved::vote_polls::contested_document_resource_vote_poll::ContestedDocumentResourceVotePollWithContractInfoAllowBorrowed;
7#[cfg(feature = "server")]
8use crate::drive::Drive;
9use crate::error::Error;
10#[cfg(feature = "server")]
11use crate::fees::op::LowLevelDriveOperation;
12#[cfg(feature = "server")]
13use crate::query::GroveError;
14use crate::query::Query;
15use bincode::{Decode, Encode};
16#[cfg(feature = "server")]
17use dpp::block::block_info::BlockInfo;
18use dpp::identifier::Identifier;
19#[cfg(feature = "server")]
20use dpp::platform_value;
21use dpp::voting::vote_choices::resource_vote_choice::ResourceVoteChoice::TowardsIdentity;
22use dpp::voting::vote_polls::contested_document_resource_vote_poll::ContestedDocumentResourceVotePoll;
23#[cfg(feature = "server")]
24use grovedb::query_result_type::{QueryResultElements, QueryResultType};
25#[cfg(feature = "server")]
26use grovedb::TransactionArg;
27use grovedb::{PathQuery, SizedQuery};
28use platform_version::version::PlatformVersion;
29
30/// Vote Poll Drive Query struct
31#[derive(Debug, PartialEq, Clone, Encode, Decode)]
32pub struct ContestedDocumentVotePollVotesDriveQuery {
33    /// What vote poll are we asking for?
34    pub vote_poll: ContestedDocumentResourceVotePoll,
35    /// Which contestant do we want to get the votes for
36    pub contestant_id: Identifier,
37    /// Offset
38    pub offset: Option<u16>,
39    /// Limit
40    pub limit: Option<u16>,
41    /// Start at identity id
42    pub start_at: Option<([u8; 32], bool)>,
43    /// Ascending
44    pub order_ascending: bool,
45}
46
47impl ContestedDocumentVotePollVotesDriveQuery {
48    #[cfg(feature = "server")]
49    /// Resolves the contested document vote poll drive query.
50    ///
51    /// This method processes the query by interacting with the drive, using the provided
52    /// transaction and platform version to ensure consistency and compatibility.
53    ///
54    /// # Parameters
55    ///
56    /// * `drive`: A reference to the `Drive` object used for database interactions.
57    /// * `transaction`: The transaction argument used to ensure consistency during the resolve operation.
58    /// * `platform_version`: The platform version to ensure compatibility.
59    ///
60    /// # Returns
61    ///
62    /// * `Ok(ResolvedContestedDocumentVotePollDriveQuery)` - The resolved query information.
63    /// * `Err(Error)` - An error if the resolution process fails.
64    ///
65    /// # Errors
66    ///
67    /// This method returns an `Error` variant if there is an issue resolving the query.
68    /// The specific error depends on the underlying problem encountered during resolution.
69    pub fn resolve(
70        &self,
71        drive: &Drive,
72        transaction: TransactionArg,
73        platform_version: &PlatformVersion,
74    ) -> Result<ResolvedContestedDocumentVotePollVotesDriveQuery<'_>, Error> {
75        let ContestedDocumentVotePollVotesDriveQuery {
76            vote_poll,
77            contestant_id,
78            offset,
79            limit,
80            start_at,
81            order_ascending,
82        } = self;
83        Ok(ResolvedContestedDocumentVotePollVotesDriveQuery {
84            vote_poll: vote_poll.resolve_allow_borrowed(drive, transaction, platform_version)?,
85            contestant_id: *contestant_id,
86            offset: *offset,
87            limit: *limit,
88            start_at: *start_at,
89            order_ascending: *order_ascending,
90        })
91    }
92
93    /// Resolves the contested document vote poll drive query.
94    ///
95    /// See [ContestedDocumentVotePollVotesDriveQuery::resolve](ContestedDocumentVotePollVotesDriveQuery::resolve) for more information.
96    #[cfg(feature = "verify")]
97    pub fn resolve_with_known_contracts_provider<'a>(
98        &self,
99        known_contracts_provider: &ContractLookupFn,
100    ) -> Result<ResolvedContestedDocumentVotePollVotesDriveQuery<'a>, Error> {
101        let ContestedDocumentVotePollVotesDriveQuery {
102            vote_poll,
103            contestant_id,
104            offset,
105            limit,
106            start_at,
107            order_ascending,
108        } = self;
109        Ok(ResolvedContestedDocumentVotePollVotesDriveQuery {
110            vote_poll: vote_poll.resolve_with_known_contracts_provider(known_contracts_provider)?,
111            contestant_id: *contestant_id,
112            offset: *offset,
113            limit: *limit,
114            start_at: *start_at,
115            order_ascending: *order_ascending,
116        })
117    }
118
119    #[cfg(feature = "server")]
120    /// Executes a query with proof and returns the items and fee.
121    pub fn execute_with_proof(
122        self,
123        drive: &Drive,
124        block_info: Option<BlockInfo>,
125        transaction: TransactionArg,
126        platform_version: &PlatformVersion,
127    ) -> Result<(Vec<u8>, u64), Error> {
128        let mut drive_operations = vec![];
129        let items = self.execute_with_proof_internal(
130            drive,
131            transaction,
132            &mut drive_operations,
133            platform_version,
134        )?;
135        let cost = if let Some(block_info) = block_info {
136            let fee_result = Drive::calculate_fee(
137                None,
138                Some(drive_operations),
139                &block_info.epoch,
140                drive.config.epochs_per_era,
141                platform_version,
142                None,
143            )?;
144            fee_result.processing_fee
145        } else {
146            0
147        };
148        Ok((items, cost))
149    }
150
151    #[cfg(feature = "server")]
152    /// Executes an internal query with proof and returns the items.
153    pub(crate) fn execute_with_proof_internal(
154        self,
155        drive: &Drive,
156        transaction: TransactionArg,
157        drive_operations: &mut Vec<LowLevelDriveOperation>,
158        platform_version: &PlatformVersion,
159    ) -> Result<Vec<u8>, Error> {
160        let resolved = self.resolve(drive, transaction, platform_version)?;
161        let path_query = resolved.construct_path_query(platform_version)?;
162        drive.grove_get_proved_path_query(
163            &path_query,
164            transaction,
165            drive_operations,
166            &platform_version.drive,
167        )
168    }
169
170    #[cfg(feature = "server")]
171    /// Executes a query with no proof and returns the items, skipped items, and fee.
172    pub fn execute_no_proof_with_cost(
173        &self,
174        drive: &Drive,
175        block_info: Option<BlockInfo>,
176        transaction: TransactionArg,
177        platform_version: &PlatformVersion,
178    ) -> Result<(Vec<Identifier>, u64), Error> {
179        let mut drive_operations = vec![];
180        let result =
181            self.execute_no_proof(drive, transaction, &mut drive_operations, platform_version)?;
182        let cost = if let Some(block_info) = block_info {
183            let fee_result = Drive::calculate_fee(
184                None,
185                Some(drive_operations),
186                &block_info.epoch,
187                drive.config.epochs_per_era,
188                platform_version,
189                None,
190            )?;
191            fee_result.processing_fee
192        } else {
193            0
194        };
195        Ok((result, cost))
196    }
197
198    #[cfg(feature = "server")]
199    /// Executes an internal query with no proof and returns the values and skipped items.
200    pub fn execute_no_proof(
201        &self,
202        drive: &Drive,
203        transaction: TransactionArg,
204        drive_operations: &mut Vec<LowLevelDriveOperation>,
205        platform_version: &PlatformVersion,
206    ) -> Result<Vec<Identifier>, Error> {
207        let resolved = self.resolve(drive, transaction, platform_version)?;
208        let path_query = resolved.construct_path_query(platform_version)?;
209        let query_result = drive.grove_get_path_query(
210            &path_query,
211            transaction,
212            QueryResultType::QueryPathKeyElementTrioResultType,
213            drive_operations,
214            &platform_version.drive,
215        );
216        match query_result {
217            Err(Error::GroveDB(e))
218                if matches!(
219                    e.as_ref(),
220                    GroveError::PathKeyNotFound(_)
221                        | GroveError::PathNotFound(_)
222                        | GroveError::PathParentLayerNotFound(_)
223                ) =>
224            {
225                Ok(vec![])
226            }
227            Err(e) => Err(e),
228            Ok((query_result_elements, _skipped)) => {
229                let voters = query_result_elements
230                    .to_keys()
231                    .into_iter()
232                    .map(Identifier::try_from)
233                    .collect::<Result<Vec<Identifier>, platform_value::Error>>()?;
234
235                Ok(voters)
236            }
237        }
238    }
239
240    #[cfg(feature = "server")]
241    #[allow(unused)]
242    /// Executes an internal query with no proof and returns the values and skipped items.
243    pub(crate) fn execute_no_proof_internal(
244        &self,
245        drive: &Drive,
246        result_type: QueryResultType,
247        transaction: TransactionArg,
248        drive_operations: &mut Vec<LowLevelDriveOperation>,
249        platform_version: &PlatformVersion,
250    ) -> Result<(QueryResultElements, u16), Error> {
251        let resolved = self.resolve(drive, transaction, platform_version)?;
252        let path_query = resolved.construct_path_query(platform_version)?;
253        let query_result = drive.grove_get_path_query(
254            &path_query,
255            transaction,
256            result_type,
257            drive_operations,
258            &platform_version.drive,
259        );
260        match query_result {
261            Err(Error::GroveDB(e))
262                if matches!(
263                    e.as_ref(),
264                    GroveError::PathKeyNotFound(_)
265                        | GroveError::PathNotFound(_)
266                        | GroveError::PathParentLayerNotFound(_)
267                ) =>
268            {
269                Ok((QueryResultElements::new(), 0))
270            }
271            _ => {
272                let (data, skipped) = query_result?;
273                {
274                    Ok((data, skipped))
275                }
276            }
277        }
278    }
279}
280/// Vote Poll Drive Query struct
281#[derive(Debug, PartialEq, Clone)]
282pub struct ResolvedContestedDocumentVotePollVotesDriveQuery<'a> {
283    /// What vote poll are we asking for?
284    pub vote_poll: ContestedDocumentResourceVotePollWithContractInfoAllowBorrowed<'a>,
285    /// Who's votes are we looking for
286    pub contestant_id: Identifier,
287    /// Offset
288    pub offset: Option<u16>,
289    /// Limit
290    pub limit: Option<u16>,
291    /// Start at identity id, the bool is if it is also included
292    pub start_at: Option<([u8; 32], bool)>,
293    /// Ascending
294    pub order_ascending: bool,
295}
296
297impl ResolvedContestedDocumentVotePollVotesDriveQuery<'_> {
298    /// Operations to construct a path query.
299    pub fn construct_path_query(
300        &self,
301        platform_version: &PlatformVersion,
302    ) -> Result<PathQuery, Error> {
303        let path = self
304            .vote_poll
305            .contender_voting_path(&TowardsIdentity(self.contestant_id), platform_version)?;
306
307        let mut query = Query::new_with_direction(self.order_ascending);
308
309        // this is a range on all elements
310        match &self.start_at {
311            None => {
312                query.insert_all();
313            }
314            Some((starts_at_key_bytes, start_at_included)) => {
315                let starts_at_key = starts_at_key_bytes.to_vec();
316                match self.order_ascending {
317                    true => match start_at_included {
318                        true => query.insert_range_from(starts_at_key..),
319                        false => query.insert_range_after(starts_at_key..),
320                    },
321                    false => match start_at_included {
322                        true => query.insert_range_to_inclusive(..=starts_at_key),
323                        false => query.insert_range_to(..starts_at_key),
324                    },
325                }
326            }
327        }
328
329        Ok(PathQuery {
330            path,
331            query: SizedQuery {
332                query,
333                limit: self.limit,
334                offset: self.offset,
335            },
336        })
337    }
338}