From cdc4e5af041aa13e0dcf64d0cecaa06ff9ac7473 Mon Sep 17 00:00:00 2001 From: Flavian DESVERNE Date: Wed, 11 Aug 2021 17:38:40 +0200 Subject: [PATCH 1/2] fix: count on one2m with multiple fks --- .../aggregation/many_count_relation.rs | 75 +++++++++++++++++++ .../sql-query-connector/src/join_utils.rs | 28 +++---- 2 files changed, 89 insertions(+), 14 deletions(-) diff --git a/query-engine/connector-test-kit-rs/query-engine-tests/tests/queries/aggregation/many_count_relation.rs b/query-engine/connector-test-kit-rs/query-engine-tests/tests/queries/aggregation/many_count_relation.rs index af48d497e390..bdc8838f7951 100644 --- a/query-engine/connector-test-kit-rs/query-engine-tests/tests/queries/aggregation/many_count_relation.rs +++ b/query-engine/connector-test-kit-rs/query-engine-tests/tests/queries/aggregation/many_count_relation.rs @@ -263,6 +263,81 @@ mod many_count_rel { Ok(()) } + fn schema_one2m_multi_fks() -> String { + let schema = indoc! { + r#"model User { + #id(id, Int, @id, @default(autoincrement())) + votes Vote[] + UserToObjective UserToObjective[] + } + + model Objective { + #id(id, Int, @default(autoincrement()), @id) + name String @unique + UserToObjective UserToObjective[] @relation(name: "UserObjectives") + } + + model UserToObjective { + user User @relation(fields: [userId], references: [id]) + userId Int + objective Objective @relation(name: "UserObjectives", fields: [objectiveId], references: [id]) + objectiveId Int + votes Vote[] + + @@id([userId, objectiveId]) + } + + model Vote { + createdAt DateTime @default(now()) + user User @relation(fields: [userId], references: [id]) + userId Int + userObjective UserToObjective @relation(fields: [objectiveId, followerId], references: [objectiveId, userId]) + objectiveId Int + followerId Int + + @@id([userId, objectiveId]) + }"# + }; + + schema.to_owned() + } + + // Regression test for: https://github.com/prisma/prisma/issues/7299 + #[connector_test(schema(schema_one2m_multi_fks))] + async fn count_one2m_multi_fks(runner: Runner) -> TestResult<()> { + run_query!( + runner, + r#"mutation { + createOneUserToObjective( + data: { + user: { create: {} } + objective: { create: { name: "Objective 1" } } + votes: { create: [{ user: { create: {} } }, { user: { create: {} } }] } + } + ) { + userId + _count { + votes + } + } + } + "# + ); + + insta::assert_snapshot!( + run_query!(&runner, r#"query { + findManyUserToObjective { + _count { + votes + } + } + }"#), + @r###"{"data":{"findManyUserToObjective":[{"_count":{"votes":2}}]}}"### + ); + + Ok(()) + } + async fn create_row(runner: &Runner, data: &str) -> TestResult<()> { runner .query(format!("mutation {{ createOnePost(data: {}) {{ id }} }}", data)) diff --git a/query-engine/connectors/sql-query-connector/src/join_utils.rs b/query-engine/connectors/sql-query-connector/src/join_utils.rs index f0528b026641..d8fc59f267fb 100644 --- a/query-engine/connectors/sql-query-connector/src/join_utils.rs +++ b/query-engine/connectors/sql-query-connector/src/join_utils.rs @@ -63,7 +63,7 @@ fn compute_aggr_join_one2m( let query = right_fields.iter().fold(query, |acc, f| acc.group_by(f.as_column())); let pairs = left_fields.into_iter().zip(right_fields.into_iter()); - let on_conditions = pairs + let on_conditions: Vec = pairs .map(|(a, b)| { let col_a = match previous_join { Some(prev_join) => Column::from((prev_join.alias.to_owned(), a.db_name().to_owned())), @@ -71,7 +71,7 @@ fn compute_aggr_join_one2m( }; let col_b = Column::from((join_alias.to_owned(), b.db_name().to_owned())); - col_a.equals(col_b) + col_a.equals(col_b).into() }) .collect::>(); @@ -81,7 +81,7 @@ fn compute_aggr_join_one2m( // + ) AS ON (. = .) let join = Table::from(query) .alias(join_alias.to_owned()) - .on(ConditionTree::single(on_conditions)); + .on(ConditionTree::And(on_conditions)); AliasedJoin { data: join, @@ -111,18 +111,18 @@ fn compute_aggr_join_m2m( // FROM _AtoB let query = query.value(aggr_expr.alias(aggregator_alias.to_owned())); - let conditions_a: Vec<_> = a_ids + let conditions_a: Vec = a_ids .as_columns() - .map(|c| c.equals(rf.related_field().m2m_columns())) + .map(|c| c.equals(rf.related_field().m2m_columns()).into()) .collect(); - let conditions_b: Vec<_> = b_ids.as_columns().map(|c| c.equals(rf.m2m_columns())).collect(); + let conditions_b: Vec = b_ids.as_columns().map(|c| c.equals(rf.m2m_columns()).into()).collect(); // SELECT A.id, COUNT(*) AS FROM _AtoB // + INNER JOIN A ON A.id = _AtoB.A // + INNER JOIN B ON B.id = _AtoB.B let query = query - .inner_join(rf.model().as_table().on(ConditionTree::single(conditions_a))) - .inner_join(rf.related_model().as_table().on(ConditionTree::single(conditions_b))); + .inner_join(rf.model().as_table().on(ConditionTree::And(conditions_a))) + .inner_join(rf.related_model().as_table().on(ConditionTree::And(conditions_b))); // SELECT A.id, COUNT(*) AS FROM _AtoB // INNER JOIN A ON A.id = _AtoB.A @@ -132,7 +132,7 @@ fn compute_aggr_join_m2m( let (left_fields, right_fields) = (a_ids.scalar_fields(), b_ids.scalar_fields()); let pairs = left_fields.zip(right_fields); - let on_conditions = pairs + let on_conditions: Vec = pairs .map(|(a, b)| { let col_a = match previous_join { Some(prev_join) => Column::from((prev_join.alias.to_owned(), a.db_name().to_owned())), @@ -140,7 +140,7 @@ fn compute_aggr_join_m2m( }; let col_b = Column::from((join_alias.to_owned(), b.db_name().to_owned())); - col_a.equals(col_b) + col_a.equals(col_b).into() }) .collect::>(); @@ -152,7 +152,7 @@ fn compute_aggr_join_m2m( // + ) AS ON (.id = .id) let join = Table::from(query) .alias(join_alias.to_owned()) - .on(ConditionTree::single(on_conditions)); + .on(ConditionTree::And(on_conditions)); AliasedJoin { alias: join_alias.to_owned(), @@ -182,7 +182,7 @@ pub fn compute_one2m_join(base_model: &ModelRef, rf: &RelationFieldRef, join_pre let related_model = rf.related_model(); let pairs = left_fields.into_iter().zip(right_fields.into_iter()); - let on_conditions = pairs + let on_conditions: Vec = pairs .map(|(a, b)| { let a_col = if let Some(alias) = left_table_alias.clone() { Column::from((alias, a.db_name().to_owned())) @@ -192,7 +192,7 @@ pub fn compute_one2m_join(base_model: &ModelRef, rf: &RelationFieldRef, join_pre let b_col = Column::from((right_table_alias.clone(), b.db_name().to_owned())); - a_col.equals(b_col) + a_col.equals(b_col).into() }) .collect::>(); @@ -201,6 +201,6 @@ pub fn compute_one2m_join(base_model: &ModelRef, rf: &RelationFieldRef, join_pre data: related_model .as_table() .alias(right_table_alias) - .on(ConditionTree::single(on_conditions)), + .on(ConditionTree::And(on_conditions)), } } From 9544a95c92a262a51fc34b23326671aad17b8541 Mon Sep 17 00:00:00 2001 From: Flavian DESVERNE Date: Wed, 11 Aug 2021 18:52:24 +0200 Subject: [PATCH 2/2] fix dm for sqlserver --- .../tests/queries/aggregation/many_count_relation.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/query-engine/connector-test-kit-rs/query-engine-tests/tests/queries/aggregation/many_count_relation.rs b/query-engine/connector-test-kit-rs/query-engine-tests/tests/queries/aggregation/many_count_relation.rs index bdc8838f7951..fd8e32dc6973 100644 --- a/query-engine/connector-test-kit-rs/query-engine-tests/tests/queries/aggregation/many_count_relation.rs +++ b/query-engine/connector-test-kit-rs/query-engine-tests/tests/queries/aggregation/many_count_relation.rs @@ -280,7 +280,7 @@ mod many_count_rel { model UserToObjective { user User @relation(fields: [userId], references: [id]) userId Int - objective Objective @relation(name: "UserObjectives", fields: [objectiveId], references: [id]) + objective Objective @relation(name: "UserObjectives", fields: [objectiveId], references: [id], onDelete: NoAction, onUpdate: NoAction) objectiveId Int votes Vote[] @@ -291,7 +291,7 @@ mod many_count_rel { createdAt DateTime @default(now()) user User @relation(fields: [userId], references: [id]) userId Int - userObjective UserToObjective @relation(fields: [objectiveId, followerId], references: [objectiveId, userId]) + userObjective UserToObjective @relation(fields: [objectiveId, followerId], references: [userId, objectiveId], onDelete: NoAction, onUpdate: NoAction) objectiveId Int followerId Int