utils tests created
TQueryFnData, TData & TQueryData now only can be Maps or subclass of Map
This commit is contained in:
@@ -9,16 +9,19 @@ typedef QueryKeyHashFunction = String Function(QueryKey queryKey);
|
||||
typedef QueryFunction<T, TPageParam> = FutureOr<T> Function(
|
||||
QueryFunctionContext<TPageParam> context,
|
||||
);
|
||||
typedef GetPreviousPageParamFunction<TQueryFnData> = Function(
|
||||
typedef GetPreviousPageParamFunction<TQueryFnData extends Map<String, dynamic>>
|
||||
= Function(
|
||||
TQueryFnData firstPage,
|
||||
List<TQueryFnData> allPages,
|
||||
);
|
||||
typedef GetNextPageParamFunction<TQueryFnData> = Function(
|
||||
typedef GetNextPageParamFunction<TQueryFnData extends Map<String, dynamic>>
|
||||
= Function(
|
||||
TQueryFnData firstPage,
|
||||
List<TQueryFnData> allPages,
|
||||
);
|
||||
|
||||
class QueryOptions<TQueryFnData, TError, TData> {
|
||||
class QueryOptions<TQueryFnData extends Map<String, dynamic>, TError,
|
||||
TData extends Map<String, dynamic>> {
|
||||
ShouldRetryFunction<TError>? retry;
|
||||
RetryDelayFunction<TError>? retryDelay;
|
||||
Duration? cacheTime;
|
||||
@@ -259,7 +262,7 @@ enum QueryStatus {
|
||||
success,
|
||||
}
|
||||
|
||||
class QueryObserverResult<TData, TError> {
|
||||
class QueryObserverResult<TData extends Map<String, dynamic>, TError> {
|
||||
TData? data;
|
||||
DateTime? dataUpdatedAt;
|
||||
TError? error;
|
||||
@@ -373,7 +376,11 @@ class QueryObserverResult<TData, TError> {
|
||||
}
|
||||
}
|
||||
|
||||
typedef RefetchIntervalFunction<TQueryFnData, TError, TQueryData, TData>
|
||||
typedef RefetchIntervalFunction<
|
||||
TQueryFnData extends Map<String, dynamic>,
|
||||
TError,
|
||||
TQueryData extends Map<String, dynamic>,
|
||||
TData extends Map<String, dynamic>>
|
||||
= Duration? Function(
|
||||
TData? data,
|
||||
Query<TQueryFnData, TError, TQueryData> query,
|
||||
@@ -391,7 +398,11 @@ enum RefetchOnMount {
|
||||
always,
|
||||
}
|
||||
|
||||
class QueryObserverOptions<TQueryFnData, TError, TData, TQueryData>
|
||||
class QueryObserverOptions<
|
||||
TQueryFnData extends Map<String, dynamic>,
|
||||
TError,
|
||||
TData extends Map<String, dynamic>,
|
||||
TQueryData extends Map<String, dynamic>>
|
||||
extends QueryOptions<TQueryFnData, TError, TQueryData> {
|
||||
bool? enabled;
|
||||
Duration? staleTime;
|
||||
@@ -520,7 +531,8 @@ class DefaultOptions<TError> {
|
||||
});
|
||||
}
|
||||
|
||||
class FetchQueryOptions<TQueryFnData, TError, TData>
|
||||
class FetchQueryOptions<TQueryFnData extends Map<String, dynamic>, TError,
|
||||
TData extends Map<String, dynamic>>
|
||||
extends QueryOptions<TQueryFnData, TError, TData> {
|
||||
/// The time after data is considered stale.
|
||||
/// If the data is fresh it will be returned from the cache.
|
||||
|
||||
@@ -17,7 +17,8 @@ class FetchOptions {
|
||||
FetchOptions({this.cancelRefetch, this.meta});
|
||||
}
|
||||
|
||||
class FetchContext<TQueryFnData, TError, TData> {
|
||||
class FetchContext<TQueryFnData extends Map<String, dynamic>, TError,
|
||||
TData extends Map<String, dynamic>> {
|
||||
FutureOr<TQueryFnData> Function() fetchFn;
|
||||
FetchOptions? fetchOptions;
|
||||
QueryOptions<TQueryFnData, TError, TData> options;
|
||||
@@ -35,12 +36,13 @@ class FetchContext<TQueryFnData, TError, TData> {
|
||||
});
|
||||
}
|
||||
|
||||
class QueryBehavior<TQueryFnData, TError, TData> {
|
||||
class QueryBehavior<TQueryFnData extends Map<String, dynamic>, TError,
|
||||
TData extends Map<String, dynamic>> {
|
||||
void Function(FetchContext<TQueryFnData, TError, TData> context) onFetch;
|
||||
QueryBehavior({required this.onFetch});
|
||||
}
|
||||
|
||||
class QueryState<TData, TError> {
|
||||
class QueryState<TData extends Map<String, dynamic>, TError> {
|
||||
TData? data;
|
||||
TError? error;
|
||||
QueryStatus status;
|
||||
@@ -120,7 +122,7 @@ class SetStateOptions {
|
||||
}
|
||||
}
|
||||
|
||||
class Action<TData, TError> {
|
||||
class Action<TData extends Map<String, dynamic>, TError> {
|
||||
ActionType type;
|
||||
Object? meta;
|
||||
TData? data;
|
||||
@@ -160,7 +162,8 @@ class Action<TData, TError> {
|
||||
}
|
||||
}
|
||||
|
||||
class Query<TQueryFnData, TError, TData> {
|
||||
class Query<TQueryFnData extends Map<String, dynamic>, TError,
|
||||
TData extends Map<String, dynamic>> {
|
||||
QueryKey queryKey;
|
||||
String queryHash;
|
||||
late QueryOptions<TQueryFnData, TError, TData> options;
|
||||
@@ -277,7 +280,7 @@ class Query<TQueryFnData, TError, TData> {
|
||||
data = prevData as TData;
|
||||
} else if (this.options.structuralSharing != false) {
|
||||
// Structurally share data between prev and new data if needed
|
||||
data = replaceEqualDeep<TData>(prevData ?? {} as TData, data);
|
||||
data = replaceEqualDeep(prevData ?? {} as TData, data);
|
||||
}
|
||||
// Set data and mark it as cached
|
||||
_dispatch(Action(
|
||||
@@ -360,7 +363,7 @@ class Query<TQueryFnData, TError, TData> {
|
||||
var observer =
|
||||
_observers.firstWhereOrNull((x) => x.options.queryFn != null);
|
||||
if (observer != null) {
|
||||
_setOptions(QueryOptions(
|
||||
_setOptions(QueryOptions<TQueryFnData, TError, TData>(
|
||||
queryKey: observer.options.queryKey,
|
||||
queryKeyHashFn: observer.options.queryKeyHashFn,
|
||||
cacheTime: observer.options.cacheTime,
|
||||
@@ -368,7 +371,7 @@ class Query<TQueryFnData, TError, TData> {
|
||||
queryFn:
|
||||
observer.options.queryFn as QueryFunction<TQueryFnData, dynamic>,
|
||||
queryHash: observer.options.queryHash,
|
||||
initialData: observer.options.initialData,
|
||||
initialData: observer.options.initialData as TData?,
|
||||
initialDataUpdatedAt: observer.options.initialDataUpdatedAt,
|
||||
meta: observer.options.meta,
|
||||
structuralSharing: observer.options.structuralSharing,
|
||||
|
||||
@@ -59,7 +59,10 @@ class QueryCache extends Subscribable<QueryCacheListener> {
|
||||
_queriesMap = {},
|
||||
super();
|
||||
|
||||
Query<TQueryFnData, TError, TData> build<TQueryFnData, TError, TData>(
|
||||
Query<TQueryFnData, TError, TData> build<
|
||||
TQueryFnData extends Map<String, dynamic>,
|
||||
TError,
|
||||
TData extends Map<String, dynamic>>(
|
||||
QueryClient client,
|
||||
QueryOptions<TQueryFnData, TError, TData> options, [
|
||||
QueryState<TData, TError>? state,
|
||||
@@ -124,8 +127,10 @@ class QueryCache extends Subscribable<QueryCacheListener> {
|
||||
});
|
||||
}
|
||||
|
||||
Query<TQueryFnData, TError, TData>? get<TQueryFnData, TError, TData>(
|
||||
String queryHash) {
|
||||
Query<TQueryFnData, TError, TData>? get<
|
||||
TQueryFnData extends Map<String, dynamic>,
|
||||
TError,
|
||||
TData extends Map<String, dynamic>>(String queryHash) {
|
||||
return _queriesMap[queryHash] as Query<TQueryFnData, TError, TData>?;
|
||||
}
|
||||
|
||||
@@ -133,13 +138,16 @@ class QueryCache extends Subscribable<QueryCacheListener> {
|
||||
return _queries;
|
||||
}
|
||||
|
||||
Query? find<TQueryFnData, TError, TData>(
|
||||
Query<TQueryFnData, TError, TData>? find<
|
||||
TQueryFnData extends Map<String, dynamic>,
|
||||
TError,
|
||||
TData extends Map<String, dynamic>>(
|
||||
QueryKey queryKey,
|
||||
QueryFilters queryFilters,
|
||||
) {
|
||||
queryFilters.exact ??= true;
|
||||
return _queries
|
||||
.firstWhereOrNull((query) => matchQuery(queryFilters, query));
|
||||
return _queries.firstWhereOrNull((query) => matchQuery(queryFilters, query))
|
||||
as Query<TQueryFnData, TError, TData>?;
|
||||
}
|
||||
|
||||
List<Query> findAll(QueryKey? queryKey, [QueryFilters? filters]) {
|
||||
|
||||
@@ -26,7 +26,7 @@ class MutationDefaults {
|
||||
// });
|
||||
}
|
||||
|
||||
class QueryData<TData> {
|
||||
class QueryData<TData extends Map<String, dynamic>> {
|
||||
QueryKey queryKey;
|
||||
TData data;
|
||||
QueryData({
|
||||
@@ -85,17 +85,18 @@ class QueryClient {
|
||||
// return _mutationCache.findAll({ ...filters, fetching: true }).length
|
||||
// }
|
||||
|
||||
TData? getQueryData<TData>(
|
||||
TData? getQueryData<TData extends Map<String, dynamic>>(
|
||||
QueryKey queryKey, [
|
||||
QueryFilters? filters,
|
||||
]) {
|
||||
return _queryCache
|
||||
.find<TData, dynamic, dynamic>(queryKey, filters ?? QueryFilters())
|
||||
.find<TData, dynamic, Map<String, dynamic>>(
|
||||
queryKey, filters ?? QueryFilters())
|
||||
?.state
|
||||
.data;
|
||||
.data as TData?;
|
||||
}
|
||||
|
||||
List<QueryData<TData>> getQueriesData<TData>({
|
||||
List<QueryData<TData>> getQueriesData<TData extends Map<String, dynamic>>({
|
||||
QueryKey? queryKey,
|
||||
QueryFilters? filters,
|
||||
}) {
|
||||
@@ -107,26 +108,27 @@ class QueryClient {
|
||||
}).toList();
|
||||
}
|
||||
|
||||
TData setQueryData<TData>(
|
||||
TData setQueryData<TData extends Map<String, dynamic>>(
|
||||
QueryKey queryKey,
|
||||
DataUpdateFunction<TData?, TData> updater, [
|
||||
DateTime? updatedAt,
|
||||
]) {
|
||||
final QueryOptions<dynamic, dynamic, TData> defaultedOptions =
|
||||
QueryOptions<dynamic, dynamic, TData>.fromJson(
|
||||
defaultQueryOptions<dynamic, dynamic, TData, dynamic>(
|
||||
QueryObserverOptions<dynamic, dynamic, TData, dynamic>(
|
||||
queryKey: queryKey))
|
||||
final QueryOptions<Map<String, dynamic>, dynamic, TData> defaultedOptions =
|
||||
QueryOptions<Map<String, dynamic>, dynamic, TData>.fromJson(
|
||||
defaultQueryOptions<Map<String, dynamic>, dynamic, TData,
|
||||
Map<String, dynamic>>(
|
||||
QueryObserverOptions<Map<String, dynamic>, dynamic, TData,
|
||||
Map<String, dynamic>>(queryKey: queryKey))
|
||||
.toJson());
|
||||
return _queryCache
|
||||
.build<dynamic, dynamic, TData>(this, defaultedOptions)
|
||||
.build<Map<String, dynamic>, dynamic, TData>(this, defaultedOptions)
|
||||
.setData(
|
||||
updater,
|
||||
updatedAt: updatedAt,
|
||||
);
|
||||
}
|
||||
|
||||
List<QueryData> setQueriesData<TData>({
|
||||
List<QueryData> setQueriesData<TData extends Map<String, dynamic>>({
|
||||
required DataUpdateFunction<TData?, TData> updater,
|
||||
QueryKey? queryKey,
|
||||
QueryFilters? filters,
|
||||
@@ -149,12 +151,13 @@ class QueryClient {
|
||||
.toList();
|
||||
}
|
||||
|
||||
QueryState<TData, TError>? getQueryState<TData, TError>(
|
||||
QueryState<TData, TError>?
|
||||
getQueryState<TData extends Map<String, dynamic>, TError>(
|
||||
QueryKey queryKey, [
|
||||
QueryFilters? filters,
|
||||
]) {
|
||||
return _queryCache
|
||||
.find<TData, TError, dynamic>(
|
||||
.find<TData, TError, Map<String, dynamic>>(
|
||||
queryKey,
|
||||
filters ?? QueryFilters(),
|
||||
)
|
||||
@@ -257,13 +260,15 @@ class QueryClient {
|
||||
return future;
|
||||
}
|
||||
|
||||
Future<TData> fetchQuery<TQueryFnData, TError, TData>({
|
||||
Future<TData> fetchQuery<TQueryFnData extends Map<String, dynamic>, TError,
|
||||
TData extends Map<String, dynamic>>({
|
||||
QueryKey? queryKey,
|
||||
QueryFunction<TQueryFnData, dynamic>? queryFn,
|
||||
FetchQueryOptions<TQueryFnData, TError, TData>? options,
|
||||
}) {
|
||||
var defaultedOptions = this.defaultQueryOptions(
|
||||
QueryObserverOptions(
|
||||
QueryObserverOptions<Map<String, dynamic>, dynamic, Map<String, dynamic>,
|
||||
TData>(
|
||||
queryFn: queryFn,
|
||||
queryKey: queryKey,
|
||||
staleTime: options?.staleTime,
|
||||
@@ -280,28 +285,33 @@ class QueryClient {
|
||||
);
|
||||
// returning 0 indicates turing off retry
|
||||
defaultedOptions.retry ??= (_, __) => 0;
|
||||
var query = _queryCache.build(this, defaultedOptions);
|
||||
var query = _queryCache.build<Map<String, dynamic>, dynamic, TData>(
|
||||
this, defaultedOptions);
|
||||
return query.isStaleByTime(defaultedOptions.staleTime)
|
||||
? query.fetch(defaultedOptions)
|
||||
: Future.value(query.state.data as TData);
|
||||
}
|
||||
|
||||
Future<void> prefetchQuery<TQueryFnData, TError, TData>({
|
||||
Future<void> prefetchQuery<TQueryFnData extends Map<String, dynamic>, TError,
|
||||
TData extends Map<String, dynamic>>({
|
||||
QueryKey? queryKey,
|
||||
QueryFunction<TQueryFnData, dynamic>? queryFn,
|
||||
FetchQueryOptions<TQueryFnData, TError, TData>? options,
|
||||
}) {
|
||||
return fetchQuery(
|
||||
return fetchQuery<TQueryFnData, dynamic, TData>(
|
||||
queryKey: queryKey,
|
||||
queryFn: queryFn,
|
||||
options: options,
|
||||
).then(noop).catchError(noop);
|
||||
}
|
||||
|
||||
QueryObserverOptions<TQueryFnData, TError, TData, TQueryData>
|
||||
defaultQueryOptions<TQueryFnData, TError, TData, TQueryData>(
|
||||
QueryObserverOptions<TQueryFnData, TError, TData, TQueryData>?
|
||||
options) {
|
||||
QueryObserverOptions<TQueryFnData, TError, TData,
|
||||
TQueryData> defaultQueryOptions<
|
||||
TQueryFnData extends Map<String, dynamic>,
|
||||
TError,
|
||||
TData extends Map<String, dynamic>,
|
||||
TQueryData extends Map<String, dynamic>>(
|
||||
QueryObserverOptions<TQueryFnData, TError, TData, TQueryData>? options) {
|
||||
if (options?.defaulted == true) return options!;
|
||||
var defaultedOptions =
|
||||
QueryObserverOptions<TQueryFnData, TError, TData, TQueryData>.fromJson({
|
||||
@@ -322,7 +332,11 @@ class QueryClient {
|
||||
}
|
||||
|
||||
QueryObserverOptions<TQueryFnData, TError, TData, TQueryData>
|
||||
defaultQueryObserverOptions<TQueryFnData, TError, TData, TQueryData>([
|
||||
defaultQueryObserverOptions<
|
||||
TQueryFnData extends Map<String, dynamic>,
|
||||
TError,
|
||||
TData extends Map<String, dynamic>,
|
||||
TQueryData extends Map<String, dynamic>>([
|
||||
QueryObserverOptions<TQueryFnData, TError, TData, TQueryData>? options,
|
||||
]) {
|
||||
return this.defaultQueryOptions(options);
|
||||
|
||||
@@ -15,8 +15,8 @@ import 'package:fl_query/src/core/subscribable.dart';
|
||||
import 'package:fl_query/src/core/utils.dart';
|
||||
import 'package:meta/meta.dart';
|
||||
|
||||
typedef QueryObserverListener<TData, TError> = void Function(
|
||||
QueryObserverResult<TData, TError> result);
|
||||
typedef QueryObserverListener<TData extends Map<String, dynamic>, TError> = void
|
||||
Function(QueryObserverResult<TData, TError> result);
|
||||
|
||||
class NotifyOptions {
|
||||
bool? cache;
|
||||
@@ -52,13 +52,18 @@ class ObserverFetchOptions extends FetchOptions {
|
||||
}) : super(cancelRefetch: cancelRefetch, meta: meta);
|
||||
}
|
||||
|
||||
class SelectQuery<TQueryData, TData> {
|
||||
class SelectQuery<TQueryData extends Map<String, dynamic>,
|
||||
TData extends Map<String, dynamic>> {
|
||||
TData Function(TQueryData data) fn;
|
||||
TData result;
|
||||
SelectQuery(this.fn, this.result);
|
||||
}
|
||||
|
||||
class QueryObserver<TQueryFnData, TError, TData, TQueryData>
|
||||
class QueryObserver<
|
||||
TQueryFnData extends Map<String, dynamic>,
|
||||
TError,
|
||||
TData extends Map<String, dynamic>,
|
||||
TQueryData extends Map<String, dynamic>>
|
||||
extends Subscribable<QueryObserverListener> {
|
||||
late QueryObserverOptions<TQueryFnData, TError, TData, TQueryData> options;
|
||||
QueryClient _client;
|
||||
@@ -70,7 +75,7 @@ class QueryObserver<TQueryFnData, TError, TData, TQueryData>
|
||||
_currentResultOptions;
|
||||
QueryObserverResult<TData, TError>? _previousQueryResult;
|
||||
Exception? _previousSelectError;
|
||||
SelectQuery? _previousSelect;
|
||||
SelectQuery<TQueryData, TData>? _previousSelect;
|
||||
Timer? _staleTimeout;
|
||||
Timer? _refetchInterval;
|
||||
Duration? _currentRefetchInterval;
|
||||
@@ -119,8 +124,8 @@ class QueryObserver<TQueryFnData, TError, TData, TQueryData>
|
||||
QueryObserverOptions<TQueryFnData, TError, TData, TQueryData>? options, [
|
||||
NotifyOptions? notifyOptions,
|
||||
]) {
|
||||
var prevOptions = this.options;
|
||||
var prevQuery = _currentQuery;
|
||||
final prevOptions = this.options;
|
||||
final prevQuery = _currentQuery;
|
||||
|
||||
this.options = this._client.defaultQueryObserverOptions(options);
|
||||
|
||||
@@ -190,7 +195,7 @@ class QueryObserver<TQueryFnData, TError, TData, TQueryData>
|
||||
Future<QueryObserverResult<TData, TError>> getNextResult(
|
||||
bool? throwOnError,
|
||||
) {
|
||||
var completer = Completer<QueryObserverResult<TData, TError>>();
|
||||
final completer = Completer<QueryObserverResult<TData, TError>>();
|
||||
var unsubscribe;
|
||||
unsubscribe = subscribe((result) {
|
||||
if (!result.isFetching) {
|
||||
@@ -215,8 +220,8 @@ class QueryObserver<TQueryFnData, TError, TData, TQueryData>
|
||||
|
||||
Future<QueryObserverResult<TData, TError>> fetchOptimistic(
|
||||
QueryObserverOptions<TQueryFnData, TError, TData, TQueryData> options) {
|
||||
var defaultedOptions = _client.defaultQueryObserverOptions(options);
|
||||
var query = _client.getQueryCache().build(_client, defaultedOptions);
|
||||
final defaultedOptions = _client.defaultQueryObserverOptions(options);
|
||||
final query = _client.getQueryCache().build(_client, defaultedOptions);
|
||||
|
||||
return query.fetch().then((val) {
|
||||
return createResult(query, defaultedOptions);
|
||||
@@ -269,7 +274,7 @@ class QueryObserver<TQueryFnData, TError, TData, TQueryData>
|
||||
Map<String, dynamic> prevResultMap = prevResult.toJson();
|
||||
|
||||
return resultMap.keys.any((key) {
|
||||
var changed = resultMap[key] != prevResultMap[key];
|
||||
final changed = resultMap[key] != prevResultMap[key];
|
||||
bool? isIncluded = includedProps?.any((x) => x == key);
|
||||
bool isExcluded =
|
||||
options.notifyOnChangePropsExclusions?.any((x) => x == key) ?? false;
|
||||
@@ -280,7 +285,7 @@ class QueryObserver<TQueryFnData, TError, TData, TQueryData>
|
||||
}
|
||||
|
||||
void updateResult([NotifyOptions? notifyOptions]) {
|
||||
QueryObserverResult<TData, TError>? prevResult = _currentResult;
|
||||
final QueryObserverResult<TData, TError>? prevResult = _currentResult;
|
||||
|
||||
if (_currentQuery != null)
|
||||
_currentResult = this.createResult(_currentQuery!, this.options);
|
||||
@@ -288,7 +293,7 @@ class QueryObserver<TQueryFnData, TError, TData, TQueryData>
|
||||
_currentResultOptions = this.options;
|
||||
|
||||
// Only notify if something has changed
|
||||
if (shallowEqualMap(_currentResult.toJson(), prevResult.toJson())) {
|
||||
if (shallowEqualMap(_currentResult.toJson(), prevResult?.toJson())) {
|
||||
return;
|
||||
}
|
||||
NotifyOptions defaultNotifyOptions = NotifyOptions(cache: true);
|
||||
@@ -304,11 +309,12 @@ class QueryObserver<TQueryFnData, TError, TData, TQueryData>
|
||||
}
|
||||
|
||||
void _updateQuery() {
|
||||
var query = this._client.getQueryCache().build(this._client, this.options);
|
||||
final query =
|
||||
this._client.getQueryCache().build(this._client, this.options);
|
||||
|
||||
if (query == _currentQuery) return;
|
||||
|
||||
var prevQuery = _currentQuery;
|
||||
final prevQuery = _currentQuery;
|
||||
_currentQuery = query;
|
||||
_currentQueryInitialState = query.state;
|
||||
_previousQueryResult = _currentResult;
|
||||
@@ -339,22 +345,22 @@ class QueryObserver<TQueryFnData, TError, TData, TQueryData>
|
||||
Query<TQueryFnData, TError, TQueryData> query,
|
||||
QueryObserverOptions<TQueryFnData, TError, TData, TQueryData> options,
|
||||
) {
|
||||
var prevQuery = _currentQuery;
|
||||
var prevOptions = this.options;
|
||||
var prevResult = _currentResult;
|
||||
var prevResultState = _currentResultState;
|
||||
var prevResultOptions = _currentResultOptions;
|
||||
bool queryChange = query != prevQuery;
|
||||
var queryInitialState =
|
||||
final prevQuery = _currentQuery;
|
||||
final prevOptions = this.options;
|
||||
final prevResult = _currentResult;
|
||||
final prevResultState = _currentResultState;
|
||||
final prevResultOptions = _currentResultOptions;
|
||||
final bool queryChange = query != prevQuery;
|
||||
final queryInitialState =
|
||||
queryChange ? query.state : _currentQueryInitialState;
|
||||
var prevQueryResult = queryChange ? _currentResult : _previousQueryResult;
|
||||
final prevQueryResult = queryChange ? _currentResult : _previousQueryResult;
|
||||
|
||||
var state = query.state;
|
||||
var dataUpdatedAt = state.dataUpdatedAt;
|
||||
var error = state.error;
|
||||
var errorUpdatedAt = state.errorUpdatedAt;
|
||||
var isFetching = state.isFetching;
|
||||
var status = state.status;
|
||||
final state = query.state;
|
||||
DateTime? dataUpdatedAt = state.dataUpdatedAt;
|
||||
TError? error = state.error;
|
||||
DateTime? errorUpdatedAt = state.errorUpdatedAt;
|
||||
bool isFetching = state.isFetching;
|
||||
QueryStatus status = state.status;
|
||||
|
||||
bool isPreviousData = false;
|
||||
bool isPlaceholderData = false;
|
||||
@@ -362,9 +368,9 @@ class QueryObserver<TQueryFnData, TError, TData, TQueryData>
|
||||
|
||||
// Optimistically set result in fetching state if needed
|
||||
if (options.optimisticResults == true) {
|
||||
var mounted = hasListeners();
|
||||
final bool mounted = hasListeners();
|
||||
|
||||
var fetchOnMount = !mounted && shouldFetchOnMount(query, options);
|
||||
final bool fetchOnMount = !mounted && shouldFetchOnMount(query, options);
|
||||
|
||||
bool fetchOptionally = mounted &&
|
||||
prevQuery != null &&
|
||||
@@ -401,7 +407,7 @@ class QueryObserver<TQueryFnData, TError, TData, TQueryData>
|
||||
try {
|
||||
data = options.select?.call(state.data);
|
||||
if (options.structuralSharing != false) {
|
||||
data = replaceEqualDeep(prevResult?.data, data);
|
||||
data = replaceEqualDeep(prevResult.data, data);
|
||||
}
|
||||
if (options.select != null && data != null) {
|
||||
_previousSelect = SelectQuery<TQueryData, TData>(
|
||||
@@ -429,7 +435,7 @@ class QueryObserver<TQueryFnData, TError, TData, TQueryData>
|
||||
(status == QueryStatus.loading || status == QueryStatus.idle)) {
|
||||
var placeholderData;
|
||||
|
||||
if (prevResult?.isPlaceholderData == true &&
|
||||
if (prevResult.isPlaceholderData == true &&
|
||||
options.placeholderData == prevResultOptions?.placeholderData) {
|
||||
placeholderData = prevResult.data;
|
||||
} else {
|
||||
@@ -439,7 +445,7 @@ class QueryObserver<TQueryFnData, TError, TData, TQueryData>
|
||||
placeholderData = options.select?.call(placeholderData);
|
||||
if (options.structuralSharing != false) {
|
||||
placeholderData =
|
||||
replaceEqualDeep(prevResult?.data, placeholderData);
|
||||
replaceEqualDeep(prevResult.data, placeholderData);
|
||||
}
|
||||
_previousSelectError = null;
|
||||
} catch (selectError) {
|
||||
@@ -459,7 +465,8 @@ class QueryObserver<TQueryFnData, TError, TData, TQueryData>
|
||||
}
|
||||
}
|
||||
|
||||
QueryObserverResult<TData, TError> result = QueryObserverResult(
|
||||
final QueryObserverResult<TData, TError> result =
|
||||
QueryObserverResult<TData, TError>(
|
||||
status: status,
|
||||
dataUpdatedAt: dataUpdatedAt,
|
||||
isLoading: status == QueryStatus.loading,
|
||||
@@ -602,7 +609,11 @@ class QueryObserver<TQueryFnData, TError, TData, TQueryData>
|
||||
}
|
||||
}
|
||||
|
||||
bool shouldLoadOnMount<TQueryFnData, TError, TData, TQueryData>(
|
||||
bool shouldLoadOnMount<
|
||||
TQueryFnData extends Map<String, dynamic>,
|
||||
TError,
|
||||
TData extends Map<String, dynamic>,
|
||||
TQueryData extends Map<String, dynamic>>(
|
||||
Query<TQueryFnData, TError, TQueryData> query,
|
||||
QueryObserverOptions<TQueryFnData, TError, TData, TQueryData> options,
|
||||
) {
|
||||
@@ -612,7 +623,11 @@ bool shouldLoadOnMount<TQueryFnData, TError, TData, TQueryData>(
|
||||
options.retryOnMount == false));
|
||||
}
|
||||
|
||||
bool shouldRefetchOnMount<TQueryFnData, TError, TData, TQueryData>(
|
||||
bool shouldRefetchOnMount<
|
||||
TQueryFnData extends Map<String, dynamic>,
|
||||
TError,
|
||||
TData extends Map<String, dynamic>,
|
||||
TQueryData extends Map<String, dynamic>>(
|
||||
Query<TQueryFnData, TError, TQueryData> query,
|
||||
QueryObserverOptions<TQueryFnData, TError, TData, TQueryData> options,
|
||||
) {
|
||||
@@ -623,7 +638,11 @@ bool shouldRefetchOnMount<TQueryFnData, TError, TData, TQueryData>(
|
||||
isStale(query, options))));
|
||||
}
|
||||
|
||||
bool shouldFetchOnMount<TQueryFnData, TError, TData, TQueryData>(
|
||||
bool shouldFetchOnMount<
|
||||
TQueryFnData extends Map<String, dynamic>,
|
||||
TError,
|
||||
TData extends Map<String, dynamic>,
|
||||
TQueryData extends Map<String, dynamic>>(
|
||||
Query<TQueryFnData, TError, TQueryData> query,
|
||||
QueryObserverOptions<TQueryFnData, TError, TData, TQueryData> options,
|
||||
) {
|
||||
@@ -631,17 +650,26 @@ bool shouldFetchOnMount<TQueryFnData, TError, TData, TQueryData>(
|
||||
shouldRefetchOnMount(query, options));
|
||||
}
|
||||
|
||||
bool shouldFetchOnReconnect<TQueryFnData, TError, TData, TQueryData>(
|
||||
bool shouldFetchOnReconnect<
|
||||
TQueryFnData extends Map<String, dynamic>,
|
||||
TError,
|
||||
TData extends Map<String, dynamic>,
|
||||
TQueryData extends Map<String, dynamic>>(
|
||||
Query<TQueryFnData, TError, TQueryData> query,
|
||||
QueryObserverOptions<TQueryFnData, TError, TData, TQueryData> options,
|
||||
) {
|
||||
return (options.enabled != false &&
|
||||
(options.refetchOnReconnect == RefetchOnReconnect.always ||
|
||||
(options.refetchOnReconnect != RefetchOnReconnect.off &&
|
||||
isStale(query, options))));
|
||||
isStale<TQueryFnData, TError, TData, TQueryData>(
|
||||
query, options))));
|
||||
}
|
||||
|
||||
bool shouldFetchOptionally<TQueryFnData, TError, TData, TQueryData>(
|
||||
bool shouldFetchOptionally<
|
||||
TQueryFnData extends Map<String, dynamic>,
|
||||
TError,
|
||||
TData extends Map<String, dynamic>,
|
||||
TQueryData extends Map<String, dynamic>>(
|
||||
Query<TQueryFnData, TError, TQueryData> query,
|
||||
Query<TQueryFnData, TError, TQueryData> prevQuery,
|
||||
QueryObserverOptions<TQueryFnData, TError, TData, TQueryData> options,
|
||||
@@ -653,7 +681,11 @@ bool shouldFetchOptionally<TQueryFnData, TError, TData, TQueryData>(
|
||||
isStale(query, options));
|
||||
}
|
||||
|
||||
bool isStale<TQueryFnData, TError, TData, TQueryData>(
|
||||
bool isStale<
|
||||
TQueryFnData extends Map<String, dynamic>,
|
||||
TError,
|
||||
TData extends Map<String, dynamic>,
|
||||
TQueryData extends Map<String, dynamic>>(
|
||||
Query<TQueryFnData, TError, TQueryData> query,
|
||||
QueryObserverOptions<TQueryFnData, TError, TData, TQueryData> options,
|
||||
) {
|
||||
|
||||
@@ -36,9 +36,9 @@ bool isCancelledError(value) {
|
||||
}
|
||||
|
||||
typedef OnError<TError> = void Function(TError error);
|
||||
typedef OnData<TData> = void Function(TData data);
|
||||
typedef OnData<TData extends Map<String, dynamic>> = void Function(TData data);
|
||||
|
||||
class Retryer<TData, TError> {
|
||||
class Retryer<TData extends Map<String, dynamic>, TError> {
|
||||
late void Function({bool? revert, bool? silent}) cancel;
|
||||
late void Function() cancelRetry;
|
||||
late void Function() continueRetry;
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import 'package:fl_query/src/core/models.dart';
|
||||
import 'package:fl_query/src/core/query.dart';
|
||||
import 'package:fl_query/src/core/query_key.dart';
|
||||
import 'package:collection/collection.dart';
|
||||
|
||||
/// Default query keys hash function.
|
||||
/// Dummy function just to fill the gaps for original react-query like
|
||||
@@ -95,41 +96,61 @@ bool shallowEqualMap(Map? a, Map? b) {
|
||||
/// If not, it will replace any deeply equal children of `b` with those
|
||||
/// of `a`\
|
||||
/// This can be used for structural sharing between JSON values for example.
|
||||
/// `a` & `b` can only be Type of [Iterable] or [Map]
|
||||
T replaceEqualDeep<T>(T a, T b) {
|
||||
/// `a` & `b` can only be Type of [List] or [Map]
|
||||
replaceEqualDeep(a, b) {
|
||||
if (a == b) {
|
||||
return a;
|
||||
}
|
||||
|
||||
bool isList = (a is Iterable && b is Iterable);
|
||||
if (isList || (a is Map && b is Map)) {
|
||||
int aSize = isList ? a.length : (a as Map).keys.length;
|
||||
List bItems = (isList ? b : (b as Map).keys).toList();
|
||||
int bSize = bItems.length;
|
||||
var copy;
|
||||
|
||||
int equalItems = 0;
|
||||
|
||||
for (int i = 0; i < bSize; i++) {
|
||||
var key = isList ? i : bItems[i];
|
||||
if (isList) {
|
||||
copy ??= [];
|
||||
copy[key] = replaceEqualDeep((a as List)[key], (b as List)[key]);
|
||||
if (copy[key] == a[key]) {
|
||||
equalItems++;
|
||||
}
|
||||
} else {
|
||||
copy ??= {};
|
||||
copy[key] = replaceEqualDeep((a as Map)[key], (b as Map)[key]);
|
||||
if (copy[key] == a[key]) {
|
||||
equalItems++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return aSize == bSize && equalItems == aSize ? a : copy as T;
|
||||
int aSize;
|
||||
List bItems;
|
||||
int bSize;
|
||||
int equalItems = 0;
|
||||
onEqual() => equalItems++;
|
||||
var copy;
|
||||
if (a is List && b is List) {
|
||||
aSize = a.length;
|
||||
bItems = b;
|
||||
bSize = bItems.length;
|
||||
copy = replaceEqualDeepList(a, b, onEqual);
|
||||
} else if (a is Map && b is Map) {
|
||||
aSize = a.keys.length;
|
||||
bItems = b.keys.toList();
|
||||
bSize = bItems.length;
|
||||
copy = replaceEqualDeepMap(a, b, onEqual);
|
||||
} else {
|
||||
return b;
|
||||
}
|
||||
return b;
|
||||
return aSize == bSize && equalItems == aSize ? a : copy;
|
||||
}
|
||||
|
||||
Map replaceEqualDeepMap(Map a, Map b, void Function() onEqual) {
|
||||
final copy = Map.from(a);
|
||||
copy.clear();
|
||||
for (final bEntry in b.entries) {
|
||||
final aItem = a[bEntry.key];
|
||||
copy[bEntry.key] =
|
||||
aItem != null ? replaceEqualDeep(aItem, bEntry.value) : bEntry.value;
|
||||
if (copy[bEntry.key] == aItem) {
|
||||
onEqual();
|
||||
}
|
||||
}
|
||||
return copy;
|
||||
}
|
||||
|
||||
List replaceEqualDeepList(List a, List b, void Function() onEqual) {
|
||||
final copy = List.of(a, growable: true);
|
||||
copy.clear();
|
||||
for (final bEntry in b.asMap().entries) {
|
||||
final aItem = a.firstWhereIndexedOrNull((i, _) => i == bEntry.key);
|
||||
final result =
|
||||
aItem != null ? replaceEqualDeep(aItem, bEntry.value) : bEntry.value;
|
||||
copy.add(result);
|
||||
if (copy.last == aItem) {
|
||||
onEqual();
|
||||
}
|
||||
}
|
||||
return copy;
|
||||
}
|
||||
|
||||
Duration timeUntilStale(DateTime updatedAt, [Duration? staleTime]) =>
|
||||
|
||||
Reference in New Issue
Block a user