Skip to main content

drive/query/drive_document_sum_query/executors/
total.rs

1//! Total-sum executor for [`super::super::DocumentSumMode::Total`]
2//! dispatch — `prove = false` sum queries without a range clause.
3//!
4//! Mirror of count's `executors/total.rs` with the substitutions
5//! documented in `executors/mod.rs` (count → sum, u64 → i64,
6//! count_value_or_default → sum_value_or_default).
7
8use super::super::index_picker::find_summable_index_for_where_clauses;
9use super::super::{DriveDocumentSumQuery, SumEntry};
10use crate::drive::Drive;
11use crate::error::query::QuerySyntaxError;
12use crate::error::Error;
13use crate::query::WhereClause;
14use dpp::data_contract::document_type::DocumentTypeRef;
15use dpp::version::PlatformVersion;
16use grovedb::TransactionArg;
17
18impl Drive {
19    /// Total sum for the given where clauses against an exactly-
20    /// covering summable index, OR — when the where clauses are
21    /// empty and the document type has `documents_summable: Some(_)`
22    /// — the type's primary-key SumTree (O(1) read at the doctype
23    /// tree's root).
24    ///
25    /// Single summed entry with empty key.
26    #[allow(clippy::too_many_arguments)]
27    pub fn execute_document_sum_total_no_proof(
28        &self,
29        contract_id: [u8; 32],
30        document_type: DocumentTypeRef,
31        document_type_name: String,
32        where_clauses: Vec<WhereClause>,
33        sum_property: String,
34        transaction: TransactionArg,
35        platform_version: &PlatformVersion,
36    ) -> Result<Vec<SumEntry>, Error> {
37        use dpp::data_contract::document_type::accessors::{
38            DocumentTypeV0Getters, DocumentTypeV2Getters,
39        };
40
41        // Fast path: unfiltered total sum on a `documents_summable:
42        // Some(matching_property)` doctype reads the primary-key
43        // SumTree directly (O(1)). No index needed — the doctype tree
44        // itself carries the sum.
45        if where_clauses.is_empty()
46            && document_type
47                .documents_summable()
48                .map(|p| p == sum_property)
49                .unwrap_or(false)
50        {
51            let sum = self.read_primary_key_sum_tree(
52                &contract_id,
53                &document_type_name,
54                transaction,
55                platform_version,
56            )?;
57            return Ok(vec![SumEntry {
58                in_key: None,
59                key: vec![],
60                sum: Some(sum),
61            }]);
62        }
63
64        let index = find_summable_index_for_where_clauses(
65            document_type.indexes(),
66            &where_clauses,
67            &sum_property,
68        )
69        .ok_or_else(|| {
70            Error::Query(QuerySyntaxError::WhereClauseOnNonIndexedProperty(
71                "sum query requires a `summable: \"<prop>\"` index whose properties \
72                 exactly match the where clause fields and whose summed property \
73                 matches the request's `sum_property`, or `documentsSummable: \
74                 \"<prop>\"` on the document type for unfiltered total sums"
75                    .to_string(),
76            ))
77        })?;
78        let sum_query = DriveDocumentSumQuery {
79            document_type,
80            contract_id,
81            document_type_name,
82            index,
83            where_clauses,
84            sum_property,
85        };
86        sum_query.execute_no_proof(self, transaction, platform_version)
87    }
88
89    /// Reads the document-type primary-key tree's `SumTree` element
90    /// (`[contract_doc, contract_id, [1], doctype, 0]`) and returns
91    /// `sum_value_or_default()`. Used by the `documents_summable:
92    /// Some(_)` fast path on the total-sum flow.
93    ///
94    /// `insert_contract_operations_v0` unconditionally creates a
95    /// sum-bearing tree at `[..., doctype, 0]` for every applied
96    /// document type whose `documents_summable` is set, so a missing
97    /// element here indicates contract-state corruption or a
98    /// mis-applied contract — fail fast rather than silently
99    /// returning 0.
100    pub(super) fn read_primary_key_sum_tree(
101        &self,
102        contract_id: &[u8; 32],
103        document_type_name: &str,
104        transaction: TransactionArg,
105        platform_version: &PlatformVersion,
106    ) -> Result<i64, Error> {
107        let drive_version = &platform_version.drive;
108        let path = [
109            &[crate::drive::RootTree::DataContractDocuments as u8] as &[u8],
110            contract_id,
111            &[1u8],
112            document_type_name.as_bytes(),
113        ];
114        let mut drive_operations = vec![];
115        let element = self
116            .grove_get_raw_optional(
117                grovedb_path::SubtreePath::from(path.as_slice()),
118                &[0],
119                crate::util::grove_operations::DirectQueryType::StatefulDirectQuery,
120                transaction,
121                &mut drive_operations,
122                drive_version,
123            )?
124            .ok_or_else(|| {
125                Error::Drive(crate::error::drive::DriveError::CorruptedCodeExecution(
126                    "missing primary-key sum tree for an applied document type — \
127                     insert_contract_operations_v0 must have created it",
128                ))
129            })?;
130        Ok(element.sum_value_or_default())
131    }
132}