From 099ad18aaf1ae6d4bf83546a9bd0fc13a4a81e61 Mon Sep 17 00:00:00 2001 From: Valentin Zickner <3200232+vzickner@users.noreply.github.com> Date: Wed, 20 Oct 2021 15:41:40 -0400 Subject: [PATCH] refactor data-provider.service.ts to have dynamic list of services (#429) * Refactor data-provider.service.ts to have dynamic list of services * Update changelog Co-authored-by: Valentin Zickner Co-authored-by: Thomas <4159106+dtslvr@users.noreply.github.com> --- CHANGELOG.md | 6 ++++ .../portfolio/current-rate.service.spec.ts | 10 +----- .../alpha-vantage/alpha-vantage.service.ts | 4 +++ .../data-provider/data-provider.module.ts | 20 +++++++++++ .../data-provider/data-provider.service.ts | 34 ++++++------------- .../ghostfolio-scraper-api.service.ts | 4 +++ .../interfaces/data-provider.interface.ts | 3 ++ .../rakuten-rapid-api.service.ts | 13 ++++--- .../yahoo-finance/yahoo-finance.service.ts | 4 +++ 9 files changed, 58 insertions(+), 40 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 33181786c..43275ac61 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,12 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## Unreleased + +### Changed + +- Changed the data provider service to handle a dynamic list of services + ## 1.63.0 - 19.10.2021 ### Added diff --git a/apps/api/src/app/portfolio/current-rate.service.spec.ts b/apps/api/src/app/portfolio/current-rate.service.spec.ts index 7795552eb..5521faf04 100644 --- a/apps/api/src/app/portfolio/current-rate.service.spec.ts +++ b/apps/api/src/app/portfolio/current-rate.service.spec.ts @@ -72,15 +72,7 @@ describe('CurrentRateService', () => { let marketDataService: MarketDataService; beforeAll(async () => { - dataProviderService = new DataProviderService( - null, - null, - [], - null, - null, - null, - null - ); + dataProviderService = new DataProviderService(null, [], [], null); exchangeRateDataService = new ExchangeRateDataService(null, null); marketDataService = new MarketDataService(null); diff --git a/apps/api/src/services/data-provider/alpha-vantage/alpha-vantage.service.ts b/apps/api/src/services/data-provider/alpha-vantage/alpha-vantage.service.ts index 6482c4522..3719fbe7c 100644 --- a/apps/api/src/services/data-provider/alpha-vantage/alpha-vantage.service.ts +++ b/apps/api/src/services/data-provider/alpha-vantage/alpha-vantage.service.ts @@ -84,6 +84,10 @@ export class AlphaVantageService implements DataProviderInterface { } } + public getName(): DataSource { + return DataSource.ALPHA_VANTAGE; + } + public async search(aSymbol: string): Promise<{ items: LookupItem[] }> { const result = await this.alphaVantage.data.search(aSymbol); diff --git a/apps/api/src/services/data-provider/data-provider.module.ts b/apps/api/src/services/data-provider/data-provider.module.ts index 9e3e57fd4..9ade183a5 100644 --- a/apps/api/src/services/data-provider/data-provider.module.ts +++ b/apps/api/src/services/data-provider/data-provider.module.ts @@ -22,6 +22,26 @@ import { DataProviderService } from './data-provider.service'; inject: [TrackinsightDataEnhancerService], provide: 'DataEnhancers', useFactory: (trackinsight) => [trackinsight] + }, + { + inject: [ + AlphaVantageService, + GhostfolioScraperApiService, + RakutenRapidApiService, + YahooFinanceService + ], + provide: 'DataProviderInterfaces', + useFactory: ( + alphaVantageService, + ghostfolioScraperApiService, + rakutenRapidApiService, + yahooFinanceService + ) => [ + alphaVantageService, + ghostfolioScraperApiService, + rakutenRapidApiService, + yahooFinanceService + ] } ], exports: [DataProviderService, GhostfolioScraperApiService] 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 efb2a4ec0..bba2b8b82 100644 --- a/apps/api/src/services/data-provider/data-provider.service.ts +++ b/apps/api/src/services/data-provider/data-provider.service.ts @@ -13,26 +13,18 @@ import { Inject, Injectable } from '@nestjs/common'; import { DataSource, MarketData } from '@prisma/client'; import { format } from 'date-fns'; import { isEmpty } from 'lodash'; - -import { AlphaVantageService } from './alpha-vantage/alpha-vantage.service'; -import { GhostfolioScraperApiService } from './ghostfolio-scraper-api/ghostfolio-scraper-api.service'; -import { RakutenRapidApiService } from './rakuten-rapid-api/rakuten-rapid-api.service'; -import { YahooFinanceService } from './yahoo-finance/yahoo-finance.service'; +import { DataProviderInterface } from '@ghostfolio/api/services/data-provider/interfaces/data-provider.interface'; @Injectable() export class DataProviderService { public constructor( - private readonly alphaVantageService: AlphaVantageService, private readonly configurationService: ConfigurationService, @Inject('DataEnhancers') private readonly dataEnhancers: DataEnhancerInterface[], - private readonly ghostfolioScraperApiService: GhostfolioScraperApiService, - private readonly prismaService: PrismaService, - private readonly rakutenRapidApiService: RakutenRapidApiService, - private readonly yahooFinanceService: YahooFinanceService - ) { - this.rakutenRapidApiService?.setPrisma(this.prismaService); - } + @Inject('DataProviderInterfaces') + private readonly dataProviderInterfaces: DataProviderInterface[], + private readonly prismaService: PrismaService + ) {} public async get(items: IDataGatheringItem[]): Promise<{ [symbol: string]: IDataProviderResponse; @@ -204,17 +196,11 @@ export class DataProviderService { } private getDataProvider(providerName: DataSource) { - switch (providerName) { - case DataSource.ALPHA_VANTAGE: - return this.alphaVantageService; - case DataSource.GHOSTFOLIO: - return this.ghostfolioScraperApiService; - case DataSource.RAKUTEN: - return this.rakutenRapidApiService; - case DataSource.YAHOO: - return this.yahooFinanceService; - default: - throw new Error('No data provider has been found.'); + for (const dataProviderInterface of this.dataProviderInterfaces) { + if (dataProviderInterface.getName() === providerName) { + return dataProviderInterface; + } } + throw new Error('No data provider has been found.'); } } diff --git a/apps/api/src/services/data-provider/ghostfolio-scraper-api/ghostfolio-scraper-api.service.ts b/apps/api/src/services/data-provider/ghostfolio-scraper-api/ghostfolio-scraper-api.service.ts index dd240e8b3..6c1a313d6 100644 --- a/apps/api/src/services/data-provider/ghostfolio-scraper-api/ghostfolio-scraper-api.service.ts +++ b/apps/api/src/services/data-provider/ghostfolio-scraper-api/ghostfolio-scraper-api.service.ts @@ -144,6 +144,10 @@ export class GhostfolioScraperApiService implements DataProviderInterface { return []; } + public getName(): DataSource { + return DataSource.GHOSTFOLIO; + } + public async search(aSymbol: string): Promise<{ items: LookupItem[] }> { return { items: [] }; } diff --git a/apps/api/src/services/data-provider/interfaces/data-provider.interface.ts b/apps/api/src/services/data-provider/interfaces/data-provider.interface.ts index 864dbcf52..ebc72e922 100644 --- a/apps/api/src/services/data-provider/interfaces/data-provider.interface.ts +++ b/apps/api/src/services/data-provider/interfaces/data-provider.interface.ts @@ -5,6 +5,7 @@ import { IDataProviderHistoricalResponse, IDataProviderResponse } from '../../interfaces/interfaces'; +import { DataSource } from '@prisma/client'; export interface DataProviderInterface { canHandle(symbol: string): boolean; @@ -20,5 +21,7 @@ export interface DataProviderInterface { [symbol: string]: { [date: string]: IDataProviderHistoricalResponse }; }>; + getName(): DataSource; + search(aSymbol: string): Promise<{ items: LookupItem[] }>; } diff --git a/apps/api/src/services/data-provider/rakuten-rapid-api/rakuten-rapid-api.service.ts b/apps/api/src/services/data-provider/rakuten-rapid-api/rakuten-rapid-api.service.ts index b6b5642b6..0da563de2 100644 --- a/apps/api/src/services/data-provider/rakuten-rapid-api/rakuten-rapid-api.service.ts +++ b/apps/api/src/services/data-provider/rakuten-rapid-api/rakuten-rapid-api.service.ts @@ -25,10 +25,9 @@ import { DataProviderInterface } from '../interfaces/data-provider.interface'; export class RakutenRapidApiService implements DataProviderInterface { public static FEAR_AND_GREED_INDEX_NAME = 'Fear & Greed Index'; - private prismaService: PrismaService; - public constructor( - private readonly configurationService: ConfigurationService + private readonly configurationService: ConfigurationService, + private readonly prismaService: PrismaService ) {} public canHandle(symbol: string) { @@ -134,12 +133,12 @@ export class RakutenRapidApiService implements DataProviderInterface { return {}; } - public async search(aSymbol: string): Promise<{ items: LookupItem[] }> { - return { items: [] }; + public getName(): DataSource { + return DataSource.RAKUTEN; } - public setPrisma(aPrismaService: PrismaService) { - this.prismaService = aPrismaService; + public async search(aSymbol: string): Promise<{ items: LookupItem[] }> { + return { items: [] }; } private async getFearAndGreedIndex(): Promise<{ diff --git a/apps/api/src/services/data-provider/yahoo-finance/yahoo-finance.service.ts b/apps/api/src/services/data-provider/yahoo-finance/yahoo-finance.service.ts index d1f155f6c..0a87c2a16 100644 --- a/apps/api/src/services/data-provider/yahoo-finance/yahoo-finance.service.ts +++ b/apps/api/src/services/data-provider/yahoo-finance/yahoo-finance.service.ts @@ -171,6 +171,10 @@ export class YahooFinanceService implements DataProviderInterface { } } + public getName(): DataSource { + return DataSource.YAHOO; + } + public async search(aSymbol: string): Promise<{ items: LookupItem[] }> { const items: LookupItem[] = [];