-
Notifications
You must be signed in to change notification settings - Fork 28
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
eng(supabase): add supabase and offline first with supabase packages #403
Changes from 1 commit
234c5eb
28d52ec
90c6a22
124afb3
f75c645
c7c68f3
ae4af57
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
name: Brick Offline First with Supabase | ||
on: | ||
push: | ||
branches: | ||
- main | ||
pull_request: | ||
paths: | ||
- "packages/brick_offline_first_with_supabase/**" | ||
- ".github/workflows/brick_offline_first_with_supabase.yaml" | ||
|
||
env: | ||
PUB_ENVIRONMENT: bot.github | ||
|
||
jobs: | ||
analyze_format_test: | ||
uses: ./.github/workflows/reusable-flutter-analyze-format-test.yaml | ||
with: | ||
package: brick_offline_first_with_supabase |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
name: Brick Supabase | ||
on: | ||
push: | ||
branches: | ||
- main | ||
pull_request: | ||
paths: | ||
- "packages/brick_supabase/**" | ||
- ".github/workflows/brick_supabase.yaml" | ||
|
||
env: | ||
PUB_ENVIRONMENT: bot.github | ||
|
||
jobs: | ||
analyze_format_test: | ||
uses: ./.github/workflows/reusable-dart-analyze-format-test.yaml | ||
with: | ||
package: brick_supabase |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
!example/**/*.g.dart |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
## Unreleased | ||
|
||
### 0.0.1 | ||
|
||
Initial |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
The MIT License (MIT) | ||
|
||
Copyright (c) Green Bits, Inc. and its affiliates. | ||
|
||
Permission is hereby granted, free of charge, to any person obtaining a copy | ||
of this software and associated documentation files (the "Software"), to deal | ||
in the Software without supabaseriction, including without limitation the rights | ||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
copies of the Software, and to permit persons to whom the Software is | ||
furnished to do so, subject to the following conditions: | ||
|
||
The above copyright notice and this permission notice shall be included in all | ||
copies or substantial portions of the Software. | ||
|
||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
SOFTWARE. |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
![brick_offline_first_with_supabase workflow](https://github.com/GetDutchie/brick/actions/workflows/brick_offline_first_with_supabase.yaml/badge.svg) | ||
|
||
`OfflineFirstWithSupabaseRepository` streamlines the Supabase integration with an `OfflineFirstRepository`. | ||
|
||
The `OfflineFirstWithSupabase` domain uses all the same configurations and annotations as `OfflineFirst`. | ||
|
||
## Models | ||
|
||
### ConnectOfflineFirstWithSupabase | ||
|
||
`@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: | ||
|
||
```dart | ||
@ConnectOfflineFirstWithSupabase( | ||
supabaseConfig: SupabaseSerializable(), | ||
sqliteConfig: SqliteSerializable(), | ||
) | ||
class MyModel extends OfflineFirstModel {} | ||
``` | ||
|
||
### FAQ | ||
|
||
#### Why can't I declare a model argument? | ||
|
||
Due to [an open analyzer bug](https://github.com/dart-lang/sdk/issues/38309), a custom model cannot be passed to the repository as a type argument. | ||
|
||
## Unsupported Field Types | ||
|
||
- Any unsupported field types from `SupabaseProvider`, or `SqliteProvider` | ||
- Future iterables of future models (i.e. `Future<List<Future<Model>>>`). |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
include: ../../analysis_options.yaml |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
export 'package:brick_offline_first_with_supabase/src/offline_first_with_supabase_adapter.dart'; | ||
export 'package:brick_offline_first_with_supabase/src/offline_first_with_supabase_model.dart'; | ||
export 'package:brick_offline_first_with_supabase/src/offline_first_with_supabase_repository.dart'; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
import 'package:brick_offline_first/brick_offline_first.dart'; | ||
import 'package:brick_offline_first_with_supabase/src/offline_first_with_supabase_model.dart'; | ||
import 'package:brick_supabase/brick_supabase.dart'; | ||
|
||
/// This adapter fetches first from [SqliteProvider] then hydrates with [SupabaseProvider]. | ||
abstract class OfflineFirstWithSupabaseAdapter<_Model extends OfflineFirstWithSupabaseModel> | ||
extends OfflineFirstAdapter<_Model> with SupabaseAdapter<_Model> { | ||
OfflineFirstWithSupabaseAdapter(); | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
import 'package:brick_offline_first/brick_offline_first.dart'; | ||
import 'package:brick_supabase_abstract/brick_supabase_abstract.dart'; | ||
|
||
abstract class OfflineFirstWithSupabaseModel extends OfflineFirstModel with SupabaseModel {} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
import 'package:brick_offline_first/brick_offline_first.dart'; | ||
import 'package:brick_offline_first_with_supabase/src/offline_first_with_supabase_model.dart'; | ||
import 'package:brick_supabase/brick_supabase.dart' show SupabaseProvider; | ||
|
||
/// Ensures the [remoteProvider] is a [SupabaseProvider]. | ||
/// | ||
/// OfflineFirstWithSupabaseRepository should accept a type argument such as | ||
/// <_RepositoryModel extends OfflineFirstWithSupabaseModel>, however, this causes a type bound | ||
/// error on runtime. The argument should be reintroduced with a future version of the | ||
/// compiler/analyzer. | ||
abstract class OfflineFirstWithSupabaseRepository | ||
extends OfflineFirstRepository<OfflineFirstWithSupabaseModel> { | ||
/// The type declaration is important here for the rare circumstances that | ||
/// require interfacting with [SupabaseProvider]'s client directly. | ||
@override | ||
// ignore: overridden_fields | ||
final SupabaseProvider remoteProvider; | ||
|
||
OfflineFirstWithSupabaseRepository({ | ||
super.autoHydrate, | ||
super.loggerName, | ||
super.memoryCacheProvider, | ||
required super.migrations, | ||
required SupabaseProvider supabaseProvider, | ||
required super.sqliteProvider, | ||
}) : remoteProvider = supabaseProvider, | ||
super( | ||
remoteProvider: supabaseProvider, | ||
); | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
name: brick_offline_first_with_supabase | ||
description: A Brick domain that routes data fetching through local providers | ||
before a Supabase provider. | ||
homepage: https://github.com/GetDutchie/brick/tree/main/packages/brick_offline_first_with_supabase | ||
issue_tracker: https://github.com/GetDutchie/brick/issues | ||
repository: https://github.com/GetDutchie/brick | ||
|
||
version: 0.0.1 | ||
|
||
environment: | ||
sdk: ">=2.18.0 <4.0.0" | ||
|
||
dependencies: | ||
brick_core: ^1.1.1 | ||
brick_offline_first: ">=3.0.0 <4.0.0" | ||
brick_supabase: ">=0.0.1 <2.0.0" | ||
brick_supabase_abstract: ">=0.0.1 <2.0.0" | ||
brick_sqlite: ">=3.0.0 <4.0.0" | ||
logging: ">=1.0.0 <2.0.0" | ||
meta: ">=1.3.0 <2.0.0" | ||
sqflite_common: ">=2.0.0 <3.0.0" | ||
|
||
dev_dependencies: | ||
lints: ^2.0.1 | ||
mockito: ^5.0.0 | ||
test: ^1.16.5 | ||
sqflite_common_ffi: ^2.0.0 |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
## Unreleased | ||
|
||
### 0.0.1 | ||
|
||
Initial |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
The MIT License (MIT) | ||
|
||
Copyright (c) Green Bits, Inc. and its affiliates. | ||
|
||
Permission is hereby granted, free of charge, to any person obtaining a copy | ||
of this software and associated documentation files (the "Software"), to deal | ||
in the Software without supabaseriction, including without limitation the rights | ||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
copies of the Software, and to permit persons to whom the Software is | ||
furnished to do so, subject to the following conditions: | ||
|
||
The above copyright notice and this permission notice shall be included in all | ||
copies or substantial portions of the Software. | ||
|
||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
SOFTWARE. |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,90 @@ | ||
![brick_supabase workflow](https://github.com/GetDutchie/brick/actions/workflows/brick_supabase.yaml/badge.svg) | ||
|
||
# Supabase Provider | ||
|
||
Connecting [Brick](https://github.com/GetDutchie/brick) with Supabase. | ||
|
||
## Models | ||
|
||
### `@SupabaseSerializable(tableName:)` | ||
|
||
The Supabase table name must be specified to connect `from`, `upsert` and `delete` invocations: | ||
|
||
```dart | ||
@SupabaseSerializable(tableName: 'users') | ||
class User | ||
``` | ||
|
||
## Fields | ||
|
||
### `@Supabase(unique:)` | ||
|
||
Connect Supabase's primary key (or any other index) to your application code. This is useful for `upsert` and `delete` logic when mutating instances. | ||
|
||
```dart | ||
@Supabase(unique: true, name: 'id') | ||
final int supabaseId; | ||
``` | ||
|
||
### `@Supabase(foreignKey:)` | ||
|
||
Specify the foreign key to use on the table when fetching for a remote association. | ||
|
||
For example, given the `orders` table has a `customer_id` column that associates | ||
the `customers` table, an `Order` class in Dart may look like: | ||
|
||
```dart | ||
@SupabaseSerializeable(tableName: 'orders') | ||
class Order { | ||
@Supabase(foreignKey: 'customer_id') | ||
final Customer customer; | ||
} | ||
|
||
@SupabaseSerializeable(tableName: 'customers') | ||
class Customer { | ||
final int id; | ||
} | ||
``` | ||
|
||
### `@Supabase(enumAsString:)` | ||
|
||
Brick by default assumes enums from a REST API will be delivered as integers matching the index in the Flutter app. However, if your API delivers strings instead, the field can be easily annotated without writing a custom generator. | ||
|
||
Given the API: | ||
|
||
```json | ||
{ "user": { "hats": ["bowler", "birthday"] } } | ||
``` | ||
|
||
Simply convert `hats` into a Dart enum: | ||
|
||
```dart | ||
enum Hat { baseball, bowler, birthday } | ||
|
||
... | ||
|
||
@Supabase(enumAsString: true) | ||
final List<Hat> hats; | ||
``` | ||
|
||
Comment on lines
+49
to
+69
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Question: When enums (Enumerated Types) are stored and returned by their name and not the index in Postgres/PostgREST, why is this option necessary? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @devj3ns this option is necessary for exactly that case. By default, enums are serialized/deserialized by their index, and |
||
### `@Supabase(name:)` | ||
|
||
REST 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 REST instead of "last_name" | ||
) | ||
final String lastName; | ||
``` | ||
|
||
### `@Supabase(ignoreFrom:)` and `@Supabase(ignoreTo:)` | ||
|
||
When true, the field will be ignored by the (de)serializing function in the adapter. | ||
|
||
## Unsupported Field Types | ||
|
||
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 |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
include: ../../analysis_options.yaml |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
export 'package:brick_supabase/src/supabase_adapter.dart'; | ||
export 'package:brick_supabase/src/supabase_model_dictionary.dart'; | ||
export 'package:brick_supabase/src/supabase_provider.dart'; | ||
export 'package:brick_supabase_abstract/brick_supabase_abstract.dart'; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would suggest changing this to type String or UUID, to avoid collisions. As recommended in the docs.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Excellent catch, updated