diff --git a/app/lib/fake/backend/fake_download_counts.dart b/app/lib/fake/backend/fake_download_counts.dart index 3b38e8aef8..e1df8214e9 100644 --- a/app/lib/fake/backend/fake_download_counts.dart +++ b/app/lib/fake/backend/fake_download_counts.dart @@ -5,7 +5,7 @@ import 'dart:io'; import 'package:gcloud/storage.dart'; -import 'package:pub_dev/service/download_counts/compute_30_days_total_counts.dart'; +import 'package:pub_dev/service/download_counts/computations.dart'; import 'package:pub_dev/shared/configuration.dart'; import 'package:pub_dev/shared/utils.dart'; diff --git a/app/lib/service/download_counts/backend.dart b/app/lib/service/download_counts/backend.dart index a734abdf3d..1ddb97600a 100644 --- a/app/lib/service/download_counts/backend.dart +++ b/app/lib/service/download_counts/backend.dart @@ -7,7 +7,7 @@ import 'dart:convert'; import 'package:gcloud/service_scope.dart' as ss; import 'package:gcloud/storage.dart'; import 'package:googleapis/storage/v1.dart'; -import 'package:pub_dev/service/download_counts/compute_30_days_total_counts.dart'; +import 'package:pub_dev/service/download_counts/computations.dart'; import 'package:pub_dev/service/download_counts/download_counts.dart'; import 'package:pub_dev/service/download_counts/models.dart'; import 'package:pub_dev/service/entrypoint/analyzer.dart'; diff --git a/app/lib/service/download_counts/compute_30_days_total_counts.dart b/app/lib/service/download_counts/computations.dart similarity index 63% rename from app/lib/service/download_counts/compute_30_days_total_counts.dart rename to app/lib/service/download_counts/computations.dart index 5aaaffa65d..7a428b52fb 100644 --- a/app/lib/service/download_counts/compute_30_days_total_counts.dart +++ b/app/lib/service/download_counts/computations.dart @@ -42,3 +42,32 @@ Future upload30DaysTotal(Map counts) async { await uploadBytesWithRetry(reportsBucket, downloadCounts30DaysTotalsFileName, jsonUtf8Encoder.convert(counts)); } + +/// Computes `weeklyDownloads` starting from `newestDate` for [package]. +/// +/// Each number in `weeklyDownloads` is the total number of downloads for +/// a given 7 day period starting from the newest date with download counts +/// data available. +Future<({List weeklyDownloads, DateTime? newestDate})> + computeWeeklyDownloads(String package) async { + final weeklyDownloads = List.filled(52, 0); + final countData = + await downloadCountsBackend.lookupDownloadCountData(package); + if (countData == null) { + return (weeklyDownloads: [], newestDate: null); + } + + final totals = countData.totalCounts; + + for (int w = 0; w < 52; w++) { + var sum = 0; + for (int d = 0; d < 7; d++) { + if (totals[w * 7 + d] > 0) { + sum += totals[w * 7 + d]; + } + } + weeklyDownloads[w] = sum; + } + + return (weeklyDownloads: weeklyDownloads, newestDate: countData.newestDate!); +} diff --git a/app/lib/tool/neat_task/pub_dev_tasks.dart b/app/lib/tool/neat_task/pub_dev_tasks.dart index e50f784cb6..881060ba5c 100644 --- a/app/lib/tool/neat_task/pub_dev_tasks.dart +++ b/app/lib/tool/neat_task/pub_dev_tasks.dart @@ -8,7 +8,7 @@ import 'dart:io'; import 'package:gcloud/service_scope.dart' as ss; import 'package:logging/logging.dart'; import 'package:neat_periodic_task/neat_periodic_task.dart'; -import 'package:pub_dev/service/download_counts/compute_30_days_total_counts.dart'; +import 'package:pub_dev/service/download_counts/computations.dart'; import '../../account/backend.dart'; import '../../account/consent_backend.dart'; diff --git a/app/test/service/download_counts/compute_total_download_counts_test.dart b/app/test/service/download_counts/computations_test.dart similarity index 76% rename from app/test/service/download_counts/compute_total_download_counts_test.dart rename to app/test/service/download_counts/computations_test.dart index fd39024661..d2b46d2eb7 100644 --- a/app/test/service/download_counts/compute_total_download_counts_test.dart +++ b/app/test/service/download_counts/computations_test.dart @@ -7,7 +7,7 @@ import 'package:basics/basics.dart'; import 'package:gcloud/storage.dart'; import 'package:pub_dev/fake/backend/fake_download_counts.dart'; import 'package:pub_dev/service/download_counts/backend.dart'; -import 'package:pub_dev/service/download_counts/compute_30_days_total_counts.dart'; +import 'package:pub_dev/service/download_counts/computations.dart'; import 'package:pub_dev/shared/configuration.dart'; import 'package:test/test.dart'; @@ -119,5 +119,49 @@ void main() { expect(downloadCountsBackend.lookup30DaysTotalCounts('baz'), 150); expect(downloadCountsBackend.lookup30DaysTotalCounts('bax'), isNull); }); + + testWithProfile('compute weekly', fn: () async { + final pkg = 'foo'; + final date = DateTime.parse('1986-02-16'); + final versionsCounts = { + '1.0.1': 2, + '2.0.0-alpha': 2, + '2.0.0': 2, + '2.1.0': 2, + '3.1.0': 2, + '4.0.0-0': 2, + '6.1.0': 2, + }; + final versionsCounts2 = { + '1.0.1': 3, + '2.0.0-alpha': 3, + '2.0.0': 3, + '2.1.0': 3, + '3.1.0': 3, + '4.0.0-0': 3, + '6.1.0': 3, + }; + + for (var i = 0; i <= 7 * 20; i++) { + await downloadCountsBackend.updateDownloadCounts( + pkg, versionsCounts, date.addCalendarDays(i)); + } + + for (var i = 7 * 20 + 1; i <= 7 * 40; i++) { + await downloadCountsBackend.updateDownloadCounts( + pkg, versionsCounts2, date.addCalendarDays(i)); + } + + final res = await computeWeeklyDownloads(pkg); + + final expectedList = List.from(List.filled(20, 147)) + ..addAll(List.filled(20, 98)) + ..add(14) + ..addAll(List.filled(11, 0)); + final expectedNewstDate = date.addCalendarDays(7 * 40); + + expect(res.weeklyDownloads, expectedList); + expect(res.newestDate, expectedNewstDate); + }); }); }