Skip to content

Commit

Permalink
Feat: Add honest_measurement_count platform stat (#89)
Browse files Browse the repository at this point in the history
* Add honest_measurement_count platform stat

* Switched to new column name for measurement count

* Fix: Migrate to dedicated station count endpoints (#93)

* Migrate to dedicated station count endpoints

* Improved local helper function SQL security

* Renamed request helper methods

* Add honest_measurement_count platform stat

---------

Co-authored-by: Miroslav Bajtoš <oss@bajtos.net>
  • Loading branch information
PatrickNercessian and bajtos authored May 13, 2024
1 parent 589c3d3 commit a4da16c
Show file tree
Hide file tree
Showing 3 changed files with 98 additions and 15 deletions.
14 changes: 13 additions & 1 deletion lib/platform-routes.js
Original file line number Diff line number Diff line change
@@ -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!
Expand All @@ -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')
Expand Down
15 changes: 15 additions & 0 deletions lib/platform-stats-fetchers.js
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
84 changes: 70 additions & 14 deletions test/platform-routes.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand All @@ -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(
Expand All @@ -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)
])
}

0 comments on commit a4da16c

Please sign in to comment.