From 978b63f963ca3573621260f0b5e541c3e991e579 Mon Sep 17 00:00:00 2001 From: Matthias Date: Fri, 20 Mar 2020 10:38:47 +0100 Subject: [PATCH 1/4] adjust logic for recognizing Prisma m:n relations --- .../src/misc_helpers.rs | 68 +++++++++---------- 1 file changed, 34 insertions(+), 34 deletions(-) diff --git a/introspection-engine/connectors/sql-introspection-connector/src/misc_helpers.rs b/introspection-engine/connectors/sql-introspection-connector/src/misc_helpers.rs index 64e637d01988..10d6bba96a02 100644 --- a/introspection-engine/connectors/sql-introspection-connector/src/misc_helpers.rs +++ b/introspection-engine/connectors/sql-introspection-connector/src/misc_helpers.rs @@ -18,46 +18,46 @@ pub fn is_migration_table(table: &Table) -> bool { } pub(crate) fn is_prisma_1_point_1_join_table(table: &Table) -> bool { - table.columns.len() == 2 - && table.foreign_keys.len() == 2 - && table.foreign_keys[0].referenced_table < table.foreign_keys[1].referenced_table - && table.name.starts_with("_") - && table - .columns - .iter() - .find(|column| column.name.to_lowercase() == "a") - .is_some() - && table - .columns - .iter() - .find(|column| column.name.to_lowercase() == "b") - .is_some() - && table.indices.len() >= 1 - && table.indices.last().unwrap().columns.len() == 2 - && table.indices.last().unwrap().tpe == IndexType::Unique + table.columns.len() == 2 && table.indices.len() == 2 && shared(table) } pub(crate) fn is_prisma_1_point_0_join_table(table: &Table) -> bool { table.columns.len() == 3 - && table.foreign_keys.len() == 2 - && table.foreign_keys[0].referenced_table < table.foreign_keys[1].referenced_table - && table.name.starts_with("_") - && table - .columns - .iter() - .find(|column| column.name.to_lowercase() == "a") - .is_some() - && table - .columns - .iter() - .find(|column| column.name.to_lowercase() == "b") - .is_some() + && table.indices.len() == 3 + && table.columns.iter().any(|c| c.name == "id".to_string()) + && shared(table) +} + +fn shared(table: &Table) -> bool { + fn is_a(column: &String) -> bool { + column.to_lowercase() == "a" + } + + fn is_b(column: &String) -> bool { + column.to_lowercase() == "b" + } + + table.name.starts_with("_") + //UNIQUE INDEX [A,B] + && table.indices.iter().any(|i| { + i.columns.len() == 2 + && is_a(&i.columns[0]) + && is_b(&i.columns[1]) + && i.tpe == IndexType::Unique + }) + //INDEX [B] && table - .columns + .indices .iter() - .find(|column| column.name.to_lowercase() == "id") - .is_some() - && table.indices.len() >= 1 + .any(|i| i.columns.len() == 1 && is_b(&i.columns[0]) && i.tpe == IndexType::Normal) + // 2 FKs + && table.foreign_keys.len() == 2 + // Lexicographically lower model referenced by A + && if table.foreign_keys[0].referenced_table <= table.foreign_keys[1].referenced_table { + is_a(&table.foreign_keys[0].columns[0]) && is_b(&table.foreign_keys[1].columns[1]) + } else { + is_b(&table.foreign_keys[0].columns[0]) && is_a(&table.foreign_keys[1].columns[1]) + } } pub(crate) fn is_foreign_key_column(table: &Table, column: &Column) -> bool { From bcc363a4efe73d2e2006726ad534c977d7275b1b Mon Sep 17 00:00:00 2001 From: Matthias Date: Fri, 20 Mar 2020 10:52:49 +0100 Subject: [PATCH 2/4] add test case, fix condition --- .../src/misc_helpers.rs | 4 +- .../postgres/tables_postgres.rs | 41 +++++++++++++++++++ 2 files changed, 43 insertions(+), 2 deletions(-) diff --git a/introspection-engine/connectors/sql-introspection-connector/src/misc_helpers.rs b/introspection-engine/connectors/sql-introspection-connector/src/misc_helpers.rs index 10d6bba96a02..0e5bd77a8f84 100644 --- a/introspection-engine/connectors/sql-introspection-connector/src/misc_helpers.rs +++ b/introspection-engine/connectors/sql-introspection-connector/src/misc_helpers.rs @@ -54,9 +54,9 @@ fn shared(table: &Table) -> bool { && table.foreign_keys.len() == 2 // Lexicographically lower model referenced by A && if table.foreign_keys[0].referenced_table <= table.foreign_keys[1].referenced_table { - is_a(&table.foreign_keys[0].columns[0]) && is_b(&table.foreign_keys[1].columns[1]) + is_a(&table.foreign_keys[0].columns[0]) && is_b(&table.foreign_keys[1].columns[0]) } else { - is_b(&table.foreign_keys[0].columns[0]) && is_a(&table.foreign_keys[1].columns[1]) + is_b(&table.foreign_keys[0].columns[0]) && is_a(&table.foreign_keys[1].columns[0]) } } diff --git a/introspection-engine/connectors/sql-introspection-connector/tests/db_specific_introspection/postgres/tables_postgres.rs b/introspection-engine/connectors/sql-introspection-connector/tests/db_specific_introspection/postgres/tables_postgres.rs index d19d60e05a2a..95fe96f504c2 100644 --- a/introspection-engine/connectors/sql-introspection-connector/tests/db_specific_introspection/postgres/tables_postgres.rs +++ b/introspection-engine/connectors/sql-introspection-connector/tests/db_specific_introspection/postgres/tables_postgres.rs @@ -439,3 +439,44 @@ async fn introspecting_an_unsupported_type_should_comment_it_out(api: &TestApi) let result = dbg!(api.introspect().await); assert_eq!(&result, "model Test {\n id Int @default(autoincrement()) @id\n network_inet String?\n // This type is currently not supported.\n // network_mac macaddr?\n}"); } + +#[test_each_connector(tags("postgres"))] +async fn introspecting_a_legacy_m_to_n_relation_should_work(api: &TestApi) { + let barrel = api.barrel(); + let _setup_schema = barrel + .execute(|migration| { + migration.create_table("Post", |t| { + t.inject_custom("id integer PRIMARY KEY"); + }); + migration.create_table("Category", |t| { + t.inject_custom("id integer PRIMARY KEY"); + }); + + migration.create_table("_CategoryToPost", |t| { + t.inject_custom("A integer NOT NULL REFERENCES \"Category\"(id) ON DELETE CASCADE ON UPDATE CASCADE"); + t.inject_custom("B integer NOT NULL REFERENCES \"Post\"(id) ON DELETE CASCADE ON UPDATE CASCADE"); + }); + }) + .await; + let unique = + "CREATE UNIQUE INDEX _CategoryToPost_AB_unique ON \"_CategoryToPost\"(\"a\",\"b\" )"; + let index = "CREATE INDEX _CategoryToPost_AB_index ON \"_CategoryToPost\"(\"b\" )"; + + api.database().execute_raw(unique, &[]).await.unwrap(); + api.database().execute_raw(index, &[]).await.unwrap(); + + let dm = r#" + model Category { + id Int @id + post Post[] + } + + model Post { + id Int @id + category Category[] + } + "#; + + let result = dbg!(api.introspect().await); + custom_assert(&result, dm); +} From 95074acd986146568a851a602e524f64c720e3b4 Mon Sep 17 00:00:00 2001 From: Matthias Date: Fri, 20 Mar 2020 11:30:33 +0100 Subject: [PATCH 3/4] adjust tests --- .../sql-introspection-connector/src/misc_helpers.rs | 4 ++-- .../mysql/relations_mysql.rs | 1 + .../postgres/relations_postgres.rs | 11 +++++++++++ .../sqlite/relations_sqlite.rs | 11 +++++++++++ 4 files changed, 25 insertions(+), 2 deletions(-) diff --git a/introspection-engine/connectors/sql-introspection-connector/src/misc_helpers.rs b/introspection-engine/connectors/sql-introspection-connector/src/misc_helpers.rs index 0e5bd77a8f84..d94c96f3550a 100644 --- a/introspection-engine/connectors/sql-introspection-connector/src/misc_helpers.rs +++ b/introspection-engine/connectors/sql-introspection-connector/src/misc_helpers.rs @@ -18,12 +18,12 @@ pub fn is_migration_table(table: &Table) -> bool { } pub(crate) fn is_prisma_1_point_1_join_table(table: &Table) -> bool { - table.columns.len() == 2 && table.indices.len() == 2 && shared(table) + table.columns.len() == 2 && table.indices.len() >= 2 && shared(table) } pub(crate) fn is_prisma_1_point_0_join_table(table: &Table) -> bool { table.columns.len() == 3 - && table.indices.len() == 3 + && table.indices.len() >= 2 && table.columns.iter().any(|c| c.name == "id".to_string()) && shared(table) } diff --git a/introspection-engine/connectors/sql-introspection-connector/tests/db_specific_introspection/mysql/relations_mysql.rs b/introspection-engine/connectors/sql-introspection-connector/tests/db_specific_introspection/mysql/relations_mysql.rs index 13fbd825d012..ea473066b69f 100644 --- a/introspection-engine/connectors/sql-introspection-connector/tests/db_specific_introspection/mysql/relations_mysql.rs +++ b/introspection-engine/connectors/sql-introspection-connector/tests/db_specific_introspection/mysql/relations_mysql.rs @@ -257,6 +257,7 @@ async fn introspecting_a_prisma_many_to_many_relation_should_work(api: &TestApi) FOREIGN KEY (`B`) REFERENCES `User`(`id`) ON DELETE CASCADE", ); t.add_index("test", types::index(vec!["A", "B"]).unique(true)); + t.add_index("test2", types::index(vec!["B"]).unique(false)); }); }, api.db_name(), diff --git a/introspection-engine/connectors/sql-introspection-connector/tests/db_specific_introspection/postgres/relations_postgres.rs b/introspection-engine/connectors/sql-introspection-connector/tests/db_specific_introspection/postgres/relations_postgres.rs index f2170653b355..9ae1ace34365 100644 --- a/introspection-engine/connectors/sql-introspection-connector/tests/db_specific_introspection/postgres/relations_postgres.rs +++ b/introspection-engine/connectors/sql-introspection-connector/tests/db_specific_introspection/postgres/relations_postgres.rs @@ -228,6 +228,17 @@ async fn introspecting_a_prisma_many_to_many_relation_should_work(api: &TestApi) .await .unwrap(); + api.database() + .execute_raw( + &format!( + "CREATE INDEX test2 ON \"{}\".\"_PostToUser\" (\"b\");", + api.schema_name() + ), + &[], + ) + .await + .unwrap(); + let dm = r#" model Post { id Int @id @default(autoincrement()) diff --git a/introspection-engine/connectors/sql-introspection-connector/tests/db_specific_introspection/sqlite/relations_sqlite.rs b/introspection-engine/connectors/sql-introspection-connector/tests/db_specific_introspection/sqlite/relations_sqlite.rs index 292d92bca34c..2c06314a436e 100644 --- a/introspection-engine/connectors/sql-introspection-connector/tests/db_specific_introspection/sqlite/relations_sqlite.rs +++ b/introspection-engine/connectors/sql-introspection-connector/tests/db_specific_introspection/sqlite/relations_sqlite.rs @@ -242,6 +242,17 @@ async fn introspecting_a_prisma_many_to_many_relation_should_work(api: &TestApi) .await .unwrap(); + api.database() + .execute_raw( + &format!( + "CREATE INDEX \"{}\".test2 ON \"_PostToUser\" (\"B\");", + api.schema_name(), + ), + &[], + ) + .await + .unwrap(); + let dm = r#" model User { id Int @id @default(autoincrement()) From 77c3d0cb7fb4c506c154c00b24070f60f5afd320 Mon Sep 17 00:00:00 2001 From: Matthias Date: Fri, 20 Mar 2020 12:50:20 +0100 Subject: [PATCH 4/4] address review comments --- .../sql-introspection-connector/src/misc_helpers.rs | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/introspection-engine/connectors/sql-introspection-connector/src/misc_helpers.rs b/introspection-engine/connectors/sql-introspection-connector/src/misc_helpers.rs index d94c96f3550a..09fc02d4c57b 100644 --- a/introspection-engine/connectors/sql-introspection-connector/src/misc_helpers.rs +++ b/introspection-engine/connectors/sql-introspection-connector/src/misc_helpers.rs @@ -18,17 +18,19 @@ pub fn is_migration_table(table: &Table) -> bool { } pub(crate) fn is_prisma_1_point_1_join_table(table: &Table) -> bool { - table.columns.len() == 2 && table.indices.len() >= 2 && shared(table) + table.columns.len() == 2 + && table.indices.len() >= 2 + && common_prisma_m_to_n_relation_conditions(table) } pub(crate) fn is_prisma_1_point_0_join_table(table: &Table) -> bool { table.columns.len() == 3 && table.indices.len() >= 2 - && table.columns.iter().any(|c| c.name == "id".to_string()) - && shared(table) + && table.columns.iter().any(|c| c.name.as_str() == "id") + && common_prisma_m_to_n_relation_conditions(table) } -fn shared(table: &Table) -> bool { +fn common_prisma_m_to_n_relation_conditions(table: &Table) -> bool { fn is_a(column: &String) -> bool { column.to_lowercase() == "a" }