fix: Unique constraint should account for soft deleted records (#11048)

FIXES FRMW-2878

**What**
Currently, the `one-to-one` unique constraints does not account for deleted record. This prevents from inserting a new record wth the same fk if another one is deleted.

**Caveat**
`hasOne` with FK option is meant to be a special case, for example a many to one - one to many without defining the other side of the relation. In that case we don't handle this behaviour and keep it as it is
This commit is contained in:
Adrien de Peretti
2025-01-22 07:42:06 +00:00
committed by GitHub
parent ecc8efcb04
commit da3906efa4
22 changed files with 361 additions and 217 deletions
@@ -1,5 +1,7 @@
{
"namespaces": ["public"],
"namespaces": [
"public"
],
"name": "public",
"tables": [
{
@@ -86,9 +88,19 @@
"name": "region",
"schema": "public",
"indexes": [
{
"keyName": "IDX_region_deleted_at",
"columnNames": [],
"composite": false,
"primary": false,
"unique": false,
"expression": "CREATE INDEX IF NOT EXISTS \"IDX_region_deleted_at\" ON \"region\" (deleted_at) WHERE deleted_at IS NULL"
},
{
"keyName": "region_pkey",
"columnNames": ["id"],
"columnNames": [
"id"
],
"composite": false,
"primary": true,
"unique": true
@@ -198,17 +210,35 @@
"name": "region_country",
"schema": "public",
"indexes": [
{
"keyName": "IDX_region_country_region_id",
"columnNames": [],
"composite": false,
"primary": false,
"unique": false,
"expression": "CREATE INDEX IF NOT EXISTS \"IDX_region_country_region_id\" ON \"region_country\" (region_id) WHERE deleted_at IS NULL"
},
{
"keyName": "IDX_region_country_deleted_at",
"columnNames": [],
"composite": false,
"primary": false,
"unique": false,
"expression": "CREATE INDEX IF NOT EXISTS \"IDX_region_country_deleted_at\" ON \"region_country\" (deleted_at) WHERE deleted_at IS NULL"
},
{
"keyName": "IDX_region_country_region_id_iso_2_unique",
"columnNames": [],
"composite": false,
"primary": false,
"unique": false,
"expression": "CREATE UNIQUE INDEX IF NOT EXISTS \"IDX_region_country_region_id_iso_2_unique\" ON \"region_country\" (region_id, iso_2)"
"expression": "CREATE UNIQUE INDEX IF NOT EXISTS \"IDX_region_country_region_id_iso_2_unique\" ON \"region_country\" (region_id, iso_2) WHERE deleted_at IS NULL"
},
{
"keyName": "region_country_pkey",
"columnNames": ["iso_2"],
"columnNames": [
"iso_2"
],
"composite": false,
"primary": true,
"unique": true
@@ -218,9 +248,13 @@
"foreignKeys": {
"region_country_region_id_foreign": {
"constraintName": "region_country_region_id_foreign",
"columnNames": ["region_id"],
"columnNames": [
"region_id"
],
"localTableName": "public.region_country",
"referencedColumnNames": ["id"],
"referencedColumnNames": [
"id"
],
"referencedTableName": "public.region",
"deleteRule": "set null",
"updateRule": "cascade"
@@ -0,0 +1,19 @@
import { Migration } from '@mikro-orm/migrations';
export class Migration20250120110744 extends Migration {
async up(): Promise<void> {
this.addSql('CREATE INDEX IF NOT EXISTS "IDX_region_deleted_at" ON "region" (deleted_at) WHERE deleted_at IS NULL;');
this.addSql('CREATE INDEX IF NOT EXISTS "IDX_region_country_region_id" ON "region_country" (region_id) WHERE deleted_at IS NULL;');
this.addSql('CREATE INDEX IF NOT EXISTS "IDX_region_country_deleted_at" ON "region_country" (deleted_at) WHERE deleted_at IS NULL;');
}
async down(): Promise<void> {
this.addSql('drop index if exists "IDX_region_deleted_at";');
this.addSql('drop index if exists "IDX_region_country_region_id";');
this.addSql('drop index if exists "IDX_region_country_deleted_at";');
}
}