From c90cfc2cac7cd730119b112c4ebd8e47b8206951 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=20Houl=C3=A9?= <13155277+tomhoule@users.noreply.github.com> Date: Fri, 25 Nov 2022 10:18:06 +0100 Subject: [PATCH] Test postgres multi-schema introspection (#3297) Test postgres multi-schema introspection The test expectations show that there are cases where our choice _not_ to rename models and enums in case of conflict leads to ambiguous situations that may be difficult for users to resolve. The test case where this is the most apparent is `multiple_schemas_w_duplicate_enums_are_introspected`. closes https://github.com/prisma/prisma/issues/15800 --- .../tests/multi_schema/mod.rs | 395 ++++++++++-------- 1 file changed, 232 insertions(+), 163 deletions(-) diff --git a/introspection-engine/introspection-engine-tests/tests/multi_schema/mod.rs b/introspection-engine/introspection-engine-tests/tests/multi_schema/mod.rs index dd7609b8d4f7..6e5ec8fac5e4 100644 --- a/introspection-engine/introspection-engine-tests/tests/multi_schema/mod.rs +++ b/introspection-engine/introspection-engine-tests/tests/multi_schema/mod.rs @@ -1,5 +1,4 @@ use introspection_engine_tests::{test_api::*, TestResult}; -use test_macros::test_connector; #[test_connector(tags(Postgres))] async fn multiple_schemas_without_schema_property_are_not_introspected(api: &TestApi) -> TestResult { @@ -78,44 +77,54 @@ async fn multiple_schemas_w_tables_are_introspected(api: &TestApi) -> TestResult Ok(()) } -//TODO(matthias) this is not working yet, but this is what it would look like if done ;-) -// #[test_connector(tags(Postgres), preview_features("multiSchema"), db_schemas("first", "second"))] -// async fn multiple_schemas_w_duplicate_table_names_are_introspected(api: &TestApi) -> TestResult { -// let schema_name = "first"; -// let other_name = "second"; -// let create_schema = format!("CREATE Schema \"{schema_name}\"",); -// let create_table = format!("CREATE TABLE \"{schema_name}\".\"A\" (id Text PRIMARY KEY)",); -// -// api.database().raw_cmd(&create_schema).await?; -// api.database().raw_cmd(&create_table).await?; -// -// let create_schema = format!("CREATE Schema \"{other_name}\"",); -// let create_table = format!("CREATE TABLE \"{other_name}\".\"A\" (id Text PRIMARY KEY)",); -// -// api.database().raw_cmd(&create_schema).await?; -// api.database().raw_cmd(&create_table).await?; -// -// let expected = expect![[r#" -// model first_A { -// id String @id -// -// @@map("A") -// @@schema("first") -// } -// -// model second_A { -// id String @id -// -// @@map("A") -// @@schema("second") -// } -// "#]]; -// -// let result = api.introspect_dml().await?; -// expected.assert_eq(&result); -// -// Ok(()) -// } +#[test_connector( + tags(Postgres), + exclude(CockroachDb), + preview_features("multiSchema"), + namespaces("first", "second") +)] +async fn multiple_schemas_w_duplicate_table_names_are_introspected(api: &TestApi) -> TestResult { + let schema_name = "first"; + let other_name = "second"; + let setup = formatdoc! { + r#" + CREATE SCHEMA "{schema_name}"; + CREATE TABLE "{schema_name}"."A" (id TEXT PRIMARY KEY); + + CREATE SCHEMA "{other_name}"; + CREATE TABLE "{other_name}"."A" (id TEXT PRIMARY KEY); + "# + }; + api.raw_cmd(&setup).await; + + let expected = expect![[r#" + generator client { + provider = "prisma-client-js" + previewFeatures = ["multiSchema"] + } + + datasource db { + provider = "postgresql" + url = "env(TEST_DATABASE_URL)" + schemas = ["first", "second"] + } + + model A { + id String @id + + @@schema("first") + } + + model A { + id String @id + + @@schema("second") + } + "#]]; + + api.expect_datamodel(&expected).await; + Ok(()) +} #[test_connector(tags(Postgres), preview_features("multiSchema"), namespaces("first", "second"))] async fn multiple_schemas_w_cross_schema_are_introspected(api: &TestApi) -> TestResult { @@ -158,75 +167,36 @@ async fn multiple_schemas_w_cross_schema_are_introspected(api: &TestApi) -> Test Ok(()) } -//TODO(matthias) this is not working yet, but this is what it would look like if done ;-) -// #[test_connector(tags(Postgres), preview_features("multiSchema"), db_schemas("first", "second"))] -// async fn multiple_schemas_w_cross_schema_fks_w_duplicate_names_are_introspected(api: &TestApi) -> TestResult { -// let schema_name = "first"; -// let other_name = "second"; -// let create_schema = format!("CREATE Schema \"{schema_name}\"",); -// let create_table = format!("CREATE TABLE \"{schema_name}\".\"A\" (id Text PRIMARY KEY)",); -// //Todo -// api.database().raw_cmd(&create_schema).await?; -// api.database().raw_cmd(&create_table).await?; -// -// let create_schema = format!("CREATE Schema \"{other_name}\"",); -// let create_table = format!( -// "CREATE TABLE \"{other_name}\".\"A\" (id Text PRIMARY KEY, fk Text References \"{schema_name}\".\"A\"(\"id\"))", -// ); -// -// api.database().raw_cmd(&create_schema).await?; -// api.database().raw_cmd(&create_table).await?; -// -// let expected = expect![[r#" -// model first_A { -// id String @id -// second_A second_A[] -// -// @@map("A") -// @@schema("first") -// } -// -// model second_A { -// id String @id -// fk String? -// first_A first_A? @relation(fields: [fk], references: [id], onDelete: NoAction, onUpdate: NoAction) -// -// @@map("A") -// @@schema("second") -// } -// "#]]; -// -// let result = api.introspect_dml().await?; -// expected.assert_eq(&result); -// -// Ok(()) -// } - #[test_connector(tags(Postgres), preview_features("multiSchema"), namespaces("first", "second"))] -async fn multiple_schemas_w_enums_are_introspected(api: &TestApi) -> TestResult { +async fn multiple_schemas_w_cross_schema_fks_w_duplicate_names_are_introspected(api: &TestApi) -> TestResult { let schema_name = "first"; let other_name = "second"; - let create_schema = format!("CREATE Schema \"{schema_name}\"",); - let create_type = format!("CREATE TYPE \"{schema_name}\".\"HappyMood\" AS ENUM ('happy')",); - + let create_schema = format!("CREATE SCHEMA \"{schema_name}\"",); + let create_table = format!("CREATE TABLE \"{schema_name}\".\"A\" (id Text PRIMARY KEY)",); + //Todo api.database().raw_cmd(&create_schema).await?; - api.database().raw_cmd(&create_type).await?; + api.database().raw_cmd(&create_table).await?; - let create_schema = format!("CREATE Schema \"{other_name}\"",); - let create_type = format!("CREATE TYPE \"{other_name}\".\"SadMood\" AS ENUM ('sad')",); + let create_schema = format!("CREATE SCHEMA \"{other_name}\"",); + let create_table = format!( + "CREATE TABLE \"{other_name}\".\"A\" (id TEXT PRIMARY KEY, fk TEXT REFERENCES \"{schema_name}\".\"A\"(\"id\"))", + ); api.database().raw_cmd(&create_schema).await?; - api.database().raw_cmd(&create_type).await?; + api.database().raw_cmd(&create_table).await?; let expected = expect![[r#" - enum HappyMood { - happy + model A { + id String @id + A A[] @@schema("first") } - enum SadMood { - sad + model A { + id String @id + fk String? + A A? @relation(fields: [fk], references: [id], onDelete: NoAction, onUpdate: NoAction) @@schema("second") } @@ -238,74 +208,126 @@ async fn multiple_schemas_w_enums_are_introspected(api: &TestApi) -> TestResult Ok(()) } -// Todo(matthias) not passing yet due to us not retrieving and passing around the schema information of an enum -// when it is used in a column type. We only pass the name currently which might not be unique -// therefore the renaming logic for name clashes is not working for point of use yet -// #[test_connector(tags(Postgres), preview_features("multiSchema"), db_schemas("first", "second"))] -// async fn multiple_schemas_w_duplicate_enums_are_introspected(api: &TestApi) -> TestResult { -// let schema_name = "first"; -// let other_name = "second"; -// let create_schema = format!("CREATE Schema \"{schema_name}\"",); -// let create_type = format!("CREATE TYPE \"{schema_name}\".\"HappyMood\" AS ENUM ('happy')",); -// let create_table = -// format!("CREATE TABLE \"{schema_name}\".\"HappyPerson\" (mood \"{schema_name}\".\"HappyMood\" PRIMARY KEY)",); -// -// api.database().raw_cmd(&create_schema).await?; -// api.database().raw_cmd(&create_type).await?; -// api.database().raw_cmd(&create_table).await?; -// -// let create_schema = format!("CREATE Schema \"{other_name}\"",); -// let create_type = format!("CREATE TYPE \"{other_name}\".\"HappyMood\" AS ENUM ('veryHappy')",); -// let create_table = -// format!("CREATE TABLE \"{other_name}\".\"VeryHappyPerson\" (mood \"{other_name}\".\"HappyMood\" PRIMARY KEY)",); -// -// let create_table_2 = -// format!("CREATE TABLE \"{other_name}\".\"HappyPerson\" (mood \"{schema_name}\".\"HappyMood\" PRIMARY KEY)",); -// -// api.database().raw_cmd(&create_schema).await?; -// api.database().raw_cmd(&create_type).await?; -// api.database().raw_cmd(&create_table).await?; -// api.database().raw_cmd(&create_table_2).await?; -// -// let expected = expect![[r#" -// model HappyPerson { -// mood first_HappyMood @id -// -// @@schema("first") -// } -// -// model HappyPerson { -// mood first_HappyMood @id -// -// @@schema("second") -// } -// -// model VeryHappyPerson { -// mood second_HappyMood @id -// -// @@schema("second") -// } -// -// enum first_HappyMood { -// happy -// -// @@map("HappyMood") -// @@schema("first") -// } -// -// enum second_HappyMood { -// veryHappy -// -// @@map("HappyMood") -// @@schema("second") -// } -// "#]]; -// -// let result = api.introspect_dml().await?; -// expected.assert_eq(&result); -// -// Ok(()) -// } +#[test_connector( + tags(Postgres), + exclude(CockroachDb), + preview_features("multiSchema"), + namespaces("first", "second_schema") +)] +async fn multiple_schemas_w_enums_are_introspected(api: &TestApi) -> TestResult { + let schema_name = "first"; + let other_name = "second_schema"; + let sql = format! { + r#" + CREATE SCHEMA "{schema_name}"; + CREATE TYPE "{schema_name}"."HappyMood" AS ENUM ('happy'); + CREATE SCHEMA "{other_name}"; + CREATE TYPE "{other_name}"."SadMood" AS ENUM ('sad'); + "#, + }; + + api.raw_cmd(&sql).await; + + let expected = expect![[r#" + generator client { + provider = "prisma-client-js" + previewFeatures = ["multiSchema"] + } + + datasource db { + provider = "postgresql" + url = "env(TEST_DATABASE_URL)" + schemas = ["first", "second_schema"] + } + + enum HappyMood { + happy + + @@schema("first") + } + + enum SadMood { + sad + + @@schema("second_schema") + } + "#]]; + + api.expect_datamodel(&expected).await; + Ok(()) +} + +#[test_connector( + tags(Postgres), + exclude(CockroachDb), + preview_features("multiSchema"), + namespaces("first", "second") +)] +async fn multiple_schemas_w_duplicate_enums_are_introspected(api: &TestApi) -> TestResult { + let schema_name = "first"; + let other_name = "second"; + let setup = formatdoc! { + r#" + CREATE SCHEMA "{schema_name}"; + CREATE TYPE "{schema_name}"."HappyMood" AS ENUM ('happy'); + CREATE TABLE "{schema_name}"."HappyPerson" (mood "{schema_name}"."HappyMood" PRIMARY KEY); + + CREATE SCHEMA "{other_name}"; + CREATE TYPE "{other_name}"."HappyMood" AS ENUM ('veryHappy'); + CREATE TABLE "{other_name}"."VeryHappyPerson" (mood "{other_name}"."HappyMood" PRIMARY KEY); + CREATE TABLE "{other_name}"."HappyPerson" (mood "{schema_name}"."HappyMood" PRIMARY KEY); + + "# + }; + + api.raw_cmd(&setup).await; + + let expected = expect![[r#" + generator client { + provider = "prisma-client-js" + previewFeatures = ["multiSchema"] + } + + datasource db { + provider = "postgresql" + url = "env(TEST_DATABASE_URL)" + schemas = ["first", "second"] + } + + model HappyPerson { + mood HappyMood @id + + @@schema("first") + } + + model HappyPerson { + mood HappyMood @id + + @@schema("second") + } + + model VeryHappyPerson { + mood HappyMood @id + + @@schema("second") + } + + enum HappyMood { + happy + + @@schema("first") + } + + enum HappyMood { + veryHappy + + @@schema("second") + } + "#]]; + + api.expect_datamodel(&expected).await; + Ok(()) +} #[test_connector(tags(Postgres))] async fn multiple_schemas_w_enums_without_schemas_are_not_introspected(api: &TestApi) -> TestResult { @@ -333,6 +355,53 @@ async fn multiple_schemas_w_enums_without_schemas_are_not_introspected(api: &Tes Ok(()) } +#[test_connector( + tags(Postgres), + exclude(CockroachDb), + preview_features("multiSchema"), + namespaces("first", "second_schema") +)] +async fn same_table_name_with_relation_in_two_schemas(api: &TestApi) -> TestResult { + let sql = r#" + CREATE SCHEMA "first"; + CREATE SCHEMA "second_schema"; + CREATE TABLE "first"."tbl" ( id SERIAL PRIMARY KEY ); + CREATE TABLE "second_schema"."tbl" ( id SERIAL PRIMARY KEY, fst INT REFERENCES "first"."tbl"("id") ); + "#; + + api.raw_cmd(&sql).await; + + let expected = expect![[r#" + generator client { + provider = "prisma-client-js" + previewFeatures = ["multiSchema"] + } + + datasource db { + provider = "postgresql" + url = "env(TEST_DATABASE_URL)" + schemas = ["first", "second_schema"] + } + + model tbl { + id Int @id @default(autoincrement()) + tbl tbl[] + + @@schema("first") + } + + model tbl { + id Int @id @default(autoincrement()) + fst Int? + tbl tbl? @relation(fields: [fst], references: [id], onDelete: NoAction, onUpdate: NoAction) + + @@schema("second_schema") + } + "#]]; + + api.expect_datamodel(&expected).await; + Ok(()) +} //cross schema // fks // enums