diff --git a/apps/triggers/src/constant/index.ts b/apps/triggers/src/constant/index.ts index dc1f695..cada000 100644 --- a/apps/triggers/src/constant/index.ts +++ b/apps/triggers/src/constant/index.ts @@ -111,6 +111,9 @@ export const MS_TRIGGERS_JOBS = { GET_ONE: 'ms.jobs.sources.getOne', GET_HEALTH: 'ms.jobs.sources.getHealth', }, + SOURCE_DATA: { + GET_SERIES_BY_DATA_SOURCE: 'ms.jobs.sources-data.getSeriesByDataSource', + }, ACTIVITIES: { GET_ONE: 'ms.jobs.activities.getOne', GET_ALL: 'ms.jobs.activities.getAll', diff --git a/apps/triggers/src/sources-data/dto/get-series.ts b/apps/triggers/src/sources-data/dto/get-series.ts new file mode 100644 index 0000000..3756d2d --- /dev/null +++ b/apps/triggers/src/sources-data/dto/get-series.ts @@ -0,0 +1,32 @@ +import { ApiProperty } from '@nestjs/swagger'; +import { DataSource, SourceType } from '@lib/database'; +import { IsEnum, IsOptional, IsString } from 'class-validator'; + +export class GetSeriesDto { + @ApiProperty({ + type: String, + }) + @IsString() + @IsOptional() + type?: SourceType; + + @ApiProperty({ + example: DataSource.DHM, + }) + @IsEnum(DataSource) + @IsString() + dataSource: DataSource; + + @ApiProperty({ + example: 'karnali', + }) + @IsString() + riverBasin: string; + + @ApiProperty({ + example: 'karnali', + }) + @IsOptional() + @IsString() + stationName?: string; +} diff --git a/apps/triggers/src/sources-data/sources-data.controller.ts b/apps/triggers/src/sources-data/sources-data.controller.ts index 9a76150..48f6166 100644 --- a/apps/triggers/src/sources-data/sources-data.controller.ts +++ b/apps/triggers/src/sources-data/sources-data.controller.ts @@ -5,6 +5,7 @@ import { DhmService } from './dhm.service'; import { GlofasService } from './glofas.service'; import { GetSouceDataDto } from './dto/get-source-data'; import { SourcesDataService } from './sources-data.service'; +import { GetSeriesDto } from './dto/get-series'; @Controller('sources-data') export class SourcesDataController { @@ -56,6 +57,13 @@ export class SourcesDataController { return this.dhmService.getRiverStations(); } + @MessagePattern({ + cmd: MS_TRIGGERS_JOBS.SOURCE_DATA.GET_SERIES_BY_DATA_SOURCE, + }) + async getSeriesByDataSource(payload: GetSeriesDto) { + return this.sourceDataService.findSeriesByDataSource(payload); + } + @MessagePattern({ cmd: MS_TRIGGERS_JOBS.WATER_LEVELS.GET_DHM, }) diff --git a/apps/triggers/src/sources-data/sources-data.service.ts b/apps/triggers/src/sources-data/sources-data.service.ts index 62aa8ee..177f369 100644 --- a/apps/triggers/src/sources-data/sources-data.service.ts +++ b/apps/triggers/src/sources-data/sources-data.service.ts @@ -28,6 +28,10 @@ import { buildQueryParams, getFormattedDate } from 'src/common'; import { SettingsService } from '@lib/core'; import { DataSourceValue } from 'src/types/settings'; import { DhmService } from './dhm.service'; +import { GetSeriesDto } from './dto/get-series'; +import { DhmService as DHM } from '@lib/dhm-adapter'; +import { GlofasServices } from '@lib/glofas-adapter'; +import { GfhService } from '@lib/gfh-adapter'; const paginate: PaginatorTypes.PaginateFunction = paginator({ perPage: 10 }); const httpsAgent = new https.Agent({ rejectUnauthorized: false }); @@ -38,6 +42,9 @@ export class SourcesDataService { private prisma: PrismaService, private readonly dhmService: DhmService, private readonly httpService: HttpService, + private readonly dhm: DHM, + private readonly glofasServices: GlofasServices, + private readonly gfhServices: GfhService, ) {} async create(dto: CreateSourcesDataDto) { @@ -95,6 +102,40 @@ export class SourcesDataService { } } + async findSeriesByDataSource(payload: GetSeriesDto) { + try { + const { dataSource, type, riverBasin, stationName } = payload; + + switch (dataSource) { + case DataSource.DHM: { + const dhm = await this.dhm.getSourceData(type, riverBasin); + return dhm; + } + case DataSource.GLOFAS: { + const glofas = await this.glofasServices.getSourceData( + type || SourceType.WATER_LEVEL, + riverBasin, + ); + return glofas; + } + + case DataSource.GFH: { + const gfh = await this.gfhServices.getSourceData( + type || SourceType.WATER_LEVEL, + riverBasin, + stationName, + ); + return gfh; + } + default: + return []; + } + } catch (error: any) { + this.logger.error('Error while fetching source data', error); + throw new RpcException(error); + } + } + async findOne(id: number) { try { this.logger.log(`Fetching sourceData with uuid: ${id}`); diff --git a/apps/triggers/src/trigger/validation/trigger.schema.ts b/apps/triggers/src/trigger/validation/trigger.schema.ts index b6ed788..6177dc3 100644 --- a/apps/triggers/src/trigger/validation/trigger.schema.ts +++ b/apps/triggers/src/trigger/validation/trigger.schema.ts @@ -117,7 +117,7 @@ export const triggerPayloadSchema = z.object({ .transform((val) => (val === null ? undefined : val)), notes: z.string().trim().max(500).optional().default(''), title: z.string().trim().min(3).max(120), - description: z.string().trim().min(3).max(500), + description: z.string().optional(), isMandatory: z.boolean().optional().default(false), isTriggered: z.boolean().optional().default(false), isDeleted: z.boolean().optional().default(false), diff --git a/packages/dhm-adapter/src/services/dhm.service.ts b/packages/dhm-adapter/src/services/dhm.service.ts index 49fb955..624a8cf 100644 --- a/packages/dhm-adapter/src/services/dhm.service.ts +++ b/packages/dhm-adapter/src/services/dhm.service.ts @@ -1,6 +1,13 @@ -import { DataSource, PrismaService, SourceType } from "@lib/database"; +import { + DataSource, + DataSourceValue, + Prisma, + PrismaService, + SourceType, +} from "@lib/database"; import { Inject, Injectable, Logger } from "@nestjs/common"; import { + DhmInfo, RainfallStationData, RiverStationData, } from "types/dhm-observation.type"; @@ -12,7 +19,7 @@ export class DhmService { async saveDataInDhm( type: SourceType, riverBasin: string, - payload: RiverStationData | RainfallStationData, + payload: RiverStationData | RainfallStationData ): Promise { try { return await this.prisma.$transaction(async (tx) => { @@ -51,11 +58,11 @@ export class DhmService { } this.logger.log( - `Series mismatch. Creating new for: ${payloadData.name}`, + `Series mismatch. Creating new for: ${payloadData.name}` ); } else { this.logger.log( - `No record found. Creating new for: ${payloadData.name}`, + `No record found. Creating new for: ${payloadData.name}` ); } @@ -81,4 +88,35 @@ export class DhmService { throw error; } } + + async getSourceData( + type: SourceType, + riverBasin: string + ): Promise> { + try { + const sourceData = await this.prisma.sourcesData.findMany({ + where: { + dataSource: DataSource.DHM, + source: { + riverBasin, + }, + type, + }, + select: { + info: true, + }, + }); + + return sourceData.map((value) => { + const info = value.info as DhmInfo; + return { + seriesId: info["series_id"], + stationName: info["name"], + }; + }); + } catch (error: any) { + this.logger.error("Error while fetching source data", error); + throw error; + } + } } diff --git a/packages/dhm-adapter/src/types/dhm-observation.type.ts b/packages/dhm-adapter/src/types/dhm-observation.type.ts index 2ce8e0f..4f62e72 100644 --- a/packages/dhm-adapter/src/types/dhm-observation.type.ts +++ b/packages/dhm-adapter/src/types/dhm-observation.type.ts @@ -125,3 +125,8 @@ export interface DhmStationResponse { rainfall_watch: RainfallStationItem[]; river_watch: RiverStationItem[]; } + +export type DhmInfo = { + series_id: string; + name: string; +}; diff --git a/packages/gfh-adapter/src/gfh.service.ts b/packages/gfh-adapter/src/gfh.service.ts index 566e28e..4193b1a 100644 --- a/packages/gfh-adapter/src/gfh.service.ts +++ b/packages/gfh-adapter/src/gfh.service.ts @@ -1,5 +1,6 @@ -import { DataSource, PrismaService, SourceType } from "@lib/database"; +import { DataSource, Prisma, PrismaService, SourceType } from "@lib/database"; import { Inject, Injectable, Logger } from "@nestjs/common"; +import { GfhInfo } from "types"; @Injectable() export class GfhService { @@ -79,4 +80,41 @@ export class GfhService { throw err; } } + async getSourceData( + type: SourceType, + riverBasin: string, + stationName?: string + ): Promise> { + try { + const sourceData = await this.prisma.sourcesData.findMany({ + where: { + dataSource: DataSource.GFH, + source: { + riverBasin, + }, + type, + ...(stationName && { + info: { + path: ["stationName"], + equals: stationName, + }, + }), + }, + select: { + info: true, + }, + }); + + return sourceData.map((value) => { + const info = value.info as GfhInfo; + return { + seriesId: info["info"].riverGaugeId, + stationName: info["info"].stationName, + }; + }); + } catch (error: any) { + this.logger.error("Error while fetching source data", error); + throw error; + } + } } diff --git a/packages/gfh-adapter/src/types/gfh-observation.type.ts b/packages/gfh-adapter/src/types/gfh-observation.type.ts index 7d57e6f..0c75e0d 100644 --- a/packages/gfh-adapter/src/types/gfh-observation.type.ts +++ b/packages/gfh-adapter/src/types/gfh-observation.type.ts @@ -1,3 +1,5 @@ +import { Prisma } from "@lib/database"; + export type GfhStationDetails = { RIVER_BASIN: string; STATION_LOCATIONS_DETAILS: StationLoacationDetails[]; @@ -150,3 +152,7 @@ export interface GfhTransformedResult { forecastDate: string; history: GfhHistoryItem[]; } + +export type GfhInfo = { + info: { riverGaugeId: string; stationName: string }; +}; diff --git a/packages/glofas-adapter/src/glofas.services.ts b/packages/glofas-adapter/src/glofas.services.ts index e24f913..222e578 100644 --- a/packages/glofas-adapter/src/glofas.services.ts +++ b/packages/glofas-adapter/src/glofas.services.ts @@ -1,6 +1,6 @@ import { DataSource, Prisma, PrismaService, SourceType } from '@lib/database'; import { Inject, Injectable, Logger } from '@nestjs/common'; -import { GlofasDataObject } from 'types/glofas-observation.type'; +import { GfofasInfo, GlofasDataObject } from 'types/glofas-observation.type'; @Injectable() export class GlofasServices { @@ -62,4 +62,34 @@ export class GlofasServices { throw error; } } + async getSourceData( + type: SourceType, + riverBasin: string, + ): Promise> { + try { + const sourceData = await this.prisma.sourcesData.findMany({ + where: { + dataSource: DataSource.GLOFAS, + source: { + riverBasin, + }, + type, + }, + select: { + info: true, + }, + }); + + return sourceData.map((value) => { + const info = value.info as GfofasInfo; + return { + seriesId: info['location'].basinId, + stationName: info['location'].basinId, + }; + }); + } catch (error: any) { + this.logger.error('Error while fetching source data', error); + throw error; + } + } } diff --git a/packages/glofas-adapter/src/types/glofas-observation.type.ts b/packages/glofas-adapter/src/types/glofas-observation.type.ts index 92d7492..5109939 100644 --- a/packages/glofas-adapter/src/types/glofas-observation.type.ts +++ b/packages/glofas-adapter/src/types/glofas-observation.type.ts @@ -1,3 +1,4 @@ +import { Prisma } from '@lib/database'; import axios from 'axios'; export interface GlofasObservation { @@ -63,3 +64,7 @@ export interface GlofasInfoObject { }; forecastDate: string; } + +export type GfofasInfo = { + location: { basinId: string }; +};