2023-01-24 03:37:09 +00:00
|
|
|
import 'package:logging/logging.dart';
|
|
|
|
import 'package:result_monad/result_monad.dart';
|
2023-02-10 10:29:02 +00:00
|
|
|
import 'package:uuid/uuid.dart';
|
2023-01-24 03:37:09 +00:00
|
|
|
|
|
|
|
import '../models/exec_error.dart';
|
|
|
|
import 'paging_data.dart';
|
|
|
|
|
|
|
|
final _logger = Logger('PagedResponse');
|
|
|
|
|
|
|
|
class PagedResponse<T> {
|
2023-02-10 10:29:02 +00:00
|
|
|
String id;
|
2023-01-24 03:37:09 +00:00
|
|
|
PagingData? previous;
|
|
|
|
PagingData? next;
|
|
|
|
T data;
|
|
|
|
|
2023-02-10 10:29:02 +00:00
|
|
|
PagedResponse(this.data, {String? id, this.previous, this.next})
|
|
|
|
: id = id ?? Uuid().v4();
|
2023-01-24 03:37:09 +00:00
|
|
|
|
|
|
|
bool get hasMorePages => previous != null || next != null;
|
|
|
|
|
|
|
|
static Result<PagedResponse<T>, ExecError> fromLinkHeader<T>(
|
|
|
|
String? linkHeader, T data) {
|
|
|
|
if (linkHeader == null || linkHeader.isEmpty) {
|
|
|
|
return Result.ok(PagedResponse(data));
|
|
|
|
}
|
|
|
|
|
|
|
|
String? previousPage;
|
|
|
|
String? nextPage;
|
|
|
|
for (String linkTerms in linkHeader.trim().split(',')) {
|
|
|
|
if (linkHeader.isEmpty) {
|
|
|
|
return buildErrorResult(
|
|
|
|
type: ErrorType.parsingError,
|
|
|
|
message: 'Link header element is blank',
|
|
|
|
);
|
|
|
|
}
|
|
|
|
final paging = linkTerms.split(';');
|
|
|
|
if (paging.length != 2) {
|
|
|
|
return buildErrorResult(
|
|
|
|
type: ErrorType.parsingError,
|
|
|
|
message:
|
|
|
|
'Incorrect number of elements, ${paging.length} != 2, for: $linkTerms',
|
|
|
|
);
|
|
|
|
}
|
|
|
|
final urlPieceString = paging.first.trim();
|
|
|
|
if (!urlPieceString.startsWith('<') && !urlPieceString.endsWith('>')) {
|
|
|
|
return buildErrorResult(
|
|
|
|
type: ErrorType.parsingError,
|
|
|
|
message:
|
|
|
|
'Link URL is malformed (no leading trailing <>): $urlPieceString',
|
|
|
|
);
|
|
|
|
}
|
|
|
|
final url = urlPieceString.substring(1, urlPieceString.length - 1);
|
|
|
|
final directionString = paging.last.trim();
|
|
|
|
if (directionString == 'rel="prev"') {
|
|
|
|
previousPage = url;
|
|
|
|
} else if (directionString == 'rel="next"') {
|
|
|
|
nextPage = url;
|
|
|
|
} else {
|
|
|
|
_logger.info('Unknown paging data: $directionString for url: $url');
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return Result.ok(PagedResponse(
|
|
|
|
data,
|
|
|
|
previous: previousPage == null
|
|
|
|
? null
|
|
|
|
: PagingData.fromQueryParameters(
|
|
|
|
Uri.parse(previousPage),
|
|
|
|
),
|
|
|
|
next: nextPage == null
|
|
|
|
? null
|
|
|
|
: PagingData.fromQueryParameters(
|
|
|
|
Uri.parse(nextPage),
|
|
|
|
),
|
|
|
|
));
|
|
|
|
}
|
|
|
|
|
|
|
|
PagedResponse<T2> map<T2>(T2 Function(T data) func) => PagedResponse(
|
|
|
|
func(data),
|
|
|
|
previous: previous,
|
|
|
|
next: next,
|
2023-02-10 10:29:02 +00:00
|
|
|
id: id,
|
2023-01-24 03:37:09 +00:00
|
|
|
);
|
|
|
|
|
|
|
|
@override
|
|
|
|
String toString() {
|
|
|
|
return 'PagedResponse{previous: $previous, next: $next, data: $data}';
|
|
|
|
}
|
|
|
|
|
|
|
|
@override
|
|
|
|
bool operator ==(Object other) =>
|
|
|
|
identical(this, other) ||
|
|
|
|
other is PagedResponse &&
|
|
|
|
runtimeType == other.runtimeType &&
|
|
|
|
previous == other.previous &&
|
|
|
|
next == other.next &&
|
|
|
|
data == other.data;
|
|
|
|
|
|
|
|
@override
|
|
|
|
int get hashCode => previous.hashCode ^ next.hashCode ^ data.hashCode;
|
|
|
|
}
|