diff --git a/lib/platform-routes.js b/lib/platform-routes.js index daf72027..36ec1441 100644 --- a/lib/platform-routes.js +++ b/lib/platform-routes.js @@ -1,5 +1,9 @@ import { getStatsWithFilterAndCaching } from './request-helpers.js' -import { fetchDailyStationCount, fetchMonthlyStationCount } from './platform-stats-fetchers.js' +import { + fetchDailyStationCount, + fetchMonthlyStationCount, + fetchDailyStationAcceptedMeasurementCount +} from './platform-stats-fetchers.js' export const handlePlatformRoutes = async (req, res, pgPool) => { // Caveat! `new URL('//foo', 'http://127.0.0.1')` would produce "http://foo/" - not what we want! @@ -21,6 +25,14 @@ export const handlePlatformRoutes = async (req, res, pgPool) => { pgPool, fetchMonthlyStationCount) return true + } else if (req.method === 'GET' && segs[0] === 'measurements' && segs[1] === 'daily' && segs.length === 2) { + await getStatsWithFilterAndCaching( + pathname, + searchParams, + res, + pgPool, + fetchDailyStationAcceptedMeasurementCount) + return true } else if (req.method === 'GET' && segs.length === 0) { // health check - required by Grafana datasources res.end('OK') diff --git a/lib/platform-stats-fetchers.js b/lib/platform-stats-fetchers.js index 89fd4cf1..edb29e96 100644 --- a/lib/platform-stats-fetchers.js +++ b/lib/platform-stats-fetchers.js @@ -25,3 +25,18 @@ export const fetchMonthlyStationCount = async (pgPool, filter) => { filter }) } + +/** + * @param {import('pg').Pool} pgPool + * @param {import('./typings').Filter} filter + */ +export const fetchDailyStationAcceptedMeasurementCount = async (pgPool, filter) => { + const { rows } = await pgPool.query(` + SELECT day::TEXT, SUM(accepted_measurement_count) as accepted_measurement_count + FROM daily_stations + WHERE day >= $1 AND day <= $2 + GROUP BY day + ORDER BY day + `, [filter.from, filter.to]) + return rows +} diff --git a/test/platform-routes.test.js b/test/platform-routes.test.js index e9ae0982..7e0af46d 100644 --- a/test/platform-routes.test.js +++ b/test/platform-routes.test.js @@ -48,10 +48,19 @@ describe('Platform Routes HTTP request handler', () => { describe('GET /stations/daily', () => { it('returns daily station metrics for the given date range', async () => { - await givenDailyStationMetrics(pgPool, '2024-01-10', ['station1']) - await givenDailyStationMetrics(pgPool, '2024-01-11', ['station2']) - await givenDailyStationMetrics(pgPool, '2024-01-12', ['station2', 'station3']) - await givenDailyStationMetrics(pgPool, '2024-01-13', ['station1']) + await givenDailyStationMetrics(pgPool, '2024-01-10', [ + { station_id: 'station1', accepted_measurement_count: 1 } + ]) + await givenDailyStationMetrics(pgPool, '2024-01-11', [ + { station_id: 'station2', accepted_measurement_count: 1 } + ]) + await givenDailyStationMetrics(pgPool, '2024-01-12', [ + { station_id: 'station2', accepted_measurement_count: 2 }, + { station_id: 'station3', accepted_measurement_count: 1 } + ]) + await givenDailyStationMetrics(pgPool, '2024-01-13', [ + { station_id: 'station1', accepted_measurement_count: 1 } + ]) const res = await fetch( new URL( @@ -73,14 +82,27 @@ describe('Platform Routes HTTP request handler', () => { describe('GET /stations/monthly', () => { it('returns monthly station metrics for the given date range ignoring the day number', async () => { // before the date range - await givenDailyStationMetrics(pgPool, '2023-12-31', ['station1']) + await givenDailyStationMetrics(pgPool, '2023-12-31', [ + { station_id: 'station1', accepted_measurement_count: 1 } + ]) // in the date range - await givenDailyStationMetrics(pgPool, '2024-01-10', ['station1']) - await givenDailyStationMetrics(pgPool, '2024-01-11', ['station2']) - await givenDailyStationMetrics(pgPool, '2024-01-12', ['station2', 'station3']) - await givenDailyStationMetrics(pgPool, '2024-02-13', ['station1']) + await givenDailyStationMetrics(pgPool, '2024-01-10', [ + { station_id: 'station1', accepted_measurement_count: 1 } + ]) + await givenDailyStationMetrics(pgPool, '2024-01-11', [ + { station_id: 'station2', accepted_measurement_count: 1 } + ]) + await givenDailyStationMetrics(pgPool, '2024-01-12', [ + { station_id: 'station2', accepted_measurement_count: 2 }, + { station_id: 'station3', accepted_measurement_count: 1 } + ]) + await givenDailyStationMetrics(pgPool, '2024-02-13', [ + { station_id: 'station1', accepted_measurement_count: 1 } + ]) // after the date range - await givenDailyStationMetrics(pgPool, '2024-03-01', ['station1']) + await givenDailyStationMetrics(pgPool, '2024-03-01', [ + { station_id: 'station1', accepted_measurement_count: 1 } + ]) const res = await fetch( new URL( @@ -98,15 +120,49 @@ describe('Platform Routes HTTP request handler', () => { ]) }) }) + + describe('GET /measurements/daily', () => { + it('returns daily total accepted measurement count for the given date range', async () => { + await givenDailyStationMetrics(pgPool, '2024-01-10', [ + { station_id: 'station1', accepted_measurement_count: 1 } + ]) + await givenDailyStationMetrics(pgPool, '2024-01-11', [ + { station_id: 'station2', accepted_measurement_count: 1 } + ]) + await givenDailyStationMetrics(pgPool, '2024-01-12', [ + { station_id: 'station2', accepted_measurement_count: 2 }, + { station_id: 'station3', accepted_measurement_count: 1 } + ]) + await givenDailyStationMetrics(pgPool, '2024-01-13', [ + { station_id: 'station1', accepted_measurement_count: 1 } + ]) + + const res = await fetch( + new URL( + '/measurements/daily?from=2024-01-11&to=2024-01-12', + baseUrl + ), { + redirect: 'manual' + } + ) + await assertResponseStatus(res, 200) + const metrics = await res.json() + assert.deepStrictEqual(metrics, [ + { day: '2024-01-11', accepted_measurement_count: '1' }, + { day: '2024-01-12', accepted_measurement_count: '3' } + ]) + }) + }) }) -const givenDailyStationMetrics = async (pgPool, day, stationIds) => { +const givenDailyStationMetrics = async (pgPool, day, stationStats) => { await pgPool.query(` - INSERT INTO daily_stations (day, station_id) - SELECT $1 AS day, UNNEST($2::text[]) AS station_id + INSERT INTO daily_stations (day, station_id, accepted_measurement_count) + SELECT $1 AS day, UNNEST($2::text[]) AS station_id, UNNEST($3::int[]) AS accepted_measurement_count ON CONFLICT DO NOTHING `, [ day, - stationIds + stationStats.map(s => s.station_id), + stationStats.map(s => s.accepted_measurement_count) ]) }