mirror of
https://github.com/SyncrowIOT/backend.git
synced 2025-08-26 04:59:39 +00:00
139 lines
4.3 KiB
TypeScript
139 lines
4.3 KiB
TypeScript
import { HttpException, HttpStatus, Injectable } from '@nestjs/common';
|
|
import {
|
|
GetAqiDailyBySpaceDto,
|
|
GetAqiPollutantBySpaceDto,
|
|
} from '../dto/get-aqi.dto';
|
|
import { SuccessResponseDto } from '@app/common/dto/success.response.dto';
|
|
import { SpaceParamsDto } from '../dto/aqi-params.dto';
|
|
import { SqlLoaderService } from '@app/common/helper/services/sql-loader.service';
|
|
import { DataSource } from 'typeorm';
|
|
import { SQL_PROCEDURES_PATH } from '@app/common/constants/sql-query-path';
|
|
import { BaseResponseDto } from '@app/common/dto/base.response.dto';
|
|
import { convertKeysToCamelCase } from '@app/common/helper/camelCaseConverter';
|
|
import { PollutantType } from '@app/common/constants/pollutants.enum';
|
|
|
|
@Injectable()
|
|
export class AqiService {
|
|
constructor(
|
|
private readonly sqlLoader: SqlLoaderService,
|
|
private readonly dataSource: DataSource,
|
|
) {}
|
|
async getAQIDistributionDataBySpace(
|
|
params: SpaceParamsDto,
|
|
query: GetAqiPollutantBySpaceDto,
|
|
): Promise<BaseResponseDto> {
|
|
const { monthDate, pollutantType } = query;
|
|
const { spaceUuid } = params;
|
|
|
|
try {
|
|
const data = await this.executeProcedure(
|
|
'fact_daily_space_aqi',
|
|
'proceduce_select_daily_space_aqi',
|
|
[spaceUuid, monthDate],
|
|
);
|
|
|
|
const categories = [
|
|
'good',
|
|
'moderate',
|
|
'unhealthy_sensitive',
|
|
'unhealthy',
|
|
'very_unhealthy',
|
|
'hazardous',
|
|
];
|
|
|
|
const transformedData = data.map((item) => {
|
|
const date = new Date(item.event_date).toLocaleDateString('en-CA'); // YYYY-MM-DD
|
|
|
|
const categoryData = categories.map((category) => {
|
|
const key = `${category}_${pollutantType.toLowerCase()}_percentage`;
|
|
return {
|
|
type: category,
|
|
percentage: item[key] ?? 0,
|
|
};
|
|
});
|
|
|
|
return { date, data: categoryData };
|
|
});
|
|
|
|
const response = this.buildResponse(
|
|
`AQI distribution data fetched successfully for ${spaceUuid} space and pollutant ${pollutantType}`,
|
|
transformedData,
|
|
);
|
|
return response;
|
|
} catch (error) {
|
|
console.error('Failed to fetch AQI distribution data', {
|
|
error,
|
|
spaceUuid,
|
|
});
|
|
throw new HttpException(
|
|
error.response?.message || 'Failed to fetch AQI distribution data',
|
|
error.status || HttpStatus.INTERNAL_SERVER_ERROR,
|
|
);
|
|
}
|
|
}
|
|
|
|
async getAQIRangeDataBySpace(
|
|
params: SpaceParamsDto,
|
|
query: GetAqiDailyBySpaceDto,
|
|
): Promise<BaseResponseDto> {
|
|
const { monthDate } = query;
|
|
const { spaceUuid } = params;
|
|
|
|
try {
|
|
const data = await this.executeProcedure(
|
|
'fact_daily_space_aqi',
|
|
'proceduce_select_daily_space_aqi',
|
|
[spaceUuid, monthDate],
|
|
);
|
|
|
|
// Define pollutants dynamically
|
|
const pollutants = Object.values(PollutantType);
|
|
|
|
const transformedData = data.map((item) => {
|
|
const date = new Date(item.event_date).toLocaleDateString('en-CA'); // YYYY-MM-DD
|
|
const dailyData = pollutants.map((type) => ({
|
|
type,
|
|
min: item[`daily_min_${type}`],
|
|
max: item[`daily_max_${type}`],
|
|
average: item[`daily_avg_${type}`],
|
|
}));
|
|
return { date, data: dailyData };
|
|
});
|
|
|
|
const response = this.buildResponse(
|
|
`AQI data fetched successfully for ${spaceUuid} space`,
|
|
transformedData,
|
|
);
|
|
return convertKeysToCamelCase(response);
|
|
} catch (error) {
|
|
console.error('Failed to fetch AQI data', {
|
|
error,
|
|
spaceUuid,
|
|
});
|
|
throw new HttpException(
|
|
error.response?.message || 'Failed to fetch AQI data',
|
|
error.status || HttpStatus.INTERNAL_SERVER_ERROR,
|
|
);
|
|
}
|
|
}
|
|
|
|
private buildResponse(message: string, data: any[]) {
|
|
return new SuccessResponseDto({
|
|
message,
|
|
data,
|
|
statusCode: HttpStatus.OK,
|
|
});
|
|
}
|
|
private async executeProcedure(
|
|
procedureFolderName: string,
|
|
procedureFileName: string,
|
|
params: (string | number | null)[],
|
|
): Promise<any[]> {
|
|
const query = this.loadQuery(procedureFolderName, procedureFileName);
|
|
return await this.dataSource.query(query, params);
|
|
}
|
|
private loadQuery(folderName: string, fileName: string): string {
|
|
return this.sqlLoader.loadQuery(folderName, fileName, SQL_PROCEDURES_PATH);
|
|
}
|
|
}
|