Browse Source

Refine asset profiles response structure

* Move the asset profile item type to the responses interfaces

* Rename the response payload from marketData to assetProfiles

* Align asset profile response mapping
pull/7056/head
Sjohn21 4 weeks ago
parent
commit
ed6824c5b9
  1. 129
      apps/api/src/app/endpoints/asset-profiles/asset-profiles.service.ts
  2. 10
      apps/client/src/app/components/admin-market-data/admin-market-data.component.ts
  3. 8
      libs/common/src/lib/interfaces/index.ts
  4. 12
      libs/common/src/lib/interfaces/responses/asset-profile-item.interface.ts
  5. 4
      libs/ui/src/lib/assistant/assistant.component.ts

129
apps/api/src/app/endpoints/asset-profiles/asset-profiles.service.ts

@ -160,7 +160,7 @@ export class AssetProfilesService {
}),
this.prismaService.symbolProfile.count({ where })
]);
const assetProfiles = symbolProfileResult[0];
const symbolProfiles = symbolProfileResult[0];
let count = symbolProfileResult[1];
const lastMarketPrices = await this.prismaService.marketData.findMany({
@ -173,12 +173,12 @@ export class AssetProfilesService {
},
where: {
dataSource: {
in: assetProfiles.map(({ dataSource }) => {
in: symbolProfiles.map(({ dataSource }) => {
return dataSource;
})
},
symbol: {
in: assetProfiles.map(({ symbol }) => {
in: symbolProfiles.map(({ symbol }) => {
return symbol;
})
}
@ -194,8 +194,8 @@ export class AssetProfilesService {
);
}
let marketData: AssetProfileItem[] = await Promise.all(
assetProfiles.map(async (assetProfile) => {
let assetProfiles: AssetProfileItem[] = await Promise.all(
symbolProfiles.map(async (assetProfile) => {
const {
_count,
activities,
@ -239,8 +239,8 @@ export class AssetProfilesService {
currency,
dataSource,
id,
isin,
isActive,
isin,
lastMarketPrice,
marketDataItemCount,
name,
@ -256,21 +256,21 @@ export class AssetProfilesService {
if (presetId) {
if (presetId === 'ETF_WITHOUT_COUNTRIES') {
marketData = marketData.filter(({ countriesCount }) => {
assetProfiles = assetProfiles.filter(({ countriesCount }) => {
return countriesCount === 0;
});
} else if (presetId === 'ETF_WITHOUT_SECTORS') {
marketData = marketData.filter(({ sectorsCount }) => {
assetProfiles = assetProfiles.filter(({ sectorsCount }) => {
return sectorsCount === 0;
});
}
count = marketData.length;
count = assetProfiles.length;
}
return {
count,
marketData
assetProfiles,
count
};
}
@ -348,50 +348,6 @@ export class AssetProfilesService {
return data;
}
private getExtendedPrismaClient() {
const symbolProfileExtension = Prisma.defineExtension((client) => {
return client.$extends({
result: {
symbolProfile: {
isUsedByUsersWithSubscription: {
compute: async ({ id }) => {
const { _count } =
await this.prismaService.symbolProfile.findUnique({
select: {
_count: {
select: {
activities: {
where: {
user: {
subscriptions: {
some: {
expiresAt: {
gt: new Date()
}
}
}
}
}
}
}
}
},
where: {
id
}
});
return _count.activities > 0;
}
}
}
}
});
});
return this.prismaService.$extends(symbolProfileExtension);
}
private async getAssetProfilesForCurrencies(): Promise<AssetProfilesResponse> {
const currencyPairs = this.exchangeRateDataService.getCurrencyPairs();
@ -432,7 +388,7 @@ export class AssetProfilesService {
);
}
const marketDataPromise: Promise<AssetProfileItem>[] = currencyPairs.map(
const assetProfilePromises: Promise<AssetProfileItem>[] = currencyPairs.map(
async ({ dataSource, symbol }) => {
let activitiesCount: EnhancedSymbolProfile['activitiesCount'] = 0;
let currency: EnhancedSymbolProfile['currency'] = '-';
@ -458,26 +414,71 @@ export class AssetProfilesService {
return {
activitiesCount,
currency,
dataSource,
isin: null,
lastMarketPrice,
marketDataItemCount,
symbol,
assetClass: AssetClass.LIQUIDITY,
assetSubClass: AssetSubClass.CASH,
comment: null,
countriesCount: 0,
currency,
dataSource,
date: dateOfFirstActivity,
id: undefined,
isActive: true,
isin: null,
lastMarketPrice,
marketDataItemCount,
name: symbol,
sectorsCount: 0,
symbol,
watchedByCount: 0
};
}
);
const marketData = await Promise.all(marketDataPromise);
return { marketData, count: marketData.length };
const assetProfiles = await Promise.all(assetProfilePromises);
return { assetProfiles, count: assetProfiles.length };
}
private getExtendedPrismaClient() {
const symbolProfileExtension = Prisma.defineExtension((client) => {
return client.$extends({
result: {
symbolProfile: {
isUsedByUsersWithSubscription: {
compute: async ({ id }) => {
const { _count } =
await this.prismaService.symbolProfile.findUnique({
select: {
_count: {
select: {
activities: {
where: {
user: {
subscriptions: {
some: {
expiresAt: {
gt: new Date()
}
}
}
}
}
}
}
}
},
where: {
id
}
});
return _count.activities > 0;
}
}
}
}
});
});
return this.prismaService.$extends(symbolProfileExtension);
}
}

10
apps/client/src/app/components/admin-market-data/admin-market-data.component.ts

@ -10,11 +10,11 @@ import {
} from '@ghostfolio/common/helper';
import {
AssetProfileIdentifier,
AssetProfileItem,
Filter,
InfoItem,
User
} from '@ghostfolio/common/interfaces';
import { AssetProfileItem } from '@ghostfolio/common/interfaces';
import { hasPermission, permissions } from '@ghostfolio/common/permissions';
import { GfSymbolPipe } from '@ghostfolio/common/pipes';
import { GfActivitiesFilterComponent } from '@ghostfolio/ui/activities-filter';
@ -384,15 +384,15 @@ export class GfAdminMarketDataComponent implements AfterViewInit, OnInit {
take: this.pageSize
})
.pipe(takeUntilDestroyed(this.destroyRef))
.subscribe(({ count, marketData }) => {
.subscribe(({ assetProfiles, count }) => {
this.totalItems = count;
this.dataSource = new MatTableDataSource(
marketData.map((marketDataItem) => {
assetProfiles.map((assetProfile) => {
return {
...marketDataItem,
...assetProfile,
isBenchmark: this.benchmarks.some(({ id }) => {
return id === marketDataItem.id;
return id === assetProfile.id;
})
};
})

8
libs/common/src/lib/interfaces/index.ts

@ -7,10 +7,6 @@ import type { AdminMarketDataDetails } from './admin-market-data-details.interfa
import type { AdminUser } from './admin-user.interface';
import type { AssetClassSelectorOption } from './asset-class-selector-option.interface';
import type { AssetProfileIdentifier } from './asset-profile-identifier.interface';
import type {
AssetProfileItem,
AssetProfilesResponse
} from './asset-profiles-response.interface';
import type { BenchmarkProperty } from './benchmark-property.interface';
import type { Benchmark } from './benchmark.interface';
import type { Coupon } from './coupon.interface';
@ -46,6 +42,10 @@ import type { AdminUsersResponse } from './responses/admin-users-response.interf
import type { AiPromptResponse } from './responses/ai-prompt-response.interface';
import type { AiServiceHealthResponse } from './responses/ai-service-health-response.interface';
import type { ApiKeyResponse } from './responses/api-key-response.interface';
import type {
AssetProfileItem,
AssetProfilesResponse
} from './responses/asset-profile-item.interface';
import type { AssetResponse } from './responses/asset-response.interface';
import type { BenchmarkMarketDataDetailsResponse } from './responses/benchmark-market-data-details-response.interface';
import type { BenchmarkResponse } from './responses/benchmark-response.interface';

12
libs/common/src/lib/interfaces/asset-profiles-response.interface.ts → libs/common/src/lib/interfaces/responses/asset-profile-item.interface.ts

@ -1,10 +1,5 @@
import { AssetClass, AssetSubClass, DataSource } from '@prisma/client';
export interface AssetProfilesResponse {
count: number;
marketData: AssetProfileItem[];
}
export interface AssetProfileItem {
activitiesCount: number;
assetClass?: AssetClass;
@ -15,9 +10,9 @@ export interface AssetProfileItem {
dataSource: DataSource;
date: Date;
id: string;
isin?: string | null;
isActive: boolean;
isBenchmark?: boolean;
isin?: string | null;
isUsedByUsersWithSubscription?: boolean;
lastMarketPrice: number;
marketDataItemCount: number;
@ -26,3 +21,8 @@ export interface AssetProfileItem {
symbol: string;
watchedByCount: number;
}
export interface AssetProfilesResponse {
assetProfiles: AssetProfileItem[];
count: number;
}

4
libs/ui/src/lib/assistant/assistant.component.ts

@ -688,8 +688,8 @@ export class GfAssistantComponent implements OnChanges, OnDestroy, OnInit {
catchError(() => {
return EMPTY;
}),
map(({ marketData }) => {
return marketData.map(
map(({ assetProfiles }) => {
return assetProfiles.map(
({ assetSubClass, currency, dataSource, name, symbol }) => {
return {
currency,

Loading…
Cancel
Save