From 514b59acc3a887add7ed5f7a8fb5aaee6484c200 Mon Sep 17 00:00:00 2001 From: Marc Durdin Date: Wed, 7 Jan 2026 08:14:48 +1100 Subject: [PATCH] feat: add keyboard download stats by period Returns list of keyboard id and name, with keyboard download count and daily average, in JSON or CSV format Usage: * JSON: /script/statistics/keyboards.php?startDate=2025-01-01&endDate=2026-01-01 * CSV: /script/statistics/keyboards.php?startDate=2025-01-01&endDate=2026-01-01&csv=1 Test-bot: skip --- script/statistics/annual-statistics.inc.php | 52 ++++++++++----------- script/statistics/keyboards.php | 49 +++++++++++++++++++ tools/db/build/annual-statistics.sql | 35 +++++++++++++- 3 files changed, 109 insertions(+), 27 deletions(-) create mode 100644 script/statistics/keyboards.php diff --git a/script/statistics/annual-statistics.inc.php b/script/statistics/annual-statistics.inc.php index 96f50d8..98ca7c6 100644 --- a/script/statistics/annual-statistics.inc.php +++ b/script/statistics/annual-statistics.inc.php @@ -7,44 +7,44 @@ namespace Keyman\Site\com\keyman\api; - // strip out repeated columns with numeric keys (by default the results returned - // give each column twice, once with a column name, and once with a column index) - function filter_columns_by_name($data) { - $result = []; - foreach($data as $row) { - $r = []; - foreach($row as $id => $val) { - if(!is_numeric($id)) { - $r[$id] = intval($val); - } - } - array_push($result, $r); - } - return $result; - } - class AnnualStatistics { function execute($mssql, $startDate, $endDate) { + return $this->_execute('sp_annual_statistics', $mssql, $startDate, $endDate); + } - $stmt = $mssql->prepare('EXEC sp_annual_statistics :prmStartDate, :prmEndDate'); - - $stmt->bindParam(":prmStartDate", $startDate); - $stmt->bindParam(":prmEndDate", $endDate); + function executeDownloadsByMonth($mssql, $startDate, $endDate) { + return $this->_execute('sp_keyboard_downloads_by_month_statistics', $mssql, $startDate, $endDate); + } - $stmt->execute(); - $data = $stmt->fetchAll(); - return filter_columns_by_name($data); + function executeKeyboards($mssql, $startDate, $endDate) { + return $this->_execute('sp_statistics_keyboard_downloads_by_id', $mssql, $startDate, $endDate); } - function executeDownloadsByMonth($mssql, $startDate, $endDate) { - $stmt = $mssql->prepare('EXEC sp_keyboard_downloads_by_month_statistics :prmStartDate, :prmEndDate'); + private function _execute($proc, $mssql, $startDate, $endDate) { + $stmt = $mssql->prepare("EXEC $proc :prmStartDate, :prmEndDate"); $stmt->bindParam(":prmStartDate", $startDate); $stmt->bindParam(":prmEndDate", $endDate); $stmt->execute(); $data = $stmt->fetchAll(); - return filter_columns_by_name($data); + return $this->filter_columns_by_name($data); + } + + // strip out repeated columns with numeric keys (by default the results returned + // give each column twice, once with a column name, and once with a column index) + private function filter_columns_by_name($data) { + $result = []; + foreach($data as $row) { + $r = []; + foreach($row as $id => $val) { + if(!is_numeric($id)) { + $r[$id] = is_numeric($val) ? intval($val) : $val; + } + } + array_push($result, $r); + } + return $result; } } diff --git a/script/statistics/keyboards.php b/script/statistics/keyboards.php new file mode 100644 index 0000000..5fc7fcd --- /dev/null +++ b/script/statistics/keyboards.php @@ -0,0 +1,49 @@ +executeKeyboards($mssql, $startDate, $endDate); + + if(isset($_REQUEST['csv'])) { + $out = fopen('php://output', 'w'); + + if(sizeof($keyboards) > 0) { + $data = array_keys($keyboards[0]); + fputcsv($out, $data, ',', '"', ''); + foreach($keyboards as $row) { + $data = array_values($row); + fputcsv($out, $data, ',', '"', ''); + } + } + + fclose($out); + } else { + $data = ["keyboards" => $keyboards]; + json_print($data); + } diff --git a/tools/db/build/annual-statistics.sql b/tools/db/build/annual-statistics.sql index 8307055..ec632ed 100644 --- a/tools/db/build/annual-statistics.sql +++ b/tools/db/build/annual-statistics.sql @@ -22,6 +22,8 @@ users or keyboards in use, but gives a rough volume. */ +/* TODO(lowpri): rename these procs to sp_statistics_xxxx */ + DROP PROCEDURE IF EXISTS sp_annual_statistics; GO @@ -40,6 +42,8 @@ SELECT (select sum(count) from kstats.t_keyboard_downloads WHERE statdate >= @prmStartDate AND statdate < @prmEndDate) RawKeyboardDownloadCount GO +/* ======================================================================== */ + DROP PROCEDURE IF EXISTS sp_keyboard_downloads_by_month_statistics; GO @@ -57,4 +61,33 @@ CREATE PROCEDURE sp_keyboard_downloads_by_month_statistics ( WHERE statdate >= @prmStartDate AND statdate < @prmEndDate group by month(statdate), year(statdate) order by 2, 1 -GO \ No newline at end of file +GO + +/* ======================================================================== */ + +DROP PROCEDURE IF EXISTS sp_statistics_keyboard_downloads_by_id; +GO + +CREATE PROCEDURE sp_statistics_keyboard_downloads_by_id ( + @prmStartDate DATE, + @prmEndDate DATE +) AS + + DECLARE @DayCount INT = DATEDIFF(day,@prmStartDate,@prmEndDate) + 1 + + SELECT + k.keyboard_id, + k.name, + SUM(count) RawKeyboardDownloadCount, + SUM(count)/@DayCount DownloadsPerDay + FROM + k0.t_keyboard k LEFT JOIN + kstats.t_keyboard_downloads d ON d.keyboard_id = k.keyboard_id + WHERE + (d.statdate >= @prmStartDate AND d.statdate < @prmEndDate) OR (d.keyboard_id IS NULL) + GROUP BY + k.keyboard_id, + k.name + ORDER BY + k.keyboard_id +GO