diff --git a/grovedb/src/element/mod.rs b/grovedb/src/element/mod.rs index a5573b4d..c71bb52f 100644 --- a/grovedb/src/element/mod.rs +++ b/grovedb/src/element/mod.rs @@ -45,6 +45,8 @@ mod insert; #[cfg(any(feature = "full", feature = "verify"))] mod query; #[cfg(any(feature = "full", feature = "verify"))] +pub use query::QueryOptions; +#[cfg(any(feature = "full", feature = "verify"))] mod serialize; #[cfg(feature = "full")] use core::fmt; diff --git a/grovedb/src/element/query.rs b/grovedb/src/element/query.rs index cc914949..eba5ae1f 100644 --- a/grovedb/src/element/query.rs +++ b/grovedb/src/element/query.rs @@ -59,7 +59,7 @@ use crate::{ #[cfg(any(feature = "full", feature = "verify"))] use crate::{Element, SizedQuery}; -#[cfg(feature = "full")] +#[cfg(any(feature = "full", feature = "verify"))] #[derive(Copy, Clone, Debug)] pub struct QueryOptions { pub allow_get_raw: bool, @@ -71,6 +71,19 @@ pub struct QueryOptions { /// sub elements have no matches, hence the limit would not decrease and /// hence we would continue on the increasingly expensive query. pub decrease_limit_on_range_with_no_sub_elements: bool, + pub error_if_intermediate_path_tree_not_present: bool, +} + +#[cfg(any(feature = "full", feature = "verify"))] +impl Default for QueryOptions { + fn default() -> Self { + QueryOptions { + allow_get_raw: false, + allow_cache: true, + decrease_limit_on_range_with_no_sub_elements: true, + error_if_intermediate_path_tree_not_present: true, + } + } } #[cfg(feature = "full")] @@ -101,6 +114,7 @@ impl Element { storage: &RocksDbStorage, merk_path: &[&[u8]], query: &Query, + query_options: QueryOptions, result_type: QueryResultType, transaction: TransactionArg, ) -> CostResult { @@ -109,8 +123,7 @@ impl Element { storage, merk_path, &sized_query, - true, - true, + query_options, result_type, transaction, ) @@ -123,12 +136,14 @@ impl Element { storage: &RocksDbStorage, merk_path: &[&[u8]], query: &Query, + query_options: QueryOptions, transaction: TransactionArg, ) -> CostResult, Error> { Element::get_query( storage, merk_path, query, + query_options, QueryElementResultType, transaction, ) @@ -226,39 +241,7 @@ impl Element { pub fn get_path_query( storage: &RocksDbStorage, path_query: &PathQuery, - allow_cache: bool, - decrease_limit_on_range_with_no_sub_elements: bool, - result_type: QueryResultType, - transaction: TransactionArg, - ) -> CostResult<(QueryResultElements, u16), Error> { - let path_slices = path_query - .path - .iter() - .map(|x| x.as_slice()) - .collect::>(); - Element::get_query_apply_function( - storage, - path_slices.as_slice(), - &path_query.query, - QueryOptions { - allow_get_raw: false, - allow_cache, - decrease_limit_on_range_with_no_sub_elements, - }, - result_type, - transaction, - Element::path_query_push, - ) - } - - #[cfg(feature = "full")] - /// Returns a vector of elements including trees, and the number of skipped - /// elements - pub fn get_raw_path_query( - storage: &RocksDbStorage, - path_query: &PathQuery, - allow_cache: bool, - decrease_limit_on_range_with_no_sub_elements: bool, + query_options: QueryOptions, result_type: QueryResultType, transaction: TransactionArg, ) -> CostResult<(QueryResultElements, u16), Error> { @@ -271,11 +254,7 @@ impl Element { storage, path_slices.as_slice(), &path_query.query, - QueryOptions { - allow_get_raw: true, - allow_cache, - decrease_limit_on_range_with_no_sub_elements, - }, + query_options, result_type, transaction, Element::path_query_push, @@ -288,8 +267,7 @@ impl Element { storage: &RocksDbStorage, path: &[&[u8]], sized_query: &SizedQuery, - allow_cache: bool, - decrease_limit_on_range_with_no_sub_elements: bool, + query_options: QueryOptions, result_type: QueryResultType, transaction: TransactionArg, ) -> CostResult<(QueryResultElements, u16), Error> { @@ -297,11 +275,7 @@ impl Element { storage, path, sized_query, - QueryOptions { - allow_get_raw: false, - allow_cache, - decrease_limit_on_range_with_no_sub_elements, - }, + query_options, result_type, transaction, Element::path_query_push, @@ -332,6 +306,7 @@ impl Element { allow_get_raw, allow_cache, decrease_limit_on_range_with_no_sub_elements, + .. } = query_options; if element.is_tree() { let mut path_vec = path.to_vec(); @@ -357,8 +332,7 @@ impl Element { Element::get_path_query( storage, &inner_path_query, - allow_cache, - decrease_limit_on_range_with_no_sub_elements, + query_options, result_type, transaction ) @@ -605,7 +579,7 @@ impl Element { Ok(element) => { let (subquery_path, subquery) = Self::subquery_paths_and_value_for_sized_query(sized_query, key); - add_element_function(PathQueryPushArgs { + match add_element_function(PathQueryPushArgs { storage, transaction, key: Some(key.as_slice()), @@ -621,9 +595,31 @@ impl Element { offset, }) .unwrap_add_cost(&mut cost) + { + Ok(_) => Ok(()), + Err(e) => { + if !query_options.error_if_intermediate_path_tree_not_present { + match e { + Error::PathParentLayerNotFound(_) => Ok(()), + _ => Err(e), + } + } else { + Err(e) + } + } + } } Err(Error::PathKeyNotFound(_)) => Ok(()), - Err(e) => Err(e), + Err(e) => { + if !query_options.error_if_intermediate_path_tree_not_present { + match e { + Error::PathParentLayerNotFound(_) => Ok(()), + _ => Err(e), + } + } else { + Err(e) + } + } } } else { Err(Error::InternalError( @@ -657,24 +653,36 @@ impl Element { .expect("key should exist"); let (subquery_path, subquery) = Self::subquery_paths_and_value_for_sized_query(sized_query, key); - cost_return_on_error!( - &mut cost, - add_element_function(PathQueryPushArgs { - storage, - transaction, - key: Some(key), - element, - path, - subquery_path, - subquery, - left_to_right: sized_query.query.left_to_right, - query_options, - result_type, - results, - limit, - offset, - }) - ); + let result_with_cost = add_element_function(PathQueryPushArgs { + storage, + transaction, + key: Some(key), + element, + path, + subquery_path, + subquery, + left_to_right: sized_query.query.left_to_right, + query_options, + result_type, + results, + limit, + offset, + }); + let result = result_with_cost.unwrap_add_cost(&mut cost); + match result { + Ok(x) => x, + Err(e) => { + if !query_options.error_if_intermediate_path_tree_not_present { + match e { + Error::PathKeyNotFound(_) + | Error::PathParentLayerNotFound(_) => (), + _ => return Err(e).wrap_with_cost(cost), + } + } else { + return Err(e).wrap_with_cost(cost); + } + } + } if sized_query.query.left_to_right { iter.next().unwrap_add_cost(&mut cost); } else { @@ -750,7 +758,7 @@ mod tests { use grovedb_storage::{Storage, StorageBatch}; use crate::{ - element::*, + element::{query::QueryOptions, *}, query_result_type::{ KeyElementPair, QueryResultElement, QueryResultElements, QueryResultType::{QueryKeyElementPairResultType, QueryPathKeyElementTrioResultType}, @@ -806,7 +814,7 @@ mod tests { query.insert_key(b"a".to_vec()); assert_eq!( - Element::get_query_values(&db.db, &[TEST_LEAF], &query, None) + Element::get_query_values(&db.db, &[TEST_LEAF], &query, QueryOptions::default(), None) .unwrap() .expect("expected successful get_query"), vec![ @@ -820,7 +828,7 @@ mod tests { query.insert_range(b"b".to_vec()..b"d".to_vec()); query.insert_range(b"a".to_vec()..b"c".to_vec()); assert_eq!( - Element::get_query_values(&db.db, &[TEST_LEAF], &query, None) + Element::get_query_values(&db.db, &[TEST_LEAF], &query, QueryOptions::default(), None) .unwrap() .expect("expected successful get_query"), vec![ @@ -835,7 +843,7 @@ mod tests { query.insert_range_inclusive(b"b".to_vec()..=b"d".to_vec()); query.insert_range(b"b".to_vec()..b"c".to_vec()); assert_eq!( - Element::get_query_values(&db.db, &[TEST_LEAF], &query, None) + Element::get_query_values(&db.db, &[TEST_LEAF], &query, QueryOptions::default(), None) .unwrap() .expect("expected successful get_query"), vec![ @@ -851,7 +859,7 @@ mod tests { query.insert_range(b"b".to_vec()..b"d".to_vec()); query.insert_range(b"a".to_vec()..b"c".to_vec()); assert_eq!( - Element::get_query_values(&db.db, &[TEST_LEAF], &query, None) + Element::get_query_values(&db.db, &[TEST_LEAF], &query, QueryOptions::default(), None) .unwrap() .expect("expected successful get_query"), vec![ @@ -912,6 +920,7 @@ mod tests { &db.db, &[TEST_LEAF], &query, + QueryOptions::default(), QueryPathKeyElementTrioResultType, None ) @@ -975,8 +984,7 @@ mod tests { storage, &[TEST_LEAF], &ascending_query, - true, - true, + QueryOptions::default(), QueryKeyElementPairResultType, None, ) @@ -1010,8 +1018,7 @@ mod tests { storage, &[TEST_LEAF], &backwards_query, - true, - true, + QueryOptions::default(), QueryKeyElementPairResultType, None, ) @@ -1100,8 +1107,7 @@ mod tests { storage, &[TEST_LEAF], &ascending_query, - true, - true, + QueryOptions::default(), QueryKeyElementPairResultType, None, ) @@ -1118,8 +1124,7 @@ mod tests { storage, &[TEST_LEAF], &backwards_query, - true, - true, + QueryOptions::default(), QueryKeyElementPairResultType, None, ) @@ -1139,8 +1144,7 @@ mod tests { storage, &[TEST_LEAF], &backwards_query, - true, - true, + QueryOptions::default(), QueryKeyElementPairResultType, None, ) @@ -1202,8 +1206,7 @@ mod tests { &db.db, &[TEST_LEAF], &backwards_query, - true, - true, + QueryOptions::default(), QueryKeyElementPairResultType, None, ) @@ -1229,8 +1232,7 @@ mod tests { &db.db, &[TEST_LEAF], &backwards_query, - true, - true, + QueryOptions::default(), QueryKeyElementPairResultType, None, ) @@ -1251,8 +1253,7 @@ mod tests { &db.db, &[TEST_LEAF], &limit_query, - true, - true, + QueryOptions::default(), QueryKeyElementPairResultType, None, ) @@ -1273,8 +1274,7 @@ mod tests { &db.db, &[TEST_LEAF], &limit_query, - true, - true, + QueryOptions::default(), QueryKeyElementPairResultType, None, ) @@ -1294,8 +1294,7 @@ mod tests { &db.db, &[TEST_LEAF], &limit_offset_query, - true, - true, + QueryOptions::default(), QueryKeyElementPairResultType, None, ) @@ -1320,8 +1319,7 @@ mod tests { &db.db, &[TEST_LEAF], &limit_offset_backwards_query, - true, - true, + QueryOptions::default(), QueryKeyElementPairResultType, None, ) @@ -1345,8 +1343,7 @@ mod tests { &db.db, &[TEST_LEAF], &limit_full_query, - true, - true, + QueryOptions::default(), QueryKeyElementPairResultType, None, ) @@ -1371,8 +1368,7 @@ mod tests { &db.db, &[TEST_LEAF], &limit_offset_backwards_query, - true, - true, + QueryOptions::default(), QueryKeyElementPairResultType, None, ) @@ -1397,8 +1393,7 @@ mod tests { &db.db, &[TEST_LEAF], &limit_backwards_query, - true, - true, + QueryOptions::default(), QueryKeyElementPairResultType, None, ) diff --git a/grovedb/src/operations/get/query.rs b/grovedb/src/operations/get/query.rs index deef7437..29a581d9 100644 --- a/grovedb/src/operations/get/query.rs +++ b/grovedb/src/operations/get/query.rs @@ -36,7 +36,7 @@ use grovedb_costs::{ #[cfg(feature = "full")] use integer_encoding::VarInt; -use crate::query_result_type::PathKeyOptionalElementTrio; +use crate::{element::QueryOptions, query_result_type::PathKeyOptionalElementTrio}; #[cfg(feature = "full")] use crate::{ query_result_type::{QueryResultElement, QueryResultElements, QueryResultType}, @@ -52,6 +52,7 @@ impl GroveDb { path_queries: &[&PathQuery], allow_cache: bool, decrease_limit_on_range_with_no_sub_elements: bool, + error_if_intermediate_path_tree_not_present: bool, transaction: TransactionArg, ) -> CostResult>, Error> { let mut cost = OperationCost::default(); @@ -62,6 +63,7 @@ impl GroveDb { path_queries, allow_cache, decrease_limit_on_range_with_no_sub_elements, + error_if_intermediate_path_tree_not_present, QueryResultType::QueryElementResultType, transaction ) @@ -112,6 +114,7 @@ impl GroveDb { path_queries: &[&PathQuery], allow_cache: bool, decrease_limit_on_range_with_no_sub_elements: bool, + error_if_intermediate_path_tree_not_present: bool, result_type: QueryResultType, transaction: TransactionArg, ) -> CostResult @@ -125,6 +128,7 @@ where { &query, allow_cache, decrease_limit_on_range_with_no_sub_elements, + error_if_intermediate_path_tree_not_present, result_type, transaction ) @@ -199,6 +203,7 @@ where { path_query: &PathQuery, allow_cache: bool, decrease_limit_on_range_with_no_sub_elements: bool, + error_if_intermediate_path_tree_not_present: bool, result_type: QueryResultType, transaction: TransactionArg, ) -> CostResult<(QueryResultElements, u16), Error> { @@ -210,6 +215,7 @@ where { path_query, allow_cache, decrease_limit_on_range_with_no_sub_elements, + error_if_intermediate_path_tree_not_present, result_type, transaction ) @@ -235,6 +241,7 @@ where { path_query: &PathQuery, allow_cache: bool, decrease_limit_on_range_with_no_sub_elements: bool, + error_if_intermediate_path_tree_not_present: bool, transaction: TransactionArg, ) -> CostResult<(Vec>, u16), Error> { let mut cost = OperationCost::default(); @@ -245,6 +252,7 @@ where { path_query, allow_cache, decrease_limit_on_range_with_no_sub_elements, + error_if_intermediate_path_tree_not_present, QueryResultType::QueryElementResultType, transaction ) @@ -307,6 +315,7 @@ where { path_query: &PathQuery, allow_cache: bool, decrease_limit_on_range_with_no_sub_elements: bool, + error_if_intermediate_path_tree_not_present: bool, transaction: TransactionArg, ) -> CostResult<(Vec, u16), Error> { let mut cost = OperationCost::default(); @@ -317,6 +326,7 @@ where { path_query, allow_cache, decrease_limit_on_range_with_no_sub_elements, + error_if_intermediate_path_tree_not_present, QueryResultType::QueryElementResultType, transaction ) @@ -381,14 +391,19 @@ where { path_query: &PathQuery, allow_cache: bool, decrease_limit_on_range_with_no_sub_elements: bool, + error_if_intermediate_path_tree_not_present: bool, result_type: QueryResultType, transaction: TransactionArg, ) -> CostResult<(QueryResultElements, u16), Error> { - Element::get_raw_path_query( + Element::get_path_query( &self.db, path_query, - allow_cache, - decrease_limit_on_range_with_no_sub_elements, + QueryOptions { + allow_get_raw: true, + allow_cache, + decrease_limit_on_range_with_no_sub_elements, + error_if_intermediate_path_tree_not_present, + }, result_type, transaction, ) @@ -401,6 +416,7 @@ where { path_query: &PathQuery, allow_cache: bool, decrease_limit_on_range_with_no_sub_elements: bool, + error_if_intermediate_path_tree_not_present: bool, transaction: TransactionArg, ) -> CostResult, Error> { let max_results = cost_return_on_error_default!(path_query.query.limit.ok_or( @@ -423,6 +439,7 @@ where { path_query, allow_cache, decrease_limit_on_range_with_no_sub_elements, + error_if_intermediate_path_tree_not_present, QueryResultType::QueryPathKeyElementTrioResultType, transaction ) @@ -446,6 +463,7 @@ where { path_query: &PathQuery, allow_cache: bool, decrease_limit_on_range_with_no_sub_elements: bool, + error_if_intermediate_path_tree_not_present: bool, transaction: TransactionArg, ) -> CostResult, Error> { let max_results = cost_return_on_error_default!(path_query.query.limit.ok_or( @@ -468,6 +486,7 @@ where { path_query, allow_cache, decrease_limit_on_range_with_no_sub_elements, + error_if_intermediate_path_tree_not_present, QueryResultType::QueryPathKeyElementTrioResultType, transaction ) @@ -539,7 +558,7 @@ mod tests { let path = vec![TEST_LEAF.to_vec()]; let path_query = PathQuery::new(path.clone(), SizedQuery::new(query, Some(5), None)); let raw_result = db - .query_raw_keys_optional(&path_query, true, true, None) + .query_raw_keys_optional(&path_query, true, true, true, None) .unwrap() .expect("should get successfully"); @@ -595,7 +614,7 @@ mod tests { let path = vec![TEST_LEAF.to_vec()]; let path_query = PathQuery::new(path.clone(), SizedQuery::new(query, Some(5), None)); let raw_result = db - .query_raw_keys_optional(&path_query, true, true, None) + .query_raw_keys_optional(&path_query, true, true, true, None) .unwrap() .expect("should get successfully"); @@ -652,7 +671,7 @@ mod tests { let path = vec![TEST_LEAF.to_vec()]; let path_query = PathQuery::new(path.clone(), SizedQuery::new(query, Some(5), None)); let raw_result = db - .query_raw_keys_optional(&path_query, true, true, None) + .query_raw_keys_optional(&path_query, true, true, true, None) .unwrap() .expect("should get successfully"); @@ -720,7 +739,7 @@ mod tests { let path = vec![TEST_LEAF.to_vec()]; let path_query = PathQuery::new(path, SizedQuery::new(query, Some(4), None)); - db.query_raw_keys_optional(&path_query, true, true, None) + db.query_raw_keys_optional(&path_query, true, true, true, None) .unwrap() .expect_err("range a should error"); @@ -729,7 +748,7 @@ mod tests { query.insert_key(b"5".to_vec()); // 3 let path = vec![TEST_LEAF.to_vec()]; let path_query = PathQuery::new(path, SizedQuery::new(query, Some(3), None)); - db.query_raw_keys_optional(&path_query, true, true, None) + db.query_raw_keys_optional(&path_query, true, true, true, None) .unwrap() .expect("range b should not error"); @@ -738,7 +757,7 @@ mod tests { query.insert_key(b"5".to_vec()); // 4 let path = vec![TEST_LEAF.to_vec()]; let path_query = PathQuery::new(path, SizedQuery::new(query, Some(3), None)); - db.query_raw_keys_optional(&path_query, true, true, None) + db.query_raw_keys_optional(&path_query, true, true, true, None) .unwrap() .expect_err("range c should error"); @@ -747,7 +766,7 @@ mod tests { query.insert_key(b"5".to_vec()); // 3 let path = vec![TEST_LEAF.to_vec()]; let path_query = PathQuery::new(path, SizedQuery::new(query, Some(2), None)); - db.query_raw_keys_optional(&path_query, true, true, None) + db.query_raw_keys_optional(&path_query, true, true, true, None) .unwrap() .expect_err("range d should error"); @@ -755,7 +774,7 @@ mod tests { query.insert_range(b"z".to_vec()..b"10".to_vec()); let path = vec![TEST_LEAF.to_vec()]; let path_query = PathQuery::new(path, SizedQuery::new(query, Some(1000), None)); - db.query_raw_keys_optional(&path_query, true, true, None) + db.query_raw_keys_optional(&path_query, true, true, true, None) .unwrap() .expect_err("range using 2 bytes should error"); } @@ -806,7 +825,7 @@ mod tests { let path = vec![TEST_LEAF.to_vec()]; let path_query = PathQuery::new(path.clone(), SizedQuery::new(query, Some(1000), None)); let raw_result = db - .query_raw_keys_optional(&path_query, true, true, None) + .query_raw_keys_optional(&path_query, true, true, true, None) .unwrap() .expect("range starting with null should not error"); @@ -889,7 +908,7 @@ mod tests { query.insert_range(b"".to_vec()..b"c".to_vec()); let path = vec![TEST_LEAF.to_vec()]; let path_query = PathQuery::new(path, SizedQuery::new(query, Some(1000), None)); - db.query_keys_optional(&path_query, true, true, None) + db.query_keys_optional(&path_query, true, true, true, None) .unwrap() .expect_err("range should error because we didn't subquery"); @@ -899,7 +918,7 @@ mod tests { let path = vec![TEST_LEAF.to_vec()]; let path_query = PathQuery::new(path, SizedQuery::new(query, Some(1000), None)); let raw_result = db - .query_raw_keys_optional(&path_query, true, true, None) + .query_raw_keys_optional(&path_query, true, true, true, None) .unwrap() .expect("query with subquery should not error"); @@ -1007,7 +1026,7 @@ mod tests { let path = vec![TEST_LEAF.to_vec()]; let path_query = PathQuery::new(path, SizedQuery::new(query, Some(1000), None)); let raw_result = db - .query_raw_keys_optional(&path_query, true, true, None) + .query_raw_keys_optional(&path_query, true, true, true, None) .unwrap() .expect("query with subquery should not error"); @@ -1057,6 +1076,187 @@ mod tests { ); // because we didn't query for it } + #[test] + fn test_query_raw_keys_options_with_subquery_having_intermediate_paths_missing() { + let db = make_test_grovedb(); + + db.insert([TEST_LEAF].as_ref(), b"", Element::empty_tree(), None, None) + .unwrap() + .expect("should insert subtree successfully"); + db.insert( + [TEST_LEAF].as_ref(), + b"1", + Element::empty_tree(), + None, + None, + ) + .unwrap() + .expect("should insert subtree successfully"); + db.insert( + [TEST_LEAF].as_ref(), + b"2", + Element::empty_tree(), + None, + None, + ) + .unwrap() + .expect("should insert subtree successfully"); + db.insert( + [TEST_LEAF].as_ref(), + b"3", + Element::empty_tree(), + None, + None, + ) + .unwrap() + .expect("should insert subtree successfully"); + db.insert( + [TEST_LEAF, b"1"].as_ref(), + b"deep_1", + Element::empty_tree(), + None, + None, + ) + .unwrap() + .expect("should insert subtree successfully"); + db.insert( + [TEST_LEAF, b"1", b"deep_1"].as_ref(), + b"deeper_1", + Element::empty_tree(), + None, + None, + ) + .unwrap() + .expect("should insert subtree successfully"); + db.insert( + [TEST_LEAF, b"1", b"deep_1", b"deeper_1"].as_ref(), + b"2", + Element::new_item(b"found_me".to_vec()), + None, + None, + ) + .unwrap() + .expect("should insert subtree successfully"); + db.insert( + [TEST_LEAF, b"2"].as_ref(), + b"1", + Element::new_item(b"1 in 2".to_vec()), + None, + None, + ) + .unwrap() + .expect("should insert subtree successfully"); + db.insert( + [TEST_LEAF, b"2"].as_ref(), + b"5", + Element::new_item(b"5 in 2".to_vec()), + None, + None, + ) + .unwrap() + .expect("should insert subtree successfully"); + db.insert( + [TEST_LEAF, b"2"].as_ref(), + b"2", + Element::new_item(b"2 in 2".to_vec()), + None, + None, + ) + .unwrap() + .expect("should insert subtree successfully"); + + let mut sub_query = Query::new(); + sub_query.insert_key(b"1".to_vec()); + sub_query.insert_key(b"2".to_vec()); + let mut query = Query::new(); + query.insert_keys(vec![b"1".to_vec(), b"2".to_vec(), b"3".to_vec()]); + query.set_subquery_path(vec![b"deep_1".to_vec(), b"deeper_1".to_vec()]); + query.set_subquery(sub_query); + let path = vec![TEST_LEAF.to_vec()]; + let path_query = PathQuery::new(path, SizedQuery::new(query, Some(1000), None)); + + let raw_result = db + .query_raw_keys_optional(&path_query, true, true, true, None) + .unwrap() + .expect_err( + "query with subquery should error if error_if_intermediate_path_tree_not_present \ + is set to true", + ); + + let raw_result = db + .query_raw_keys_optional(&path_query, true, true, false, None) + .unwrap() + .expect("query with subquery should not error"); + + // because is 99 ascii, and we have empty too = 100 then x 2 + assert_eq!(raw_result.len(), 6); + + let expected_result = vec![ + ( + vec![ + b"test_leaf".to_vec(), + b"1".to_vec(), + b"deep_1".to_vec(), + b"deeper_1".to_vec(), + ], + b"1".to_vec(), + None, + ), + ( + vec![ + b"test_leaf".to_vec(), + b"1".to_vec(), + b"deep_1".to_vec(), + b"deeper_1".to_vec(), + ], + b"2".to_vec(), + Some(Element::new_item(b"found_me".to_vec())), + ), + ( + vec![ + b"test_leaf".to_vec(), + b"2".to_vec(), + b"deep_1".to_vec(), + b"deeper_1".to_vec(), + ], + b"1".to_vec(), + None, + ), + ( + vec![ + b"test_leaf".to_vec(), + b"2".to_vec(), + b"deep_1".to_vec(), + b"deeper_1".to_vec(), + ], + b"2".to_vec(), + None, + ), + ( + vec![ + b"test_leaf".to_vec(), + b"3".to_vec(), + b"deep_1".to_vec(), + b"deeper_1".to_vec(), + ], + b"1".to_vec(), + None, + ), + ( + vec![ + b"test_leaf".to_vec(), + b"3".to_vec(), + b"deep_1".to_vec(), + b"deeper_1".to_vec(), + ], + b"2".to_vec(), + None, + ), + ]; + + assert_eq!(raw_result, expected_result); + } + #[test] fn test_query_raw_keys_options_with_subquery_and_subquery_path() { let db = make_test_grovedb(); @@ -1155,7 +1355,7 @@ mod tests { let path = vec![TEST_LEAF.to_vec()]; let path_query = PathQuery::new(path, SizedQuery::new(query, Some(1000), None)); let raw_result = db - .query_raw_keys_optional(&path_query, true, true, None) + .query_raw_keys_optional(&path_query, true, true, true, None) .unwrap() .expect("query with subquery should not error"); @@ -1322,7 +1522,7 @@ mod tests { let path = vec![TEST_LEAF.to_vec()]; let path_query = PathQuery::new(path, SizedQuery::new(query, Some(1000), None)); let raw_result = db - .query_raw_keys_optional(&path_query, true, true, None) + .query_raw_keys_optional(&path_query, true, true, true, None) .unwrap() .expect("query with subquery should not error"); @@ -1502,7 +1702,7 @@ mod tests { let path = vec![TEST_LEAF.to_vec()]; let path_query = PathQuery::new(path, SizedQuery::new(query, Some(1000), None)); let result = db - .query_keys_optional(&path_query, true, true, None) + .query_keys_optional(&path_query, true, true, true, None) .unwrap() .expect("query with subquery should not error"); diff --git a/grovedb/src/query/mod.rs b/grovedb/src/query/mod.rs index 1b72e274..db75144d 100644 --- a/grovedb/src/query/mod.rs +++ b/grovedb/src/query/mod.rs @@ -536,6 +536,7 @@ mod tests { &merged_path_query, true, true, + true, QueryResultType::QueryPathKeyElementTrioResultType, None, ) @@ -829,6 +830,7 @@ mod tests { &merged_path_query, true, true, + true, QueryResultType::QueryPathKeyElementTrioResultType, None, ) diff --git a/grovedb/src/reference_path.rs b/grovedb/src/reference_path.rs index 2b9fb7ed..52f07eb8 100644 --- a/grovedb/src/reference_path.rs +++ b/grovedb/src/reference_path.rs @@ -387,7 +387,7 @@ mod tests { let path_query = PathQuery::new_unsized(vec![TEST_LEAF.to_vec(), b"innertree4".to_vec()], query); let result = db - .query_item_value(&path_query, true, true, None) + .query_item_value(&path_query, true, true, true, None) .unwrap() .expect("should query items"); assert_eq!(result.0.len(), 5); diff --git a/grovedb/src/tests/mod.rs b/grovedb/src/tests/mod.rs index 3d905224..09a38e6b 100644 --- a/grovedb/src/tests/mod.rs +++ b/grovedb/src/tests/mod.rs @@ -541,7 +541,14 @@ fn test_element_with_flags() { SizedQuery::new(query, None, None), ); let (flagged_ref_no_follow, _) = db - .query_raw(&path_query, true, true, QueryKeyElementPairResultType, None) + .query_raw( + &path_query, + true, + true, + true, + QueryKeyElementPairResultType, + None, + ) .unwrap() .expect("should get successfully"); @@ -2623,6 +2630,7 @@ fn test_get_full_query() { &[&path_query1, &path_query2], true, true, + true, QueryKeyElementPairResultType, None ) diff --git a/grovedb/src/tests/query_tests.rs b/grovedb/src/tests/query_tests.rs index 830a18e0..304042bd 100644 --- a/grovedb/src/tests/query_tests.rs +++ b/grovedb/src/tests/query_tests.rs @@ -365,7 +365,7 @@ fn test_get_range_query_with_non_unique_subquery() { let path_query = PathQuery::new_unsized(path, query.clone()); let (elements, _) = db - .query_item_value(&path_query, true, true, None) + .query_item_value(&path_query, true, true, true, None) .unwrap() .expect("expected successful get_path_query"); @@ -402,7 +402,7 @@ fn test_get_range_query_with_unique_subquery() { let path_query = PathQuery::new_unsized(path, query.clone()); let (elements, _) = db - .query_item_value(&path_query, true, true, None) + .query_item_value(&path_query, true, true, true, None) .unwrap() .expect("expected successful get_path_query"); @@ -437,7 +437,7 @@ fn test_get_range_query_with_unique_subquery_on_references() { let path_query = PathQuery::new_unsized(path, query.clone()); let (elements, _) = db - .query_item_value(&path_query, true, true, None) + .query_item_value(&path_query, true, true, true, None) .unwrap() .expect("expected successful get_path_query"); @@ -481,7 +481,7 @@ fn test_get_range_query_with_unique_subquery_with_non_unique_null_values() { let path_query = PathQuery::new_unsized(path, query.clone()); let (elements, _) = db - .query_item_value(&path_query, true, true, None) + .query_item_value(&path_query, true, true, true, None) .unwrap() .expect("expected successful get_path_query"); @@ -524,7 +524,7 @@ fn test_get_range_query_with_unique_subquery_ignore_non_unique_null_values() { let path_query = PathQuery::new_unsized(path, query.clone()); let (elements, _) = db - .query_item_value(&path_query, true, true, None) + .query_item_value(&path_query, true, true, true, None) .unwrap() .expect("expected successful get_path_query"); @@ -562,7 +562,7 @@ fn test_get_range_inclusive_query_with_non_unique_subquery() { let path_query = PathQuery::new_unsized(path, query.clone()); let (elements, _) = db - .query_item_value(&path_query, true, true, None) + .query_item_value(&path_query, true, true, true, None) .unwrap() .expect("expected successful get_path_query"); @@ -602,7 +602,7 @@ fn test_get_range_inclusive_query_with_non_unique_subquery_on_references() { let path_query = PathQuery::new_unsized(path, query.clone()); let (elements, _) = db - .query_item_value(&path_query, true, true, None) + .query_item_value(&path_query, true, true, true, None) .unwrap() .expect("expected successful get_path_query"); @@ -642,7 +642,7 @@ fn test_get_range_inclusive_query_with_unique_subquery() { let path_query = PathQuery::new_unsized(path, query.clone()); let (elements, _) = db - .query_item_value(&path_query, true, true, None) + .query_item_value(&path_query, true, true, true, None) .unwrap() .expect("expected successful get_path_query"); @@ -680,7 +680,7 @@ fn test_get_range_from_query_with_non_unique_subquery() { let path_query = PathQuery::new_unsized(path, query.clone()); let (elements, _) = db - .query_item_value(&path_query, true, true, None) + .query_item_value(&path_query, true, true, true, None) .unwrap() .expect("expected successful get_path_query"); @@ -717,7 +717,7 @@ fn test_get_range_from_query_with_unique_subquery() { let path_query = PathQuery::new_unsized(path, query.clone()); let (elements, _) = db - .query_item_value(&path_query, true, true, None) + .query_item_value(&path_query, true, true, true, None) .unwrap() .expect("expected successful get_path_query"); @@ -755,7 +755,7 @@ fn test_get_range_to_query_with_non_unique_subquery() { let path_query = PathQuery::new_unsized(path, query.clone()); let (elements, _) = db - .query_item_value(&path_query, true, true, None) + .query_item_value(&path_query, true, true, true, None) .unwrap() .expect("expected successful get_path_query"); @@ -792,7 +792,7 @@ fn test_get_range_to_query_with_unique_subquery() { let path_query = PathQuery::new_unsized(path, query.clone()); let (elements, _) = db - .query_item_value(&path_query, true, true, None) + .query_item_value(&path_query, true, true, true, None) .unwrap() .expect("expected successful get_path_query"); @@ -830,7 +830,7 @@ fn test_get_range_to_inclusive_query_with_non_unique_subquery() { let path_query = PathQuery::new_unsized(path, query.clone()); let (elements, _) = db - .query_item_value(&path_query, true, true, None) + .query_item_value(&path_query, true, true, true, None) .unwrap() .expect("expected successful get_path_query"); @@ -870,7 +870,7 @@ fn test_get_range_to_inclusive_query_with_non_unique_subquery_and_key_out_of_bou let path_query = PathQuery::new_unsized(path, query.clone()); let (elements, _) = db - .query_item_value(&path_query, true, true, None) + .query_item_value(&path_query, true, true, true, None) .unwrap() .expect("expected successful get_path_query"); @@ -907,7 +907,7 @@ fn test_get_range_to_inclusive_query_with_unique_subquery() { let path_query = PathQuery::new_unsized(path, query.clone()); let (elements, _) = db - .query_item_value(&path_query, true, true, None) + .query_item_value(&path_query, true, true, true, None) .unwrap() .expect("expected successful get_path_query"); @@ -945,7 +945,7 @@ fn test_get_range_after_query_with_non_unique_subquery() { let path_query = PathQuery::new_unsized(path, query.clone()); let (elements, _) = db - .query_item_value(&path_query, true, true, None) + .query_item_value(&path_query, true, true, true, None) .unwrap() .expect("expected successful get_path_query"); @@ -985,7 +985,7 @@ fn test_get_range_after_to_query_with_non_unique_subquery() { let path_query = PathQuery::new_unsized(path, query.clone()); let (elements, _) = db - .query_item_value(&path_query, true, true, None) + .query_item_value(&path_query, true, true, true, None) .unwrap() .expect("expected successful get_path_query"); @@ -1027,7 +1027,7 @@ fn test_get_range_after_to_inclusive_query_with_non_unique_subquery() { let path_query = PathQuery::new_unsized(path, query.clone()); let (elements, _) = db - .query_item_value(&path_query, true, true, None) + .query_item_value(&path_query, true, true, true, None) .unwrap() .expect("expected successful get_path_query"); @@ -1069,7 +1069,7 @@ fn test_get_range_after_to_inclusive_query_with_non_unique_subquery_and_key_out_ let path_query = PathQuery::new_unsized(path, query.clone()); let (elements, _) = db - .query_item_value(&path_query, true, true, None) + .query_item_value(&path_query, true, true, true, None) .unwrap() .expect("expected successful get_path_query"); @@ -1117,7 +1117,7 @@ fn test_get_range_inclusive_query_with_double_non_unique_subquery() { let path_query = PathQuery::new_unsized(path, query.clone()); let (elements, _) = db - .query_item_value(&path_query, true, true, None) + .query_item_value(&path_query, true, true, true, None) .unwrap() .expect("expected successful get_path_query"); @@ -1156,7 +1156,7 @@ fn test_get_range_query_with_limit_and_offset() { let path_query = PathQuery::new(path.clone(), SizedQuery::new(query.clone(), None, None)); let (elements, _) = db - .query_item_value(&path_query, true, true, None) + .query_item_value(&path_query, true, true, true, None) .unwrap() .expect("expected successful get_path_query"); @@ -1187,7 +1187,7 @@ fn test_get_range_query_with_limit_and_offset() { let path_query = PathQuery::new(path.clone(), SizedQuery::new(query.clone(), None, None)); let (elements, _) = db - .query_item_value(&path_query, true, true, None) + .query_item_value(&path_query, true, true, true, None) .unwrap() .expect("expected successful get_path_query"); @@ -1218,7 +1218,7 @@ fn test_get_range_query_with_limit_and_offset() { let path_query = PathQuery::new(path.clone(), SizedQuery::new(query.clone(), Some(55), None)); let (elements, _) = db - .query_item_value(&path_query, true, true, None) + .query_item_value(&path_query, true, true, true, None) .unwrap() .expect("expected successful get_path_query"); @@ -1249,7 +1249,7 @@ fn test_get_range_query_with_limit_and_offset() { ); let (elements, _) = db - .query_item_value(&path_query, true, true, None) + .query_item_value(&path_query, true, true, true, None) .unwrap() .expect("expected successful get_path_query"); @@ -1287,7 +1287,7 @@ fn test_get_range_query_with_limit_and_offset() { ); let (elements, _) = db - .query_item_value(&path_query, true, true, None) + .query_item_value(&path_query, true, true, true, None) .unwrap() .expect("expected successful get_path_query"); @@ -1322,7 +1322,7 @@ fn test_get_range_query_with_limit_and_offset() { ); let (elements, _) = db - .query_item_value(&path_query, true, true, None) + .query_item_value(&path_query, true, true, true, None) .unwrap() .expect("expected successful get_path_query"); @@ -1343,7 +1343,7 @@ fn test_get_range_query_with_limit_and_offset() { ); let (elements, _) = db - .query_item_value(&path_query, true, true, None) + .query_item_value(&path_query, true, true, true, None) .unwrap() .expect("expected successful get_path_query"); @@ -1366,7 +1366,7 @@ fn test_get_range_query_with_limit_and_offset() { let path_query = PathQuery::new(path, SizedQuery::new(query.clone(), Some(5), Some(2))); let (elements, _) = db - .query_item_value(&path_query, true, true, None) + .query_item_value(&path_query, true, true, true, None) .unwrap() .expect("expected successful get_path_query"); @@ -1609,7 +1609,7 @@ fn test_mixed_level_proofs() { let path_query = PathQuery::new_unsized(path.clone(), query.clone()); let (elements, _) = db - .query_item_value(&path_query, true, true, None) + .query_item_value(&path_query, true, true, true, None) .unwrap() .expect("successful get_path_query"); @@ -1625,7 +1625,7 @@ fn test_mixed_level_proofs() { // Test mixed element proofs with limit and offset let path_query = PathQuery::new_unsized(path.clone(), query.clone()); let (elements, _) = db - .query_item_value(&path_query, true, true, None) + .query_item_value(&path_query, true, true, true, None) .unwrap() .expect("successful get_path_query"); @@ -1642,7 +1642,7 @@ fn test_mixed_level_proofs() { let path_query = PathQuery::new(path.clone(), SizedQuery::new(query.clone(), Some(1), None)); let (elements, _) = db - .query_item_value(&path_query, true, true, None) + .query_item_value(&path_query, true, true, true, None) .unwrap() .expect("successful get_path_query"); @@ -1660,7 +1660,7 @@ fn test_mixed_level_proofs() { SizedQuery::new(query.clone(), Some(3), Some(0)), ); let (elements, _) = db - .query_item_value(&path_query, true, true, None) + .query_item_value(&path_query, true, true, true, None) .unwrap() .expect("successful get_path_query"); @@ -1678,7 +1678,7 @@ fn test_mixed_level_proofs() { SizedQuery::new(query.clone(), Some(4), Some(0)), ); let (elements, _) = db - .query_item_value(&path_query, true, true, None) + .query_item_value(&path_query, true, true, true, None) .unwrap() .expect("successful get_path_query"); @@ -1693,7 +1693,7 @@ fn test_mixed_level_proofs() { let path_query = PathQuery::new(path, SizedQuery::new(query.clone(), Some(10), Some(4))); let (elements, _) = db - .query_item_value(&path_query, true, true, None) + .query_item_value(&path_query, true, true, true, None) .unwrap() .expect("successful get_path_query"); @@ -1790,6 +1790,7 @@ fn test_mixed_level_proofs_with_tree() { &path_query, true, true, + true, QueryResultType::QueryPathKeyElementTrioResultType, None, ) @@ -1813,6 +1814,7 @@ fn test_mixed_level_proofs_with_tree() { &path_query, true, true, + true, QueryResultType::QueryPathKeyElementTrioResultType, None, ) diff --git a/merk/src/proofs/query/mod.rs b/merk/src/proofs/query/mod.rs index 3a070919..9d485564 100644 --- a/merk/src/proofs/query/mod.rs +++ b/merk/src/proofs/query/mod.rs @@ -183,7 +183,8 @@ impl Query { for key in conditional_keys.into_iter() { if current_len > max_results { return Err(Error::RequestAmountExceeded(format!( - "terminal keys limit exceeded, set max is {max_results}", + "terminal keys limit exceeded for conditional subqueries, set max is \ + {max_results}, current length is {current_len}", ))); } already_added_keys.insert(key.clone()); @@ -196,14 +197,15 @@ impl Query { // push the subquery path to the path path.extend(subquery_path.iter().cloned()); // recurse onto the lower level - let added_here = - subquery.terminal_keys(path, max_results - current_len, result)?; + let added_here = subquery.terminal_keys(path, max_results, result)?; added += added_here; current_len += added_here; } else { if current_len == max_results { return Err(Error::RequestAmountExceeded(format!( - "terminal keys limit exceeded, set max is {max_results}", + "terminal keys limit exceeded when subquery path but no \ + subquery, set max is {max_results}, current length is \ + {current_len}", ))); } // a subquery path but no subquery @@ -249,7 +251,8 @@ impl Query { } if current_len > max_results { return Err(Error::RequestAmountExceeded(format!( - "terminal keys limit exceeded, set max is {max_results}", + "terminal keys limit exceeded for items, set max is {max_results}, \ + current len is {current_len}", ))); } let mut path = current_path.clone(); @@ -261,14 +264,14 @@ impl Query { // push the subquery path to the path path.extend(subquery_path.iter().cloned()); // recurse onto the lower level - let added_here = - subquery.terminal_keys(path, max_results - current_len, result)?; + let added_here = subquery.terminal_keys(path, max_results, result)?; added += added_here; current_len += added_here; } else { if current_len == max_results { return Err(Error::RequestAmountExceeded(format!( - "terminal keys limit exceeded, set max is {max_results}", + "terminal keys limit exceeded when subquery path but no subquery, \ + set max is {max_results}, current len is {current_len}", ))); } // a subquery path but no subquery @@ -292,14 +295,14 @@ impl Query { // push the key to the path path.push(key); // recurse onto the lower level - let added_here = - subquery.terminal_keys(path, max_results - current_len, result)?; + let added_here = subquery.terminal_keys(path, max_results, result)?; added += added_here; current_len += added_here; } else { if current_len == max_results { return Err(Error::RequestAmountExceeded(format!( - "terminal keys limit exceeded, set max is {max_results}", + "terminal keys limit exceeded without subquery or subquery path, set \ + max is {max_results}, current len is {current_len}", ))); } result.push((path, key)); diff --git a/node-grove/src/lib.rs b/node-grove/src/lib.rs index a955b744..d3d6e0a6 100644 --- a/node-grove/src/lib.rs +++ b/node-grove/src/lib.rs @@ -664,6 +664,7 @@ impl GroveDbWrapper { &path_query, allows_cache, true, + true, using_transaction.then_some(transaction).flatten(), ) .unwrap(); // Todo: Costs;