From d5d315cf933eb01ec43ab0272722100550db7345 Mon Sep 17 00:00:00 2001 From: Sophie <29753584+Druue@users.noreply.github.com> Date: Thu, 9 Nov 2023 23:46:08 +0100 Subject: [PATCH] fix(psl): composite type validation in indices (#4401) fixed https://github.com/prisma/prisma/issues/21441 * Updated composite type validation in indexes - only check for composites in _compound unique_ indexes - clarified validation message - Added link for tracking issue to add support for composite types in compound indexes --- .../validation_pipeline/validations.rs | 2 +- .../validations/indexes.rs | 33 ++-- .../prisma-models/src/field/scalar.rs | 2 +- .../tests/datamodel_converter_tests.rs | 160 ++++++++++++++++-- 4 files changed, 165 insertions(+), 32 deletions(-) diff --git a/psl/psl-core/src/validate/validation_pipeline/validations.rs b/psl/psl-core/src/validate/validation_pipeline/validations.rs index 4040844bb767..90f8ec9fe79e 100644 --- a/psl/psl-core/src/validate/validation_pipeline/validations.rs +++ b/psl/psl-core/src/validate/validation_pipeline/validations.rs @@ -123,7 +123,7 @@ pub(super) fn validate(ctx: &mut Context<'_>) { indexes::supports_clustering_setting(index, ctx); indexes::clustering_can_be_defined_only_once(index, ctx); indexes::opclasses_are_not_allowed_with_other_than_normal_indices(index, ctx); - indexes::composite_types_are_not_allowed_in_index(index, ctx); + indexes::composite_type_in_compound_unique_index(index, ctx); for field_attribute in index.scalar_field_attributes() { let span = index.ast_attribute().span; diff --git a/psl/psl-core/src/validate/validation_pipeline/validations/indexes.rs b/psl/psl-core/src/validate/validation_pipeline/validations/indexes.rs index 5f3288264016..7a7d0e1d105e 100644 --- a/psl/psl-core/src/validate/validation_pipeline/validations/indexes.rs +++ b/psl/psl-core/src/validate/validation_pipeline/validations/indexes.rs @@ -386,20 +386,25 @@ pub(crate) fn opclasses_are_not_allowed_with_other_than_normal_indices(index: In } } -pub(crate) fn composite_types_are_not_allowed_in_index(index: IndexWalker<'_>, ctx: &mut Context<'_>) { - for field in index.fields() { - if field.scalar_field_type().as_composite_type().is_some() { - let message = format!( - "Indexes can only contain scalar attributes. Please remove {:?} from the argument list of the indexes.", - field.name() - ); - ctx.push_error(DatamodelError::new_attribute_validation_error( - &message, - index.attribute_name(), - index.ast_attribute().span, - )); - return; - } +pub(crate) fn composite_type_in_compound_unique_index(index: IndexWalker<'_>, ctx: &mut Context<'_>) { + if !index.is_unique() { + return; + } + + let composite_type = index + .fields() + .find(|f| f.scalar_field_type().as_composite_type().is_some()); + + if index.fields().len() > 1 && composite_type.is_some() { + let message = format!( + "Prisma does not currently support composite types in compound unique indices, please remove {:?} from the index. See https://pris.ly/d/mongodb-composite-compound-indices for more details", + composite_type.unwrap().name() + ); + ctx.push_error(DatamodelError::new_attribute_validation_error( + &message, + index.attribute_name(), + index.ast_attribute().span, + )); } } diff --git a/query-engine/prisma-models/src/field/scalar.rs b/query-engine/prisma-models/src/field/scalar.rs index 92039da53663..b8ef8ab204e2 100644 --- a/query-engine/prisma-models/src/field/scalar.rs +++ b/query-engine/prisma-models/src/field/scalar.rs @@ -91,7 +91,7 @@ impl ScalarField { match scalar_field_type { ScalarFieldType::CompositeType(_) => { - unreachable!("Cannot convert a composite type to a type identifier. This error is typically caused by mistakenly using a composite type within a composite index.",) + unreachable!("This shouldn't be reached; composite types are not supported in compound unique indices.",) } ScalarFieldType::Enum(x) => TypeIdentifier::Enum(x), ScalarFieldType::BuiltInScalar(scalar) => scalar.into(), diff --git a/query-engine/prisma-models/tests/datamodel_converter_tests.rs b/query-engine/prisma-models/tests/datamodel_converter_tests.rs index 0a45c80ed163..a2ee28ca6c0d 100644 --- a/query-engine/prisma-models/tests/datamodel_converter_tests.rs +++ b/query-engine/prisma-models/tests/datamodel_converter_tests.rs @@ -38,31 +38,159 @@ fn converting_enums() { } } +// region: composite #[test] -fn converting_composite_types() { +fn converting_composite_types_compound() { let res = psl::parse_schema( r#" - datasource db { - provider = "mongodb" - url = "mongodb://localhost:27017/hello" - } + datasource db { + provider = "mongodb" + url = "mongodb://localhost:27017/hello" + } - model MyModel { - id String @id @default(auto()) @map("_id") @db.ObjectId - attribute Attribute + model Post { + id String @id @default(auto()) @map("_id") @db.ObjectId + author User @relation(fields: [authorId], references: [id]) + authorId String @db.ObjectId + attributes Attribute[] + + @@index([authorId, attributes]) + } + + type Attribute { + name String + value String + group String + } + + model User { + id String @id @default(auto()) @map("_id") @db.ObjectId + Post Post[] + } + "#, + ); - @@unique([attribute], name: "composite_index") - } + assert!(res.is_ok()); +} - type Attribute { - name String - value String - group String - } +#[test] +fn converting_composite_types_compound_unique() { + let res = psl::parse_schema( + r#" + datasource db { + provider = "mongodb" + url = "mongodb://localhost:27017/hello" + } + + model Post { + id String @id @default(auto()) @map("_id") @db.ObjectId + author User @relation(fields: [authorId], references: [id]) + authorId String @db.ObjectId + attributes Attribute[] + + @@unique([authorId, attributes]) + // ^^^^^^^^^^^^^^^^^^^^^^ + // Prisma does not currently support composite types in compound unique indices... + } + + type Attribute { + name String + value String + group String + } + + model User { + id String @id @default(auto()) @map("_id") @db.ObjectId + Post Post[] + } "#, ); - assert!(res.unwrap_err().contains("Indexes can only contain scalar attributes. Please remove \"attribute\" from the argument list of the indexes.")); + + assert!(res + .unwrap_err() + .contains(r#"Prisma does not currently support composite types in compound unique indices, please remove "attributes" from the index. See https://pris.ly/d/mongodb-composite-compound-indices for more details"#)); +} + +#[test] +fn converting_composite_types_nested() { + let res = psl::parse_schema( + r#" + datasource db { + provider = "mongodb" + url = "mongodb://localhost:27017/hello" + } + + type TheatersLocation { + address TheatersLocationAddress + geo TheatersLocationGeo + } + + type TheatersLocationAddress { + city String + state String + street1 String + street2 String? + zipcode String + } + + type TheatersLocationGeo { + coordinates Float[] + type String + } + + model theaters { + id String @id @default(auto()) @map("_id") @db.ObjectId + location TheatersLocation + theaterId Int + + @@index([location.geo], map: "geo index") + } + "#, + ); + + assert!(res.is_ok()); +} + +#[test] +fn converting_composite_types_nested_scalar() { + let res = psl::parse_schema( + r#" + datasource db { + provider = "mongodb" + url = "mongodb://localhost:27017/hello" + } + + type TheatersLocation { + address TheatersLocationAddress + geo TheatersLocationGeo + } + + type TheatersLocationAddress { + city String + state String + street1 String + street2 String? + zipcode String + } + + type TheatersLocationGeo { + coordinates Float[] + type String + } + + model theaters { + id String @id @default(auto()) @map("_id") @db.ObjectId + location TheatersLocation + theaterId Int + + @@index([location.geo.type], map: "geo index") + } + "#, + ); + + assert!(res.is_ok()); } +// endregion #[test] fn models_with_only_scalar_fields() {