From ecab63915cbe05c9bb91f0c0386f868b0d8ab8cf Mon Sep 17 00:00:00 2001 From: Michael Vlach Date: Mon, 23 Sep 2024 07:44:10 +0200 Subject: [PATCH 01/13] wip --- agdb/src/query/search_query.rs | 19 +++++++++++ agdb/src/query_builder.rs | 12 +++++-- agdb/src/query_builder/search.rs | 55 +++++++++++++++----------------- agdb/tests/select_test.rs | 26 +++++++++++++++ 4 files changed, 79 insertions(+), 33 deletions(-) diff --git a/agdb/src/query/search_query.rs b/agdb/src/query/search_query.rs index 4b134200..e4241598 100644 --- a/agdb/src/query/search_query.rs +++ b/agdb/src/query/search_query.rs @@ -1,4 +1,5 @@ use crate::db::db_key_order::DbKeyOrder; +use crate::query_builder::search::SetSearchQueryBuilder; use crate::DbElement; use crate::DbId; use crate::DbImpl; @@ -212,6 +213,18 @@ impl SearchQuery { (_, _) => ids[self.offset as usize..(self.offset + self.limit) as usize].to_vec(), }) } + + pub(crate) fn new() -> Self { + Self { + algorithm: SearchQueryAlgorithm::BreadthFirst, + origin: QueryId::Id(DbId(0)), + destination: QueryId::Id(DbId(0)), + limit: 0, + offset: 0, + order_by: vec![], + conditions: vec![], + } + } } impl Query for &SearchQuery { @@ -220,6 +233,12 @@ impl Query for &SearchQuery { } } +impl SetSearchQueryBuilder for SearchQuery { + fn set_search(self, search: SearchQuery) -> Self { + search + } +} + #[cfg(test)] mod tests { use super::*; diff --git a/agdb/src/query_builder.rs b/agdb/src/query_builder.rs index 82d83b22..c521a154 100644 --- a/agdb/src/query_builder.rs +++ b/agdb/src/query_builder.rs @@ -9,7 +9,7 @@ mod remove_aliases; mod remove_ids; mod remove_index; mod remove_values; -mod search; +pub mod search; mod select; mod select_aliases; mod select_edge_count; @@ -21,6 +21,9 @@ mod select_node_count; mod select_values; mod where_; +use crate::query_builder::search::SearchQueryBuilder; +use crate::SearchQuery; + use self::insert::Insert; use self::remove::Remove; use self::search::Search; @@ -99,8 +102,11 @@ impl QueryBuilder { /// QueryBuilder::search().depth_first(); /// QueryBuilder::search().elements(); /// ``` - pub fn search() -> Search { - Search {} + pub fn search() -> Search { + Search(SearchQueryBuilder { + query: SearchQuery::new(), + search: SearchQuery::new(), + }) } /// Selects data from the database: diff --git a/agdb/src/query_builder/search.rs b/agdb/src/query_builder/search.rs index c6ce79ce..0dbb3c95 100644 --- a/agdb/src/query_builder/search.rs +++ b/agdb/src/query_builder/search.rs @@ -8,39 +8,48 @@ use crate::QueryId; use crate::SearchQuery; use crate::SearchQueryAlgorithm; +pub trait SetSearchQueryBuilder { + fn set_search(self, search: SearchQuery) -> Self; +} + +pub struct SearchQueryBuilder { + pub query: T, + pub search: SearchQuery, +} + /// Search builder query. -pub struct Search {} +pub struct Search(pub SearchQueryBuilder); /// Search builder query that lets you choose search origin /// and other parameters. -pub struct SearchFrom(pub SearchQuery); +pub struct SearchFrom(pub SearchQueryBuilder); /// Search builder query that lets you choose search destination /// and other parameters. -pub struct SearchTo(pub SearchQuery); +pub struct SearchTo(pub SearchQueryBuilder); /// Search builder query that lets you choose an index to search /// instead of the graph search entirely. -pub struct SearchIndex(pub DbValue); +pub struct SearchIndex(pub SearchQueryBuilder); /// Search builder query that lets you choose a a value to find /// in the index. -pub struct SearchIndexValue(pub (DbValue, DbValue)); +pub struct SearchIndexValue(pub SearchQueryBuilder); /// Search builder query that lets you choose limit and offset. -pub struct SearchOrderBy(pub SearchQuery); +pub struct SearchOrderBy(pub SearchQueryBuilder); /// Search builder query that lets you choose conditions. -pub struct SelectLimit(pub SearchQuery); +pub struct SelectLimit(pub SearchQueryBuilder); /// Search builder query that lets you choose limit. -pub struct SelectOffset(pub SearchQuery); +pub struct SelectOffset(pub SearchQueryBuilder); /// Search builder query that lets you choose search origin /// and other parameters. -pub struct SearchAlgorithm(pub SearchQuery); +pub struct SearchAlgorithm(pub SearchQueryBuilder); -impl Search { +impl Search { /// Use breadth-first (BFS) search algorithm. This option is redundant as /// BFS is the default. BFS means each level of the graph is examined in full /// before advancing to the next level. E.g. all edges coming from a node, @@ -55,16 +64,9 @@ impl Search { /// QueryBuilder::search().breadth_first().from(1); /// QueryBuilder::search().breadth_first().to(1); /// ``` - pub fn breadth_first(self) -> SearchAlgorithm { - SearchAlgorithm(SearchQuery { - algorithm: SearchQueryAlgorithm::BreadthFirst, - origin: QueryId::from(0), - destination: QueryId::from(0), - limit: 0, - offset: 0, - order_by: vec![], - conditions: vec![], - }) + pub fn breadth_first(mut self) -> SearchAlgorithm { + self.0.search.algorithm = SearchQueryAlgorithm::BreadthFirst; + SearchAlgorithm(self.0) } /// Use depth-first (DFS) search algorithm. DFS means each element is followed @@ -79,16 +81,9 @@ impl Search { /// QueryBuilder::search().depth_first().from(1); /// QueryBuilder::search().depth_first().to(1); /// ``` - pub fn depth_first(self) -> SearchAlgorithm { - SearchAlgorithm(SearchQuery { - algorithm: SearchQueryAlgorithm::DepthFirst, - origin: QueryId::from(0), - destination: QueryId::from(0), - limit: 0, - offset: 0, - order_by: vec![], - conditions: vec![], - }) + pub fn depth_first(mut self) -> SearchAlgorithm { + self.0.search.algorithm = SearchQueryAlgorithm::DepthFirst; + SearchAlgorithm(self.0) } /// Searches all elements (nodes & edges) in the database disregarding the graph diff --git a/agdb/tests/select_test.rs b/agdb/tests/select_test.rs index 7eb0af8c..2307d693 100644 --- a/agdb/tests/select_test.rs +++ b/agdb/tests/select_test.rs @@ -74,3 +74,29 @@ fn select_from_search() { &[1, -6, 3, -7, 5], ); } + +#[test] +fn select_embedded_search() { + let mut db = TestDb::new(); + + db.exec_mut( + QueryBuilder::insert() + .nodes() + .aliases(["alias1", "alias2", "alias3", "alias4", "alias5"]) + .query(), + 5, + ); + db.exec_mut( + QueryBuilder::insert() + .edges() + .from(["alias1", "alias3"]) + .to(["alias3", "alias5"]) + .query(), + 2, + ); + + db.exec_ids( + QueryBuilder::select().search().from("alias1").query(), + &[1, -6, 3, -7, 5], + ); +} From 176aa91e3c5a5c69a3bc5baeed0b8765531bde8f Mon Sep 17 00:00:00 2001 From: Michael Vlach Date: Mon, 23 Sep 2024 19:20:33 +0200 Subject: [PATCH 02/13] first version --- agdb/src/query_builder/search.rs | 212 ++++++++++++++----------------- agdb/src/query_builder/where_.rs | 75 +++++------ agdb/tests/select_test.rs | 46 +++---- 3 files changed, 150 insertions(+), 183 deletions(-) diff --git a/agdb/src/query_builder/search.rs b/agdb/src/query_builder/search.rs index 0dbb3c95..bdee7ac8 100644 --- a/agdb/src/query_builder/search.rs +++ b/agdb/src/query_builder/search.rs @@ -4,6 +4,8 @@ use crate::Comparison; use crate::DbValue; use crate::QueryCondition; use crate::QueryConditionData; +use crate::QueryConditionLogic; +use crate::QueryConditionModifier; use crate::QueryId; use crate::SearchQuery; use crate::SearchQueryAlgorithm; @@ -29,8 +31,11 @@ pub struct SearchFrom(pub SearchQueryBuilder); pub struct SearchTo(pub SearchQueryBuilder); /// Search builder query that lets you choose an index to search -/// instead of the graph search entirely. -pub struct SearchIndex(pub SearchQueryBuilder); +/// instead of the graph search. +pub struct SearchIndex { + pub index: DbValue, + pub search: SearchQueryBuilder, +} /// Search builder query that lets you choose a a value to find /// in the index. @@ -104,20 +109,16 @@ impl Search { /// QueryBuilder::search().elements().limit(10); /// QueryBuilder::search().elements().where_(); /// ``` - pub fn elements(self) -> SearchTo { - SearchTo(SearchQuery { - algorithm: SearchQueryAlgorithm::Elements, - origin: QueryId::from(0), - destination: QueryId::from(0), - limit: 0, - offset: 0, - order_by: vec![], - conditions: vec![], - }) + pub fn elements(mut self) -> SearchTo { + self.0.search.algorithm = SearchQueryAlgorithm::Elements; + SearchTo(self.0) } - pub fn index>(self, key: T) -> SearchIndex { - SearchIndex(key.into()) + pub fn index>(self, key: K) -> SearchIndex { + SearchIndex { + index: key.into(), + search: self.0, + } } /// Sets the origin of the search. @@ -134,16 +135,9 @@ impl Search { /// QueryBuilder::search().from(1).limit(10); /// QueryBuilder::search().from(1).where_(); /// ``` - pub fn from>(self, id: T) -> SearchFrom { - SearchFrom(SearchQuery { - algorithm: SearchQueryAlgorithm::BreadthFirst, - origin: id.into(), - destination: QueryId::from(0), - limit: 0, - offset: 0, - order_by: vec![], - conditions: vec![], - }) + pub fn from>(mut self, id: I) -> SearchFrom { + self.0.search.origin = id.into(); + SearchFrom(self.0) } /// Reverses the search setting only the destination. Reverse search @@ -159,20 +153,13 @@ impl Search { /// QueryBuilder::search().to(1).limit(10); /// QueryBuilder::search().to(1).where_(); /// ``` - pub fn to>(self, id: T) -> SearchTo { - SearchTo(SearchQuery { - algorithm: SearchQueryAlgorithm::BreadthFirst, - origin: QueryId::from(0), - destination: id.into(), - limit: 0, - offset: 0, - order_by: vec![], - conditions: vec![], - }) + pub fn to>(mut self, id: I) -> SearchTo { + self.0.search.destination = id.into(); + SearchTo(self.0) } } -impl SearchAlgorithm { +impl SearchAlgorithm { /// Sets the origin of the search. /// /// Options: @@ -187,8 +174,8 @@ impl SearchAlgorithm { /// QueryBuilder::search().depth_first().from(1).limit(10); /// QueryBuilder::search().depth_first().from(1).where_(); /// ``` - pub fn from>(mut self, id: T) -> SearchFrom { - self.0.origin = id.into(); + pub fn from>(mut self, id: I) -> SearchFrom { + self.0.search.origin = id.into(); SearchFrom(self.0) } @@ -205,13 +192,13 @@ impl SearchAlgorithm { /// QueryBuilder::search().depth_first().to(1).limit(10); /// QueryBuilder::search().depth_first().to(1).where_(); /// ``` - pub fn to>(mut self, id: T) -> SearchTo { - self.0.destination = id.into(); + pub fn to>(mut self, id: I) -> SearchTo { + self.0.search.destination = id.into(); SearchTo(self.0) } } -impl SearchFrom { +impl SearchFrom { /// Sets the limit to number of ids returned. If during the search /// the `limit + offset` is hit the search ends and the result is returned. /// However when doing a path search or requesting ordering of the result @@ -225,9 +212,8 @@ impl SearchFrom { /// QueryBuilder::search().from(1).limit(10).query(); /// QueryBuilder::search().from(1).limit(10).where_(); /// ``` - pub fn limit(mut self, value: u64) -> SelectLimit { - self.0.limit = value; - + pub fn limit(mut self, value: u64) -> SelectLimit { + self.0.search.limit = value; SelectLimit(self.0) } @@ -246,9 +232,8 @@ impl SearchFrom { /// QueryBuilder::search().from(1).offset(10).limit(5); /// QueryBuilder::search().from(1).offset(10).where_(); /// ``` - pub fn offset(mut self, value: u64) -> SelectOffset { - self.0.offset = value; - + pub fn offset(mut self, value: u64) -> SelectOffset { + self.0.search.offset = value; SelectOffset(self.0) } @@ -264,15 +249,14 @@ impl SearchFrom { /// QueryBuilder::search().from(1).order_by([DbKeyOrder::Asc("k".into())]).limit(5); /// QueryBuilder::search().from(1).order_by([DbKeyOrder::Asc("k".into())]).where_(); /// ``` - pub fn order_by>(mut self, keys: T) -> SearchOrderBy { - self.0.order_by = Into::::into(keys).0; - + pub fn order_by>(mut self, keys: K) -> SearchOrderBy { + self.0.search.order_by = Into::::into(keys).0; SearchOrderBy(self.0) } - /// Returns the built `SearchQuery` object. - pub fn query(self) -> SearchQuery { - self.0 + /// Returns the built query object. + pub fn query(self) -> T { + self.0.query.set_search(self.0.search) } /// Sets the destination (to) and changes the search algorithm to path search @@ -289,9 +273,8 @@ impl SearchFrom { /// QueryBuilder::search().from(1).to(2).limit(5); /// QueryBuilder::search().from(1).to(2).where_(); /// ``` - pub fn to>(mut self, id: T) -> SearchTo { - self.0.destination = id.into(); - + pub fn to>(mut self, id: I) -> SearchTo { + self.0.search.destination = id.into(); SearchTo(self.0) } @@ -316,12 +299,12 @@ impl SearchFrom { /// QueryBuilder::search().from(1).where_().beyond(); /// QueryBuilder::search().from(1).where_().not_beyond(); /// ``` - pub fn where_(self) -> Where { - Where::new(self.0) + pub fn where_(self) -> Where { + Where::new(self.0.query, self.0.search) } } -impl SearchOrderBy { +impl SearchOrderBy { /// Sets the limit to number of ids returned. If during the search /// the `limit + offset` is hit the search ends and the result is returned. /// However when doing a path search or requesting ordering of the result @@ -335,9 +318,8 @@ impl SearchOrderBy { /// QueryBuilder::search().from(1).order_by([DbKeyOrder::Asc("k".into())]).limit(10).query(); /// QueryBuilder::search().from(1).order_by([DbKeyOrder::Asc("k".into())]).limit(10).where_(); /// ``` - pub fn limit(mut self, value: u64) -> SelectLimit { - self.0.limit = value; - + pub fn limit(mut self, value: u64) -> SelectLimit { + self.0.search.limit = value; SelectLimit(self.0) } @@ -356,15 +338,14 @@ impl SearchOrderBy { /// QueryBuilder::search().from(1).order_by([DbKeyOrder::Asc("k".into())]).offset(10).limit(5); /// QueryBuilder::search().from(1).order_by([DbKeyOrder::Asc("k".into())]).offset(10).where_(); /// ``` - pub fn offset(mut self, value: u64) -> SelectOffset { - self.0.offset = value; - + pub fn offset(mut self, value: u64) -> SelectOffset { + self.0.search.offset = value; SelectOffset(self.0) } - /// Returns the built `SearchQuery` object. - pub fn query(self) -> SearchQuery { - self.0 + /// Returns the built query object. + pub fn query(self) -> T { + self.0.query.set_search(self.0.search) } /// Starts the condition builder. @@ -388,12 +369,12 @@ impl SearchOrderBy { /// QueryBuilder::search().from(1).where_().beyond(); /// QueryBuilder::search().from(1).where_().not_beyond(); /// ``` - pub fn where_(self) -> Where { - Where::new(self.0) + pub fn where_(self) -> Where { + Where::new(self.0.query, self.0.search) } } -impl SearchTo { +impl SearchTo { /// Sets the limit to number of ids returned. If during the search /// the `limit + offset` is hit the search ends and the result is returned. /// However when doing a path search or requesting ordering of the result @@ -407,9 +388,8 @@ impl SearchTo { /// QueryBuilder::search().to(1).order_by([DbKeyOrder::Asc("k".into())]).limit(10).query(); /// QueryBuilder::search().to(1).order_by([DbKeyOrder::Asc("k".into())]).limit(10).where_(); /// ``` - pub fn limit(mut self, value: u64) -> SelectLimit { - self.0.limit = value; - + pub fn limit(mut self, value: u64) -> SelectLimit { + self.0.search.limit = value; SelectLimit(self.0) } @@ -428,9 +408,8 @@ impl SearchTo { /// QueryBuilder::search().to(1).order_by([DbKeyOrder::Asc("k".into())]).offset(10).limit(5); /// QueryBuilder::search().to(1).order_by([DbKeyOrder::Asc("k".into())]).offset(10).where_(); /// ``` - pub fn offset(mut self, value: u64) -> SelectOffset { - self.0.offset = value; - + pub fn offset(mut self, value: u64) -> SelectOffset { + self.0.search.offset = value; SelectOffset(self.0) } @@ -449,15 +428,14 @@ impl SearchTo { /// QueryBuilder::search().to(1).order_by([DbKeyOrder::Asc("k".into())]).offset(10).limit(5); /// QueryBuilder::search().to(1).order_by([DbKeyOrder::Asc("k".into())]).offset(10).where_(); /// ``` - pub fn order_by>(mut self, keys: T) -> SearchOrderBy { - self.0.order_by = Into::::into(keys).0; - + pub fn order_by>(mut self, keys: K) -> SearchOrderBy { + self.0.search.order_by = Into::::into(keys).0; SearchOrderBy(self.0) } /// Returns the built `SearchQuery` object. - pub fn query(self) -> SearchQuery { - self.0 + pub fn query(self) -> T { + self.0.query.set_search(self.0.search) } /// Starts the condition builder. @@ -481,15 +459,15 @@ impl SearchTo { /// QueryBuilder::search().from(1).where_().beyond(); /// QueryBuilder::search().from(1).where_().not_beyond(); /// ``` - pub fn where_(self) -> Where { - Where::new(self.0) + pub fn where_(self) -> Where { + Where::new(self.0.query, self.0.search) } } -impl SelectLimit { - /// Returns the built `SearchQuery` object. - pub fn query(self) -> SearchQuery { - self.0 +impl SelectLimit { + /// Returns the built query object. + pub fn query(self) -> T { + self.0.query.set_search(self.0.search) } /// Starts the condition builder. @@ -513,12 +491,12 @@ impl SelectLimit { /// QueryBuilder::search().from(1).where_().beyond(); /// QueryBuilder::search().from(1).where_().not_beyond(); /// ``` - pub fn where_(self) -> Where { - Where::new(self.0) + pub fn where_(self) -> Where { + Where::new(self.0.query, self.0.search) } } -impl SelectOffset { +impl SelectOffset { /// Sets the limit to number of ids returned. If during the search /// the `limit + offset` is hit the search ends and the result is returned. /// However when doing a path search or requesting ordering of the result @@ -532,15 +510,14 @@ impl SelectOffset { /// QueryBuilder::search().from(1).offset(10).limit(10).query(); /// QueryBuilder::search().from(1).offset(10).limit(10).where_(); /// ``` - pub fn limit(mut self, value: u64) -> SelectLimit { - self.0.limit = value; - + pub fn limit(mut self, value: u64) -> SelectLimit { + self.0.search.limit = value; SelectLimit(self.0) } - /// Returns the built `SearchQuery` object. - pub fn query(self) -> SearchQuery { - self.0 + /// Returns the built query object. + pub fn query(self) -> T { + self.0.query.set_search(self.0.search) } /// Starts the condition builder. @@ -564,36 +541,31 @@ impl SelectOffset { /// QueryBuilder::search().from(1).where_().beyond(); /// QueryBuilder::search().from(1).where_().not_beyond(); /// ``` - pub fn where_(self) -> Where { - Where::new(self.0) + pub fn where_(self) -> Where { + Where::new(self.0.query, self.0.search) } } -impl SearchIndex { +impl SearchIndex { /// Sets the value to be searched in the index. - pub fn value>(self, value: T) -> SearchIndexValue { - SearchIndexValue((self.0, value.into())) + pub fn value>(mut self, value: V) -> SearchIndexValue { + self.search.search.algorithm = SearchQueryAlgorithm::Index; + self.search.search.conditions.push(QueryCondition { + data: QueryConditionData::KeyValue { + key: self.index, + value: Comparison::Equal(value.into()), + }, + logic: QueryConditionLogic::And, + modifier: QueryConditionModifier::None, + }); + + SearchIndexValue(self.search) } } -impl SearchIndexValue { - /// Returns the built `SearchQuery` object. - pub fn query(self) -> SearchQuery { - SearchQuery { - algorithm: SearchQueryAlgorithm::Index, - origin: QueryId::from(0), - destination: QueryId::from(0), - limit: 0, - offset: 0, - order_by: vec![], - conditions: vec![QueryCondition { - logic: crate::QueryConditionLogic::And, - modifier: crate::QueryConditionModifier::None, - data: QueryConditionData::KeyValue { - key: self.0 .0, - value: Comparison::Equal(self.0 .1), - }, - }], - } +impl SearchIndexValue { + /// Returns the built q object. + pub fn query(self) -> T { + self.0.query.set_search(self.0.search) } } diff --git a/agdb/src/query_builder/where_.rs b/agdb/src/query_builder/where_.rs index 65b85f1a..1bbf80d6 100644 --- a/agdb/src/query_builder/where_.rs +++ b/agdb/src/query_builder/where_.rs @@ -5,28 +5,30 @@ use crate::query::query_condition::QueryConditionData; use crate::query::query_condition::QueryConditionLogic; use crate::query::query_condition::QueryConditionModifier; use crate::query::search_query::SearchQuery; +use crate::query_builder::search::SetSearchQueryBuilder; use crate::Comparison; use crate::DbValue; use crate::QueryIds; /// Condition builder -pub struct Where { +pub struct Where { logic: QueryConditionLogic, modifier: QueryConditionModifier, conditions: Vec>, - query: SearchQuery, + query: T, + search: SearchQuery, } /// Condition builder for `key` condition. -pub struct WhereKey { +pub struct WhereKey { key: DbValue, - where_: Where, + where_: Where, } /// Condition builder setting the logic operator. -pub struct WhereLogicOperator(pub Where); +pub struct WhereLogicOperator(pub Where); -impl Where { +impl Where { /// Sets the condition modifier for the following condition so /// that the search will continue beyond current element only /// if the condition is satisfied. For the opposite effect see @@ -47,9 +49,8 @@ impl Where { /// // Only edges or nodes with exactly 1 edge are followed. /// QueryBuilder::search().from(1).where_().beyond().edge().or().edge_count(CountComparison::Equal(1)); /// ``` - pub fn beyond(mut self) -> Where { + pub fn beyond(mut self) -> Self { self.modifier = QueryConditionModifier::Beyond; - self } @@ -68,7 +69,7 @@ impl Where { /// // Start accepting elements at distance greater than 1 (2+) /// QueryBuilder::search().from(1).where_().distance(CountComparison::GreaterThan(1)).query(); /// ``` - pub fn distance(mut self, comparison: CountComparison) -> WhereLogicOperator { + pub fn distance(mut self, comparison: CountComparison) -> WhereLogicOperator { self.add_condition(QueryCondition { logic: self.logic, modifier: self.modifier, @@ -87,7 +88,7 @@ impl Where { /// /// QueryBuilder::search().from(1).where_().edge().query(); /// ``` - pub fn edge(mut self) -> WhereLogicOperator { + pub fn edge(mut self) -> WhereLogicOperator { self.add_condition(QueryCondition { logic: self.logic, modifier: self.modifier, @@ -109,7 +110,7 @@ impl Where { /// /// QueryBuilder::search().from(1).where_().edge_count(CountComparison::Equal(1)).query(); /// ``` - pub fn edge_count(mut self, comparison: CountComparison) -> WhereLogicOperator { + pub fn edge_count(mut self, comparison: CountComparison) -> WhereLogicOperator { self.add_condition(QueryCondition { logic: self.logic, modifier: self.modifier, @@ -129,7 +130,7 @@ impl Where { /// /// QueryBuilder::search().from(1).where_().edge_count_from(CountComparison::Equal(1)).query(); /// ``` - pub fn edge_count_from(mut self, comparison: CountComparison) -> WhereLogicOperator { + pub fn edge_count_from(mut self, comparison: CountComparison) -> WhereLogicOperator { self.add_condition(QueryCondition { logic: self.logic, modifier: self.modifier, @@ -149,7 +150,7 @@ impl Where { /// /// QueryBuilder::search().from(1).where_().edge_count_to(CountComparison::Equal(1)).query(); /// ``` - pub fn edge_count_to(mut self, comparison: CountComparison) -> WhereLogicOperator { + pub fn edge_count_to(mut self, comparison: CountComparison) -> WhereLogicOperator { self.add_condition(QueryCondition { logic: self.logic, modifier: self.modifier, @@ -175,7 +176,7 @@ impl Where { /// // Do not continue the search beyond "alias" element /// QueryBuilder::search().from(1).where_().not_beyond().ids("alias").query(); /// ``` - pub fn ids>(mut self, ids: T) -> WhereLogicOperator { + pub fn ids>(mut self, ids: I) -> WhereLogicOperator { self.add_condition(QueryCondition { logic: self.logic, modifier: self.modifier, @@ -196,7 +197,7 @@ impl Where { /// // Includes only elements with property `String("k") == 1_i64` /// QueryBuilder::search().from(1).where_().key("k").value(Comparison::Equal(1.into())).query(); /// ``` - pub fn key>(self, key: T) -> WhereKey { + pub fn key>(self, key: K) -> WhereKey { WhereKey { key: key.into(), where_: self, @@ -218,7 +219,7 @@ impl Where { /// // Includes only elements with either "a" or "b" properties (keys). /// QueryBuilder::search().from(1).where_().keys("a").or().keys("b").query(); /// ``` - pub fn keys>(mut self, keys: T) -> WhereLogicOperator { + pub fn keys>(mut self, keys: K) -> WhereLogicOperator { self.add_condition(QueryCondition { logic: self.logic, modifier: self.modifier, @@ -237,7 +238,7 @@ impl Where { /// /// QueryBuilder::search().from(1).where_().node().query(); /// ``` - pub fn node(mut self) -> WhereLogicOperator { + pub fn node(mut self) -> WhereLogicOperator { self.add_condition(QueryCondition { logic: self.logic, modifier: self.modifier, @@ -324,15 +325,17 @@ impl Where { modifier: QueryConditionModifier::None, conditions: self.conditions, query: self.query, + search: self.search, } } - pub(crate) fn new(query: SearchQuery) -> Self { + pub(crate) fn new(query: T, search: SearchQuery) -> Self { Self { logic: QueryConditionLogic::And, modifier: QueryConditionModifier::None, conditions: vec![vec![]], query, + search, } } @@ -360,9 +363,9 @@ impl Where { } } -impl WhereKey { +impl WhereKey { /// Sets the value of the `key` condition to `comparison`. - pub fn value(mut self, comparison: Comparison) -> WhereLogicOperator { + pub fn value(mut self, comparison: Comparison) -> WhereLogicOperator { let condition = QueryCondition { logic: self.where_.logic, modifier: self.where_.modifier, @@ -376,23 +379,24 @@ impl WhereKey { } } -impl WhereLogicOperator { +impl WhereLogicOperator { /// Sets the logic operator for the following condition /// to logical AND (&&). The condition passes only if /// both sides evaluates to `true`. - pub fn and(self) -> Where { + pub fn and(self) -> Where { Where { logic: QueryConditionLogic::And, modifier: QueryConditionModifier::None, conditions: self.0.conditions, query: self.0.query, + search: self.0.search, } } /// Closes the current level condition level returning /// to the previous one. It semantically represents a /// closing bracket. - pub fn end_where(mut self) -> WhereLogicOperator { + pub fn end_where(mut self) -> WhereLogicOperator { self.0.collapse_conditions(); WhereLogicOperator(self.0) @@ -401,45 +405,36 @@ impl WhereLogicOperator { /// Sets the logic operator for the following condition /// to logical OR (||). The condition passes only if /// both sides evaluates to `false`. - pub fn or(self) -> Where { + pub fn or(self) -> Where { Where { logic: QueryConditionLogic::Or, modifier: QueryConditionModifier::None, conditions: self.0.conditions, query: self.0.query, + search: self.0.search, } } /// Returns the built `SearchQuery` object. - pub fn query(mut self) -> SearchQuery { + pub fn query(mut self) -> T { while self.0.collapse_conditions() {} - std::mem::swap(&mut self.0.query.conditions, &mut self.0.conditions[0]); - self.0.query + std::mem::swap(&mut self.0.search.conditions, &mut self.0.conditions[0]); + self.0.query.set_search(self.0.search) } } #[cfg(test)] mod test { use super::*; - use crate::DbId; - use crate::QueryId; - use crate::SearchQueryAlgorithm; #[test] fn invalid_collapse() { - let mut where_ = Where { + let mut where_ = Where:: { logic: QueryConditionLogic::And, modifier: QueryConditionModifier::None, conditions: vec![vec![], vec![]], - query: SearchQuery { - algorithm: SearchQueryAlgorithm::BreadthFirst, - origin: QueryId::Id(DbId(0)), - destination: QueryId::Id(DbId(0)), - limit: 0, - offset: 0, - order_by: vec![], - conditions: vec![], - }, + query: SearchQuery::new(), + search: SearchQuery::new(), }; assert!(!where_.collapse_conditions()); } diff --git a/agdb/tests/select_test.rs b/agdb/tests/select_test.rs index 2307d693..e3f3fe7c 100644 --- a/agdb/tests/select_test.rs +++ b/agdb/tests/select_test.rs @@ -75,28 +75,28 @@ fn select_from_search() { ); } -#[test] -fn select_embedded_search() { - let mut db = TestDb::new(); +// #[test] +// fn select_embedded_search() { +// let mut db = TestDb::new(); - db.exec_mut( - QueryBuilder::insert() - .nodes() - .aliases(["alias1", "alias2", "alias3", "alias4", "alias5"]) - .query(), - 5, - ); - db.exec_mut( - QueryBuilder::insert() - .edges() - .from(["alias1", "alias3"]) - .to(["alias3", "alias5"]) - .query(), - 2, - ); +// db.exec_mut( +// QueryBuilder::insert() +// .nodes() +// .aliases(["alias1", "alias2", "alias3", "alias4", "alias5"]) +// .query(), +// 5, +// ); +// db.exec_mut( +// QueryBuilder::insert() +// .edges() +// .from(["alias1", "alias3"]) +// .to(["alias3", "alias5"]) +// .query(), +// 2, +// ); - db.exec_ids( - QueryBuilder::select().search().from("alias1").query(), - &[1, -6, 3, -7, 5], - ); -} +// db.exec_ids( +// QueryBuilder::select().search().from("alias1").query(), +// &[1, -6, 3, -7, 5], +// ); +// } From ecfd9ad0e4ceebaffe5d431e90a682844a663bc6 Mon Sep 17 00:00:00 2001 From: Michael Vlach Date: Mon, 23 Sep 2024 19:44:02 +0200 Subject: [PATCH 03/13] refactoring --- agdb/src/query/search_query.rs | 8 +-- agdb/src/query_builder.rs | 9 +-- agdb/src/query_builder/search.rs | 112 +++++++++++++++---------------- agdb/src/query_builder/where_.rs | 31 ++++----- 4 files changed, 73 insertions(+), 87 deletions(-) diff --git a/agdb/src/query/search_query.rs b/agdb/src/query/search_query.rs index e4241598..ebbb6f36 100644 --- a/agdb/src/query/search_query.rs +++ b/agdb/src/query/search_query.rs @@ -1,5 +1,5 @@ use crate::db::db_key_order::DbKeyOrder; -use crate::query_builder::search::SetSearchQueryBuilder; +use crate::query_builder::search::SearchQueryBuilder; use crate::DbElement; use crate::DbId; use crate::DbImpl; @@ -233,9 +233,9 @@ impl Query for &SearchQuery { } } -impl SetSearchQueryBuilder for SearchQuery { - fn set_search(self, search: SearchQuery) -> Self { - search +impl SearchQueryBuilder for SearchQuery { + fn search_mut(&mut self) -> &mut SearchQuery { + self } } diff --git a/agdb/src/query_builder.rs b/agdb/src/query_builder.rs index c521a154..2295985d 100644 --- a/agdb/src/query_builder.rs +++ b/agdb/src/query_builder.rs @@ -21,13 +21,11 @@ mod select_node_count; mod select_values; mod where_; -use crate::query_builder::search::SearchQueryBuilder; -use crate::SearchQuery; - use self::insert::Insert; use self::remove::Remove; use self::search::Search; use self::select::Select; +use crate::SearchQuery; /// The starting point of all queries. /// @@ -103,10 +101,7 @@ impl QueryBuilder { /// QueryBuilder::search().elements(); /// ``` pub fn search() -> Search { - Search(SearchQueryBuilder { - query: SearchQuery::new(), - search: SearchQuery::new(), - }) + Search(SearchQuery::new()) } /// Selects data from the database: diff --git a/agdb/src/query_builder/search.rs b/agdb/src/query_builder/search.rs index bdee7ac8..46a0e19a 100644 --- a/agdb/src/query_builder/search.rs +++ b/agdb/src/query_builder/search.rs @@ -10,51 +10,46 @@ use crate::QueryId; use crate::SearchQuery; use crate::SearchQueryAlgorithm; -pub trait SetSearchQueryBuilder { - fn set_search(self, search: SearchQuery) -> Self; -} - -pub struct SearchQueryBuilder { - pub query: T, - pub search: SearchQuery, +pub trait SearchQueryBuilder { + fn search_mut(&mut self) -> &mut SearchQuery; } /// Search builder query. -pub struct Search(pub SearchQueryBuilder); +pub struct Search(pub T); /// Search builder query that lets you choose search origin /// and other parameters. -pub struct SearchFrom(pub SearchQueryBuilder); +pub struct SearchFrom(pub T); /// Search builder query that lets you choose search destination /// and other parameters. -pub struct SearchTo(pub SearchQueryBuilder); +pub struct SearchTo(pub T); /// Search builder query that lets you choose an index to search /// instead of the graph search. -pub struct SearchIndex { +pub struct SearchIndex { pub index: DbValue, - pub search: SearchQueryBuilder, + pub query: T, } /// Search builder query that lets you choose a a value to find /// in the index. -pub struct SearchIndexValue(pub SearchQueryBuilder); +pub struct SearchIndexValue(pub T); /// Search builder query that lets you choose limit and offset. -pub struct SearchOrderBy(pub SearchQueryBuilder); +pub struct SearchOrderBy(pub T); /// Search builder query that lets you choose conditions. -pub struct SelectLimit(pub SearchQueryBuilder); +pub struct SelectLimit(pub T); /// Search builder query that lets you choose limit. -pub struct SelectOffset(pub SearchQueryBuilder); +pub struct SelectOffset(pub T); /// Search builder query that lets you choose search origin /// and other parameters. -pub struct SearchAlgorithm(pub SearchQueryBuilder); +pub struct SearchAlgorithm(pub T); -impl Search { +impl Search { /// Use breadth-first (BFS) search algorithm. This option is redundant as /// BFS is the default. BFS means each level of the graph is examined in full /// before advancing to the next level. E.g. all edges coming from a node, @@ -70,7 +65,7 @@ impl Search { /// QueryBuilder::search().breadth_first().to(1); /// ``` pub fn breadth_first(mut self) -> SearchAlgorithm { - self.0.search.algorithm = SearchQueryAlgorithm::BreadthFirst; + self.0.search_mut().algorithm = SearchQueryAlgorithm::BreadthFirst; SearchAlgorithm(self.0) } @@ -87,7 +82,7 @@ impl Search { /// QueryBuilder::search().depth_first().to(1); /// ``` pub fn depth_first(mut self) -> SearchAlgorithm { - self.0.search.algorithm = SearchQueryAlgorithm::DepthFirst; + self.0.search_mut().algorithm = SearchQueryAlgorithm::DepthFirst; SearchAlgorithm(self.0) } @@ -110,14 +105,14 @@ impl Search { /// QueryBuilder::search().elements().where_(); /// ``` pub fn elements(mut self) -> SearchTo { - self.0.search.algorithm = SearchQueryAlgorithm::Elements; + self.0.search_mut().algorithm = SearchQueryAlgorithm::Elements; SearchTo(self.0) } pub fn index>(self, key: K) -> SearchIndex { SearchIndex { index: key.into(), - search: self.0, + query: self.0, } } @@ -136,7 +131,7 @@ impl Search { /// QueryBuilder::search().from(1).where_(); /// ``` pub fn from>(mut self, id: I) -> SearchFrom { - self.0.search.origin = id.into(); + self.0.search_mut().origin = id.into(); SearchFrom(self.0) } @@ -154,12 +149,12 @@ impl Search { /// QueryBuilder::search().to(1).where_(); /// ``` pub fn to>(mut self, id: I) -> SearchTo { - self.0.search.destination = id.into(); + self.0.search_mut().destination = id.into(); SearchTo(self.0) } } -impl SearchAlgorithm { +impl SearchAlgorithm { /// Sets the origin of the search. /// /// Options: @@ -175,7 +170,7 @@ impl SearchAlgorithm { /// QueryBuilder::search().depth_first().from(1).where_(); /// ``` pub fn from>(mut self, id: I) -> SearchFrom { - self.0.search.origin = id.into(); + self.0.search_mut().origin = id.into(); SearchFrom(self.0) } @@ -193,12 +188,12 @@ impl SearchAlgorithm { /// QueryBuilder::search().depth_first().to(1).where_(); /// ``` pub fn to>(mut self, id: I) -> SearchTo { - self.0.search.destination = id.into(); + self.0.search_mut().destination = id.into(); SearchTo(self.0) } } -impl SearchFrom { +impl SearchFrom { /// Sets the limit to number of ids returned. If during the search /// the `limit + offset` is hit the search ends and the result is returned. /// However when doing a path search or requesting ordering of the result @@ -213,7 +208,7 @@ impl SearchFrom { /// QueryBuilder::search().from(1).limit(10).where_(); /// ``` pub fn limit(mut self, value: u64) -> SelectLimit { - self.0.search.limit = value; + self.0.search_mut().limit = value; SelectLimit(self.0) } @@ -233,7 +228,7 @@ impl SearchFrom { /// QueryBuilder::search().from(1).offset(10).where_(); /// ``` pub fn offset(mut self, value: u64) -> SelectOffset { - self.0.search.offset = value; + self.0.search_mut().offset = value; SelectOffset(self.0) } @@ -250,13 +245,13 @@ impl SearchFrom { /// QueryBuilder::search().from(1).order_by([DbKeyOrder::Asc("k".into())]).where_(); /// ``` pub fn order_by>(mut self, keys: K) -> SearchOrderBy { - self.0.search.order_by = Into::::into(keys).0; + self.0.search_mut().order_by = Into::::into(keys).0; SearchOrderBy(self.0) } /// Returns the built query object. pub fn query(self) -> T { - self.0.query.set_search(self.0.search) + self.0 } /// Sets the destination (to) and changes the search algorithm to path search @@ -274,7 +269,7 @@ impl SearchFrom { /// QueryBuilder::search().from(1).to(2).where_(); /// ``` pub fn to>(mut self, id: I) -> SearchTo { - self.0.search.destination = id.into(); + self.0.search_mut().destination = id.into(); SearchTo(self.0) } @@ -300,11 +295,11 @@ impl SearchFrom { /// QueryBuilder::search().from(1).where_().not_beyond(); /// ``` pub fn where_(self) -> Where { - Where::new(self.0.query, self.0.search) + Where::new(self.0) } } -impl SearchOrderBy { +impl SearchOrderBy { /// Sets the limit to number of ids returned. If during the search /// the `limit + offset` is hit the search ends and the result is returned. /// However when doing a path search or requesting ordering of the result @@ -319,7 +314,7 @@ impl SearchOrderBy { /// QueryBuilder::search().from(1).order_by([DbKeyOrder::Asc("k".into())]).limit(10).where_(); /// ``` pub fn limit(mut self, value: u64) -> SelectLimit { - self.0.search.limit = value; + self.0.search_mut().limit = value; SelectLimit(self.0) } @@ -339,13 +334,13 @@ impl SearchOrderBy { /// QueryBuilder::search().from(1).order_by([DbKeyOrder::Asc("k".into())]).offset(10).where_(); /// ``` pub fn offset(mut self, value: u64) -> SelectOffset { - self.0.search.offset = value; + self.0.search_mut().offset = value; SelectOffset(self.0) } /// Returns the built query object. pub fn query(self) -> T { - self.0.query.set_search(self.0.search) + self.0 } /// Starts the condition builder. @@ -370,11 +365,11 @@ impl SearchOrderBy { /// QueryBuilder::search().from(1).where_().not_beyond(); /// ``` pub fn where_(self) -> Where { - Where::new(self.0.query, self.0.search) + Where::new(self.0) } } -impl SearchTo { +impl SearchTo { /// Sets the limit to number of ids returned. If during the search /// the `limit + offset` is hit the search ends and the result is returned. /// However when doing a path search or requesting ordering of the result @@ -389,7 +384,7 @@ impl SearchTo { /// QueryBuilder::search().to(1).order_by([DbKeyOrder::Asc("k".into())]).limit(10).where_(); /// ``` pub fn limit(mut self, value: u64) -> SelectLimit { - self.0.search.limit = value; + self.0.search_mut().limit = value; SelectLimit(self.0) } @@ -409,7 +404,7 @@ impl SearchTo { /// QueryBuilder::search().to(1).order_by([DbKeyOrder::Asc("k".into())]).offset(10).where_(); /// ``` pub fn offset(mut self, value: u64) -> SelectOffset { - self.0.search.offset = value; + self.0.search_mut().offset = value; SelectOffset(self.0) } @@ -429,13 +424,13 @@ impl SearchTo { /// QueryBuilder::search().to(1).order_by([DbKeyOrder::Asc("k".into())]).offset(10).where_(); /// ``` pub fn order_by>(mut self, keys: K) -> SearchOrderBy { - self.0.search.order_by = Into::::into(keys).0; + self.0.search_mut().order_by = Into::::into(keys).0; SearchOrderBy(self.0) } /// Returns the built `SearchQuery` object. pub fn query(self) -> T { - self.0.query.set_search(self.0.search) + self.0 } /// Starts the condition builder. @@ -460,14 +455,14 @@ impl SearchTo { /// QueryBuilder::search().from(1).where_().not_beyond(); /// ``` pub fn where_(self) -> Where { - Where::new(self.0.query, self.0.search) + Where::new(self.0) } } -impl SelectLimit { +impl SelectLimit { /// Returns the built query object. pub fn query(self) -> T { - self.0.query.set_search(self.0.search) + self.0 } /// Starts the condition builder. @@ -492,11 +487,11 @@ impl SelectLimit { /// QueryBuilder::search().from(1).where_().not_beyond(); /// ``` pub fn where_(self) -> Where { - Where::new(self.0.query, self.0.search) + Where::new(self.0) } } -impl SelectOffset { +impl SelectOffset { /// Sets the limit to number of ids returned. If during the search /// the `limit + offset` is hit the search ends and the result is returned. /// However when doing a path search or requesting ordering of the result @@ -511,13 +506,13 @@ impl SelectOffset { /// QueryBuilder::search().from(1).offset(10).limit(10).where_(); /// ``` pub fn limit(mut self, value: u64) -> SelectLimit { - self.0.search.limit = value; + self.0.search_mut().limit = value; SelectLimit(self.0) } /// Returns the built query object. pub fn query(self) -> T { - self.0.query.set_search(self.0.search) + self.0 } /// Starts the condition builder. @@ -542,15 +537,15 @@ impl SelectOffset { /// QueryBuilder::search().from(1).where_().not_beyond(); /// ``` pub fn where_(self) -> Where { - Where::new(self.0.query, self.0.search) + Where::new(self.0) } } -impl SearchIndex { +impl SearchIndex { /// Sets the value to be searched in the index. pub fn value>(mut self, value: V) -> SearchIndexValue { - self.search.search.algorithm = SearchQueryAlgorithm::Index; - self.search.search.conditions.push(QueryCondition { + self.query.search_mut().algorithm = SearchQueryAlgorithm::Index; + self.query.search_mut().conditions.push(QueryCondition { data: QueryConditionData::KeyValue { key: self.index, value: Comparison::Equal(value.into()), @@ -558,14 +553,13 @@ impl SearchIndex { logic: QueryConditionLogic::And, modifier: QueryConditionModifier::None, }); - - SearchIndexValue(self.search) + SearchIndexValue(self.query) } } -impl SearchIndexValue { +impl SearchIndexValue { /// Returns the built q object. pub fn query(self) -> T { - self.0.query.set_search(self.0.search) + self.0 } } diff --git a/agdb/src/query_builder/where_.rs b/agdb/src/query_builder/where_.rs index 1bbf80d6..78db8963 100644 --- a/agdb/src/query_builder/where_.rs +++ b/agdb/src/query_builder/where_.rs @@ -4,31 +4,29 @@ use crate::query::query_condition::QueryCondition; use crate::query::query_condition::QueryConditionData; use crate::query::query_condition::QueryConditionLogic; use crate::query::query_condition::QueryConditionModifier; -use crate::query::search_query::SearchQuery; -use crate::query_builder::search::SetSearchQueryBuilder; +use crate::query_builder::search::SearchQueryBuilder; use crate::Comparison; use crate::DbValue; use crate::QueryIds; /// Condition builder -pub struct Where { +pub struct Where { logic: QueryConditionLogic, modifier: QueryConditionModifier, conditions: Vec>, query: T, - search: SearchQuery, } /// Condition builder for `key` condition. -pub struct WhereKey { +pub struct WhereKey { key: DbValue, where_: Where, } /// Condition builder setting the logic operator. -pub struct WhereLogicOperator(pub Where); +pub struct WhereLogicOperator(pub Where); -impl Where { +impl Where { /// Sets the condition modifier for the following condition so /// that the search will continue beyond current element only /// if the condition is satisfied. For the opposite effect see @@ -325,17 +323,15 @@ impl Where { modifier: QueryConditionModifier::None, conditions: self.conditions, query: self.query, - search: self.search, } } - pub(crate) fn new(query: T, search: SearchQuery) -> Self { + pub(crate) fn new(query: T) -> Self { Self { logic: QueryConditionLogic::And, modifier: QueryConditionModifier::None, conditions: vec![vec![]], query, - search, } } @@ -363,7 +359,7 @@ impl Where { } } -impl WhereKey { +impl WhereKey { /// Sets the value of the `key` condition to `comparison`. pub fn value(mut self, comparison: Comparison) -> WhereLogicOperator { let condition = QueryCondition { @@ -379,7 +375,7 @@ impl WhereKey { } } -impl WhereLogicOperator { +impl WhereLogicOperator { /// Sets the logic operator for the following condition /// to logical AND (&&). The condition passes only if /// both sides evaluates to `true`. @@ -389,7 +385,6 @@ impl WhereLogicOperator { modifier: QueryConditionModifier::None, conditions: self.0.conditions, query: self.0.query, - search: self.0.search, } } @@ -411,21 +406,24 @@ impl WhereLogicOperator { modifier: QueryConditionModifier::None, conditions: self.0.conditions, query: self.0.query, - search: self.0.search, } } /// Returns the built `SearchQuery` object. pub fn query(mut self) -> T { while self.0.collapse_conditions() {} - std::mem::swap(&mut self.0.search.conditions, &mut self.0.conditions[0]); - self.0.query.set_search(self.0.search) + std::mem::swap( + &mut self.0.query.search_mut().conditions, + &mut self.0.conditions[0], + ); + self.0.query } } #[cfg(test)] mod test { use super::*; + use crate::SearchQuery; #[test] fn invalid_collapse() { @@ -434,7 +432,6 @@ mod test { modifier: QueryConditionModifier::None, conditions: vec![vec![], vec![]], query: SearchQuery::new(), - search: SearchQuery::new(), }; assert!(!where_.collapse_conditions()); } From 6c8859e344e97231205c1be85e58cd611e9119f7 Mon Sep 17 00:00:00 2001 From: Michael Vlach Date: Mon, 23 Sep 2024 20:07:23 +0200 Subject: [PATCH 04/13] select search --- agdb/src/query/select_values_query.rs | 12 ++++ agdb/src/query_builder/select.rs | 8 +++ agdb/tests/select_test.rs | 79 +++++++++++++++++++-------- 3 files changed, 76 insertions(+), 23 deletions(-) diff --git a/agdb/src/query/select_values_query.rs b/agdb/src/query/select_values_query.rs index b2162f6e..e8764297 100644 --- a/agdb/src/query/select_values_query.rs +++ b/agdb/src/query/select_values_query.rs @@ -1,3 +1,4 @@ +use crate::query_builder::search::SearchQueryBuilder; use crate::DbElement; use crate::DbImpl; use crate::DbValue; @@ -5,6 +6,7 @@ use crate::Query; use crate::QueryError; use crate::QueryIds; use crate::QueryResult; +use crate::SearchQuery; use crate::StorageData; /// Query to select elements with only certain properties of @@ -76,3 +78,13 @@ impl Query for &SelectValuesQuery { (*self).process(db) } } + +impl SearchQueryBuilder for SelectValuesQuery { + fn search_mut(&mut self) -> &mut SearchQuery { + if let QueryIds::Search(search) = &mut self.ids { + search + } else { + panic!("Expected search query"); + } + } +} diff --git a/agdb/src/query_builder/select.rs b/agdb/src/query_builder/select.rs index ecb0f364..2c04b7b7 100644 --- a/agdb/src/query_builder/select.rs +++ b/agdb/src/query_builder/select.rs @@ -1,4 +1,5 @@ use crate::db::db_value::DbValues; +use crate::query_builder::search::Search; use crate::query_builder::select_aliases::SelectAliases; use crate::query_builder::select_edge_count::SelectEdgeCount; use crate::query_builder::select_ids::SelectIds; @@ -107,6 +108,13 @@ impl Select { SelectNodeCount {} } + pub fn search(self) -> Search { + Search(SelectValuesQuery { + keys: vec![], + ids: QueryIds::Search(crate::SearchQuery::new()), + }) + } + /// Select elements with `ids` with only `keys` properties (key-values). /// All ids specified must exist in the database. pub fn values>(self, keys: T) -> SelectValues { diff --git a/agdb/tests/select_test.rs b/agdb/tests/select_test.rs index e3f3fe7c..d7eba265 100644 --- a/agdb/tests/select_test.rs +++ b/agdb/tests/select_test.rs @@ -1,5 +1,7 @@ mod test_db; +use agdb::DbElement; +use agdb::DbId; use agdb::QueryBuilder; use test_db::TestDb; @@ -75,28 +77,59 @@ fn select_from_search() { ); } -// #[test] -// fn select_embedded_search() { -// let mut db = TestDb::new(); +#[test] +fn select_embedded_search() { + let mut db = TestDb::new(); -// db.exec_mut( -// QueryBuilder::insert() -// .nodes() -// .aliases(["alias1", "alias2", "alias3", "alias4", "alias5"]) -// .query(), -// 5, -// ); -// db.exec_mut( -// QueryBuilder::insert() -// .edges() -// .from(["alias1", "alias3"]) -// .to(["alias3", "alias5"]) -// .query(), -// 2, -// ); + db.exec_mut( + QueryBuilder::insert() + .nodes() + .aliases(["alias1", "alias2", "alias3", "alias4", "alias5"]) + .values([ + [("k", 1).into()], + [("k", 2).into()], + [("k", 3).into()], + [("k", 4).into()], + [("k", 5).into()], + ]) + .query(), + 5, + ); + db.exec_mut( + QueryBuilder::insert() + .edges() + .from(["alias1", "alias3"]) + .to(["alias3", "alias5"]) + .query(), + 2, + ); -// db.exec_ids( -// QueryBuilder::select().search().from("alias1").query(), -// &[1, -6, 3, -7, 5], -// ); -// } + db.exec_elements( + QueryBuilder::select() + .search() + .from("alias1") + .where_() + .node() + .query(), + &[ + DbElement { + id: DbId(1), + from: None, + to: None, + values: vec![("k", 1).into()], + }, + DbElement { + id: DbId(3), + from: None, + to: None, + values: vec![("k", 3).into()], + }, + DbElement { + id: DbId(5), + from: None, + to: None, + values: vec![("k", 5).into()], + }, + ], + ); +} From 11eb3e166dad4c75a1ec167c93bc00dc48c95748 Mon Sep 17 00:00:00 2001 From: Michael Vlach Date: Mon, 23 Sep 2024 20:21:35 +0200 Subject: [PATCH 05/13] keys & key_count --- agdb/src/query/select_key_count_query.rs | 12 +++++ agdb/src/query/select_keys_query.rs | 12 +++++ agdb/src/query_builder/select.rs | 2 + agdb/src/query_builder/select_key_count.rs | 9 ++++ agdb/src/query_builder/select_keys.rs | 7 +++ agdb/tests/select_key_count_test.rs | 55 +++++++++++++++++++- agdb/tests/select_keys.rs | 58 ++++++++++++++++++++++ 7 files changed, 154 insertions(+), 1 deletion(-) diff --git a/agdb/src/query/select_key_count_query.rs b/agdb/src/query/select_key_count_query.rs index 148ae996..3d6cf08b 100644 --- a/agdb/src/query/select_key_count_query.rs +++ b/agdb/src/query/select_key_count_query.rs @@ -1,9 +1,11 @@ +use crate::query_builder::search::SearchQueryBuilder; use crate::DbElement; use crate::DbImpl; use crate::Query; use crate::QueryError; use crate::QueryIds; use crate::QueryResult; +use crate::SearchQuery; use crate::StorageData; /// Query to select number of properties (key count) of @@ -55,3 +57,13 @@ impl Query for &SelectKeyCountQuery { (*self).process(db) } } + +impl SearchQueryBuilder for SelectKeyCountQuery { + fn search_mut(&mut self) -> &mut SearchQuery { + if let QueryIds::Search(search) = &mut self.0 { + search + } else { + panic!("Expected search query"); + } + } +} diff --git a/agdb/src/query/select_keys_query.rs b/agdb/src/query/select_keys_query.rs index 2e3fef3e..bcf93046 100644 --- a/agdb/src/query/select_keys_query.rs +++ b/agdb/src/query/select_keys_query.rs @@ -1,9 +1,11 @@ +use crate::query_builder::search::SearchQueryBuilder; use crate::DbElement; use crate::DbImpl; use crate::Query; use crate::QueryError; use crate::QueryIds; use crate::QueryResult; +use crate::SearchQuery; use crate::StorageData; /// Query to select only property keys of given ids. All @@ -54,3 +56,13 @@ impl Query for &SelectKeysQuery { (*self).process(db) } } + +impl SearchQueryBuilder for SelectKeysQuery { + fn search_mut(&mut self) -> &mut SearchQuery { + if let QueryIds::Search(search) = &mut self.0 { + search + } else { + panic!("Expected search query"); + } + } +} diff --git a/agdb/src/query_builder/select.rs b/agdb/src/query_builder/select.rs index 2c04b7b7..dfc8e9de 100644 --- a/agdb/src/query_builder/select.rs +++ b/agdb/src/query_builder/select.rs @@ -108,6 +108,8 @@ impl Select { SelectNodeCount {} } + /// Select with all properties (key-values) using result + /// of the search query as ids. Equivalent to `ids(QueryBuilder::search()/* ... */)`. pub fn search(self) -> Search { Search(SelectValuesQuery { keys: vec![], diff --git a/agdb/src/query_builder/select_key_count.rs b/agdb/src/query_builder/select_key_count.rs index de6824b7..ee6d2f7c 100644 --- a/agdb/src/query_builder/select_key_count.rs +++ b/agdb/src/query_builder/select_key_count.rs @@ -1,3 +1,4 @@ +use crate::query_builder::search::Search; use crate::QueryIds; use crate::SelectKeyCountQuery; @@ -16,6 +17,14 @@ impl SelectKeyCount { SelectKeyCountIds(self.0) } + + /// Select key count for elements returned from the search query. + /// Equivalent to `ids(QueryBuilder::search()/* ... */)`. + pub fn search(self) -> Search { + Search(SelectKeyCountQuery(QueryIds::Search( + crate::SearchQuery::new(), + ))) + } } impl SelectKeyCountIds { diff --git a/agdb/src/query_builder/select_keys.rs b/agdb/src/query_builder/select_keys.rs index c24998a9..079b5158 100644 --- a/agdb/src/query_builder/select_keys.rs +++ b/agdb/src/query_builder/select_keys.rs @@ -1,3 +1,4 @@ +use crate::query_builder::search::Search; use crate::QueryIds; use crate::SelectKeysQuery; @@ -16,6 +17,12 @@ impl SelectKeys { SelectKeysIds(self.0) } + + /// Select keys of elements returned from the search query. + /// Equivalent to `ids(QueryBuilder::search()/* ... */)`. + pub fn search(self) -> Search { + Search(SelectKeysQuery(QueryIds::Search(crate::SearchQuery::new()))) + } } impl SelectKeysIds { diff --git a/agdb/tests/select_key_count_test.rs b/agdb/tests/select_key_count_test.rs index 655c1067..ee55ff70 100644 --- a/agdb/tests/select_key_count_test.rs +++ b/agdb/tests/select_key_count_test.rs @@ -47,7 +47,7 @@ fn select_keys_count_no_keys() { } #[test] -fn select_keys_search() { +fn select_key_count_search() { let mut db = TestDb::new(); let values = vec![ @@ -101,3 +101,56 @@ fn select_keys_search() { ], ); } + +#[test] +fn select_key_count_search_alt() { + let mut db = TestDb::new(); + + let values = vec![ + ("key1", 1).into(), + ("key2", 10).into(), + ("key3", 100).into(), + ]; + + db.exec_mut( + QueryBuilder::insert() + .nodes() + .count(5) + .values_uniform(values.clone()) + .query(), + 5, + ); + db.exec_mut( + QueryBuilder::insert() + .edges() + .from([1, 3]) + .to([3, 5]) + .values_uniform(values) + .query(), + 2, + ); + + db.exec_elements( + QueryBuilder::select().key_count().search().from(3).query(), + &[ + DbElement { + id: DbId(3), + from: None, + to: None, + values: vec![("key_count", 3_u64).into()], + }, + DbElement { + id: DbId(-7), + from: Some(DbId(3)), + to: Some(DbId(5)), + values: vec![("key_count", 3_u64).into()], + }, + DbElement { + id: DbId(5), + from: None, + to: None, + values: vec![("key_count", 3_u64).into()], + }, + ], + ); +} diff --git a/agdb/tests/select_keys.rs b/agdb/tests/select_keys.rs index fff8ced2..b64402ef 100644 --- a/agdb/tests/select_keys.rs +++ b/agdb/tests/select_keys.rs @@ -111,3 +111,61 @@ fn select_keys_search() { ], ); } + +#[test] +fn select_keys_search_alt() { + let mut db = TestDb::new(); + + db.exec_mut( + QueryBuilder::insert() + .nodes() + .count(5) + .values_uniform([ + ("key1", 1).into(), + ("key2", 10).into(), + ("key3", 100).into(), + ]) + .query(), + 5, + ); + db.exec_mut( + QueryBuilder::insert() + .edges() + .from([1, 3]) + .to([3, 5]) + .query(), + 2, + ); + + db.exec_elements( + QueryBuilder::select().keys().search().from(3).query(), + &[ + DbElement { + id: DbId(3), + from: None, + to: None, + values: vec![ + ("key1", DbValue::default()).into(), + ("key2", DbValue::default()).into(), + ("key3", DbValue::default()).into(), + ], + }, + DbElement { + id: DbId(-7), + from: Some(DbId(3)), + to: Some(DbId(5)), + values: vec![], + }, + DbElement { + id: DbId(5), + from: None, + to: None, + values: vec![ + ("key1", DbValue::default()).into(), + ("key2", DbValue::default()).into(), + ("key3", DbValue::default()).into(), + ], + }, + ], + ); +} From 54cb0f79d6684e2538b6bc53423ef033359e3a8a Mon Sep 17 00:00:00 2001 From: Michael Vlach Date: Mon, 23 Sep 2024 21:32:45 +0200 Subject: [PATCH 06/13] add more alts --- agdb/src/query/remove_query.rs | 23 +++++++ agdb/src/query/remove_values_query.rs | 27 ++++++++ agdb/src/query/select_aliases_query.rs | 23 +++++++ agdb/src/query/select_edge_count_query.rs | 28 +++++++++ agdb/src/query/select_key_count_query.rs | 11 ++++ agdb/src/query/select_keys_query.rs | 11 ++++ agdb/src/query/select_values_query.rs | 15 +++++ agdb/src/query_builder/remove.rs | 8 +++ agdb/src/query_builder/remove_values.rs | 9 +++ agdb/src/query_builder/select_aliases.rs | 9 +++ agdb/src/query_builder/select_edge_count.rs | 8 +++ agdb/src/query_builder/select_values.rs | 8 +++ agdb/tests/remove_index_test.rs | 2 +- agdb/tests/remove_nodes_test.rs | 11 ++++ agdb/tests/remove_values_test.rs | 38 ++++++++++++ agdb/tests/select_aliases_test.rs | 44 +++++++++++++ agdb/tests/select_edge_count_test.rs | 68 +++++++++++++++++++++ agdb/tests/select_values_test.rs | 54 ++++++++++++++++ 18 files changed, 396 insertions(+), 1 deletion(-) diff --git a/agdb/src/query/remove_query.rs b/agdb/src/query/remove_query.rs index 97d89ec7..ab18d4f2 100644 --- a/agdb/src/query/remove_query.rs +++ b/agdb/src/query/remove_query.rs @@ -1,8 +1,10 @@ +use crate::query_builder::search::SearchQueryBuilder; use crate::DbImpl; use crate::QueryError; use crate::QueryIds; use crate::QueryMut; use crate::QueryResult; +use crate::SearchQuery; use crate::StorageData; /// Query to remove database elements (nodes & edges). It @@ -53,3 +55,24 @@ impl QueryMut for &RemoveQuery { (*self).process(db) } } + +impl SearchQueryBuilder for RemoveQuery { + fn search_mut(&mut self) -> &mut SearchQuery { + if let QueryIds::Search(search) = &mut self.0 { + search + } else { + panic!("Expected search query"); + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + #[should_panic] + fn missing_search() { + RemoveQuery(QueryIds::Ids(vec![])).search_mut(); + } +} diff --git a/agdb/src/query/remove_values_query.rs b/agdb/src/query/remove_values_query.rs index 9b557fe7..992f0ffc 100644 --- a/agdb/src/query/remove_values_query.rs +++ b/agdb/src/query/remove_values_query.rs @@ -1,8 +1,10 @@ +use crate::query_builder::search::SearchQueryBuilder; use crate::DbImpl; use crate::QueryError; use crate::QueryIds; use crate::QueryMut; use crate::QueryResult; +use crate::SearchQuery; use crate::SelectValuesQuery; use crate::StorageData; @@ -49,3 +51,28 @@ impl QueryMut for &RemoveValuesQuery { (*self).process(db) } } + +impl SearchQueryBuilder for RemoveValuesQuery { + fn search_mut(&mut self) -> &mut SearchQuery { + if let QueryIds::Search(search) = &mut self.0.ids { + search + } else { + panic!("Expected search query"); + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + #[should_panic] + fn missing_search() { + RemoveValuesQuery(SelectValuesQuery { + keys: vec![], + ids: QueryIds::Ids(vec![]), + }) + .search_mut(); + } +} diff --git a/agdb/src/query/select_aliases_query.rs b/agdb/src/query/select_aliases_query.rs index 7928c3c0..d331d3fc 100644 --- a/agdb/src/query/select_aliases_query.rs +++ b/agdb/src/query/select_aliases_query.rs @@ -1,3 +1,4 @@ +use crate::query_builder::search::SearchQueryBuilder; use crate::DbElement; use crate::DbImpl; use crate::Query; @@ -5,6 +6,7 @@ use crate::QueryError; use crate::QueryId; use crate::QueryIds; use crate::QueryResult; +use crate::SearchQuery; use crate::StorageData; /// Query to select aliases of given ids. All of the ids @@ -69,3 +71,24 @@ impl Query for &SelectAliasesQuery { (*self).process(db) } } + +impl SearchQueryBuilder for SelectAliasesQuery { + fn search_mut(&mut self) -> &mut SearchQuery { + if let QueryIds::Search(search) = &mut self.0 { + search + } else { + panic!("Expected search query"); + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + #[should_panic] + fn missing_search() { + SelectAliasesQuery(QueryIds::Ids(vec![])).search_mut(); + } +} diff --git a/agdb/src/query/select_edge_count_query.rs b/agdb/src/query/select_edge_count_query.rs index 8c701b06..df88dddc 100644 --- a/agdb/src/query/select_edge_count_query.rs +++ b/agdb/src/query/select_edge_count_query.rs @@ -1,9 +1,11 @@ +use crate::query_builder::search::SearchQueryBuilder; use crate::DbElement; use crate::DbImpl; use crate::Query; use crate::QueryError; use crate::QueryIds; use crate::QueryResult; +use crate::SearchQuery; use crate::StorageData; /// Query to select number of edges of given node ids. @@ -72,3 +74,29 @@ impl Query for &SelectEdgeCountQuery { (*self).process(db) } } + +impl SearchQueryBuilder for SelectEdgeCountQuery { + fn search_mut(&mut self) -> &mut SearchQuery { + if let QueryIds::Search(search) = &mut self.ids { + search + } else { + panic!("Expected search query"); + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + #[should_panic] + fn missing_search() { + SelectEdgeCountQuery { + ids: QueryIds::Ids(vec![]), + from: false, + to: false, + } + .search_mut(); + } +} diff --git a/agdb/src/query/select_key_count_query.rs b/agdb/src/query/select_key_count_query.rs index 3d6cf08b..e319883a 100644 --- a/agdb/src/query/select_key_count_query.rs +++ b/agdb/src/query/select_key_count_query.rs @@ -67,3 +67,14 @@ impl SearchQueryBuilder for SelectKeyCountQuery { } } } + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + #[should_panic] + fn missing_search() { + SelectKeyCountQuery(QueryIds::Ids(vec![])).search_mut(); + } +} diff --git a/agdb/src/query/select_keys_query.rs b/agdb/src/query/select_keys_query.rs index bcf93046..f5d892df 100644 --- a/agdb/src/query/select_keys_query.rs +++ b/agdb/src/query/select_keys_query.rs @@ -66,3 +66,14 @@ impl SearchQueryBuilder for SelectKeysQuery { } } } + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + #[should_panic] + fn missing_search() { + SelectKeysQuery(QueryIds::Ids(vec![])).search_mut(); + } +} diff --git a/agdb/src/query/select_values_query.rs b/agdb/src/query/select_values_query.rs index e8764297..998cccca 100644 --- a/agdb/src/query/select_values_query.rs +++ b/agdb/src/query/select_values_query.rs @@ -88,3 +88,18 @@ impl SearchQueryBuilder for SelectValuesQuery { } } } + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + #[should_panic] + fn missing_search() { + SelectValuesQuery { + keys: vec![], + ids: QueryIds::Ids(vec![]), + } + .search_mut(); + } +} diff --git a/agdb/src/query_builder/remove.rs b/agdb/src/query_builder/remove.rs index eaffa607..503f1688 100644 --- a/agdb/src/query_builder/remove.rs +++ b/agdb/src/query_builder/remove.rs @@ -4,11 +4,13 @@ use crate::query_builder::remove_aliases::RemoveAliases; use crate::query_builder::remove_ids::RemoveIds; use crate::query_builder::remove_index::RemoveIndex; use crate::query_builder::remove_values::RemoveValues; +use crate::query_builder::search::Search; use crate::DbValue; use crate::QueryIds; use crate::RemoveAliasesQuery; use crate::RemoveQuery; use crate::RemoveValuesQuery; +use crate::SearchQuery; use crate::SelectValuesQuery; /// Remove builder to choose what to delete from the database. @@ -38,6 +40,12 @@ impl Remove { RemoveIndex(key.into()) } + /// Remove the elements found using the search query. + /// Equivalent to `ids(QueryIds::Search(search)/*...*/)`. + pub fn search(self) -> Search { + Search(RemoveQuery(QueryIds::Search(SearchQuery::new()))) + } + /// List of keys to delete from ids selected in the next step. It is not an /// error if not all of the keys exist on the elements. /// diff --git a/agdb/src/query_builder/remove_values.rs b/agdb/src/query_builder/remove_values.rs index 6befc33c..a94beeeb 100644 --- a/agdb/src/query_builder/remove_values.rs +++ b/agdb/src/query_builder/remove_values.rs @@ -1,5 +1,7 @@ +use crate::query_builder::search::Search; use crate::QueryIds; use crate::RemoveValuesQuery; +use crate::SearchQuery; /// Remove values builder that lets you select the ids from /// which to remove the values. @@ -17,6 +19,13 @@ impl RemoveValues { RemoveValuesIds(self.0) } + + /// Remove the values from the elements found using the search query. + /// Equivalent to `ids(QueryIds::Search(search)/*...*/)`. + pub fn search(mut self) -> Search { + self.0 .0.ids = QueryIds::Search(SearchQuery::new()); + Search(self.0) + } } impl RemoveValuesIds { diff --git a/agdb/src/query_builder/select_aliases.rs b/agdb/src/query_builder/select_aliases.rs index d6b83c24..35cc3ae6 100644 --- a/agdb/src/query_builder/select_aliases.rs +++ b/agdb/src/query_builder/select_aliases.rs @@ -1,4 +1,6 @@ +use crate::query_builder::search::Search; use crate::QueryIds; +use crate::SearchQuery; use crate::SelectAliasesQuery; use crate::SelectAllAliasesQuery; @@ -18,6 +20,13 @@ impl SelectAliases { SelectAliasesIds(self.0) } + /// Select using the result of a search query as ids. + /// Equivalent to `ids(QueryBuilder::search()/* ... */)`. + pub fn search(mut self) -> Search { + self.0 .0 = QueryIds::Search(SearchQuery::new()); + Search(self.0) + } + /// Returns the built `SelectAllAliases` object. pub fn query(self) -> SelectAllAliasesQuery { SelectAllAliasesQuery {} diff --git a/agdb/src/query_builder/select_edge_count.rs b/agdb/src/query_builder/select_edge_count.rs index f636ad33..ed20cef9 100644 --- a/agdb/src/query_builder/select_edge_count.rs +++ b/agdb/src/query_builder/select_edge_count.rs @@ -1,3 +1,4 @@ +use crate::query_builder::search::Search; use crate::QueryIds; use crate::SelectEdgeCountQuery; @@ -16,6 +17,13 @@ impl SelectEdgeCount { SelectEdgeCountIds(self.0) } + + /// Select keys of elements returned from the search query. + /// Equivalent to `ids(QueryBuilder::search()/* ... */)`. + pub fn search(mut self) -> Search { + self.0.ids = QueryIds::Search(crate::SearchQuery::new()); + Search(self.0) + } } impl SelectEdgeCountIds { diff --git a/agdb/src/query_builder/select_values.rs b/agdb/src/query_builder/select_values.rs index 0968a194..4dfe6016 100644 --- a/agdb/src/query_builder/select_values.rs +++ b/agdb/src/query_builder/select_values.rs @@ -1,3 +1,4 @@ +use crate::query_builder::search::Search; use crate::QueryIds; use crate::SelectValuesQuery; @@ -16,6 +17,13 @@ impl SelectValues { SelectValuesIds(self.0) } + + /// Select using the result of a search query as ids. + /// Equivalent to `ids(QueryBuilder::search()/* ... */)`. + pub fn search(mut self) -> Search { + self.0.ids = QueryIds::Search(crate::SearchQuery::new()); + Search(self.0) + } } impl SelectValuesIds { diff --git a/agdb/tests/remove_index_test.rs b/agdb/tests/remove_index_test.rs index 9e6671d3..0c05cb75 100644 --- a/agdb/tests/remove_index_test.rs +++ b/agdb/tests/remove_index_test.rs @@ -25,7 +25,7 @@ fn remove_index_with_data() { } #[test] -fn rmove_missing_index() { +fn remove_missing_index() { let mut db = TestDb::new(); db.exec_mut(QueryBuilder::remove().index("username").query(), 0); } diff --git a/agdb/tests/remove_nodes_test.rs b/agdb/tests/remove_nodes_test.rs index 7b74b0a7..139fc9c0 100644 --- a/agdb/tests/remove_nodes_test.rs +++ b/agdb/tests/remove_nodes_test.rs @@ -210,6 +210,17 @@ fn remove_nodes_search() { db.exec_error(QueryBuilder::select().ids(2).query(), "Id '2' not found"); } +#[test] +fn remove_nodes_search_alt() { + let mut db = TestDb::new(); + db.exec_mut(QueryBuilder::insert().nodes().count(2).query(), 2); + db.exec_mut_ids(QueryBuilder::insert().edges().from(1).to(2).query(), &[-3]); + + db.exec_mut(QueryBuilder::remove().search().from(1).query(), -2); + db.exec_error(QueryBuilder::select().ids(1).query(), "Id '1' not found"); + db.exec_error(QueryBuilder::select().ids(2).query(), "Id '2' not found"); +} + #[test] fn remove_nodes_removes_edges_with_all_values() { let mut db = TestDb::new(); diff --git a/agdb/tests/remove_values_test.rs b/agdb/tests/remove_values_test.rs index 133b083a..5932ff20 100644 --- a/agdb/tests/remove_values_test.rs +++ b/agdb/tests/remove_values_test.rs @@ -96,6 +96,44 @@ fn remove_values_search() { ); } +#[test] +fn remove_values_search_alt() { + let mut db = TestDb::new(); + db.exec_mut( + QueryBuilder::insert() + .nodes() + .values([[("key", 1).into()], [("key", 2).into()]]) + .query(), + 2, + ); + db.exec_mut(QueryBuilder::insert().edges().from(1).to(2).query(), 1); + db.exec_mut( + QueryBuilder::remove() + .values("key") + .search() + .from(1) + .query(), + -2, + ); + db.exec_elements( + QueryBuilder::select().ids([1, 2]).query(), + &[ + DbElement { + id: DbId(1), + from: None, + to: None, + values: vec![], + }, + DbElement { + id: DbId(2), + from: None, + to: None, + values: vec![], + }, + ], + ); +} + #[test] fn remove_missing_key() { let mut db = TestDb::new(); diff --git a/agdb/tests/select_aliases_test.rs b/agdb/tests/select_aliases_test.rs index 359dbb1c..9505e362 100644 --- a/agdb/tests/select_aliases_test.rs +++ b/agdb/tests/select_aliases_test.rs @@ -131,6 +131,50 @@ fn select_aliases_search() { ); } +#[test] +fn select_aliases_search_alt() { + let mut db = TestDb::new(); + + db.exec_mut( + QueryBuilder::insert() + .nodes() + .aliases(["alias1", "alias2", "alias3", "alias4", "alias5"]) + .query(), + 5, + ); + db.exec_mut( + QueryBuilder::insert() + .edges() + .from([1, 3]) + .to([3, 5]) + .values_uniform([ + ("key1", 1).into(), + ("key2", 10).into(), + ("key3", 100).into(), + ]) + .query(), + 2, + ); + + db.exec_elements( + QueryBuilder::select().aliases().search().from(3).query(), + &[ + DbElement { + id: DbId(3), + from: None, + to: None, + values: vec![("alias", "alias3").into()], + }, + DbElement { + id: DbId(5), + from: None, + to: None, + values: vec![("alias", "alias5").into()], + }, + ], + ); +} + #[test] fn select_all_aliases_empty() { let db = TestDb::new(); diff --git a/agdb/tests/select_edge_count_test.rs b/agdb/tests/select_edge_count_test.rs index 1d8e861c..d59c59f8 100644 --- a/agdb/tests/select_edge_count_test.rs +++ b/agdb/tests/select_edge_count_test.rs @@ -201,6 +201,74 @@ fn select_edge_count_search() { ); } +#[test] +fn select_edge_count_search_alt() { + let mut db = TestDb::new(); + db.exec_mut( + QueryBuilder::insert() + .nodes() + .aliases(["node1", "node2", "node3"]) + .query(), + 3, + ); + db.exec_mut( + QueryBuilder::insert() + .edges() + .from(["node1", "node3", "node2", "node2"]) + .to(["node3", "node2", "node1", "node2"]) + .query(), + 4, + ); + + db.exec_elements( + QueryBuilder::select() + .edge_count() + .search() + .from("node1") + .where_() + .edge_count(CountComparison::Equal(4)) + .query(), + &[DbElement { + id: DbId(2), + from: None, + to: None, + values: vec![("edge_count", 4_u64).into()], + }], + ); + + db.exec_elements( + QueryBuilder::select() + .edge_count_from() + .search() + .from("node1") + .where_() + .edge_count(CountComparison::Equal(4)) + .query(), + &[DbElement { + id: DbId(2), + from: None, + to: None, + values: vec![("edge_count", 2_u64).into()], + }], + ); + + db.exec_elements( + QueryBuilder::select() + .edge_count_to() + .search() + .from("node1") + .where_() + .edge_count(CountComparison::Equal(4)) + .query(), + &[DbElement { + id: DbId(2), + from: None, + to: None, + values: vec![("edge_count", 2_u64).into()], + }], + ); +} + #[test] fn select_edge_count_non_nodes() { let mut db = TestDb::new(); diff --git a/agdb/tests/select_values_test.rs b/agdb/tests/select_values_test.rs index b7ea79dd..c5a5b8de 100644 --- a/agdb/tests/select_values_test.rs +++ b/agdb/tests/select_values_test.rs @@ -128,3 +128,57 @@ fn select_values_search() { ], ); } + +#[test] +fn select_values_search_alt() { + let mut db = TestDb::new(); + + db.exec_mut( + QueryBuilder::insert() + .nodes() + .count(5) + .values_uniform([ + ("key1", 1).into(), + ("key2", 10).into(), + ("key3", 100).into(), + ]) + .query(), + 5, + ); + db.exec_mut( + QueryBuilder::insert() + .edges() + .from([1, 3]) + .to([3, 5]) + .query(), + 2, + ); + + db.exec_elements( + QueryBuilder::select() + .values("key2") + .search() + .from(3) + .query(), + &[ + DbElement { + id: DbId(3), + from: None, + to: None, + values: vec![("key2", 10).into()], + }, + DbElement { + id: DbId(-7), + from: Some(DbId(3)), + to: Some(DbId(5)), + values: vec![], + }, + DbElement { + id: DbId(5), + from: None, + to: None, + values: vec![("key2", 10).into()], + }, + ], + ); +} From 2ccb016cb35f2ecefb678b4c67fb7c45fd0b749c Mon Sep 17 00:00:00 2001 From: Michael Vlach Date: Mon, 23 Sep 2024 21:38:59 +0200 Subject: [PATCH 07/13] add search to inserts --- agdb/src/query/insert_values_query.rs | 27 +++++++++++++++ agdb/src/query_builder/insert_values.rs | 9 +++++ agdb/tests/insert_values_test.rs | 44 +++++++++++++++++++++++++ 3 files changed, 80 insertions(+) diff --git a/agdb/src/query/insert_values_query.rs b/agdb/src/query/insert_values_query.rs index ae1f66c2..2eab5582 100644 --- a/agdb/src/query/insert_values_query.rs +++ b/agdb/src/query/insert_values_query.rs @@ -1,4 +1,5 @@ use crate::query::query_values::QueryValues; +use crate::query_builder::search::SearchQueryBuilder; use crate::DbElement; use crate::DbId; use crate::DbImpl; @@ -8,6 +9,7 @@ use crate::QueryId; use crate::QueryIds; use crate::QueryMut; use crate::QueryResult; +use crate::SearchQuery; use crate::StorageData; /// Query to insert or update key-value pairs (properties) @@ -150,3 +152,28 @@ fn insert_values_id( } Ok(()) } + +impl SearchQueryBuilder for InsertValuesQuery { + fn search_mut(&mut self) -> &mut SearchQuery { + if let QueryIds::Search(search) = &mut self.ids { + search + } else { + panic!("Expected search query"); + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + #[should_panic] + fn missing_search() { + InsertValuesQuery { + values: QueryValues::Single(vec![]), + ids: QueryIds::Ids(vec![]), + } + .search_mut(); + } +} diff --git a/agdb/src/query_builder/insert_values.rs b/agdb/src/query_builder/insert_values.rs index bb752f19..15931a71 100644 --- a/agdb/src/query_builder/insert_values.rs +++ b/agdb/src/query_builder/insert_values.rs @@ -1,5 +1,7 @@ +use crate::query_builder::search::Search; use crate::InsertValuesQuery; use crate::QueryIds; +use crate::SearchQuery; /// Insert values builder to set ids to which the values /// should be inserted. @@ -16,6 +18,13 @@ impl InsertValues { InsertValuesIds(self.0) } + + /// Inserts values into elements found using the search query. + /// Equivalent to `ids(QueryIds::Search(search)/*...*/)`. + pub fn search(mut self) -> Search { + self.0.ids = QueryIds::Search(SearchQuery::new()); + Search(self.0) + } } impl InsertValuesIds { diff --git a/agdb/tests/insert_values_test.rs b/agdb/tests/insert_values_test.rs index d92975e8..90427f2c 100644 --- a/agdb/tests/insert_values_test.rs +++ b/agdb/tests/insert_values_test.rs @@ -239,6 +239,50 @@ fn insert_values_search() { ); } +#[test] +fn insert_values_search_alt() { + let mut db = TestDb::new(); + db.exec_mut(QueryBuilder::insert().nodes().count(3).query(), 3); + db.exec_mut(QueryBuilder::insert().edges().from(1).to(3).query(), 1); + db.exec_mut( + QueryBuilder::insert() + .values([ + [("key1", "value1").into()], + [("key2", "value2").into()], + [("key3", "value3").into()], + ]) + .search() + .from(1) + .query(), + 3, + ); + db.exec_elements( + QueryBuilder::select() + .ids(QueryBuilder::search().from(1).query()) + .query(), + &[ + DbElement { + id: DbId(1), + from: None, + to: None, + values: vec![("key1", "value1").into()], + }, + DbElement { + id: DbId(-4), + from: Some(DbId(1)), + to: Some(DbId(3)), + values: vec![("key2", "value2").into()], + }, + DbElement { + id: DbId(3), + from: None, + to: None, + values: vec![("key3", "value3").into()], + }, + ], + ); +} + #[test] fn insert_values_search_invalid_length() { let mut db = TestDb::new(); From 69f8ef2c2c2fd85db0d02ab8636f1f270c08ba68 Mon Sep 17 00:00:00 2001 From: Michael Vlach Date: Wed, 25 Sep 2024 19:05:52 +0200 Subject: [PATCH 08/13] Update search.rs --- agdb/src/query_builder/search.rs | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/agdb/src/query_builder/search.rs b/agdb/src/query_builder/search.rs index 46a0e19a..999db4dd 100644 --- a/agdb/src/query_builder/search.rs +++ b/agdb/src/query_builder/search.rs @@ -91,7 +91,7 @@ impl Search { /// through the entire database which may be prohibitively expensive. Consider /// using `limit()`. /// - /// Note2: While the full range of conitions can be used some conditions do not + /// Note: While the full range of conitions can be used some conditions do not /// make logical sense (e.g. distance, beyond, edge_count etc.). /// /// Options: @@ -109,6 +109,16 @@ impl Search { SearchTo(self.0) } + /// Searches an index specified by `key`. This is to provide fast lookup of + /// specific elements with particular key-value pair. + /// + /// Options: + /// + /// ``` + /// use agdb::QueryBuilder; + /// + /// QueryBuilder::search().index("k").value(1); + /// ``` pub fn index>(self, key: K) -> SearchIndex { SearchIndex { index: key.into(), From 23f0d316ad5cb586e2dd1733e47d3b2044d8a2e7 Mon Sep 17 00:00:00 2001 From: Michael Vlach Date: Wed, 25 Sep 2024 19:09:55 +0200 Subject: [PATCH 09/13] update readme --- README.md | 15 ++++++--------- agdb/tests/quickstart.rs | 15 ++++++--------- 2 files changed, 12 insertions(+), 18 deletions(-) diff --git a/README.md b/README.md index 1ef7f4ab..070aa8a9 100644 --- a/README.md +++ b/README.md @@ -133,15 +133,12 @@ You can also search through the graph to get back only certain elements based on let user: User = db .exec( QueryBuilder::select() - .values(User::db_keys()) - .ids( - QueryBuilder::search() - .from("users") - .where_() - .key("name") - .value(Equal("Bob".into())) - .query(), - ) + .elements::() + .search() + .from("users") + .where_() + .key("name") + .value(Equal("Bob".into())) .query(), )? .try_into()?; diff --git a/agdb/tests/quickstart.rs b/agdb/tests/quickstart.rs index 21947ba4..06ee2914 100644 --- a/agdb/tests/quickstart.rs +++ b/agdb/tests/quickstart.rs @@ -58,15 +58,12 @@ fn quickstart() -> Result<(), QueryError> { let user: User = db .exec( QueryBuilder::select() - .values(User::db_keys()) - .ids( - QueryBuilder::search() - .from("users") - .where_() - .key("name") - .value(Equal("Bob".into())) - .query(), - ) + .elements::() + .search() + .from("users") + .where_() + .key("name") + .value(Equal("Bob".into())) .query(), )? .try_into()?; From cf90c7e5e6dcdd5bc529059150cb0d090ecafb7f Mon Sep 17 00:00:00 2001 From: Michael Vlach Date: Wed, 25 Sep 2024 19:19:45 +0200 Subject: [PATCH 10/13] update examples --- examples/app_db/src/main.rs | 18 ++++------ examples/indexes/src/main.rs | 9 ++--- examples/joins/src/main.rs | 45 ++++++++++--------------- examples/schema_migration/src/main.rs | 11 +++--- examples/server_client_rust/src/main.rs | 15 ++++----- examples/strong_types/src/main.rs | 26 ++++++-------- 6 files changed, 49 insertions(+), 75 deletions(-) diff --git a/examples/app_db/src/main.rs b/examples/app_db/src/main.rs index d0eeb1e6..55c88dc0 100644 --- a/examples/app_db/src/main.rs +++ b/examples/app_db/src/main.rs @@ -55,23 +55,19 @@ fn main() -> Result<(), QueryError> { // SELECT * FROM users WHERE name = "user1" // ``` // - // It uses the `agdb::UserValue::db_keys()` to select required keys. It also - // changes the sarch algorithm to depth-first (default is breadth-first) + // It changes the search algorithm to depth-first (default is breadth-first) // which is more efficient when searching for a single item only. We could additionally // limit the search by adding `limit(1)` to ensure we get only one result back // and/or additional condition on `distance(Equal(2))` to stop search beyond users. But since // we know the structure of our data (graph) we can safely omit them as unnecessary here. let user_result = db.exec( QueryBuilder::select() - .ids( - QueryBuilder::search() - .depth_first() - .from("users") - .where_() - .key("username") - .value(Comparison::Equal("user1".into())) - .query(), - ) + .search() + .depth_first() + .from("users") + .where_() + .key("username") + .value(Comparison::Equal("user1".into())) .query(), )?; diff --git a/examples/indexes/src/main.rs b/examples/indexes/src/main.rs index 00a149d2..0d1c9cc2 100644 --- a/examples/indexes/src/main.rs +++ b/examples/indexes/src/main.rs @@ -58,12 +58,9 @@ fn main() -> Result<(), QueryError> { .exec( QueryBuilder::select() .values(User::db_keys()) - .ids( - QueryBuilder::search() - .index("username") - .value("user50") - .query(), - ) + .search() + .index("username") + .value("user50") .query(), )? .try_into()?; diff --git a/examples/joins/src/main.rs b/examples/joins/src/main.rs index fe264316..1406bd70 100644 --- a/examples/joins/src/main.rs +++ b/examples/joins/src/main.rs @@ -48,16 +48,13 @@ fn main() -> Result<(), QueryError> { let mut user_dbs: Vec = vec![]; db.exec( QueryBuilder::select() - .ids( - QueryBuilder::search() - .depth_first() - .from("user") - .where_() - .keys("role") - .or() - .keys("name") - .query(), - ) + .search() + .depth_first() + .from("user") + .where_() + .keys("role") + .or() + .keys("name") .query(), )? .elements @@ -87,15 +84,12 @@ fn main() -> Result<(), QueryError> { let user_dbs = db.transaction(|t| -> Result, QueryError> { let db_names = t.exec( QueryBuilder::select() - .ids( - QueryBuilder::search() - .from("user") - .where_() - .distance(CountComparison::Equal(2)) - .and() - .keys("name") - .query(), - ) + .search() + .from("user") + .where_() + .distance(CountComparison::Equal(2)) + .and() + .keys("name") .query(), )?; @@ -104,14 +98,11 @@ fn main() -> Result<(), QueryError> { for db_name in db_names.elements { let role = t.exec( QueryBuilder::select() - .ids( - QueryBuilder::search() - .to(db_name.id) - .limit(1) - .where_() - .keys("role") - .query(), - ) + .search() + .to(db_name.id) + .limit(1) + .where_() + .keys("role") .query(), )?; diff --git a/examples/schema_migration/src/main.rs b/examples/schema_migration/src/main.rs index 8cebd425..1d9920cc 100644 --- a/examples/schema_migration/src/main.rs +++ b/examples/schema_migration/src/main.rs @@ -110,13 +110,10 @@ fn main() -> Result<(), QueryError> { let users: Vec = t .exec( QueryBuilder::select() - .ids( - QueryBuilder::search() - .from("users") - .where_() - .distance(CountComparison::Equal(2)) - .query(), - ) + .search() + .from("users") + .where_() + .distance(CountComparison::Equal(2)) .query(), )? .try_into()?; diff --git a/examples/server_client_rust/src/main.rs b/examples/server_client_rust/src/main.rs index 32b36196..bf4201b1 100644 --- a/examples/server_client_rust/src/main.rs +++ b/examples/server_client_rust/src/main.rs @@ -60,15 +60,12 @@ async fn main() -> Result<(), anyhow::Error> { .query() .into(), QueryBuilder::select() - .ids( - QueryBuilder::search() - .depth_first() - .from("users") - .where_() - .key("username") - .value(Comparison::Equal("user1".into())) - .query(), - ) + .search() + .depth_first() + .from("users") + .where_() + .key("username") + .value(Comparison::Equal("user1".into())) .query() .into(), ]; diff --git a/examples/strong_types/src/main.rs b/examples/strong_types/src/main.rs index 73f427b8..61467b5e 100644 --- a/examples/strong_types/src/main.rs +++ b/examples/strong_types/src/main.rs @@ -1,7 +1,6 @@ use agdb::Comparison; use agdb::DbError; use agdb::DbMemory; -use agdb::DbUserValue; use agdb::DbValue; use agdb::QueryBuilder; use agdb::QueryError; @@ -106,10 +105,10 @@ fn main() -> Result<(), QueryError> { // SELECT username, password, status FROM users WHERE name = "user1" // ``` // - // It uses the `agdb::UserValue::db_keys()` to select required keys. It also - // changes the sarch algorithm to depth-first (default is breadth-first) - // which is more efficient when searching for a single item only. We could additionally - // limit the search by adding `limit(1)` to ensure we get only one result back + // Internally it uses the `agdb::DbUserValue::db_keys()` to select required keys as the `User` is + // required to implement the `DbUserValue` trait. It also changes the sarch algorithm to depth-first + // (default is breadth-first) which is more efficient when searching for a single item only. We could + // additionally limit the search by adding `limit(1)` to ensure we get only one result back // and/or additional condition on `distance(Equal(2))` to stop search beyond users. But since // we know the structure of our data (graph) we can safely omit them as unnecessary here. // @@ -118,16 +117,13 @@ fn main() -> Result<(), QueryError> { let user: User = db .exec( QueryBuilder::select() - .values(User::db_keys()) - .ids( - QueryBuilder::search() - .depth_first() - .from("users") - .where_() - .key("username") - .value(Comparison::Equal("user1".into())) - .query(), - ) + .elements::() + .search() + .depth_first() + .from("users") + .where_() + .key("username") + .value(Comparison::Equal("user1".into())) .query(), )? .try_into()?; From be3ec1955b07084e7c5c009ee609e3e44b3915c6 Mon Sep 17 00:00:00 2001 From: Michael Vlach Date: Wed, 25 Sep 2024 19:27:26 +0200 Subject: [PATCH 11/13] update efficient agdb --- agdb/tests/efficient_agdb.rs | 101 +++++++----------- .../docs/references/efficient-agdb.en-US.md | 101 ++++++++---------- 2 files changed, 83 insertions(+), 119 deletions(-) diff --git a/agdb/tests/efficient_agdb.rs b/agdb/tests/efficient_agdb.rs index 9bc8d2dd..82f26d3c 100644 --- a/agdb/tests/efficient_agdb.rs +++ b/agdb/tests/efficient_agdb.rs @@ -7,7 +7,6 @@ use agdb::Db; use agdb::DbId; use agdb::DbKeyOrder; use agdb::DbKeyValue; -use agdb::DbUserValue; use agdb::QueryBuilder; use agdb::QueryError; use agdb::QueryId; @@ -163,14 +162,11 @@ fn remove_like(db: &mut Db, user: DbId, id: DbId) -> Result<(), QueryError> { db.transaction_mut(|t| -> Result<(), QueryError> { t.exec_mut( QueryBuilder::remove() - .ids( - QueryBuilder::search() - .from(user) - .to(id) - .where_() - .keys("liked") - .query(), - ) + .search() + .from(user) + .to(id) + .where_() + .keys("liked") .query(), )?; Ok(()) @@ -182,18 +178,15 @@ fn login(db: &Db, username: &str, password: &str) -> Result { .exec( QueryBuilder::select() .values("password") - .ids( - QueryBuilder::search() - .depth_first() - .from("users") - .limit(1) - .where_() - .distance(CountComparison::Equal(2)) - .and() - .key("username") - .value(Equal(username.into())) - .query(), - ) + .search() + .depth_first() + .from("users") + .limit(1) + .where_() + .distance(CountComparison::Equal(2)) + .and() + .key("username") + .value(Equal(username.into())) .query(), )? .elements; @@ -242,16 +235,13 @@ fn posts(db: &Db, offset: u64, limit: u64) -> Result, QueryError> { Ok(db .exec( QueryBuilder::select() - .values(Post::db_keys()) - .ids( - QueryBuilder::search() - .from("posts") - .offset(offset) - .limit(limit) - .where_() - .distance(CountComparison::Equal(2)) - .query(), - ) + .elements::() + .search() + .from("posts") + .offset(offset) + .limit(limit) + .where_() + .distance(CountComparison::Equal(2)) .query(), )? .try_into()?) @@ -261,17 +251,14 @@ fn comments(db: &Db, id: DbId) -> Result, QueryError> { Ok(db .exec( QueryBuilder::select() - .values(Comment::db_keys()) - .ids( - QueryBuilder::search() - .depth_first() - .from(id) - .where_() - .node() - .and() - .distance(CountComparison::GreaterThan(1)) - .query(), - ) + .elements::() + .search() + .depth_first() + .from(id) + .where_() + .node() + .and() + .distance(CountComparison::GreaterThan(1)) .query(), )? .try_into()?) @@ -312,17 +299,14 @@ fn liked_posts(db: &Db, offset: u64, limit: u64) -> Result, Query Ok(db .exec( QueryBuilder::select() - .values(PostLiked::db_keys()) - .ids( - QueryBuilder::search() - .from("posts") - .order_by([DbKeyOrder::Desc("likes".into())]) - .offset(offset) - .limit(limit) - .where_() - .distance(CountComparison::Equal(2)) - .query(), - ) + .elements::() + .search() + .from("posts") + .order_by([DbKeyOrder::Desc("likes".into())]) + .offset(offset) + .limit(limit) + .where_() + .distance(CountComparison::Equal(2)) .query(), )? .try_into()?) @@ -332,13 +316,10 @@ fn mark_top_level_comments(db: &mut Db) -> Result<(), QueryError> { db.exec_mut( QueryBuilder::insert() .values_uniform([("level", 1).into()]) - .ids( - QueryBuilder::search() - .from("posts") - .where_() - .distance(CountComparison::Equal(4)) - .query(), - ) + .search() + .from("posts") + .where_() + .distance(CountComparison::Equal(4)) .query(), )?; Ok(()) diff --git a/agdb_web/pages/docs/references/efficient-agdb.en-US.md b/agdb_web/pages/docs/references/efficient-agdb.en-US.md index d413249d..8d4bd3f0 100644 --- a/agdb_web/pages/docs/references/efficient-agdb.en-US.md +++ b/agdb_web/pages/docs/references/efficient-agdb.en-US.md @@ -230,14 +230,11 @@ fn remove_like(db: &mut Db, user: DbId, id: DbId) -> Result<(), QueryError> { db.transaction_mut(|t| -> Result<(), QueryError> { t.exec_mut( QueryBuilder::remove() - .ids( - QueryBuilder::search() - .from(user) - .to(id) - .where_() - .keys(vec!["liked".into()]) - .query(), - ) + .search() + .from(user) + .to(id) + .where_() + .keys(vec!["liked".into()]) .query(), )?; Ok(()) @@ -282,18 +279,15 @@ fn login(db: &Db, username: &str, password: &str) -> Result { .exec( QueryBuilder::select() .values("password".into()) - .ids( - QueryBuilder::search() - .depth_first() - .from("users") - .limit(1) - .where_() - .distance(CountComparison::Equal(2)) - .and() - .key("username") - .value(Equal(username.into())) - .query(), - ) + .search() + .depth_first() + .from("users") + .limit(1) + .where_() + .distance(CountComparison::Equal(2)) + .and() + .key("username") + .value(Equal(username.into())) .query(), )? .elements; @@ -385,16 +379,13 @@ fn posts(db: &Db, offset: u64, limit: u64) -> Result, QueryError> { Ok(db .exec( QueryBuilder::select() - .values(Post::db_keys()) - .ids( - QueryBuilder::search() - .from("posts") - .offset(offset) - .limit(limit) - .where_() - .distance(CountComparison::Equal(2)) - .query(), - ) + .elements::() + .search() + .from("posts") + .offset(offset) + .limit(limit) + .where_() + .distance(CountComparison::Equal(2)) .query(), )? .try_into()?) @@ -414,17 +405,14 @@ fn comments(db: &Db, id: DbId) -> Result, QueryError> { Ok(db .exec( QueryBuilder::select() - .values(Comment::db_keys()) - .ids( - QueryBuilder::search() - .depth_first() - .from(id) - .where_() - .node() - .and() - .distance(CountComparison::GreaterThan(1)) - .query(), - ) + .elements::() + .search() + .depth_first() + .from(id) + .where_() + .node() + .and() + .distance(CountComparison::GreaterThan(1)) .query(), )? .try_into()?) @@ -460,6 +448,7 @@ fn add_likes_to_posts(db: &mut Db) -> Result<(), QueryError> { .distance(CountComparison::Equal(2)) .query(), )?; + let mut likes = Vec::>::new(); for post in posts.ids() { @@ -502,17 +491,14 @@ fn liked_posts(db: &Db, offset: u64, limit: u64) -> Result, Query Ok(db .exec( QueryBuilder::select() - .values(PostLiked::db_keys()) - .ids( - QueryBuilder::search() - .from("posts") - .order_by([DbKeyOrder::Desc("likes".into())]) - .offset(offset) - .limit(limit) - .where_() - .distance(CountComparison::Equal(2)) - .query(), - ) + .elements::() + .search() + .from("posts") + .order_by([DbKeyOrder::Desc("likes".into())]) + .offset(offset) + .limit(limit) + .where_() + .distance(CountComparison::Equal(2)) .query(), )? .try_into()?) @@ -530,13 +516,10 @@ fn mark_top_level_comments(db: &mut Db) -> Result<(), QueryError> { db.exec_mut( QueryBuilder::insert() .values_uniform([("level", 1).into()]) - .ids( - QueryBuilder::search() - .from("posts") - .where_() - .distance(CountComparison::Equal(4)) - .query(), - ) + .search() + .from("posts") + .where_() + .distance(CountComparison::Equal(4)) .query(), )?; Ok(()) From b9fe519d8d8d9b1a0759e35ba90eef83eeda95f1 Mon Sep 17 00:00:00 2001 From: Michael Vlach Date: Wed, 25 Sep 2024 19:39:50 +0200 Subject: [PATCH 12/13] Update queries.en-US.md --- agdb_web/pages/docs/references/queries.en-US.md | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/agdb_web/pages/docs/references/queries.en-US.md b/agdb_web/pages/docs/references/queries.en-US.md index 2e19bac2..08bb0dd2 100644 --- a/agdb_web/pages/docs/references/queries.en-US.md +++ b/agdb_web/pages/docs/references/queries.en-US.md @@ -521,8 +521,10 @@ QueryBuilder::insert().element(&T { ... }).query(); //Where T: DbUserValue (i.e. QueryBuilder::insert().elements(&vec![T {...}, T {...}]).query(); //Where T: DbUserValue (i.e. #derive(UserValue)) QueryBuilder::insert().values([vec![("k", "v").into(), (1, 10).into()], vec![("k", 2).into()]]).ids([1, 2]).query(); QueryBuilder::insert().values([vec![("k", "v").into(), (1, 10).into()], vec![("k", 2).into()]]).ids(QueryBuilder::search().from("a").query()).query(); +QueryBuilder::insert().values([vec![("k", "v").into(), (1, 10).into()], vec![("k", 2).into()]]).search().from("a").query(); //Equivalent to the previous query QueryBuilder::insert().values_uniform([("k", "v").into(), (1, 10).into()]).ids([1, 2]).query(); QueryBuilder::insert().values_uniform([("k", "v").into(), (1, 10).into()]).ids(QueryBuilder::search().from("a").query()).query(); +QueryBuilder::insert().values_uniform([("k", "v").into(), (1, 10).into()]).search().from("a").query(); //Equivalent to the previous query ``` @@ -600,6 +602,7 @@ QueryBuilder::remove().ids("a").query(); QueryBuilder::remove().ids([1, 2]).query(); QueryBuilder::remove().ids(["a", "b"]).query(); QueryBuilder::remove().ids(QueryBuilder::search().from("a").query()).query(); +QueryBuilder::remove().search().from("a").query(); //Equivalent to the previous query ``` @@ -659,6 +662,7 @@ pub struct QueryResult { ```rs QueryBuilder::remove().values(["k1".into(), "k2".into()]).ids([1, 2]).query(); QueryBuilder::remove().values(["k1".into(), "k2".into()]).ids(QueryBuilder::search().from("a").query()).query(); +QueryBuilder::remove().values(["k1".into(), "k2".into()]).search().from("a").query(); //Equivalent to the previous query ``` @@ -705,6 +709,7 @@ pub struct QueryResult { ```rs QueryBuilder::select().aliases().ids([1, 2]).query(); QueryBuilder::select().aliases().ids(QueryBuilder::search().from(1).query()).query(); +QueryBuilder::select().aliases().search().from(1).query(); //Equivalent to the previous query ``` @@ -771,6 +776,8 @@ pub struct QueryResult { QueryBuilder::select().edge_count().ids([1, 2]).query(); QueryBuilder::select().edge_count_from().ids([1, 2]).query(); QueryBuilder::select().edge_count_to().ids([1, 2]).query(); +QueryBuilder::select().edge_count().ids(QueryBuilder::search().from("a").query()).query(); +QueryBuilder::select().edge_count().search().from("a").query(); // Equivalent to the previous query ``` @@ -836,6 +843,7 @@ pub struct QueryResult { QueryBuilder::select().keys().ids("a").query(); QueryBuilder::select().keys().ids([1, 2]).query(); QueryBuilder::select().keys().ids(QueryBuilder::search().from(1).query()).query(); +QueryBuilder::select().keys().search().from(1).query(); // Equivalent to the previous query ``` @@ -868,6 +876,7 @@ pub struct QueryResult { QueryBuilder::select().key_count().ids("a").query(); QueryBuilder::select().key_count().ids([1, 2]).query(); QueryBuilder::select().key_count().ids(QueryBuilder::search().from(1).query()).query(); +QueryBuilder::select().key_count().search().from(1).query(); // Equivalent to the previous query ``` @@ -927,13 +936,18 @@ pub struct QueryResult { Builder ```rs + QueryBuilder::select().ids("a").query(); QueryBuilder::select().ids([1, 2]).query(); QueryBuilder::select().ids(QueryBuilder::search().from(1).query()).query(); +QueryBuilder::select().search().from(1).query(); // Equivalent to the previous query QueryBuilder::select().values(["k".into(), "k2".into()]).ids("a").query(); QueryBuilder::select().values(["k".into(), "k2".into()]).ids([1, 2]).query(); QueryBuilder::select().values(["k".into(), "k2".into()]).ids(QueryBuilder::search().from(1).query()).query(); +QueryBuilder::select().values(["k".into(), "k2".into()]).search().from(1).query(); // Equivalent to the previous query QueryBuilder::select().elements::().ids(1).query(); +QueryBuilder::select().elements::().ids(QueryBuilder::search().from("a").query()).query(); +QueryBuilder::select().elements::().search().from("a").query(); // Equivalent to the previous query ``` From 5acab3b97d4759862fb91ad284b16af5c8e6ff4e Mon Sep 17 00:00:00 2001 From: Michael Vlach Date: Wed, 25 Sep 2024 19:41:18 +0200 Subject: [PATCH 13/13] Update quickstart.en-US.mdx --- agdb_web/pages/docs/guides/quickstart.en-US.mdx | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/agdb_web/pages/docs/guides/quickstart.en-US.mdx b/agdb_web/pages/docs/guides/quickstart.en-US.mdx index 515f6c5a..75ae5652 100644 --- a/agdb_web/pages/docs/guides/quickstart.en-US.mdx +++ b/agdb_web/pages/docs/guides/quickstart.en-US.mdx @@ -111,16 +111,13 @@ db.exec_mut( let users: Vec = db .exec( QueryBuilder::select() - .values(User::db_keys()) // Select only relevant properties for the User struct. - .ids( - QueryBuilder::search() - .from("users") // Start the search from the "users" node. - .where_() - .key("age") // Examine "age" property. - .value(LessThan(40.into())) // Include it in the search result if the value - // is less than 40. - .query(), - ) + .elements::() // Select only relevant properties for the User struct. + .search() + .from("users") // Start the search from the "users" node. + .where_() + .key("age") // Examine "age" property. + .value(LessThan(40.into())) // Include it in the search result if the value + // is less than 40. .query(), )? .try_into()?; // Convert the result into a list of User objects.