diff --git a/query-engine/connector-test-kit-rs/query-engine-tests/tests/queries/distinct.rs b/query-engine/connector-test-kit-rs/query-engine-tests/tests/queries/distinct.rs index aff7845eee90..bc52fb7cfdf6 100644 --- a/query-engine/connector-test-kit-rs/query-engine-tests/tests/queries/distinct.rs +++ b/query-engine/connector-test-kit-rs/query-engine-tests/tests/queries/distinct.rs @@ -85,7 +85,7 @@ mod distinct { } #[connector_test] - async fn with_skip(runner: Runner) -> TestResult<()> { + async fn with_skip_basic(runner: Runner) -> TestResult<()> { test_user(&runner, r#"{ id: 1, first_name: "Joe", last_name: "Doe", email: "1" }"#).await?; test_user( &runner, @@ -104,7 +104,7 @@ mod distinct { ), // r#"{"data":{"findManyUser":[{"id":2,"first_name":"Hans","last_name":"Wurst"}]}}"# // ! SELECT DISTINCT ON expressions must match initial ORDER BY expressions - @r###""### + @r###"{"data":{"findManyUser":[{"id":2,"first_name":"Hans","last_name":"Wurst"},{"id":3,"first_name":"Joe","last_name":"Doe"}]}}"### ); Ok(()) @@ -158,14 +158,14 @@ mod distinct { ), // r#"{"data":{"findManyUser":[{"id":3,"first_name":"Joe","last_name":"Doe"},{"id":2,"first_name":"Hans","last_name":"Wurst"}]}}"# // ! SELECT DISTINCT ON expressions must match initial ORDER BY expressions - @r###""### + @r###"{"data":{"findManyUser":[{"id":3,"first_name":"Joe","last_name":"Doe"},{"id":2,"first_name":"Hans","last_name":"Wurst"}]}}"### ); Ok(()) } /// Mut return only distinct records for top record, and only for those the distinct relation records. - // #[connector_test] + #[connector_test] async fn nested_distinct(runner: Runner) -> TestResult<()> { nested_dataset(&runner).await?; @@ -187,7 +187,7 @@ mod distinct { ), // {"data":{"findManyUser":[{"id":1,"posts":[{"title":"3"},{"title":"1"},{"title":"2"}]},{"id":3,"posts":[]},{"id":4,"posts":[{"title":"1"}]},{"id":5,"posts":[{"title":"2"},{"title":"3"}]}]}} // ! SELECT DISTINCT ON expressions must match initial ORDER BY expressions - @r###""### + @r###"{"data":{"findManyUser":[{"id":1,"posts":[{"title":"3"},{"title":"1"},{"title":"2"}]},{"id":4,"posts":[{"title":"1"}]},{"id":3,"posts":[]},{"id":5,"posts":[{"title":"2"},{"title":"3"}]}]}}"### ); Ok(()) @@ -218,7 +218,7 @@ mod distinct { ), // {"data":{"findManyUser":[{"id":5,"posts":[{"title":"2"},{"title":"3"}]},{"id":4,"posts":[{"title":"1"}]},{"id":3,"posts":[]},{"id":2,"posts":[{"title":"2"},{"title":"1"}]}]}} // ! SELECT DISTINCT ON expressions must match initial ORDER BY expressions - @r###""### + @r###"{"data":{"findManyUser":[{"id":5,"posts":[{"title":"2"},{"title":"3"}]},{"id":4,"posts":[{"title":"1"}]},{"id":3,"posts":[]},{"id":2,"posts":[{"title":"2"},{"title":"1"}]}]}}"### ); Ok(()) diff --git a/query-engine/core/src/interpreter/query_interpreters/inmemory_record_processor.rs b/query-engine/core/src/interpreter/query_interpreters/inmemory_record_processor.rs index b2a605ef5872..b78e172a6c0e 100644 --- a/query-engine/core/src/interpreter/query_interpreters/inmemory_record_processor.rs +++ b/query-engine/core/src/interpreter/query_interpreters/inmemory_record_processor.rs @@ -229,8 +229,8 @@ impl InMemoryRecordProcessorBuilder { self } - pub fn distinct(mut self, distinct: FieldSelection) -> Self { - self.args.distinct = Some(distinct); + pub fn distinct(mut self, distinct: Option) -> Self { + self.args.distinct = distinct.clone(); self } diff --git a/query-engine/core/src/interpreter/query_interpreters/nested_read.rs b/query-engine/core/src/interpreter/query_interpreters/nested_read.rs index 4c39369a0ee9..3a83595a7696 100644 --- a/query-engine/core/src/interpreter/query_interpreters/nested_read.rs +++ b/query-engine/core/src/interpreter/query_interpreters/nested_read.rs @@ -17,17 +17,16 @@ pub(crate) async fn m2m( query.args.ignore_take, ); - let processor = match query.args.distinct { - Some(ref fs) => { - if query.args.requires_inmemory_distinct() { - inm_builder.distinct(fs.clone()) - } else { - inm_builder - } - } - None => inm_builder, - } - .build(); + let inm_builder = if query.args.requires_inmemory_distinct() { + let inm_builder = inm_builder.distinct(query.args.distinct.clone()); + query.args.distinct = None; + + inm_builder + } else { + inm_builder + }; + + let processor = inm_builder.build(); let parent_field = &query.parent_field; let child_link_id = parent_field.related_field().linking_fields(); @@ -153,7 +152,7 @@ pub async fn one2m( parent_field: &RelationFieldRef, parent_selections: Option>, parent_result: Option<&ManyRecords>, - query_args: QueryArguments, + mut query_args: QueryArguments, selected_fields: &FieldSelection, aggr_selections: Vec, trace_id: Option, @@ -220,15 +219,13 @@ pub async fn one2m( query_args.ignore_take, ); - let inm_builder = match query_args.distinct { - Some(ref fs) => { - if req_inmem_distinct { - inm_builder.distinct(fs.clone()) - } else { - inm_builder - } - } - None => inm_builder, + let inm_builder = if req_inmem_distinct { + let inm_builder = inm_builder.distinct(query_args.distinct); + query_args.distinct = None; + + inm_builder + } else { + inm_builder }; Some(inm_builder.build()) diff --git a/query-engine/core/src/interpreter/query_interpreters/read.rs b/query-engine/core/src/interpreter/query_interpreters/read.rs index c653e11418ee..49cc9754c649 100644 --- a/query-engine/core/src/interpreter/query_interpreters/read.rs +++ b/query-engine/core/src/interpreter/query_interpreters/read.rs @@ -85,7 +85,7 @@ fn read_one( /// -> Unstable cursors can't reliably be fetched by the underlying datasource, so we need to process part of it in-memory. fn read_many( tx: &mut dyn ConnectionLike, - query: ManyRecordsQuery, + mut query: ManyRecordsQuery, trace_id: Option, ) -> BoxFuture<'_, InterpretationResult> { let req_inmem_distinct = query.args.requires_inmemory_distinct(); @@ -98,15 +98,15 @@ fn read_many( query.args.ignore_take, ); - let inm_builder = match query.args.distinct { - Some(ref fs) => { - if req_inmem_distinct { - inm_builder.distinct(fs.clone()) - } else { - inm_builder - } - } - None => inm_builder, + dbg!(req_inmem_distinct); + let inm_builder = if req_inmem_distinct { + let inm_builder = inm_builder.distinct(query.args.distinct); + query.args.distinct = None; + dbg!(&query.args.distinct); + + inm_builder + } else { + inm_builder }; Some(inm_builder.build()) diff --git a/query-engine/query-structure/src/query_arguments.rs b/query-engine/query-structure/src/query_arguments.rs index 83b432ac91dd..70551d6c726f 100644 --- a/query-engine/query-structure/src/query_arguments.rs +++ b/query-engine/query-structure/src/query_arguments.rs @@ -72,17 +72,27 @@ impl QueryArguments { /// retrieved by the connector or if it requires the query engine to fetch a raw set /// of records and perform certain operations itself, in-memory. pub fn requires_inmemory_processing(&self) -> bool { - self.contains_unstable_cursor() || self.contains_null_cursor() + self.contains_unstable_cursor() || self.contains_null_cursor() || self.requires_inmemory_distinct() } pub fn requires_inmemory_distinct(&self) -> bool { + self.has_distinct() && (!self.has_distinct_capability() || self.has_orderby()) + } + + fn has_distinct_capability(&self) -> bool { + self.model() + .dm + .schema + .connector + .has_capability(ConnectorCapability::Distinct) + } + + fn has_distinct(&self) -> bool { self.distinct.is_some() - && !self - .model() - .dm - .schema - .connector - .has_capability(ConnectorCapability::Distinct) + } + + fn has_orderby(&self) -> bool { + !self.order_by.is_empty() } /// An unstable cursor is a cursor that is used in conjunction with an unstable (non-unique) combination of orderBys.