Skip to content

Commit

Permalink
Better recursive paging (#54)
Browse files Browse the repository at this point in the history
  • Loading branch information
Rexios80 authored Dec 26, 2024
1 parent 25ea064 commit ce55f76
Show file tree
Hide file tree
Showing 4 changed files with 52 additions and 24 deletions.
11 changes: 9 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ Aims to be the most complete and stable pub.dev API client. If any particular en
- [Flutter Favorites](#flutter-favorites)
- [Google Packages](#google-packages)
- [Publisher Packages](#publisher-packages)
- [All Packages](#all-packages)

## Usage

Expand Down Expand Up @@ -231,7 +232,6 @@ print(results.packages)
Returns all Flutter favorites on pub.dev

```dart
final results = await client.fetchFlutterFavorites();
```

Expand All @@ -240,7 +240,6 @@ final results = await client.fetchFlutterFavorites();
Returns all official Google packages. This will be a large payload with hundreds of packages.

```dart
final results = await client.fetchGooglePackages();
```

Expand All @@ -252,3 +251,11 @@ Returns all packages for a specific publisher
final results = await client.fetchPublisherPackages();
```

### All Packages

Returns all packages that match a given query

```dart
final results = await fetchAllPackages('', tags: [PackageTag.publisher('leoafarias.com')])
```
19 changes: 8 additions & 11 deletions lib/src/helpers/recursive_paging.dart
Original file line number Diff line number Diff line change
@@ -1,17 +1,14 @@
import '../models/search_results_model.dart';
import '../pub_api_client_base.dart';

Future<List<PackageResult>> recursivePaging(
PubClient client,
SearchResults prevResults,
Future<List<T>> recursivePaging<T>(
PaginatedResults<T> prevResults,
Future<PaginatedResults<T>> Function(String url) getNext,
) async {
final packages = [...prevResults.packages];
final results = prevResults.results;
final nextPage = prevResults.next;
if (nextPage != null) {
final results = await client.nextPage(nextPage);
final nextResults = await recursivePaging(client, results);
packages.addAll(nextResults);
if (nextPage == null) {
return results;
}

return packages;
final next = await getNext(nextPage);
return results + await recursivePaging(next, getNext);
}
20 changes: 19 additions & 1 deletion lib/src/models/search_results_model.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,29 @@ import 'package:dart_mappable/dart_mappable.dart';

part 'search_results_model.mapper.dart';

/// Base class for results that are paginated
abstract class PaginatedResults<T> {
/// The current results
List<T> get results;

/// The URL to the next page of results
String? get next;

const PaginatedResults();
}

/// Search Results Model
@MappableClass()
class SearchResults with SearchResultsMappable {
class SearchResults extends PaginatedResults<PackageResult>
with SearchResultsMappable {
final List<PackageResult> packages;

@override
List<PackageResult> get results => packages;

@override
final String? next;

const SearchResults({
required this.packages,
this.next,
Expand Down
26 changes: 16 additions & 10 deletions lib/src/pub_api_client_base.dart
Original file line number Diff line number Diff line change
Expand Up @@ -212,6 +212,15 @@ class PubClient {
.toList();
}

/// Get all packages that match the query
Future<List<PackageResult>> fetchAllPackages(
String query, {
List<String> tags = const [],
}) async {
final results = await search(query, tags: tags);
return recursivePaging(results, nextPage);
}

/// Retrieves all Google packages from pub.dev
/// Mostly used as an internal tool to generate
/// google_packages_list.dart
Expand Down Expand Up @@ -240,22 +249,19 @@ class PubClient {

/// Retrieves all the flutter favorites
Future<List<String>> fetchFlutterFavorites() async {
final searchResults =
await search('', tags: [PackageTag.isFlutterFavorite]);
final results = await recursivePaging(this, searchResults);
final results =
await fetchAllPackages('', tags: [PackageTag.isFlutterFavorite]);
return results.map((r) => r.package).toList();
}

Future<List<PackageResult>> fetchPublisherPackages(
String publisherName, {
List<String> tags = const [],
}) async {
final results = await search('', tags: [
PackageTag.publisher(publisherName),
...tags,
]);
return recursivePaging(this, results);
}
}) =>
fetchAllPackages('', tags: [
PackageTag.publisher(publisherName),
...tags,
]);

void close() {
_client.close();
Expand Down

0 comments on commit ce55f76

Please sign in to comment.