From 16d21be1a23e5df093d72ac72c632a065dc3ae9c Mon Sep 17 00:00:00 2001 From: Rexios Date: Tue, 19 Nov 2024 12:36:50 -0500 Subject: [PATCH] Make the recursive paging reusable --- lib/src/helpers/recursive_paging.dart | 19 ++- lib/src/models/search_results_model.dart | 42 +++++- .../models/search_results_model.mapper.dart | 122 ++++++++++++++++++ 3 files changed, 172 insertions(+), 11 deletions(-) diff --git a/lib/src/helpers/recursive_paging.dart b/lib/src/helpers/recursive_paging.dart index 8d3bf5d..9a178b7 100644 --- a/lib/src/helpers/recursive_paging.dart +++ b/lib/src/helpers/recursive_paging.dart @@ -1,15 +1,14 @@ import '../models/search_results_model.dart'; -import '../pub_api_client_base.dart'; -Future> recursivePaging( - PubClient client, SearchResults prevResults) async { - final packages = [...prevResults.packages]; +Future> recursivePaging( + PaginatedResults prevResults, + Future> Function(String url) getNext, +) async { + 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); } diff --git a/lib/src/models/search_results_model.dart b/lib/src/models/search_results_model.dart index 8202b85..59d968a 100644 --- a/lib/src/models/search_results_model.dart +++ b/lib/src/models/search_results_model.dart @@ -2,11 +2,51 @@ import 'package:dart_mappable/dart_mappable.dart'; part 'search_results_model.mapper.dart'; +/// Base class for results that are paginated +abstract class PaginatedResults { + /// The current results + List get results; + + /// The URL to the next page of results + String? get next; + + const PaginatedResults(); +} + +/// Package Names Model +@MappableClass() +class PackageNamesResults extends PaginatedResults { + final List packages; + + @override + List get results => packages; + + final String? nextUrl; + + @override + String? get next => nextUrl; + + const PackageNamesResults({ + required this.packages, + this.nextUrl, + }); + + static const fromMap = PackageNamesResultsMapper.fromMap; + static const fromJson = PackageNamesResultsMapper.fromJson; +} + /// Search Results Model @MappableClass() -class SearchResults with SearchResultsMappable { +class SearchResults extends PaginatedResults + with SearchResultsMappable { final List packages; + + @override + List get results => packages; + + @override final String? next; + const SearchResults({ required this.packages, this.next, diff --git a/lib/src/models/search_results_model.mapper.dart b/lib/src/models/search_results_model.mapper.dart index a28fc47..9bbd23e 100644 --- a/lib/src/models/search_results_model.mapper.dart +++ b/lib/src/models/search_results_model.mapper.dart @@ -6,6 +6,128 @@ part of 'search_results_model.dart'; +class PackageNamesResultsMapper extends ClassMapperBase { + PackageNamesResultsMapper._(); + + static PackageNamesResultsMapper? _instance; + static PackageNamesResultsMapper ensureInitialized() { + if (_instance == null) { + MapperContainer.globals.use(_instance = PackageNamesResultsMapper._()); + } + return _instance!; + } + + @override + final String id = 'PackageNamesResults'; + + static List _$packages(PackageNamesResults v) => v.packages; + static const Field> _f$packages = + Field('packages', _$packages); + static String? _$nextUrl(PackageNamesResults v) => v.nextUrl; + static const Field _f$nextUrl = + Field('nextUrl', _$nextUrl, opt: true); + + @override + final MappableFields fields = const { + #packages: _f$packages, + #nextUrl: _f$nextUrl, + }; + + static PackageNamesResults _instantiate(DecodingData data) { + return PackageNamesResults( + packages: data.dec(_f$packages), nextUrl: data.dec(_f$nextUrl)); + } + + @override + final Function instantiate = _instantiate; + + static PackageNamesResults fromMap(Map map) { + return ensureInitialized().decodeMap(map); + } + + static PackageNamesResults fromJson(String json) { + return ensureInitialized().decodeJson(json); + } +} + +mixin PackageNamesResultsMappable { + String toJson() { + return PackageNamesResultsMapper.ensureInitialized() + .encodeJson(this as PackageNamesResults); + } + + Map toMap() { + return PackageNamesResultsMapper.ensureInitialized() + .encodeMap(this as PackageNamesResults); + } + + PackageNamesResultsCopyWith + get copyWith => _PackageNamesResultsCopyWithImpl( + this as PackageNamesResults, $identity, $identity); + @override + String toString() { + return PackageNamesResultsMapper.ensureInitialized() + .stringifyValue(this as PackageNamesResults); + } + + @override + bool operator ==(Object other) { + return PackageNamesResultsMapper.ensureInitialized() + .equalsValue(this as PackageNamesResults, other); + } + + @override + int get hashCode { + return PackageNamesResultsMapper.ensureInitialized() + .hashValue(this as PackageNamesResults); + } +} + +extension PackageNamesResultsValueCopy<$R, $Out> + on ObjectCopyWith<$R, PackageNamesResults, $Out> { + PackageNamesResultsCopyWith<$R, PackageNamesResults, $Out> + get $asPackageNamesResults => + $base.as((v, t, t2) => _PackageNamesResultsCopyWithImpl(v, t, t2)); +} + +abstract class PackageNamesResultsCopyWith<$R, $In extends PackageNamesResults, + $Out> implements ClassCopyWith<$R, $In, $Out> { + ListCopyWith<$R, String, ObjectCopyWith<$R, String, String>> get packages; + $R call({List? packages, String? nextUrl}); + PackageNamesResultsCopyWith<$R2, $In, $Out2> $chain<$R2, $Out2>( + Then<$Out2, $R2> t); +} + +class _PackageNamesResultsCopyWithImpl<$R, $Out> + extends ClassCopyWithBase<$R, PackageNamesResults, $Out> + implements PackageNamesResultsCopyWith<$R, PackageNamesResults, $Out> { + _PackageNamesResultsCopyWithImpl(super.value, super.then, super.then2); + + @override + late final ClassMapperBase $mapper = + PackageNamesResultsMapper.ensureInitialized(); + @override + ListCopyWith<$R, String, ObjectCopyWith<$R, String, String>> get packages => + ListCopyWith($value.packages, (v, t) => ObjectCopyWith(v, $identity, t), + (v) => call(packages: v)); + @override + $R call({List? packages, Object? nextUrl = $none}) => + $apply(FieldCopyWithData({ + if (packages != null) #packages: packages, + if (nextUrl != $none) #nextUrl: nextUrl + })); + @override + PackageNamesResults $make(CopyWithData data) => PackageNamesResults( + packages: data.get(#packages, or: $value.packages), + nextUrl: data.get(#nextUrl, or: $value.nextUrl)); + + @override + PackageNamesResultsCopyWith<$R2, PackageNamesResults, $Out2> + $chain<$R2, $Out2>(Then<$Out2, $R2> t) => + _PackageNamesResultsCopyWithImpl($value, $cast, t); +} + class SearchResultsMapper extends ClassMapperBase { SearchResultsMapper._();