From 742b890cbbae44ab9c470e083447576808af3953 Mon Sep 17 00:00:00 2001 From: Tim Shedor Date: Sat, 5 Oct 2024 14:28:24 -0700 Subject: [PATCH] doc: clean up doc links --- docs/_sidebar.md | 3 +- docs/data/query.md | 46 +++++++++---------- docs/graphql/fields.md | 8 ++-- docs/graphql/query.md | 13 +++--- docs/home.md | 3 +- .../offline_first_with_graphql_repository.md | 2 - docs/offline_first/policies.md | 41 +++++++++++++++++ .../lib/brick/models/customer.model.dart | 5 +- 8 files changed, 78 insertions(+), 43 deletions(-) create mode 100644 docs/offline_first/policies.md diff --git a/docs/_sidebar.md b/docs/_sidebar.md index 58328069..ffb5c7f5 100644 --- a/docs/_sidebar.md +++ b/docs/_sidebar.md @@ -8,7 +8,7 @@ - [Fetching data](data/query.md) - [Providers](data/providers.md) - [Repositories](data/repositories.md) -- [Supabase](supabase/repository.md) +- [Supabase](supabase/fields.md) - [Model Config](supabase/models.md) - [Field Config](supabase/fields.md) - [Querying](supabase/query.md) @@ -29,6 +29,7 @@ - [Offline First](offline_first/fields.md) - [Model Config](offline_first/models.md) - [Field Config](offline_first/fields.md) + - [Policies](offline_first/policies.md) - [Testing](offline_first/testing.md) - [With Supabase](offline_first/offline_first_with_supabase_repository.md) - [With GraphQL](offline_first/offline_first_with_graphql_repository.md) diff --git a/docs/data/query.md b/docs/data/query.md index 2c27e1a7..56eeb8ea 100644 --- a/docs/data/query.md +++ b/docs/data/query.md @@ -19,19 +19,19 @@ Query.where('lastName', 'Mustermann') // note this is lastName and not name or l Querying can be done with `Where` or `WherePhrase`: -1) `WherePhrase` is a collection of `Where` statements. -2) `WherePhrase` can't contain mixed `required:` because this will output invalid SQL. For example, when it's mixed: `WHERE id = 2 AND name = 'Thomas' OR name = 'Guy'`. The OR needs to be its own phrase: `WHERE (id = 2 AND name = 'Thomas') OR (name = 'Guy')`. -3) `WherePhrase` can be intermixed with `Where`. - ```dart - [ - Where('id').isExactly(2), - WherePhrase([ - Or('name').isExactly('Guy'), - Or('name').isExactly('Thomas') - ], required: false) - ] - // => (id == 2) || (name == 'Thomas' || name == 'Guy') - ``` +1. `WherePhrase` is a collection of `Where` statements. +2. `WherePhrase` can't contain mixed `required:` because this will output invalid SQL. For example, when it's mixed: `WHERE id = 2 AND name = 'Thomas' OR name = 'Guy'`. The OR needs to be its own phrase: `WHERE (id = 2 AND name = 'Thomas') OR (name = 'Guy')`. +3. `WherePhrase` can be intermixed with `Where`. + ```dart + [ + Where('id').isExactly(2), + WherePhrase([ + Or('name').isExactly('Guy'), + Or('name').isExactly('Thomas') + ], required: false) + ] + // => (id == 2) || (name == 'Thomas' || name == 'Guy') + ``` !> Queried enum values should map to a primitive. Plainly, **always include `.index`**: `Where('type').isExactly(MyEnumType.value.index)`. @@ -57,15 +57,15 @@ Fields can be compared to their values beyond an exact match (the default). Where('name', value: 'Thomas', compare: Compare.contains); ``` -* `between` -* `contains` -* `doesNotContain` -* `exact` -* `greaterThan` -* `greaterThanOrEqualTo` -* `lessThan` -* `lessThanOrEqualTo` -* `notEqual` +- `between` +- `contains` +- `doesNotContain` +- `exact` +- `greaterThan` +- `greaterThanOrEqualTo` +- `lessThan` +- `lessThanOrEqualTo` +- `notEqual` Please note that the provider is ultimately responsible for supporting `Where` queries. @@ -97,7 +97,7 @@ Query(where: [ // => (name == 'Thomas' || age != 42) && (height > 182 && height < 186 && country == 'France') ``` -?> If expanded `WherePhrase`s become unlegible, helpers `And` and `Or` can be used: +?> If expanded `WherePhrase`s become illegible, helpers `And` and `Or` can be used: ```dart Query(where: [ diff --git a/docs/graphql/fields.md b/docs/graphql/fields.md index 90e7f652..59c3ed19 100644 --- a/docs/graphql/fields.md +++ b/docs/graphql/fields.md @@ -1,5 +1,3 @@ -?> The GraphQL domain is currently in Alpha. APIs are subject to change. - # Field Configuration ## Annotations @@ -11,7 +9,7 @@ Brick by default assumes enums from a GraphQL API will be delivered as integers Given the API: ```json -{ "user": { "hats": [ "bowler", "birthday" ] } } +{ "user": { "hats": ["bowler", "birthday"] } } ``` Simply convert `hats` into a Dart enum: @@ -80,5 +78,5 @@ query { The following are not serialized to GraphQL. However, unsupported types can still be accessed in the model as non-final fields. -* Nested `List<>` e.g. `>>` -* Many-to-many associations +- Nested `List<>` e.g. `>>` +- Many-to-many associations diff --git a/docs/graphql/query.md b/docs/graphql/query.md index 5c82d04c..c8de0aa3 100644 --- a/docs/graphql/query.md +++ b/docs/graphql/query.md @@ -1,13 +1,11 @@ -?> The GraphQL domain is currently in Alpha. APIs are subject to change. - # `Query` Configuration ## `providerArgs:` -| Name | Type | Description | -|---|---|---| -| `'operation'` | `GraphqlOperation` | apply this operation instead of one of the defaults from `graphqlOperationTransformer`. The document subfields **will not** be populated by the model. | -| `'context'` | `Map` | apply this as the context to the request instead of an empty object. Useful for subsequent consumers/`Link`s of the request. The key should be the runtime type of the `ContextEntry`. | +| Name | Type | Description | +| ------------- | --------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `'operation'` | `GraphqlOperation` | apply this operation instead of one of the defaults from `graphqlOperationTransformer`. The document subfields **will not** be populated by the model. | +| `'context'` | `Map` | apply this as the context to the request instead of an empty object. Useful for subsequent consumers/`Link`s of the request. The key should be the runtime type of the `ContextEntry`. | #### `variablesNamespace` @@ -47,4 +45,5 @@ final variables = { !> Association values within `Where` **are not** converted to variables !> Multiple `where` keys (`OfflineFirst(where: {'id': 'data["id"]', 'otherVar': 'data["otherVar"]'})`) or nested properties (`OfflineFirst(where: {'id': 'data["subfield"]["id"]})`) will not generate. -* `@OfflineFirst(where:` only supports extremely simple renames. Multiple `where` keys (`OfflineFirst(where: {'id': 'data["id"]', 'otherVar': 'data["otherVar"]'})`) or nested properties (`OfflineFirst(where: {'id': 'data["subfield"]["id"]})`) will be ignored. Be sure to use `@Graphql(name:)` to rename the generated document field. + +- `@OfflineFirst(where:` only supports extremely simple renames. Multiple `where` keys (`OfflineFirst(where: {'id': 'data["id"]', 'otherVar': 'data["otherVar"]'})`) or nested properties (`OfflineFirst(where: {'id': 'data["subfield"]["id"]})`) will be ignored. Be sure to use `@Graphql(name:)` to rename the generated document field. diff --git a/docs/home.md b/docs/home.md index 46b0e514..b3173f32 100644 --- a/docs/home.md +++ b/docs/home.md @@ -61,10 +61,11 @@ ## Learn -- Video: [Brick Architecture](https://www.youtube.com/watch?v=2noLcro9iIw). An explanation of Brick parlance with a supplemental analogy. +- Video: [Brick Architecture](https://www.youtube.com/watch?v=2noLcro9iIw). An explanation of Brick parlance with a [supplemental analogy](https://medium.com/flutter-community/brick-your-app-five-compelling-reasons-and-a-pizza-analogy-to-make-your-data-accessible-8d802e1e526e). - Video: [Brick Basics](https://www.youtube.com/watch?v=jm5i7e_BQq0). An overview of essential Brick mechanics. - Example: [Simple Associations using the OfflineFirstWithGraphql domain](https://github.com/GetDutchie/brick/blob/main/example_graphql) - Example: [Simple Associations using the OfflineFirstWithRest domain](https://github.com/GetDutchie/brick/blob/main/example) +- Example: [Simple Associations using the OfflineFirstWithSupabase domain](https://github.com/GetDutchie/brick/blob/main/example_supabase) - Tutorial: [Setting up a simple app with Brick](http://www.flutterbyexample.com/#/posts/2_adding_a_repository) ## Glossary diff --git a/docs/offline_first/offline_first_with_graphql_repository.md b/docs/offline_first/offline_first_with_graphql_repository.md index 1742d31a..3b31104a 100644 --- a/docs/offline_first/offline_first_with_graphql_repository.md +++ b/docs/offline_first/offline_first_with_graphql_repository.md @@ -1,5 +1,3 @@ -?> The GraphQL domain is currently in Alpha. APIs are subject to change. - # Offline First With GraphQL Repository `OfflineFirstWithGraphqlRepository` streamlines the GraphQL integration with an `OfflineFirstRepository`. A serial queue is included to track GraphQL mutations in a separate SQLite database, only removing requests when a response is returned from the host (i.e. the device has lost internet connectivity). diff --git a/docs/offline_first/policies.md b/docs/offline_first/policies.md new file mode 100644 index 00000000..cb729d65 --- /dev/null +++ b/docs/offline_first/policies.md @@ -0,0 +1,41 @@ +# Offline First Policies + +Repository methods can be invoked with policies to prioritize data sources. For example, a request may need to skip the offline queue or the response must come from a remote source. It is strongly encouraged to use a policy (e.g. `Repository().get(policy: .requireRemote))`) instead of directly accessing a provider (e.g. `Repository().restPovider.get()`) + +## OfflineFirstDeletePolicy + +### `optimisticLocal` + +Delete local results before waiting for the remote provider to respond + +### `requireRemote` + +Delete local results after remote responds; local results are not deleted if remote responds with any exception + +## OfflineFirstGetPolicy + +### `alwaysHydrate` + +Ensures data is fetched from the remote provider(s) at each invocation. This hydration is unawaited and is not guaranteed to complete before results are returned. This can be expensive to perform for some queries; see [`awaitRemoteWhenNoneExist`](#awaitremotewhennoneexist) for a more performant option or [`awaitRemote`](#awaitremote) to await the hydration before returning results. + +### `awaitRemote` + +Ensures results must be updated from the remote proivder(s) before returning if the app is online. An empty array will be returned if the app is offline. + +### `awaitRemoteWhenNoneExist` + +Retrieves from the remote provider(s) if the query returns no results from the local provider(s). + +### `localOnly` + +Do not request from the remote provider(s) + +## OfflineFirstUpsertPolicy + +### `optimisticLocal` + +Save results to local before waiting for the remote provider to respond + +### `requireRemote` + +Save results to local after remote responds; local results are not saved if remote responds with any exception diff --git a/example_supabase/lib/brick/models/customer.model.dart b/example_supabase/lib/brick/models/customer.model.dart index aa659e7d..433d28bc 100644 --- a/example_supabase/lib/brick/models/customer.model.dart +++ b/example_supabase/lib/brick/models/customer.model.dart @@ -1,10 +1,7 @@ import 'package:brick_offline_first_with_supabase/brick_offline_first_with_supabase.dart'; import 'package:brick_sqlite/brick_sqlite.dart'; -import 'package:brick_supabase/brick_supabase.dart'; -@ConnectOfflineFirstWithSupabase( - supabaseConfig: SupabaseSerializable(), -) +@ConnectOfflineFirstWithSupabase() class Customer extends OfflineFirstWithSupabaseModel { @Sqlite(unique: true) final String id;