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:
@@ -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,
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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();
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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();
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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);
|
||||||
|
},
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
Reference in New Issue
Block a user