feat: initial query and retryer implementation

This commit is contained in:
Kingkor Roy Tirtho
2023-02-10 22:11:33 +06:00
parent f632fe8403
commit b304466d73
11 changed files with 248 additions and 24 deletions
+10 -11
View File
@@ -1,12 +1,11 @@
# This is a generated file; do not edit or check into version control.
connectivity_plus=/home/krtirtho/.pub-cache/hosted/pub.dartlang.org/connectivity_plus-2.3.9/
connectivity_plus_linux=/home/krtirtho/.pub-cache/hosted/pub.dartlang.org/connectivity_plus_linux-1.3.1/
connectivity_plus_macos=/home/krtirtho/.pub-cache/hosted/pub.dartlang.org/connectivity_plus_macos-1.2.6/
connectivity_plus_web=/home/krtirtho/.pub-cache/hosted/pub.dartlang.org/connectivity_plus_web-1.2.5/
connectivity_plus_windows=/home/krtirtho/.pub-cache/hosted/pub.dartlang.org/connectivity_plus_windows-1.2.2/
path_provider=/home/krtirtho/.pub-cache/hosted/pub.dartlang.org/path_provider-2.0.11/
path_provider_android=/home/krtirtho/.pub-cache/hosted/pub.dartlang.org/path_provider_android-2.0.22/
path_provider_ios=/home/krtirtho/.pub-cache/hosted/pub.dartlang.org/path_provider_ios-2.0.11/
path_provider_linux=/home/krtirtho/.pub-cache/hosted/pub.dartlang.org/path_provider_linux-2.1.7/
path_provider_macos=/home/krtirtho/.pub-cache/hosted/pub.dartlang.org/path_provider_macos-2.0.6/
path_provider_windows=/home/krtirtho/.pub-cache/hosted/pub.dartlang.org/path_provider_windows-2.1.3/
connectivity_plus=/home/krtirtho/.pub-cache/hosted/pub.dev/connectivity_plus-2.3.9/
connectivity_plus_linux=/home/krtirtho/.pub-cache/hosted/pub.dev/connectivity_plus_linux-1.3.1/
connectivity_plus_macos=/home/krtirtho/.pub-cache/hosted/pub.dev/connectivity_plus_macos-1.2.6/
connectivity_plus_web=/home/krtirtho/.pub-cache/hosted/pub.dev/connectivity_plus_web-1.2.5/
connectivity_plus_windows=/home/krtirtho/.pub-cache/hosted/pub.dev/connectivity_plus_windows-1.2.2/
path_provider=/home/krtirtho/.pub-cache/hosted/pub.dev/path_provider-2.0.12/
path_provider_android=/home/krtirtho/.pub-cache/hosted/pub.dev/path_provider_android-2.0.22/
path_provider_foundation=/home/krtirtho/.pub-cache/hosted/pub.dev/path_provider_foundation-2.1.1/
path_provider_linux=/home/krtirtho/.pub-cache/hosted/pub.dev/path_provider_linux-2.1.7/
path_provider_windows=/home/krtirtho/.pub-cache/hosted/pub.dev/path_provider_windows-2.1.3/
@@ -1 +1 @@
{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"connectivity_plus","path":"/home/krtirtho/.pub-cache/hosted/pub.dartlang.org/connectivity_plus-2.3.9/","native_build":true,"dependencies":[]},{"name":"path_provider_ios","path":"/home/krtirtho/.pub-cache/hosted/pub.dartlang.org/path_provider_ios-2.0.11/","native_build":true,"dependencies":[]}],"android":[{"name":"connectivity_plus","path":"/home/krtirtho/.pub-cache/hosted/pub.dartlang.org/connectivity_plus-2.3.9/","native_build":true,"dependencies":[]},{"name":"path_provider_android","path":"/home/krtirtho/.pub-cache/hosted/pub.dartlang.org/path_provider_android-2.0.22/","native_build":true,"dependencies":[]}],"macos":[{"name":"connectivity_plus_macos","path":"/home/krtirtho/.pub-cache/hosted/pub.dartlang.org/connectivity_plus_macos-1.2.6/","native_build":true,"dependencies":[]},{"name":"path_provider_macos","path":"/home/krtirtho/.pub-cache/hosted/pub.dartlang.org/path_provider_macos-2.0.6/","native_build":true,"dependencies":[]}],"linux":[{"name":"connectivity_plus_linux","path":"/home/krtirtho/.pub-cache/hosted/pub.dartlang.org/connectivity_plus_linux-1.3.1/","native_build":false,"dependencies":[]},{"name":"path_provider_linux","path":"/home/krtirtho/.pub-cache/hosted/pub.dartlang.org/path_provider_linux-2.1.7/","native_build":false,"dependencies":[]}],"windows":[{"name":"connectivity_plus_windows","path":"/home/krtirtho/.pub-cache/hosted/pub.dartlang.org/connectivity_plus_windows-1.2.2/","native_build":true,"dependencies":[]},{"name":"path_provider_windows","path":"/home/krtirtho/.pub-cache/hosted/pub.dartlang.org/path_provider_windows-2.1.3/","native_build":false,"dependencies":[]}],"web":[{"name":"connectivity_plus_web","path":"/home/krtirtho/.pub-cache/hosted/pub.dartlang.org/connectivity_plus_web-1.2.5/","dependencies":[]}]},"dependencyGraph":[{"name":"connectivity_plus","dependencies":["connectivity_plus_linux","connectivity_plus_macos","connectivity_plus_web","connectivity_plus_windows"]},{"name":"connectivity_plus_linux","dependencies":[]},{"name":"connectivity_plus_macos","dependencies":[]},{"name":"connectivity_plus_web","dependencies":[]},{"name":"connectivity_plus_windows","dependencies":[]},{"name":"path_provider","dependencies":["path_provider_android","path_provider_ios","path_provider_linux","path_provider_macos","path_provider_windows"]},{"name":"path_provider_android","dependencies":[]},{"name":"path_provider_ios","dependencies":[]},{"name":"path_provider_linux","dependencies":[]},{"name":"path_provider_macos","dependencies":[]},{"name":"path_provider_windows","dependencies":[]}],"date_created":"2022-12-15 14:11:20.974968","version":"3.3.8"}
{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"connectivity_plus","path":"/home/krtirtho/.pub-cache/hosted/pub.dev/connectivity_plus-2.3.9/","native_build":true,"dependencies":[]},{"name":"path_provider_foundation","path":"/home/krtirtho/.pub-cache/hosted/pub.dev/path_provider_foundation-2.1.1/","native_build":true,"dependencies":[]}],"android":[{"name":"connectivity_plus","path":"/home/krtirtho/.pub-cache/hosted/pub.dev/connectivity_plus-2.3.9/","native_build":true,"dependencies":[]},{"name":"path_provider_android","path":"/home/krtirtho/.pub-cache/hosted/pub.dev/path_provider_android-2.0.22/","native_build":true,"dependencies":[]}],"macos":[{"name":"connectivity_plus_macos","path":"/home/krtirtho/.pub-cache/hosted/pub.dev/connectivity_plus_macos-1.2.6/","native_build":true,"dependencies":[]},{"name":"path_provider_foundation","path":"/home/krtirtho/.pub-cache/hosted/pub.dev/path_provider_foundation-2.1.1/","native_build":true,"dependencies":[]}],"linux":[{"name":"connectivity_plus_linux","path":"/home/krtirtho/.pub-cache/hosted/pub.dev/connectivity_plus_linux-1.3.1/","native_build":false,"dependencies":[]},{"name":"path_provider_linux","path":"/home/krtirtho/.pub-cache/hosted/pub.dev/path_provider_linux-2.1.7/","native_build":false,"dependencies":[]}],"windows":[{"name":"connectivity_plus_windows","path":"/home/krtirtho/.pub-cache/hosted/pub.dev/connectivity_plus_windows-1.2.2/","native_build":true,"dependencies":[]},{"name":"path_provider_windows","path":"/home/krtirtho/.pub-cache/hosted/pub.dev/path_provider_windows-2.1.3/","native_build":false,"dependencies":[]}],"web":[{"name":"connectivity_plus_web","path":"/home/krtirtho/.pub-cache/hosted/pub.dev/connectivity_plus_web-1.2.5/","dependencies":[]}]},"dependencyGraph":[{"name":"connectivity_plus","dependencies":["connectivity_plus_linux","connectivity_plus_macos","connectivity_plus_web","connectivity_plus_windows"]},{"name":"connectivity_plus_linux","dependencies":[]},{"name":"connectivity_plus_macos","dependencies":[]},{"name":"connectivity_plus_web","dependencies":[]},{"name":"connectivity_plus_windows","dependencies":[]},{"name":"path_provider","dependencies":["path_provider_android","path_provider_foundation","path_provider_linux","path_provider_windows"]},{"name":"path_provider_android","dependencies":[]},{"name":"path_provider_foundation","dependencies":[]},{"name":"path_provider_linux","dependencies":[]},{"name":"path_provider_windows","dependencies":[]}],"date_created":"2023-02-10 20:40:48.392862","version":"3.7.0"}
+1
View File
@@ -0,0 +1 @@
class QueryCache {}
+1
View File
@@ -0,0 +1 @@
class QueryClient {}
+15
View File
@@ -0,0 +1,15 @@
import 'package:fl_query/src/query.dart';
import 'package:fl_query/src/retryer.dart';
abstract class Constants {
static const RetryConfig defaultRetryConfig = RetryConfig(
maxRetries: 3,
retryDelay: Duration(seconds: 1),
timeout: Duration(seconds: 5),
);
static const RefreshConfig defaultRefreshConfig = RefreshConfig(
staleDuration: Duration(seconds: 10),
refreshInterval: Duration(seconds: 5),
);
}
+12
View File
@@ -0,0 +1,12 @@
import 'package:fl_query/src/client.dart';
import 'package:flutter/material.dart';
class QueryClientProvider extends InheritedWidget {
final QueryClient client;
QueryClientProvider({required super.child}) : client = QueryClient();
@override
bool updateShouldNotify(covariant QueryClientProvider oldWidget) {
return client != oldWidget.client;
}
}
+145
View File
@@ -0,0 +1,145 @@
import 'dart:async';
import 'package:fl_query/src/constants.dart';
import 'package:fl_query/src/retryer.dart';
import 'package:flutter/cupertino.dart';
import 'package:hive_flutter/adapters.dart';
import 'package:mutex/mutex.dart';
import 'package:state_notifier/state_notifier.dart';
typedef QueryFn<T> = FutureOr<T?> Function();
class QueryState<T, E> {
final T? data;
final E? error;
final QueryFn<T>? queryFn;
final DateTime updatedAt;
final Duration staleDuration;
const QueryState({
this.data,
this.error,
this.queryFn,
required this.updatedAt,
required this.staleDuration,
});
bool get isStale {
return DateTime.now().difference(updatedAt) > staleDuration;
}
QueryState<T, E> copyWith({
T? data,
E? error,
QueryFn<T>? queryFn,
}) {
return QueryState<T, E>(
updatedAt: DateTime.now(),
staleDuration: staleDuration,
data: data ?? this.data,
error: error ?? this.error,
queryFn: queryFn ?? this.queryFn,
);
}
}
class JsonConfig<T> {
final Map<String, dynamic> Function(T data) toJson;
final T Function(Map<String, dynamic> json) fromJson;
const JsonConfig({
required this.toJson,
required this.fromJson,
});
}
class RefreshConfig {
final Duration staleDuration;
final Duration refreshInterval;
const RefreshConfig({
required this.staleDuration,
required this.refreshInterval,
});
}
class Query<T, E, K> extends StateNotifier<QueryState<T, E>>
with Retryer<T, E> {
final ValueKey<K> key;
final T? initial;
final RefreshConfig refreshConfig;
final RetryConfig retryConfig;
final JsonConfig<T>? jsonConfig;
Query(
this.key,
QueryFn<T> queryFn, {
this.initial,
this.retryConfig = Constants.defaultRetryConfig,
this.refreshConfig = Constants.defaultRefreshConfig,
this.jsonConfig,
}) : _box = Hive.lazyBox("cache"),
super(QueryState<T, E>(
updatedAt: DateTime.now(),
staleDuration: refreshConfig.staleDuration,
data: initial,
queryFn: queryFn,
)) {
if (jsonConfig != null) {
_mutex.protect(() async {
final json = await _box.get(key);
if (json != null) {
state = state.copyWith(data: jsonConfig!.fromJson(json));
}
});
Timer.periodic(refreshConfig.refreshInterval, (_) async {
if (state.isStale) {
await refresh();
}
});
}
}
final LazyBox _box;
final _mutex = Mutex();
bool get isInitial => state.data == initial;
bool get isLoading => isInitial ? _mutex.isLocked : !hasData && !hasError;
bool get isRefreshing =>
((!isInitial && hasData) || hasError) && _mutex.isLocked;
bool get hasData => state.data != null;
bool get hasError => state.error != null;
Future<void> _operate() {
return _mutex.protect(() async {
retryOperation(
state.queryFn!,
config: retryConfig,
onSuccessful: (T? data) {
state = state.copyWith(data: data);
if (jsonConfig != null) {
_box.put(
key,
jsonConfig!.toJson(data!),
);
}
},
onFailed: (E? error) {
state = state.copyWith(error: error);
},
);
});
}
Future<T?> fetch() async {
if (_mutex.isLocked || hasData) return state.data;
return _operate().then((_) => state.data);
}
Future<T?> refresh() async {
if (_mutex.isLocked) return state.data;
return _operate().then((_) => state.data);
}
}
+50
View File
@@ -0,0 +1,50 @@
import 'dart:async';
import 'package:flutter/foundation.dart';
class RetryConfig {
final int maxRetries;
final Duration retryDelay;
final Duration timeout;
const RetryConfig({
required this.maxRetries,
required this.retryDelay,
required this.timeout,
});
}
mixin Retryer<T, E> {
VoidCallback retryOperation(
FutureOr<T?> Function() operation, {
required RetryConfig config,
required Function(T?) onSuccessful,
required Function(E?) onFailed,
}) {
int retries = 0;
late Timer timer;
VoidCallback? cancel;
void retry() {
if (retries < config.maxRetries) {
retries++;
timer = Timer(config.retryDelay, () async {
await Future.value(operation()).then((T? data) {
onSuccessful(data);
}).catchError((error) {
if (error is E) onFailed(error);
retry();
});
});
} else {
cancel?.call();
}
}
cancel = timer.cancel;
timer = Timer(config.timeout, retry);
return cancel;
}
}
+2
View File
@@ -18,6 +18,8 @@ dependencies:
flutter:
sdk: flutter
hive_flutter: ^1.1.0
state_notifier: ^0.7.2+1
mutex: ^3.0.1
queue: ^3.1.0+1
uuid: ^3.0.6
+10 -11
View File
@@ -1,12 +1,11 @@
# This is a generated file; do not edit or check into version control.
connectivity_plus=/home/krtirtho/.pub-cache/hosted/pub.dartlang.org/connectivity_plus-2.3.9/
connectivity_plus_linux=/home/krtirtho/.pub-cache/hosted/pub.dartlang.org/connectivity_plus_linux-1.3.1/
connectivity_plus_macos=/home/krtirtho/.pub-cache/hosted/pub.dartlang.org/connectivity_plus_macos-1.2.6/
connectivity_plus_web=/home/krtirtho/.pub-cache/hosted/pub.dartlang.org/connectivity_plus_web-1.2.5/
connectivity_plus_windows=/home/krtirtho/.pub-cache/hosted/pub.dartlang.org/connectivity_plus_windows-1.2.2/
path_provider=/home/krtirtho/.pub-cache/hosted/pub.dartlang.org/path_provider-2.0.11/
path_provider_android=/home/krtirtho/.pub-cache/hosted/pub.dartlang.org/path_provider_android-2.0.22/
path_provider_ios=/home/krtirtho/.pub-cache/hosted/pub.dartlang.org/path_provider_ios-2.0.11/
path_provider_linux=/home/krtirtho/.pub-cache/hosted/pub.dartlang.org/path_provider_linux-2.1.7/
path_provider_macos=/home/krtirtho/.pub-cache/hosted/pub.dartlang.org/path_provider_macos-2.0.6/
path_provider_windows=/home/krtirtho/.pub-cache/hosted/pub.dartlang.org/path_provider_windows-2.1.3/
connectivity_plus=/home/krtirtho/.pub-cache/hosted/pub.dev/connectivity_plus-2.3.9/
connectivity_plus_linux=/home/krtirtho/.pub-cache/hosted/pub.dev/connectivity_plus_linux-1.3.1/
connectivity_plus_macos=/home/krtirtho/.pub-cache/hosted/pub.dev/connectivity_plus_macos-1.2.6/
connectivity_plus_web=/home/krtirtho/.pub-cache/hosted/pub.dev/connectivity_plus_web-1.2.5/
connectivity_plus_windows=/home/krtirtho/.pub-cache/hosted/pub.dev/connectivity_plus_windows-1.2.2/
path_provider=/home/krtirtho/.pub-cache/hosted/pub.dev/path_provider-2.0.12/
path_provider_android=/home/krtirtho/.pub-cache/hosted/pub.dev/path_provider_android-2.0.22/
path_provider_foundation=/home/krtirtho/.pub-cache/hosted/pub.dev/path_provider_foundation-2.1.1/
path_provider_linux=/home/krtirtho/.pub-cache/hosted/pub.dev/path_provider_linux-2.1.7/
path_provider_windows=/home/krtirtho/.pub-cache/hosted/pub.dev/path_provider_windows-2.1.3/
@@ -1 +1 @@
{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"connectivity_plus","path":"/home/krtirtho/.pub-cache/hosted/pub.dartlang.org/connectivity_plus-2.3.9/","native_build":true,"dependencies":[]},{"name":"path_provider_ios","path":"/home/krtirtho/.pub-cache/hosted/pub.dartlang.org/path_provider_ios-2.0.11/","native_build":true,"dependencies":[]}],"android":[{"name":"connectivity_plus","path":"/home/krtirtho/.pub-cache/hosted/pub.dartlang.org/connectivity_plus-2.3.9/","native_build":true,"dependencies":[]},{"name":"path_provider_android","path":"/home/krtirtho/.pub-cache/hosted/pub.dartlang.org/path_provider_android-2.0.22/","native_build":true,"dependencies":[]}],"macos":[{"name":"connectivity_plus_macos","path":"/home/krtirtho/.pub-cache/hosted/pub.dartlang.org/connectivity_plus_macos-1.2.6/","native_build":true,"dependencies":[]},{"name":"path_provider_macos","path":"/home/krtirtho/.pub-cache/hosted/pub.dartlang.org/path_provider_macos-2.0.6/","native_build":true,"dependencies":[]}],"linux":[{"name":"connectivity_plus_linux","path":"/home/krtirtho/.pub-cache/hosted/pub.dartlang.org/connectivity_plus_linux-1.3.1/","native_build":false,"dependencies":[]},{"name":"path_provider_linux","path":"/home/krtirtho/.pub-cache/hosted/pub.dartlang.org/path_provider_linux-2.1.7/","native_build":false,"dependencies":[]}],"windows":[{"name":"connectivity_plus_windows","path":"/home/krtirtho/.pub-cache/hosted/pub.dartlang.org/connectivity_plus_windows-1.2.2/","native_build":true,"dependencies":[]},{"name":"path_provider_windows","path":"/home/krtirtho/.pub-cache/hosted/pub.dartlang.org/path_provider_windows-2.1.3/","native_build":false,"dependencies":[]}],"web":[{"name":"connectivity_plus_web","path":"/home/krtirtho/.pub-cache/hosted/pub.dartlang.org/connectivity_plus_web-1.2.5/","dependencies":[]}]},"dependencyGraph":[{"name":"connectivity_plus","dependencies":["connectivity_plus_linux","connectivity_plus_macos","connectivity_plus_web","connectivity_plus_windows"]},{"name":"connectivity_plus_linux","dependencies":[]},{"name":"connectivity_plus_macos","dependencies":[]},{"name":"connectivity_plus_web","dependencies":[]},{"name":"connectivity_plus_windows","dependencies":[]},{"name":"path_provider","dependencies":["path_provider_android","path_provider_ios","path_provider_linux","path_provider_macos","path_provider_windows"]},{"name":"path_provider_android","dependencies":[]},{"name":"path_provider_ios","dependencies":[]},{"name":"path_provider_linux","dependencies":[]},{"name":"path_provider_macos","dependencies":[]},{"name":"path_provider_windows","dependencies":[]}],"date_created":"2022-12-15 14:11:22.006668","version":"3.3.8"}
{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"connectivity_plus","path":"/home/krtirtho/.pub-cache/hosted/pub.dev/connectivity_plus-2.3.9/","native_build":true,"dependencies":[]},{"name":"path_provider_foundation","path":"/home/krtirtho/.pub-cache/hosted/pub.dev/path_provider_foundation-2.1.1/","native_build":true,"dependencies":[]}],"android":[{"name":"connectivity_plus","path":"/home/krtirtho/.pub-cache/hosted/pub.dev/connectivity_plus-2.3.9/","native_build":true,"dependencies":[]},{"name":"path_provider_android","path":"/home/krtirtho/.pub-cache/hosted/pub.dev/path_provider_android-2.0.22/","native_build":true,"dependencies":[]}],"macos":[{"name":"connectivity_plus_macos","path":"/home/krtirtho/.pub-cache/hosted/pub.dev/connectivity_plus_macos-1.2.6/","native_build":true,"dependencies":[]},{"name":"path_provider_foundation","path":"/home/krtirtho/.pub-cache/hosted/pub.dev/path_provider_foundation-2.1.1/","native_build":true,"dependencies":[]}],"linux":[{"name":"connectivity_plus_linux","path":"/home/krtirtho/.pub-cache/hosted/pub.dev/connectivity_plus_linux-1.3.1/","native_build":false,"dependencies":[]},{"name":"path_provider_linux","path":"/home/krtirtho/.pub-cache/hosted/pub.dev/path_provider_linux-2.1.7/","native_build":false,"dependencies":[]}],"windows":[{"name":"connectivity_plus_windows","path":"/home/krtirtho/.pub-cache/hosted/pub.dev/connectivity_plus_windows-1.2.2/","native_build":true,"dependencies":[]},{"name":"path_provider_windows","path":"/home/krtirtho/.pub-cache/hosted/pub.dev/path_provider_windows-2.1.3/","native_build":false,"dependencies":[]}],"web":[{"name":"connectivity_plus_web","path":"/home/krtirtho/.pub-cache/hosted/pub.dev/connectivity_plus_web-1.2.5/","dependencies":[]}]},"dependencyGraph":[{"name":"connectivity_plus","dependencies":["connectivity_plus_linux","connectivity_plus_macos","connectivity_plus_web","connectivity_plus_windows"]},{"name":"connectivity_plus_linux","dependencies":[]},{"name":"connectivity_plus_macos","dependencies":[]},{"name":"connectivity_plus_web","dependencies":[]},{"name":"connectivity_plus_windows","dependencies":[]},{"name":"path_provider","dependencies":["path_provider_android","path_provider_foundation","path_provider_linux","path_provider_windows"]},{"name":"path_provider_android","dependencies":[]},{"name":"path_provider_foundation","dependencies":[]},{"name":"path_provider_linux","dependencies":[]},{"name":"path_provider_windows","dependencies":[]}],"date_created":"2023-02-10 20:40:45.760783","version":"3.7.0"}