From 34361e2f2f341a59b3a29dd99d275515c0c422d4 Mon Sep 17 00:00:00 2001 From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com> Date: Sun, 2 Aug 2026 16:08:00 +0200 Subject: [PATCH] Refactoring --- .../asset-profiles.controller.ts | 3 +- .../asset-profiles/asset-profiles.service.ts | 13 ++--- .../asset-profile-split.service.ts | 47 ++++++------------ .../asset-profile-dialog.component.ts | 36 +++++++++----- .../asset-profile-dialog.html | 27 ++++++++--- .../dtos/create-asset-profile-split.dto.ts | 28 +++++++---- libs/common/src/lib/helper.spec.ts | 48 ++++++++++++------- libs/common/src/lib/helper.ts | 23 +++++++-- .../validator-constraints/is-split-factor.ts | 17 ------- .../validator-constraints/is-split-ratio.ts | 18 +++++++ .../migration.sql | 3 +- prisma/schema.prisma | 14 ++++-- 12 files changed, 163 insertions(+), 114 deletions(-) delete mode 100644 libs/common/src/lib/validator-constraints/is-split-factor.ts create mode 100644 libs/common/src/lib/validator-constraints/is-split-ratio.ts diff --git a/apps/api/src/app/endpoints/asset-profiles/asset-profiles.controller.ts b/apps/api/src/app/endpoints/asset-profiles/asset-profiles.controller.ts index 62c1b15bac..dd050f6d03 100644 --- a/apps/api/src/app/endpoints/asset-profiles/asset-profiles.controller.ts +++ b/apps/api/src/app/endpoints/asset-profiles/asset-profiles.controller.ts @@ -144,7 +144,8 @@ export class AssetProfilesController { return this.assetProfilesService.createSplit({ symbolProfileId, date: parseISO(data.date), - factor: data.factor + denominator: data.denominator, + numerator: data.numerator }); } diff --git a/apps/api/src/app/endpoints/asset-profiles/asset-profiles.service.ts b/apps/api/src/app/endpoints/asset-profiles/asset-profiles.service.ts index 639fe6278a..7d75fc40bb 100644 --- a/apps/api/src/app/endpoints/asset-profiles/asset-profiles.service.ts +++ b/apps/api/src/app/endpoints/asset-profiles/asset-profiles.service.ts @@ -42,16 +42,19 @@ export class AssetProfilesService { public async createSplit({ date, - factor, + denominator, + numerator, symbolProfileId }: { date: Date; - factor: number; + denominator: number; + numerator: number; symbolProfileId: string; }) { return this.assetProfileSplitService.upsert({ date, - factor, + denominator, + numerator, symbolProfileId }); } @@ -105,9 +108,7 @@ export class AssetProfilesService { symbol } }), - this.assetProfileSplitService.getSplits({ - assetProfileIdentifiers: [{ dataSource, symbol }] - }) + this.assetProfileSplitService.getSplits({ dataSource, symbol }) ]); if (assetProfile) { diff --git a/apps/api/src/services/asset-profile-split/asset-profile-split.service.ts b/apps/api/src/services/asset-profile-split/asset-profile-split.service.ts index 46023fccde..ec842caaf5 100644 --- a/apps/api/src/services/asset-profile-split/asset-profile-split.service.ts +++ b/apps/api/src/services/asset-profile-split/asset-profile-split.service.ts @@ -5,10 +5,6 @@ import { AssetProfileIdentifier } from '@ghostfolio/common/interfaces'; import { Injectable } from '@nestjs/common'; import { AssetProfileSplit } from '@prisma/client'; -export type AssetProfileSplitWithAssetProfileIdentifier = AssetProfileSplit & { - symbolProfile: AssetProfileIdentifier; -}; - @Injectable() export class AssetProfileSplitService { public constructor(private readonly prismaService: PrismaService) {} @@ -35,28 +31,13 @@ export class AssetProfileSplitService { } /** - * Returns the splits of the given asset profiles in ascending order by date. - * Each split carries the identifier of its asset profile so that the result - * can be grouped when querying multiple asset profiles at once. + * Returns the splits of the given asset profile in ascending order by date */ public async getSplits({ - assetProfileIdentifiers - }: { - assetProfileIdentifiers: AssetProfileIdentifier[]; - }): Promise { - if (assetProfileIdentifiers.length === 0) { - return []; - } - + dataSource, + symbol + }: AssetProfileIdentifier): Promise { return this.prismaService.assetProfileSplit.findMany({ - include: { - symbolProfile: { - select: { - dataSource: true, - symbol: true - } - } - }, orderBy: [ { date: 'asc' @@ -64,12 +45,8 @@ export class AssetProfileSplitService { ], where: { symbolProfile: { - OR: assetProfileIdentifiers.map(({ dataSource, symbol }) => { - return { - dataSource, - symbol - }; - }) + dataSource, + symbol } } }); @@ -77,23 +54,27 @@ export class AssetProfileSplitService { public async upsert({ date, - factor, + denominator, + numerator, symbolProfileId }: { date: Date; - factor: number; + denominator: number; + numerator: number; symbolProfileId: string; }): Promise { const dateOfSplit = resetHours(date); return this.prismaService.assetProfileSplit.upsert({ create: { - factor, + denominator, + numerator, symbolProfileId, date: dateOfSplit }, update: { - factor + denominator, + numerator }, where: { symbolProfileId_date: { diff --git a/apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts b/apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts index d4d23e9ef9..7e91696c0c 100644 --- a/apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts +++ b/apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts @@ -15,7 +15,7 @@ import { getStringOrNull, getStringOrUndefined, isCurrency, - isSplitFactor + isSplitRatio } from '@ghostfolio/common/helper'; import { AdminMarketDataDetails, @@ -204,17 +204,25 @@ export class GfAssetProfileDialogComponent implements OnInit { } ); - protected readonly assetProfileSplitForm = this.formBuilder.group({ - date: new FormControl(null, Validators.required), - factor: new FormControl(null, [ - Validators.required, - (control: AbstractControl): ValidationErrors | null => { - return isSplitFactor(control.value) + protected readonly assetProfileSplitForm = this.formBuilder.group( + { + date: new FormControl(null, Validators.required), + denominator: new FormControl(null, Validators.required), + numerator: new FormControl(null, Validators.required) + }, + { + validators: (control: AbstractControl): ValidationErrors | null => { + const { denominator, numerator } = control.value as { + denominator: number; + numerator: number; + }; + + return isSplitRatio({ denominator, numerator }) ? null - : { invalidSplitFactor: true }; + : { invalidSplitRatio: true }; } - ]) - }); + } + ); protected readonly canDeleteAssetProfile = canDeleteAssetProfile; protected canEditAssetProfile = true; @@ -550,9 +558,10 @@ export class GfAssetProfileDialogComponent implements OnInit { } protected onAddSplit() { - const { date, factor } = this.assetProfileSplitForm.getRawValue(); + const { date, denominator, numerator } = + this.assetProfileSplitForm.getRawValue(); - if (!date || !factor) { + if (!date || !denominator || !numerator) { return; } @@ -560,7 +569,8 @@ export class GfAssetProfileDialogComponent implements OnInit { .postAssetProfileSplit({ dataSource: this.data.dataSource, split: { - factor, + denominator, + numerator, date: format(date, DATE_FORMAT) }, symbol: this.data.symbol diff --git a/apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html b/apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html index 74514a50d8..f79dd8ddab 100644 --- a/apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html +++ b/apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html @@ -527,7 +527,7 @@ class="mat-mdc-header-cell px-1 py-2 text-right" i18n > - Split Factor + Split Ratio @@ -539,7 +539,7 @@ {{ split.date | date: defaultDateFormat }} - {{ split.factor }} + {{ split.numerator }}:{{ split.denominator }}