From 973c18a576389e9064aa66c828fee76b6e0fa5d7 Mon Sep 17 00:00:00 2001 From: yubrot Date: Tue, 19 Mar 2024 22:56:18 +0900 Subject: [PATCH] Fix `relation_fields` validation to accept primary key indexes (#4376) * Fix `relation_fields` validation to accept primary key indexes This resolves https://github.com/prisma/language-tools/issues/1387 --------- Co-authored-by: Jan Piotrowski --- .../validations/relation_fields.rs | 36 ++++++++++--------- .../one_field_at_at_id.prisma | 19 ++++++++++ .../one_field_at_id.prisma | 17 +++++++++ .../three_fields_mixed_id.prisma | 32 +++++++++++++++++ 4 files changed, 88 insertions(+), 16 deletions(-) create mode 100644 psl/psl/tests/validation/attributes/index/missing_index_warning/relation_mode_prisma/one_field_at_at_id.prisma create mode 100644 psl/psl/tests/validation/attributes/index/missing_index_warning/relation_mode_prisma/one_field_at_id.prisma create mode 100644 psl/psl/tests/validation/attributes/index/missing_index_warning/relation_mode_prisma/three_fields_mixed_id.prisma diff --git a/psl/psl-core/src/validate/validation_pipeline/validations/relation_fields.rs b/psl/psl-core/src/validate/validation_pipeline/validations/relation_fields.rs index 765b6b2bb39f..146f119f149d 100644 --- a/psl/psl-core/src/validate/validation_pipeline/validations/relation_fields.rs +++ b/psl/psl-core/src/validate/validation_pipeline/validations/relation_fields.rs @@ -267,23 +267,27 @@ pub(super) fn validate_missing_relation_indexes(relation_field: RelationFieldWal // Considers all groups of indexes explicitly declared in the given model. // An index group can be: // - a singleton (@unique or @id) - // - an ordered set (@@unique or @@index) - let index_field_groups = model.indexes(); - - let referencing_fields_appear_in_index = index_field_groups - .map(|index_walker| index_walker.fields().map(|index| index.field_id())) - .any(|index_fields_it| { - let fields_it = referencing_fields_it.clone(); - is_leftwise_included_it(fields_it, index_fields_it) - }); - - if !referencing_fields_appear_in_index { - let ast_field = relation_field.ast_field(); - let span = ast_field - .span_for_attribute("relation") - .unwrap_or_else(|| ast_field.span()); - ctx.push_warning(DatamodelWarning::new_missing_index_on_emulated_relation(span)); + // - an ordered set (@@unique, @@index, or @@id) + for index_walker in model.indexes() { + let index_fields_it = index_walker.fields().map(|col| col.field_id()); + let referencing_fields_it = referencing_fields_it.clone(); + if is_leftwise_included_it(referencing_fields_it, index_fields_it) { + return; + } + } + + if let Some(primary_key_walker) = model.primary_key() { + let primary_key_fields_it = primary_key_walker.fields().map(|col| col.field_id()); + if is_leftwise_included_it(referencing_fields_it, primary_key_fields_it) { + return; + } } + + let ast_field = relation_field.ast_field(); + let span = ast_field + .span_for_attribute("relation") + .unwrap_or_else(|| ast_field.span()); + ctx.push_warning(DatamodelWarning::new_missing_index_on_emulated_relation(span)); } } diff --git a/psl/psl/tests/validation/attributes/index/missing_index_warning/relation_mode_prisma/one_field_at_at_id.prisma b/psl/psl/tests/validation/attributes/index/missing_index_warning/relation_mode_prisma/one_field_at_at_id.prisma new file mode 100644 index 000000000000..5083b79c0d94 --- /dev/null +++ b/psl/psl/tests/validation/attributes/index/missing_index_warning/relation_mode_prisma/one_field_at_at_id.prisma @@ -0,0 +1,19 @@ +// no relation index validation warning on relationMode = "prisma" when a referenced field is already in @@id. + +datasource db { + provider = "mysql" + url = env("TEST_DATABASE_URL") + relationMode = "prisma" +} + +model SomeUser { + id Int @id + profile Profile? +} + +model Profile { + id Int + user SomeUser? @relation(fields: [id], references: [id]) + + @@id([id]) +} diff --git a/psl/psl/tests/validation/attributes/index/missing_index_warning/relation_mode_prisma/one_field_at_id.prisma b/psl/psl/tests/validation/attributes/index/missing_index_warning/relation_mode_prisma/one_field_at_id.prisma new file mode 100644 index 000000000000..57de9b5c6fa3 --- /dev/null +++ b/psl/psl/tests/validation/attributes/index/missing_index_warning/relation_mode_prisma/one_field_at_id.prisma @@ -0,0 +1,17 @@ +// no relation index validation warning on relationMode = "prisma" when a referenced field is already in @id. + +datasource db { + provider = "mysql" + url = env("TEST_DATABASE_URL") + relationMode = "prisma" +} + +model SomeUser { + id Int @id + profile Profile? +} + +model Profile { + id Int @id + user SomeUser? @relation(fields: [id], references: [id]) +} diff --git a/psl/psl/tests/validation/attributes/index/missing_index_warning/relation_mode_prisma/three_fields_mixed_id.prisma b/psl/psl/tests/validation/attributes/index/missing_index_warning/relation_mode_prisma/three_fields_mixed_id.prisma new file mode 100644 index 000000000000..10a2d3877fcb --- /dev/null +++ b/psl/psl/tests/validation/attributes/index/missing_index_warning/relation_mode_prisma/three_fields_mixed_id.prisma @@ -0,0 +1,32 @@ +// add missing relation index validation warning on relationMode = "prisma". + +datasource db { + provider = "mysql" + url = env("TEST_DATABASE_URL") + relationMode = "prisma" +} + +model SomeUser { + idA Int + idB Int + idC Int + posts Post[] + + @@id([idA, idB, idC]) +} + +model Post { + userIdA Int @unique + userIdB Int + userIdC Int @unique + user SomeUser @relation(fields: [userIdA, userIdB, userIdC], references: [idA, idB, idC]) + + @@id([userIdA, userIdB]) +} + +// warning: With `relationMode = "prisma"`, no foreign keys are used, so relation fields will not benefit from the index usually created by the relational database under the hood. This can lead to poor performance when querying these fields. We recommend adding an index manually. Learn more at https://pris.ly/d/relation-mode-prisma-indexes"  +// --> schema.prisma:22 +//  |  +// 21 |  userIdC Int @unique +// 22 |  user SomeUser @relation(fields: [userIdA, userIdB, userIdC], references: [idA, idB, idC]) +//  |