Skip to content

Commit 612a7f7

Browse files
authored
fix(psl): retrieve all referential actions based on relationMode (#4844)
* rename referential_actions to reflect that it only works for foreign_keys * add new referential_actions fn that matches on relation_mode and defers to the FK / emulated actions * Add test cases for completions on mongodb and for mysql w/ RM = prisma & FK
1 parent d3ec637 commit 612a7f7

File tree

18 files changed

+157
-15
lines changed

18 files changed

+157
-15
lines changed

prisma-fmt/src/actions.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ pub(crate) fn run(schema: &str) -> String {
88
} else if let Some(datasource) = validated_configuration.datasources.first() {
99
let available_referential_actions = datasource
1010
.active_connector
11-
.referential_actions()
11+
.referential_actions(&datasource.relation_mode())
1212
.iter()
1313
.map(|act| format!("{act:?}"))
1414
.collect::<Vec<_>>();

prisma-fmt/src/text_document_completion.rs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -91,12 +91,17 @@ impl<'a> CompletionContext<'a> {
9191
}
9292

9393
fn push_ast_completions(ctx: CompletionContext<'_>, completion_list: &mut CompletionList) {
94+
let relation_mode = match ctx.config.map(|c| c.relation_mode()) {
95+
Some(Some(rm)) => rm,
96+
_ => ctx.connector().default_relation_mode(),
97+
};
98+
9499
match ctx.db.ast_assert_single().find_at_position(ctx.position) {
95100
ast::SchemaPosition::Model(
96101
_model_id,
97102
ast::ModelPosition::Field(_, ast::FieldPosition::Attribute("relation", _, Some(attr_name))),
98103
) if attr_name == "onDelete" || attr_name == "onUpdate" => {
99-
for referential_action in ctx.connector().referential_actions().iter() {
104+
for referential_action in ctx.connector().referential_actions(&relation_mode).iter() {
100105
completion_list.items.push(CompletionItem {
101106
label: referential_action.as_str().to_owned(),
102107
kind: Some(CompletionItemKind::ENUM),
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
{
2+
"isIncomplete": false,
3+
"items": [
4+
{
5+
"label": "Cascade",
6+
"kind": 13,
7+
"detail": "Delete the child records when the parent record is deleted."
8+
},
9+
{
10+
"label": "Restrict",
11+
"kind": 13,
12+
"detail": "Prevent deleting a parent record as long as it is referenced."
13+
},
14+
{
15+
"label": "NoAction",
16+
"kind": 13,
17+
"detail": "Prevent deleting a parent record as long as it is referenced."
18+
},
19+
{
20+
"label": "SetNull",
21+
"kind": 13,
22+
"detail": "Set the referencing fields to NULL when the referenced record is deleted."
23+
},
24+
{
25+
"label": "SetDefault",
26+
"kind": 13,
27+
"detail": "Set the referencing field's value to the default when the referenced record is deleted."
28+
}
29+
]
30+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
datasource db {
2+
provider = "mysql"
3+
url = env("DATABASE_URL")
4+
relationMode = "foreignKeys"
5+
}
6+
7+
model Post {
8+
id Int @id @default(autoincrement())
9+
title String
10+
author User @relation(fields: [authorId], references: [id], onDelete: <|>)
11+
authorId Int
12+
}
13+
14+
model User {
15+
id Int @id @default(autoincrement())
16+
posts Post[]
17+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
{
2+
"isIncomplete": false,
3+
"items": [
4+
{
5+
"label": "Cascade",
6+
"kind": 13,
7+
"detail": "Delete the child records when the parent record is deleted."
8+
},
9+
{
10+
"label": "Restrict",
11+
"kind": 13,
12+
"detail": "Prevent deleting a parent record as long as it is referenced."
13+
},
14+
{
15+
"label": "NoAction",
16+
"kind": 13,
17+
"detail": "Prevent deleting a parent record as long as it is referenced."
18+
},
19+
{
20+
"label": "SetNull",
21+
"kind": 13,
22+
"detail": "Set the referencing fields to NULL when the referenced record is deleted."
23+
}
24+
]
25+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
datasource db {
2+
provider = "mongodb"
3+
url = env("DATABASE_URL")
4+
}
5+
6+
model Post {
7+
id String @id @default(auto()) @map("_id") @db.ObjectId
8+
title String
9+
author User @relation(fields: [authorId], references: [id], onDelete: <|>)
10+
authorId String @db.ObjectId
11+
}
12+
13+
model User {
14+
id String @id @default(auto()) @map("_id") @db.ObjectId
15+
posts Post[]
16+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
{
2+
"isIncomplete": false,
3+
"items": [
4+
{
5+
"label": "Cascade",
6+
"kind": 13,
7+
"detail": "Delete the child records when the parent record is deleted."
8+
},
9+
{
10+
"label": "Restrict",
11+
"kind": 13,
12+
"detail": "Prevent deleting a parent record as long as it is referenced."
13+
},
14+
{
15+
"label": "NoAction",
16+
"kind": 13,
17+
"detail": "Prevent deleting a parent record as long as it is referenced."
18+
},
19+
{
20+
"label": "SetNull",
21+
"kind": 13,
22+
"detail": "Set the referencing fields to NULL when the referenced record is deleted."
23+
}
24+
]
25+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
datasource db {
2+
provider = "mysql"
3+
url = env("DATABASE_URL")
4+
relationMode = "prisma"
5+
}
6+
7+
model Post {
8+
id Int @id @default(autoincrement())
9+
title String
10+
author User @relation(fields: [authorId], references: [id], onDelete: <|>)
11+
authorId Int
12+
}
13+
14+
model User {
15+
id Int @id @default(autoincrement())
16+
posts Post[]
17+
}

prisma-fmt/tests/text_document_completion/tests.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,9 @@ scenarios! {
3535
referential_actions_in_progress_2
3636
referential_actions_middle_of_args_list
3737
referential_actions_mssql
38+
referential_actions_relation_mode_prisma_mongodb
39+
referential_actions_relation_mode_prisma_mysql
40+
referential_actions_relation_mode_fk_mysql
3841
referential_actions_with_trailing_comma
3942
datasource_default_completions
4043
datasource_multischema

psl/psl-core/src/builtin_connectors/cockroach_datamodel_connector.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,7 @@ impl Connector for CockroachDatamodelConnector {
100100
63
101101
}
102102

103-
fn referential_actions(&self) -> BitFlags<ReferentialAction> {
103+
fn foreign_key_referential_actions(&self) -> BitFlags<ReferentialAction> {
104104
use ReferentialAction::*;
105105

106106
NoAction | Restrict | Cascade | SetNull | SetDefault

psl/psl-core/src/builtin_connectors/mongodb.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ impl Connector for MongoDbDatamodelConnector {
6161
&[ConstraintScope::ModelKeyIndex]
6262
}
6363

64-
fn referential_actions(&self) -> BitFlags<ReferentialAction> {
64+
fn foreign_key_referential_actions(&self) -> BitFlags<ReferentialAction> {
6565
BitFlags::empty()
6666
}
6767

psl/psl-core/src/builtin_connectors/mssql_datamodel_connector.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@ impl Connector for MsSqlDatamodelConnector {
9393
128
9494
}
9595

96-
fn referential_actions(&self) -> BitFlags<ReferentialAction> {
96+
fn foreign_key_referential_actions(&self) -> BitFlags<ReferentialAction> {
9797
use ReferentialAction::*;
9898

9999
NoAction | Cascade | SetNull | SetDefault

psl/psl-core/src/builtin_connectors/mysql_datamodel_connector.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,7 @@ impl Connector for MySqlDatamodelConnector {
109109
64
110110
}
111111

112-
fn referential_actions(&self) -> BitFlags<ReferentialAction> {
112+
fn foreign_key_referential_actions(&self) -> BitFlags<ReferentialAction> {
113113
use ReferentialAction::*;
114114

115115
Restrict | Cascade | SetNull | NoAction | SetDefault

psl/psl-core/src/builtin_connectors/postgres_datamodel_connector.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -273,7 +273,7 @@ impl Connector for PostgresDatamodelConnector {
273273
63
274274
}
275275

276-
fn referential_actions(&self) -> BitFlags<ReferentialAction> {
276+
fn foreign_key_referential_actions(&self) -> BitFlags<ReferentialAction> {
277277
use ReferentialAction::*;
278278

279279
NoAction | Restrict | Cascade | SetNull | SetDefault

psl/psl-core/src/builtin_connectors/sqlite_datamodel_connector.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ impl Connector for SqliteDatamodelConnector {
5252
10000
5353
}
5454

55-
fn referential_actions(&self) -> BitFlags<ReferentialAction> {
55+
fn foreign_key_referential_actions(&self) -> BitFlags<ReferentialAction> {
5656
use ReferentialAction::*;
5757

5858
SetNull | SetDefault | Cascade | Restrict | NoAction

psl/psl-core/src/datamodel_connector.rs

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -78,8 +78,15 @@ pub trait Connector: Send + Sync {
7878
RelationMode::ForeignKeys
7979
}
8080

81+
fn referential_actions(&self, relation_mode: &RelationMode) -> BitFlags<ReferentialAction> {
82+
match relation_mode {
83+
RelationMode::ForeignKeys => self.foreign_key_referential_actions(),
84+
RelationMode::Prisma => self.emulated_referential_actions(),
85+
}
86+
}
87+
8188
/// The referential actions supported by the connector.
82-
fn referential_actions(&self) -> BitFlags<ReferentialAction>;
89+
fn foreign_key_referential_actions(&self) -> BitFlags<ReferentialAction>;
8390

8491
/// The referential actions supported when using relationMode = "prisma" by the connector.
8592
/// There are in fact scenarios in which the set of emulated referential actions supported may change
@@ -101,10 +108,7 @@ pub trait Connector: Send + Sync {
101108
}
102109

103110
fn supports_referential_action(&self, relation_mode: &RelationMode, action: ReferentialAction) -> bool {
104-
match relation_mode {
105-
RelationMode::ForeignKeys => self.referential_actions().contains(action),
106-
RelationMode::Prisma => self.emulated_referential_actions().contains(action),
107-
}
111+
self.referential_actions(relation_mode).contains(action)
108112
}
109113

110114
/// This is used by the query engine schema builder.

psl/psl-core/src/datamodel_connector/empty_connector.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ impl Connector for EmptyDatamodelConnector {
1515
std::any::type_name::<EmptyDatamodelConnector>()
1616
}
1717

18-
fn referential_actions(&self) -> BitFlags<ReferentialAction> {
18+
fn foreign_key_referential_actions(&self) -> BitFlags<ReferentialAction> {
1919
BitFlags::all()
2020
}
2121

psl/psl-core/src/validate/validation_pipeline/validations/relation_fields.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -153,7 +153,7 @@ pub(super) fn referential_actions(field: RelationFieldWalker<'_>, ctx: &mut Cont
153153

154154
// validation template for relationMode = "foreignKeys"
155155
let msg_foreign_keys = |action: ReferentialAction| {
156-
let allowed_actions = connector.referential_actions();
156+
let allowed_actions = connector.referential_actions(&relation_mode);
157157

158158
format!(
159159
"Invalid referential action: `{}`. Allowed values: ({})",

0 commit comments

Comments
 (0)