Skip to main content

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