feat: working query builder, remove timeout from retryConfig

This commit is contained in:
Kingkor Roy Tirtho
2023-02-16 12:37:35 +06:00
parent 18584a3c57
commit 091491966f
8 changed files with 86 additions and 38 deletions
+15 -8
View File
@@ -1,3 +1,5 @@
import 'dart:math';
import 'package:fl_query/fl_query.dart';
import 'package:flutter/material.dart';
@@ -16,21 +18,26 @@ class MainApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
final value = Random().nextInt(200000);
return MaterialApp(
home: Scaffold(
body: QueryBuilder<String, void, String>(
body: QueryBuilder<String, dynamic, String>(
const ValueKey('hello'),
() {
return Future.delayed(
const Duration(seconds: 5),
() => 'Hello World!',
);
const Duration(seconds: 6), () => 'Hello World! $value');
},
initial: 'Hello',
// jsonConfig: JsonConfig(
// fromJson: (json) => json['data'],
// toJson: (data) => {'data': data},
// ),
jsonConfig: JsonConfig(
fromJson: (json) => json['data'],
toJson: (data) => {'data': data},
),
onData: (value) {
print('onData: $value');
},
onError: (error) {
print('onError: $error');
},
builder: (context, query) {
if (query.isLoading) {
return const Center(
@@ -5,12 +5,11 @@ abstract class DefaultConstants {
static const RetryConfig retryConfig = RetryConfig(
maxRetries: 3,
retryDelay: Duration(seconds: 1),
timeout: Duration(seconds: 5),
);
static const RefreshConfig refreshConfig = RefreshConfig(
staleDuration: Duration(seconds: 10),
refreshInterval: Duration(seconds: 5),
refreshInterval: Duration.zero,
refreshOnMount: true,
refreshOnQueryFnChange: false,
);
@@ -1,11 +1,6 @@
class RetryConfig {
final int maxRetries;
final Duration retryDelay;
final Duration timeout;
const RetryConfig({
required this.maxRetries,
required this.retryDelay,
required this.timeout,
});
const RetryConfig({required this.maxRetries, required this.retryDelay});
}
@@ -131,7 +131,8 @@ class InfiniteQuery<DataType, ErrorType, KeyType, PageType>
);
}
});
}
if (refreshConfig.refreshInterval > Duration.zero)
Timer.periodic(refreshConfig.refreshInterval, (_) async {
await Future.wait(
state.pages.map((page) async {
@@ -142,7 +143,6 @@ class InfiniteQuery<DataType, ErrorType, KeyType, PageType>
);
});
}
}
final _mutex = Mutex();
final _box = Hive.lazyBox("cache");
@@ -1,5 +1,6 @@
import 'package:fl_query/src/core/client.dart';
import 'package:flutter/material.dart';
import 'package:flutter/src/foundation/diagnostics.dart';
class QueryClientProvider extends InheritedWidget {
final QueryClient client;
@@ -9,4 +10,10 @@ class QueryClientProvider extends InheritedWidget {
bool updateShouldNotify(covariant QueryClientProvider oldWidget) {
return client != oldWidget.client;
}
@override
void debugFillProperties(DiagnosticPropertiesBuilder properties) {
super.debugFillProperties(properties);
properties.add(DiagnosticsProperty<QueryClient>('client', client));
}
}
+17 -8
View File
@@ -51,21 +51,22 @@ class Query<DataType, ErrorType, KeyType>
extends StateNotifier<QueryState<DataType, ErrorType>>
with Retryer<DataType, ErrorType> {
final ValueKey<KeyType> key;
final DataType? initial;
final RefreshConfig refreshConfig;
final RetryConfig retryConfig;
final JsonConfig<DataType>? jsonConfig;
Query(
this.key,
QueryFn<DataType> queryFn, {
this.initial,
DataType? initial,
this.retryConfig = DefaultConstants.retryConfig,
this.refreshConfig = DefaultConstants.refreshConfig,
this.jsonConfig,
}) : _box = Hive.lazyBox("cache"),
_dataController = StreamController<DataType>.broadcast(),
_errorController = StreamController<ErrorType>.broadcast(),
_initial = initial,
super(QueryState<DataType, ErrorType>(
updatedAt: DateTime.now(),
staleDuration: refreshConfig.staleDuration,
@@ -76,28 +77,35 @@ class Query<DataType, ErrorType, KeyType>
_mutex.protect(() async {
final json = await _box.get(key.toString());
if (json != null) {
state = state.copyWith(
data: jsonConfig!.fromJson(
_initial = jsonConfig!.fromJson(
Map.castFrom<dynamic, dynamic, String, dynamic>(json),
),
);
state = state.copyWith(data: _initial);
}
}).then((_) {
if (hasListeners) {
return fetch();
}
});
} else {
_initial = initial;
}
if (refreshConfig.refreshInterval > Duration.zero)
Timer.periodic(refreshConfig.refreshInterval, (_) async {
if (state.isStale) {
await refresh();
}
});
}
}
DataType? _initial;
final LazyBox _box;
final _mutex = Mutex();
final StreamController<DataType> _dataController;
final StreamController<ErrorType> _errorController;
bool get isInitial => state.data == initial;
bool get isInitial => hasData && state.data == _initial;
bool get isLoading => isInitial ? _mutex.isLocked : !hasData && !hasError;
bool get isRefreshing =>
((!isInitial && hasData) || hasError) && _mutex.isLocked;
@@ -134,7 +142,8 @@ class Query<DataType, ErrorType, KeyType>
}
Future<DataType?> fetch() async {
if (_mutex.isLocked || hasData || hasError) return state.data;
if (_mutex.isLocked || (hasData && !isInitial) || hasError)
return state.data;
return _operate().then((_) => state.data);
}
@@ -15,16 +15,6 @@ mixin Retryer<T, E> {
attempts == 0 ? Duration.zero : config.retryDelay,
operation,
).then(completer.complete).catchError(completer.completeError);
await Future.delayed(config.timeout, () {
if (!completer.isCompleted) {
completer.completeError(
TimeoutException(
'Operation timed out after ${config.timeout.inSeconds} seconds',
),
StackTrace.current,
);
}
});
try {
final result = await completer.future;
onSuccessful(result);
@@ -7,6 +7,7 @@ import 'package:fl_query/src/collections/retry_config.dart';
import 'package:fl_query/src/core/client.dart';
import 'package:fl_query/src/core/query.dart';
import 'package:flutter/material.dart';
import 'package:flutter/src/foundation/diagnostics.dart';
typedef QueryBuilderFn<DataType, ErrorType, KeyType> = Widget Function(
BuildContext context,
@@ -42,7 +43,10 @@ class QueryBuilder<DataType, ErrorType, KeyType> extends StatefulWidget {
this.onError,
this.enabled = true,
super.key,
});
}) : assert(
enabled && jsonConfig != null,
'jsonConfig is only supported when enabled is true',
);
@override
State<QueryBuilder<DataType, ErrorType, KeyType>> createState() =>
@@ -132,4 +136,41 @@ class _QueryBuilderState<DataType, ErrorType, KeyType>
}
return widget.builder(context, query!);
}
@override
void debugFillProperties(DiagnosticPropertiesBuilder properties) {
super.debugFillProperties(properties);
properties.add(
DiagnosticsProperty<Query<DataType, ErrorType, KeyType>>('query', query),
);
properties.add(
DiagnosticsProperty<ValueKey<KeyType>>('queryKey', widget.queryKey),
);
properties.add(
DiagnosticsProperty<QueryBuilderFn>('builder', widget.builder),
);
properties.add(DiagnosticsProperty<DataType>('initial', widget.initial));
properties.add(
DiagnosticsProperty<RetryConfig>('retryConfig', widget.retryConfig),
);
properties.add(
DiagnosticsProperty<RefreshConfig>(
'refreshConfig',
widget.refreshConfig,
),
);
properties.add(
DiagnosticsProperty<JsonConfig<DataType>>(
'jsonConfig',
widget.jsonConfig,
),
);
properties.add(
DiagnosticsProperty<ValueChanged<DataType>>('onData', widget.onData),
);
properties.add(
DiagnosticsProperty<ValueChanged<ErrorType>>('onError', widget.onError),
);
properties.add(DiagnosticsProperty<bool>('enabled', widget.enabled));
}
}