Skip to content

Commit

Permalink
fix(psl): retrieve all referential actions based on relationMode (#4844)
Browse files Browse the repository at this point in the history
* 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
  • Loading branch information
Druue authored Apr 30, 2024
1 parent d3ec637 commit 612a7f7
Show file tree
Hide file tree
Showing 18 changed files with 157 additions and 15 deletions.
2 changes: 1 addition & 1 deletion prisma-fmt/src/actions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ pub(crate) fn run(schema: &str) -> String {
} else if let Some(datasource) = validated_configuration.datasources.first() {
let available_referential_actions = datasource
.active_connector
.referential_actions()
.referential_actions(&datasource.relation_mode())
.iter()
.map(|act| format!("{act:?}"))
.collect::<Vec<_>>();
Expand Down
7 changes: 6 additions & 1 deletion prisma-fmt/src/text_document_completion.rs
Original file line number Diff line number Diff line change
Expand Up @@ -91,12 +91,17 @@ impl<'a> CompletionContext<'a> {
}

fn push_ast_completions(ctx: CompletionContext<'_>, completion_list: &mut CompletionList) {
let relation_mode = match ctx.config.map(|c| c.relation_mode()) {
Some(Some(rm)) => rm,
_ => ctx.connector().default_relation_mode(),
};

match ctx.db.ast_assert_single().find_at_position(ctx.position) {
ast::SchemaPosition::Model(
_model_id,
ast::ModelPosition::Field(_, ast::FieldPosition::Attribute("relation", _, Some(attr_name))),
) if attr_name == "onDelete" || attr_name == "onUpdate" => {
for referential_action in ctx.connector().referential_actions().iter() {
for referential_action in ctx.connector().referential_actions(&relation_mode).iter() {
completion_list.items.push(CompletionItem {
label: referential_action.as_str().to_owned(),
kind: Some(CompletionItemKind::ENUM),
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
{
"isIncomplete": false,
"items": [
{
"label": "Cascade",
"kind": 13,
"detail": "Delete the child records when the parent record is deleted."
},
{
"label": "Restrict",
"kind": 13,
"detail": "Prevent deleting a parent record as long as it is referenced."
},
{
"label": "NoAction",
"kind": 13,
"detail": "Prevent deleting a parent record as long as it is referenced."
},
{
"label": "SetNull",
"kind": 13,
"detail": "Set the referencing fields to NULL when the referenced record is deleted."
},
{
"label": "SetDefault",
"kind": 13,
"detail": "Set the referencing field's value to the default when the referenced record is deleted."
}
]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
datasource db {
provider = "mysql"
url = env("DATABASE_URL")
relationMode = "foreignKeys"
}

model Post {
id Int @id @default(autoincrement())
title String
author User @relation(fields: [authorId], references: [id], onDelete: <|>)
authorId Int
}

model User {
id Int @id @default(autoincrement())
posts Post[]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
{
"isIncomplete": false,
"items": [
{
"label": "Cascade",
"kind": 13,
"detail": "Delete the child records when the parent record is deleted."
},
{
"label": "Restrict",
"kind": 13,
"detail": "Prevent deleting a parent record as long as it is referenced."
},
{
"label": "NoAction",
"kind": 13,
"detail": "Prevent deleting a parent record as long as it is referenced."
},
{
"label": "SetNull",
"kind": 13,
"detail": "Set the referencing fields to NULL when the referenced record is deleted."
}
]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
datasource db {
provider = "mongodb"
url = env("DATABASE_URL")
}

model Post {
id String @id @default(auto()) @map("_id") @db.ObjectId
title String
author User @relation(fields: [authorId], references: [id], onDelete: <|>)
authorId String @db.ObjectId
}

model User {
id String @id @default(auto()) @map("_id") @db.ObjectId
posts Post[]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
{
"isIncomplete": false,
"items": [
{
"label": "Cascade",
"kind": 13,
"detail": "Delete the child records when the parent record is deleted."
},
{
"label": "Restrict",
"kind": 13,
"detail": "Prevent deleting a parent record as long as it is referenced."
},
{
"label": "NoAction",
"kind": 13,
"detail": "Prevent deleting a parent record as long as it is referenced."
},
{
"label": "SetNull",
"kind": 13,
"detail": "Set the referencing fields to NULL when the referenced record is deleted."
}
]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
datasource db {
provider = "mysql"
url = env("DATABASE_URL")
relationMode = "prisma"
}

model Post {
id Int @id @default(autoincrement())
title String
author User @relation(fields: [authorId], references: [id], onDelete: <|>)
authorId Int
}

model User {
id Int @id @default(autoincrement())
posts Post[]
}
3 changes: 3 additions & 0 deletions prisma-fmt/tests/text_document_completion/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,9 @@ scenarios! {
referential_actions_in_progress_2
referential_actions_middle_of_args_list
referential_actions_mssql
referential_actions_relation_mode_prisma_mongodb
referential_actions_relation_mode_prisma_mysql
referential_actions_relation_mode_fk_mysql
referential_actions_with_trailing_comma
datasource_default_completions
datasource_multischema
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ impl Connector for CockroachDatamodelConnector {
63
}

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

NoAction | Restrict | Cascade | SetNull | SetDefault
Expand Down
2 changes: 1 addition & 1 deletion psl/psl-core/src/builtin_connectors/mongodb.rs
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ impl Connector for MongoDbDatamodelConnector {
&[ConstraintScope::ModelKeyIndex]
}

fn referential_actions(&self) -> BitFlags<ReferentialAction> {
fn foreign_key_referential_actions(&self) -> BitFlags<ReferentialAction> {
BitFlags::empty()
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ impl Connector for MsSqlDatamodelConnector {
128
}

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

NoAction | Cascade | SetNull | SetDefault
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ impl Connector for MySqlDatamodelConnector {
64
}

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

Restrict | Cascade | SetNull | NoAction | SetDefault
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -273,7 +273,7 @@ impl Connector for PostgresDatamodelConnector {
63
}

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

NoAction | Restrict | Cascade | SetNull | SetDefault
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ impl Connector for SqliteDatamodelConnector {
10000
}

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

SetNull | SetDefault | Cascade | Restrict | NoAction
Expand Down
14 changes: 9 additions & 5 deletions psl/psl-core/src/datamodel_connector.rs
Original file line number Diff line number Diff line change
Expand Up @@ -78,8 +78,15 @@ pub trait Connector: Send + Sync {
RelationMode::ForeignKeys
}

fn referential_actions(&self, relation_mode: &RelationMode) -> BitFlags<ReferentialAction> {
match relation_mode {
RelationMode::ForeignKeys => self.foreign_key_referential_actions(),
RelationMode::Prisma => self.emulated_referential_actions(),
}
}

/// The referential actions supported by the connector.
fn referential_actions(&self) -> BitFlags<ReferentialAction>;
fn foreign_key_referential_actions(&self) -> BitFlags<ReferentialAction>;

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

fn supports_referential_action(&self, relation_mode: &RelationMode, action: ReferentialAction) -> bool {
match relation_mode {
RelationMode::ForeignKeys => self.referential_actions().contains(action),
RelationMode::Prisma => self.emulated_referential_actions().contains(action),
}
self.referential_actions(relation_mode).contains(action)
}

/// This is used by the query engine schema builder.
Expand Down
2 changes: 1 addition & 1 deletion psl/psl-core/src/datamodel_connector/empty_connector.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ impl Connector for EmptyDatamodelConnector {
std::any::type_name::<EmptyDatamodelConnector>()
}

fn referential_actions(&self) -> BitFlags<ReferentialAction> {
fn foreign_key_referential_actions(&self) -> BitFlags<ReferentialAction> {
BitFlags::all()
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,7 @@ pub(super) fn referential_actions(field: RelationFieldWalker<'_>, ctx: &mut Cont

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

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

0 comments on commit 612a7f7

Please sign in to comment.