Files
fl-query/packages/fl_query/lib/src/query.dart
T

137 lines
3.9 KiB
Dart

import 'dart:async';
import 'package:connectivity_plus/connectivity_plus.dart';
import 'package:fl_query/fl_query.dart';
import 'package:fl_query/src/base_query.dart';
import 'package:fl_query/src/models/query_job.dart';
import 'package:flutter/widgets.dart';
enum QueryStatus {
/// in times when an error occurs
/// will get reset to idle on refetch/retry
error,
/// when a query successfully executes
success,
/// when the query is running (not refetching)
loading,
/// when the query isn't yet fetched, re-fetched, or got reset
/// mostly when both [data] & [error] are null. Also [fetched] is false
idle,
/// when the query is refetching (rerunning)
refetching;
}
typedef QueryTaskFunction<T extends Object, Outside> = FutureOr<T> Function(
String queryKey,
Outside externalData,
);
typedef QueryListener<T> = FutureOr<void> Function(T);
typedef ListenerUnsubscriber = void Function();
typedef QueryUpdateFunction<T> = FutureOr<T> Function(T? oldData);
class Query<T extends Object, Outside> extends BaseQuery<T, Outside, dynamic> {
QueryTaskFunction<T, Outside> task;
final Set<QueryListener<T>> onDataListeners = Set();
final Set<QueryListener<dynamic>> onErrorListeners = Set();
Query({
required super.queryKey,
required this.task,
required super.staleTime,
required super.cacheTime,
required super.externalData,
required super.retries,
required super.retryDelay,
required super.status,
super.refetchOnMount,
super.refetchOnReconnect,
super.refetchInterval,
super.enabled,
super.previousData,
super.connectivity,
super.initialData,
super.refetchOnApplicationResume,
QueryListener<T>? super.onData,
QueryListener<dynamic>? super.onError,
});
Query.fromOptions(
QueryJob<T, Outside> options, {
required Outside externalData,
T? previousData,
QueryListener<T>? onData,
QueryListener<dynamic>? onError,
}) : task = options.task,
super(
cacheTime: options.cacheTime ?? const Duration(minutes: 5),
retries: options.retries ?? 3,
retryDelay: options.retryDelay ?? const Duration(milliseconds: 200),
externalData: externalData,
enabled: options.enabled ?? true,
staleTime: options.staleTime ?? const Duration(milliseconds: 500),
initialData: options.initialData,
refetchInterval: options.refetchInterval,
refetchOnMount: options.refetchOnMount,
refetchOnReconnect: options.refetchOnReconnect,
status: previousData == null ? QueryStatus.idle : QueryStatus.success,
connectivity: options.connectivity ?? Connectivity(),
previousData: previousData,
queryKey: options.queryKey,
refetchOnApplicationResume: options.refetchOnApplicationResume,
onData: onData,
onError: onError,
);
@override
Timer createRefetchTimer() {
return Timer.periodic(
refetchInterval!,
(_) async {
// only refetch if its connected to the internet or refetch will
// always result in error while there's no internet
if (isStale && await isInternetConnected()) await refetch();
},
);
}
String get debugLabel => "Query($queryKey)";
@override
void mount(ValueKey<String> uKey) {
super.mount(uKey);
/// refetching on mount if it's set to true
/// also checking if the is stale or not
/// no need to refetch a valid query for no reason
if (refetchOnMount == true && isStale) {
this.isInternetConnected().then((isConnected) async {
if (isConnected) await refetch();
});
}
}
@override
bool operator ==(other) {
return (other is Query<T, Outside> && other.queryKey == queryKey) ||
identical(other, this);
}
@override
FutureOr<void> setData() async {
data = await task(queryKey, externalData);
}
@override
void setError(e) {
error = e;
}
}