feat: add notification data model and migration
This commit is contained in:
@@ -0,0 +1,56 @@
|
||||
import { MigrationInterface, QueryRunner } from 'typeorm';
|
||||
|
||||
export class AddNotificationTables1785600000000 implements MigrationInterface {
|
||||
name = 'AddNotificationTables1785600000000';
|
||||
|
||||
public async up(queryRunner: QueryRunner): Promise<void> {
|
||||
await queryRunner.query(`
|
||||
CREATE TABLE "notification" (
|
||||
"id" SERIAL NOT NULL,
|
||||
"teamId" integer NOT NULL,
|
||||
"event" character varying NOT NULL,
|
||||
"actorUserId" integer NOT NULL,
|
||||
"payload" text NOT NULL,
|
||||
"createdAt" TIMESTAMP NOT NULL DEFAULT now(),
|
||||
CONSTRAINT "PK_notification_id" PRIMARY KEY ("id")
|
||||
)
|
||||
`);
|
||||
await queryRunner.query(
|
||||
`CREATE INDEX "IDX_notification_team_id" ON "notification" ("teamId")`,
|
||||
);
|
||||
await queryRunner.query(`
|
||||
ALTER TABLE "notification"
|
||||
ADD CONSTRAINT "FK_notification_team"
|
||||
FOREIGN KEY ("teamId") REFERENCES "team"("id")
|
||||
ON DELETE CASCADE
|
||||
`);
|
||||
|
||||
await queryRunner.query(`
|
||||
CREATE TABLE "notification_recipient" (
|
||||
"id" SERIAL NOT NULL,
|
||||
"notificationId" integer NOT NULL,
|
||||
"userId" integer NOT NULL,
|
||||
"read" boolean NOT NULL DEFAULT false,
|
||||
"readAt" TIMESTAMP,
|
||||
CONSTRAINT "PK_notification_recipient_id" PRIMARY KEY ("id")
|
||||
)
|
||||
`);
|
||||
await queryRunner.query(
|
||||
`CREATE INDEX "IDX_notification_recipient_notification_id" ON "notification_recipient" ("notificationId")`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`CREATE INDEX "IDX_notification_recipient_user_id" ON "notification_recipient" ("userId")`,
|
||||
);
|
||||
await queryRunner.query(`
|
||||
ALTER TABLE "notification_recipient"
|
||||
ADD CONSTRAINT "FK_notification_recipient_notification"
|
||||
FOREIGN KEY ("notificationId") REFERENCES "notification"("id")
|
||||
ON DELETE CASCADE
|
||||
`);
|
||||
}
|
||||
|
||||
public async down(queryRunner: QueryRunner): Promise<void> {
|
||||
await queryRunner.query(`DROP TABLE "notification_recipient"`);
|
||||
await queryRunner.query(`DROP TABLE "notification"`);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
describe('AddNotificationTables1785600000000', () => {
|
||||
it('creates the notification and notification_recipient tables with their indexes and foreign keys', async () => {
|
||||
const migrationModule = require('./1785600000000-AddNotificationTables');
|
||||
const migration = new migrationModule.AddNotificationTables1785600000000();
|
||||
const queryRunner = { query: jest.fn() } as any;
|
||||
|
||||
await migration.up(queryRunner);
|
||||
|
||||
const calls: string[] = queryRunner.query.mock.calls.map((c: any) => c[0]);
|
||||
expect(calls).toHaveLength(7);
|
||||
expect(calls.some((sql) => sql.includes('CREATE TABLE "notification"'))).toBe(true);
|
||||
expect(calls.some((sql) => sql.includes('CREATE TABLE "notification_recipient"'))).toBe(
|
||||
true,
|
||||
);
|
||||
expect(calls.some((sql) => sql.includes('IDX_notification_team_id'))).toBe(true);
|
||||
expect(
|
||||
calls.some((sql) => sql.includes('IDX_notification_recipient_notification_id')),
|
||||
).toBe(true);
|
||||
expect(calls.some((sql) => sql.includes('IDX_notification_recipient_user_id'))).toBe(
|
||||
true,
|
||||
);
|
||||
expect(calls.some((sql) => sql.includes('FK_notification_team'))).toBe(true);
|
||||
expect(calls.some((sql) => sql.includes('FK_notification_recipient_notification'))).toBe(
|
||||
true,
|
||||
);
|
||||
});
|
||||
|
||||
it('drops both tables on down, recipient first to respect the foreign key', async () => {
|
||||
const migrationModule = require('./1785600000000-AddNotificationTables');
|
||||
const migration = new migrationModule.AddNotificationTables1785600000000();
|
||||
const queryRunner = { query: jest.fn() } as any;
|
||||
|
||||
await migration.down(queryRunner);
|
||||
|
||||
const calls: string[] = queryRunner.query.mock.calls.map((c: any) => c[0]);
|
||||
expect(calls).toEqual(['DROP TABLE "notification_recipient"', 'DROP TABLE "notification"']);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,23 @@
|
||||
import { Column, Entity, Index, ManyToOne, PrimaryGeneratedColumn } from 'typeorm';
|
||||
import { EntityHelper } from 'src/utils/entity-helper';
|
||||
import { Notification } from './notification.entity';
|
||||
|
||||
@Entity()
|
||||
export class NotificationRecipient extends EntityHelper {
|
||||
@PrimaryGeneratedColumn()
|
||||
id: number;
|
||||
|
||||
@Index('IDX_notification_recipient_notification_id')
|
||||
@ManyToOne(() => Notification, { onDelete: 'CASCADE' })
|
||||
notification: Notification;
|
||||
|
||||
@Index('IDX_notification_recipient_user_id')
|
||||
@Column()
|
||||
userId: number;
|
||||
|
||||
@Column({ default: false })
|
||||
read: boolean;
|
||||
|
||||
@Column({ nullable: true })
|
||||
readAt: Date | null;
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
import {
|
||||
Column,
|
||||
CreateDateColumn,
|
||||
Entity,
|
||||
Index,
|
||||
ManyToOne,
|
||||
PrimaryGeneratedColumn,
|
||||
} from 'typeorm';
|
||||
import { EntityHelper } from 'src/utils/entity-helper';
|
||||
import { Team } from 'src/teams/entities/team.entity';
|
||||
import { NOTIFICATION_EVENT } from '../model/notification-event.type';
|
||||
|
||||
@Entity()
|
||||
export class Notification extends EntityHelper {
|
||||
@PrimaryGeneratedColumn()
|
||||
id: number;
|
||||
|
||||
@Index('IDX_notification_team_id')
|
||||
@ManyToOne(() => Team, { eager: false })
|
||||
team: Team;
|
||||
|
||||
@Column()
|
||||
event: NOTIFICATION_EVENT;
|
||||
|
||||
@Column()
|
||||
actorUserId: number;
|
||||
|
||||
@Column({ type: 'text' })
|
||||
payload: string;
|
||||
|
||||
@CreateDateColumn()
|
||||
createdAt: Date;
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
export type NOTIFICATION_EVENT =
|
||||
| 'player_active_update'
|
||||
| 'player_team_role_update'
|
||||
| 'player_creation'
|
||||
| 'public_access_enabled'
|
||||
| 'public_access_rotated'
|
||||
| 'user_invite_link_create';
|
||||
|
||||
export const NOTIFICATION_EVENT_VALUES: NOTIFICATION_EVENT[] = [
|
||||
'player_active_update',
|
||||
'player_team_role_update',
|
||||
'player_creation',
|
||||
'public_access_enabled',
|
||||
'public_access_rotated',
|
||||
'user_invite_link_create',
|
||||
];
|
||||
Reference in New Issue
Block a user