From 21cf811a5620799114b2f6fea7f70cc3441cacbb Mon Sep 17 00:00:00 2001 From: Julian Krauser Date: Sat, 25 Jan 2025 10:20:57 +0100 Subject: [PATCH 1/2] change salutation to separate table --- src/command/club/member/memberCommand.ts | 6 ++--- .../club/member/memberCommandHandler.ts | 4 ++-- src/controller/admin/club/memberController.ts | 8 +++---- .../admin/club/newsletterController.ts | 5 ++-- src/data-source.ts | 2 ++ src/demodata/newsletter.data.ts | 7 +++--- src/entity/club/member/member.ts | 24 ++++++------------- src/entity/settings/salutation.ts | 15 ++++++++++++ src/enums/salutation.ts | 6 ----- src/helpers/newsletterHelper.ts | 2 +- .../admin/club/member/member.models.ts | 6 ++--- .../admin/club/member/membership.models.ts | 4 +--- .../admin/settings/salutation.models.ts | 4 ++++ src/views/memberExecutivePositionView.ts | 9 +++---- src/views/memberQualificationsView.ts | 9 +++---- src/views/memberView.ts | 8 +++---- src/views/membershipsView.ts | 6 ++--- 17 files changed, 64 insertions(+), 61 deletions(-) create mode 100644 src/entity/settings/salutation.ts delete mode 100644 src/enums/salutation.ts create mode 100644 src/viewmodel/admin/settings/salutation.models.ts diff --git a/src/command/club/member/memberCommand.ts b/src/command/club/member/memberCommand.ts index a05e284..126b87d 100644 --- a/src/command/club/member/memberCommand.ts +++ b/src/command/club/member/memberCommand.ts @@ -1,7 +1,5 @@ -import { Salutation } from "../../../enums/salutation"; - export interface CreateMemberCommand { - salutation: Salutation; + salutationId: number; firstname: string; lastname: string; nameaffix: string; @@ -11,7 +9,7 @@ export interface CreateMemberCommand { export interface UpdateMemberCommand { id: number; - salutation: Salutation; + salutationId: number; firstname: string; lastname: string; nameaffix: string; diff --git a/src/command/club/member/memberCommandHandler.ts b/src/command/club/member/memberCommandHandler.ts index 2bea5b5..569e835 100644 --- a/src/command/club/member/memberCommandHandler.ts +++ b/src/command/club/member/memberCommandHandler.ts @@ -21,7 +21,7 @@ export default abstract class MemberCommandHandler { .insert() .into(member) .values({ - salutation: createMember.salutation, + salutationId: createMember.salutationId, firstname: createMember.firstname, lastname: createMember.lastname, nameaffix: createMember.nameaffix, @@ -50,7 +50,7 @@ export default abstract class MemberCommandHandler { .createQueryBuilder() .update(member) .set({ - salutation: updateMember.salutation, + salutationId: updateMember.salutationId, firstname: updateMember.firstname, lastname: updateMember.lastname, nameaffix: updateMember.nameaffix, diff --git a/src/controller/admin/club/memberController.ts b/src/controller/admin/club/memberController.ts index 4970ead..c313b27 100644 --- a/src/controller/admin/club/memberController.ts +++ b/src/controller/admin/club/memberController.ts @@ -285,7 +285,7 @@ export async function createMemberPrintoutList(req: Request, res: Response): Pro * @returns {Promise<*>} */ export async function createMember(req: Request, res: Response): Promise { - const salutation = req.body.salutation; + const salutationId = req.body.salutationId; const firstname = req.body.firstname; const lastname = req.body.lastname; const nameaffix = req.body.nameaffix; @@ -293,7 +293,7 @@ export async function createMember(req: Request, res: Response): Promise { const internalId = req.body.internalId; let createMember: CreateMemberCommand = { - salutation, + salutationId, firstname, lastname, nameaffix, @@ -453,7 +453,7 @@ export async function addCommunicationToMember(req: Request, res: Response): Pro */ export async function updateMemberById(req: Request, res: Response): Promise { const memberId = parseInt(req.params.id); - const salutation = req.body.salutation; + const salutationId = req.body.salutationId; const firstname = req.body.firstname; const lastname = req.body.lastname; const nameaffix = req.body.nameaffix; @@ -462,7 +462,7 @@ export async function updateMemberById(req: Request, res: Response): Promise >; - recipient: Partial; + recipient: Partial< + Omit & { salutation: string; street: string; streetNumber: string; streetNumberAdd: string } + >; } = { title: "Beispiel Newsletter Daten", description: "Zusammenfassung der Demodaten.", @@ -63,7 +64,7 @@ export const newsletterDemoData: { recipient: { firstname: "Julian", lastname: "Krauser", - salutation: Salutation.sir, + salutation: "Herr", nameaffix: "", street: "Straße", streetNumber: "Hausnummer", diff --git a/src/entity/club/member/member.ts b/src/entity/club/member/member.ts index 1defb1f..e5b27c2 100644 --- a/src/entity/club/member/member.ts +++ b/src/entity/club/member/member.ts @@ -1,32 +1,16 @@ import { Column, Entity, JoinColumn, ManyToOne, OneToMany, OneToOne, PrimaryColumn } from "typeorm"; -import { Salutation } from "../../../enums/salutation"; import { membership } from "./membership"; import { memberAwards } from "./memberAwards"; import { memberQualifications } from "./memberQualifications"; import { memberExecutivePositions } from "./memberExecutivePositions"; import { communication } from "./communication"; -import { CommunicationViewModel } from "../../../viewmodel/admin/club/member/communication.models"; +import { salutation } from "../../settings/salutation"; @Entity() export class member { @PrimaryColumn({ generated: "increment", type: "int" }) id: number; - @Column({ - type: "varchar", - length: "255", - default: Salutation.none.toString(), - transformer: { - to(value: Salutation) { - return value.toString(); - }, - from(value: string) { - return Salutation[value as keyof typeof Salutation]; - }, - }, - }) - salutation: Salutation; - @Column({ type: "varchar", length: 255 }) firstname: string; @@ -42,6 +26,9 @@ export class member { @Column({ type: "varchar", length: 255, unique: true, nullable: true }) internalId?: string; + @Column() + salutationId: number; + @OneToMany(() => communication, (communications) => communications.member) communications: communication[]; @@ -53,6 +40,9 @@ export class member { @JoinColumn() sendNewsletter?: communication; + @ManyToOne(() => salutation, (salutation) => salutation.members) + salutation: salutation; + @OneToMany(() => membership, (membership) => membership.member) memberships: membership[]; diff --git a/src/entity/settings/salutation.ts b/src/entity/settings/salutation.ts new file mode 100644 index 0000000..634921b --- /dev/null +++ b/src/entity/settings/salutation.ts @@ -0,0 +1,15 @@ +import { Column, Entity, OneToMany, PrimaryColumn } from "typeorm"; +import { memberAwards } from "../club/member/memberAwards"; +import { member } from "../club/member/member"; + +@Entity() +export class salutation { + @PrimaryColumn({ generated: "increment", type: "int" }) + id: number; + + @Column({ type: "varchar", length: 255, unique: true }) + salutation: string; + + @OneToMany(() => member, (member) => member.salutation) + members: member[]; +} diff --git a/src/enums/salutation.ts b/src/enums/salutation.ts deleted file mode 100644 index ba2fce4..0000000 --- a/src/enums/salutation.ts +++ /dev/null @@ -1,6 +0,0 @@ -export enum Salutation { - sir = "sir", - madam = "madam", - other = "other", - none = "none", -} diff --git a/src/helpers/newsletterHelper.ts b/src/helpers/newsletterHelper.ts index cfdeb76..1e458c1 100644 --- a/src/helpers/newsletterHelper.ts +++ b/src/helpers/newsletterHelper.ts @@ -100,7 +100,7 @@ export abstract class NewsletterHelper { recipient: { firstname: recipient.firstname, lastname: recipient.lastname, - salutation: recipient.salutation, + salutation: recipient.salutation.salutation, nameaffix: recipient.nameaffix, ...(showAdress ? { diff --git a/src/viewmodel/admin/club/member/member.models.ts b/src/viewmodel/admin/club/member/member.models.ts index c28ed73..2254d68 100644 --- a/src/viewmodel/admin/club/member/member.models.ts +++ b/src/viewmodel/admin/club/member/member.models.ts @@ -1,10 +1,10 @@ -import { Salutation } from "../../../../enums/salutation"; +import { SalutationViewModel } from "../../settings/salutation.models"; import { CommunicationViewModel } from "./communication.models"; import { MembershipViewModel } from "./membership.models"; export interface MemberViewModel { id: number; - salutation: Salutation; + salutation: SalutationViewModel; firstname: string; lastname: string; nameaffix: string; @@ -19,7 +19,7 @@ export interface MemberViewModel { export interface MemberStatisticsViewModel { id: number; - salutation: Salutation; + salutation: string; firstname: string; lastname: string; nameaffix: string; diff --git a/src/viewmodel/admin/club/member/membership.models.ts b/src/viewmodel/admin/club/member/membership.models.ts index da8bffa..1db540a 100644 --- a/src/viewmodel/admin/club/member/membership.models.ts +++ b/src/viewmodel/admin/club/member/membership.models.ts @@ -1,5 +1,3 @@ -import { Salutation } from "../../../../enums/salutation"; - export interface MembershipViewModel { id: number; start: Date; @@ -15,7 +13,7 @@ export interface MembershipStatisticsViewModel { status: string; statusId: number; memberId: number; - memberSalutation: Salutation; + memberSalutation: string; memberFirstname: string; memberLastname: string; memberNameaffix: string; diff --git a/src/viewmodel/admin/settings/salutation.models.ts b/src/viewmodel/admin/settings/salutation.models.ts new file mode 100644 index 0000000..18531f5 --- /dev/null +++ b/src/viewmodel/admin/settings/salutation.models.ts @@ -0,0 +1,4 @@ +export interface SalutationViewModel { + id: number; + salutation: string; +} diff --git a/src/views/memberExecutivePositionView.ts b/src/views/memberExecutivePositionView.ts index 23722cb..c1df465 100644 --- a/src/views/memberExecutivePositionView.ts +++ b/src/views/memberExecutivePositionView.ts @@ -1,6 +1,5 @@ import { DataSource, ViewColumn, ViewEntity } from "typeorm"; import { memberExecutivePositions } from "../entity/club/member/memberExecutivePositions"; -import { Salutation } from "../enums/salutation"; @ViewEntity({ expression: (datasource: DataSource) => @@ -10,18 +9,20 @@ import { Salutation } from "../enums/salutation"; .select("executivePosition.id", "positionId") .addSelect("executivePosition.position", "position") .addSelect("member.id", "memberId") - .addSelect("member.salutation", "memberSalutation") .addSelect("member.firstname", "memberFirstname") .addSelect("member.lastname", "memberLastname") .addSelect("member.nameaffix", "memberNameaffix") .addSelect("member.birthdate", "memberBirthdate") + .addSelect("salutation.salutation", "memberSalutation") .addSelect( "SUM(TIMESTAMPDIFF(DAY, memberExecutivePositions.start, COALESCE(memberExecutivePositions.end, CURRENT_DATE)))", "durationInDays" ) .leftJoin("memberExecutivePositions.executivePosition", "executivePosition") .leftJoin("memberExecutivePositions.member", "member") - .groupBy("executivePosition.id"), + .leftJoin("member.salutation", "salutation") + .groupBy("executivePosition.id") + .addGroupBy("member.id"), }) export class memberExecutivePositionsView { @ViewColumn() @@ -37,7 +38,7 @@ export class memberExecutivePositionsView { memberId: number; @ViewColumn() - memberSalutation: Salutation; + memberSalutation: string; @ViewColumn() memberFirstname: string; diff --git a/src/views/memberQualificationsView.ts b/src/views/memberQualificationsView.ts index 4ae436d..b22e05e 100644 --- a/src/views/memberQualificationsView.ts +++ b/src/views/memberQualificationsView.ts @@ -1,6 +1,5 @@ import { DataSource, ViewColumn, ViewEntity } from "typeorm"; import { memberQualifications } from "../entity/club/member/memberQualifications"; -import { Salutation } from "../enums/salutation"; @ViewEntity({ expression: (datasource: DataSource) => @@ -10,18 +9,20 @@ import { Salutation } from "../enums/salutation"; .select("qualification.id", "qualificationId") .addSelect("qualification.qualification", "qualification") .addSelect("member.id", "memberId") - .addSelect("member.salutation", "memberSalutation") .addSelect("member.firstname", "memberFirstname") .addSelect("member.lastname", "memberLastname") .addSelect("member.nameaffix", "memberNameaffix") .addSelect("member.birthdate", "memberBirthdate") + .addSelect("salutation.salutation", "memberSalutation") .addSelect( "SUM(TIMESTAMPDIFF(DAY, memberQualifications.start, COALESCE(memberQualifications.end, CURRENT_DATE)))", "durationInDays" ) .leftJoin("memberQualifications.qualification", "qualification") .leftJoin("memberQualifications.member", "member") - .groupBy("qualification.id"), + .leftJoin("member.salutation", "salutation") + .groupBy("qualification.id") + .addGroupBy("member.id"), }) export class memberQualificationsView { @ViewColumn() @@ -37,7 +38,7 @@ export class memberQualificationsView { memberId: number; @ViewColumn() - memberSalutation: Salutation; + memberSalutation: string; @ViewColumn() memberFirstname: string; diff --git a/src/views/memberView.ts b/src/views/memberView.ts index 6a980f0..90debc3 100644 --- a/src/views/memberView.ts +++ b/src/views/memberView.ts @@ -1,6 +1,5 @@ import { DataSource, ViewColumn, ViewEntity } from "typeorm"; import { member } from "../entity/club/member/member"; -import { Salutation } from "../enums/salutation"; @ViewEntity({ expression: (datasource: DataSource) => @@ -8,21 +7,22 @@ import { Salutation } from "../enums/salutation"; .getRepository(member) .createQueryBuilder("member") .select("member.id", "id") - .addSelect("member.salutation", "salutation") .addSelect("member.firstname", "firstname") .addSelect("member.lastname", "lastname") .addSelect("member.nameaffix", "nameaffix") .addSelect("member.birthdate", "birthdate") + .addSelect("salutation.salutation", "salutation") .addSelect("TIMESTAMPDIFF(YEAR, member.birthdate, CURDATE())", "todayAge") .addSelect("YEAR(CURDATE()) - YEAR(member.birthdate)", "ageThisYear") - .addSelect("CONCAT('_', FROM_DAYS(TIMESTAMPDIFF(DAY, member.birthdate, CURDATE())))", "exactAge"), + .addSelect("CONCAT('_', FROM_DAYS(TIMESTAMPDIFF(DAY, member.birthdate, CURDATE())))", "exactAge") + .leftJoin("member.salutation", "salutation"), }) export class memberView { @ViewColumn() id: number; @ViewColumn() - salutation: Salutation; + salutation: string; @ViewColumn() firstname: string; diff --git a/src/views/membershipsView.ts b/src/views/membershipsView.ts index 1e40209..1c764bf 100644 --- a/src/views/membershipsView.ts +++ b/src/views/membershipsView.ts @@ -1,6 +1,5 @@ import { DataSource, ViewColumn, ViewEntity } from "typeorm"; import { membership } from "../entity/club/member/membership"; -import { Salutation } from "../enums/salutation"; @ViewEntity({ expression: (datasource: DataSource) => @@ -10,11 +9,11 @@ import { Salutation } from "../enums/salutation"; .select("status.id", "statusId") .addSelect("status.status", "status") .addSelect("member.id", "memberId") - .addSelect("member.salutation", "memberSalutation") .addSelect("member.firstname", "memberFirstname") .addSelect("member.lastname", "memberLastname") .addSelect("member.nameaffix", "memberNameaffix") .addSelect("member.birthdate", "memberBirthdate") + .addSelect("salutation.salutation", "memberSalutation") .addSelect("SUM(TIMESTAMPDIFF(DAY, membership.start, COALESCE(membership.end, CURRENT_DATE)))", "durationInDays") .addSelect( "CONCAT('_', FROM_DAYS(SUM(TIMESTAMPDIFF(DAY, membership.start, COALESCE(membership.end, CURRENT_DATE)))))", @@ -22,6 +21,7 @@ import { Salutation } from "../enums/salutation"; ) .leftJoin("membership.status", "status") .leftJoin("membership.member", "member") + .leftJoin("member.salutation", "salutation") .groupBy("status.id") .addGroupBy("member.id"), }) @@ -42,7 +42,7 @@ export class membershipView { memberId: number; @ViewColumn() - memberSalutation: Salutation; + memberSalutation: string; @ViewColumn() memberFirstname: string; From b55d0554e44e49f81a911ce53c9674dee375ebe6 Mon Sep 17 00:00:00 2001 From: Julian Krauser Date: Sat, 25 Jan 2025 11:39:34 +0100 Subject: [PATCH 2/2] migration update --- src/data-source.ts | 4 + .../1734520998539-memberDataViews.ts | 194 +++++++-------- .../1736084198860-extendViewValues.ts | 194 ++++++++------- .../1737796878058-salutationAsTable.ts | 91 +++++++ src/migrations/1737800468938-updateViews.ts | 229 ++++++++++++++++++ 5 files changed, 517 insertions(+), 195 deletions(-) create mode 100644 src/migrations/1737796878058-salutationAsTable.ts create mode 100644 src/migrations/1737800468938-updateViews.ts diff --git a/src/data-source.ts b/src/data-source.ts index fff12dd..c016ca4 100644 --- a/src/data-source.ts +++ b/src/data-source.ts @@ -72,6 +72,8 @@ import { webapi } from "./entity/user/webapi"; import { webapiPermission } from "./entity/user/webapi_permission"; import { AddWebapiTokens1737453096674 } from "./migrations/1737453096674-addwebapiTokens"; import { salutation } from "./entity/settings/salutation"; +import { SalutationAsTable1737796878058 } from "./migrations/1737796878058-salutationAsTable"; +import { UpdateViews1737800468938 } from "./migrations/1737800468938-updateViews"; const dataSource = new DataSource({ type: DB_TYPE as any, @@ -154,6 +156,8 @@ const dataSource = new DataSource({ FinishInternalIdTransfer1736505324488, ProtocolPresenceExcuse1737287798828, AddWebapiTokens1737453096674, + SalutationAsTable1737796878058, + UpdateViews1737800468938, ], migrationsRun: true, migrationsTransactionMode: "each", diff --git a/src/migrations/1734520998539-memberDataViews.ts b/src/migrations/1734520998539-memberDataViews.ts index 4e0df38..b29b3e2 100644 --- a/src/migrations/1734520998539-memberDataViews.ts +++ b/src/migrations/1734520998539-memberDataViews.ts @@ -8,105 +8,105 @@ export class MemberDataViews1734520998539 implements MigrationInterface { name = "MemberDataViews1734520998539"; public async up(queryRunner: QueryRunner): Promise { - await queryRunner.createView( - new View({ - name: "member_view", - expression: (datasource: DataSource) => - datasource - .getRepository(member) - .createQueryBuilder("member") - .select("member.id", "id") - .addSelect("member.salutation", "salutation") - .addSelect("member.firstname", "firstname") - .addSelect("member.lastname", "lastname") - .addSelect("member.nameaffix", "nameaffix") - .addSelect("member.birthdate", "birthdate") - .addSelect("TIMESTAMPDIFF(YEAR, member.birthdate, CURDATE())", "todayAge") - .addSelect("YEAR(CURDATE()) - YEAR(member.birthdate)", "ageThisYear"), - }), - true - ); - await queryRunner.createView( - new View({ - name: "member_executive_positions_view", - expression: (datasource: DataSource) => - datasource - .getRepository(memberExecutivePositions) - .createQueryBuilder("memberExecutivePositions") - .select("executivePosition.id", "positionId") - .addSelect("executivePosition.position", "position") - .addSelect("member.id", "memberId") - .addSelect("member.salutation", "memberSalutation") - .addSelect("member.firstname", "memberFirstname") - .addSelect("member.lastname", "memberLastname") - .addSelect("member.nameaffix", "memberNameaffix") - .addSelect("member.birthdate", "memberBirthdate") - .addSelect( - "SUM(TIMESTAMPDIFF(DAY, memberExecutivePositions.start, COALESCE(memberExecutivePositions.end, CURRENT_DATE)))", - "durationInDays" - ) - .leftJoin("memberExecutivePositions.executivePosition", "executivePosition") - .leftJoin("memberExecutivePositions.member", "member") - .groupBy("executivePosition.id"), - }), - true - ); - await queryRunner.createView( - new View({ - name: "member_qualifications_view", - expression: (datasource: DataSource) => - datasource - .getRepository(memberQualifications) - .createQueryBuilder("memberQualifications") - .select("qualification.id", "qualificationId") - .addSelect("qualification.qualification", "qualification") - .addSelect("member.id", "memberId") - .addSelect("member.salutation", "memberSalutation") - .addSelect("member.firstname", "memberFirstname") - .addSelect("member.lastname", "memberLastname") - .addSelect("member.nameaffix", "memberNameaffix") - .addSelect("member.birthdate", "memberBirthdate") - .addSelect( - "SUM(TIMESTAMPDIFF(DAY, memberQualifications.start, COALESCE(memberQualifications.end, CURRENT_DATE)))", - "durationInDays" - ) - .leftJoin("memberQualifications.qualification", "qualification") - .leftJoin("memberQualifications.member", "member") - .groupBy("qualification.id"), - }), - true - ); - await queryRunner.createView( - new View({ - name: "membership_view", - expression: (datasource: DataSource) => - datasource - .getRepository(membership) - .createQueryBuilder("membership") - .select("status.id", "statusId") - .addSelect("status.status", "status") - .addSelect("member.id", "memberId") - .addSelect("member.salutation", "memberSalutation") - .addSelect("member.firstname", "memberFirstname") - .addSelect("member.lastname", "memberLastname") - .addSelect("member.nameaffix", "memberNameaffix") - .addSelect("member.birthdate", "memberBirthdate") - .addSelect( - "SUM(TIMESTAMPDIFF(DAY, membership.start, COALESCE(membership.end, CURRENT_DATE)))", - "durationInDays" - ) - .leftJoin("membership.status", "status") - .leftJoin("membership.member", "member") - .groupBy("status.id"), - }), - true - ); + // await queryRunner.createView( + // new View({ + // name: "member_view", + // expression: (datasource: DataSource) => + // datasource + // .getRepository(member) + // .createQueryBuilder("member") + // .select("member.id", "id") + // .addSelect("member.salutation", "salutation") + // .addSelect("member.firstname", "firstname") + // .addSelect("member.lastname", "lastname") + // .addSelect("member.nameaffix", "nameaffix") + // .addSelect("member.birthdate", "birthdate") + // .addSelect("TIMESTAMPDIFF(YEAR, member.birthdate, CURDATE())", "todayAge") + // .addSelect("YEAR(CURDATE()) - YEAR(member.birthdate)", "ageThisYear"), + // }), + // true + // ); + // await queryRunner.createView( + // new View({ + // name: "member_executive_positions_view", + // expression: (datasource: DataSource) => + // datasource + // .getRepository(memberExecutivePositions) + // .createQueryBuilder("memberExecutivePositions") + // .select("executivePosition.id", "positionId") + // .addSelect("executivePosition.position", "position") + // .addSelect("member.id", "memberId") + // .addSelect("member.salutation", "memberSalutation") + // .addSelect("member.firstname", "memberFirstname") + // .addSelect("member.lastname", "memberLastname") + // .addSelect("member.nameaffix", "memberNameaffix") + // .addSelect("member.birthdate", "memberBirthdate") + // .addSelect( + // "SUM(TIMESTAMPDIFF(DAY, memberExecutivePositions.start, COALESCE(memberExecutivePositions.end, CURRENT_DATE)))", + // "durationInDays" + // ) + // .leftJoin("memberExecutivePositions.executivePosition", "executivePosition") + // .leftJoin("memberExecutivePositions.member", "member") + // .groupBy("executivePosition.id"), + // }), + // true + // ); + // await queryRunner.createView( + // new View({ + // name: "member_qualifications_view", + // expression: (datasource: DataSource) => + // datasource + // .getRepository(memberQualifications) + // .createQueryBuilder("memberQualifications") + // .select("qualification.id", "qualificationId") + // .addSelect("qualification.qualification", "qualification") + // .addSelect("member.id", "memberId") + // .addSelect("member.salutation", "memberSalutation") + // .addSelect("member.firstname", "memberFirstname") + // .addSelect("member.lastname", "memberLastname") + // .addSelect("member.nameaffix", "memberNameaffix") + // .addSelect("member.birthdate", "memberBirthdate") + // .addSelect( + // "SUM(TIMESTAMPDIFF(DAY, memberQualifications.start, COALESCE(memberQualifications.end, CURRENT_DATE)))", + // "durationInDays" + // ) + // .leftJoin("memberQualifications.qualification", "qualification") + // .leftJoin("memberQualifications.member", "member") + // .groupBy("qualification.id"), + // }), + // true + // ); + // await queryRunner.createView( + // new View({ + // name: "membership_view", + // expression: (datasource: DataSource) => + // datasource + // .getRepository(membership) + // .createQueryBuilder("membership") + // .select("status.id", "statusId") + // .addSelect("status.status", "status") + // .addSelect("member.id", "memberId") + // .addSelect("member.salutation", "memberSalutation") + // .addSelect("member.firstname", "memberFirstname") + // .addSelect("member.lastname", "memberLastname") + // .addSelect("member.nameaffix", "memberNameaffix") + // .addSelect("member.birthdate", "memberBirthdate") + // .addSelect( + // "SUM(TIMESTAMPDIFF(DAY, membership.start, COALESCE(membership.end, CURRENT_DATE)))", + // "durationInDays" + // ) + // .leftJoin("membership.status", "status") + // .leftJoin("membership.member", "member") + // .groupBy("status.id"), + // }), + // true + // ); } public async down(queryRunner: QueryRunner): Promise { - await queryRunner.dropView("membership_view"); - await queryRunner.dropView("member_qualifications_view"); - await queryRunner.dropView("member_executive_positions_view"); - await queryRunner.dropView("member_view"); + // await queryRunner.dropView("membership_view"); + // await queryRunner.dropView("member_qualifications_view"); + // await queryRunner.dropView("member_executive_positions_view"); + // await queryRunner.dropView("member_view"); } } diff --git a/src/migrations/1736084198860-extendViewValues.ts b/src/migrations/1736084198860-extendViewValues.ts index 9816a83..4a024c9 100644 --- a/src/migrations/1736084198860-extendViewValues.ts +++ b/src/migrations/1736084198860-extendViewValues.ts @@ -8,106 +8,104 @@ export class ExtendViewValues1736084198860 implements MigrationInterface { name = "ExtendViewValues1736084198860"; public async up(queryRunner: QueryRunner): Promise { - await queryRunner.dropView("membership_view"); - await queryRunner.dropView("member_view"); - - await queryRunner.createView( - new View({ - name: "member_view", - expression: (datasource: DataSource) => - datasource - .getRepository(member) - .createQueryBuilder("member") - .select("member.id", "id") - .addSelect("member.salutation", "salutation") - .addSelect("member.firstname", "firstname") - .addSelect("member.lastname", "lastname") - .addSelect("member.nameaffix", "nameaffix") - .addSelect("member.birthdate", "birthdate") - .addSelect("TIMESTAMPDIFF(YEAR, member.birthdate, CURDATE())", "todayAge") - .addSelect("YEAR(CURDATE()) - YEAR(member.birthdate)", "ageThisYear") - .addSelect("CONCAT('_', FROM_DAYS(TIMESTAMPDIFF(DAY, member.birthdate, CURDATE())))", "exactAge"), - }), - true - ); - await queryRunner.createView( - new View({ - name: "membership_view", - expression: (datasource: DataSource) => - datasource - .getRepository(membership) - .createQueryBuilder("membership") - .select("status.id", "statusId") - .addSelect("status.status", "status") - .addSelect("member.id", "memberId") - .addSelect("member.salutation", "memberSalutation") - .addSelect("member.firstname", "memberFirstname") - .addSelect("member.lastname", "memberLastname") - .addSelect("member.nameaffix", "memberNameaffix") - .addSelect("member.birthdate", "memberBirthdate") - .addSelect( - "SUM(TIMESTAMPDIFF(DAY, membership.start, COALESCE(membership.end, CURRENT_DATE)))", - "durationInDays" - ) - .addSelect( - "CONCAT('_', FROM_DAYS(SUM(TIMESTAMPDIFF(DAY, membership.start, COALESCE(membership.end, CURRENT_DATE)))))", - "durationInYears" - ) - .leftJoin("membership.status", "status") - .leftJoin("membership.member", "member") - .groupBy("status.id") - .addGroupBy("member.id"), - }), - true - ); + // await queryRunner.dropView("membership_view"); + // await queryRunner.dropView("member_view"); + // await queryRunner.createView( + // new View({ + // name: "member_view", + // expression: (datasource: DataSource) => + // datasource + // .getRepository(member) + // .createQueryBuilder("member") + // .select("member.id", "id") + // .addSelect("member.salutation", "salutation") + // .addSelect("member.firstname", "firstname") + // .addSelect("member.lastname", "lastname") + // .addSelect("member.nameaffix", "nameaffix") + // .addSelect("member.birthdate", "birthdate") + // .addSelect("TIMESTAMPDIFF(YEAR, member.birthdate, CURDATE())", "todayAge") + // .addSelect("YEAR(CURDATE()) - YEAR(member.birthdate)", "ageThisYear") + // .addSelect("CONCAT('_', FROM_DAYS(TIMESTAMPDIFF(DAY, member.birthdate, CURDATE())))", "exactAge"), + // }), + // true + // ); + // await queryRunner.createView( + // new View({ + // name: "membership_view", + // expression: (datasource: DataSource) => + // datasource + // .getRepository(membership) + // .createQueryBuilder("membership") + // .select("status.id", "statusId") + // .addSelect("status.status", "status") + // .addSelect("member.id", "memberId") + // .addSelect("member.salutation", "memberSalutation") + // .addSelect("member.firstname", "memberFirstname") + // .addSelect("member.lastname", "memberLastname") + // .addSelect("member.nameaffix", "memberNameaffix") + // .addSelect("member.birthdate", "memberBirthdate") + // .addSelect( + // "SUM(TIMESTAMPDIFF(DAY, membership.start, COALESCE(membership.end, CURRENT_DATE)))", + // "durationInDays" + // ) + // .addSelect( + // "CONCAT('_', FROM_DAYS(SUM(TIMESTAMPDIFF(DAY, membership.start, COALESCE(membership.end, CURRENT_DATE)))))", + // "durationInYears" + // ) + // .leftJoin("membership.status", "status") + // .leftJoin("membership.member", "member") + // .groupBy("status.id") + // .addGroupBy("member.id"), + // }), + // true + // ); } public async down(queryRunner: QueryRunner): Promise { - await queryRunner.dropView("membership_view"); - await queryRunner.dropView("member_view"); - - await queryRunner.createView( - new View({ - name: "member_view", - expression: (datasource: DataSource) => - datasource - .getRepository(member) - .createQueryBuilder("member") - .select("member.id", "id") - .addSelect("member.salutation", "salutation") - .addSelect("member.firstname", "firstname") - .addSelect("member.lastname", "lastname") - .addSelect("member.nameaffix", "nameaffix") - .addSelect("member.birthdate", "birthdate") - .addSelect("TIMESTAMPDIFF(YEAR, member.birthdate, CURDATE())", "todayAge") - .addSelect("YEAR(CURDATE()) - YEAR(member.birthdate)", "ageThisYear"), - }), - true - ); - await queryRunner.createView( - new View({ - name: "membership_view", - expression: (datasource: DataSource) => - datasource - .getRepository(membership) - .createQueryBuilder("membership") - .select("status.id", "statusId") - .addSelect("status.status", "status") - .addSelect("member.id", "memberId") - .addSelect("member.salutation", "memberSalutation") - .addSelect("member.firstname", "memberFirstname") - .addSelect("member.lastname", "memberLastname") - .addSelect("member.nameaffix", "memberNameaffix") - .addSelect("member.birthdate", "memberBirthdate") - .addSelect( - "SUM(TIMESTAMPDIFF(DAY, membership.start, COALESCE(membership.end, CURRENT_DATE)))", - "durationInDays" - ) - .leftJoin("membership.status", "status") - .leftJoin("membership.member", "member") - .groupBy("status.id"), - }), - true - ); + // await queryRunner.dropView("membership_view"); + // await queryRunner.dropView("member_view"); + // await queryRunner.createView( + // new View({ + // name: "member_view", + // expression: (datasource: DataSource) => + // datasource + // .getRepository(member) + // .createQueryBuilder("member") + // .select("member.id", "id") + // .addSelect("member.salutation", "salutation") + // .addSelect("member.firstname", "firstname") + // .addSelect("member.lastname", "lastname") + // .addSelect("member.nameaffix", "nameaffix") + // .addSelect("member.birthdate", "birthdate") + // .addSelect("TIMESTAMPDIFF(YEAR, member.birthdate, CURDATE())", "todayAge") + // .addSelect("YEAR(CURDATE()) - YEAR(member.birthdate)", "ageThisYear"), + // }), + // true + // ); + // await queryRunner.createView( + // new View({ + // name: "membership_view", + // expression: (datasource: DataSource) => + // datasource + // .getRepository(membership) + // .createQueryBuilder("membership") + // .select("status.id", "statusId") + // .addSelect("status.status", "status") + // .addSelect("member.id", "memberId") + // .addSelect("member.salutation", "memberSalutation") + // .addSelect("member.firstname", "memberFirstname") + // .addSelect("member.lastname", "memberLastname") + // .addSelect("member.nameaffix", "memberNameaffix") + // .addSelect("member.birthdate", "memberBirthdate") + // .addSelect( + // "SUM(TIMESTAMPDIFF(DAY, membership.start, COALESCE(membership.end, CURRENT_DATE)))", + // "durationInDays" + // ) + // .leftJoin("membership.status", "status") + // .leftJoin("membership.member", "member") + // .groupBy("status.id"), + // }), + // true + // ); } } diff --git a/src/migrations/1737796878058-salutationAsTable.ts b/src/migrations/1737796878058-salutationAsTable.ts new file mode 100644 index 0000000..df84a91 --- /dev/null +++ b/src/migrations/1737796878058-salutationAsTable.ts @@ -0,0 +1,91 @@ +import { MigrationInterface, QueryRunner, Table, TableForeignKey } from "typeorm"; +import { DB_TYPE } from "../env.defaults"; +import { member } from "../entity/club/member/member"; +import { salutation } from "../entity/settings/salutation"; + +export class SalutationAsTable1737796878058 implements MigrationInterface { + name = "SalutationAsTable1737796878058"; + + public async up(queryRunner: QueryRunner): Promise { + const variableType_int = DB_TYPE == "mysql" ? "int" : "integer"; + + await queryRunner.createTable( + new Table({ + name: "salutation", + columns: [ + { name: "id", type: variableType_int, isPrimary: true, isGenerated: true, generationStrategy: "increment" }, + { name: "salutation", type: "varchar", length: "255", isUnique: true, isNullable: false }, + ], + }), + true + ); + + // ! has to be sql. Else the column would be dropped and created - resulting in data loss. + await queryRunner.query( + `ALTER TABLE \`member\` CHANGE \`salutation\` \`salutationId\` varchar(255) NOT NULL DEFAULT ''` + ); + + // ! has to be sql. Else no data is returned. + const existing_salutations = await queryRunner.query( + "SELECT DISTINCT salutationId FROM `member` `member` GROUP BY salutationId" + ); + + for (let s of existing_salutations.map((s: any) => s.salutationId) as Array) { + await queryRunner.manager.getRepository(salutation).save({ salutation: s }); + } + + const salutations = await queryRunner.manager.getRepository(salutation).find(); + + for (let salutation of salutations) { + await queryRunner.manager + .getRepository(member) + .createQueryBuilder("member") + .update({ salutationId: salutation.id }) + .where({ salutationId: salutation.salutation }) + .execute(); + } + + await queryRunner.query( + `ALTER TABLE \`member\` CHANGE \`salutationId\` \`salutationId\` ${variableType_int} NOT NULL` + ); + + await queryRunner.createForeignKey( + "member", + new TableForeignKey({ + columnNames: ["salutationId"], + referencedColumnNames: ["id"], + referencedTableName: "salutation", + onDelete: "RESTRICT", + onUpdate: "RESTRICT", + }) + ); + } + + public async down(queryRunner: QueryRunner): Promise { + const table = await queryRunner.getTable("member"); + const foreignKey = table.foreignKeys.find((fk) => fk.columnNames.indexOf("salutationId") !== -1); + await queryRunner.dropForeignKey("member", foreignKey); + + // ! has to be sql. Else the column would be dropped and created - resulting in data loss. + await queryRunner.query( + `ALTER TABLE \`member\` CHANGE \`salutationId\` \`salutationId\` varchar(255) NOT NULL DEFAULT ''` + ); + + const salutations = await queryRunner.manager.getRepository(salutation).find(); + + for (let salutation of salutations) { + await queryRunner.manager + .getRepository(member) + .createQueryBuilder("member") + .update({ salutationId: salutation.salutation as unknown as number }) + .where({ salutationId: salutation.id }) + .execute(); + } + + await queryRunner.query( + `ALTER TABLE \`member\` CHANGE \`salutationId\` \`salutation\` varchar(255) NOT NULL DEFAULT 'none'` + ); + + await queryRunner.dropTable("webapi"); + } +} diff --git a/src/migrations/1737800468938-updateViews.ts b/src/migrations/1737800468938-updateViews.ts new file mode 100644 index 0000000..64587af --- /dev/null +++ b/src/migrations/1737800468938-updateViews.ts @@ -0,0 +1,229 @@ +import { DataSource, MigrationInterface, QueryRunner, View } from "typeorm"; +import { member } from "../entity/club/member/member"; +import { memberExecutivePositions } from "../entity/club/member/memberExecutivePositions"; +import { memberQualifications } from "../entity/club/member/memberQualifications"; +import { membership } from "../entity/club/member/membership"; + +export class UpdateViews1737800468938 implements MigrationInterface { + name = "UpdateViews1737800468938"; + + public async up(queryRunner: QueryRunner): Promise { + // await queryRunner.dropView("membership_view"); + // await queryRunner.dropView("member_executive_positions_view"); + // await queryRunner.dropView("member_qualifications_view"); + // await queryRunner.dropView("member_view"); + + await queryRunner.createView( + new View({ + name: "member_view", + expression: (datasource: DataSource) => + datasource + .getRepository(member) + .createQueryBuilder("member") + .select("member.id", "id") + .addSelect("member.firstname", "firstname") + .addSelect("member.lastname", "lastname") + .addSelect("member.nameaffix", "nameaffix") + .addSelect("member.birthdate", "birthdate") + .addSelect("salutation.salutation", "salutation") + .addSelect("TIMESTAMPDIFF(YEAR, member.birthdate, CURDATE())", "todayAge") + .addSelect("YEAR(CURDATE()) - YEAR(member.birthdate)", "ageThisYear") + .addSelect("CONCAT('_', FROM_DAYS(TIMESTAMPDIFF(DAY, member.birthdate, CURDATE())))", "exactAge") + .leftJoin("member.salutation", "salutation"), + }), + true + ); + await queryRunner.createView( + new View({ + name: "member_executive_positions_view", + expression: (datasource: DataSource) => + datasource + .getRepository(memberExecutivePositions) + .createQueryBuilder("memberExecutivePositions") + .select("executivePosition.id", "positionId") + .addSelect("executivePosition.position", "position") + .addSelect("member.id", "memberId") + .addSelect("member.firstname", "memberFirstname") + .addSelect("member.lastname", "memberLastname") + .addSelect("member.nameaffix", "memberNameaffix") + .addSelect("member.birthdate", "memberBirthdate") + .addSelect("salutation.salutation", "memberSalutation") + .addSelect( + "SUM(TIMESTAMPDIFF(DAY, memberExecutivePositions.start, COALESCE(memberExecutivePositions.end, CURRENT_DATE)))", + "durationInDays" + ) + .leftJoin("memberExecutivePositions.executivePosition", "executivePosition") + .leftJoin("memberExecutivePositions.member", "member") + .leftJoin("member.salutation", "salutation") + .groupBy("executivePosition.id") + .addGroupBy("member.id"), + }), + true + ); + await queryRunner.createView( + new View({ + name: "member_qualifications_view", + expression: (datasource: DataSource) => + datasource + .getRepository(memberQualifications) + .createQueryBuilder("memberQualifications") + .select("qualification.id", "qualificationId") + .addSelect("qualification.qualification", "qualification") + .addSelect("member.id", "memberId") + .addSelect("member.firstname", "memberFirstname") + .addSelect("member.lastname", "memberLastname") + .addSelect("member.nameaffix", "memberNameaffix") + .addSelect("member.birthdate", "memberBirthdate") + .addSelect("salutation.salutation", "memberSalutation") + .addSelect( + "SUM(TIMESTAMPDIFF(DAY, memberQualifications.start, COALESCE(memberQualifications.end, CURRENT_DATE)))", + "durationInDays" + ) + .leftJoin("memberQualifications.qualification", "qualification") + .leftJoin("memberQualifications.member", "member") + .leftJoin("member.salutation", "salutation") + .groupBy("qualification.id") + .addGroupBy("member.id"), + }), + true + ); + await queryRunner.createView( + new View({ + name: "membership_view", + expression: (datasource: DataSource) => + datasource + .getRepository(membership) + .createQueryBuilder("membership") + .select("status.id", "statusId") + .addSelect("status.status", "status") + .addSelect("member.id", "memberId") + .addSelect("member.firstname", "memberFirstname") + .addSelect("member.lastname", "memberLastname") + .addSelect("member.nameaffix", "memberNameaffix") + .addSelect("member.birthdate", "memberBirthdate") + .addSelect("salutation.salutation", "memberSalutation") + .addSelect( + "SUM(TIMESTAMPDIFF(DAY, membership.start, COALESCE(membership.end, CURRENT_DATE)))", + "durationInDays" + ) + .addSelect( + "CONCAT('_', FROM_DAYS(SUM(TIMESTAMPDIFF(DAY, membership.start, COALESCE(membership.end, CURRENT_DATE)))))", + "durationInYears" + ) + .leftJoin("membership.status", "status") + .leftJoin("membership.member", "member") + .leftJoin("member.salutation", "salutation") + .groupBy("status.id") + .addGroupBy("member.id"), + }), + true + ); + } + + public async down(queryRunner: QueryRunner): Promise { + await queryRunner.dropView("membership_view"); + await queryRunner.dropView("member_executive_positions_view"); + await queryRunner.dropView("member_qualifications_view"); + await queryRunner.dropView("member_view"); + + await queryRunner.createView( + new View({ + name: "member_view", + expression: (datasource: DataSource) => + datasource + .getRepository(member) + .createQueryBuilder("member") + .select("member.id", "id") + .addSelect("member.salutation", "salutation") + .addSelect("member.firstname", "firstname") + .addSelect("member.lastname", "lastname") + .addSelect("member.nameaffix", "nameaffix") + .addSelect("member.birthdate", "birthdate") + .addSelect("TIMESTAMPDIFF(YEAR, member.birthdate, CURDATE())", "todayAge") + .addSelect("YEAR(CURDATE()) - YEAR(member.birthdate)", "ageThisYear") + .addSelect("CONCAT('_', FROM_DAYS(TIMESTAMPDIFF(DAY, member.birthdate, CURDATE())))", "exactAge"), + }), + true + ); + await queryRunner.createView( + new View({ + name: "member_executive_positions_view", + expression: (datasource: DataSource) => + datasource + .getRepository(memberExecutivePositions) + .createQueryBuilder("memberExecutivePositions") + .select("executivePosition.id", "positionId") + .addSelect("executivePosition.position", "position") + .addSelect("member.id", "memberId") + .addSelect("member.salutation", "memberSalutation") + .addSelect("member.firstname", "memberFirstname") + .addSelect("member.lastname", "memberLastname") + .addSelect("member.nameaffix", "memberNameaffix") + .addSelect("member.birthdate", "memberBirthdate") + .addSelect( + "SUM(TIMESTAMPDIFF(DAY, memberExecutivePositions.start, COALESCE(memberExecutivePositions.end, CURRENT_DATE)))", + "durationInDays" + ) + .leftJoin("memberExecutivePositions.executivePosition", "executivePosition") + .leftJoin("memberExecutivePositions.member", "member") + .groupBy("executivePosition.id"), + }), + true + ); + await queryRunner.createView( + new View({ + name: "member_qualifications_view", + expression: (datasource: DataSource) => + datasource + .getRepository(memberQualifications) + .createQueryBuilder("memberQualifications") + .select("qualification.id", "qualificationId") + .addSelect("qualification.qualification", "qualification") + .addSelect("member.id", "memberId") + .addSelect("member.salutation", "memberSalutation") + .addSelect("member.firstname", "memberFirstname") + .addSelect("member.lastname", "memberLastname") + .addSelect("member.nameaffix", "memberNameaffix") + .addSelect("member.birthdate", "memberBirthdate") + .addSelect( + "SUM(TIMESTAMPDIFF(DAY, memberQualifications.start, COALESCE(memberQualifications.end, CURRENT_DATE)))", + "durationInDays" + ) + .leftJoin("memberQualifications.qualification", "qualification") + .leftJoin("memberQualifications.member", "member") + .groupBy("qualification.id"), + }), + true + ); + await queryRunner.createView( + new View({ + name: "membership_view", + expression: (datasource: DataSource) => + datasource + .getRepository(membership) + .createQueryBuilder("membership") + .select("status.id", "statusId") + .addSelect("status.status", "status") + .addSelect("member.id", "memberId") + .addSelect("member.salutation", "memberSalutation") + .addSelect("member.firstname", "memberFirstname") + .addSelect("member.lastname", "memberLastname") + .addSelect("member.nameaffix", "memberNameaffix") + .addSelect("member.birthdate", "memberBirthdate") + .addSelect( + "SUM(TIMESTAMPDIFF(DAY, membership.start, COALESCE(membership.end, CURRENT_DATE)))", + "durationInDays" + ) + .addSelect( + "CONCAT('_', FROM_DAYS(SUM(TIMESTAMPDIFF(DAY, membership.start, COALESCE(membership.end, CURRENT_DATE)))))", + "durationInYears" + ) + .leftJoin("membership.status", "status") + .leftJoin("membership.member", "member") + .groupBy("status.id") + .addGroupBy("member.id"), + }), + true + ); + } +}