UNPKG

@accounter/server

Version:
93 lines (84 loc) 3.07 kB
import DataLoader from 'dataloader'; import { Injectable, Scope } from 'graphql-modules'; import { sql } from '@pgtyped/runtime'; import { dateToTimelessDateString, getCacheInstance } from '../../../shared/helpers/index.js'; import { DBProvider } from '../../app-providers/db.provider.js'; import type { IGetExchangeRatesByDateQuery, IGetExchangeRatesByDateResult, IGetExchangeRatesByDatesQuery, IGetExchangeRatesByDatesResult, } from '../types.js'; const getExchangeRatesByDate = sql<IGetExchangeRatesByDateQuery>` select * from accounter_schema.exchange_rates where exchange_date <= to_date($date, 'YYYY-MM-DD') order by exchange_date desc limit 1; `; const getExchangeRatesByDates = sql<IGetExchangeRatesByDatesQuery>` SELECT * FROM accounter_schema.exchange_rates WHERE exchange_date BETWEEN ( SELECT exchange_date FROM accounter_schema.exchange_rates WHERE exchange_date <= to_date($fromDate, 'YYYY-MM-DD') ORDER BY exchange_date DESC LIMIT 1 ) AND to_date($toDate, 'YYYY-MM-DD') ORDER BY exchange_date DESC; `; @Injectable({ scope: Scope.Singleton, global: true, }) export class FiatExchangeProvider { cache = getCacheInstance({ stdTTL: 60 * 60 * 24, // 24 hours }); constructor(private dbProvider: DBProvider) {} public async getExchangeRates(date: Date) { const formattedDate = dateToTimelessDateString(date); try { const cached = this.cache.get<IGetExchangeRatesByDateResult[]>(formattedDate); if (cached) { return Promise.resolve(cached); } const [result] = await getExchangeRatesByDate.run({ date: formattedDate }, this.dbProvider); this.cache.set(formattedDate, result); return result; } catch (error) { const message = `Error fetching exchange rates for date ${formattedDate}`; console.error(`${message}: ${error}`); throw new Error(message, { cause: error }); } } private async batchExchangeRatesByDates(dates: readonly Date[]) { const fromDate = dateToTimelessDateString(new Date(Math.min(...dates.map(d => d.getTime())))); const toDate = dateToTimelessDateString(new Date(Math.max(...dates.map(d => d.getTime())))); const rates = await getExchangeRatesByDates.run( { fromDate, toDate, }, this.dbProvider, ); return dates.map(date => { const stringifiedDate = dateToTimelessDateString(date); return rates .filter(rate => dateToTimelessDateString(rate.exchange_date!) <= stringifiedDate) .reduce((prev: IGetExchangeRatesByDatesResult, curr: IGetExchangeRatesByDatesResult) => (prev.exchange_date?.getTime() ?? 0) > (curr.exchange_date?.getTime() ?? 0) ? prev : curr, ); }); } public getExchangeRatesByDatesLoader = new DataLoader( (keys: readonly Date[]) => this.batchExchangeRatesByDates(keys), { cacheKeyFn: key => dateToTimelessDateString(key), cacheMap: this.cache, }, ); public clearCache() { this.cache.clear(); } }