feat: working query builder, remove timeout from retryConfig
This commit is contained in:
@@ -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));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user