From 24d4ec99be4ccb34ba7620a277de4dff52045d8c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miroslav=20Bajto=C5=A1?= Date: Thu, 13 Jun 2024 14:57:00 +0200 Subject: [PATCH] feat: `GET /deals/daily` (#146) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Miroslav Bajtoš Co-authored-by: Julian Gruber --- README.md | 4 ++++ stats/lib/handler.js | 2 ++ stats/lib/stats-fetchers.js | 19 +++++++++++++++++++ stats/test/handler.test.js | 32 ++++++++++++++++++++++++++++++++ 4 files changed, 57 insertions(+) diff --git a/README.md b/README.md index a40eac7..a5cf7e7 100644 --- a/README.md +++ b/README.md @@ -52,6 +52,10 @@ Base URL: http://stats.filspark.com/ http://stats.filspark.com/measurements/daily +- `GET /deals/daily?from=2024-01-01&to=2024-01-31` + + http://stats.filspark.com/deals/daily + ## Development ### Database diff --git a/stats/lib/handler.js b/stats/lib/handler.js index f158f80..accb685 100644 --- a/stats/lib/handler.js +++ b/stats/lib/handler.js @@ -3,6 +3,7 @@ import * as Sentry from '@sentry/node' import { getStatsWithFilterAndCaching } from './request-helpers.js' import { + fetchDailyDealStats, fetchDailyParticipants, fetchMinersRSRSummary, fetchMonthlyParticipants, @@ -46,6 +47,7 @@ const handler = async (req, res, pgPools) => { const segs = pathname.split('/').filter(Boolean) const fetchFunctionMap = { + 'deals/daily': fetchDailyDealStats, 'retrieval-success-rate': fetchRetrievalSuccessRate, 'participants/daily': fetchDailyParticipants, 'participants/monthly': fetchMonthlyParticipants, diff --git a/stats/lib/stats-fetchers.js b/stats/lib/stats-fetchers.js index a535688..07d3381 100644 --- a/stats/lib/stats-fetchers.js +++ b/stats/lib/stats-fetchers.js @@ -26,6 +26,25 @@ export const fetchRetrievalSuccessRate = async (pgPools, filter) => { return stats } +/** + * @param {import('@filecoin-station/spark-stats-db').pgPools} pgPools + * @param {import('./typings').DateRangeFilter} filter + */ +export const fetchDailyDealStats = async (pgPools, filter) => { + // Fetch the "day" (DATE) as a string (TEXT) to prevent node-postgres from converting it into + // a JavaScript Date with a timezone, as that could change the date one day forward or back. + const { rows } = await pgPools.evaluate.query(` + SELECT day::text, total, indexed, retrievable + FROM daily_deals + WHERE day >= $1 AND day <= $2 + ORDER BY day + `, [ + filter.from, + filter.to + ]) + return rows +} + export const fetchDailyParticipants = async (pgPools, filter) => { return await getDailyDistinctCount({ pgPool: pgPools.evaluate, diff --git a/stats/test/handler.test.js b/stats/test/handler.test.js index 9cc6663..9a17b75 100644 --- a/stats/test/handler.test.js +++ b/stats/test/handler.test.js @@ -50,6 +50,7 @@ describe('HTTP request handler', () => { beforeEach(async () => { await pgPool.query('DELETE FROM retrieval_stats') await pgPool.query('DELETE FROM daily_participants') + await pgPool.query('DELETE FROM daily_deals') }) it('returns 200 for GET /', async () => { @@ -381,6 +382,30 @@ describe('HTTP request handler', () => { ]) }) }) + + describe('GET /deals/daily', () => { + it('returns daily deal stats for the given date range', async () => { + await givenDailyDealStats(pgPool, { day: '2024-01-10', total: 10, indexed: 5, retrievable: 1 }) + await givenDailyDealStats(pgPool, { day: '2024-01-11', total: 20, indexed: 6, retrievable: 2 }) + await givenDailyDealStats(pgPool, { day: '2024-01-12', total: 30, indexed: 7, retrievable: 3 }) + await givenDailyDealStats(pgPool, { day: '2024-01-13', total: 40, indexed: 8, retrievable: 4 }) + + const res = await fetch( + new URL( + '/deals/daily?from=2024-01-11&to=2024-01-12', + baseUrl + ), { + redirect: 'manual' + } + ) + await assertResponseStatus(res, 200) + const stats = await res.json() + assert.deepStrictEqual(stats, [ + { day: '2024-01-11', total: 20, indexed: 6, retrievable: 2 }, + { day: '2024-01-12', total: 30, indexed: 7, retrievable: 3 } + ]) + }) + }) }) const givenRetrievalStats = async (pgPool, { day, minerId, total, successful }) => { @@ -389,3 +414,10 @@ const givenRetrievalStats = async (pgPool, { day, minerId, total, successful }) [day, minerId ?? 'f1test', total, successful] ) } + +const givenDailyDealStats = async (pgPool, { day, total, indexed, retrievable }) => { + await pgPool.query(` + INSERT INTO daily_deals (day, total, indexed, retrievable) + VALUES ($1, $2, $3, $4) + `, [day, total, indexed, retrievable]) +}