fix(customer): Unique constraint on customer email (#7439)

**What**
Prevent creating multiple customers with the same email
This commit is contained in:
Adrien de Peretti
2024-05-24 14:20:54 +00:00
committed by GitHub
parent 066fd3c3d2
commit 77d72c5791
11 changed files with 186 additions and 35 deletions
@@ -124,6 +124,14 @@
"name": "customer",
"schema": "public",
"indexes": [
{
"keyName": "IDX_customer_email_has_account_unique",
"columnNames": [],
"composite": false,
"primary": false,
"unique": false,
"expression": "CREATE UNIQUE INDEX IF NOT EXISTS \"IDX_customer_email_has_account_unique\" ON \"customer\" (email, has_account) WHERE deleted_at IS NULL"
},
{
"keyName": "customer_pkey",
"columnNames": [
@@ -321,20 +329,20 @@
"unique": false
},
{
"keyName": "IDX_customer_address_unqiue_customer_billing",
"keyName": "IDX_customer_address_unique_customer_billing",
"columnNames": [],
"composite": false,
"primary": false,
"unique": false,
"expression": "create unique index \"IDX_customer_address_unqiue_customer_billing\" on \"customer_address\" (\"customer_id\") where \"is_default_billing\" = true"
"expression": "CREATE UNIQUE INDEX IF NOT EXISTS \"IDX_customer_address_unique_customer_billing\" ON \"customer_address\" (customer_id) WHERE \"is_default_billing\" = true"
},
{
"keyName": "IDX_customer_address_unqiue_customer_shipping",
"keyName": "IDX_customer_address_unique_customer_shipping",
"columnNames": [],
"composite": false,
"primary": false,
"unique": false,
"expression": "create unique index \"IDX_customer_address_unique_customer_shipping\" on \"customer_address\" (\"customer_id\") where \"is_default_shipping\" = true"
"expression": "CREATE UNIQUE INDEX IF NOT EXISTS \"IDX_customer_address_unique_customer_shipping\" ON \"customer_address\" (customer_id) WHERE \"is_default_shipping\" = true"
},
{
"keyName": "customer_address_pkey",
@@ -0,0 +1,21 @@
import { Migration } from '@mikro-orm/migrations';
export class Migration20240524123112 extends Migration {
async up(): Promise<void> {
this.addSql('CREATE UNIQUE INDEX IF NOT EXISTS "IDX_customer_email_has_account_unique" ON "customer" (email, has_account) WHERE deleted_at IS NULL;');
this.addSql('drop index if exists "IDX_customer_address_unqiue_customer_billing";');
this.addSql('drop index if exists "IDX_customer_address_unqiue_customer_shipping";');
this.addSql('CREATE UNIQUE INDEX IF NOT EXISTS "IDX_customer_address_unique_customer_billing" ON "customer_address" (customer_id) WHERE "is_default_billing" = true;');
this.addSql('CREATE UNIQUE INDEX IF NOT EXISTS "IDX_customer_address_unique_customer_shipping" ON "customer_address" (customer_id) WHERE "is_default_shipping" = true;');
}
async down(): Promise<void> {
this.addSql('drop index if exists "IDX_customer_email_has_account_unique";');
this.addSql('drop index if exists "IDX_customer_address_unique_customer_billing";');
this.addSql('drop index if exists "IDX_customer_address_unique_customer_shipping";');
this.addSql('create unique index if not exists "IDX_customer_address_unqiue_customer_billing" on "customer_address" ("customer_id") where "is_default_billing" = true;');
this.addSql('create unique index if not exists "IDX_customer_address_unique_customer_shipping" on "customer_address" ("customer_id") where "is_default_shipping" = true;');
}
}
+24 -16
View File
@@ -1,10 +1,13 @@
import { DAL } from "@medusajs/types"
import { Searchable, generateEntityId } from "@medusajs/utils"
import {
createPsqlIndexStatementHelper,
generateEntityId,
Searchable,
} from "@medusajs/utils"
import {
BeforeCreate,
Cascade,
Entity,
Index,
ManyToOne,
OnInit,
OptionalProps,
@@ -15,22 +18,27 @@ import Customer from "./customer"
type OptionalAddressProps = DAL.EntityDateColumns // TODO: To be revisited when more clear
export const UNIQUE_CUSTOMER_SHIPPING_ADDRESS =
"IDX_customer_address_unique_customer_shipping"
export const UNIQUE_CUSTOMER_BILLING_ADDRESS =
"IDX_customer_address_unique_customer_billing"
const CustomerAddressUniqueCustomerShippingAddress =
createPsqlIndexStatementHelper({
name: "IDX_customer_address_unique_customer_shipping",
tableName: "customer_address",
columns: "customer_id",
unique: true,
where: '"is_default_shipping" = true',
})
const CustomerAddressUniqueCustomerBillingAddress =
createPsqlIndexStatementHelper({
name: "IDX_customer_address_unique_customer_billing",
tableName: "customer_address",
columns: "customer_id",
unique: true,
where: '"is_default_billing" = true',
})
@Entity({ tableName: "customer_address" })
@Index({
name: UNIQUE_CUSTOMER_SHIPPING_ADDRESS,
expression:
'create unique index "IDX_customer_address_unique_customer_shipping" on "customer_address" ("customer_id") where "is_default_shipping" = true',
})
@Index({
name: UNIQUE_CUSTOMER_BILLING_ADDRESS,
expression:
'create unique index "IDX_customer_address_unique_customer_billing" on "customer_address" ("customer_id") where "is_default_billing" = true',
})
@CustomerAddressUniqueCustomerShippingAddress.MikroORMIndex()
@CustomerAddressUniqueCustomerBillingAddress.MikroORMIndex()
export default class Address {
[OptionalProps]: OptionalAddressProps
@@ -1,5 +1,10 @@
import { DAL } from "@medusajs/types"
import { DALUtils, Searchable, generateEntityId } from "@medusajs/utils"
import {
createPsqlIndexStatementHelper,
DALUtils,
generateEntityId,
Searchable,
} from "@medusajs/utils"
import {
BeforeCreate,
Cascade,
@@ -7,8 +12,8 @@ import {
Entity,
Filter,
ManyToMany,
OnInit,
OneToMany,
OnInit,
OptionalProps,
PrimaryKey,
Property,
@@ -22,8 +27,16 @@ type OptionalCustomerProps =
| "addresses"
| DAL.SoftDeletableEntityDateColumns
const CustomerUniqueEmail = createPsqlIndexStatementHelper({
tableName: "customer",
columns: ["email", "has_account"],
unique: true,
where: "deleted_at IS NULL",
})
@Entity({ tableName: "customer" })
@Filter(DALUtils.mikroOrmSoftDeletableFilterOptions)
@CustomerUniqueEmail.MikroORMIndex()
export default class Customer {
[OptionalProps]?: OptionalCustomerProps
@@ -1 +0,0 @@
export { MikroOrmBaseRepository as BaseRepository } from "@medusajs/utils"