feat: add initial support for InfiniteQuery

Added new infinite query class with it's own builder widget and integration with query_bowl
The `cast` method used in mutation and query are now a mixin instead of BasicOperation property
This commit is contained in:
Kingkor Roy Tirtho
2022-08-21 20:10:40 +06:00
parent 0c2eae1f11
commit 1452d7d79e
25 changed files with 563 additions and 32 deletions
@@ -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-08-07 10:53:50.758755","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-08-16 21:50:29.137318","version":"3.0.5"}
@@ -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-08-07 10:27:39.110033","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-08-21 19:29:44.415263","version":"3.0.5"}
@@ -1,2 +1,2 @@
sdk.dir=/opt/android-sdk
flutter.sdk=/opt/flutter
flutter.sdk=/home/krtirtho/fvm/versions/3.0.5
@@ -1,5 +1,5 @@
// This is a generated file; do not edit or check into version control.
FLUTTER_ROOT=/opt/flutter
FLUTTER_ROOT=/home/krtirtho/fvm/versions/3.0.5
FLUTTER_APPLICATION_PATH=/home/krtirtho/dev/fl-query/packages/fl_query/example
COCOAPODS_PARALLEL_CODE_SIGN=true
FLUTTER_TARGET=lib/main.dart
@@ -1,6 +1,6 @@
#!/bin/sh
# This is a generated file; do not edit or check into version control.
export "FLUTTER_ROOT=/opt/flutter"
export "FLUTTER_ROOT=/home/krtirtho/fvm/versions/3.0.5"
export "FLUTTER_APPLICATION_PATH=/home/krtirtho/dev/fl-query/packages/fl_query/example"
export "COCOAPODS_PARALLEL_CODE_SIGN=true"
export "FLUTTER_TARGET=lib/main.dart"
@@ -0,0 +1,62 @@
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart';
import 'package:fl_query/fl_query.dart';
import 'package:http/http.dart' as http;
final infiniteQueryJob = InfiniteQueryJob<Map, void, int>(
queryKey: "infinite-posts",
initialParam: 1,
task: (queryKey, pageParam, externalData) async {
return jsonDecode(
(await http.get(
Uri.parse("https://jsonplaceholder.typicode.com/posts/$pageParam"),
))
.body,
);
},
getNextPageParam: (lastPage, lastParam) {
return lastParam + 1;
},
getPreviousPageParam: (lastPage, lastParam) {
return lastParam - 1;
},
);
class BasicInfiniteQueryExample extends StatelessWidget {
const BasicInfiniteQueryExample({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(),
body: InfiniteQueryBuilder<Map, void, int>(
job: infiniteQueryJob,
externalData: null,
builder: (context, infiniteQuery) {
return Stack(
children: [
ListView.builder(
itemCount: infiniteQuery.pages.length,
itemBuilder: (context, index) {
final page = infiniteQuery.pages[index];
return ListTile(
title: Text(page?["title"] ?? ""),
subtitle: Text(page?["body"] ?? ""),
);
},
),
Align(
alignment: Alignment.bottomRight,
child: IconButton(
icon: const Icon(Icons.get_app_rounded),
onPressed: () => infiniteQuery.fetchNextPage(),
),
),
],
);
}),
);
}
}
+21 -9
View File
@@ -1,3 +1,4 @@
import 'package:fl_query_example/components/basic_infinite_query.dart';
import 'package:fl_query_example/components/basic_mutation.dart';
import 'package:fl_query_example/components/basic_query.dart';
import 'package:fl_query_example/components/lazy_query.dart';
@@ -49,15 +50,26 @@ class _MyHomePageState extends State<MyHomePage> with WidgetsBindingObserver {
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Column(
children: const [
BasicQueryExample(),
QueryExternalDataExample(),
LazyQueryExample(),
QueryVariableKeyExample(),
QueryPreviousDataExample(),
Divider(),
BasicMutationExample(),
MutationVariableKeyExample(),
children: [
const BasicQueryExample(),
const QueryExternalDataExample(),
const LazyQueryExample(),
const QueryVariableKeyExample(),
const QueryPreviousDataExample(),
ListTile(
title: const Text("Infinite Query Example"),
trailing: const Icon(Icons.open_in_new),
onTap: () {
Navigator.of(context).push(
MaterialPageRoute(
builder: (context) => const BasicInfiniteQueryExample(),
),
);
},
),
const Divider(),
const BasicMutationExample(),
const MutationVariableKeyExample(),
],
),
)),
@@ -1,10 +1,10 @@
# Generated code do not commit.
file(TO_CMAKE_PATH "/opt/flutter" FLUTTER_ROOT)
file(TO_CMAKE_PATH "/home/krtirtho/fvm/versions/3.0.5" FLUTTER_ROOT)
file(TO_CMAKE_PATH "/home/krtirtho/dev/fl-query/packages/fl_query/example" PROJECT_DIR)
# Environment variables to pass to tool_backend.sh
list(APPEND FLUTTER_TOOL_ENVIRONMENT
"FLUTTER_ROOT=/opt/flutter"
"FLUTTER_ROOT=/home/krtirtho/fvm/versions/3.0.5"
"PROJECT_DIR=/home/krtirtho/dev/fl-query/packages/fl_query/example"
"DART_DEFINES=RkxVVFRFUl9XRUJfQVVUT19ERVRFQ1Q9dHJ1ZQ=="
"DART_OBFUSCATION=false"
@@ -1,5 +1,5 @@
// This is a generated file; do not edit or check into version control.
FLUTTER_ROOT=/opt/flutter
FLUTTER_ROOT=/home/krtirtho/fvm/versions/3.0.5
FLUTTER_APPLICATION_PATH=/home/krtirtho/dev/fl-query/packages/fl_query/example
COCOAPODS_PARALLEL_CODE_SIGN=true
FLUTTER_BUILD_DIR=build
@@ -1,6 +1,6 @@
#!/bin/sh
# This is a generated file; do not edit or check into version control.
export "FLUTTER_ROOT=/opt/flutter"
export "FLUTTER_ROOT=/home/krtirtho/fvm/versions/3.0.5"
export "FLUTTER_APPLICATION_PATH=/home/krtirtho/dev/fl-query/packages/fl_query/example"
export "COCOAPODS_PARALLEL_CODE_SIGN=true"
export "FLUTTER_BUILD_DIR=build"
+16 -2
View File
@@ -133,7 +133,7 @@ packages:
path: ".."
relative: true
source: path
version: "0.1.0"
version: "0.2.0"
flutter:
dependency: "direct main"
description: flutter
@@ -170,6 +170,13 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "4.0.1"
infinite_scroll_pagination:
dependency: "direct main"
description:
name: infinite_scroll_pagination
url: "https://pub.dartlang.org"
source: hosted
version: "3.2.0"
js:
dependency: transitive
description:
@@ -238,6 +245,13 @@ packages:
description: flutter
source: sdk
version: "0.0.99"
sliver_tools:
dependency: transitive
description:
name: sliver_tools
url: "https://pub.dartlang.org"
source: hosted
version: "0.2.7"
source_span:
dependency: transitive
description:
@@ -310,4 +324,4 @@ packages:
version: "6.1.0"
sdks:
dart: ">=2.17.1 <3.0.0"
flutter: ">=1.20.0"
flutter: ">=1.22.0"
+1
View File
@@ -36,6 +36,7 @@ dependencies:
cupertino_icons: ^1.0.2
fl_query: ^0.2.0
http: ^0.13.5
infinite_scroll_pagination: ^3.2.0
dev_dependencies:
flutter_test:
+3
View File
@@ -1,10 +1,13 @@
library fl_query;
export 'src/infinite_query.dart';
export 'src/infinite_query_builder.dart';
export 'src/query.dart';
export 'src/query_bowl.dart';
export 'src/query_builder.dart';
export 'src/mutation.dart';
export 'src/mutation_builder.dart';
export 'src/models/infinite_query_job.dart';
export 'src/models/query_job.dart';
export 'src/models/mutation_job.dart';
export 'src/utils.dart' show isShallowEqual, getVariable;
@@ -0,0 +1,135 @@
import 'dart:async';
import 'package:fl_query/src/mixins/autocast.dart';
import 'package:fl_query/src/models/infinite_query_job.dart';
import 'package:flutter/widgets.dart';
typedef InfiniteQueryTaskFunction<T extends Object, Outside,
PageParam extends Object>
= FutureOr<T> Function(
String queryKey,
PageParam pageParam,
Outside externalData,
);
typedef InfiniteQueryPageParamFunction<T extends Object,
PageParam extends Object>
= FutureOr<PageParam> Function(T lastPage, PageParam lastParam);
class InfiniteQuery<T extends Object, Outside, PageParam extends Object>
with ChangeNotifier, AutoCast {
String queryKey;
Map<PageParam, T?> _data;
Map<PageParam, dynamic> _error;
InfiniteQueryTaskFunction<T, Outside, PageParam> task;
InfiniteQueryPageParamFunction<T, PageParam>? getNextPageParam;
InfiniteQueryPageParamFunction<T, PageParam>? getPreviousPageParam;
List<PageParam> get pageParams => _data.keys.toList();
List<dynamic> get errors => _error.values.toList();
List<T?> get pages => _data.values.toList();
PageParam currentParam;
Outside _externalData;
bool _hasNextPage = false;
bool _hasPreviousPage = false;
bool get hasNextPage => _hasNextPage;
bool get hasPreviousPage => _hasPreviousPage;
InfiniteQuery({
required this.queryKey,
required this.task,
required PageParam initialParam,
required Outside externalData,
this.getNextPageParam,
this.getPreviousPageParam,
T? initialPage,
}) : currentParam = initialParam,
_externalData = externalData,
_error = {},
_data = {
if (initialPage != null) initialParam: initialPage,
};
InfiniteQuery.fromOptions(
InfiniteQueryJob<T, Outside, PageParam> options, {
required Outside externalData,
}) : queryKey = options.queryKey,
task = options.task,
currentParam = options.initialParam,
_externalData = externalData,
_error = {},
getNextPageParam = options.getNextPageParam,
getPreviousPageParam = options.getPreviousPageParam,
_data = {
if (options.initialPage != null)
options.initialParam: options.initialPage,
};
Future<void> _execute() async {
final page = await task(
queryKey,
currentParam,
_externalData,
);
_data[currentParam] = page;
notifyListeners();
}
Future<List<T?>> fetch() async {
if (_data.isEmpty) await _execute();
return pages;
}
Future<T?> fetchNextPage([
InfiniteQueryPageParamFunction<T, PageParam>? getNextPageParam,
]) async {
try {
if (_data[currentParam] == null) await _execute();
final nextParam = await (getNextPageParam ?? this.getNextPageParam)?.call(
_data[currentParam]!,
currentParam,
);
if (nextParam == null) {
_hasNextPage = false;
notifyListeners();
return null;
}
_hasNextPage = true;
currentParam = nextParam;
return await _execute().then((_) => _data[currentParam]);
} catch (e) {
print("[InfiniteQuery.fetchNextPage]: $e");
rethrow;
}
}
Future<T?> fetchPreviousPage([
InfiniteQueryPageParamFunction<T, PageParam>? getPreviousPageParam,
]) async {
try {
if (_data[currentParam] == null) await _execute();
final prevParam =
await (getNextPageParam ?? this.getPreviousPageParam)?.call(
_data[currentParam]!,
currentParam,
);
if (prevParam == null) {
_hasPreviousPage = false;
notifyListeners();
return null;
}
_hasPreviousPage = true;
currentParam = prevParam;
return await _execute().then((_) => _data[currentParam]);
} catch (e) {
print("[InfiniteQuery.fetchPreviousPage]: $e");
rethrow;
}
}
}
@@ -0,0 +1,67 @@
import 'package:fl_query/src/infinite_query.dart';
import 'package:fl_query/src/models/infinite_query_job.dart';
import 'package:fl_query/src/query_bowl.dart';
import 'package:fl_query/src/utils.dart';
import 'package:flutter/widgets.dart';
class InfiniteQueryBuilder<T extends Object, Outside, PageParam extends Object>
extends StatefulWidget {
final Function(
BuildContext context,
InfiniteQuery<T, Outside, PageParam> query,
) builder;
final InfiniteQueryJob<T, Outside, PageParam> job;
final Outside externalData;
InfiniteQueryBuilder({
required this.job,
required this.builder,
required this.externalData,
Key? key,
}) : super(key: key);
@override
State<InfiniteQueryBuilder<T, Outside, PageParam>> createState() =>
_InfiniteQueryBuilderState<T, Outside, PageParam>();
}
class _InfiniteQueryBuilderState<T extends Object, Outside,
PageParam extends Object>
extends State<InfiniteQueryBuilder<T, Outside, PageParam>> {
InfiniteQuery<T, Outside, PageParam>? infiniteQuery;
late QueryBowl queryBowl;
late final ValueKey<String> uKey;
@override
void initState() {
super.initState();
uKey = ValueKey<String>(uuid.v4());
WidgetsBinding.instance.addPostFrameCallback((_) => init());
}
void init([T? previousData]) async {
final bowl = QueryBowl.of(context);
infiniteQuery = bowl.addInfiniteQuery<T, Outside, PageParam>(
widget.job,
externalData: widget.externalData,
key: uKey,
);
// final hasExternalDataChanged = infiniteQuery!.externalData != null &&
// infiniteQuery!.prevUsedExternalData != null &&
// !isShallowEqual(infiniteQuery!.externalData!, infiniteQuery!.prevUsedExternalData!);
// if (infiniteQuery!.fetched && hasExternalDataChanged) {
// await infiniteQuery!.refetch();
// } else if (!infiniteQuery!.fetched) {
await infiniteQuery!.fetch();
// }
}
@override
Widget build(BuildContext context) {
queryBowl = QueryBowl.of(context);
final latestInfiniteQuery = queryBowl
.getInfiniteQuery<T, Outside, PageParam>(widget.job.queryKey) ??
infiniteQuery;
if (latestInfiniteQuery == null) return Container();
return widget.builder(context, latestInfiniteQuery);
}
}
@@ -0,0 +1,3 @@
mixin AutoCast {
A? cast<A>() => this is A ? this as A : null;
}
@@ -0,0 +1,9 @@
class InfiniteQueryData<T extends Object> {
final Set<T> pages;
final Set<String> pageParams;
InfiniteQueryData({
required this.pages,
required this.pageParams,
});
}
@@ -0,0 +1,105 @@
import 'package:connectivity_plus/connectivity_plus.dart';
import 'package:fl_query/src/infinite_query.dart';
import 'package:flutter/widgets.dart';
class InfiniteQueryJob<T extends Object, Outside, PageParam extends Object> {
// all params
String _queryKey;
InfiniteQueryTaskFunction<T, Outside, PageParam> task;
final int? retries;
final Duration? retryDelay;
T? initialPage;
PageParam initialParam;
/// If set to false then the initial fetch will not be called & to
/// start the process the user has to call the refetch first
final bool? enabled;
// got from global options
final bool? refetchOnMount;
final bool? refetchOnReconnect;
final bool? refetchOnExternalDataChange;
final bool? keepPreviousData;
final Duration? staleTime;
final Duration? cacheTime;
final Duration? refetchInterval;
final Connectivity? connectivity;
final InfiniteQueryPageParamFunction<T, PageParam> getNextPageParam;
final InfiniteQueryPageParamFunction<T, PageParam> getPreviousPageParam;
@protected
bool isDynamic = false;
InfiniteQueryJob({
required String queryKey,
required this.task,
required this.initialParam,
required this.getNextPageParam,
required this.getPreviousPageParam,
this.retries,
this.retryDelay,
this.initialPage,
this.staleTime,
this.cacheTime,
this.enabled,
this.refetchInterval,
this.refetchOnMount,
this.refetchOnReconnect,
this.refetchOnExternalDataChange,
this.connectivity,
this.keepPreviousData,
}) : _queryKey = queryKey;
String get queryKey => _queryKey;
static InfiniteQueryJob<T, Outside, PageParam> Function(String queryKey)
withVariableKey<T extends Object, Outside, PageParam extends Object>({
required InfiniteQueryTaskFunction<T, Outside, PageParam> task,
required InfiniteQueryPageParamFunction<T, PageParam> getNextPageParam,
required InfiniteQueryPageParamFunction<T, PageParam> getPreviousPageParam,
required PageParam initialParam,
/// a extra key joined with queryKey by a '#'
///
/// useful for matching a group query
String? preQueryKey,
int? retries,
Duration? retryDelay,
T? initialPage,
Duration? staleTime,
Duration? cacheTime,
bool? enabled,
Duration? refetchInterval,
bool? refetchOnMount,
bool? refetchOnReconnect,
bool? refetchOnExternalDataChange,
Connectivity? connectivity,
bool? keepPreviousData,
}) {
return (String queryKey) {
if (preQueryKey != null) queryKey = "$preQueryKey#$queryKey";
final query = InfiniteQueryJob<T, Outside, PageParam>(
queryKey: queryKey,
task: task,
getNextPageParam: getNextPageParam,
getPreviousPageParam: getPreviousPageParam,
retries: retries,
retryDelay: retryDelay,
initialPage: initialPage,
staleTime: staleTime,
cacheTime: cacheTime,
enabled: enabled,
refetchInterval: refetchInterval,
refetchOnMount: refetchOnMount,
refetchOnReconnect: refetchOnReconnect,
refetchOnExternalDataChange: refetchOnExternalDataChange,
connectivity: connectivity,
keepPreviousData: keepPreviousData,
initialParam: initialParam,
);
query.isDynamic = true;
return query;
};
}
}
+2 -3
View File
@@ -2,6 +2,7 @@ import 'dart:async';
import 'package:fl_query/fl_query.dart';
import 'package:fl_query/src/base_operation.dart';
import 'package:fl_query/src/mixins/autocast.dart';
import 'package:fl_query/src/models/mutation_job.dart';
import 'package:flutter/widgets.dart';
@@ -23,7 +24,7 @@ typedef MutationListener<T, V> = FutureOr<void> Function(
typedef MutationTaskFunction<T, V> = FutureOr<T> Function(
String queryKey, V variables);
class Mutation<T extends Object, V> extends BaseOperation<T> {
class Mutation<T extends Object, V> extends BaseOperation<T> with AutoCast {
// all params
final String mutationKey;
MutationTaskFunction<T, V> task;
@@ -201,8 +202,6 @@ class Mutation<T extends Object, V> extends BaseOperation<T> {
_sideEffectContext = null;
}
A? cast<A>() => this is A ? this as A : null;
bool get isError => status == MutationStatus.error;
bool get isIdle => status == MutationStatus.idle;
bool get isLoading => status == MutationStatus.loading;
+3 -4
View File
@@ -2,6 +2,7 @@ import 'dart:async';
import 'package:connectivity_plus/connectivity_plus.dart';
import 'package:fl_query/src/base_operation.dart';
import 'package:fl_query/src/mixins/autocast.dart';
import 'package:fl_query/src/models/query_job.dart';
import 'package:fl_query/src/utils.dart';
import 'package:flutter/widgets.dart';
@@ -36,7 +37,7 @@ typedef ListenerUnsubscriber = void Function();
typedef QueryUpdateFunction<T> = FutureOr<T> Function(T? oldData);
class Query<T extends Object, Outside> extends BaseOperation<T> {
class Query<T extends Object, Outside> extends BaseOperation<T> with AutoCast {
// all params
final String queryKey;
QueryTaskFunction<T, Outside> task;
@@ -234,7 +235,7 @@ class Query<T extends Object, Outside> extends BaseOperation<T> {
/// and will only return the available data
///
/// If a [fetch] is already running in the background it'll just return
/// the current available [data] (which can be nul if no [initialData]
/// the current available [data] (which can be nul if no [initialPage]
/// was provided) instead of running the task to prevent race conditions
Future<T?> fetch() async {
if (!enabled) return null;
@@ -391,8 +392,6 @@ class Query<T extends Object, Outside> extends BaseOperation<T> {
return _previousData != null ? _previousData == data : false;
}
A? cast<A>() => this is A ? this as A : null;
String get debugLabel => "Query($queryKey)";
@override
+123 -1
View File
@@ -1,6 +1,8 @@
import 'dart:async';
import 'package:connectivity_plus/connectivity_plus.dart';
import 'package:fl_query/src/infinite_query.dart';
import 'package:fl_query/src/models/infinite_query_job.dart';
import 'package:fl_query/src/models/mutation_job.dart';
import 'package:fl_query/src/models/query_job.dart';
import 'package:fl_query/src/mutation.dart';
@@ -90,6 +92,7 @@ class QueryBowlScope extends StatefulWidget {
}
class _QueryBowlScopeState extends State<QueryBowlScope> {
late Set<InfiniteQuery> infiniteQueries;
late Set<Query> queries;
late Set<Mutation> mutations;
@@ -98,6 +101,7 @@ class _QueryBowlScopeState extends State<QueryBowlScope> {
@override
void initState() {
super.initState();
infiniteQueries = {};
queries = {};
mutations = {};
@@ -122,6 +126,9 @@ class _QueryBowlScopeState extends State<QueryBowlScope> {
}
void _listenToUpdates() {
for (final infiniteQuery in infiniteQueries) {
infiniteQuery.addListener(() => updateInfiniteQueries(infiniteQuery));
}
for (final query in queries) {
query.addListener(() => updateQueries(query));
}
@@ -131,6 +138,9 @@ class _QueryBowlScopeState extends State<QueryBowlScope> {
}
void _disposeUpdateListeners() {
for (final infiniteQuery in infiniteQueries) {
infiniteQuery.removeListener(() => updateInfiniteQueries(infiniteQuery));
}
for (final query in queries) {
query.removeListener(() => updateQueries(query));
}
@@ -153,6 +163,21 @@ class _QueryBowlScopeState extends State<QueryBowlScope> {
});
}
void updateInfiniteQueries(InfiniteQuery infiniteQuery) {
WidgetsBinding.instance.addPostFrameCallback((_) {
// checking & not including inactive queries
// basically garbage collecting queries
setState(() {
infiniteQueries = Set.from(
// infiniteQuery.isInactive
// ? infiniteQueries.where((el) => el.queryKey != infiniteQuery.queryKey)
// : infiniteQuery,
infiniteQueries,
);
});
});
}
void updateMutations(Mutation mutation) {
WidgetsBinding.instance.addPostFrameCallback((_) {
setState(() {
@@ -169,6 +194,15 @@ class _QueryBowlScopeState extends State<QueryBowlScope> {
});
}
void addInfiniteQuery<T extends Object, Outside, PageParam extends Object>(
InfiniteQuery<T, Outside, PageParam> infiniteQuery) {
WidgetsBinding.instance.addPostFrameCallback((_) {
setState(() {
infiniteQueries = Set.from({...infiniteQueries, infiniteQuery});
});
});
}
void addQuery<T extends Object, Outside>(Query<T, Outside> query) {
WidgetsBinding.instance.addPostFrameCallback((_) {
setState(() {
@@ -215,10 +249,12 @@ class _QueryBowlScopeState extends State<QueryBowlScope> {
_disposeUpdateListeners();
_listenToUpdates();
return QueryBowl(
addInfiniteQuery: addInfiniteQuery,
addQuery: addQuery,
addMutation: addMutation,
removeQueries: removeQueries,
clear: clear,
infiniteQueries: infiniteQueries,
queries: queries,
mutations: mutations,
staleTime: widget.staleTime,
@@ -238,6 +274,7 @@ class _QueryBowlScopeState extends State<QueryBowlScope> {
/// Its responsible or can be used for (not recommended) creating,
/// updating & deleting queries & mutations
class QueryBowl extends InheritedWidget {
final Set<InfiniteQuery> _infiniteQueries;
final Set<Query> _queries;
final Set<Mutation> _mutations;
final Duration staleTime;
@@ -248,6 +285,9 @@ class QueryBowl extends InheritedWidget {
final bool refetchOnReconnect;
final bool refetchOnExternalDataChange;
final void Function<T extends Object, Outside, PageParam extends Object>(
InfiniteQuery<T, Outside, PageParam> infiniteQuery) _addInfiniteQuery;
final void Function<T extends Object, Outside>(Query<T, Outside> query)
_addQuery;
@@ -260,11 +300,16 @@ class QueryBowl extends InheritedWidget {
const QueryBowl({
required Widget child,
required final void Function<T extends Object, Outside,
PageParam extends Object>(
InfiniteQuery<T, Outside, PageParam> infiniteQuery)
addInfiniteQuery,
required final void Function<T extends Object, Outside>(
Query<T, Outside> query)
addQuery,
required final void Function<T extends Object, V>(Mutation<T, V> mutation)
addMutation,
required final Set<InfiniteQuery> infiniteQueries,
required final Set<Query> queries,
required final Set<Mutation> mutations,
required this.staleTime,
@@ -280,6 +325,8 @@ class QueryBowl extends InheritedWidget {
_queries = queries,
_mutations = mutations,
_addMutation = addMutation,
_addInfiniteQuery = addInfiniteQuery,
_infiniteQueries = infiniteQueries,
super(child: child, key: key);
Query<T, Outside> _createQueryWithDefaults<T extends Object, Outside>(
@@ -303,6 +350,26 @@ class QueryBowl extends InheritedWidget {
return query;
}
// InfiniteQuery<T, Outside, PageParam> _createInfiniteQueryWithDefaults<
// T extends Object, Outside, PageParam extends Object>(
// InfiniteQueryJob<T, Outside, PageParam> options,
// Outside externalData,
// ) {
// final query = InfiniteQuery<T, Outside, PageParam>.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,
@@ -355,6 +422,50 @@ class QueryBowl extends InheritedWidget {
return await query.fetch();
}
@protected
InfiniteQuery<T, Outside, PageParam>
addInfiniteQuery<T extends Object, Outside, PageParam extends Object>(
InfiniteQueryJob<T, Outside, PageParam> infiniteQueryJob, {
required Outside externalData,
required ValueKey<String> key,
final QueryListener<T>? onData,
final QueryListener<dynamic>? onError,
}) {
final prevInfiniteQuery = _infiniteQueries.firstWhereOrNull(
(q) => q.queryKey == infiniteQueryJob.queryKey,
);
if (prevInfiniteQuery is InfiniteQuery<T, Outside, PageParam>) {
// run the query if its still not called or if externalData has
// changed
// if (prevQuery.prevUsedExternalData != null &&
// externalData != null &&
// !isShallowEqual(
// prevQuery.prevUsedExternalData!,
// externalData,
// )) {
// prevQuery.setExternalData(externalData);
// }
// prevQuery.mount(key);
// if (onData != null) prevQuery.addDataListener(onData);
// if (onError != null) prevQuery.addErrorListener(onError);
// mounting the widget that is using the query in the prevQuery
return prevInfiniteQuery;
}
// _createQueryWithDefaults<T, Outside, PageParam>(
// infiniteQueryJob,
// externalData,
// );
final infiniteQuery = InfiniteQuery<T, Outside, PageParam>.fromOptions(
infiniteQueryJob,
externalData: externalData,
);
// if (onData != null) infiniteQuery.addDataListener(onData);
// if (onError != null) infiniteQuery.addErrorListener(onError);
// infiniteQuery.mount(key);
_addInfiniteQuery<T, Outside, PageParam>(infiniteQuery);
return infiniteQuery;
}
/// !⚠️**Warning** only for internal library usage
@protected
Query<T, Outside> addQuery<T extends Object, Outside>(
@@ -428,6 +539,16 @@ class QueryBowl extends InheritedWidget {
}
}
InfiniteQuery<T, Outside, PageParam>?
getInfiniteQuery<T extends Object, Outside, PageParam extends Object>(
String queryKey,
) {
return _infiniteQueries.firstWhereOrNull((infiniteQuery) {
return infiniteQuery.queryKey == queryKey &&
infiniteQuery is InfiniteQuery<T, Outside, PageParam>;
})?.cast<InfiniteQuery<T, Outside, PageParam>>();
}
/// Get a query by providing queryKey only
///
/// Useful for optimistic update or single query refetch
@@ -519,6 +640,7 @@ class QueryBowl extends InheritedWidget {
bool updateShouldNotify(QueryBowl oldWidget) {
return oldWidget.staleTime != staleTime ||
oldWidget._queries != _queries ||
oldWidget._mutations != _mutations;
oldWidget._mutations != _mutations ||
oldWidget._infiniteQueries != _infiniteQueries;
}
}
@@ -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-08-04 09:09:33.749791","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-08-16 21:50:27.976582","version":"3.0.5"}
@@ -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-08-07 10:52:09.828374","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-08-16 21:50:30.683860","version":"3.0.5"}
+2 -2
View File
@@ -133,14 +133,14 @@ packages:
path: "../../fl_query"
relative: true
source: path
version: "0.1.0"
version: "0.2.0"
fl_query_hooks:
dependency: "direct main"
description:
path: ".."
relative: true
source: path
version: "0.1.0"
version: "0.2.0"
flutter:
dependency: "direct main"
description: flutter