Skip to content

Commit

Permalink
Return of some of the old normalization for now
Browse files Browse the repository at this point in the history
  • Loading branch information
Julius de Bruijn committed Oct 20, 2022
1 parent 01a002e commit d424260
Show file tree
Hide file tree
Showing 4 changed files with 131 additions and 67 deletions.
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
use std::collections::HashMap;

use crate::{calculate_datamodel::CalculateDatamodelContext as Context, SqlFamilyTrait};
use once_cell::sync::Lazy;
use psl::{
Expand All @@ -16,8 +18,8 @@ static RE_START: Lazy<Regex> = Lazy::new(|| Regex::new("^[^a-zA-Z]+").unwrap());
static RE: Lazy<Regex> = Lazy::new(|| Regex::new("[^_a-zA-Z0-9]").unwrap());

pub(crate) fn sanitize_datamodel_names(ctx: &Context, datamodel: &mut Datamodel) {
sanitize_models(ctx, datamodel);
sanitize_enums(datamodel);
let mut enum_renames = sanitize_models(ctx, datamodel);
sanitize_enums(&mut enum_renames, datamodel);
}

// if after opionated renames we have duplicated names, e.g. a database with
Expand All @@ -41,7 +43,8 @@ pub fn sanitization_leads_to_duplicate_names(datamodel: &Datamodel) -> bool {
}

// Todo: Sanitizing might need to be adjusted to also change the fields in the RelationInfo
fn sanitize_models(ctx: &Context, datamodel: &mut Datamodel) {
fn sanitize_models(ctx: &Context, datamodel: &mut Datamodel) -> HashMap<String, (String, Option<String>)> {
let mut enum_renames = HashMap::new();
let sql_family = ctx.sql_family();

for model in datamodel.models_mut() {
Expand Down Expand Up @@ -74,16 +77,26 @@ fn sanitize_models(ctx: &Context, datamodel: &mut Datamodel) {
// Enums in MySQL are defined on the column and do not have a separate name.
// Introspection generates an enum name for MySQL as `<model_name>_<field_type>`.
// If the sanitization changes the enum name, we need to make sure it's changed everywhere.
let sanitized_enum_name = if let SqlFamily::Mysql = sql_family {
let (sanitized_enum_name, db_name) = if let SqlFamily::Mysql = sql_family {
if model_db_name.is_none() && sf.database_name.is_none() {
enum_name.to_owned()
(enum_name.to_owned(), None)
} else {
format!("{}_{}", model_name, sf.name())
(format!("{}_{}", model_name, sf.name()), Some(enum_name.to_owned()))
}
} else {
sanitize_string(enum_name)
let sanitized = sanitize_string(enum_name);

if &sanitized != enum_name {
(sanitized, Some(enum_name.to_owned()))
} else {
(sanitized, None)
}
};

if db_name.is_some() {
enum_renames.insert(enum_name.to_owned(), (sanitized_enum_name.clone(), db_name));
}

sf.field_type = FieldType::Enum(sanitized_enum_name);

// If the field also has an associated default enum value, we need to sanitize that enum value.
Expand Down Expand Up @@ -116,14 +129,29 @@ fn sanitize_models(ctx: &Context, datamodel: &mut Datamodel) {
sanitize_index_field_names(&mut index.fields);
}
}

enum_renames
}

fn sanitize_enums(datamodel: &mut Datamodel) {
fn sanitize_enums(enum_renames: &HashMap<String, (String, Option<String>)>, datamodel: &mut Datamodel) {
for enm in datamodel.enums_mut() {
sanitize_name(enm);
if let Some((sanitized_name, db_name)) = enum_renames.get(&enm.name) {
if enm.database_name().is_none() {
enm.set_database_name(db_name.clone());
}

enm.set_name(sanitized_name);
} else {
sanitize_name(enm);
}

for enum_value in enm.values_mut() {
sanitize_name(enum_value);
if enum_value.name.is_empty() {
enum_value.name = EMPTY_ENUM_PLACEHOLDER.to_string();
enum_value.database_name = Some("".to_string());
} else {
sanitize_name(enum_value);
}
}
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
mod mssql;
mod mysql;
mod postgresql;
mod sqlite;

use barrel::types;
Expand All @@ -19,7 +21,6 @@ async fn should_not_remap_if_renaming_would_lead_to_duplicate_names(api: &TestAp
CONSTRAINT _nodes_node_a_fkey FOREIGN KEY(node_a) REFERENCES nodes(id) ON DELETE CASCADE ON UPDATE CASCADE,
CONSTRAINT _nodes_node_b_fkey FOREIGN KEY(node_b) REFERENCES nodes(id) ON DELETE CASCADE ON UPDATE CASCADE
);
"#;
api.raw_cmd(sql).await;

Expand Down Expand Up @@ -301,62 +302,6 @@ async fn remapping_fields_in_compound_relations(api: &TestApi) -> TestResult {
Ok(())
}

#[test_connector(capabilities(Enums), exclude(CockroachDb))]
async fn remapping_enum_names(api: &TestApi) -> TestResult {
let sql_family = api.sql_family();

if sql_family.is_postgres() {
api.database()
.raw_cmd("CREATE TYPE \"123color\" AS ENUM ('black')")
.await?;
}

api.barrel()
.execute(move |migration| {
migration.create_table("123Book", move |t| {
t.add_column("id", types::primary());

let typ = if sql_family.is_mysql() {
"ENUM ('black')"
} else {
"\"123color\""
};

t.add_column("1color", types::custom(typ).nullable(true));
});
})
.await?;

let enum_name = if sql_family.is_mysql() { "Book_color" } else { "color" };

let renamed_enum = if sql_family.is_mysql() {
"123Book_1color"
} else {
"123color"
};

let dm = format!(
r#"
model Book {{
id Int @id @default(autoincrement())
color {0}? @map("1color")
@@map("123Book")
}}
enum {0} {{
black
@@map("{1}")
}}
"#,
enum_name, renamed_enum
);

api.assert_eq_datamodels(&dm, &api.introspect().await?);

Ok(())
}

#[test_connector(capabilities(Enums), exclude(CockroachDb))]
async fn remapping_enum_values(api: &TestApi) -> TestResult {
let sql_family = api.sql_family();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
use expect_test::expect;
use indoc::indoc;
use introspection_engine_tests::test_api::*;
use test_macros::test_connector;

#[test_connector(tags(Mysql))]
async fn remapping_enum_names(api: &TestApi) -> TestResult {
let setup = indoc! {r#"
CREATE TABLE `123Book` (
id INT NOT NULL AUTO_INCREMENT,
1color ENUM ('black') NULL,
PRIMARY KEY (id)
)
"#};

api.raw_cmd(setup).await;

let expectation = expect![[r#"
generator client {
provider = "prisma-client-js"
}
datasource db {
provider = "mysql"
url = "env(TEST_DATABASE_URL)"
}
model Book {
id Int @id @default(autoincrement())
color Book_color? @map("1color")
@@map("123Book")
}
enum Book_color {
black
@@map("123Book_1color")
}
"#]];

api.expect_datamodel(&expectation).await;

Ok(())
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
use expect_test::expect;
use indoc::indoc;
use introspection_engine_tests::test_api::*;
use test_macros::test_connector;

#[test_connector(tags(Postgres), exclude(CockroachDb))]
async fn remapping_enum_names(api: &TestApi) -> TestResult {
let setup = indoc! {r#"
CREATE TYPE "123color" AS ENUM ('black');
CREATE TABLE "123Book" (
id SERIAL PRIMARY KEY,
"1color" "123color" NULL
);
"#};

api.raw_cmd(setup).await;

let expectation = expect![[r#"
generator client {
provider = "prisma-client-js"
}
datasource db {
provider = "postgresql"
url = "env(TEST_DATABASE_URL)"
}
model Book {
id Int @id @default(autoincrement())
color color? @map("1color")
@@map("123Book")
}
enum color {
black
@@map("123color")
}
"#]];

api.expect_datamodel(&expectation).await;

Ok(())
}

0 comments on commit d424260

Please sign in to comment.