|
|
@ -27,12 +27,13 @@ import { |
|
|
|
} from '@ghostfolio/common/interfaces'; |
|
|
|
import { MarketDataPreset } from '@ghostfolio/common/types'; |
|
|
|
|
|
|
|
import { BadRequestException, Injectable } from '@nestjs/common'; |
|
|
|
import { BadRequestException, Injectable, Logger } from '@nestjs/common'; |
|
|
|
import { |
|
|
|
AssetClass, |
|
|
|
AssetSubClass, |
|
|
|
DataSource, |
|
|
|
Prisma, |
|
|
|
PrismaClient, |
|
|
|
Property, |
|
|
|
SymbolProfile |
|
|
|
} from '@prisma/client'; |
|
|
@ -212,98 +213,113 @@ export class AdminService { |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
let [assetProfiles, count] = await Promise.all([ |
|
|
|
this.prismaService.symbolProfile.findMany({ |
|
|
|
orderBy, |
|
|
|
skip, |
|
|
|
take, |
|
|
|
where, |
|
|
|
select: { |
|
|
|
_count: { |
|
|
|
select: { Order: true } |
|
|
|
}, |
|
|
|
assetClass: true, |
|
|
|
assetSubClass: true, |
|
|
|
comment: true, |
|
|
|
countries: true, |
|
|
|
currency: true, |
|
|
|
dataSource: true, |
|
|
|
id: true, |
|
|
|
name: true, |
|
|
|
Order: { |
|
|
|
orderBy: [{ date: 'asc' }], |
|
|
|
select: { date: true }, |
|
|
|
take: 1 |
|
|
|
}, |
|
|
|
scraperConfiguration: true, |
|
|
|
sectors: true, |
|
|
|
symbol: true |
|
|
|
} |
|
|
|
}), |
|
|
|
this.prismaService.symbolProfile.count({ where }) |
|
|
|
]); |
|
|
|
const extendedPrismaClient = this.getExtendedPrismaClient(); |
|
|
|
|
|
|
|
let marketData: AdminMarketDataItem[] = assetProfiles.map( |
|
|
|
({ |
|
|
|
_count, |
|
|
|
assetClass, |
|
|
|
assetSubClass, |
|
|
|
comment, |
|
|
|
countries, |
|
|
|
currency, |
|
|
|
dataSource, |
|
|
|
id, |
|
|
|
name, |
|
|
|
Order, |
|
|
|
sectors, |
|
|
|
symbol |
|
|
|
}) => { |
|
|
|
const countriesCount = countries ? Object.keys(countries).length : 0; |
|
|
|
const marketDataItemCount = |
|
|
|
marketDataItems.find((marketDataItem) => { |
|
|
|
return ( |
|
|
|
marketDataItem.dataSource === dataSource && |
|
|
|
marketDataItem.symbol === symbol |
|
|
|
); |
|
|
|
})?._count ?? 0; |
|
|
|
const sectorsCount = sectors ? Object.keys(sectors).length : 0; |
|
|
|
try { |
|
|
|
let [assetProfiles, count] = await Promise.all([ |
|
|
|
extendedPrismaClient.symbolProfile.findMany({ |
|
|
|
orderBy, |
|
|
|
skip, |
|
|
|
take, |
|
|
|
where, |
|
|
|
select: { |
|
|
|
_count: { |
|
|
|
select: { Order: true } |
|
|
|
}, |
|
|
|
assetClass: true, |
|
|
|
assetSubClass: true, |
|
|
|
comment: true, |
|
|
|
countries: true, |
|
|
|
currency: true, |
|
|
|
dataSource: true, |
|
|
|
id: true, |
|
|
|
isUsedByUsersWithSubscription: true, |
|
|
|
name: true, |
|
|
|
Order: { |
|
|
|
orderBy: [{ date: 'asc' }], |
|
|
|
select: { date: true }, |
|
|
|
take: 1 |
|
|
|
}, |
|
|
|
scraperConfiguration: true, |
|
|
|
sectors: true, |
|
|
|
symbol: true |
|
|
|
} |
|
|
|
}), |
|
|
|
this.prismaService.symbolProfile.count({ where }) |
|
|
|
]); |
|
|
|
|
|
|
|
return { |
|
|
|
assetClass, |
|
|
|
assetSubClass, |
|
|
|
comment, |
|
|
|
currency, |
|
|
|
countriesCount, |
|
|
|
dataSource, |
|
|
|
id, |
|
|
|
name, |
|
|
|
symbol, |
|
|
|
marketDataItemCount, |
|
|
|
sectorsCount, |
|
|
|
activitiesCount: _count.Order, |
|
|
|
date: Order?.[0]?.date |
|
|
|
}; |
|
|
|
} |
|
|
|
); |
|
|
|
let marketData: AdminMarketDataItem[] = await Promise.all( |
|
|
|
assetProfiles.map( |
|
|
|
async ({ |
|
|
|
_count, |
|
|
|
assetClass, |
|
|
|
assetSubClass, |
|
|
|
comment, |
|
|
|
countries, |
|
|
|
currency, |
|
|
|
dataSource, |
|
|
|
id, |
|
|
|
isUsedByUsersWithSubscription, |
|
|
|
name, |
|
|
|
Order, |
|
|
|
sectors, |
|
|
|
symbol |
|
|
|
}) => { |
|
|
|
const countriesCount = countries |
|
|
|
? Object.keys(countries).length |
|
|
|
: 0; |
|
|
|
const marketDataItemCount = |
|
|
|
marketDataItems.find((marketDataItem) => { |
|
|
|
return ( |
|
|
|
marketDataItem.dataSource === dataSource && |
|
|
|
marketDataItem.symbol === symbol |
|
|
|
); |
|
|
|
})?._count ?? 0; |
|
|
|
const sectorsCount = sectors ? Object.keys(sectors).length : 0; |
|
|
|
|
|
|
|
return { |
|
|
|
assetClass, |
|
|
|
assetSubClass, |
|
|
|
comment, |
|
|
|
currency, |
|
|
|
countriesCount, |
|
|
|
dataSource, |
|
|
|
id, |
|
|
|
name, |
|
|
|
symbol, |
|
|
|
marketDataItemCount, |
|
|
|
sectorsCount, |
|
|
|
activitiesCount: _count.Order, |
|
|
|
date: Order?.[0]?.date, |
|
|
|
isUsedByUsersWithSubscription: await isUsedByUsersWithSubscription |
|
|
|
}; |
|
|
|
} |
|
|
|
) |
|
|
|
); |
|
|
|
|
|
|
|
if (presetId) { |
|
|
|
if (presetId === 'ETF_WITHOUT_COUNTRIES') { |
|
|
|
marketData = marketData.filter(({ countriesCount }) => { |
|
|
|
return countriesCount === 0; |
|
|
|
}); |
|
|
|
} else if (presetId === 'ETF_WITHOUT_SECTORS') { |
|
|
|
marketData = marketData.filter(({ sectorsCount }) => { |
|
|
|
return sectorsCount === 0; |
|
|
|
}); |
|
|
|
if (presetId) { |
|
|
|
if (presetId === 'ETF_WITHOUT_COUNTRIES') { |
|
|
|
marketData = marketData.filter(({ countriesCount }) => { |
|
|
|
return countriesCount === 0; |
|
|
|
}); |
|
|
|
} else if (presetId === 'ETF_WITHOUT_SECTORS') { |
|
|
|
marketData = marketData.filter(({ sectorsCount }) => { |
|
|
|
return sectorsCount === 0; |
|
|
|
}); |
|
|
|
} |
|
|
|
|
|
|
|
count = marketData.length; |
|
|
|
} |
|
|
|
|
|
|
|
count = marketData.length; |
|
|
|
} |
|
|
|
return { |
|
|
|
count, |
|
|
|
marketData |
|
|
|
}; |
|
|
|
} finally { |
|
|
|
await extendedPrismaClient.$disconnect(); |
|
|
|
|
|
|
|
return { |
|
|
|
count, |
|
|
|
marketData |
|
|
|
}; |
|
|
|
Logger.debug('Disconnect extended prisma client', 'AdminService'); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
public async getMarketDataBySymbol({ |
|
|
@ -431,6 +447,52 @@ export class AdminService { |
|
|
|
return response; |
|
|
|
} |
|
|
|
|
|
|
|
private getExtendedPrismaClient() { |
|
|
|
Logger.debug('Connect extended prisma client', 'AdminService'); |
|
|
|
|
|
|
|
const symbolProfileExtension = Prisma.defineExtension((client) => { |
|
|
|
return client.$extends({ |
|
|
|
result: { |
|
|
|
symbolProfile: { |
|
|
|
isUsedByUsersWithSubscription: { |
|
|
|
compute: async ({ id }) => { |
|
|
|
const { _count } = |
|
|
|
await this.prismaService.symbolProfile.findUnique({ |
|
|
|
select: { |
|
|
|
_count: { |
|
|
|
select: { |
|
|
|
Order: { |
|
|
|
where: { |
|
|
|
User: { |
|
|
|
Subscription: { |
|
|
|
some: { |
|
|
|
expiresAt: { |
|
|
|
gt: new Date() |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
}, |
|
|
|
where: { |
|
|
|
id |
|
|
|
} |
|
|
|
}); |
|
|
|
|
|
|
|
return _count.Order > 0; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
}); |
|
|
|
}); |
|
|
|
|
|
|
|
return new PrismaClient().$extends(symbolProfileExtension); |
|
|
|
} |
|
|
|
|
|
|
|
private async getMarketDataForCurrencies(): Promise<AdminMarketData> { |
|
|
|
const marketDataItems = await this.prismaService.marketData.groupBy({ |
|
|
|
_count: true, |
|
|
|