Skip to content

Commit

Permalink
feat(user): Migrate user module to DML (medusajs#10389)
Browse files Browse the repository at this point in the history
* feat(user): Migrate user module to DML

* Create rotten-tigers-worry.md

* update indexes names following conventions

* remove duplicate modifier
  • Loading branch information
adrien2p authored and hirotaka committed Dec 7, 2024
1 parent b8d872a commit 7672d20
Show file tree
Hide file tree
Showing 8 changed files with 105 additions and 259 deletions.
5 changes: 5 additions & 0 deletions .changeset/rotten-tigers-worry.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@medusajs/user": minor
---

feat(user): Migrate user module to DML
Original file line number Diff line number Diff line change
Expand Up @@ -8,22 +8,16 @@ import jwt, { JwtPayload } from "jsonwebtoken"

jest.setTimeout(30000)

const expireDate = new Date().setMilliseconds(
new Date().getMilliseconds() + 60 * 60 * 24
)

const defaultInviteData = [
{
id: "1",
email: "[email protected]",
token: "test",
expires_at: expireDate,
},
{
id: "2",
email: "[email protected]",
token: "test",
expires_at: expireDate,
},
]

Expand Down
42 changes: 24 additions & 18 deletions packages/modules/user/src/migrations/.snapshot-medusa-user.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
{
"namespaces": ["public"],
"namespaces": [
"public"
],
"name": "public",
"tables": [
{
Expand Down Expand Up @@ -97,32 +99,34 @@
"schema": "public",
"indexes": [
{
"keyName": "IDX_invite_email",
"columnNames": ["email"],
"keyName": "IDX_invite_deleted_at",
"columnNames": [],
"composite": false,
"primary": false,
"unique": false,
"expression": "CREATE UNIQUE INDEX IF NOT EXISTS \"IDX_invite_email\" ON \"invite\" (email) WHERE deleted_at IS NULL"
"expression": "CREATE INDEX IF NOT EXISTS \"IDX_invite_deleted_at\" ON \"invite\" (deleted_at) WHERE deleted_at IS NULL"
},
{
"keyName": "IDX_invite_token",
"columnNames": ["token"],
"keyName": "IDX_invite_email_unique",
"columnNames": [],
"composite": false,
"primary": false,
"unique": false,
"expression": "CREATE INDEX IF NOT EXISTS \"IDX_invite_token\" ON \"invite\" (token) WHERE deleted_at IS NULL"
"expression": "CREATE UNIQUE INDEX IF NOT EXISTS \"IDX_invite_email_unique\" ON \"invite\" (email) WHERE deleted_at IS NULL"
},
{
"keyName": "IDX_invite_deleted_at",
"columnNames": ["deleted_at"],
"keyName": "IDX_invite_token",
"columnNames": [],
"composite": false,
"primary": false,
"unique": false,
"expression": "CREATE INDEX IF NOT EXISTS \"IDX_invite_deleted_at\" ON \"invite\" (deleted_at) WHERE deleted_at IS NOT NULL"
"expression": "CREATE INDEX IF NOT EXISTS \"IDX_invite_token\" ON \"invite\" (token) WHERE deleted_at IS NULL"
},
{
"keyName": "invite_pkey",
"columnNames": ["id"],
"columnNames": [
"id"
],
"composite": false,
"primary": true,
"unique": true
Expand Down Expand Up @@ -224,24 +228,26 @@
"schema": "public",
"indexes": [
{
"keyName": "IDX_user_email",
"columnNames": ["email"],
"keyName": "IDX_user_deleted_at",
"columnNames": [],
"composite": false,
"primary": false,
"unique": false,
"expression": "CREATE UNIQUE INDEX IF NOT EXISTS \"IDX_user_email\" ON \"user\" (email) WHERE deleted_at IS NULL"
"expression": "CREATE INDEX IF NOT EXISTS \"IDX_user_deleted_at\" ON \"user\" (deleted_at) WHERE deleted_at IS NULL"
},
{
"keyName": "IDX_user_deleted_at",
"columnNames": ["deleted_at"],
"keyName": "IDX_user_email_unique",
"columnNames": [],
"composite": false,
"primary": false,
"unique": false,
"expression": "CREATE INDEX IF NOT EXISTS \"IDX_user_deleted_at\" ON \"user\" (deleted_at) WHERE deleted_at IS NOT NULL"
"expression": "CREATE UNIQUE INDEX IF NOT EXISTS \"IDX_user_email_unique\" ON \"user\" (email) WHERE deleted_at IS NULL"
},
{
"keyName": "user_pkey",
"columnNames": ["id"],
"columnNames": [
"id"
],
"composite": false,
"primary": true,
"unique": true
Expand Down
21 changes: 21 additions & 0 deletions packages/modules/user/src/migrations/Migration20241202103352.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { Migration } from '@mikro-orm/migrations';

export class Migration20241202103352 extends Migration {

async up(): Promise<void> {
this.addSql('drop index if exists "IDX_invite_email";');
this.addSql('CREATE UNIQUE INDEX IF NOT EXISTS "IDX_invite_email_unique" ON "invite" (email) WHERE deleted_at IS NULL;');

this.addSql('drop index if exists "IDX_user_email";');
this.addSql('CREATE UNIQUE INDEX IF NOT EXISTS "IDX_user_email_unique" ON "user" (email) WHERE deleted_at IS NULL;');
}

async down(): Promise<void> {
this.addSql('drop index if exists "IDX_invite_email_unique";');
this.addSql('CREATE UNIQUE INDEX IF NOT EXISTS "IDX_invite_email" ON "invite" (email) WHERE deleted_at IS NULL;');

this.addSql('drop index if exists "IDX_user_email_unique";');
this.addSql('CREATE UNIQUE INDEX IF NOT EXISTS "IDX_user_email" ON "user" (email) WHERE deleted_at IS NULL;');
}

}
4 changes: 2 additions & 2 deletions packages/modules/user/src/models/index.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
export { default as User } from "./user"
export { default as Invite } from "./invite"
export { User } from "./user"
export { Invite } from "./invite"
132 changes: 21 additions & 111 deletions packages/modules/user/src/models/invite.ts
Original file line number Diff line number Diff line change
@@ -1,112 +1,22 @@
import {
BeforeCreate,
Entity,
Filter,
Index,
OnInit,
OptionalProps,
PrimaryKey,
Property,
} from "@mikro-orm/core"

import { DAL } from "@medusajs/framework/types"
import {
DALUtils,
createPsqlIndexStatementHelper,
generateEntityId,
Searchable,
} from "@medusajs/framework/utils"

const inviteEmailIndexName = "IDX_invite_email"
const inviteEmailIndexStatement = createPsqlIndexStatementHelper({
name: inviteEmailIndexName,
tableName: "invite",
columns: "email",
where: "deleted_at IS NULL",
unique: true,
}).expression

const inviteTokenIndexName = "IDX_invite_token"
const inviteTokenIndexStatement = createPsqlIndexStatementHelper({
name: inviteTokenIndexName,
tableName: "invite",
columns: "token",
where: "deleted_at IS NULL",
}).expression

const inviteDeletedAtIndexName = "IDX_invite_deleted_at"
const inviteDeletedAtIndexStatement = createPsqlIndexStatementHelper({
name: inviteDeletedAtIndexName,
tableName: "invite",
columns: "deleted_at",
where: "deleted_at IS NOT NULL",
}).expression

type OptionalFields =
| "metadata"
| "accepted"
| DAL.SoftDeletableModelDateColumns
@Entity({ tableName: "invite" })
@Filter(DALUtils.mikroOrmSoftDeletableFilterOptions)
export default class Invite {
[OptionalProps]: OptionalFields

@PrimaryKey({ columnType: "text" })
id: string

@Index({
name: inviteEmailIndexName,
expression: inviteEmailIndexStatement,
})
@Searchable()
@Property({ columnType: "text" })
email: string

@Property({ columnType: "boolean" })
accepted: boolean = false

@Index({
name: inviteTokenIndexName,
expression: inviteTokenIndexStatement,
import { model } from "@medusajs/framework/utils"

export const Invite = model
.define("invite", {
id: model.id({ prefix: "invite" }).primaryKey(),
email: model.text().searchable(),
accepted: model.boolean().default(false),
token: model.text(),
expires_at: model.dateTime(),
metadata: model.json().nullable(),
})
@Property({ columnType: "text" })
token: string

@Property({ columnType: "timestamptz" })
expires_at: Date

@Property({ columnType: "jsonb", nullable: true })
metadata: Record<string, unknown> | null = null

@Property({
onCreate: () => new Date(),
columnType: "timestamptz",
defaultRaw: "now()",
})
created_at: Date

@Property({
onCreate: () => new Date(),
onUpdate: () => new Date(),
columnType: "timestamptz",
defaultRaw: "now()",
})
updated_at: Date

@Index({
name: inviteDeletedAtIndexName,
expression: inviteDeletedAtIndexStatement,
})
@Property({ columnType: "timestamptz", nullable: true })
deleted_at: Date | null = null

@OnInit()
onInit() {
this.id = generateEntityId(this.id, "invite")
}

@BeforeCreate()
beforeCreate() {
this.id = generateEntityId(this.id, "invite")
}
}
.indexes([
{
on: ["email"],
unique: true,
where: "deleted_at IS NULL",
},
{
on: ["token"],
where: "deleted_at IS NULL",
},
])
118 changes: 17 additions & 101 deletions packages/modules/user/src/models/user.ts
Original file line number Diff line number Diff line change
@@ -1,102 +1,18 @@
import {
BeforeCreate,
Entity,
Filter,
Index,
OnInit,
OptionalProps,
PrimaryKey,
Property,
} from "@mikro-orm/core"

import { DAL } from "@medusajs/framework/types"
import {
createPsqlIndexStatementHelper,
DALUtils,
generateEntityId,
Searchable,
} from "@medusajs/framework/utils"

const userEmailIndexName = "IDX_user_email"
const userEmailIndexStatement = createPsqlIndexStatementHelper({
name: userEmailIndexName,
unique: true,
tableName: "user",
columns: "email",
where: "deleted_at IS NULL",
})

const userDeletedAtIndexName = "IDX_user_deleted_at"
const userDeletedAtIndexStatement = createPsqlIndexStatementHelper({
name: userDeletedAtIndexName,
tableName: "user",
columns: "deleted_at",
where: "deleted_at IS NOT NULL",
}).expression

type OptionalFields =
| "first_name"
| "last_name"
| "metadata"
| "avatar_url"
| DAL.SoftDeletableModelDateColumns

@Entity()
@Filter(DALUtils.mikroOrmSoftDeletableFilterOptions)
export default class User {
[OptionalProps]?: OptionalFields

@PrimaryKey({ columnType: "text" })
id!: string

@Searchable()
@Property({ columnType: "text", nullable: true })
first_name: string | null = null

@Searchable()
@Property({ columnType: "text", nullable: true })
last_name: string | null = null

@userEmailIndexStatement.MikroORMIndex()
@Searchable()
@Property({ columnType: "text" })
email: string

@Property({ columnType: "text", nullable: true })
avatar_url: string | null = null

@Property({ columnType: "jsonb", nullable: true })
metadata: Record<string, unknown> | null = null

@Property({
onCreate: () => new Date(),
columnType: "timestamptz",
defaultRaw: "now()",
})
created_at: Date

@Property({
onCreate: () => new Date(),
onUpdate: () => new Date(),
columnType: "timestamptz",
defaultRaw: "now()",
import { model } from "@medusajs/framework/utils"

export const User = model
.define("user", {
id: model.id({ prefix: "user" }).primaryKey(),
first_name: model.text().searchable().nullable(),
last_name: model.text().searchable().nullable(),
email: model.text().searchable(),
avatar_url: model.text().nullable(),
metadata: model.json().nullable(),
})
updated_at: Date

@Index({
name: userDeletedAtIndexName,
expression: userDeletedAtIndexStatement,
})
@Property({ columnType: "timestamptz", nullable: true })
deleted_at?: Date | null = null

@BeforeCreate()
onCreate() {
this.id = generateEntityId(this.id, "user")
}

@OnInit()
onInit() {
this.id = generateEntityId(this.id, "user")
}
}
.indexes([
{
unique: true,
on: ["email"],
where: "deleted_at IS NULL",
},
])
Loading

0 comments on commit 7672d20

Please sign in to comment.