more tests added for Query

prefetchQuery support added
seperate methods for adding & removing listeners for events of both query & mutations
refetchInterval not working when used Query.fromOptions bug fixed
This commit is contained in:
Kingkor Roy Tirtho
2022-07-28 12:01:37 +06:00
parent 4e329169b5
commit 6d2952ae6a
14 changed files with 383 additions and 167 deletions
@@ -56,12 +56,14 @@ class _BasicMutationExampleState extends State<BasicMutationExample> {
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
Text( Text(
"# Basic Mutation Example", "# Basic Mutation Example (with Failure & Retry simulation)",
style: Theme.of(context).textTheme.headline5, style: Theme.of(context).textTheme.headline5,
), ),
MutationBuilder<Map, Map<String, dynamic>>( MutationBuilder<Map, Map<String, dynamic>>(
job: basicMutationJob, job: basicMutationJob,
onMutate: (v) { onMutate: (v) {
final data =
QueryBowl.of(context).getQuery(successJob.queryKey)?.data;
QueryBowl.of(context) QueryBowl.of(context)
.setQueryData<String, void>(successJob.queryKey, (oldData) { .setQueryData<String, void>(successJob.queryKey, (oldData) {
if (oldData?.contains("After Mutate (OPTIMISTIC UPDATE)") == if (oldData?.contains("After Mutate (OPTIMISTIC UPDATE)") ==
@@ -70,6 +72,11 @@ class _BasicMutationExampleState extends State<BasicMutationExample> {
} }
return "$oldData - After Mutate (OPTIMISTIC UPDATE)"; return "$oldData - After Mutate (OPTIMISTIC UPDATE)";
}); });
return data;
},
onData: (data, variables, context) {
print("Passed Variable: $variables");
print("Safe Previous Value: $context");
}, },
builder: (context, mutation) { builder: (context, mutation) {
return Padding( return Padding(
@@ -94,7 +101,7 @@ class _BasicMutationExampleState extends State<BasicMutationExample> {
"title": title, "title": title,
"body": body, "body": body,
"id": id, "id": id,
}, onData: (data) { }, onData: (data, variables, context) {
// resetting the form // resetting the form
titleController.text = ""; titleController.text = "";
bodyController.text = ""; bodyController.text = "";
@@ -49,7 +49,7 @@ class BasicHookMutationExample extends HookWidget {
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
Text( Text(
"# Basic Mutation Hook Example", "# Basic Mutation Hook Example (with failure & retry simulation)",
style: Theme.of(context).textTheme.headline5, style: Theme.of(context).textTheme.headline5,
), ),
Padding( Padding(
@@ -74,7 +74,7 @@ class BasicHookMutationExample extends HookWidget {
"title": title, "title": title,
"body": body, "body": body,
"id": id, "id": id,
}, onData: (data) { }, onData: (data, variable, context) {
// resetting the form // resetting the form
titleController.text = ""; titleController.text = "";
bodyController.text = ""; bodyController.text = "";
@@ -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.5/","native_build":true,"dependencies":[]}],"android":[{"name":"connectivity_plus","path":"/home/krtirtho/.pub-cache/hosted/pub.dartlang.org/connectivity_plus-2.3.5/","native_build":true,"dependencies":[]}],"macos":[{"name":"connectivity_plus_macos","path":"/home/krtirtho/.pub-cache/hosted/pub.dartlang.org/connectivity_plus_macos-1.2.4/","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":[]}],"windows":[{"name":"connectivity_plus_windows","path":"/home/krtirtho/.pub-cache/hosted/pub.dartlang.org/connectivity_plus_windows-1.2.2/","native_build":true,"dependencies":[]}],"web":[{"name":"connectivity_plus_web","path":"/home/krtirtho/.pub-cache/hosted/pub.dartlang.org/connectivity_plus_web-1.2.2/","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":[]}],"date_created":"2022-07-20 12:20:16.617434","version":"3.0.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.5/","native_build":true,"dependencies":[]}],"android":[{"name":"connectivity_plus","path":"/home/krtirtho/.pub-cache/hosted/pub.dartlang.org/connectivity_plus-2.3.5/","native_build":true,"dependencies":[]}],"macos":[{"name":"connectivity_plus_macos","path":"/home/krtirtho/.pub-cache/hosted/pub.dartlang.org/connectivity_plus_macos-1.2.4/","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":[]}],"windows":[{"name":"connectivity_plus_windows","path":"/home/krtirtho/.pub-cache/hosted/pub.dartlang.org/connectivity_plus_windows-1.2.2/","native_build":true,"dependencies":[]}],"web":[{"name":"connectivity_plus_web","path":"/home/krtirtho/.pub-cache/hosted/pub.dartlang.org/connectivity_plus_web-1.2.2/","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":[]}],"date_created":"2022-07-28 10:55:33.933539","version":"3.0.1"}
@@ -1,3 +1,4 @@
import 'package:connectivity_plus/connectivity_plus.dart';
import 'package:fl_query/src/query.dart'; import 'package:fl_query/src/query.dart';
class QueryJob<T extends Object, Outside> { class QueryJob<T extends Object, Outside> {
@@ -20,6 +21,7 @@ class QueryJob<T extends Object, Outside> {
Duration? cacheTime; Duration? cacheTime;
Duration? refetchInterval; Duration? refetchInterval;
Connectivity? connectivity;
QueryJob({ QueryJob({
required String queryKey, required String queryKey,
@@ -34,6 +36,7 @@ class QueryJob<T extends Object, Outside> {
this.refetchOnMount, this.refetchOnMount,
this.refetchOnReconnect, this.refetchOnReconnect,
this.refetchOnExternalDataChange, this.refetchOnExternalDataChange,
this.connectivity,
}) : _queryKey = queryKey; }) : _queryKey = queryKey;
String get queryKey => _queryKey; String get queryKey => _queryKey;
@@ -56,6 +59,7 @@ class QueryJob<T extends Object, Outside> {
bool? refetchOnMount, bool? refetchOnMount,
bool? refetchOnReconnect, bool? refetchOnReconnect,
bool? refetchOnExternalDataChange, bool? refetchOnExternalDataChange,
Connectivity? connectivity,
}) { }) {
return (String queryKey) { return (String queryKey) {
if (preQueryKey != null) queryKey = "$preQueryKey#$queryKey"; if (preQueryKey != null) queryKey = "$preQueryKey#$queryKey";
@@ -72,6 +76,7 @@ class QueryJob<T extends Object, Outside> {
refetchOnMount: refetchOnMount, refetchOnMount: refetchOnMount,
refetchOnReconnect: refetchOnReconnect, refetchOnReconnect: refetchOnReconnect,
refetchOnExternalDataChange: refetchOnExternalDataChange, refetchOnExternalDataChange: refetchOnExternalDataChange,
connectivity: connectivity,
); );
}; };
} }
+76 -36
View File
@@ -1,5 +1,6 @@
import 'dart:async'; import 'dart:async';
import 'package:fl_query/fl_query.dart';
import 'package:fl_query/src/base_operation.dart'; import 'package:fl_query/src/base_operation.dart';
import 'package:fl_query/src/models/mutation_job.dart'; import 'package:fl_query/src/models/mutation_job.dart';
import 'package:flutter/widgets.dart'; import 'package:flutter/widgets.dart';
@@ -11,7 +12,13 @@ enum MutationStatus {
idle, idle,
} }
typedef MutationListener<T> = FutureOr<void> Function(T); typedef MutationListenerReturnable<T, R> = FutureOr<R> Function(T);
typedef MutationListener<T, V> = FutureOr<void> Function(
T payload,
V variables,
dynamic context,
);
typedef MutationTaskFunction<T, V> = FutureOr<T> Function( typedef MutationTaskFunction<T, V> = FutureOr<T> Function(
String queryKey, V variables); String queryKey, V variables);
@@ -23,12 +30,18 @@ class Mutation<T extends Object, V> extends BaseOperation<T> {
MutationStatus status; MutationStatus status;
dynamic _sideEffectContext;
@protected @protected
final Set<MutationListener<T>> onDataListeners = {}; final Set<MutationListener<T, V>> _onDataListeners = {};
@protected @protected
final Set<MutationListener<dynamic>> onErrorListeners = {}; final Set<MutationListener<dynamic, V>> _onErrorListeners = {};
@protected @protected
final Set<MutationListener<V>> onMutateListeners = {}; final Set<MutationListenerReturnable<V, dynamic>> _onMutateListeners = {};
// using late as _variables will only be used after a [mutate] or
// [mutateAsync] is executed
late V _variables;
Mutation({ Mutation({
required this.mutationKey, required this.mutationKey,
@@ -37,21 +50,21 @@ class Mutation<T extends Object, V> extends BaseOperation<T> {
required super.retryDelay, required super.retryDelay,
required super.queryBowl, required super.queryBowl,
required Duration cacheTime, required Duration cacheTime,
MutationListener<T>? onData, MutationListener<T, V>? onData,
MutationListener<dynamic>? onError, MutationListener<dynamic, V>? onError,
MutationListener<V>? onMutate, MutationListenerReturnable<V, dynamic>? onMutate,
}) : status = MutationStatus.idle, }) : status = MutationStatus.idle,
super(cacheTime: cacheTime) { super(cacheTime: cacheTime) {
if (onData != null) onDataListeners.add(onData); if (onData != null) _onDataListeners.add(onData);
if (onError != null) onErrorListeners.add(onError); if (onError != null) _onErrorListeners.add(onError);
if (onMutate != null) onMutateListeners.add(onMutate); if (onMutate != null) _onMutateListeners.add(onMutate);
} }
Mutation.fromOptions( Mutation.fromOptions(
MutationJob<T, V> options, { MutationJob<T, V> options, {
MutationListener<T>? onData, MutationListener<T, V>? onData,
MutationListener<dynamic>? onError, MutationListener<dynamic, V>? onError,
MutationListener<V>? onMutate, MutationListenerReturnable<V, dynamic>? onMutate,
required super.queryBowl, required super.queryBowl,
}) : mutationKey = options.mutationKey, }) : mutationKey = options.mutationKey,
task = options.task, task = options.task,
@@ -61,8 +74,8 @@ class Mutation<T extends Object, V> extends BaseOperation<T> {
retryDelay: options.retryDelay ?? const Duration(milliseconds: 200), retryDelay: options.retryDelay ?? const Duration(milliseconds: 200),
cacheTime: options.cacheTime ?? const Duration(minutes: 5), cacheTime: options.cacheTime ?? const Duration(minutes: 5),
) { ) {
if (onData != null) onDataListeners.add(onData); if (onData != null) _onDataListeners.add(onData);
if (onError != null) onErrorListeners.add(onError); if (onError != null) _onErrorListeners.add(onError);
} }
// all methods // all methods
@@ -74,22 +87,22 @@ class Mutation<T extends Object, V> extends BaseOperation<T> {
status = MutationStatus.loading; status = MutationStatus.loading;
notifyListeners(); notifyListeners();
retryAttempts = 0; retryAttempts = 0;
for (final onMutate in onMutateListeners) { for (final onMutate in _onMutateListeners) {
onMutate(variables); _sideEffectContext = await onMutate(variables);
} }
data = await task(mutationKey, variables); data = await task(mutationKey, variables);
updatedAt = DateTime.now(); updatedAt = DateTime.now();
status = MutationStatus.success; status = MutationStatus.success;
for (final onData in onDataListeners) { for (final onData in _onDataListeners) {
onData(data!); onData(data!, _variables, _sideEffectContext);
} }
notifyListeners(); notifyListeners();
} catch (e) { } catch (e) {
if (retries == 0) { if (retries == 0) {
status = MutationStatus.error; status = MutationStatus.error;
error = e; error = e;
for (final onError in onErrorListeners) { for (final onError in _onErrorListeners) {
onError(error); onError(error, variables, _sideEffectContext);
} }
notifyListeners(); notifyListeners();
} else { } else {
@@ -97,13 +110,13 @@ class Mutation<T extends Object, V> extends BaseOperation<T> {
while (retryAttempts <= retries) { while (retryAttempts <= retries) {
await Future.delayed(retryDelay); await Future.delayed(retryDelay);
try { try {
for (final onMutate in onMutateListeners) { for (final onMutate in _onMutateListeners) {
onMutate(variables); _sideEffectContext = onMutate(variables);
} }
data = await task(mutationKey, variables); data = await task(mutationKey, variables);
status = MutationStatus.success; status = MutationStatus.success;
for (final onData in onDataListeners) { for (final onData in _onDataListeners) {
onData(data!); onData(data!, variables, _sideEffectContext);
} }
notifyListeners(); notifyListeners();
break; break;
@@ -111,8 +124,8 @@ class Mutation<T extends Object, V> extends BaseOperation<T> {
if (retryAttempts == retries) { if (retryAttempts == retries) {
status = MutationStatus.error; status = MutationStatus.error;
error = e; error = e;
for (final onError in onErrorListeners) { for (final onError in _onErrorListeners) {
onError(error); onError(error, variables, _sideEffectContext);
} }
notifyListeners(); notifyListeners();
} }
@@ -123,20 +136,46 @@ class Mutation<T extends Object, V> extends BaseOperation<T> {
} }
} }
void addDataListener(MutationListener<T, V> listener) {
_onDataListeners.add(listener);
}
void addErrorListener(MutationListener<dynamic, V> listener) {
_onErrorListeners.add(listener);
}
void addMutateListener(MutationListenerReturnable<V, dynamic> listener) {
_onMutateListeners.add(listener);
}
void removeDataListener(MutationListener<T, V> listener) {
_onDataListeners.remove(listener);
}
void removeErrorListener(MutationListener<dynamic, V> listener) {
_onErrorListeners.remove(listener);
}
void removeMutateListener(MutationListenerReturnable<V, dynamic> listener) {
_onMutateListeners.remove(listener);
}
void mutate( void mutate(
V variables, { V variables, {
MutationListener<T>? onData, MutationListener<T, V>? onData,
MutationListener<dynamic>? onError, MutationListener<dynamic, V>? onError,
}) { }) {
if (onData != null) onDataListeners.add(onData); _variables = variables;
if (onError != null) onErrorListeners.add(onError); if (onData != null) _onDataListeners.add(onData);
if (onError != null) _onErrorListeners.add(onError);
_execute(variables).then((_) { _execute(variables).then((_) {
onDataListeners.remove(onData); _onDataListeners.remove(onData);
onErrorListeners.remove(onError); _onErrorListeners.remove(onError);
}); });
} }
Future<T?> mutateAsync(V variables) async { Future<T?> mutateAsync(V variables) async {
_variables = variables;
return await _execute(variables).then((_) => data); return await _execute(variables).then((_) => data);
} }
@@ -155,10 +194,11 @@ class Mutation<T extends Object, V> extends BaseOperation<T> {
data = null; data = null;
retryAttempts = 0; retryAttempts = 0;
updatedAt = DateTime.now(); updatedAt = DateTime.now();
onDataListeners.clear(); _onDataListeners.clear();
onErrorListeners.clear(); _onErrorListeners.clear();
status = MutationStatus.idle; status = MutationStatus.idle;
onMutateListeners.clear(); _onMutateListeners.clear();
_sideEffectContext = null;
} }
A? cast<A>() => this is A ? this as A : null; A? cast<A>() => this is A ? this as A : null;
+12 -16
View File
@@ -10,15 +10,15 @@ class MutationBuilder<T extends Object, V> extends StatefulWidget {
/// Called when the query returns new data, on query /// Called when the query returns new data, on query
/// refetch or query gets expired /// refetch or query gets expired
final MutationListener<T>? onData; final MutationListener<T, V>? onData;
/// Called when the query returns error /// Called when the query returns error
final MutationListener<dynamic>? onError; final MutationListener<dynamic, V>? onError;
/// called right before the mutation is about to run /// called right before the mutation is about to run
/// ///
/// perfect scenario for doing optimistic updates /// perfect scenario for doing optimistic updates
final MutationListener<V>? onMutate; final MutationListenerReturnable<V, dynamic>? onMutate;
const MutationBuilder({ const MutationBuilder({
required this.job, required this.job,
@@ -66,19 +66,17 @@ class _MutationBuilderState<T extends Object, V>
init(); init();
} else { } else {
if (oldWidget.onData != widget.onData && oldWidget.onData != null) { if (oldWidget.onData != widget.onData && oldWidget.onData != null) {
mutation?.onDataListeners.remove(oldWidget.onData); mutation?.removeDataListener(oldWidget.onData!);
if (widget.onData != null) if (widget.onData != null) mutation?.addDataListener(widget.onData!);
mutation?.onDataListeners.add(widget.onData!);
} }
if (oldWidget.onError != widget.onError && oldWidget.onError != null) { if (oldWidget.onError != widget.onError && oldWidget.onError != null) {
mutation?.onErrorListeners.remove(oldWidget.onError); mutation?.removeErrorListener(oldWidget.onError!);
if (widget.onError != null) if (widget.onError != null) mutation?.addErrorListener(widget.onError!);
mutation?.onErrorListeners.add(widget.onError!);
} }
if (oldWidget.onMutate != widget.onMutate && oldWidget.onMutate != null) { if (oldWidget.onMutate != widget.onMutate && oldWidget.onMutate != null) {
mutation?.onMutateListeners.remove(oldWidget.onMutate); mutation?.removeMutateListener(oldWidget.onMutate!);
if (widget.onMutate != null) if (widget.onMutate != null)
mutation?.onMutateListeners.add(widget.onMutate!); mutation?.addMutateListener(widget.onMutate!);
} }
} }
super.didUpdateWidget(oldWidget); super.didUpdateWidget(oldWidget);
@@ -92,11 +90,9 @@ class _MutationBuilderState<T extends Object, V>
void _mutationDispose() { void _mutationDispose() {
mutation?.unmount(uKey); mutation?.unmount(uKey);
if (widget.onData != null) mutation?.onDataListeners.remove(widget.onData); if (widget.onData != null) mutation?.addDataListener(widget.onData!);
if (widget.onError != null) if (widget.onError != null) mutation?.addErrorListener(widget.onError!);
mutation?.onErrorListeners.remove(widget.onError); if (widget.onMutate != null) mutation?.addMutateListener(widget.onMutate!);
if (widget.onMutate != null)
mutation?.onMutateListeners.remove(widget.onMutate);
} }
@override @override
+54 -22
View File
@@ -56,10 +56,8 @@ class Query<T extends Object, Outside> extends BaseOperation<T> {
QueryStatus status; QueryStatus status;
@protected final Set<QueryListener<T>> _onDataListeners = Set<QueryListener<T>>();
final Set<QueryListener<T>> onDataListeners = Set<QueryListener<T>>(); final Set<QueryListener<dynamic>> _onErrorListeners =
@protected
final Set<QueryListener<dynamic>> onErrorListeners =
Set<QueryListener<dynamic>>(); Set<QueryListener<dynamic>>();
// externalData will always be passed to the task Callback // externalData will always be passed to the task Callback
@@ -72,6 +70,8 @@ class Query<T extends Object, Outside> extends BaseOperation<T> {
Timer? _refetchIntervalTimer; Timer? _refetchIntervalTimer;
Connectivity _connectivity;
Query({ Query({
required this.queryKey, required this.queryKey,
required this.task, required this.task,
@@ -85,6 +85,7 @@ class Query<T extends Object, Outside> extends BaseOperation<T> {
this.refetchOnReconnect, this.refetchOnReconnect,
this.refetchInterval, this.refetchInterval,
this.enabled = true, this.enabled = true,
Connectivity? connectivity,
T? initialData, T? initialData,
QueryListener<T>? onData, QueryListener<T>? onData,
QueryListener<dynamic>? onError, QueryListener<dynamic>? onError,
@@ -92,9 +93,10 @@ class Query<T extends Object, Outside> extends BaseOperation<T> {
_initialData = initialData, _initialData = initialData,
_externalData = externalData, _externalData = externalData,
status = QueryStatus.idle, status = QueryStatus.idle,
_connectivity = connectivity ?? Connectivity(),
super(data: initialData) { super(data: initialData) {
if (onData != null) onDataListeners.add(onData); if (onData != null) _onDataListeners.add(onData);
if (onError != null) onErrorListeners.add(onError); if (onError != null) _onErrorListeners.add(onError);
if (refetchInterval != null && refetchInterval != Duration.zero) { if (refetchInterval != null && refetchInterval != Duration.zero) {
_refetchIntervalTimer = _createRefetchTimer(); _refetchIntervalTimer = _createRefetchTimer();
@@ -117,14 +119,18 @@ class Query<T extends Object, Outside> extends BaseOperation<T> {
refetchOnMount = options.refetchOnMount, refetchOnMount = options.refetchOnMount,
refetchOnReconnect = options.refetchOnReconnect, refetchOnReconnect = options.refetchOnReconnect,
status = QueryStatus.idle, status = QueryStatus.idle,
_connectivity = options.connectivity ?? Connectivity(),
super( super(
cacheTime: options.cacheTime ?? const Duration(minutes: 5), cacheTime: options.cacheTime ?? const Duration(minutes: 5),
retries: options.retries ?? 3, retries: options.retries ?? 3,
retryDelay: options.retryDelay ?? const Duration(milliseconds: 200), retryDelay: options.retryDelay ?? const Duration(milliseconds: 200),
data: options.initialData, data: options.initialData,
) { ) {
if (onData != null) onDataListeners.add(onData); if (onData != null) _onDataListeners.add(onData);
if (onError != null) onErrorListeners.add(onError); if (onError != null) _onErrorListeners.add(onError);
if (refetchInterval != null && refetchInterval != Duration.zero) {
_refetchIntervalTimer = _createRefetchTimer();
}
} }
// all getters & setters // all getters & setters
@@ -138,9 +144,7 @@ class Query<T extends Object, Outside> extends BaseOperation<T> {
(_) async { (_) async {
// only refetch if its connected to the internet or refetch will // only refetch if its connected to the internet or refetch will
// always result in error while there's no internet // always result in error while there's no internet
if (isStale && if (isStale && await isInternetConnected()) await refetch();
isConnectedToInternet(await Connectivity().checkConnectivity()))
await refetch();
}, },
); );
} }
@@ -157,7 +161,7 @@ class Query<T extends Object, Outside> extends BaseOperation<T> {
_prevUsedExternalData = _externalData; _prevUsedExternalData = _externalData;
updatedAt = DateTime.now(); updatedAt = DateTime.now();
status = QueryStatus.success; status = QueryStatus.success;
for (final onData in onDataListeners) { for (final onData in _onDataListeners) {
onData(data!); onData(data!);
} }
notifyListeners(); notifyListeners();
@@ -165,7 +169,7 @@ class Query<T extends Object, Outside> extends BaseOperation<T> {
if (retries == 0) { if (retries == 0) {
status = QueryStatus.error; status = QueryStatus.error;
error = e; error = e;
for (final onError in onErrorListeners) { for (final onError in _onErrorListeners) {
onError(error); onError(error);
} }
notifyListeners(); notifyListeners();
@@ -180,7 +184,7 @@ class Query<T extends Object, Outside> extends BaseOperation<T> {
); );
_prevUsedExternalData = _externalData; _prevUsedExternalData = _externalData;
status = QueryStatus.success; status = QueryStatus.success;
for (final onData in onDataListeners) { for (final onData in _onDataListeners) {
await onData(data!); await onData(data!);
} }
notifyListeners(); notifyListeners();
@@ -189,7 +193,7 @@ class Query<T extends Object, Outside> extends BaseOperation<T> {
if (retryAttempts == retries) { if (retryAttempts == retries) {
status = QueryStatus.error; status = QueryStatus.error;
error = e; error = e;
for (final onError in onErrorListeners) { for (final onError in _onErrorListeners) {
await onError(error); await onError(error);
} }
notifyListeners(); notifyListeners();
@@ -202,6 +206,22 @@ class Query<T extends Object, Outside> extends BaseOperation<T> {
} }
} }
void addDataListener(QueryListener<T> listener) {
_onDataListeners.add(listener);
}
void addErrorListener(QueryListener<dynamic> listener) {
_onErrorListeners.add(listener);
}
void removeDataListener(QueryListener<T> listener) {
_onDataListeners.remove(listener);
}
void removeErrorListener(QueryListener<dynamic> listener) {
_onErrorListeners.remove(listener);
}
Future<T?> fetch() async { Future<T?> fetch() async {
if (!enabled) return null; if (!enabled) return null;
@@ -258,8 +278,8 @@ class Query<T extends Object, Outside> extends BaseOperation<T> {
fetched = false; fetched = false;
status = QueryStatus.idle; status = QueryStatus.idle;
retryAttempts = 0; retryAttempts = 0;
onDataListeners.clear(); _onDataListeners.clear();
onErrorListeners.clear(); _onErrorListeners.clear();
mounts.clear(); mounts.clear();
} }
@@ -290,13 +310,27 @@ class Query<T extends Object, Outside> extends BaseOperation<T> {
notifyListeners(); notifyListeners();
} }
Future<bool> isInternetConnected() async {
return isConnectedToInternet(await _connectivity.checkConnectivity());
}
/// invalidates the query
void invalidate() {
/// subtracting [staleTime] from [updatedAt] as staleTime=Duration.zero
/// indicates the query must never become stale but subtracting the
/// [staleTime] will always revert the updatedAt time to the default
/// time whenever isStale is called
updatedAt = updatedAt.subtract(_staleTime);
notifyListeners();
}
bool get isStale { bool get isStale {
/// when [_staleTime] is [Duration.zero], the query will always be /// when [_staleTime] is [Duration.zero], the query will always be
/// stale & will never refetch in the background. But can be inactive /// stale & will never refetch in the background. But can be inactive
/// if [mounts.length] become zero /// if [mounts.length] become zero
if (_staleTime == Duration.zero) return false; if (_staleTime == Duration.zero) return false;
// when current DateTime is after [update_at + stale_time] it means // when [DateTime.now()] is after [update_at + stale_time] it means
// the data has become stale // the data has become stale
return DateTime.now().isAfter(updatedAt.add(_staleTime)); return DateTime.now().isAfter(updatedAt.add(_staleTime));
} }
@@ -315,10 +349,8 @@ class Query<T extends Object, Outside> extends BaseOperation<T> {
void mount(ValueKey<String> uKey) { void mount(ValueKey<String> uKey) {
super.mount(uKey); super.mount(uKey);
if (refetchOnMount == true && isStale) { if (refetchOnMount == true && isStale) {
Connectivity().checkConnectivity().then((status) async { this.isInternetConnected().then((isConnected) async {
if (isConnectedToInternet(status)) { if (isConnected) await refetch();
await refetch();
}
}); });
} }
} }
+64 -46
View File
@@ -282,6 +282,39 @@ class QueryBowl extends InheritedWidget {
_addMutation = addMutation, _addMutation = addMutation,
super(child: child, key: key); super(child: child, key: key);
Query<T, Outside> _createQueryWithDefaults<T extends Object, Outside>(
QueryJob<T, Outside> options,
Outside externalData,
) {
final query = Query<T, Outside>.fromOptions(
options,
externalData: externalData,
queryBowl: this,
);
query.updateDefaultOptions(
cacheTime: cacheTime,
staleTime: staleTime,
refetchInterval: refetchInterval,
refetchOnMount: refetchOnMount,
refetchOnReconnect: refetchOnReconnect,
);
return query;
}
Future<T?> prefetchQuery<T extends Object, Outside>(
QueryJob<T, Outside> options, {
required Outside externalData,
}) async {
final prevQuery =
_queries.firstWhereOrNull((q) => q.queryKey == options.queryKey);
if (prevQuery != null && prevQuery is Query<T, Outside>)
return prevQuery.data;
final query = _createQueryWithDefaults<T, Outside>(options, externalData);
_addQuery<T, Outside>(query);
return await query.fetch();
}
/// !⚠️**Warning** only for internal library usage /// !⚠️**Warning** only for internal library usage
@protected @protected
Future<T?> fetchQuery<T extends Object, Outside>( Future<T?> fetchQuery<T extends Object, Outside>(
@@ -303,8 +336,8 @@ class QueryBowl extends InheritedWidget {
externalData, externalData,
); );
prevQuery.mount(key); prevQuery.mount(key);
if (onData != null) prevQuery.onDataListeners.add(onData); if (onData != null) prevQuery.addDataListener(onData);
if (onError != null) prevQuery.onErrorListeners.add(onError); if (onError != null) prevQuery.addErrorListener(onError);
if (!prevQuery.hasData || hasExternalDataChanged) { if (!prevQuery.hasData || hasExternalDataChanged) {
if (hasExternalDataChanged) prevQuery.setExternalData(externalData); if (hasExternalDataChanged) prevQuery.setExternalData(externalData);
@@ -314,19 +347,7 @@ class QueryBowl extends InheritedWidget {
return prevQuery.data; return prevQuery.data;
} }
/// populating with default configurations final query = _createQueryWithDefaults<T, Outside>(options, externalData);
options.refetchInterval ??= refetchInterval;
options.staleTime ??= staleTime;
options.cacheTime ??= cacheTime;
options.refetchOnMount ??= refetchOnMount;
options.refetchOnReconnect ??= refetchOnReconnect;
final query = Query<T, Outside>.fromOptions(
options,
externalData: externalData,
queryBowl: this,
onData: onData,
onError: onError,
);
query.mount(key); query.mount(key);
_addQuery<T, Outside>(query); _addQuery<T, Outside>(query);
return await query.fetch(); return await query.fetch();
@@ -355,25 +376,14 @@ class QueryBowl extends InheritedWidget {
prevQuery.setExternalData(externalData); prevQuery.setExternalData(externalData);
} }
prevQuery.mount(key); prevQuery.mount(key);
if (onData != null) prevQuery.onDataListeners.add(onData); if (onData != null) prevQuery.addDataListener(onData);
if (onError != null) prevQuery.onErrorListeners.add(onError); if (onError != null) prevQuery.addErrorListener(onError);
// mounting the widget that is using the query in the prevQuery // mounting the widget that is using the query in the prevQuery
return prevQuery; return prevQuery;
} }
final query = Query<T, Outside>.fromOptions( final query = _createQueryWithDefaults<T, Outside>(queryJob, externalData);
queryJob, if (onData != null) query.addDataListener(onData);
externalData: externalData, if (onError != null) query.addErrorListener(onError);
queryBowl: this,
);
if (onData != null) query.onDataListeners.add(onData);
if (onError != null) query.onErrorListeners.add(onError);
query.updateDefaultOptions(
cacheTime: cacheTime,
staleTime: staleTime,
refetchInterval: refetchInterval,
refetchOnMount: refetchOnMount,
refetchOnReconnect: refetchOnReconnect,
);
query.mount(key); query.mount(key);
_addQuery<T, Outside>(query); _addQuery<T, Outside>(query);
return query; return query;
@@ -383,17 +393,17 @@ class QueryBowl extends InheritedWidget {
@protected @protected
Mutation<T, V> addMutation<T extends Object, V>( Mutation<T, V> addMutation<T extends Object, V>(
MutationJob<T, V> mutationJob, { MutationJob<T, V> mutationJob, {
final MutationListener<T>? onData, final MutationListener<T, V>? onData,
final MutationListener<dynamic>? onError, final MutationListener<dynamic, V>? onError,
final MutationListener<V>? onMutate, final MutationListenerReturnable<V, dynamic>? onMutate,
required ValueKey<String> key, required ValueKey<String> key,
}) { }) {
final prevMutation = _mutations.firstWhereOrNull( final prevMutation = _mutations.firstWhereOrNull(
(prevMutation) => prevMutation.mutationKey == mutationJob.mutationKey); (prevMutation) => prevMutation.mutationKey == mutationJob.mutationKey);
if (prevMutation != null && prevMutation is Mutation<T, V>) { if (prevMutation != null && prevMutation is Mutation<T, V>) {
if (onData != null) prevMutation.onDataListeners.add(onData); if (onData != null) prevMutation.addDataListener(onData);
if (onError != null) prevMutation.onErrorListeners.add(onError); if (onError != null) prevMutation.addErrorListener(onError);
if (onMutate != null) prevMutation.onMutateListeners.add(onMutate); if (onMutate != null) prevMutation.addMutateListener(onMutate);
prevMutation.mount(key); prevMutation.mount(key);
return prevMutation; return prevMutation;
} else { } else {
@@ -401,9 +411,9 @@ class QueryBowl extends InheritedWidget {
mutationJob, mutationJob,
queryBowl: this, queryBowl: this,
); );
if (onData != null) mutation.onDataListeners.add(onData); if (onData != null) mutation.addDataListener(onData);
if (onError != null) mutation.onErrorListeners.add(onError); if (onError != null) mutation.addErrorListener(onError);
if (onMutate != null) mutation.onMutateListeners.add(onMutate); if (onMutate != null) mutation.addMutateListener(onMutate);
mutation.updateDefaultOptions(cacheTime: cacheTime); mutation.updateDefaultOptions(cacheTime: cacheTime);
mutation.mount(key); mutation.mount(key);
_addMutation(mutation); _addMutation(mutation);
@@ -461,27 +471,35 @@ class QueryBowl extends InheritedWidget {
} }
/// resets all the queries matching the passed List of queryKeys /// resets all the queries matching the passed List of queryKeys
///
/// If an empty list of [queryKeys] is passed then all of the queries
/// will be reset
void resetQueries(List<String> queryKeys) { void resetQueries(List<String> queryKeys) {
for (final query in _queries) { for (final query in _queries) {
if (!queryKeys.contains(query.queryKey)) continue; if (queryKeys.isNotEmpty && !queryKeys.contains(query.queryKey)) continue;
query.reset(); query.reset();
} }
} }
/// makes all the queries matching the passed List of queryKeys stale /// makes all the queries matching the passed List of queryKeys stale
///
/// If an empty list of [queryKeys] is passed then all of the queries
/// will be invalidated
void invalidateQueries(List<String> queryKeys) { void invalidateQueries(List<String> queryKeys) {
for (final query in _queries) { for (final query in _queries) {
if (!queryKeys.contains(query.queryKey)) continue; if (queryKeys.isNotEmpty && queryKeys.contains(query.queryKey)) continue;
// TODO: Implement Invaldiate Queries query.invalidate();
} }
} }
/// refetches all the queries matching the passed List of queryKeys /// refetches all the queries matching the passed List of queryKeys
///
/// If an empty list of [queryKeys] is passed then all of the queries
/// will be refetched
Future<void> refetchQueries(List<String> queryKeys) async { Future<void> refetchQueries(List<String> queryKeys) async {
for (final query in _queries) { for (final query in _queries) {
if (queryKeys.contains(query.queryKey)) { if (queryKeys.isNotEmpty && queryKeys.contains(query.queryKey)) continue;
await query.refetch(); await query.refetch();
}
} }
} }
+8 -9
View File
@@ -90,17 +90,16 @@ class _QueryBuilderState<T extends Object, Outside>
.getQuery(widget.job.queryKey) .getQuery(widget.job.queryKey)
?.setExternalData(widget.externalData); ?.setExternalData(widget.externalData);
} }
if (hasOnDataChanged) query?.onDataListeners.remove(oldWidget.onData); if (hasOnDataChanged) query?.removeDataListener(oldWidget.onData!);
if (hasOnErrorChanged) query?.onErrorListeners.remove(oldWidget.onError); if (hasOnErrorChanged) query?.removeErrorListener(oldWidget.onError!);
} else { } else {
if (hasOnDataChanged) { if (hasOnDataChanged) {
query?.onDataListeners.remove(oldWidget.onData); query?.removeDataListener(oldWidget.onData!);
if (widget.onData != null) query?.onDataListeners.add(widget.onData!); if (widget.onData != null) query?.addDataListener(widget.onData!);
} }
if (hasOnErrorChanged) { if (hasOnErrorChanged) {
query?.onErrorListeners.remove(oldWidget.onError); query?.removeErrorListener(oldWidget.onError!);
if (widget.onError != null) if (widget.onError != null) query?.addErrorListener(widget.onError!);
query?.onErrorListeners.add(widget.onError!);
} }
} }
super.didUpdateWidget(oldWidget); super.didUpdateWidget(oldWidget);
@@ -108,8 +107,8 @@ class _QueryBuilderState<T extends Object, Outside>
_queryDispose() { _queryDispose() {
query?.unmount(uKey); query?.unmount(uKey);
if (widget.onData != null) query?.onDataListeners.remove(widget.onData); if (widget.onData != null) query?.removeDataListener(widget.onData!);
if (widget.onError != null) query?.onErrorListeners.remove(widget.onError); if (widget.onError != null) query?.removeErrorListener(widget.onError!);
} }
@override @override
+101 -7
View File
@@ -1,15 +1,18 @@
import 'dart:math'; import 'dart:math';
import 'package:connectivity_plus/connectivity_plus.dart';
import 'package:fl_query/src/models/query_job.dart'; import 'package:fl_query/src/models/query_job.dart';
import 'package:fl_query/src/query.dart'; import 'package:fl_query/src/query.dart';
import 'package:fl_query/src/query_bowl.dart'; import 'package:fl_query/src/query_bowl.dart';
import 'package:fl_query/src/utils.dart';
import 'package:flutter/widgets.dart';
import 'package:flutter_test/flutter_test.dart'; import 'package:flutter_test/flutter_test.dart';
import 'package:mockito/annotations.dart'; import 'package:mockito/annotations.dart';
import 'package:mockito/mockito.dart'; import 'package:mockito/mockito.dart';
import 'query_test.mocks.dart'; import 'query_test.mocks.dart';
@GenerateMocks( @GenerateMocks(
[QueryBowl], [QueryBowl, Connectivity],
customMocks: [ customMocks: [
MockSpec<QueryJob<Object, void>>( MockSpec<QueryJob<Object, void>>(
as: #MockQueryJobVoidObject, as: #MockQueryJobVoidObject,
@@ -129,7 +132,7 @@ void main() {
"onData listeners are called When new data is fetched and set", "onData listeners are called When new data is fetched and set",
() async { () async {
int count = 0; int count = 0;
query.onDataListeners.add((_) { query.addDataListener((_) {
count++; count++;
}); });
await query.fetch(); await query.fetch();
@@ -138,20 +141,111 @@ void main() {
); );
test( test(
"onError listeners are called When any error occurs", "onError listeners are called When any error occurs",
() {}, () async {
reset(queryJob);
when(queryJob.queryKey).thenReturn("test");
when(queryJob.task).thenAnswer(
(_) => (_, __) => Future.error("Error"),
);
query = Query.fromOptions(
queryJob,
externalData: null,
queryBowl: queryBowl,
);
int count = 0;
query.addErrorListener((_) {
count++;
});
await query.fetch();
expect(count, 1);
},
); );
test("query should become stale after defined amount time", () {}); test("query should become stale after defined amount time", () async {
when(queryJob.staleTime).thenReturn(Duration(milliseconds: 500));
query = Query.fromOptions(
queryJob,
externalData: null,
queryBowl: queryBowl,
);
expect(query.isStale, isFalse);
await Future.delayed(Duration(milliseconds: 300));
expect(query.isStale, isFalse);
await Future.delayed(Duration(milliseconds: 600));
expect(query.isStale, isTrue);
});
test( test(
"query should refetch in interval When refetchInterval is specified", "query should refetch in interval When refetchInterval is specified",
() {}, () async {
reset(queryJob);
when(queryJob.queryKey).thenReturn("test");
when(queryJob.task).thenAnswer(
(_) => (_, __) => Future.value(Random().nextInt(100)),
);
when(queryJob.staleTime).thenReturn(
Duration(milliseconds: 1),
);
when(queryJob.refetchInterval).thenReturn(
Duration(milliseconds: 200),
);
query = Query.fromOptions(
queryJob,
externalData: null,
queryBowl: queryBowl,
);
final data = await query.fetch();
await Future.delayed(Duration(milliseconds: 400));
expect(data, isNot(equals(await query.fetch())));
},
); );
test( test(
"query should revalidate When a new caller gets mounted", "query should revalidate When a new caller gets mounted",
() {}, () async {
reset(queryJob);
when(queryJob.queryKey).thenReturn("test");
when(queryJob.task).thenAnswer(
(_) => (_, __) => Future.value(Random().nextInt(150)),
);
when(queryJob.refetchOnMount).thenReturn(true);
query = Query.fromOptions(
queryJob,
externalData: null,
queryBowl: queryBowl,
);
final data = await query.fetch();
query.invalidate();
query.mount(ValueKey<String>(uuid.v4()));
await Future.delayed(Duration(milliseconds: 100));
expect(data, isNot(equals(await query.fetch())));
expect(query.refetchCount, 1);
},
); );
test( test(
"query should not revalidate When there's no Internet Connectivity and a new caller gets mounted", "query should not revalidate When there's no Internet Connectivity and a new caller gets mounted",
() {}, () async {
final connectivityMock = MockConnectivity();
when(connectivityMock.checkConnectivity()).thenAnswer(
(_) async => ConnectivityResult.none,
);
reset(queryJob);
when(queryJob.queryKey).thenReturn("test");
when(queryJob.task).thenAnswer(
(_) => (_, __) => Future.value(Random().nextInt(150)),
);
when(queryJob.connectivity).thenReturn(connectivityMock);
when(queryJob.refetchOnMount).thenReturn(true);
query = Query.fromOptions(
queryJob,
externalData: null,
queryBowl: queryBowl,
);
final data = await query.fetch();
query.invalidate();
query.mount(ValueKey<String>(uuid.v4()));
await Future.delayed(Duration(milliseconds: 100));
expect(data, equals(await query.fetch()));
expect(query.refetchCount, 0);
},
); );
}); });
} }
+30 -5
View File
@@ -4,13 +4,13 @@
import 'dart:async' as _i7; import 'dart:async' as _i7;
import 'package:connectivity_plus/connectivity_plus.dart' as _i10;
import 'package:fl_query/src/models/mutation_job.dart' as _i9; import 'package:fl_query/src/models/mutation_job.dart' as _i9;
import 'package:fl_query/src/models/query_job.dart' as _i8; import 'package:fl_query/src/models/query_job.dart' as _i8;
import 'package:fl_query/src/mutation.dart' as _i4; import 'package:fl_query/src/mutation.dart' as _i4;
import 'package:fl_query/src/query.dart' as _i3; import 'package:fl_query/src/query.dart' as _i3;
import 'package:fl_query/src/query_bowl.dart' as _i6; import 'package:fl_query/src/query_bowl.dart' as _i6;
import 'package:flutter/foundation.dart' as _i5; import 'package:flutter/foundation.dart' as _i5;
import 'package:flutter/rendering.dart' as _i10;
import 'package:flutter/widgets.dart' as _i2; import 'package:flutter/widgets.dart' as _i2;
import 'package:mockito/mockito.dart' as _i1; import 'package:mockito/mockito.dart' as _i1;
@@ -136,9 +136,9 @@ class MockQueryBowl extends _i1.Mock implements _i6.QueryBowl {
@override @override
_i4.Mutation<T, V> addMutation<T extends Object, V>( _i4.Mutation<T, V> addMutation<T extends Object, V>(
_i9.MutationJob<T, V>? mutationJob, _i9.MutationJob<T, V>? mutationJob,
{_i4.MutationListener<T>? onData, {_i4.MutationListener<T, V>? onData,
_i4.MutationListener<dynamic>? onError, _i4.MutationListener<dynamic, V>? onError,
_i4.MutationListener<V>? onMutate, _i4.MutationListenerReturnable<V, dynamic>? onMutate,
_i2.ValueKey<String>? key}) => _i2.ValueKey<String>? key}) =>
(super.noSuchMethod( (super.noSuchMethod(
Invocation.method(#addMutation, [ Invocation.method(#addMutation, [
@@ -190,7 +190,7 @@ class MockQueryBowl extends _i1.Mock implements _i6.QueryBowl {
.noSuchMethod(Invocation.method(#toStringShort, []), returnValue: '') .noSuchMethod(Invocation.method(#toStringShort, []), returnValue: '')
as String); as String);
@override @override
void debugFillProperties(_i10.DiagnosticPropertiesBuilder? properties) => void debugFillProperties(_i5.DiagnosticPropertiesBuilder? properties) =>
super.noSuchMethod(Invocation.method(#debugFillProperties, [properties]), super.noSuchMethod(Invocation.method(#debugFillProperties, [properties]),
returnValueForMissingStub: null); returnValueForMissingStub: null);
@override @override
@@ -229,6 +229,27 @@ class MockQueryBowl extends _i1.Mock implements _i6.QueryBowl {
super.toString(); super.toString();
} }
/// A class which mocks [Connectivity].
///
/// See the documentation for Mockito's code generation for more information.
class MockConnectivity extends _i1.Mock implements _i10.Connectivity {
MockConnectivity() {
_i1.throwOnMissingStub(this);
}
@override
_i7.Stream<_i10.ConnectivityResult> get onConnectivityChanged =>
(super.noSuchMethod(Invocation.getter(#onConnectivityChanged),
returnValue: Stream<_i10.ConnectivityResult>.empty())
as _i7.Stream<_i10.ConnectivityResult>);
@override
_i7.Future<_i10.ConnectivityResult> checkConnectivity() =>
(super.noSuchMethod(Invocation.method(#checkConnectivity, []),
returnValue: Future<_i10.ConnectivityResult>.value(
_i10.ConnectivityResult.bluetooth))
as _i7.Future<_i10.ConnectivityResult>);
}
/// A class which mocks [QueryJob]. /// A class which mocks [QueryJob].
/// ///
/// See the documentation for Mockito's code generation for more information. /// See the documentation for Mockito's code generation for more information.
@@ -271,6 +292,10 @@ class MockQueryJobVoidObject extends _i1.Mock
super.noSuchMethod(Invocation.setter(#refetchInterval, _refetchInterval), super.noSuchMethod(Invocation.setter(#refetchInterval, _refetchInterval),
returnValueForMissingStub: null); returnValueForMissingStub: null);
@override @override
set connectivity(_i10.Connectivity? _connectivity) =>
super.noSuchMethod(Invocation.setter(#connectivity, _connectivity),
returnValueForMissingStub: null);
@override
String get queryKey => String get queryKey =>
(super.noSuchMethod(Invocation.getter(#queryKey), returnValue: '') (super.noSuchMethod(Invocation.getter(#queryKey), returnValue: '')
as String); as String);
@@ -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.6/","native_build":true,"dependencies":[]}],"android":[{"name":"connectivity_plus","path":"/home/krtirtho/.pub-cache/hosted/pub.dartlang.org/connectivity_plus-2.3.6/","native_build":true,"dependencies":[]}],"macos":[{"name":"connectivity_plus_macos","path":"/home/krtirtho/.pub-cache/hosted/pub.dartlang.org/connectivity_plus_macos-1.2.4/","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":[]}],"windows":[{"name":"connectivity_plus_windows","path":"/home/krtirtho/.pub-cache/hosted/pub.dartlang.org/connectivity_plus_windows-1.2.2/","native_build":true,"dependencies":[]}],"web":[{"name":"connectivity_plus_web","path":"/home/krtirtho/.pub-cache/hosted/pub.dartlang.org/connectivity_plus_web-1.2.3/","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":[]}],"date_created":"2022-07-19 23:08:04.911997","version":"3.0.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.6/","native_build":true,"dependencies":[]}],"android":[{"name":"connectivity_plus","path":"/home/krtirtho/.pub-cache/hosted/pub.dartlang.org/connectivity_plus-2.3.6/","native_build":true,"dependencies":[]}],"macos":[{"name":"connectivity_plus_macos","path":"/home/krtirtho/.pub-cache/hosted/pub.dartlang.org/connectivity_plus_macos-1.2.4/","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":[]}],"windows":[{"name":"connectivity_plus_windows","path":"/home/krtirtho/.pub-cache/hosted/pub.dartlang.org/connectivity_plus_windows-1.2.2/","native_build":true,"dependencies":[]}],"web":[{"name":"connectivity_plus_web","path":"/home/krtirtho/.pub-cache/hosted/pub.dartlang.org/connectivity_plus_web-1.2.3/","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":[]}],"date_created":"2022-07-28 10:55:26.979398","version":"3.0.1"}
@@ -8,15 +8,15 @@ Mutation<T, V> useMutation<T extends Object, V>({
/// Called when the query returns new data, on query /// Called when the query returns new data, on query
/// refetch or query gets expired /// refetch or query gets expired
MutationListener<T>? onData, MutationListener<T, V>? onData,
/// Called when the query returns error /// Called when the query returns error
MutationListener<dynamic>? onError, MutationListener<dynamic, V>? onError,
/// called right before the mutation is about to run /// called right before the mutation is about to run
/// ///
/// perfect scenario for doing optimistic updates /// perfect scenario for doing optimistic updates
MutationListener<V>? onMutate, MutationListenerReturnable<V, dynamic>? onMutate,
List<Object?>? keys, List<Object?>? keys,
}) { }) {
final context = useContext(); final context = useContext();
@@ -37,9 +37,9 @@ Mutation<T, V> useMutation<T extends Object, V>({
final disposeMutation = useCallback(() { final disposeMutation = useCallback(() {
mutation.value.unmount(uKey); mutation.value.unmount(uKey);
if (onData != null) mutation.value.onDataListeners.remove(onData); if (onData != null) mutation.value.removeDataListener(onData);
if (onError != null) mutation.value.onErrorListeners.remove(onError); if (onError != null) mutation.value.removeErrorListener(onError);
if (onMutate != null) mutation.value.onMutateListeners.remove(onMutate); if (onMutate != null) mutation.value.removeMutateListener(onMutate);
}, [mutation.value, onData, onError, onMutate]); }, [mutation.value, onData, onError, onMutate]);
final oldJob = usePrevious(job); final oldJob = usePrevious(job);
@@ -58,16 +58,16 @@ Mutation<T, V> useMutation<T extends Object, V>({
init(); init();
} else { } else {
if (oldOnData != onData && oldOnData != null) { if (oldOnData != onData && oldOnData != null) {
mutation.value.onDataListeners.remove(oldOnData); mutation.value.removeDataListener(oldOnData);
if (onData != null) mutation.value.onDataListeners.add(onData); if (onData != null) mutation.value.addDataListener(onData);
} }
if (oldOnError != onError && oldOnError != null) { if (oldOnError != onError && oldOnError != null) {
mutation.value.onErrorListeners.remove(oldOnError); mutation.value.removeErrorListener(oldOnError);
if (onError != null) mutation.value.onErrorListeners.add(onError); if (onError != null) mutation.value.addErrorListener(onError);
} }
if (oldOnMutate != onMutate && oldOnMutate != null) { if (oldOnMutate != onMutate && oldOnMutate != null) {
mutation.value.onMutateListeners.remove(oldOnMutate); mutation.value.removeMutateListener(oldOnMutate);
if (onMutate != null) mutation.value.onMutateListeners.add(onMutate); if (onMutate != null) mutation.value.addMutateListener(onMutate);
} }
} }
return null; return null;
@@ -52,8 +52,8 @@ Query<T, Outside> useQuery<T extends Object, Outside>({
final disposeQuery = useCallback(() { final disposeQuery = useCallback(() {
query.value.unmount(uKey); query.value.unmount(uKey);
if (onData != null) query.value.onDataListeners.remove(onData); if (onData != null) query.value.removeDataListener(onData);
if (onError != null) query.value.onErrorListeners.remove(onError); if (onError != null) query.value.removeErrorListener(onError);
}, [query.value, onData, onError, uKey]); }, [query.value, onData, onError, uKey]);
useEffect(() { useEffect(() {
@@ -85,16 +85,16 @@ Query<T, Outside> useQuery<T extends Object, Outside>({
?.setExternalData(externalData); ?.setExternalData(externalData);
} }
if (hasOnDataChanged) query.value.onDataListeners.remove(oldOnData); if (hasOnDataChanged) query.value.removeDataListener(oldOnData);
if (hasOnErrorChanged) query.value.onErrorListeners.remove(oldOnError); if (hasOnErrorChanged) query.value.removeErrorListener(oldOnError);
} else { } else {
if (hasOnDataChanged) { if (hasOnDataChanged) {
query.value.onDataListeners.remove(oldOnData); query.value.removeDataListener(oldOnData);
if (onData != null) query.value.onDataListeners.add(onData); if (onData != null) query.value.addDataListener(onData);
} }
if (hasOnErrorChanged) { if (hasOnErrorChanged) {
query.value.onErrorListeners.remove(oldOnError); query.value.removeErrorListener(oldOnError);
if (onError != null) query.value.onErrorListeners.add(onError); if (onError != null) query.value.addErrorListener(onError);
} }
} }
return null; return null;