diff --git a/docs/docs/advanced/JobsAPI.mdx b/docs/docs/advanced/JobsAPI.mdx new file mode 100644 index 0000000..418669d --- /dev/null +++ b/docs/docs/advanced/JobsAPI.mdx @@ -0,0 +1,186 @@ +--- +title: Jobs API +sidebar_position: 1 +--- + +import Tabs from "@theme/Tabs"; +import TabItem from "@theme/TabItem"; + +All this time, we've been directly supplying `queryKey`, `queryFn` etc to `QueryBuilder` and so on. But this might looks repetetive or might break the rules of DRY (Don't Repeat Yourself). So to tackle this issue Fl-Query has an alternate API to create queries/infinite queries/mutations. + +Jobs are nothing but a collection of arguments of `*Builder`s. It is just a more declarative way to create queries/infinite queries/mutations. + +## Query Job + +A `QueryJob` consists of same arguments as `QueryBuilder` + +```dart +final job = QueryJob, dynamic, HttpApi>( + queryKey: "todos", + task: (api) => api.getTodos(), +); +``` + +You might notice the third type argument `HttpApi`. That's the new `ArgsType`. Because QueryJob is isolated from widget tree and outside APIs are not accessible from there, you've to manually pass anything you need to the `task` function. In this case, we need an instance of `HttpApi` to call `getTodos()`. + +### `QueryBuilder.withJob` and `useQueryJob` + +`QueryBuilder.withJob` is a static method that takes a `QueryJob` and returns a `QueryBuilder`. It also accepts event callbacks such as `onError` and `onData`. Also a special argument called `args` which is passed to the `task` function. + +Similarly, we have a `useQueryJob` if you're using `flutter_hooks` + + + + +```dart +QueryBuilder.withJob( + job: job, // QueryJob we created earlier + args: httpApi, + onError: (error) => print(error), + onData: (data) => print(data), + builder: /* ... */, +); +``` + + + + +```dart +useQueryJob( + job: job, // QueryJob we created earlier + args: httpApi, + onError: (error) => print(error), + onData: (data) => print(data), + builder: /* ... */, +); +``` + + + + +## InfiniteQuery Job + +Just like `QueryJob`, `InfiniteQueryJob` is the collection of arguments that is passed to `InfiniteQueryBuilder` or `useInfiniteQuery` + +```dart +final job = InfiniteQueryBuilder( + queryKey: "products", + task: (page, api) => api.getProductsPaginated(page), + nextPage: (lastPage, lastPageData) { + /// returning [null] will set [hasNextPage] to [false] + if (lastPageData.products.length < 10) return null; + return lastPage + 1; + }, + initialPage: 0, +); +``` + +### `InfiniteQueryBuilder.withJob` and `useInfiniteQueryJob` + +Just like `QueryBuilder.withJob`, `InfiniteQueryBuilder.withJob` is a static method that takes a `InfiniteQueryJob` and returns a `InfiniteQueryBuilder`. It also accepts event callbacks such as `onError` and `onData`. Also a special argument called `args` which is passed to the `task` function. + +Simiarly, we have a `useInfiniteQueryJob` if you're using `flutter_hooks` + + + + +```dart +InfiniteQueryBuilder.withJob( + job: job, // InfiniteQueryJob we created earlier + args: httpApi, + onError: (error) => print(error), + onData: (data) => print(data), + builder: /* ... */, +); +``` + + + + +```dart +useInfiniteQueryJob( + job: job, // InfiniteQueryJob we created earlier + args: httpApi, + onError: (error) => print(error), + onData: (data) => print(data), + builder: /* ... */, +); +``` + + + + + +## Mutation Job + +For mutations we've `MutationJob` it is similar to `QueryJob` but has `mutationKey` instead of `queryKey` + +```dart +final job = MutationJob( + mutationKey: "create-todo", + task: (variables, api) => api.createTodo(), +); +``` + +:::info +`MutationJob` has both `variables` and `args` which can be confusing. But use variables for passing data that are supposed to be sent, that means data that can change on next mutation. + +Use `args` for passing anything that is not supposed to change, like an API instance, authentication info or a config etc. +::: + +### `MutationBuilder.withJob` and `useMutationJob` + +Just like `QueryBuilder.withJob`, `MutationBuilder.withJob` is a static method that takes a `MutationJob` and returns a `MutationBuilder`. It also accepts event callbacks such as `onMutate`, `onError` and `onData`. Also a special argument called `args` which is passed to the `task` function. + +Simiarly, we have a `useMutationJob` if you're using `flutter_hooks` + + + + +```dart +MutationBuilder.withJob( + job: job, // MutationJob we created earlier + args: httpApi, + onError: (error) => print(error), + onData: (data) => print(data), + builder: /* ... */, +); +``` + + + + +```dart +useInfiniteQueryJob( + job: job, // MutationJob we created earlier + args: httpApi, + onError: (error) => print(error), + onData: (data) => print(data), + builder: /* ... */, +); +``` + + + + +## Dynamic Jobs + +Every job has `.withVariableKey` static that allows creating queries/mutations with changing data on the fly. It returns a function that accepts a variable key (String). Which will create a new instance of the job with the new variable key. + +Here's the example usage for `Query`: + +```dart +final job = QueryJob.withVariableKey, dynamic, HttpApi>( + baseQueryKey: "todos/", // the variable key will be appended to this + task: (variableKey, api) => api.getTodo(variableKey), +); + +// later in the widget tree +QueryBuilder.withJob( + job: job(todoId), + args: httpApi, + builder: /* ... */, +); +``` + +Everything is just as same as for `Mutation` and `InfiniteQuery`.. \ No newline at end of file diff --git a/docs/docs/advanced/OptimisticUpdates.mdx b/docs/docs/advanced/OptimisticUpdates.mdx index 90fef8e..7890f54 100644 --- a/docs/docs/advanced/OptimisticUpdates.mdx +++ b/docs/docs/advanced/OptimisticUpdates.mdx @@ -1,6 +1,6 @@ --- title: Optimistic Updates -sidebar_position: 1 +sidebar_position: 2 --- import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; diff --git a/docs/docs/advanced/PersistingQueries.mdx b/docs/docs/advanced/PersistingQueries.mdx index bfdf7e7..303b0a6 100644 --- a/docs/docs/advanced/PersistingQueries.mdx +++ b/docs/docs/advanced/PersistingQueries.mdx @@ -1,6 +1,6 @@ --- title: Persisting Queries -sidebar_position: 1 +sidebar_position: 3 --- import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; diff --git a/docs/docs/migrations/V1Migration.mdx b/docs/docs/migrations/V1Migration.mdx index e48f3ba..a1059fe 100644 --- a/docs/docs/migrations/V1Migration.mdx +++ b/docs/docs/migrations/V1Migration.mdx @@ -8,9 +8,6 @@ Fl-Query V1 comes with lot of breaking changes in the API. It is not possible to ## Removal of APIs/methods/properties -- `QueryJob`, `MutationJob` and `InfiniteQueryJob` all were removed to bring the API closer to React Query. The `externalData` param was found to be vulnerable and was causing memory leaks. Also the query itself should not react to external data changes automatically which caused massive performance drawbacks and circular dependency related issues. - - Now everything needs to be passed to `QueryBuilder`, `MutationBuilder` and `InfiniteQueryBuilder` or `useQuery`, `useMutation` and `useInfiniteQuery` hooks directly. - `keepPreviousData` has been removed from both `Query` and `InfiniteQuery` - `QueryClient`'s (formerly `QueryBowl`) - `prefetchQuery` method was removed @@ -51,6 +48,7 @@ Fl-Query V1 comes with lot of breaking changes in the API. It is not possible to - `QueryBowlProvider` was renamed to `QueryClientProvider` - `Query.refetch` was renamed to `Query.refresh` - `InfiniteQuery.refetchPages` has been replaced with `InfiniteQuery.refresh` and `InfiniteQuery.refreshAll` +- `externalData` was renamed to `args` for `QueryJob`, `InfiniteQueryJob` and `MutationJob` Now instead of passing callback, `Future.wait` is used with `refresh` to refetch a segment of pages. `refreshAll` is a shorthand to refetch all pages at once. @@ -62,6 +60,8 @@ Fl-Query V1 comes with lot of breaking changes in the API. It is not possible to All the retry & cache invalidation related properties were moved to their own classes. +- `QueryBuilder`, `InfiniteQueryBuilder` and `MutationBuilder` doesn't accept jobs by default. To use the old Jobs API, `.withJob` constructor must be used. +- Similarly, `useQuery`, `useInfiniteQuery`, `useMutation` doesn't accept jobs now. Use `useQueryJob`, `useInfiniteQueryJob` and `useMutationJob` instead. - Retry related properties were moved to `RetryConfig` class - `retries` was renamed to `maxRetries` - Cache invalidation related properties were moved to `RefreshConfig` class diff --git a/packages/fl_query/lib/src/collections/jobs/infinite_query_job.dart b/packages/fl_query/lib/src/collections/jobs/infinite_query_job.dart index 932df4e..15fec25 100644 --- a/packages/fl_query/lib/src/collections/jobs/infinite_query_job.dart +++ b/packages/fl_query/lib/src/collections/jobs/infinite_query_job.dart @@ -6,6 +6,13 @@ import 'package:fl_query/src/core/infinite_query.dart'; typedef InfiniteQueryJobFn = Future Function(PageType page, ArgsType args); +typedef InfiniteQueryJobVariableFn + = Future Function( + String variableKey, + PageType page, + ArgsType args, +); + typedef InfiniteQueryJobVariableKeyFn = InfiniteQueryJob Function( String variable); @@ -40,7 +47,7 @@ class InfiniteQueryJob { static InfiniteQueryJobVariableKeyFn withVariableKey({ required String baseQueryKey, - required InfiniteQueryJobFn task, + required InfiniteQueryJobVariableFn task, required final InfiniteQueryNextPage nextPage, required final PageType initialPage, RetryConfig? retryConfig, @@ -48,9 +55,9 @@ class InfiniteQueryJob { JsonConfig? jsonConfig, bool enabled = true, }) { - return (String variable) => InfiniteQueryJob( - queryKey: "$baseQueryKey$variable", - task: task, + return (String variableKey) => InfiniteQueryJob( + queryKey: "$baseQueryKey$variableKey", + task: (page, args) => task(variableKey, page, args), nextPage: nextPage, initialPage: initialPage, retryConfig: retryConfig, diff --git a/packages/fl_query/lib/src/collections/jobs/mutation_job.dart b/packages/fl_query/lib/src/collections/jobs/mutation_job.dart index 0f43621..a4e9d04 100644 --- a/packages/fl_query/lib/src/collections/jobs/mutation_job.dart +++ b/packages/fl_query/lib/src/collections/jobs/mutation_job.dart @@ -6,6 +6,13 @@ typedef MutationJobFn = Future ArgsType args, ); +typedef MutationJobVariableFn + = Future Function( + String variableKey, + VariablesType variables, + ArgsType args, +); + typedef MutationJobVariableKeyFn = MutationJob @@ -33,14 +40,14 @@ class MutationJob { withVariableKey({ required String baseMutationKey, - required MutationJobFn task, + required MutationJobVariableFn task, RetryConfig? retryConfig, List? refreshQueries, List? refreshInfiniteQueries, }) { - return (String variable) => MutationJob( - mutationKey: "$baseMutationKey$variable", - task: task, + return (String variableKey) => MutationJob( + mutationKey: "$baseMutationKey$variableKey", + task: (variables, args) => task(variableKey, variables, args), retryConfig: retryConfig, refreshQueries: refreshQueries, refreshInfiniteQueries: refreshInfiniteQueries, diff --git a/packages/fl_query/lib/src/collections/jobs/query_job.dart b/packages/fl_query/lib/src/collections/jobs/query_job.dart index d91e35d..8646489 100644 --- a/packages/fl_query/lib/src/collections/jobs/query_job.dart +++ b/packages/fl_query/lib/src/collections/jobs/query_job.dart @@ -4,6 +4,10 @@ import 'package:fl_query/src/collections/retry_config.dart'; typedef QueryJobFn = Future Function( ArgsType args); +typedef QueryJobVariableFn = Future Function( + String variableKey, + ArgsType args, +); typedef QueryJobVariableKeyFn = QueryJob Function(String variable); @@ -37,16 +41,16 @@ class QueryJob { static QueryJobVariableKeyFn withVariableKey({ required String baseQueryKey, - required QueryJobFn task, + required QueryJobVariableFn task, DataType? initial, RetryConfig? retryConfig, RefreshConfig? refreshConfig, JsonConfig? jsonConfig, bool enabled = true, }) { - return (String variable) => QueryJob( - queryKey: "$baseQueryKey$variable", - task: task, + return (String variableKey) => QueryJob( + queryKey: "$baseQueryKey$variableKey", + task: (args) => task(variableKey, args), initial: initial, retryConfig: retryConfig, refreshConfig: refreshConfig, diff --git a/packages/fl_query_hooks/lib/src/jobs/use_query_job.dart b/packages/fl_query_hooks/lib/src/jobs/use_query_job.dart index fc91377..2081e6c 100644 --- a/packages/fl_query_hooks/lib/src/jobs/use_query_job.dart +++ b/packages/fl_query_hooks/lib/src/jobs/use_query_job.dart @@ -4,9 +4,9 @@ import 'package:flutter/material.dart'; Query useQueryJob({ required QueryJob job, + required ArgsType args, ValueChanged? onData, ValueChanged? onError, - required ArgsType args, }) { return useQuery( job.queryKey,