From 0e1114b23b8994c276e4643ddf5314c0b104e1c3 Mon Sep 17 00:00:00 2001 From: Greg Richardson Date: Tue, 25 Apr 2023 20:21:06 -0600 Subject: [PATCH 01/12] docs(postgres): cascade deletes --- .../NavigationMenu.constants.ts | 4 + .../database/postgres/cascade-deletes.mdx | 279 ++++++++++++++++++ 2 files changed, 283 insertions(+) create mode 100644 apps/docs/pages/guides/database/postgres/cascade-deletes.mdx diff --git a/apps/docs/components/Navigation/NavigationMenu/NavigationMenu.constants.ts b/apps/docs/components/Navigation/NavigationMenu/NavigationMenu.constants.ts index a9a53500320..2abd878db71 100644 --- a/apps/docs/components/Navigation/NavigationMenu/NavigationMenu.constants.ts +++ b/apps/docs/components/Navigation/NavigationMenu/NavigationMenu.constants.ts @@ -471,6 +471,10 @@ export const database = { name: 'Managing Indexes', url: '/guides/database/postgres/indexes', }, + { + name: 'Cascade Deletes', + url: '/guides/database/postgres/cascade-deletes', + }, { name: 'Drop All Tables in Schema', url: '/guides/database/postgres/dropping-all-tables-in-schema', diff --git a/apps/docs/pages/guides/database/postgres/cascade-deletes.mdx b/apps/docs/pages/guides/database/postgres/cascade-deletes.mdx new file mode 100644 index 00000000000..7a5b02df884 --- /dev/null +++ b/apps/docs/pages/guides/database/postgres/cascade-deletes.mdx @@ -0,0 +1,279 @@ +import Layout from '~/layouts/DefaultGuideLayout' + +export const meta = { + title: 'Cascade deletes', + description: 'Understanding the types of foreign key deletes', + footerHelpType: 'postgres', +} + +There are 5 options for cascade deletes: + +1. **CASCADE:** When a row is deleted from the parent table, all related rows in the child table(s) are deleted as well. +2. **RESTRICT:** When a row is deleted from the parent table, the delete operation is aborted if there are any related rows in the child table(s). +3. **SET NULL:** When a row is deleted from the parent table, the values of the foreign key columns in the child table(s) are set to NULL. +4. **SET DEFAULT:** When a row is deleted from the parent table, the values of the foreign key columns in the child table(s) are set to their default values. +5. **NO ACTION:** This option is similar to RESTRICT, but it also has the option to be “deferred” to the end of a transaction. This means that other cascading deletes can run first, and then this delete constraint will only through an error if there is referenced data remaining _at the end of the transaction_. + +These options can be specified when defining a foreign key constraint using the "ON DELETE" clause. For example, the following SQL statement creates a foreign key constraint with the "CASCADE" option: + +```sql +alter table + child_table add constraint fk_parent foreign key (parent_id) references parent_table (id) on delete cascade; +``` + +This means that when a row is deleted from the "parent_table", all related rows in the "child_table" will be deleted as well. + +### `RESTRICT` vs `NO ACTION` + +The difference between NO ACTION and RESTRICT can be a bit confusing. + +Both NO ACTION and RESTRICT are used to prevent deletion of a row in a parent table if there are related rows in a child table. However, there is a subtle difference in how they behave. + +When a foreign key constraint is defined with the option NO ACTION, it means that if a row in the parent table is deleted, the database will not take any action on the related rows in the child table(s). The database will not delete, update or set to NULL any rows in the child table(s). Instead, it will raise an error and prevent the deletion of the row in the parent table. + +On the other hand, when a foreign key constraint is defined with the option RESTRICT, it means that if a row in the parent table is deleted, the database will also prevent the deletion of the row in the parent table, but it will not raise an error. Instead, the database will simply reject the delete operation and keep all the related rows in the child table(s) intact. + +So the main difference between NO ACTION and RESTRICT is that NO ACTION will raise an error and prevent the deletion of the row in the parent table, while RESTRICT will simply reject the deletion of the row in the parent table without raising an error. + +In practice, you can use either NO ACTION or RESTRICT depending on your preference. However, some developers prefer to use NO ACTION to make it explicit that the deletion is not allowed, while others prefer RESTRICT to avoid raising errors unnecessarily. + +# Examples + +Here's an example to illustrate the difference, using the following data: + +`grandparent` + +| id | name | +| --- | --------- | +| 1 | Elizabeth | + +`parent` + +| id | name | parent_id | +| --- | ------- | --------- | +| 1 | Charles | 1 | +| 2 | Diana | 1 | + +`child` + +| id | name | father | mother | +| --- | ------- | ------ | ------ | +| 1 | William | 1 | 2 | + +## `RESTRICT` + +No action will prevent a delete and raise an error: + +```sql +create table + grandparent (id serial primary key, name text); + +create table + parent ( + id serial primary key, + name text, + parent_id integer references grandparent (id) on delete cascade + ); + +create table + child ( + id serial primary key, + name text, + father integer references parent (id) on delete restrict + ); + +insert into + grandparent (id, name) +values + (1, 'Elizabeth'); + +insert into + parent (id, name, parent_id) +values + (1, 'Charles', 1); + +insert into + parent (id, name, parent_id) +values + (2, 'Diana', 1); + +insert into + child (id, name, father) +values + (1, 'William', 1); +``` + +run a delete + +```markdown +postgres=# delete from grandparent; +ERROR: update or delete on table "parent" violates foreign key constraint "child_father_fkey" on table "child" +DETAIL: Key (id)=(1) is still referenced from table "child". +``` + +## `NO ACTION` + +No action will prevent a delete and raise an error: + +```sql +create table + grandparent (id serial primary key, name text); + +create table + parent ( + id serial primary key, + name text, + parent_id integer references grandparent (id) on delete cascade + ); + +create table + child ( + id serial primary key, + name text, + father integer references parent (id) on delete no action + ); + +insert into + grandparent (id, name) +values + (1, 'Elizabeth'); + +insert into + parent (id, name, parent_id) +values + (1, 'Charles', 1); + +insert into + parent (id, name, parent_id) +values + (2, 'Diana', 1); + +insert into + child (id, name, father) +values + (1, 'William', 1); +``` + +run a delete, also gets an error: + +```markdown +postgres=# delete from grandparent; +ERROR: update or delete on table "parent" violates foreign key constraint "child_father_fkey" on table "child" +DETAIL: Key (id)=(1) is still referenced from table "child". +``` + +## `NO ACTION INITIALLY DEFERRED` + +Here you will see that `initially deffered` seems to operate like `NO ACTION` or `RESTRICT` + +```sql +create table + grandparent (id serial primary key, name text); + +create table + parent ( + id serial primary key, + name text, + parent_id integer references grandparent (id) on delete cascade + ); + +create table + child ( + id serial primary key, + name text, + father integer references parent (id) on delete no action initially deferred + ); + +insert into + grandparent (id, name) +values + (1, 'Elizabeth'); + +insert into + parent (id, name, parent_id) +values + (1, 'Charles', 1); + +insert into + parent (id, name, parent_id) +values + (2, 'Diana', 1); + +insert into + child (id, name, father) +values + (1, 'William', 1); +``` + +run a delete, it seems to make no difference: + +```markdown +postgres=# delete from grandparent; +ERROR: update or delete on table "parent" violates foreign key constraint "child_father_fkey" on table "child" +DETAIL: Key (id)=(1) is still referenced from table "child". +``` + +But, when we combine it with _other_ constraints, then any other constraints take precedence. For example, let’s run the same but add a `mother` column that has a cascade delete: + +```sql +create table + grandparent (id serial primary key, name text); + +create table + parent ( + id serial primary key, + name text, + parent_id integer references grandparent (id) on delete cascade + ); + +create table + child ( + id serial primary key, + name text, + father integer references parent (id) on delete no action initially deferred, + mother integer references parent (id) on delete cascade + ); + +insert into + grandparent (id, name) +values + (1, 'Elizabeth'); + +insert into + parent (id, name, parent_id) +values + (1, 'Charles', 1); + +insert into + parent (id, name, parent_id) +values + (2, 'Diana', 1); + +insert into + child (id, name, father, mother) +values + (1, 'William', 1, 2); +``` + +Then let’s run a delete on the `grandparent` table: + +```sql +postgres=# delete from grandparent; +DELETE 1 + +postgres=# select * from parent; + id | name | parent_id +----+------+----------- +(0 rows) + +postgres=# select * from child; + id | name | father | mother +----+------+--------+-------- +(0 rows) +``` + +The `mother` deletion took precedence over the `father`, and so William was deleted. After William was deleted, there was no reference to “Charles” and so he was free to be deleted, even though previously he wasn’t (without `initially deferred`). + +export const Page = ({ children }) => + +export default Page From 388f3b5de44c419d7f7d9c4734efa51e186f52ab Mon Sep 17 00:00:00 2001 From: Greg Richardson Date: Tue, 25 Apr 2023 20:32:29 -0600 Subject: [PATCH 02/12] docs(postgres): adds missing resource link & updates broken links --- .../guides/database/postgres/cascade-deletes.mdx | 2 +- apps/docs/pages/guides/resources.mdx | 14 ++++++++++---- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/apps/docs/pages/guides/database/postgres/cascade-deletes.mdx b/apps/docs/pages/guides/database/postgres/cascade-deletes.mdx index 7a5b02df884..237ce297a1f 100644 --- a/apps/docs/pages/guides/database/postgres/cascade-deletes.mdx +++ b/apps/docs/pages/guides/database/postgres/cascade-deletes.mdx @@ -2,7 +2,7 @@ import Layout from '~/layouts/DefaultGuideLayout' export const meta = { title: 'Cascade deletes', - description: 'Understanding the types of foreign key deletes', + description: 'Understand the types of foreign key deletes', footerHelpType: 'postgres', } diff --git a/apps/docs/pages/guides/resources.mdx b/apps/docs/pages/guides/resources.mdx index 5bda171db2f..85fc25d8764 100644 --- a/apps/docs/pages/guides/resources.mdx +++ b/apps/docs/pages/guides/resources.mdx @@ -153,25 +153,31 @@ export const postgres = [ { title: 'Managing Indexes', hasLightIcon: true, - href: '/guides/resources/postgres/indexes', + href: '/guides/database/postgres/indexes', description: 'Improve query performance using various index types in Postgres.', }, + { + title: 'Cascade Deletes', + hasLightIcon: true, + href: '/guides/database/postgres/cascade-deletes', + description: 'Understand the types of foreign key deletes.', + }, { title: 'Drop all tables in schema', hasLightIcon: true, - href: '/guides/resources/postgres/dropping-all-tables-in-schema', + href: '/guides/database/postgres/dropping-all-tables-in-schema', description: 'Delete all tables in a given schema.', }, { title: 'Select first row per group', hasLightIcon: true, - href: '/guides/resources/postgres/first-row-in-group', + href: '/guides/database/postgres/first-row-in-group', description: 'Retrieve the first row in each distinct group.', }, { title: 'Print PostgreSQL version', hasLightIcon: true, - href: '/guides/resources/postgres/which-version-of-postgres', + href: '/guides/database/postgres/which-version-of-postgres', description: 'Find out which version of Postgres you are running.', }, ] From 5e8c72a3553111b1b2fb171f62610ea699585db1 Mon Sep 17 00:00:00 2001 From: Greg Richardson Date: Tue, 25 Apr 2023 20:34:46 -0600 Subject: [PATCH 03/12] docs(postgres): fix heading --- apps/docs/pages/guides/database/postgres/cascade-deletes.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/docs/pages/guides/database/postgres/cascade-deletes.mdx b/apps/docs/pages/guides/database/postgres/cascade-deletes.mdx index 237ce297a1f..eeefd7ca4bb 100644 --- a/apps/docs/pages/guides/database/postgres/cascade-deletes.mdx +++ b/apps/docs/pages/guides/database/postgres/cascade-deletes.mdx @@ -23,7 +23,7 @@ alter table This means that when a row is deleted from the "parent_table", all related rows in the "child_table" will be deleted as well. -### `RESTRICT` vs `NO ACTION` +## `RESTRICT` vs `NO ACTION` The difference between NO ACTION and RESTRICT can be a bit confusing. From 7d20489a1adc8ebb1eb2414e128f36d28b0ac230 Mon Sep 17 00:00:00 2001 From: Greg Richardson Date: Tue, 25 Apr 2023 20:55:46 -0600 Subject: [PATCH 04/12] docs(postgres): add link to cascade delete docs from dashboard --- .../ForeignKeySelector/ForeignKeySelector.tsx | 25 +++++++++++++++---- 1 file changed, 20 insertions(+), 5 deletions(-) diff --git a/studio/components/interfaces/TableGridEditor/SidePanelEditor/ForeignKeySelector/ForeignKeySelector.tsx b/studio/components/interfaces/TableGridEditor/SidePanelEditor/ForeignKeySelector/ForeignKeySelector.tsx index f1c1a6b6965..d40c56df3ee 100644 --- a/studio/components/interfaces/TableGridEditor/SidePanelEditor/ForeignKeySelector/ForeignKeySelector.tsx +++ b/studio/components/interfaces/TableGridEditor/SidePanelEditor/ForeignKeySelector/ForeignKeySelector.tsx @@ -317,11 +317,26 @@ const ForeignKeySelector: FC = ({ column, visible = false, closePanel, sa id="deletionAction" value={selectedForeignKey.deletionAction} label="Action if referenced row is removed" - // @ts-ignore - descriptionText={generateDeletionActionDescription( - selectedForeignKey.deletionAction, - `${selectedForeignKey.schema}.${selectedForeignKey.table}` - )} + descriptionText={ + <> +

+ {generateDeletionActionDescription( + selectedForeignKey.deletionAction, + `${selectedForeignKey.schema}.${selectedForeignKey.table}` + )} +

+

+ + Learn more about cascade deletes + +

+ + } error={errors.column} onChange={(value: string) => updateDeletionAction(value)} > From 9a6008a8706b7066bcc95a70320e12d9800ca1f0 Mon Sep 17 00:00:00 2001 From: Greg Richardson Date: Thu, 27 Apr 2023 13:22:55 -0600 Subject: [PATCH 05/12] docs(postgres): fix explanation and examples around restrict vs no action --- .../database/postgres/cascade-deletes.mdx | 177 +++++------------- 1 file changed, 48 insertions(+), 129 deletions(-) diff --git a/apps/docs/pages/guides/database/postgres/cascade-deletes.mdx b/apps/docs/pages/guides/database/postgres/cascade-deletes.mdx index eeefd7ca4bb..ab4b210ce16 100644 --- a/apps/docs/pages/guides/database/postgres/cascade-deletes.mdx +++ b/apps/docs/pages/guides/database/postgres/cascade-deletes.mdx @@ -12,9 +12,9 @@ There are 5 options for cascade deletes: 2. **RESTRICT:** When a row is deleted from the parent table, the delete operation is aborted if there are any related rows in the child table(s). 3. **SET NULL:** When a row is deleted from the parent table, the values of the foreign key columns in the child table(s) are set to NULL. 4. **SET DEFAULT:** When a row is deleted from the parent table, the values of the foreign key columns in the child table(s) are set to their default values. -5. **NO ACTION:** This option is similar to RESTRICT, but it also has the option to be “deferred” to the end of a transaction. This means that other cascading deletes can run first, and then this delete constraint will only through an error if there is referenced data remaining _at the end of the transaction_. +5. **NO ACTION:** This option is similar to RESTRICT, but it also has the option to be “deferred” to the end of a transaction. This means that other cascading deletes can run first, and then this delete constraint will only throw an error if there is referenced data remaining _at the end of the transaction_. -These options can be specified when defining a foreign key constraint using the "ON DELETE" clause. For example, the following SQL statement creates a foreign key constraint with the "CASCADE" option: +These options can be specified when defining a foreign key constraint using the "ON DELETE" clause. For example, the following SQL statement creates a foreign key constraint with the `CASCADE` option: ```sql alter table @@ -25,21 +25,21 @@ This means that when a row is deleted from the "parent_table", all related rows ## `RESTRICT` vs `NO ACTION` -The difference between NO ACTION and RESTRICT can be a bit confusing. +The difference between `NO ACTION` and `RESTRICT` is subtle and can be a bit confusing. -Both NO ACTION and RESTRICT are used to prevent deletion of a row in a parent table if there are related rows in a child table. However, there is a subtle difference in how they behave. +Both `NO ACTION` and `RESTRICT` are used to prevent deletion of a row in a parent table if there are related rows in a child table. However, there is a subtle difference in how they behave. -When a foreign key constraint is defined with the option NO ACTION, it means that if a row in the parent table is deleted, the database will not take any action on the related rows in the child table(s). The database will not delete, update or set to NULL any rows in the child table(s). Instead, it will raise an error and prevent the deletion of the row in the parent table. +When a foreign key constraint is defined with the option `RESTRICT`, it means that if a row in the parent table is deleted, the database will immediately raise an error and prevent the deletion of the row in the parent table. The database will not delete, update or set to NULL any rows in the referenced table(s). -On the other hand, when a foreign key constraint is defined with the option RESTRICT, it means that if a row in the parent table is deleted, the database will also prevent the deletion of the row in the parent table, but it will not raise an error. Instead, the database will simply reject the delete operation and keep all the related rows in the child table(s) intact. +When a foreign key constraint is defined with the option `NO ACTION`, it means that if a row in the parent table is deleted, the database will also raise an error and prevent the deletion of the row in the parent table. However unlike `RESTRICT`, `NO ACTION` has the option defer the check using `INITIALLY DEFERRED`. This will only raise the above error _if_ the referenced rows still exist at the end of the transaction. -So the main difference between NO ACTION and RESTRICT is that NO ACTION will raise an error and prevent the deletion of the row in the parent table, while RESTRICT will simply reject the deletion of the row in the parent table without raising an error. +The difference from `RESTRICT` is that a constraint marked as `NO ACTION INITIALLY DEFERRED` is deferred until the end of the transaction, rather than running immediately. If, for example there is another foreign key constraint between the same tables marked as `CASCADE`, the cascade will occur first and delete the referenced rows, and no error will be thrown by the deferred constraint. Otherwise if there are still rows referencing the parent row by the end of the transaction, an error will be raised just like before. Just like `RESTRICT`, the database will not delete, update or set to NULL any rows in the referenced table(s). -In practice, you can use either NO ACTION or RESTRICT depending on your preference. However, some developers prefer to use NO ACTION to make it explicit that the deletion is not allowed, while others prefer RESTRICT to avoid raising errors unnecessarily. +In practice, you can use either `NO ACTION` or `RESTRICT` depending on your needs. `NO ACTION` is the default behaviour if you do not specify anything. If you prefer to defer the check until the end of the transaction, use `NO ACTION INITIALLY DEFERRED`. -# Examples +## Example -Here's an example to illustrate the difference, using the following data: +Let's further illustrate the difference with an example. We'll use the following data: `grandparent` @@ -60,9 +60,7 @@ Here's an example to illustrate the difference, using the following data: | --- | ------- | ------ | ------ | | 1 | William | 1 | 2 | -## `RESTRICT` - -No action will prevent a delete and raise an error: +To create these tables and their data, we run: ```sql create table @@ -97,13 +95,16 @@ insert into values (2, 'Diana', 1); +-- We'll just link the father for now insert into child (id, name, father) values (1, 'William', 1); ``` -run a delete +### `RESTRICT` + +`RESTRICT` will prevent a delete and raise an error: ```markdown postgres=# delete from grandparent; @@ -111,50 +112,23 @@ ERROR: update or delete on table "parent" violates foreign key constraint "child DETAIL: Key (id)=(1) is still referenced from table "child". ``` -## `NO ACTION` +Even though the foreign key constraint between parent and grandparent is `CASCADE`, the constraint between child and father is `RESTRICT`. Therefore an error is raised and no records are deleted. -No action will prevent a delete and raise an error: +### `NO ACTION` + +Let's change the child-father relationship to `NO ACTION`: ```sql -create table - grandparent (id serial primary key, name text); +alter table + child +drop + constraint child_father_fkey; -create table - parent ( - id serial primary key, - name text, - parent_id integer references grandparent (id) on delete cascade - ); - -create table - child ( - id serial primary key, - name text, - father integer references parent (id) on delete no action - ); - -insert into - grandparent (id, name) -values - (1, 'Elizabeth'); - -insert into - parent (id, name, parent_id) -values - (1, 'Charles', 1); - -insert into - parent (id, name, parent_id) -values - (2, 'Diana', 1); - -insert into - child (id, name, father) -values - (1, 'William', 1); +alter table + child add constraint child_father_fkey foreign key (father) references parent (id) on delete no action; ``` -run a delete, also gets an error: +We see that `NO ACTION` will also prevent a delete and raise an error: ```markdown postgres=# delete from grandparent; @@ -162,50 +136,21 @@ ERROR: update or delete on table "parent" violates foreign key constraint "child DETAIL: Key (id)=(1) is still referenced from table "child". ``` -## `NO ACTION INITIALLY DEFERRED` +### `NO ACTION INITIALLY DEFERRED` -Here you will see that `initially deffered` seems to operate like `NO ACTION` or `RESTRICT` +We'll change the foreign key constraint between child and father to be `NO ACTION INITIALLY DEFERRED`: ```sql -create table - grandparent (id serial primary key, name text); +alter table + child +drop + constraint child_father_fkey; -create table - parent ( - id serial primary key, - name text, - parent_id integer references grandparent (id) on delete cascade - ); - -create table - child ( - id serial primary key, - name text, - father integer references parent (id) on delete no action initially deferred - ); - -insert into - grandparent (id, name) -values - (1, 'Elizabeth'); - -insert into - parent (id, name, parent_id) -values - (1, 'Charles', 1); - -insert into - parent (id, name, parent_id) -values - (2, 'Diana', 1); - -insert into - child (id, name, father) -values - (1, 'William', 1); +alter table + child add constraint child_father_fkey foreign key (father) references parent (id) on delete no action initially deferred; ``` -run a delete, it seems to make no difference: +Here you will see that `INITIALLY DEFFERED` seems to operate like `NO ACTION` or `RESTRICT`. When we run a delete, it seems to make no difference: ```markdown postgres=# delete from grandparent; @@ -213,49 +158,23 @@ ERROR: update or delete on table "parent" violates foreign key constraint "child DETAIL: Key (id)=(1) is still referenced from table "child". ``` -But, when we combine it with _other_ constraints, then any other constraints take precedence. For example, let’s run the same but add a `mother` column that has a cascade delete: +But, when we combine it with _other_ constraints, then any other constraints take precedence. For example, let's run the same but add a `mother` column that has a `CASCADE` delete: ```sql -create table - grandparent (id serial primary key, name text); +alter table + child +add column + mother integer references parent (id) on delete cascade; -create table - parent ( - id serial primary key, - name text, - parent_id integer references grandparent (id) on delete cascade - ); - -create table - child ( - id serial primary key, - name text, - father integer references parent (id) on delete no action initially deferred, - mother integer references parent (id) on delete cascade - ); - -insert into - grandparent (id, name) -values - (1, 'Elizabeth'); - -insert into - parent (id, name, parent_id) -values - (1, 'Charles', 1); - -insert into - parent (id, name, parent_id) -values - (2, 'Diana', 1); - -insert into - child (id, name, father, mother) -values - (1, 'William', 1, 2); +update + child +set + mother = 2 +where + id = 1; ``` -Then let’s run a delete on the `grandparent` table: +Then let's run a delete on the `grandparent` table: ```sql postgres=# delete from grandparent; @@ -272,7 +191,7 @@ postgres=# select * from child; (0 rows) ``` -The `mother` deletion took precedence over the `father`, and so William was deleted. After William was deleted, there was no reference to “Charles” and so he was free to be deleted, even though previously he wasn’t (without `initially deferred`). +The `mother` deletion took precedence over the `father`, and so William was deleted. After William was deleted, there was no reference to “Charles” and so he was free to be deleted, even though previously he wasn't (without `INITIALLY DEFERRED`). export const Page = ({ children }) => From 9ab80c5a9d7e80c15bae32518b97a0441d4a40af Mon Sep 17 00:00:00 2001 From: Greg Richardson Date: Thu, 27 Apr 2023 13:35:02 -0600 Subject: [PATCH 06/12] docs(postgres): spelling of 'behavior' --- apps/docs/pages/guides/database/postgres/cascade-deletes.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/docs/pages/guides/database/postgres/cascade-deletes.mdx b/apps/docs/pages/guides/database/postgres/cascade-deletes.mdx index ab4b210ce16..7f9ebe22ba8 100644 --- a/apps/docs/pages/guides/database/postgres/cascade-deletes.mdx +++ b/apps/docs/pages/guides/database/postgres/cascade-deletes.mdx @@ -35,7 +35,7 @@ When a foreign key constraint is defined with the option `NO ACTION`, it means t The difference from `RESTRICT` is that a constraint marked as `NO ACTION INITIALLY DEFERRED` is deferred until the end of the transaction, rather than running immediately. If, for example there is another foreign key constraint between the same tables marked as `CASCADE`, the cascade will occur first and delete the referenced rows, and no error will be thrown by the deferred constraint. Otherwise if there are still rows referencing the parent row by the end of the transaction, an error will be raised just like before. Just like `RESTRICT`, the database will not delete, update or set to NULL any rows in the referenced table(s). -In practice, you can use either `NO ACTION` or `RESTRICT` depending on your needs. `NO ACTION` is the default behaviour if you do not specify anything. If you prefer to defer the check until the end of the transaction, use `NO ACTION INITIALLY DEFERRED`. +In practice, you can use either `NO ACTION` or `RESTRICT` depending on your needs. `NO ACTION` is the default behavior if you do not specify anything. If you prefer to defer the check until the end of the transaction, use `NO ACTION INITIALLY DEFERRED`. ## Example From 06e936517b82c77ae227aa199a186d473f6afbd0 Mon Sep 17 00:00:00 2001 From: Greg Richardson Date: Thu, 27 Apr 2023 14:06:29 -0600 Subject: [PATCH 07/12] docs(postgres): rename 'cascade deletes' to 'on delete constraint behavior' --- .../Navigation/NavigationMenu/NavigationMenu.constants.ts | 4 ++-- ...ascade-deletes.mdx => on-delete-constraint-behavior.mdx} | 6 +++--- apps/docs/pages/guides/resources.mdx | 4 ++-- .../ForeignKeySelector/ForeignKeySelector.tsx | 4 ++-- 4 files changed, 9 insertions(+), 9 deletions(-) rename apps/docs/pages/guides/database/postgres/{cascade-deletes.mdx => on-delete-constraint-behavior.mdx} (97%) diff --git a/apps/docs/components/Navigation/NavigationMenu/NavigationMenu.constants.ts b/apps/docs/components/Navigation/NavigationMenu/NavigationMenu.constants.ts index 2abd878db71..29d62973ed5 100644 --- a/apps/docs/components/Navigation/NavigationMenu/NavigationMenu.constants.ts +++ b/apps/docs/components/Navigation/NavigationMenu/NavigationMenu.constants.ts @@ -472,8 +472,8 @@ export const database = { url: '/guides/database/postgres/indexes', }, { - name: 'Cascade Deletes', - url: '/guides/database/postgres/cascade-deletes', + name: 'On Delete Constraint Behavior', + url: '/guides/database/postgres/on-delete-constraint-behavior', }, { name: 'Drop All Tables in Schema', diff --git a/apps/docs/pages/guides/database/postgres/cascade-deletes.mdx b/apps/docs/pages/guides/database/postgres/on-delete-constraint-behavior.mdx similarity index 97% rename from apps/docs/pages/guides/database/postgres/cascade-deletes.mdx rename to apps/docs/pages/guides/database/postgres/on-delete-constraint-behavior.mdx index 7f9ebe22ba8..fefb563ad8b 100644 --- a/apps/docs/pages/guides/database/postgres/cascade-deletes.mdx +++ b/apps/docs/pages/guides/database/postgres/on-delete-constraint-behavior.mdx @@ -1,12 +1,12 @@ import Layout from '~/layouts/DefaultGuideLayout' export const meta = { - title: 'Cascade deletes', - description: 'Understand the types of foreign key deletes', + title: 'On Delete Constraint Behaviour', + description: 'Understand the types of foreign key constraint deletes', footerHelpType: 'postgres', } -There are 5 options for cascade deletes: +There are 5 options for foreign key constraint deletes: 1. **CASCADE:** When a row is deleted from the parent table, all related rows in the child table(s) are deleted as well. 2. **RESTRICT:** When a row is deleted from the parent table, the delete operation is aborted if there are any related rows in the child table(s). diff --git a/apps/docs/pages/guides/resources.mdx b/apps/docs/pages/guides/resources.mdx index 85fc25d8764..3e297988711 100644 --- a/apps/docs/pages/guides/resources.mdx +++ b/apps/docs/pages/guides/resources.mdx @@ -159,8 +159,8 @@ export const postgres = [ { title: 'Cascade Deletes', hasLightIcon: true, - href: '/guides/database/postgres/cascade-deletes', - description: 'Understand the types of foreign key deletes.', + href: '/guides/database/postgres/on-delete-constraint-behavior', + description: 'Understand the types of foreign key constraint deletes.', }, { title: 'Drop all tables in schema', diff --git a/studio/components/interfaces/TableGridEditor/SidePanelEditor/ForeignKeySelector/ForeignKeySelector.tsx b/studio/components/interfaces/TableGridEditor/SidePanelEditor/ForeignKeySelector/ForeignKeySelector.tsx index d40c56df3ee..372722265df 100644 --- a/studio/components/interfaces/TableGridEditor/SidePanelEditor/ForeignKeySelector/ForeignKeySelector.tsx +++ b/studio/components/interfaces/TableGridEditor/SidePanelEditor/ForeignKeySelector/ForeignKeySelector.tsx @@ -327,12 +327,12 @@ const ForeignKeySelector: FC = ({ column, visible = false, closePanel, sa

- Learn more about cascade deletes + Learn more about ON DELETE

From de211befae4894a567420f147abd308a1e0bff32 Mon Sep 17 00:00:00 2001 From: Greg Richardson Date: Thu, 27 Apr 2023 14:13:00 -0600 Subject: [PATCH 08/12] chore(postgres): studio link to on delete constraint docs --- .../SidePanelEditor/ForeignKeySelector/ForeignKeySelector.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/studio/components/interfaces/TableGridEditor/SidePanelEditor/ForeignKeySelector/ForeignKeySelector.tsx b/studio/components/interfaces/TableGridEditor/SidePanelEditor/ForeignKeySelector/ForeignKeySelector.tsx index 372722265df..3d83525fb89 100644 --- a/studio/components/interfaces/TableGridEditor/SidePanelEditor/ForeignKeySelector/ForeignKeySelector.tsx +++ b/studio/components/interfaces/TableGridEditor/SidePanelEditor/ForeignKeySelector/ForeignKeySelector.tsx @@ -332,7 +332,7 @@ const ForeignKeySelector: FC = ({ column, visible = false, closePanel, sa rel="noreferrer" className="text-brand-900 opacity-75" > - Learn more about ON DELETE + Learn more about ON DELETE actions

From 0f7063ee80e4efab34dc48676aa7363a5087e27a Mon Sep 17 00:00:00 2001 From: Greg Richardson Date: Thu, 27 Apr 2023 14:20:44 -0600 Subject: [PATCH 09/12] docs(postgres): rename other 'cascade deletes' to 'on delete constraint behavior' --- .../guides/database/postgres/on-delete-constraint-behavior.mdx | 2 +- apps/docs/pages/guides/resources.mdx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/docs/pages/guides/database/postgres/on-delete-constraint-behavior.mdx b/apps/docs/pages/guides/database/postgres/on-delete-constraint-behavior.mdx index fefb563ad8b..9476a200c18 100644 --- a/apps/docs/pages/guides/database/postgres/on-delete-constraint-behavior.mdx +++ b/apps/docs/pages/guides/database/postgres/on-delete-constraint-behavior.mdx @@ -1,7 +1,7 @@ import Layout from '~/layouts/DefaultGuideLayout' export const meta = { - title: 'On Delete Constraint Behaviour', + title: 'On Delete Constraint Behavior', description: 'Understand the types of foreign key constraint deletes', footerHelpType: 'postgres', } diff --git a/apps/docs/pages/guides/resources.mdx b/apps/docs/pages/guides/resources.mdx index 3e297988711..0d8b5601ccb 100644 --- a/apps/docs/pages/guides/resources.mdx +++ b/apps/docs/pages/guides/resources.mdx @@ -157,7 +157,7 @@ export const postgres = [ description: 'Improve query performance using various index types in Postgres.', }, { - title: 'Cascade Deletes', + title: 'On Delete Constraint Behavior', hasLightIcon: true, href: '/guides/database/postgres/on-delete-constraint-behavior', description: 'Understand the types of foreign key constraint deletes.', From c17fe90603ca2581fc5b91a6aac9fd576ce1f7de Mon Sep 17 00:00:00 2001 From: Greg Richardson Date: Fri, 28 Apr 2023 10:10:07 -0600 Subject: [PATCH 10/12] docs(postgres): reverts title back to cascade deletes --- .../Navigation/NavigationMenu/NavigationMenu.constants.ts | 4 ++-- ...{on-delete-constraint-behavior.mdx => cascade-deletes.mdx} | 2 +- apps/docs/pages/guides/resources.mdx | 4 ++-- .../SidePanelEditor/ForeignKeySelector/ForeignKeySelector.tsx | 4 ++-- 4 files changed, 7 insertions(+), 7 deletions(-) rename apps/docs/pages/guides/database/postgres/{on-delete-constraint-behavior.mdx => cascade-deletes.mdx} (99%) diff --git a/apps/docs/components/Navigation/NavigationMenu/NavigationMenu.constants.ts b/apps/docs/components/Navigation/NavigationMenu/NavigationMenu.constants.ts index 29d62973ed5..2abd878db71 100644 --- a/apps/docs/components/Navigation/NavigationMenu/NavigationMenu.constants.ts +++ b/apps/docs/components/Navigation/NavigationMenu/NavigationMenu.constants.ts @@ -472,8 +472,8 @@ export const database = { url: '/guides/database/postgres/indexes', }, { - name: 'On Delete Constraint Behavior', - url: '/guides/database/postgres/on-delete-constraint-behavior', + name: 'Cascade Deletes', + url: '/guides/database/postgres/cascade-deletes', }, { name: 'Drop All Tables in Schema', diff --git a/apps/docs/pages/guides/database/postgres/on-delete-constraint-behavior.mdx b/apps/docs/pages/guides/database/postgres/cascade-deletes.mdx similarity index 99% rename from apps/docs/pages/guides/database/postgres/on-delete-constraint-behavior.mdx rename to apps/docs/pages/guides/database/postgres/cascade-deletes.mdx index 9476a200c18..38215fce03e 100644 --- a/apps/docs/pages/guides/database/postgres/on-delete-constraint-behavior.mdx +++ b/apps/docs/pages/guides/database/postgres/cascade-deletes.mdx @@ -1,7 +1,7 @@ import Layout from '~/layouts/DefaultGuideLayout' export const meta = { - title: 'On Delete Constraint Behavior', + title: 'Cascade Deletes', description: 'Understand the types of foreign key constraint deletes', footerHelpType: 'postgres', } diff --git a/apps/docs/pages/guides/resources.mdx b/apps/docs/pages/guides/resources.mdx index 0d8b5601ccb..3e023445640 100644 --- a/apps/docs/pages/guides/resources.mdx +++ b/apps/docs/pages/guides/resources.mdx @@ -157,9 +157,9 @@ export const postgres = [ description: 'Improve query performance using various index types in Postgres.', }, { - title: 'On Delete Constraint Behavior', + title: 'Cascade Deletes', hasLightIcon: true, - href: '/guides/database/postgres/on-delete-constraint-behavior', + href: '/guides/database/postgres/cascade-deletes', description: 'Understand the types of foreign key constraint deletes.', }, { diff --git a/studio/components/interfaces/TableGridEditor/SidePanelEditor/ForeignKeySelector/ForeignKeySelector.tsx b/studio/components/interfaces/TableGridEditor/SidePanelEditor/ForeignKeySelector/ForeignKeySelector.tsx index 3d83525fb89..d40c56df3ee 100644 --- a/studio/components/interfaces/TableGridEditor/SidePanelEditor/ForeignKeySelector/ForeignKeySelector.tsx +++ b/studio/components/interfaces/TableGridEditor/SidePanelEditor/ForeignKeySelector/ForeignKeySelector.tsx @@ -327,12 +327,12 @@ const ForeignKeySelector: FC = ({ column, visible = false, closePanel, sa

- Learn more about ON DELETE actions + Learn more about cascade deletes

From 24a9c7ba027554432f4ac7276a95449d939ef6f5 Mon Sep 17 00:00:00 2001 From: Greg Richardson Date: Fri, 28 Apr 2023 11:22:56 -0600 Subject: [PATCH 11/12] fix(prettier): sql formatting --- .prettierrc | 4 +- .../database/postgres/cascade-deletes.mdx | 97 +++++++++---------- 2 files changed, 50 insertions(+), 51 deletions(-) diff --git a/.prettierrc b/.prettierrc index b9bda117c38..c60d3ab91ef 100644 --- a/.prettierrc +++ b/.prettierrc @@ -5,5 +5,7 @@ "singleQuote": true, "printWidth": 100, "endOfLine": "lf", - "sqlKeywordCase": "lower" + "sqlKeywordCase": "lower", + "pluginSearchDirs": false, + "plugins": ["prettier-plugin-sql-cst"] } diff --git a/apps/docs/pages/guides/database/postgres/cascade-deletes.mdx b/apps/docs/pages/guides/database/postgres/cascade-deletes.mdx index 38215fce03e..8093a2083f1 100644 --- a/apps/docs/pages/guides/database/postgres/cascade-deletes.mdx +++ b/apps/docs/pages/guides/database/postgres/cascade-deletes.mdx @@ -17,8 +17,9 @@ There are 5 options for foreign key constraint deletes: These options can be specified when defining a foreign key constraint using the "ON DELETE" clause. For example, the following SQL statement creates a foreign key constraint with the `CASCADE` option: ```sql -alter table - child_table add constraint fk_parent foreign key (parent_id) references parent_table (id) on delete cascade; +alter table child_table +add constraint fk_parent foreign key (parent_id) references parent_table (id) + on delete cascade; ``` This means that when a row is deleted from the "parent_table", all related rows in the "child_table" will be deleted as well. @@ -63,41 +64,43 @@ Let's further illustrate the difference with an example. We'll use the following To create these tables and their data, we run: ```sql -create table - grandparent (id serial primary key, name text); +create table grandparent ( + id serial primary key, + name text +); -create table - parent ( - id serial primary key, - name text, - parent_id integer references grandparent (id) on delete cascade - ); +create table parent ( + id serial primary key, + name text, + parent_id integer references grandparent (id) + on delete cascade +); -create table - child ( - id serial primary key, - name text, - father integer references parent (id) on delete restrict - ); +create table child ( + id serial primary key, + name text, + father integer references parent (id) + on delete restrict +); -insert into - grandparent (id, name) +insert into grandparent + (id, name) values (1, 'Elizabeth'); -insert into - parent (id, name, parent_id) +insert into parent + (id, name, parent_id) values (1, 'Charles', 1); -insert into - parent (id, name, parent_id) +insert into parent + (id, name, parent_id) values (2, 'Diana', 1); -- We'll just link the father for now -insert into - child (id, name, father) +insert into child + (id, name, father) values (1, 'William', 1); ``` @@ -106,7 +109,7 @@ values `RESTRICT` will prevent a delete and raise an error: -```markdown +```shell postgres=# delete from grandparent; ERROR: update or delete on table "parent" violates foreign key constraint "child_father_fkey" on table "child" DETAIL: Key (id)=(1) is still referenced from table "child". @@ -119,18 +122,17 @@ Even though the foreign key constraint between parent and grandparent is `CASCAD Let's change the child-father relationship to `NO ACTION`: ```sql -alter table - child -drop - constraint child_father_fkey; +alter table child +drop constraint child_father_fkey; -alter table - child add constraint child_father_fkey foreign key (father) references parent (id) on delete no action; +alter table child +add constraint child_father_fkey foreign key (father) references parent (id) + on delete no action; ``` We see that `NO ACTION` will also prevent a delete and raise an error: -```markdown +```shell postgres=# delete from grandparent; ERROR: update or delete on table "parent" violates foreign key constraint "child_father_fkey" on table "child" DETAIL: Key (id)=(1) is still referenced from table "child". @@ -141,18 +143,17 @@ DETAIL: Key (id)=(1) is still referenced from table "child". We'll change the foreign key constraint between child and father to be `NO ACTION INITIALLY DEFERRED`: ```sql -alter table - child -drop - constraint child_father_fkey; +alter table child +drop constraint child_father_fkey; -alter table - child add constraint child_father_fkey foreign key (father) references parent (id) on delete no action initially deferred; +alter table child +add constraint child_father_fkey foreign key (father) references parent (id) + on delete no action initially deferred; ``` Here you will see that `INITIALLY DEFFERED` seems to operate like `NO ACTION` or `RESTRICT`. When we run a delete, it seems to make no difference: -```markdown +```shell postgres=# delete from grandparent; ERROR: update or delete on table "parent" violates foreign key constraint "child_father_fkey" on table "child" DETAIL: Key (id)=(1) is still referenced from table "child". @@ -161,22 +162,18 @@ DETAIL: Key (id)=(1) is still referenced from table "child". But, when we combine it with _other_ constraints, then any other constraints take precedence. For example, let's run the same but add a `mother` column that has a `CASCADE` delete: ```sql -alter table - child -add column - mother integer references parent (id) on delete cascade; +alter table child +add column mother integer references parent (id) + on delete cascade; -update - child -set - mother = 2 -where - id = 1; +update child +set mother = 2 +where id = 1; ``` Then let's run a delete on the `grandparent` table: -```sql +```shell postgres=# delete from grandparent; DELETE 1 From 07915e5a6e2853e0fcf50ab119d12e162a843958 Mon Sep 17 00:00:00 2001 From: Greg Richardson Date: Fri, 28 Apr 2023 13:32:50 -0600 Subject: [PATCH 12/12] chore(prettier): reverting prettier config changes - moving to another pr --- .prettierrc | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/.prettierrc b/.prettierrc index c60d3ab91ef..b9bda117c38 100644 --- a/.prettierrc +++ b/.prettierrc @@ -5,7 +5,5 @@ "singleQuote": true, "printWidth": 100, "endOfLine": "lf", - "sqlKeywordCase": "lower", - "pluginSearchDirs": false, - "plugins": ["prettier-plugin-sql-cst"] + "sqlKeywordCase": "lower" }