Skip to content

Commit ce55f76

Browse files
authored
Better recursive paging (#54)
1 parent 25ea064 commit ce55f76

File tree

4 files changed

+52
-24
lines changed

4 files changed

+52
-24
lines changed

README.md

+9-2
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ Aims to be the most complete and stable pub.dev API client. If any particular en
2727
- [Flutter Favorites](#flutter-favorites)
2828
- [Google Packages](#google-packages)
2929
- [Publisher Packages](#publisher-packages)
30+
- [All Packages](#all-packages)
3031

3132
## Usage
3233

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

233234
```dart
234-
235235
final results = await client.fetchFlutterFavorites();
236236
```
237237

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

242242
```dart
243-
244243
final results = await client.fetchGooglePackages();
245244
```
246245

@@ -252,3 +251,11 @@ Returns all packages for a specific publisher
252251
253252
final results = await client.fetchPublisherPackages();
254253
```
254+
255+
### All Packages
256+
257+
Returns all packages that match a given query
258+
259+
```dart
260+
final results = await fetchAllPackages('', tags: [PackageTag.publisher('leoafarias.com')])
261+
```

lib/src/helpers/recursive_paging.dart

+8-11
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,14 @@
11
import '../models/search_results_model.dart';
2-
import '../pub_api_client_base.dart';
32

4-
Future<List<PackageResult>> recursivePaging(
5-
PubClient client,
6-
SearchResults prevResults,
3+
Future<List<T>> recursivePaging<T>(
4+
PaginatedResults<T> prevResults,
5+
Future<PaginatedResults<T>> Function(String url) getNext,
76
) async {
8-
final packages = [...prevResults.packages];
7+
final results = prevResults.results;
98
final nextPage = prevResults.next;
10-
if (nextPage != null) {
11-
final results = await client.nextPage(nextPage);
12-
final nextResults = await recursivePaging(client, results);
13-
packages.addAll(nextResults);
9+
if (nextPage == null) {
10+
return results;
1411
}
15-
16-
return packages;
12+
final next = await getNext(nextPage);
13+
return results + await recursivePaging(next, getNext);
1714
}

lib/src/models/search_results_model.dart

+19-1
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,29 @@ import 'package:dart_mappable/dart_mappable.dart';
22

33
part 'search_results_model.mapper.dart';
44

5+
/// Base class for results that are paginated
6+
abstract class PaginatedResults<T> {
7+
/// The current results
8+
List<T> get results;
9+
10+
/// The URL to the next page of results
11+
String? get next;
12+
13+
const PaginatedResults();
14+
}
15+
516
/// Search Results Model
617
@MappableClass()
7-
class SearchResults with SearchResultsMappable {
18+
class SearchResults extends PaginatedResults<PackageResult>
19+
with SearchResultsMappable {
820
final List<PackageResult> packages;
21+
22+
@override
23+
List<PackageResult> get results => packages;
24+
25+
@override
926
final String? next;
27+
1028
const SearchResults({
1129
required this.packages,
1230
this.next,

lib/src/pub_api_client_base.dart

+16-10
Original file line numberDiff line numberDiff line change
@@ -212,6 +212,15 @@ class PubClient {
212212
.toList();
213213
}
214214

215+
/// Get all packages that match the query
216+
Future<List<PackageResult>> fetchAllPackages(
217+
String query, {
218+
List<String> tags = const [],
219+
}) async {
220+
final results = await search(query, tags: tags);
221+
return recursivePaging(results, nextPage);
222+
}
223+
215224
/// Retrieves all Google packages from pub.dev
216225
/// Mostly used as an internal tool to generate
217226
/// google_packages_list.dart
@@ -240,22 +249,19 @@ class PubClient {
240249

241250
/// Retrieves all the flutter favorites
242251
Future<List<String>> fetchFlutterFavorites() async {
243-
final searchResults =
244-
await search('', tags: [PackageTag.isFlutterFavorite]);
245-
final results = await recursivePaging(this, searchResults);
252+
final results =
253+
await fetchAllPackages('', tags: [PackageTag.isFlutterFavorite]);
246254
return results.map((r) => r.package).toList();
247255
}
248256

249257
Future<List<PackageResult>> fetchPublisherPackages(
250258
String publisherName, {
251259
List<String> tags = const [],
252-
}) async {
253-
final results = await search('', tags: [
254-
PackageTag.publisher(publisherName),
255-
...tags,
256-
]);
257-
return recursivePaging(this, results);
258-
}
260+
}) =>
261+
fetchAllPackages('', tags: [
262+
PackageTag.publisher(publisherName),
263+
...tags,
264+
]);
259265

260266
void close() {
261267
_client.close();

0 commit comments

Comments
 (0)