Skip to content

Commit d9debfa

Browse files
committed
add docs for offline and for supabase
1 parent d9b8c49 commit d9debfa

File tree

11 files changed

+443
-126
lines changed

11 files changed

+443
-126
lines changed

README.md

Lines changed: 51 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,11 @@ An intuitive way to work with persistent data in Dart.
66

77
## Why Brick?
88

9-
* Out-of-the-box [offline access](packages/brick_offline_first) to data
10-
* [Handle and hide](packages/brick_build) complex serialization/deserialization logic
11-
* Single [access point](docs/data/repositories.md) and opinionated DSL
12-
* Automatic, [intelligently-generated migrations](docs/sqlite.md#intelligent-migrations)
13-
* Legible [querying interface](docs/data/query.md)
9+
- Out-of-the-box [offline access](packages/brick_offline_first) to data
10+
- [Handle and hide](packages/brick_build) complex serialization/deserialization logic
11+
- Single [access point](docs/data/repositories.md) and opinionated DSL
12+
- Automatic, [intelligently-generated migrations](docs/sqlite.md#intelligent-migrations)
13+
- Legible [querying interface](docs/data/query.md)
1414

1515
## What is Brick?
1616

@@ -19,51 +19,55 @@ Brick is an extensible query interface for Dart applications. It's an [all-in-on
1919
## Quick Start
2020

2121
1. Add the packages:
22-
```yaml
23-
dependencies:
24-
# Or brick_offline_first_with_graphql
25-
brick_offline_first_with_rest:
26-
sqflite: # optional
27-
dev_dependencies:
28-
# Or brick_offline_first_with_graphql_build: any
29-
brick_offline_first_with_rest_build:
30-
build_runner:
31-
```
22+
```yaml
23+
dependencies:
24+
# Or brick_offline_first_with_graphql
25+
# Or brick_offline_first_with_supabase
26+
brick_offline_first_with_rest:
27+
sqflite: # optional
28+
dev_dependencies:
29+
# Or brick_offline_first_with_graphql_build: any
30+
# Or brick_offline_first_with_supabase_build: any
31+
brick_offline_first_with_rest_build:
32+
build_runner:
33+
```
3234
1. Configure your app directory structure to match Brick's expectations:
33-
```bash
34-
mkdir -p lib/brick/adapters lib/brick/db;
35-
```
35+
```bash
36+
mkdir -p lib/brick/adapters lib/brick/db;
37+
```
3638
1. Add [models](docs/data/models.md) that contain your app logic. Models **must be** saved with the `.model.dart` suffix (i.e. `lib/brick/models/person.model.dart`).
3739
1. Run `dart run build_runner build` to generate your models and [sometimes migrations](docs/sqlite.md#intelligent-migrations). Rerun after every new model change or `dart run build_runner watch` for automatic generations. You'll need to run this again after your first migration.
3840
1. Extend [an existing repository](docs/data/repositories.md) or create your own:
39-
```dart
40-
// lib/brick/repository.dart
41-
import 'package:brick_offline_first_with_rest/brick_offline_first_with_rest.dart';
42-
import 'package:brick_rest/brick_rest.dart';
43-
import 'package:brick_sqlite/brick_sqlite.dart';
44-
import 'package:my_app/brick/brick.g.dart';
45-
import 'package:sqflite/sqflite.dart' show databaseFactory;
46-
import 'package:my_app/brick/db/schema.g.dart';
47-
export 'package:brick_core/query.dart' show And, Or, Query, QueryAction, Where, WherePhrase;
4841

49-
class Repository extends OfflineFirstWithRestRepository {
50-
Repository()
51-
: super(
52-
migrations: migrations,
53-
restProvider: RestProvider(
54-
'http://0.0.0.0:3000',
55-
modelDictionary: restModelDictionary,
56-
),
57-
sqliteProvider: SqliteProvider(
58-
_DB_NAME,
59-
databaseFactory: databaseFactory,
60-
modelDictionary: sqliteModelDictionary,
61-
),
62-
offlineQueueManager: RestRequestSqliteCacheManager(
63-
'brick_offline_queue.sqlite',
64-
databaseFactory: databaseFactory,
65-
),
66-
);
67-
}
68-
```
42+
```dart
43+
// lib/brick/repository.dart
44+
import 'package:brick_offline_first_with_rest/brick_offline_first_with_rest.dart';
45+
import 'package:brick_rest/brick_rest.dart';
46+
import 'package:brick_sqlite/brick_sqlite.dart';
47+
import 'package:my_app/brick/brick.g.dart';
48+
import 'package:sqflite/sqflite.dart' show databaseFactory;
49+
import 'package:my_app/brick/db/schema.g.dart';
50+
export 'package:brick_core/query.dart' show And, Or, Query, QueryAction, Where, WherePhrase;
51+
52+
class Repository extends OfflineFirstWithRestRepository {
53+
Repository()
54+
: super(
55+
migrations: migrations,
56+
restProvider: RestProvider(
57+
'http://0.0.0.0:3000',
58+
modelDictionary: restModelDictionary,
59+
),
60+
sqliteProvider: SqliteProvider(
61+
_DB_NAME,
62+
databaseFactory: databaseFactory,
63+
modelDictionary: sqliteModelDictionary,
64+
),
65+
offlineQueueManager: RestRequestSqliteCacheManager(
66+
'brick_offline_queue.sqlite',
67+
databaseFactory: databaseFactory,
68+
),
69+
);
70+
}
71+
```
72+
6973
1. Profit.

docs/_sidebar.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,10 @@
88
- [Fetching data](data/query.md)
99
- [Providers](data/providers.md)
1010
- [Repositories](data/repositories.md)
11+
- [Supabase](supabase/repository.md)
12+
- [Model Config](supabase/models.md)
13+
- [Field Config](supabase/fields.md)
14+
- [Querying](supabase/query.md)
1115
- [GraphQL](graphql/fields.md)
1216
- [Model Config](graphql/models.md)
1317
- [Field Config](graphql/fields.md)

docs/home.md

Lines changed: 66 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -1,74 +1,83 @@
11
# Quick Start
22

33
1. Add the packages:
4-
```yaml
5-
dependencies:
6-
# Or brick_offline_first_with_graphql
7-
brick_offline_first_with_rest:
8-
sqflite: # optional
9-
dev_dependencies:
10-
# Or brick_offline_first_with_graphql_build: any
11-
brick_offline_first_with_rest_build:
12-
build_runner:
13-
```
4+
```yaml
5+
dependencies:
6+
# Or brick_offline_first_with_supabase
7+
brick_offline_first_with_rest:
8+
sqflite: # optional
9+
dev_dependencies:
10+
# Or brick_offline_first_with_graphql_build: any
11+
# Or brick_offline_first_with_supabase_build: any
12+
brick_offline_first_with_rest_build:
13+
build_runner:
14+
```
1415
1. Configure your app directory structure to match Brick's expectations:
15-
```bash
16-
mkdir -p lib/brick/adapters lib/brick/db;
17-
```
16+
```bash
17+
mkdir -p lib/brick/adapters lib/brick/db;
18+
```
1819
1. Add [models](docs/data/models) that contain your app logic. Models **must be** saved with the `.model.dart` suffix (i.e. `lib/brick/models/person.model.dart`).
1920
1. Run `dart run build_runner build` to generate your models and [sometimes migrations](docs/sqlite.md#intelligent-migrations). Rerun after every new model change or `dart run build_runner watch` for automatic generations. You'll need to run this again after your first migration.
2021
1. Extend [an existing repository](docs/data/repositories) or create your own:
21-
```dart
22-
// lib/brick/repository.dart
23-
import 'package:brick_offline_first_with_rest/brick_offline_first_with_rest.dart';
24-
import 'package:brick_rest/brick_rest.dart';
25-
import 'package:brick_sqlite/brick_sqlite.dart';
26-
import 'package:my_app/brick/brick.g.dart';
27-
import 'package:sqflite/sqflite.dart' show databaseFactory;
28-
import 'package:my_app/brick/db/schema.g.dart';
29-
export 'package:brick_core/query.dart' show And, Or, Query, QueryAction, Where, WherePhrase;
30-
31-
class Repository extends OfflineFirstWithRestRepository {
32-
Repository()
33-
: super(
34-
migrations: migrations,
35-
restProvider: RestProvider(
36-
'http://0.0.0.0:3000',
37-
modelDictionary: restModelDictionary,
38-
),
39-
sqliteProvider: SqliteProvider(
40-
_DB_NAME,
41-
databaseFactory: databaseFactory,
42-
modelDictionary: sqliteModelDictionary,
43-
),
44-
offlineQueueManager: RestRequestSqliteCacheManager(
45-
'brick_offline_queue.sqlite',
46-
databaseFactory: databaseFactory,
47-
),
48-
);
49-
}
50-
```
22+
23+
```dart
24+
// lib/brick/repository.dart
25+
import 'package:brick_offline_first_with_rest/brick_offline_first_with_rest.dart';
26+
import 'package:brick_rest/brick_rest.dart';
27+
import 'package:brick_sqlite/brick_sqlite.dart';
28+
import 'package:my_app/brick/brick.g.dart';
29+
import 'package:sqflite/sqflite.dart' show databaseFactory;
30+
import 'package:my_app/brick/db/schema.g.dart';
31+
export 'package:brick_core/query.dart' show And, Or, Query, QueryAction, Where, WherePhrase;
32+
33+
class Repository extends OfflineFirstWithRestRepository {
34+
Repository()
35+
: super(
36+
migrations: migrations,
37+
restProvider: RestProvider(
38+
'http://0.0.0.0:3000',
39+
modelDictionary: restModelDictionary,
40+
),
41+
sqliteProvider: SqliteProvider(
42+
_DB_NAME,
43+
databaseFactory: databaseFactory,
44+
modelDictionary: sqliteModelDictionary,
45+
),
46+
offlineQueueManager: RestRequestSqliteCacheManager(
47+
'brick_offline_queue.sqlite',
48+
databaseFactory: databaseFactory,
49+
),
50+
);
51+
}
52+
```
53+
5154
1. Profit.
5255

56+
## Integrations
57+
58+
- [With Rest](offline_first/offline_first_with_rest_repository.md)
59+
- [With GraphQL](offline_first/offline_first_with_graphql_repository.md)
60+
- [With Supabase](offline_first/offline_first_with_supabase_repository.md)
61+
5362
## Learn
5463

55-
* Video: [Brick Architecture](https://www.youtube.com/watch?v=2noLcro9iIw). An explanation of Brick parlance with a supplemental analogy.
56-
* Video: [Brick Basics](https://www.youtube.com/watch?v=jm5i7e_BQq0). An overview of essential Brick mechanics.
57-
* Example: [Simple Associations using the OfflineFirstWithGraphql domain](https://github.com/GetDutchie/brick/blob/main/example_graphql)
58-
* Example: [Simple Associations using the OfflineFirstWithRest domain](https://github.com/GetDutchie/brick/blob/main/example)
59-
* Tutorial: [Setting up a simple app with Brick](http://www.flutterbyexample.com/#/posts/2_adding_a_repository)
64+
- Video: [Brick Architecture](https://www.youtube.com/watch?v=2noLcro9iIw). An explanation of Brick parlance with a supplemental analogy.
65+
- Video: [Brick Basics](https://www.youtube.com/watch?v=jm5i7e_BQq0). An overview of essential Brick mechanics.
66+
- Example: [Simple Associations using the OfflineFirstWithGraphql domain](https://github.com/GetDutchie/brick/blob/main/example_graphql)
67+
- Example: [Simple Associations using the OfflineFirstWithRest domain](https://github.com/GetDutchie/brick/blob/main/example)
68+
- Tutorial: [Setting up a simple app with Brick](http://www.flutterbyexample.com/#/posts/2_adding_a_repository)
6069

6170
## Glossary
6271

63-
* **source** - external information warehouse that delivers unrefined data
64-
* [**Provider**](data/providers.md) - fetches from and pushes to a `source`
65-
* [**Repository**](data/repositories.md) - manages `Provider`(s) and determines which provider results to send
66-
* **Adapter** - normalizes data input and output between `Provider`s
67-
* [**Model**](data/models.md) - business logic unique to the app. Fetched by the `Repository`, and if merited by the `Repository` implementation, the `Provider`.
68-
* **ModelDictionary** - guides a `Provider` to the `Model`'s `Adapter`. Unique per `Provider`.
69-
* **field** - single, accessible property of a model. For example, `final String id`
70-
* **deserialize** - convert raw data _from_ a provider
71-
* **serialize** - convert a model instance _to_ raw data for a provider
72+
- **source** - external information warehouse that delivers unrefined data
73+
- [**Provider**](data/providers.md) - fetches from and pushes to a `source`
74+
- [**Repository**](data/repositories.md) - manages `Provider`(s) and determines which provider results to send
75+
- **Adapter** - normalizes data input and output between `Provider`s
76+
- [**Model**](data/models.md) - business logic unique to the app. Fetched by the `Repository`, and if merited by the `Repository` implementation, the `Provider`.
77+
- **ModelDictionary** - guides a `Provider` to the `Model`'s `Adapter`. Unique per `Provider`.
78+
- **field** - single, accessible property of a model. For example, `final String id`
79+
- **deserialize** - convert raw data _from_ a provider
80+
- **serialize** - convert a model instance _to_ raw data for a provider
7281

7382
## FAQ
7483

docs/introduction/setup.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,11 @@
55
```yaml
66
dependencies:
77
# or brick_offline_first_with_graphql: any
8+
# or brick_offline_first_with_supabase: any
89
brick_offline_first_with_rest: any
910
dev_dependencies:
1011
# or brick_offline_first_with_graphql_build: any
12+
# or brick_offline_first_with_supabase_build: any
1113
brick_offline_first_with_rest_build: any
1214
build_runner: any
1315
```
Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
# Offline First With Supabase Repository
2+
3+
`OfflineFirstWithSupabaseRepository` streamlines the Supabase integration with an `OfflineFirstRepository`. A [serial queue](offline_queue.md) is included to track Supabase 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).
4+
5+
The `OfflineFirstWithSupabase` domain uses all the same configurations and annotations as `OfflineFirst`.
6+
7+
![OfflineFirst#get](https://user-images.githubusercontent.com/865897/72176226-cdd8ca00-3392-11ea-867d-42f5f4620153.jpg)
8+
9+
!> You can change default behavior on a per-request basis using `policy:` (e.g. `get<Person>(policy: OfflineFirstUpsertPolicy.localOnly)`). This is available for `delete`, `get`, `getBatched`, `subscribe`, and `upsert`.
10+
11+
## Packages
12+
13+
`brick_offline_first_with_supabase` and `brick_offline_first_with_supabase_build` are required in your `pubspec.yaml`:
14+
15+
```yaml
16+
dependencies:
17+
brick_offline_first_with_supabase: any
18+
dev_dependencies:
19+
brick_offline_first_with_supabase_build: any
20+
build_runner: any
21+
```
22+
23+
## Repository Configuration
24+
25+
The repository utilizes the `OfflineFirstWithRestRepository`'s queue because the Supabase client is a thin wrapper around the PostgREST API. There's a small amount of configuration to apply this queue:
26+
27+
```dart
28+
class MyRepository extends OfflineFirstWithSupabaseRepository {
29+
static late MyRepository? _singleton;
30+
31+
MyRepository._({
32+
required super.supabaseProvider,
33+
required super.sqliteProvider,
34+
required super.migrations,
35+
required super.offlineRequestQueue,
36+
super.memoryCacheProvider,
37+
});
38+
39+
factory MyRepository() => _singleton!;
40+
41+
static void configure({
42+
required String supabaseUrl,
43+
required String apiKey,
44+
required Set<Migration> migrations,
45+
}) {
46+
// Convenience method `.clientQueue` makes creating the queue and client easy.
47+
final (client, queue) = OfflineFirstWithSupabaseRepository.clientQueue(
48+
databaseFactory: databaseFactory,
49+
);
50+
51+
final provider = SupabaseProvider(
52+
SupabaseClient(supabaseUrl, apiKey, httpClient: client),
53+
modelDictionary: supabaseModelDictionary,
54+
);
55+
56+
// Finally, initialize the repository as normal.
57+
_singleton = MyRepository._(
58+
supabaseProvider: provider,
59+
sqliteProvider: SqliteProvider(
60+
'my_repository.sqlite',
61+
databaseFactory: databaseFactory,
62+
modelDictionary: sqliteModelDictionary,
63+
),
64+
migrations: migrations,
65+
offlineRequestQueue: queue,
66+
memoryCacheProvider: MemoryCacheProvider(),
67+
);
68+
}
69+
}
70+
```
71+
72+
When using [supabase_flutter](https://pub.dev/packages/supabase_flutter), create the client and queue before initializing:
73+
74+
```dart
75+
final (client, queue) = OfflineFirstWithSupabaseRepository.clientQueue(databaseFactory: databaseFactory);
76+
await Supabase.initialize(httpClient: client)
77+
final supabaseProvider = SupabaseProvider(Supabase.instance.client, modelDictionary: ...)
78+
```
79+
80+
### ConnectOfflineFirstWithSupabase
81+
82+
`@ConnectOfflineFirstWithSupabase` decorates the model that can be serialized by one or more providers. Offline First does not have configuration at the class level and only extends configuration held by its providers:
83+
84+
```dart
85+
@ConnectOfflineFirstWithSupabase(
86+
supabaseConfig: SupabaseSerializable(),
87+
sqliteConfig: SqliteSerializable(),
88+
)
89+
class MyModel extends OfflineFirstWithSupabaseModel {}
90+
```
91+
92+
## OfflineFirst(where:)
93+
94+
Ideally, `@OfflineFirst(where:)` shouldn't be necessary to specify to make the association between local Brick and remote Supabase because the generated Supabase `.select` should include all nested fields. However, if there are [too many](https://github.com/GetDutchie/brick/issues/399) REST calls, it may be necessary to guide Brick to the right foreign keys.
95+
96+
```dart
97+
@OfflineFirst(where: {'id': "data['otherId']"})
98+
// Explicitly specifying `name:` can ensure that the two annotations
99+
// definitely have the same values
100+
@Supabase(name: 'otherId')
101+
final Pizza pizza;
102+
```
103+
104+
!> Multiple `where` keys (`OfflineFirst(where: {'id': 'data["id"]', 'otherVar': 'data["otherVar"]'})`) will be ignored. Nested properties (`OfflineFirst(where: {'id': 'data["subfield"]["id"]})`) will also be ignored.

docs/rest/query.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@
22

33
## `providerArgs:`
44

5-
| Name | Type | Description |
6-
|---|---|---|
5+
| Name | Type | Description |
6+
| ----------- | ------------- | -------------------------------------------------------------------------------------- |
77
| `'request'` | `RestRequest` | Specifies configurable information about the request like HTTP method or top level key |
88

99
## `where:`

0 commit comments

Comments
 (0)