drive/util/grove_operations/
mod.rs

1//! Grove Operations.
2//!
3//! Defines and implements in Drive functions pertinent to groveDB operations.
4//!
5
6/// Grove insert operation
7pub mod grove_insert;
8
9/// Grove insert operation into an empty tree
10pub mod grove_insert_empty_tree;
11
12/// Grove insert operation, but only if it doesn't already exist
13pub mod grove_insert_if_not_exists;
14
15/// Grove delete operation
16pub mod grove_delete;
17
18/// Fetch raw grove data
19pub mod grove_get_raw;
20
21/// Fetch raw grove data and match that is item
22pub mod grove_get_raw_item;
23
24/// Fetch raw grove data if it exists
25pub mod grove_get_raw_optional;
26
27/// Fetch u64 value from encoded variable vector in raw grove data
28pub mod grove_get_raw_value_u64_from_encoded_var_vec;
29
30/// Grove get operation
31pub mod grove_get;
32
33/// Serialized results from grove path query
34pub mod grove_get_path_query_serialized_results;
35
36/// Grove path query operation
37pub mod grove_get_path_query;
38
39/// Grove path query operation with optional return value
40pub mod grove_get_path_query_with_optional;
41
42/// Fetch raw data from grove path query with optional return value
43pub mod grove_get_raw_path_query_with_optional;
44
45/// Fetch raw data from grove path query
46pub mod grove_get_raw_path_query;
47
48/// Proved path query in grove
49pub mod grove_get_proved_path_query;
50
51/// V1 proved path query in grove (supports BulkAppendTree/CommitmentTree)
52pub mod grove_get_proved_path_query_v1;
53
54/// Get total count from a CommitmentTree
55pub mod grove_commitment_tree_count;
56
57/// Proved branch chunk query in grove
58pub mod grove_get_proved_branch_chunk_query;
59
60/// Proved trunk chunk query in grove
61pub mod grove_get_proved_trunk_chunk_query;
62
63/// Get total value from sum tree in grove
64pub mod grove_get_sum_tree_total_value;
65
66/// Check if raw data exists in grove
67pub mod grove_has_raw;
68
69/// Batch insert operation into empty tree
70pub mod batch_insert_empty_tree;
71
72/// Batch insert operation into empty sum tree
73pub mod batch_insert_empty_sum_tree;
74
75/// Batch insert operation into empty tree, but only if it doesn't already exist
76pub mod batch_insert_empty_tree_if_not_exists;
77
78/// Batch insert operation into empty tree, but only if it doesn't exist and check existing operations
79pub mod batch_insert_empty_tree_if_not_exists_check_existing_operations;
80
81/// Batch insert operation
82pub mod batch_insert;
83
84/// Batch replace operation
85pub mod batch_replace;
86
87/// Batch insert operation, but only if it doesn't already exist
88pub mod batch_insert_if_not_exists;
89
90/// Batch insert operation, but only if the value has changed
91pub mod batch_insert_if_changed_value;
92
93/// Batch delete operation
94pub mod batch_delete;
95
96/// Batch remove raw data operation
97pub mod batch_remove_raw;
98
99/// Batch delete operation up the tree while it's empty
100pub mod batch_delete_up_tree_while_empty;
101
102/// Batch refresh reference operation
103pub mod batch_refresh_reference;
104
105/// Apply grove operation
106pub mod grove_apply_operation;
107
108/// Apply batch grove operation
109pub mod grove_apply_batch;
110
111/// Apply batch grove operation with additional costs
112pub mod grove_apply_batch_with_add_costs;
113
114/// Apply partial batch grove operation
115pub mod grove_apply_partial_batch;
116
117/// Apply partial batch grove operation with additional costs
118pub mod grove_apply_partial_batch_with_add_costs;
119
120/// Get cost of grove batch operations
121pub mod grove_batch_operations_costs;
122
123/// Clear a subtree in grovedb
124pub mod grove_clear;
125
126/// Provides functionality to delete items in a path based on a query.
127pub mod batch_delete_items_in_path_query;
128
129/// Inserts an element if it does not exist and returns the existing element if it does.
130pub mod batch_insert_if_not_exists_return_existing_element;
131
132/// Inserts a sum item or adds to it if it already exists.
133pub mod batch_insert_sum_item_or_add_to_if_already_exists;
134
135/// Retrieves serialized or sum results from a path query in GroveDB.
136mod grove_get_path_query_serialized_or_sum_results;
137
138/// Executes a proved path query in GroveDB with an optional conditional query.
139pub mod grove_get_proved_path_query_with_conditional;
140
141/// Inserts an element if it does not exist and returns the existing element if it does in GroveDB.
142pub mod grove_insert_if_not_exists_return_existing_element;
143
144/// Batch inserts sum item if not already existing
145pub mod batch_insert_sum_item_if_not_exists;
146/// Moved items that are found in a path query to a new path.
147pub mod batch_move_items_in_path_query;
148
149/// Batch inserts item with sum item if not already existing
150pub mod batch_insert_item_with_sum_item_if_not_exists;
151/// Keeps the item, but inserts or adds to the sum item if it already exists
152pub mod batch_keep_item_insert_sum_item_or_add_to_if_already_exists;
153mod batch_move;
154/// Get the total value from a big sum tree
155pub mod grove_get_big_sum_tree_total_value;
156/// Get total value from sum tree in grove if it exists
157pub mod grove_get_optional_sum_tree_total_value;
158/// Fetch raw grove data if it exists, None otherwise
159pub mod grove_get_raw_optional_item;
160
161use grovedb_costs::CostContext;
162
163use grovedb::{EstimatedLayerInformation, MaybeTree, TreeType};
164
165use crate::error::Error;
166use crate::fees::op::LowLevelDriveOperation;
167use crate::fees::op::LowLevelDriveOperation::CalculatedCostOperation;
168
169use grovedb::Error as GroveError;
170
171use intmap::IntMap;
172
173/// Pushes an operation's `OperationCost` to `drive_operations` given its `CostContext`
174/// and returns the operation's return value.
175fn push_drive_operation_result<T>(
176    cost_context: CostContext<Result<T, GroveError>>,
177    drive_operations: &mut Vec<LowLevelDriveOperation>,
178) -> Result<T, Error> {
179    let CostContext { value, cost } = cost_context;
180    if !cost.is_nothing() {
181        drive_operations.push(CalculatedCostOperation(cost));
182    }
183    value.map_err(Error::from)
184}
185
186/// Pushes an operation's `OperationCost` to `drive_operations` given its `CostContext`
187/// if `drive_operations` is given. Returns the operation's return value.
188fn push_drive_operation_result_optional<T>(
189    cost_context: CostContext<Result<T, GroveError>>,
190    drive_operations: Option<&mut Vec<LowLevelDriveOperation>>,
191) -> Result<T, Error> {
192    let CostContext { value, cost } = cost_context;
193    if let Some(drive_operations) = drive_operations {
194        drive_operations.push(CalculatedCostOperation(cost));
195    }
196    value.map_err(Error::from)
197}
198/// Is subtree?
199pub type IsSubTree = bool;
200/// Is sum subtree?
201pub type IsSumSubTree = bool;
202/// Is sum tree?
203pub type IsSumTree = bool;
204
205/// Batch delete apply type
206#[derive(Debug, Copy, Clone)]
207pub enum BatchDeleteApplyType {
208    /// Stateless batch delete
209    StatelessBatchDelete {
210        /// Are we deleting in a sum tree
211        in_tree_type: TreeType,
212        /// What is the estimated key size
213        estimated_key_size: u32,
214        /// What is the estimated value size
215        estimated_value_size: u32,
216    },
217    /// Stateful batch delete
218    StatefulBatchDelete {
219        /// Are we known to be in a subtree and does this subtree have sums
220        is_known_to_be_subtree_with_sum: Option<MaybeTree>,
221    },
222}
223
224/// Batch move apply type
225#[derive(Debug, Copy, Clone)]
226pub enum BatchMoveApplyType {
227    /// Stateless batch move
228    StatelessBatchMove {
229        /// What type of tree are we in for the move
230        in_tree_type: TreeType,
231        /// Are we moving a trees?
232        tree_type: Option<TreeType>,
233        /// What is the estimated key size
234        estimated_key_size: u32,
235        /// What is the estimated value size
236        estimated_value_size: u32,
237        /// The flags length
238        flags_len: FlagsLen,
239    },
240    /// Stateful batch move
241    StatefulBatchMove {
242        /// Are we known to be in a subtree and does this subtree have sums
243        is_known_to_be_subtree_with_sum: Option<MaybeTree>,
244    },
245}
246
247#[derive(Clone)]
248/// Batch delete up tree apply type
249pub enum BatchDeleteUpTreeApplyType {
250    /// Stateless batch delete
251    StatelessBatchDelete {
252        /// The estimated layer info
253        estimated_layer_info: IntMap<u16, EstimatedLayerInformation>,
254    },
255    /// Stateful batch delete
256    StatefulBatchDelete {
257        /// Are we known to be in a subtree and does this subtree have sums
258        is_known_to_be_subtree_with_sum: Option<MaybeTree>,
259    },
260}
261
262/// batch insert tree apply type
263#[derive(Clone, Copy)]
264/// Batch insert tree apply type
265pub enum BatchInsertTreeApplyType {
266    /// Stateless batch insert tree
267    StatelessBatchInsertTree {
268        /// Does this tree use sums?
269        in_tree_type: TreeType,
270        /// Are we inserting in a sum tree
271        tree_type: TreeType,
272        /// The flags length
273        flags_len: FlagsLen,
274    },
275    /// Stateful batch insert tree
276    StatefulBatchInsertTree,
277}
278
279/// Represents the types for batch insert operations in a tree structure.
280impl BatchInsertTreeApplyType {
281    /// Converts the current `BatchInsertTreeApplyType` into a corresponding `DirectQueryType`.
282    ///
283    /// # Returns
284    ///
285    /// - A variant of `DirectQueryType::StatelessDirectQuery` if the current type is `BatchInsertTreeApplyType::StatelessBatchInsertTree`.
286    /// - `DirectQueryType::StatefulDirectQuery` if the current type is `BatchInsertTreeApplyType::StatefulBatchInsertTree`.
287    /// ```
288    pub(crate) fn to_direct_query_type(self) -> DirectQueryType {
289        match self {
290            BatchInsertTreeApplyType::StatelessBatchInsertTree {
291                in_tree_type,
292                tree_type,
293                flags_len,
294            } => DirectQueryType::StatelessDirectQuery {
295                in_tree_type,
296                query_target: QueryTarget::QueryTargetTree(flags_len, tree_type),
297            },
298            BatchInsertTreeApplyType::StatefulBatchInsertTree => {
299                DirectQueryType::StatefulDirectQuery
300            }
301        }
302    }
303}
304
305/// Batch insert apply type
306#[derive(Clone, Copy)]
307pub enum BatchInsertApplyType {
308    /// Stateless batch insert
309    StatelessBatchInsert {
310        /// Does this tree use sums?
311        in_tree_type: TreeType,
312        /// the type of Target (Tree or Value)
313        target: QueryTarget,
314    },
315    /// Stateful batch insert
316    StatefulBatchInsert,
317}
318
319impl BatchInsertApplyType {
320    /// Converts the current `BatchInsertApplyType` into a corresponding `DirectQueryType`.
321    ///
322    /// # Returns
323    ///
324    /// - A variant of `DirectQueryType::StatelessDirectQuery` if the current type is `BatchInsertApplyType::StatelessBatchInsert`.
325    /// - `DirectQueryType::StatefulDirectQuery` if the current type is `BatchInsertApplyType::StatefulBatchInsert`.
326    /// ```
327    // TODO: Not using
328    #[allow(dead_code)]
329    #[allow(clippy::wrong_self_convention)]
330    pub(crate) fn to_direct_query_type(&self) -> DirectQueryType {
331        match self {
332            BatchInsertApplyType::StatelessBatchInsert {
333                in_tree_type: in_tree_using_sums,
334                target,
335            } => DirectQueryType::StatelessDirectQuery {
336                in_tree_type: *in_tree_using_sums,
337                query_target: *target,
338            },
339            BatchInsertApplyType::StatefulBatchInsert => DirectQueryType::StatefulDirectQuery,
340        }
341    }
342}
343
344/// Flags length
345pub type FlagsLen = u32;
346
347/// query target
348#[derive(Clone, Copy)]
349/// Query target
350pub enum QueryTarget {
351    /// tree
352    QueryTargetTree(FlagsLen, TreeType),
353    /// value
354    QueryTargetValue(u32),
355}
356
357impl QueryTarget {
358    /// Length
359    pub(crate) fn len(&self) -> u32 {
360        match self {
361            QueryTarget::QueryTargetTree(flags_len, tree_type) => {
362                *flags_len + tree_type.inner_node_type().cost() + 3
363            }
364            QueryTarget::QueryTargetValue(len) => *len,
365        }
366    }
367}
368
369/// direct query type
370#[derive(Clone, Copy)]
371/// Direct query type
372pub enum DirectQueryType {
373    /// Stateless direct query
374    StatelessDirectQuery {
375        /// Does this tree use sums?
376        in_tree_type: TreeType,
377        /// the type of Target (Tree or Value)
378        query_target: QueryTarget,
379    },
380    /// Stateful direct query
381    StatefulDirectQuery,
382}
383
384impl From<DirectQueryType> for QueryType {
385    fn from(value: DirectQueryType) -> Self {
386        match value {
387            DirectQueryType::StatelessDirectQuery {
388                in_tree_type,
389                query_target,
390            } => QueryType::StatelessQuery {
391                in_tree_type,
392                query_target,
393                estimated_reference_sizes: vec![],
394            },
395            DirectQueryType::StatefulDirectQuery => QueryType::StatefulQuery,
396        }
397    }
398}
399
400impl DirectQueryType {
401    /// Converts the current `DirectQueryType` into a corresponding `QueryType`
402    /// while associating it with the given reference sizes.
403    ///
404    /// # Parameters
405    ///
406    /// * `reference_sizes`: A vector of `u32` values representing the reference sizes
407    ///   associated with the query.
408    ///
409    /// # Returns
410    ///
411    /// - A variant of `QueryType::StatelessQuery` with the provided reference sizes if
412    ///   the current type is `DirectQueryType::StatelessDirectQuery`.
413    /// - `QueryType::StatefulQuery` if the current type is `DirectQueryType::StatefulDirectQuery`.
414    ///
415    /// # Example
416    ///
417    /// ```ignore
418    /// let direct_query = DirectQueryType::StatelessDirectQuery {
419    ///     in_tree_using_sums: true,
420    ///     query_target: SomeTarget, // Replace with an actual target instance.
421    /// };
422    ///
423    /// let ref_sizes = vec![100, 200, 300];
424    /// let query_type = direct_query.add_reference_sizes(ref_sizes);
425    /// ```
426    #[allow(dead_code)]
427    #[deprecated(note = "This function is marked as unused.")]
428    #[allow(deprecated)]
429    pub(crate) fn add_reference_sizes(self, reference_sizes: Vec<u32>) -> QueryType {
430        match self {
431            DirectQueryType::StatelessDirectQuery {
432                in_tree_type: in_tree_using_sums,
433                query_target,
434            } => QueryType::StatelessQuery {
435                in_tree_type: in_tree_using_sums,
436                query_target,
437                estimated_reference_sizes: reference_sizes,
438            },
439            DirectQueryType::StatefulDirectQuery => QueryType::StatefulQuery,
440        }
441    }
442}
443
444/// Query type
445#[derive(Clone)]
446pub enum QueryType {
447    /// Stateless query
448    StatelessQuery {
449        /// Does this tree use sums?
450        in_tree_type: TreeType,
451        /// the type of Target (Tree or Value)
452        query_target: QueryTarget,
453        /// The estimated sizes of references
454        estimated_reference_sizes: Vec<u32>,
455    },
456    /// Stateful query
457    StatefulQuery,
458}
459
460impl From<BatchDeleteApplyType> for QueryType {
461    fn from(value: BatchDeleteApplyType) -> Self {
462        match value {
463            BatchDeleteApplyType::StatelessBatchDelete {
464                in_tree_type: is_sum_tree,
465                estimated_value_size,
466                ..
467            } => QueryType::StatelessQuery {
468                in_tree_type: is_sum_tree,
469                query_target: QueryTarget::QueryTargetValue(estimated_value_size),
470                estimated_reference_sizes: vec![],
471            },
472            BatchDeleteApplyType::StatefulBatchDelete { .. } => QueryType::StatefulQuery,
473        }
474    }
475}
476
477impl From<&BatchDeleteApplyType> for QueryType {
478    fn from(value: &BatchDeleteApplyType) -> Self {
479        match value {
480            BatchDeleteApplyType::StatelessBatchDelete {
481                in_tree_type: is_sum_tree,
482                estimated_value_size,
483                ..
484            } => QueryType::StatelessQuery {
485                in_tree_type: *is_sum_tree,
486                query_target: QueryTarget::QueryTargetValue(*estimated_value_size),
487                estimated_reference_sizes: vec![],
488            },
489            BatchDeleteApplyType::StatefulBatchDelete { .. } => QueryType::StatefulQuery,
490        }
491    }
492}
493
494impl From<BatchDeleteApplyType> for DirectQueryType {
495    fn from(value: BatchDeleteApplyType) -> Self {
496        match value {
497            BatchDeleteApplyType::StatelessBatchDelete {
498                in_tree_type: is_sum_tree,
499                estimated_value_size,
500                ..
501            } => DirectQueryType::StatelessDirectQuery {
502                in_tree_type: is_sum_tree,
503                query_target: QueryTarget::QueryTargetValue(estimated_value_size),
504            },
505            BatchDeleteApplyType::StatefulBatchDelete { .. } => {
506                DirectQueryType::StatefulDirectQuery
507            }
508        }
509    }
510}
511
512impl From<&BatchDeleteApplyType> for DirectQueryType {
513    fn from(value: &BatchDeleteApplyType) -> Self {
514        match value {
515            BatchDeleteApplyType::StatelessBatchDelete {
516                in_tree_type: is_sum_tree,
517                estimated_value_size,
518                ..
519            } => DirectQueryType::StatelessDirectQuery {
520                in_tree_type: *is_sum_tree,
521                query_target: QueryTarget::QueryTargetValue(*estimated_value_size),
522            },
523            BatchDeleteApplyType::StatefulBatchDelete { .. } => {
524                DirectQueryType::StatefulDirectQuery
525            }
526        }
527    }
528}
529
530/// Specifies which GroveDB instance to use for a query
531#[derive(Debug, Clone, Copy, PartialEq, Eq)]
532pub enum GroveDBToUse {
533    /// Use the current (main) GroveDB
534    Current,
535    /// Use the latest checkpoint
536    LatestCheckpoint,
537    /// Use a specific checkpoint at the given block height
538    Checkpoint(u64),
539}