Skip to content

Commit

Permalink
reformatting: Fix spacing between attributes in edge cases
Browse files Browse the repository at this point in the history
In 1:1 relations, the reformatter can add `@unique` attributes. If they
come after a native type attribute, the reformatter failed to add
adequate spacing between the attributes, resulting in valid but odd
looking schemas. This commit fixes that problem.

These schemas are also not idempotent, because of interactions between
attribute sorting and missing attributes addition. Issue:
prisma/prisma#12726

closes prisma/prisma#12596
  • Loading branch information
tomhoule committed Apr 8, 2022
1 parent ba8e3c2 commit 9d22f13
Show file tree
Hide file tree
Showing 4 changed files with 95 additions and 12 deletions.
30 changes: 20 additions & 10 deletions libs/datamodel/core/src/reformat.rs
Original file line number Diff line number Diff line change
Expand Up @@ -408,16 +408,16 @@ impl<'a> Reformatter<'a> {
let attributes = Self::extract_and_sort_attributes(token, true);

// iterate through tokens and reorder attributes
let mut count = 0;
let mut attributes_count = 0;
let inner_pairs_with_sorted_attributes = token.clone().into_inner().map(|p| match p.as_rule() {
Rule::attribute => {
count += 1;
attributes[count - 1].clone()
attributes_count += 1;
attributes[attributes_count - 1].clone()
}
_ => p,
});

// write to target
// Write existing attributes first.
for current in inner_pairs_with_sorted_attributes {
match current.as_rule() {
Rule::non_empty_identifier | Rule::maybe_empty_identifier => {
Expand Down Expand Up @@ -449,12 +449,22 @@ impl<'a> Reformatter<'a> {
}
}

for missing_field_attribute in &self.missing_field_attributes {
if missing_field_attribute.field == field_name && missing_field_attribute.model.as_str() == model_name {
Renderer::render_field_attribute(
&mut target.column_locked_writer_for(2),
&missing_field_attribute.attribute,
)
// Write missing attributes.
let mut column_writer = target.column_locked_writer_for(2); // third column
let mut missing_field_attributes = self
.missing_field_attributes
.iter()
.filter(|missing_field_attribute| {
missing_field_attribute.field == field_name && missing_field_attribute.model.as_str() == model_name
})
.peekable();
if attributes_count > 0 && missing_field_attributes.peek().is_some() {
column_writer.write(" "); // space between attributes
}
while let Some(missing_field_attribute) = missing_field_attributes.next() {
Renderer::render_field_attribute(&mut column_writer, &missing_field_attribute.attribute);
if missing_field_attributes.peek().is_some() {
column_writer.write(" "); // space between attributes
}
}

Expand Down
74 changes: 74 additions & 0 deletions libs/datamodel/core/tests/reformat/reformat.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1334,3 +1334,77 @@ fn composite_type_native_types_roundtrip() {

expected.assert_eq(&reformat(schema));
}

#[test]
fn weird_at_unique() {
let schema = r#"
generator client {
provider = "prisma-client-js"
previewFeatures = "mongodb"
}
datasource db {
provider = "mongodb"
url = "m...ty"
}
model Foo {
id String @id @default(auto()) @map("_id") @db.ObjectId
name String @unique
json Json
bar Bar
bars Bar[]
baz Baz @relation(fields: [bazId], references: [id])
bazId String @db.ObjectId
list String[]
jsonList Json[]
}
type Bar {
label String
number Int
}
model Baz {
id String @id @default(auto()) @map("_id") @db.ObjectId
foo Foo?
}
"#;

let expected = expect![[r#"
generator client {
provider = "prisma-client-js"
previewFeatures = "mongodb"
}
datasource db {
provider = "mongodb"
url = "m...ty"
}
model Foo {
id String @id @default(auto()) @map("_id") @db.ObjectId
name String @unique
json Json
bar Bar
bars Bar[]
baz Baz @relation(fields: [bazId], references: [id])
bazId String @db.ObjectId @unique
list String[]
jsonList Json[]
}
type Bar {
label String
number Int
}
model Baz {
id String @id @default(auto()) @map("_id") @db.ObjectId
foo Foo?
}
"#]];

expected.assert_eq(&reformat(schema));
}
1 change: 0 additions & 1 deletion libs/datamodel/schema-ast/src/renderer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -467,7 +467,6 @@ impl<'a> Renderer<'a> {
impl<'a> LineWriteable for Renderer<'a> {
fn write(&mut self, param: &str) {
self.is_new = false;
// TODO: Proper result handling.
if self.new_line > 0 || self.maybe_new_line > 0 {
for _i in 0..std::cmp::max(self.new_line, self.maybe_new_line) {
self.stream.write_char('\n').expect("Writer error.");
Expand Down
2 changes: 1 addition & 1 deletion libs/datamodel/schema-ast/src/renderer/table.rs
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ impl TableFormat {
if row[index].is_empty() {
row[index] = String::from(text);
} else {
row[index] = format!("{}{}", &row[index], text);
row[index].push_str(text);
}
}
Row::Interleaved(_) => panic!("Cannot append to col in interleaved mode"),
Expand Down

0 comments on commit 9d22f13

Please sign in to comment.