Skip to content

Commit 9a41b95

Browse files
authored
feat(supabase): define upsertMethod within query for supabase (#529)
1 parent 0635cf1 commit 9a41b95

8 files changed

+69
-3
lines changed

packages/brick_supabase/CHANGELOG.md

+6
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,11 @@
11
## Unreleased
22

3+
## 1.4.1+1
4+
5+
- Add `SupabaseProviderQuery`
6+
- Support defining `upsertMethod` via `SupabaseProviderQuery`
7+
- Fix `orderBy` queries to use the column name instead of the field name when constructing PostgREST queries
8+
39
## 1.4.0
410

511
- **DEPRECATION** remove `Supabase#nullable`. Builders should evaluate the nullable suffix of the field instead

packages/brick_supabase/lib/brick_supabase.dart

+1
Original file line numberDiff line numberDiff line change
@@ -6,3 +6,4 @@ export 'package:brick_supabase/src/supabase_adapter.dart';
66
export 'package:brick_supabase/src/supabase_model.dart';
77
export 'package:brick_supabase/src/supabase_model_dictionary.dart';
88
export 'package:brick_supabase/src/supabase_provider.dart';
9+
export 'package:brick_supabase/src/supabase_provider_query.dart';

packages/brick_supabase/lib/src/query_supabase_transformer.dart

+3-1
Original file line numberDiff line numberDiff line change
@@ -247,10 +247,12 @@ class QuerySupabaseTransformer<_Model extends SupabaseModel> {
247247
return query!.orderBy.fold(withProviderArgs, (acc, orderBy) {
248248
final definition = adapter.fieldsToSupabaseColumns[orderBy.evaluatedField];
249249
final tableName = modelDictionary.adapterFor[definition?.associationType]?.supabaseTableName;
250+
final columnName = adapter
251+
.fieldsToSupabaseColumns[orderBy.associationField ?? orderBy.evaluatedField]?.columnName;
250252

251253
final url = acc.appendSearchParams(
252254
tableName == null ? 'order' : '$tableName.order',
253-
'${orderBy.associationField ?? orderBy.evaluatedField}.${orderBy.ascending ? 'asc' : 'desc'}.nullslast',
255+
'$columnName.${orderBy.ascending ? 'asc' : 'desc'}.nullslast',
254256
);
255257
return acc.copyWithUrl(url);
256258
});

packages/brick_supabase/lib/src/supabase_provider.dart

+3
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import 'package:brick_core/core.dart';
22
import 'package:brick_supabase/src/query_supabase_transformer.dart';
33
import 'package:brick_supabase/src/supabase_model.dart';
44
import 'package:brick_supabase/src/supabase_model_dictionary.dart';
5+
import 'package:brick_supabase/src/supabase_provider_query.dart';
56
import 'package:logging/logging.dart';
67
import 'package:meta/meta.dart';
78
import 'package:supabase/supabase.dart';
@@ -149,9 +150,11 @@ class SupabaseProvider implements Provider<SupabaseModel> {
149150
}) async {
150151
final adapter = modelDictionary.adapterFor[TModel]!;
151152
final output = await adapter.toSupabase(instance, provider: this, repository: repository);
153+
final providerQuery = query?.providerQueries[SupabaseProvider] as SupabaseProviderQuery?;
152154

153155
return await recursiveAssociationUpsert(
154156
output,
157+
method: providerQuery?.upsertMethod ?? UpsertMethod.upsert,
155158
type: TModel,
156159
query: query,
157160
repository: repository,
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
import 'package:brick_core/core.dart';
2+
import 'package:brick_supabase/src/supabase_provider.dart';
3+
4+
/// [SupabaseProvider]-specific options for a [Query]
5+
class SupabaseProviderQuery extends ProviderQuery<SupabaseProvider> {
6+
/// An internal definition for remote requests.
7+
/// In rare cases, a specific `update` or `insert` is preferable to `upsert`;
8+
/// this enum explicitly declares the desired behavior.
9+
final UpsertMethod? upsertMethod;
10+
11+
/// [SupabaseProvider]-specific options for a [Query]
12+
const SupabaseProviderQuery({
13+
this.upsertMethod,
14+
});
15+
16+
@override
17+
Map<String, dynamic> toJson() => {
18+
if (upsertMethod != null) 'upsertMethod': upsertMethod?.name,
19+
};
20+
21+
@override
22+
bool operator ==(Object other) =>
23+
identical(this, other) ||
24+
other is SupabaseProviderQuery &&
25+
runtimeType == other.runtimeType &&
26+
upsertMethod == other.upsertMethod;
27+
28+
@override
29+
int get hashCode => upsertMethod.hashCode;
30+
}

packages/brick_supabase/pubspec.yaml

+1-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ homepage: https://github.com/GetDutchie/brick/tree/main/packages/brick_supabase
44
issue_tracker: https://github.com/GetDutchie/brick/issues
55
repository: https://github.com/GetDutchie/brick
66

7-
version: 1.4.0
7+
version: 1.4.1+1
88

99
environment:
1010
sdk: ">=3.0.0 <4.0.0"

packages/brick_supabase/test/query_supabase_transformer_test.dart

+1-1
Original file line numberDiff line numberDiff line change
@@ -246,7 +246,7 @@ void main() {
246246

247247
expect(
248248
transformBuilder.query,
249-
'select=id,nested_column:demo_associations(id,name,assoc_id:demos!assoc_id(id,name,custom_age),assocs:demos(id,name,custom_age))&demo_associations.order=nested.desc.nullslast',
249+
'select=id,nested_column:demo_associations(id,name,assoc_id:demos!assoc_id(id,name,custom_age),assocs:demos(id,name,custom_age))&demo_associations.order=nested_column.desc.nullslast',
250250
);
251251
});
252252

packages/brick_supabase/test/supabase_provider_test.dart

+24
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
// ignore_for_file: unawaited_futures
22

3+
import 'package:brick_core/query.dart';
34
import 'package:brick_supabase/src/supabase_provider.dart';
5+
import 'package:brick_supabase/src/supabase_provider_query.dart';
46
import 'package:brick_supabase/testing.dart';
57
import 'package:test/test.dart';
68

@@ -141,6 +143,28 @@ void main() {
141143
expect(inserted.assoc.id, instance.assoc.id);
142144
expect(inserted.name, instance.name);
143145
});
146+
147+
test('with non-default method from query', () async {
148+
const req = SupabaseRequest<Demo>(
149+
requestMethod: 'PATCH',
150+
filter: 'id=eq.1',
151+
limit: 1,
152+
);
153+
final instance = Demo(age: 1, name: 'Demo 1', id: '1');
154+
final resp = SupabaseResponse(await mock.serialize(instance));
155+
mock.handle({req: resp});
156+
157+
final provider = SupabaseProvider(mock.client, modelDictionary: supabaseModelDictionary);
158+
final inserted = await provider.upsert<Demo>(
159+
instance,
160+
query: const Query(
161+
forProviders: [SupabaseProviderQuery(upsertMethod: UpsertMethod.update)],
162+
),
163+
);
164+
expect(inserted.id, instance.id);
165+
expect(inserted.age, instance.age);
166+
expect(inserted.name, instance.name);
167+
});
144168
});
145169
});
146170
}

0 commit comments

Comments
 (0)