Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Referential actions in the Prisma Schema Language #1947

Merged
merged 57 commits into from Jun 22, 2021
Merged

Conversation

pimeys
Copy link
Contributor

@pimeys pimeys commented May 20, 2021

Supported actions: Cascade, Restrict, NoAction, SetNull and SetDefault.

Per-database validation, e.g. Restrict doesn't validate on SQL Server.

Defaults to:

  • onUpdate: Cascade on optional and Cascade on required relations.
  • onDelete: SetNull on optional and Restrict on required relations.

Required work

  • PSL
  • ME
  • IE
  • Language server should autocomplete only the allowed actions.
  • Query Engine should not emulate any of the actions if the database supports them.

Closes: prisma/prisma#2810
Closes: prisma/prisma#5782
Closes: prisma/prisma#4711

Supported actions: `Cascade`, `Restrict`, `NoAction`, `SetNull` and
`SetDefault`.

Per-database validation, e.g. `Restrict` doesn't validate on SQL Server.

Defaults to:

- `onUpdate`: `SetNull` on optional and `Cascade` on required relations.
- `onDelete`: `SetNull` on optional and `Restrict` on required relations.

Currently ALWAYS renders the actions on introspection, due to the
database always has some action set.
@pimeys pimeys added this to the 2.25.0 milestone Jun 2, 2021
@pimeys pimeys marked this pull request as ready for review June 2, 2021 16:13
Mark some places that require work.
@pimeys
Copy link
Contributor Author

pimeys commented Jun 21, 2021

Note: "Currently ALWAYS renders the actions on introspection, due to the database always has some action set." Should not be the case if the introspected action matches the default.

We haven't been doing this for some weeks already. Updated the original comment to reflect the reality.

Copy link
Contributor

@tomhoule tomhoule left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Leaving a first small batch of comments. Still lots I haven't read, it's going to take some time.

introspection-engine/introspection-engine-tests/src/lib.rs Outdated Show resolved Hide resolved
@@ -117,7 +117,7 @@ impl Datamodel {
let mut fields = vec![];
for model in self.models() {
for field in model.scalar_fields() {
if FieldType::Enum(enum_name.to_owned()) == field.field_type {
if field.field_type.is_enum(enum_name) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

libs/datamodel/connectors/dml/src/relation_info.rs Outdated Show resolved Hide resolved
}

/// Describes what happens when related nodes are deleted.
#[repr(u8)]
#[bitflags]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I find this weird — a given relation has a single referential action, so it should be a regular enum, right?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Or is that impl used to denote the set of available referential actions for a connector? I'll continue reading.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Your guess was right. We can set multiple of them in the connector.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm wondering if the extra dependency is pulling its weight, but it's fine for now.

libs/datamodel/connectors/dml/src/relation_info.rs Outdated Show resolved Hide resolved
libs/datamodel/connectors/datamodel-connector/src/lib.rs Outdated Show resolved Hide resolved
Copy link
Contributor

@tomhoule tomhoule left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A few more comments. I'll continue reading.

matches && same_on_delete_action && same_on_update_action
} else {
matches
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

libs/datamodel/core/src/lib.rs Outdated Show resolved Hide resolved
@@ -600,7 +597,7 @@
"relationName": "AToB",
"relationFromFields": [],
"relationToFields": [],
"relationOnDelete": "NONE",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm interesting, so we are not returning this anymore in case of None? Could it break something typescript-side?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Asked from the ts team.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ping @millsp @williamluke4 @Jolg42 will we break some of your code?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We'll need to remove it from our typings and update some snapshots. All good on TS side.

@steebchen will also need to remove it from Go Client.
and @madebysid from Studio

Also, I see some projects also have it defined and will need to remove it, like Amplication.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't use this atm so no problem for me

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't use it either, all good.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually, nothing to change in TS since the field is not removed but not always passed
https://github.com/prisma/prisma/blob/7ac84453f9e096fbe6652bc0a68e2a47e15ba344/src/packages/generator-helper/src/dmmf.ts#L84

Because it's an optional field typed to string.

}
}

return Ok(());
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💯

Copy link
Contributor

@tomhoule tomhoule left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One last batch of comments/questions, but I'm done reading. I think maybe @do4gr should look at the introspection tests if possible, but in general ✔️

@@ -193,7 +205,7 @@ pub enum ConnectorCapability {
/// Contains all capabilities that the connector is able to serve.
#[derive(Debug)]
pub struct ConnectorCapabilities {
capabilities: Vec<ConnectorCapability>,
pub capabilities: Vec<ConnectorCapability>,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this need to be public? Didn't check but I think there is an accessor.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

no it should not be public

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ah, @dpetrick needs it, so will leave it as-is

}

/// Describes what happens when related nodes are deleted.
#[repr(u8)]
#[bitflags]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm wondering if the extra dependency is pulling its weight, but it's fine for now.

.assert_referential_action_on_update(ForeignKeyAction::Cascade)
})
});
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

);

let message = format!(
"Invalid referential action: `{}`. Allowed values: (`Restrict`, `SetNull`)",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this to align with current QE behaviour? I don't really understand what the PlanetScale situation after this PR is going to be.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The planetscale should emulate the referential actions. If the mode is enabled. @dpetrick can decide which modes are enabled, but currently the emulation is WIP and not part of this PR.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment