From da983eb991f78f739e65ed8ad3515aa686ed55f9 Mon Sep 17 00:00:00 2001 From: Sarah Zakarias Date: Wed, 14 May 2025 07:41:47 +0000 Subject: [PATCH] Save trend scores as doubles --- .../fake/backend/fake_download_counts.dart | 4 +- app/lib/search/search_service.dart | 4 +- app/lib/search/search_service.g.dart | 2 +- app/lib/service/download_counts/backend.dart | 60 ++++++++++--------- .../download_counts/computations_test.dart | 16 ++--- 5 files changed, 45 insertions(+), 41 deletions(-) diff --git a/app/lib/fake/backend/fake_download_counts.dart b/app/lib/fake/backend/fake_download_counts.dart index cd0774cbbc..9b3070a105 100644 --- a/app/lib/fake/backend/fake_download_counts.dart +++ b/app/lib/fake/backend/fake_download_counts.dart @@ -49,8 +49,8 @@ Future generateFake30DaysTotals(Map totals) async { downloadCounts30DaysTotalsFileName, jsonUtf8Encoder.convert(totals)); } -Future generateFakeTrendScores(Map totals) async { +Future generateFakeTrendScores(Map trends) async { await storageService .bucket(activeConfiguration.reportsBucketName!) - .writeBytesWithRetry(trendScoreFileName, jsonUtf8Encoder.convert(totals)); + .writeBytesWithRetry(trendScoreFileName, jsonUtf8Encoder.convert(trends)); } diff --git a/app/lib/search/search_service.dart b/app/lib/search/search_service.dart index 3ca8ddf9b9..73ba84a438 100644 --- a/app/lib/search/search_service.dart +++ b/app/lib/search/search_service.dart @@ -79,7 +79,7 @@ class PackageDocument { /// The normalized score between [0.0-1.0] (1.0 being the most downloaded package). double? downloadScore; - final int trendScore; + final double trendScore; final int likeCount; @@ -112,7 +112,7 @@ class PackageDocument { List? tags, int? downloadCount, this.downloadScore, - int? trendScore, + double? trendScore, int? likeCount, this.likeScore, int? grantedPoints, diff --git a/app/lib/search/search_service.g.dart b/app/lib/search/search_service.g.dart index 05f1e994f7..a0c62103f4 100644 --- a/app/lib/search/search_service.g.dart +++ b/app/lib/search/search_service.g.dart @@ -21,7 +21,7 @@ PackageDocument _$PackageDocumentFromJson(Map json) => tags: (json['tags'] as List?)?.map((e) => e as String).toList(), downloadCount: (json['downloadCount'] as num?)?.toInt(), downloadScore: (json['downloadScore'] as num?)?.toDouble(), - trendScore: (json['trendScore'] as num?)?.toInt(), + trendScore: (json['trendScore'] as num?)?.toDouble(), likeCount: (json['likeCount'] as num?)?.toInt(), likeScore: (json['likeScore'] as num?)?.toDouble(), grantedPoints: (json['grantedPoints'] as num?)?.toInt(), diff --git a/app/lib/service/download_counts/backend.dart b/app/lib/service/download_counts/backend.dart index fe3d30672a..a98e102650 100644 --- a/app/lib/service/download_counts/backend.dart +++ b/app/lib/service/download_counts/backend.dart @@ -31,16 +31,16 @@ class DownloadCountsBackend { late CachedValue> _thirtyDaysTotals; var _lastDownloadsData = (data: {}, etag: ''); - late CachedValue> _trendScores; - var _lastTrendData = (data: {}, etag: ''); + late CachedValue> _trendScores; + var _lastTrendData = (data: {}, etag: ''); DownloadCountsBackend(this._db) { - _thirtyDaysTotals = CachedValue( + _thirtyDaysTotals = CachedValue>( name: 'thirtyDaysTotalDownloadCounts', maxAge: Duration(days: 14), interval: Duration(minutes: 30), updateFn: _updateThirtyDaysTotals); - _trendScores = CachedValue( + _trendScores = CachedValue>( name: 'trendScores', maxAge: Duration(days: 14), interval: Duration(minutes: 30), @@ -48,25 +48,27 @@ class DownloadCountsBackend { } Future> _updateThirtyDaysTotals() async { - return _fetchAndUpdateCachedData( - fileName: downloadCounts30DaysTotalsFileName, - currentCachedData: _lastDownloadsData, - updateCache: (data) => _lastDownloadsData = data, - errorContext: '30-days total download counts'); + return _fetchAndUpdateCachedData( + fileName: downloadCounts30DaysTotalsFileName, + currentCachedData: _lastDownloadsData, + updateCache: (data) => _lastDownloadsData = data, + errorContext: '30-days total download counts', + ); } - Future> _updateTrendScores() async { - return _fetchAndUpdateCachedData( - fileName: trendScoreFileName, - currentCachedData: _lastTrendData, - updateCache: (data) => _lastTrendData = data, - errorContext: 'trend scores'); + Future> _updateTrendScores() async { + return _fetchAndUpdateCachedData( + fileName: trendScoreFileName, + currentCachedData: _lastTrendData, + updateCache: (data) => _lastTrendData = data, + errorContext: 'trend scores', + ); } - Future> _fetchAndUpdateCachedData({ + Future> _fetchAndUpdateCachedData({ required String fileName, - required ({Map data, String etag}) currentCachedData, - required void Function(({Map data, String etag}) newData) + required ({Map data, String etag}) currentCachedData, + required void Function(({Map data, String etag}) newData) updateCache, required String errorContext, }) async { @@ -89,7 +91,7 @@ class DownloadCountsBackend { .single, ); - final data = _parseJsonToMapStringInt(rawData, fileName); + final data = _parseJsonToMapStringV(rawData, fileName); final newData = (data: data, etag: info.etag); updateCache(newData); @@ -109,23 +111,25 @@ class DownloadCountsBackend { } } - Map _parseJsonToMapStringInt(dynamic rawJson, String fileName) { + Map _parseJsonToMapStringV(dynamic rawJson, String fileName) { if (rawJson is! Map) { - throw FormatException( - 'Expected JSON for $fileName to be a Map, but got ${rawJson.runtimeType}'); + throw FormatException('Expected JSON for $fileName to be a Map, but got' + ' ${rawJson.runtimeType}'); } - final Map result = {}; + final Map result = {}; for (final entry in rawJson.entries) { if (entry.key is! String) { throw FormatException( - 'Expected map keys for $fileName to be String, but found ${entry.key.runtimeType}'); + 'Expected map keys for $fileName to be String, but found' + ' ${entry.key.runtimeType}'); } - if (entry.value is! int) { + if (entry.value is! V) { throw FormatException( - 'Expected map value for key "${entry.key}" in $fileName to be int, but got ${entry.value.runtimeType}'); + 'Expected map value for key "${entry.key}" in $fileName to be' + ' ${V.runtimeType}, but got ${entry.value.runtimeType}'); } - result[entry.key as String] = entry.value as int; + result[entry.key as String] = entry.value as V; } return result; } @@ -143,7 +147,7 @@ class DownloadCountsBackend { int? lookup30DaysTotalCounts(String package) => _thirtyDaysTotals.isAvailable ? _thirtyDaysTotals.value![package] : null; - int? lookupTrendScore(String package) => + double? lookupTrendScore(String package) => _trendScores.isAvailable ? _trendScores.value![package] : null; Future lookupDownloadCountData(String pkg) async { diff --git a/app/test/service/download_counts/computations_test.dart b/app/test/service/download_counts/computations_test.dart index ccadfc4201..cffc0f2366 100644 --- a/app/test/service/download_counts/computations_test.dart +++ b/app/test/service/download_counts/computations_test.dart @@ -339,22 +339,22 @@ void main() { }); testWithProfile('cache package trend scores', fn: () async { - await generateFakeTrendScores({'foo': 3, 'bar': 1, 'baz': 2}); + await generateFakeTrendScores({'foo': 3.0, 'bar': 1.0, 'baz': 2.0}); expect(downloadCountsBackend.lookupTrendScore('foo'), isNull); expect(downloadCountsBackend.lookupTrendScore('bar'), isNull); expect(downloadCountsBackend.lookupTrendScore('baz'), isNull); await downloadCountsBackend.start(); - expect(downloadCountsBackend.lookupTrendScore('foo'), 3); - expect(downloadCountsBackend.lookupTrendScore('bar'), 1); - expect(downloadCountsBackend.lookupTrendScore('baz'), 2); + expect(downloadCountsBackend.lookupTrendScore('foo'), 3.0); + expect(downloadCountsBackend.lookupTrendScore('bar'), 1.0); + expect(downloadCountsBackend.lookupTrendScore('baz'), 2.0); expect(downloadCountsBackend.lookupTrendScore('bax'), isNull); - await generateFakeTrendScores({'foo': 9, 'bar': 2, 'baz': 5}); + await generateFakeTrendScores({'foo': 9.0, 'bar': 2.0, 'baz': 5.0}); await downloadCountsBackend.start(); - expect(downloadCountsBackend.lookupTrendScore('foo'), 9); - expect(downloadCountsBackend.lookupTrendScore('bar'), 2); - expect(downloadCountsBackend.lookupTrendScore('baz'), 5); + expect(downloadCountsBackend.lookupTrendScore('foo'), 9.0); + expect(downloadCountsBackend.lookupTrendScore('bar'), 2.0); + expect(downloadCountsBackend.lookupTrendScore('baz'), 5.0); expect(downloadCountsBackend.lookupTrendScore('bax'), isNull); }); }