Skip to content

Commit

Permalink
doc(supabase): improve legibility (#453)
Browse files Browse the repository at this point in the history
  • Loading branch information
tshedor authored Oct 8, 2024
1 parent 7f94425 commit a34494d
Show file tree
Hide file tree
Showing 9 changed files with 77 additions and 64 deletions.
54 changes: 27 additions & 27 deletions docs/data/fields.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,14 @@ All `final` fields of a model, unless specified, will be (de)serialized by the p

As providers are ultimately responsible for converting raw data into model data, a description of fields on models is overly generic. Field-level annotations always override class-level annotations/configuration. However, providers should adhere to some standards of annotations:

| Named Arg | Description | Example |
|---|---|---|
| `ignore:` | Do not deserialize (from) or serialize (to) this field to a provider | `@Rest(ignore: true)` |
| `name:` | Stored key for this field according to the provider. In SQLite, for example, this would be the column name. | `@Sqlite(name: "address_2")` |
| `defaultValue:` | Value to use in absence or `null` of the instance. It does not dictate what the Dart model will hold on empty instantiation. **Recommended to use Dart's default constructor assignment instead**. | `@Rest(defaultValue: '[]')` |
| `nullable:` | `null` fields are handled gracefully when serializing and deserializing. | `@Rest(nullable: true)` |
| Named Arg | Description | Example |
| --------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------ |
| `ignore:` | Do not deserialize (from) or serialize (to) this field to a provider | `@Rest(ignore: true)` |
| `name:` | Stored key for this field according to the provider. In SQLite, for example, this would be the column name. | `@Sqlite(name: "address_2")` |
| `defaultValue:` | Value to use in absence or `null` of the instance. It does not dictate what the Dart model will hold on empty instantiation. **Recommended to use Dart's default constructor assignment instead**. | `@Rest(defaultValue: '[]')` |
| `nullable:` | `null` fields are handled gracefully when serializing and deserializing. | `@Rest(nullable: true)` |
| `fromGenerator` | A stringified function with access to [placeholders](#placeholders); replaces adapter's generated deserialize code for the field. Do not include trailing semicolons or function body wrapping symbols (`{}` or `=>`) in the definition. | `@Rest(fromGenerator: "int.tryParse(%DATA_PROPERTY%.toString())")` |
| `toGenerator` | A stringified function with access to [placeholders](#placeholders); replaces adapter's generated serialize code for the field. Do not include trailing semicolons or function body wrapping symbols (`{}` or `=>`) in the definition. | `@Sqlite(toGenerator: "%INSTANCE_PROPERTY% > 1 ? 1 : 0")` |
| `toGenerator` | A stringified function with access to [placeholders](#placeholders); replaces adapter's generated serialize code for the field. Do not include trailing semicolons or function body wrapping symbols (`{}` or `=>`) in the definition. | `@Sqlite(toGenerator: "%INSTANCE_PROPERTY% > 1 ? 1 : 0")` |

## Custom Generators

Expand Down Expand Up @@ -48,7 +48,7 @@ final data = {

To replace a few parts and DRY up code in custom, field-level generators, placeholders can be employed and replaced with values at build time.

All custom generators passed through field annotations (such as `@Rest(fromGenerator:)` or `@Sqlite(toGenerator:)`) have access to predefined placeholders and custom placeholders.
All custom generators passed through field annotations (such as `@Rest(fromGenerator:)` or `@Sqlite(toGenerator:)`) have access to predefined placeholders and custom placeholders.

To declare your own variables, wrap the variable name like a tag using `@`: `@VARIABLE_NAME@value@/VARIABLE_NAME@`. Placeholders and their values **must** conform to the RegEx `[\w\d]+`.

Expand All @@ -69,27 +69,27 @@ final customGenerator = """(%DATA_PROPERTY% as Map<String, dynamic>).map((key, v

There are several globally-defined placeholders:

* `%ANNOTATED_NAME%` - key name.
```dart
@Rest(name: 'my_field')
final String myField
// => 'my_field'
```
* `%DATA_PROPERTY%` - deserializing key name (`@Rest(name:)` or `@Sqlite(name:)` or the default) wrapped in the deserialized map. **Only use in `fromGenerator`**.
```dart
@Rest(name: 'my_field')
final String myField
// => data['my_field']
```
* `%INSTANCE_PROPERTY%` - serializing property. **Only use in `toGenerator`**.
```dart
@Rest(name: 'my_field')
final String myField
// => instance.myField
```
- `%ANNOTATED_NAME%` - key name.
```dart
@Rest(name: 'my_field')
final String myField
// => 'my_field'
```
- `%DATA_PROPERTY%` - deserializing key name (`@Rest(name:)` or `@Sqlite(name:)` or the default) wrapped in the deserialized map. **Only use in `fromGenerator`**.
```dart
@Rest(name: 'my_field')
final String myField
// => data['my_field']
```
- `%INSTANCE_PROPERTY%` - serializing property. **Only use in `toGenerator`**.
```dart
@Rest(name: 'my_field')
final String myField
// => instance.myField
```

## FAQ

### Why are annotations AND extensions required?
### Why are annotations AND `extends` required?

The annotation is required to build the generated files (adapters, migrations, etc.). The type extension (e.g. `OfflineFirstModel`) is used by the repository's type system.
5 changes: 2 additions & 3 deletions docs/graphql/fields.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,8 @@ final List<Hat> hats;
GraphQL keys can be renamed per field. This will override the default set by `GraphqlSerializable#fieldRename`.

```dart
@Graphql(
name: "full_name" // "full_name" is used in ***fromGraphql*** and ***toGraphql*** requests instead of "last_name"
)
// "full_name" is used in ***fromGraphql*** and ***toGraphql*** requests instead of "last_name"
@Graphql(name: "full_name")
final String lastName;
```

Expand Down
20 changes: 19 additions & 1 deletion docs/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,10 @@
<style type="text/css">
:root {
--theme-color: #9A3536;
--code-inline-color: #9A3536;
--cover-background-color: #fff;
--code-font-size: 0.9rem;
--code-inline-background: #f8f8f8;
}

.cover {
Expand Down Expand Up @@ -43,7 +47,7 @@
}

.markdown-section h3 {
margin: 50px 0 0.6rem;
margin: 30px 0 0.6rem;
}

.markdown-section h2 code,
Expand All @@ -56,9 +60,23 @@
color: #619c3c;
}

.token.string {
color: #42b983;
color: var(--theme-color, #42b983);
}

code .token {
color: #3c7cc2;
}


.markdown-section pre>code {
color: #525252;
}

.markdown-section> :not(h1):not(h2):not(h3):not(h4):not(h5):not(h6) code {
font-size: 0.9rem;
}
</style>
</head>

Expand Down
18 changes: 9 additions & 9 deletions docs/offline_first/policies.md
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
# 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<User>(policy: .requireRemote))`) instead of directly accessing a provider (e.g. `Repository().restPovider.get<User>()`)
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<User>(policy: .requireRemote))`) instead of directly accessing a provider (e.g. `Repository().restPovider.get<User>()`).

## OfflineFirstDeletePolicy

### `optimisticLocal`
### `optimisticLocal` (default)

Delete local results before waiting for the remote provider to respond
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
Delete local results after remote responds; local results are not deleted if remote responds with any exception.

## OfflineFirstGetPolicy

Expand All @@ -22,20 +22,20 @@ Ensures data is fetched from the remote provider(s) at each invocation. This hyd

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`
### `awaitRemoteWhenNoneExist` (default)

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)
Do not request from the remote provider(s).

## OfflineFirstUpsertPolicy

### `optimisticLocal`
### `optimisticLocal` (default)

Save results to local before waiting for the remote provider to respond
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
Save results to local after remote responds; local results are not saved if remote responds with any exception.
11 changes: 5 additions & 6 deletions docs/rest/fields.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ Brick by default assumes enums from a REST API will be delivered as integers mat
Given the API:

```json
{ "user": { "hats": [ "bowler", "birthday" ] } }
{ "user": { "hats": ["bowler", "birthday"] } }
```

Simply convert `hats` into a Dart enum:
Expand All @@ -28,9 +28,8 @@ final List<Hat> hats;
REST keys can be renamed per field. This will override the default set by `RestSerializable#fieldRename`.

```dart
@Rest(
name: "full_name" // "full_name" is used in from and to requests to REST instead of "last_name"
)
// "full_name" is used in from and to requests to REST instead of "last_name"
@Rest(name: "full_name")
final String lastName;
```

Expand All @@ -42,5 +41,5 @@ When true, the field will be ignored by the (de)serializing function in the adap

The following are not serialized to REST. However, unsupported types can still be accessed in the model as non-final fields.

* Nested `List<>` e.g. `<List<List<int>>>`
* Many-to-many associations
- Nested `List<>` e.g. `<List<List<int>>>`
- Many-to-many associations
5 changes: 2 additions & 3 deletions docs/supabase/fields.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,8 @@ Supabase.instance.client.from('users')
Supabase keys can be renamed per field. This will override the default set by `SupabaseSerializable#fieldRename`.

```dart
@Supabase(
name: "full_name" // "full_name" is used in from and to requests to Supabase instead of "last_name"
)
// "full_name" is used in from and to requests to Supabase instead of "last_name"
@Supabase(name: "full_name")
final String lastName;
```

Expand Down
2 changes: 1 addition & 1 deletion docs/supabase/query.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
| `'orderBy'` | `String` | Use field names not column names and always specify direction.For example, given a `final DateTime createdAt;` field: `{'orderBy': 'createdAt ASC'}`. |
| `'orderByReferencedTable'` | `String?` | Forwards to Supabase's `referencedTable` [property](https://supabase.com/docs/reference/dart/order) |

?> The `ReferencedTable` params are awkward but necessary to not collide with other providers (like `SqliteProvider`) that also use `orderBy` and `limit`. While a `foreign_table.foreign_column` syntax is more Supabase-like, it is not supported in `orderBy` and `limit`.
?> The `ReferencedTable` naming convention is awkward but necessary to not collide with other providers (like `SqliteProvider`) that also use `orderBy` and `limit`. While a `foreign_table.foreign_column` syntax is more Supabase-like, it is not supported in `orderBy` and `limit`.

## `where:`

Expand Down
19 changes: 9 additions & 10 deletions packages/brick_rest/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ Connecting [Brick](https://github.com/GetDutchie/brick) with a RESTful API.

### `providerArgs:`

* `'request'` (`RestRequest`) Specifies configurable information about the request like HTTP method or top level key
- `'request'` (`RestRequest`) Specifies configurable information about the request like HTTP method or top level key

### `where:`

Expand Down Expand Up @@ -113,9 +113,9 @@ class User extends OfflineFirstModel {}

Data will most often be nested beneath a top-level key in a JSON response. The key is determined by the following priority:

1) A `topLevelKey` in `Query#providerArgs['request']` with a non-empty value
1) `topLevelKey` if defined in a `RestRequest`
1) The first discovered key. As a map is effectively an unordered list, relying on this fall through is not recommended.
1. A `topLevelKey` in `Query#providerArgs['request']` with a non-empty value
1. `topLevelKey` if defined in a `RestRequest`
1. The first discovered key. As a map is effectively an unordered list, relying on this fall through is not recommended.

```dart
class UserRequestTransformer extends RestRequestTransformer {
Expand Down Expand Up @@ -153,7 +153,7 @@ Brick by default assumes enums from a REST API will be delivered as integers mat
Given the API:

```json
{ "user": { "hats": [ "bowler", "birthday" ] } }
{ "user": { "hats": ["bowler", "birthday"] } }
```

Simply convert `hats` into a Dart enum:
Expand All @@ -172,9 +172,8 @@ final List<Hat> hats;
REST keys can be renamed per field. This will override the default set by `RestSerializable#fieldRename`.

```dart
@Rest(
name: "full_name" // "full_name" is used in from and to requests to REST instead of "last_name"
)
// "full_name" is used in from and to requests to REST instead of "last_name"
@Rest(name: "full_name")
final String lastName;
```

Expand All @@ -198,5 +197,5 @@ final restProvider = RestProvider(client: GZipHttpClient(level: 9));

The following are not serialized to REST. However, unsupported types can still be accessed in the model as non-final fields.

* Nested `List<>` e.g. `<List<List<int>>>`
* Many-to-many associations
- Nested `List<>` e.g. `<List<List<int>>>`
- Many-to-many associations
7 changes: 3 additions & 4 deletions packages/brick_supabase/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ Connecting [Brick](https://github.com/GetDutchie/brick) with Supabase.
| `'orderBy'` | `String` | Use field names not column names and always specify direction.For example, given a `final DateTime createdAt;` field: `{'orderBy': 'createdAt ASC'}`. |
| `'orderByReferencedTable'` | `String?` | Forwards to Supabase's `referencedTable` [property](https://supabase.com/docs/reference/dart/order) |

:bulb: The `ReferencedTable` params are awkward but necessary to not collide with other providers (like `SqliteProvider`) that also use `orderBy` and `limit`. While a `foreign_table.foreign_column` syntax is more Supabase-like, it is not supported in `orderBy` and `limit`.
:bulb: The `ReferencedTable` naming convention is awkward but necessary to not collide with other providers (like `SqliteProvider`) that also use `orderBy` and `limit`. While a `foreign_table.foreign_column` syntax is more Supabase-like, it is not supported in `orderBy` and `limit`.

### `where:`

Expand Down Expand Up @@ -104,9 +104,8 @@ final List<Hat> hats;
Supabase keys can be renamed per field. This will override the default set by `SupabaseSerializable#fieldRename`.

```dart
@Supabase(
name: "full_name" // "full_name" is used in from and to requests to Supabase instead of "last_name"
)
// "full_name" is used in from and to requests to Supabase instead of "last_name"
@Supabase(name: "full_name")
final String lastName;
```

Expand Down

0 comments on commit a34494d

Please sign in to comment.