diff --git a/apps/api/src/app/import/import.helper.ts b/apps/api/src/app/import/import.helper.ts new file mode 100644 index 000000000..fb7895cb4 --- /dev/null +++ b/apps/api/src/app/import/import.helper.ts @@ -0,0 +1,34 @@ +import { getAssetProfileIdentifier } from '@ghostfolio/common/helper'; +import { Activity } from '@ghostfolio/common/interfaces'; + +import { AssetProfileToCreate } from './interfaces/interfaces'; + +/** + * Returns the asset profiles which at least one activity of the import uses. + * The asset profiles are created after the validation of the activities, + * thus an asset profile of an activity which is not imported must not be + * created. + */ +export function getAssetProfilesToCreate({ + activities, + assetProfiles +}: { + activities: Partial[]; + assetProfiles: AssetProfileToCreate[]; +}) { + const assetProfileIdentifiersToImport = new Set( + activities + .filter(({ error }) => { + return !error; + }) + .map(({ assetProfile }) => { + return getAssetProfileIdentifier(assetProfile); + }) + ); + + return assetProfiles.filter(({ assetProfile }) => { + return assetProfileIdentifiersToImport.has( + getAssetProfileIdentifier(assetProfile) + ); + }); +} diff --git a/apps/api/src/app/import/import.service.ts b/apps/api/src/app/import/import.service.ts index 5d3574fbf..aa34b24e9 100644 --- a/apps/api/src/app/import/import.service.ts +++ b/apps/api/src/app/import/import.service.ts @@ -48,6 +48,8 @@ import { omit, uniqBy } from 'lodash'; import { randomUUID } from 'node:crypto'; import { ImportDataDto } from './import-data.dto'; +import { getAssetProfilesToCreate } from './import.helper'; +import { AssetProfileToCreate } from './interfaces/interfaces'; @Injectable() export class ImportService { @@ -534,10 +536,7 @@ export class ImportService { } } - const assetProfilesToCreate: { - assetProfile: Prisma.SymbolProfileCreateInput; - marketDataObjects: Prisma.MarketDataUpdateInput[]; - }[] = []; + const assetProfilesToCreate: AssetProfileToCreate[] = []; if (assetProfilesWithMarketDataDto?.length) { const customAssetProfileNames = assetProfilesWithMarketDataDto @@ -738,16 +737,18 @@ export class ImportService { // duplicate. An asset profile which is created before the validation of // the activities would stay behind, because the import is not rolled back // on an error. - for (const { - assetProfile, - marketDataObjects - } of this.getAssetProfilesToCreate({ - activities: activitiesExtendedWithErrors, - assetProfiles: assetProfilesToCreate - })) { - await this.symbolProfileService.add(assetProfile); - - await this.marketDataService.updateMany({ data: marketDataObjects }); + if (!isDryRun) { + for (const { + assetProfile, + marketDataObjects + } of getAssetProfilesToCreate({ + activities: activitiesExtendedWithErrors, + assetProfiles: assetProfilesToCreate + })) { + await this.symbolProfileService.add(assetProfile); + + await this.marketDataService.updateMany({ data: marketDataObjects }); + } } const activities: Activity[] = []; @@ -1086,39 +1087,6 @@ export class ImportService { return matchingAccountsOfUser[0]; } - /** - * Returns the asset profiles which at least one activity of the import uses. - * The asset profiles are created after the validation of the activities, - * thus an asset profile of an activity which is not imported must not be - * created. - */ - private getAssetProfilesToCreate({ - activities, - assetProfiles - }: { - activities: Partial[]; - assetProfiles: { - assetProfile: Prisma.SymbolProfileCreateInput; - marketDataObjects: Prisma.MarketDataUpdateInput[]; - }[]; - }) { - const assetProfileIdentifiersToImport = new Set( - activities - .filter(({ error }) => { - return !error; - }) - .map(({ assetProfile }) => { - return getAssetProfileIdentifier(assetProfile); - }) - ); - - return assetProfiles.filter(({ assetProfile }) => { - return assetProfileIdentifiersToImport.has( - getAssetProfileIdentifier(assetProfile) - ); - }); - } - private isUniqueAccount(accounts: AccountWithValue[]) { const uniqueAccountIds = new Set(); diff --git a/apps/api/src/app/import/interfaces/interfaces.ts b/apps/api/src/app/import/interfaces/interfaces.ts new file mode 100644 index 000000000..2787b7eb1 --- /dev/null +++ b/apps/api/src/app/import/interfaces/interfaces.ts @@ -0,0 +1,6 @@ +import { Prisma } from '@prisma/client'; + +export interface AssetProfileToCreate { + assetProfile: Prisma.SymbolProfileCreateInput; + marketDataObjects: Prisma.MarketDataUpdateInput[]; +} diff --git a/apps/api/src/services/data-provider/data-provider.service.ts b/apps/api/src/services/data-provider/data-provider.service.ts index 102b80d56..0912fd4f7 100644 --- a/apps/api/src/services/data-provider/data-provider.service.ts +++ b/apps/api/src/services/data-provider/data-provider.service.ts @@ -273,10 +273,10 @@ export class DataProviderService implements OnModuleInit { if (!assetProfiles[assetProfileIdentifier]) { const assetProfileInImport = assetProfilesWithMarketDataDto?.find( - (assetProfile) => { + (assetProfileWithMarketData) => { return ( - assetProfile.dataSource === dataSource && - assetProfile.symbol === symbol + assetProfileWithMarketData.dataSource === dataSource && + assetProfileWithMarketData.symbol === symbol ); } );