From 957bd8b7732db4706b44dede4db9fdc3492c9769 Mon Sep 17 00:00:00 2001 From: Leo Farias Date: Tue, 8 Aug 2023 14:39:05 -0400 Subject: [PATCH 1/5] Update close behavior --- example/example.dart | 1 + lib/src/helpers/http_client.dart | 18 ----------- lib/src/pub_api_client_base.dart | 51 +++++++++++++++++++------------- 3 files changed, 32 insertions(+), 38 deletions(-) delete mode 100644 lib/src/helpers/http_client.dart diff --git a/example/example.dart b/example/example.dart index a7d9a7b..7a9495b 100644 --- a/example/example.dart +++ b/example/example.dart @@ -4,4 +4,5 @@ void main() async { final client = PubClient(); final packageScore = await client.packageScore('fvm'); print('Package Score: $packageScore'); + client.close(); } diff --git a/lib/src/helpers/http_client.dart b/lib/src/helpers/http_client.dart deleted file mode 100644 index bc2d780..0000000 --- a/lib/src/helpers/http_client.dart +++ /dev/null @@ -1,18 +0,0 @@ -import 'package:http/http.dart' as http; - -import '../version.dart'; - -class PubApiHttpClient extends http.BaseClient { - final http.Client _inner; - final String? userAgent; - // final Credentials? credentials; - PubApiHttpClient(this._inner, {this.userAgent = 'default'}); - - @override - Future send(http.BaseRequest request) { - request.headers['user-agent'] = - 'pub_api_client/$packageVersion ($userAgent)'; - - return _inner.send(request); - } -} diff --git a/lib/src/pub_api_client_base.dart b/lib/src/pub_api_client_base.dart index 0d7c1cb..5f6a7ac 100644 --- a/lib/src/pub_api_client_base.dart +++ b/lib/src/pub_api_client_base.dart @@ -6,7 +6,6 @@ import 'package:oauth2/oauth2.dart'; import 'constants.dart'; import 'endpoints.dart'; import 'helpers/exceptions.dart'; -import 'helpers/http_client.dart'; import 'helpers/recursive_paging.dart'; import 'models/package_documentation_model.dart'; import 'models/package_like_model.dart'; @@ -17,54 +16,67 @@ import 'models/package_score_model.dart'; import 'models/pub_package_model.dart'; import 'models/search_order.dart'; import 'models/search_results_model.dart'; - -typedef FetchFunction = Future> Function(String url); +import 'version.dart'; /// Pub API Client class PubClient { final Endpoint endpoint; final String? pubUrl; - final http.Client? client; - final String? userAgent; - final Credentials? credentials; - late final PubApiHttpClient _client; + late http.Client _client; + late Map _headers = {}; + PubClient({ this.pubUrl, - this.credentials, - this.client, - this.userAgent, + Credentials? credentials, + http.Client? client, + String? userAgent, }) : endpoint = Endpoint(pubUrl) { http.Client httpClient; if (credentials == null) { httpClient = http.Client(); } else { httpClient = Client( - credentials!, + credentials, identifier: PubAuth.identifier, secret: PubAuth.secret, ); } - _client = PubApiHttpClient( - client ?? httpClient, - userAgent: userAgent, - ); + userAgent ??= 'default'; + + _headers = { + 'user-agent': 'pub_api_client/$packageVersion ($userAgent)', + }; + _client = client ?? httpClient; } Future> _fetch(String url) async { - final response = await _client.get(Uri.parse(url)); + final response = await _client.get( + Uri.parse(url), + headers: _headers, + ); + responseValidOrThrow(response); + return jsonDecode(response.body) as Map; } Future> _put(String url) async { - final response = await _client.put(Uri.parse(url)); + final response = await _client.put( + Uri.parse(url), + headers: _headers, + ); + responseValidOrThrow(response); return jsonDecode(response.body) as Map; } Future _delete(String url) async { - final response = await _client.delete(Uri.parse(url)); + final response = await _client.delete( + Uri.parse(url), + headers: _headers, + ); + responseValidOrThrow(response); } @@ -94,7 +106,6 @@ class PubClient { /// Returns the `PackageOptions` for package [packageName] Future packageOptions(String packageName) async { final data = await _fetch(endpoint.packageOptions(packageName)); - return PackageOptions.fromMap(data); } @@ -235,6 +246,6 @@ class PubClient { } void close() { - client?.close(); + _client.close(); } } From c5c8eb25740f769266e69120cd33a369143ec3ea Mon Sep 17 00:00:00 2001 From: Leo Farias Date: Tue, 8 Aug 2023 14:51:33 -0400 Subject: [PATCH 2/5] Updated data classes with equality and toString --- lib/src/models/latest_version_model.dart | 4 ++ .../models/package_documentation_model.dart | 7 ++++ lib/src/models/package_like_model.dart | 15 +++++++ lib/src/models/package_metrics_model.dart | 15 +++++++ lib/src/models/package_options_model.dart | 18 ++++++++ lib/src/models/package_publisher_model.dart | 13 ++++++ lib/src/models/package_score_model.dart | 10 +++++ lib/src/models/pub_package_model.dart | 41 +++++++++++++++++++ lib/src/models/search_results_model.dart | 6 +++ 9 files changed, 129 insertions(+) diff --git a/lib/src/models/latest_version_model.dart b/lib/src/models/latest_version_model.dart index 9a3fc34..2053c0f 100644 --- a/lib/src/models/latest_version_model.dart +++ b/lib/src/models/latest_version_model.dart @@ -26,4 +26,8 @@ class LatestVersion { @override int get hashCode => needUpdate.hashCode ^ latestVersion.hashCode ^ packageInfo.hashCode; + + @override + String toString() => + 'LatestVersion(needUpdate: $needUpdate, latestVersion: $latestVersion, packageInfo: $packageInfo)'; } diff --git a/lib/src/models/package_documentation_model.dart b/lib/src/models/package_documentation_model.dart index 8e7e12e..23e9ece 100644 --- a/lib/src/models/package_documentation_model.dart +++ b/lib/src/models/package_documentation_model.dart @@ -46,6 +46,9 @@ class PackageDocumentation { @override int get hashCode => name.hashCode ^ versions.hashCode; + + @override + String toString() => 'PackageDocumentation(name: $name, versions: $versions)'; } /// Package Documentation Version Model @@ -92,4 +95,8 @@ class PackageDocumentationVersion { @override int get hashCode => version.hashCode ^ status.hashCode ^ hasDocumentation.hashCode; + + @override + String toString() => + 'PackageDocumentationVersion(version: $version, status: $status, hasDocumentation: $hasDocumentation)'; } diff --git a/lib/src/models/package_like_model.dart b/lib/src/models/package_like_model.dart index 9cb1a3e..3264c1b 100644 --- a/lib/src/models/package_like_model.dart +++ b/lib/src/models/package_like_model.dart @@ -17,4 +17,19 @@ class PackageLike { package: map['package'] as String? ?? '', liked: map['liked'] as bool? ?? false, ); + + @override + bool operator ==(Object other) { + if (identical(this, other)) return true; + + return other is PackageLike && + other.package == package && + other.liked == liked; + } + + @override + int get hashCode => package.hashCode ^ liked.hashCode; + + @override + String toString() => 'PackageLike(package: $package, liked: $liked)'; } diff --git a/lib/src/models/package_metrics_model.dart b/lib/src/models/package_metrics_model.dart index 13d65d8..aac682e 100644 --- a/lib/src/models/package_metrics_model.dart +++ b/lib/src/models/package_metrics_model.dart @@ -20,4 +20,19 @@ class PackageMetrics { scorecard: PackageScoreCard.fromMap(map['scorecard'] as Map), ); + + @override + String toString() => 'PackageMetrics(score: $score, scorecard: $scorecard)'; + + @override + bool operator ==(Object other) { + if (identical(this, other)) return true; + + return other is PackageMetrics && + other.score == score && + other.scorecard == scorecard; + } + + @override + int get hashCode => score.hashCode ^ scorecard.hashCode; } diff --git a/lib/src/models/package_options_model.dart b/lib/src/models/package_options_model.dart index 96d57aa..4b1549c 100644 --- a/lib/src/models/package_options_model.dart +++ b/lib/src/models/package_options_model.dart @@ -22,4 +22,22 @@ class PackageOptions { isUnlisted: map['isUnlisted'] as bool? ?? false, replacedBy: map['replacedBy'] as String?, ); + + @override + String toString() => + 'PackageOptions(isDiscontinued: $isDiscontinued, isUnlisted: $isUnlisted, replacedBy: $replacedBy)'; + + @override + bool operator ==(Object other) { + if (identical(this, other)) return true; + + return other is PackageOptions && + other.isDiscontinued == isDiscontinued && + other.isUnlisted == isUnlisted && + other.replacedBy == replacedBy; + } + + @override + int get hashCode => + isDiscontinued.hashCode ^ isUnlisted.hashCode ^ replacedBy.hashCode; } diff --git a/lib/src/models/package_publisher_model.dart b/lib/src/models/package_publisher_model.dart index 5da0fb1..c77d9bd 100644 --- a/lib/src/models/package_publisher_model.dart +++ b/lib/src/models/package_publisher_model.dart @@ -14,4 +14,17 @@ class PackagePublisher { PackagePublisher( publisherId: map['publisherId'] as String?, ); + + @override + String toString() => 'PackagePublisher(publisherId: $publisherId)'; + + @override + bool operator ==(Object other) { + if (identical(this, other)) return true; + + return other is PackagePublisher && other.publisherId == publisherId; + } + + @override + int get hashCode => publisherId.hashCode; } diff --git a/lib/src/models/package_score_model.dart b/lib/src/models/package_score_model.dart index c20592c..3296b04 100644 --- a/lib/src/models/package_score_model.dart +++ b/lib/src/models/package_score_model.dart @@ -1,5 +1,7 @@ import 'package:collection/collection.dart'; +// ignore_for_file: lines_longer_than_80_chars + /// Package Score Model class PackageScore { final int? grantedPoints; @@ -31,6 +33,10 @@ class PackageScore { lastUpdated: DateTime.parse(map['lastUpdated'] as String? ?? ''), ); + @override + String toString() => + 'PackageScore(grantedPoints: $grantedPoints, maxPoints: $maxPoints, likeCount: $likeCount, popularityScore: $popularityScore, lastUpdated: $lastUpdated)'; + @override bool operator ==(Object other) { if (identical(this, other)) return true; @@ -103,6 +109,10 @@ class PackageScoreCard { List.from(map['reportTypes'] as List? ?? []), ); + @override + String toString() => + 'PackageScoreCard(packageName: $packageName, packageVersion: $packageVersion, runtimeVersion: $runtimeVersion, updated: $updated, packageCreated: $packageCreated, packageVersionCreated: $packageVersionCreated, derivedTags: $derivedTags, flags: $flags, reportTypes: $reportTypes)'; + @override bool operator ==(Object other) { if (identical(this, other)) return true; diff --git a/lib/src/models/pub_package_model.dart b/lib/src/models/pub_package_model.dart index 8b5844a..a15ad41 100644 --- a/lib/src/models/pub_package_model.dart +++ b/lib/src/models/pub_package_model.dart @@ -1,3 +1,4 @@ +import 'package:collection/collection.dart'; import 'package:pubspec/pubspec.dart'; /// Package Model @@ -36,6 +37,24 @@ class PubPackage { ), ); } + + @override + String toString() => + 'PubPackage(name: $name, latest: $latest, versions: $versions)'; + + @override + bool operator ==(Object other) { + if (identical(this, other)) return true; + final listEquals = const DeepCollectionEquality().equals; + + return other is PubPackage && + other.name == name && + other.latest == latest && + listEquals(other.versions, versions); + } + + @override + int get hashCode => name.hashCode ^ latest.hashCode ^ versions.hashCode; } /// Package Version Model @@ -65,4 +84,26 @@ class PackageVersion { archiveUrl: map['archiveUrl'] as String? ?? '', published: DateTime.parse(map['published'] as String? ?? ''), ); + + @override + String toString() => + 'PackageVersion(version: $version, pubspec: $pubspec, archiveUrl: $archiveUrl, published: $published)'; + + @override + bool operator ==(Object other) { + if (identical(this, other)) return true; + + return other is PackageVersion && + other.version == version && + other.pubspec == pubspec && + other.archiveUrl == archiveUrl && + other.published == published; + } + + @override + int get hashCode => + version.hashCode ^ + pubspec.hashCode ^ + archiveUrl.hashCode ^ + published.hashCode; } diff --git a/lib/src/models/search_results_model.dart b/lib/src/models/search_results_model.dart index d0aef59..82663dc 100644 --- a/lib/src/models/search_results_model.dart +++ b/lib/src/models/search_results_model.dart @@ -26,6 +26,9 @@ class SearchResults { ); } + @override + String toString() => 'SearchResults(packages: $packages, next: $next)'; + @override bool operator ==(Object other) { if (identical(this, other)) return true; @@ -53,6 +56,9 @@ class PackageResult { package: map['package'] as String? ?? '', ); + @override + String toString() => 'PackageResult(package: $package)'; + @override bool operator ==(Object other) { if (identical(this, other)) return true; From 80403fee7bdd9b7f4069f81511276f79548b67fa Mon Sep 17 00:00:00 2001 From: Leo Farias Date: Tue, 8 Aug 2023 15:33:08 -0400 Subject: [PATCH 3/5] Added topics and version bump --- CHANGELOG.md | 6 ++++++ lib/src/pub_api_client_base.dart | 10 ++++++++++ lib/src/version.dart | 2 +- pubspec.yaml | 2 +- test/pubdev_api_test.dart | 22 +++++++++++++++++----- 5 files changed, 35 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 771ccc5..fb0f737 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,9 @@ +## 2.6.0 + +- Feature: Added topics parameters to search method +- Chore: Improved models equality and toString methods +- Fix: Hanging on close [#40](https://github.com/leoafarias/pub_api_client/pull/40) + ## 2.5.0 - Feature: Ability to customize user-agent diff --git a/lib/src/pub_api_client_base.dart b/lib/src/pub_api_client_base.dart index 5f6a7ac..764bdd8 100644 --- a/lib/src/pub_api_client_base.dart +++ b/lib/src/pub_api_client_base.dart @@ -22,6 +22,7 @@ import 'version.dart'; class PubClient { final Endpoint endpoint; final String? pubUrl; + final bool debug; late http.Client _client; late Map _headers = {}; @@ -29,6 +30,7 @@ class PubClient { this.pubUrl, Credentials? credentials, http.Client? client, + this.debug = false, String? userAgent, }) : endpoint = Endpoint(pubUrl) { http.Client httpClient; @@ -51,6 +53,9 @@ class PubClient { } Future> _fetch(String url) async { + if (debug) { + print('Fetching: $url'); + } final response = await _client.get( Uri.parse(url), headers: _headers, @@ -152,11 +157,16 @@ class PubClient { int page = 1, SearchOrder sort = SearchOrder.top, List tags = const [], + List topics = const [], }) async { final buffer = StringBuffer(query); for (final tag in tags) { buffer.write(' $tag'); } + + for (final topic in topics) { + buffer.write(' topic:$topic'); + } final data = await _fetch(endpoint.search(buffer.toString(), page, sort)); return SearchResults.fromMap(data); } diff --git a/lib/src/version.dart b/lib/src/version.dart index 63fd551..d3561d8 100644 --- a/lib/src/version.dart +++ b/lib/src/version.dart @@ -1,2 +1,2 @@ // Generated code. Do not modify. -const packageVersion = '2.5.0'; +const packageVersion = '2.6.0'; diff --git a/pubspec.yaml b/pubspec.yaml index 46c71fb..04a5132 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,6 +1,6 @@ name: pub_api_client description: An API Client for Pub to interact with public package information. -version: 2.5.0 +version: 2.6.0 homepage: https://github.com/leoafarias/pub_api_client environment: diff --git a/test/pubdev_api_test.dart b/test/pubdev_api_test.dart index 048c024..dace594 100644 --- a/test/pubdev_api_test.dart +++ b/test/pubdev_api_test.dart @@ -5,7 +5,7 @@ import 'package:pub_api_client/pub_api_client.dart'; import 'package:test/test.dart'; const packageName = 'fvm'; -final client = PubClient(); +final client = PubClient(debug: true); void main() { group('PubDev Client', () { @@ -40,8 +40,10 @@ void main() { test('Get package version info', () async { final package = await client.packageInfo(packageName); - final version = - await client.packageVersionInfo(packageName, package.version); + final version = await client.packageVersionInfo( + packageName, + package.version, + ); expect(package.latest.archiveUrl, version.archiveUrl); expect(package.version, version.version); @@ -111,8 +113,10 @@ void main() { test('Search for packages of a publisher', () async { final payload = await client.search('', tags: [PackageTag.publisher('fvm.app')]); - final nextPagePayload = await client - .search('', tags: [PackageTag.dependency('pub_api_client')]); + final nextPagePayload = await client.search( + '', + tags: [PackageTag.dependency('pub_api_client')], + ); expect(payload.packages.length, greaterThan(0)); expect(nextPagePayload.packages.length, greaterThan(0)); }); @@ -127,6 +131,14 @@ void main() { expect(packages.length, greaterThan(20000)); }); + test('Get package topics', () async { + final results = await client.search('', topics: ['ffi']); + final zeroResults = await client.search('', topics: ['h8haisd091']); + + expect(results.packages.length, greaterThan(0)); + expect(zeroResults.packages.length, 0); + }); + // test('Can like, unlike, and view liked packages', () async { // if (pubCredentials == null) { // print('Skipping test. No credentials found.'); From 8d5aa36fc808ff6dfb65713ba93ea211316ef1bc Mon Sep 17 00:00:00 2001 From: Leo Farias Date: Tue, 8 Aug 2023 15:37:19 -0400 Subject: [PATCH 4/5] Update readme --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index f165a96..b91c0d1 100644 --- a/README.md +++ b/README.md @@ -162,6 +162,7 @@ final results = await client.search( PackageTag.dependency('dependency_name'), 'another:tag', ], + topics:['topic_1', 'topic_2'], ); // Returns the packages that match the query print(results.packages) From c9300c0443e45a11bfac9e98950fe9ff4e45b626 Mon Sep 17 00:00:00 2001 From: Leo Farias Date: Tue, 8 Aug 2023 15:42:43 -0400 Subject: [PATCH 5/5] Updated linting --- lib/src/models/latest_version_model.dart | 2 +- lib/src/models/package_documentation_model.dart | 2 +- lib/src/models/package_options_model.dart | 2 +- lib/src/models/pub_package_model.dart | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/src/models/latest_version_model.dart b/lib/src/models/latest_version_model.dart index 2053c0f..32d50d2 100644 --- a/lib/src/models/latest_version_model.dart +++ b/lib/src/models/latest_version_model.dart @@ -29,5 +29,5 @@ class LatestVersion { @override String toString() => - 'LatestVersion(needUpdate: $needUpdate, latestVersion: $latestVersion, packageInfo: $packageInfo)'; + '''LatestVersion(needUpdate: $needUpdate, latestVersion: $latestVersion, packageInfo: $packageInfo)'''; } diff --git a/lib/src/models/package_documentation_model.dart b/lib/src/models/package_documentation_model.dart index 23e9ece..96994a3 100644 --- a/lib/src/models/package_documentation_model.dart +++ b/lib/src/models/package_documentation_model.dart @@ -98,5 +98,5 @@ class PackageDocumentationVersion { @override String toString() => - 'PackageDocumentationVersion(version: $version, status: $status, hasDocumentation: $hasDocumentation)'; + '''PackageDocumentationVersion(version: $version, status: $status, hasDocumentation: $hasDocumentation)'''; } diff --git a/lib/src/models/package_options_model.dart b/lib/src/models/package_options_model.dart index 4b1549c..3f45e30 100644 --- a/lib/src/models/package_options_model.dart +++ b/lib/src/models/package_options_model.dart @@ -25,7 +25,7 @@ class PackageOptions { @override String toString() => - 'PackageOptions(isDiscontinued: $isDiscontinued, isUnlisted: $isUnlisted, replacedBy: $replacedBy)'; + '''PackageOptions(isDiscontinued: $isDiscontinued, isUnlisted: $isUnlisted, replacedBy: $replacedBy)'''; @override bool operator ==(Object other) { diff --git a/lib/src/models/pub_package_model.dart b/lib/src/models/pub_package_model.dart index a15ad41..6e5395c 100644 --- a/lib/src/models/pub_package_model.dart +++ b/lib/src/models/pub_package_model.dart @@ -87,7 +87,7 @@ class PackageVersion { @override String toString() => - 'PackageVersion(version: $version, pubspec: $pubspec, archiveUrl: $archiveUrl, published: $published)'; + '''PackageVersion(version: $version, pubspec: $pubspec, archiveUrl: $archiveUrl, published: $published)'''; @override bool operator ==(Object other) {