Skip to content

Commit

Permalink
feat(supabase): allow overrides of the generated query (#479)
Browse files Browse the repository at this point in the history
  • Loading branch information
tshedor authored Nov 12, 2024
1 parent e05ff31 commit a7a77b0
Show file tree
Hide file tree
Showing 16 changed files with 93 additions and 28 deletions.
2 changes: 2 additions & 0 deletions packages/brick_offline_first/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
## Unreleased

- Change `OfflineFirstRepository#exists` behavior: the check against memory cache will only return `true` if results have been found, otherwise it will continue to the SQLite provider

## 3.3.0

- Added `subscriptionByQuery` to `OfflineFirstRepository#notifySubscriptionsWithLocalData` to pass a custom map of `StreamControllers`
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,7 @@ abstract class OfflineFirstRepository<TRepositoryModel extends OfflineFirstModel
if (memoryCacheProvider.canFind<TModel>(query)) {
final results = memoryCacheProvider.get<TModel>(query: query, repository: this);

return results?.isNotEmpty ?? false;
if (results?.isNotEmpty ?? false) return true;
}

return await sqliteProvider.exists<TModel>(query: query, repository: this);
Expand Down
2 changes: 2 additions & 0 deletions packages/brick_offline_first_with_supabase/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
## Unreleased

## 1.1.1

- Allow a generic type argument for `OfflineFirstWithSupabaseRepository`

## 1.1.0
Expand Down
2 changes: 1 addition & 1 deletion packages/brick_offline_first_with_supabase/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ homepage: https://github.com/GetDutchie/brick/tree/main/packages/brick_offline_f
issue_tracker: https://github.com/GetDutchie/brick/issues
repository: https://github.com/GetDutchie/brick

version: 1.1.0
version: 1.1.1

environment:
sdk: ">=3.0.0 <4.0.0"
Expand Down
5 changes: 5 additions & 0 deletions packages/brick_supabase/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
## Unreleased

## 1.1.3

- Add `query:` to `@Supabase` to override the generated query at runtime
- Support `@Supabase(query:)` in `QuerySupabaseTransformer` and `RuntimeSupabaseColumnDefinition`

## 1.1.2

- Add `'offset'` to Supabase's handled `Query(providerArgs:)`
Expand Down
9 changes: 9 additions & 0 deletions packages/brick_supabase/lib/src/annotations/supabase.dart
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,14 @@ class Supabase implements FieldSerializable {
@override
final bool ignoreTo;

/// Override the generated Supabase PostgREST query.
/// This will replace **all contents** of the query, including any
/// generated nested associations.
///
/// Advanced use only. It is strongly recommended to allow Brick to
/// generate the query at runtime based on the model definition.
final String? query;

/// This field reflects a unique index in the Supabase table, such as a primary key,
/// most often `id`.
///
Expand Down Expand Up @@ -90,6 +98,7 @@ class Supabase implements FieldSerializable {
bool? ignore,
bool? ignoreFrom,
bool? ignoreTo,
this.query,
bool? unique,
this.name,
bool? nullable,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,11 @@ class QuerySupabaseTransformer<_Model extends SupabaseModel> {

for (final entry in columns.entries) {
final field = entry.value;
if (field.query != null) {
if (field.query! != '') selectedFields.add(field.query!);
continue;
}

if (field.association && field.associationType != null) {
var associationOutput = field.columnName;
if (modelDictionary.adapterFor[field.associationType!]?.supabaseTableName != null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,15 @@ class RuntimeSupabaseColumnDefinition {
/// (e.g. `customer:customers(...)`)
final String? foreignKey;

/// Forwarded from `@Supabase(query:)`, this overrides the generated query.
final String? query;

const RuntimeSupabaseColumnDefinition({
this.association = false,
this.associationIsNullable = false,
this.associationType,
required this.columnName,
this.foreignKey,
this.query,
});
}
2 changes: 1 addition & 1 deletion packages/brick_supabase/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ homepage: https://github.com/GetDutchie/brick/tree/main/packages/brick_supabase
issue_tracker: https://github.com/GetDutchie/brick/issues
repository: https://github.com/GetDutchie/brick

version: 1.1.2
version: 1.1.3

environment:
sdk: ">=3.0.0 <4.0.0"
Expand Down
3 changes: 3 additions & 0 deletions packages/brick_supabase/test/__mocks_generated__.dart
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ class DemoAdapter extends SupabaseAdapter<Demo> {
'age': const RuntimeSupabaseColumnDefinition(
association: false,
columnName: 'age',
query: 'custom_age',
),
};

Expand Down Expand Up @@ -96,6 +97,8 @@ class DemoNestedAssociationModelAdapter extends SupabaseAdapter<DemoNestedAssoci
'name': const RuntimeSupabaseColumnDefinition(
association: false,
columnName: 'name',
// Test blank query to ensure it isn't added to request
query: '',
),
'nested': const RuntimeSupabaseColumnDefinition(
association: true,
Expand Down
41 changes: 20 additions & 21 deletions packages/brick_supabase/test/query_supabase_transformer_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -45,30 +45,30 @@ void main() {
group('#selectFields', () {
test('no association', () {
final transformer = _buildTransformer<Demo>();
expect(transformer.selectFields, 'id,name,age');
expect(transformer.selectFields, 'id,name,custom_age');
});

test('association', () {
final transformer = _buildTransformer<DemoAssociationModel>();
expect(
transformer.selectFields,
'id,name,assoc_id:demos!assoc_id(id,name,age),assocs:demos(id,name,age)',
'id,name,assoc_id:demos!assoc_id(id,name,custom_age),assocs:demos(id,name,custom_age)',
);
});

test('association', () {
final transformer = _buildTransformer<DemoNestedAssociationModel>();
expect(
transformer.selectFields,
'id,name,nested_column:demo_associations(id,name,assoc_id:demos!assoc_id(id,name,age),assocs:demos(id,name,age))',
'id,nested_column:demo_associations(id,name,assoc_id:demos!assoc_id(id,name,custom_age),assocs:demos(id,name,custom_age))',
);
});

test('recursive associations', () {
final transformer = _buildTransformer<RecursiveParent>();
expect(
transformer.selectFields,
'child:recursive_children(parent:recursive_parents(parent_id),child_id,other_assoc:demos(id,name,age)),parent_id',
'child:recursive_children(parent:recursive_parents(parent_id),child_id,other_assoc:demos(id,name,custom_age)),parent_id',
);
});
});
Expand All @@ -78,7 +78,7 @@ void main() {
final select =
_buildTransformer<Demo>().select(_supabaseClient.from(DemoAdapter().supabaseTableName));

expect(select.query, 'select=id,name,age');
expect(select.query, 'select=id,name,custom_age');
});

group('with query', () {
Expand All @@ -88,7 +88,7 @@ void main() {
final select = _buildTransformer<Demo>(query)
.select(_supabaseClient.from(DemoAdapter().supabaseTableName));

expect(select.query, 'select=id,name,age&name=eq.Jens');
expect(select.query, 'select=id,name,custom_age&name=eq.Jens');
});

test('by association field', () {
Expand All @@ -98,7 +98,7 @@ void main() {

expect(
select.query,
'select=id,name,assoc_id:demos!assoc_id(id,name,age),assocs:demos(id,name,age)&demos.name=eq.Thomas&assoc=not.is.null',
'select=id,name,assoc_id:demos!assoc_id(id,name,custom_age),assocs:demos(id,name,custom_age)&demos.name=eq.Thomas&assoc=not.is.null',
);
});
});
Expand All @@ -110,7 +110,7 @@ void main() {
final select = _buildTransformer<Demo>(query)
.select(_supabaseClient.from(DemoAdapter().supabaseTableName));

expect(select.query, 'select=id,name,age&name=neq.Jens');
expect(select.query, 'select=id,name,custom_age&name=neq.Jens');
});

test('lt/gt/lte/gte', () {
Expand All @@ -127,7 +127,7 @@ void main() {

expect(
select.query,
'select=id,name,age&age=lt.30&age=gt.18&age=lte.25&age=gte.21',
'select=id,name,custom_age&age=lt.30&age=gt.18&age=lte.25&age=gte.21',
);
});

Expand All @@ -138,7 +138,7 @@ void main() {
final select = _buildTransformer<Demo>(query)
.select(_supabaseClient.from(DemoAdapter().supabaseTableName));

expect(select.query, 'select=id,name,age&name=like.search');
expect(select.query, 'select=id,name,custom_age&name=like.search');
});

test('does not contain', () {
Expand All @@ -150,7 +150,7 @@ void main() {
final select = _buildTransformer<Demo>(query)
.select(_supabaseClient.from(DemoAdapter().supabaseTableName));

expect(select.query, 'select=id,name,age&name=not.like.search');
expect(select.query, 'select=id,name,custom_age&name=not.like.search');
});
});
});
Expand All @@ -165,7 +165,7 @@ void main() {

expect(
transformBuilder.query,
'select=id,name,age&order=name.asc.nullslast',
'select=id,name,custom_age&order=name.asc.nullslast',
);
});

Expand All @@ -178,7 +178,7 @@ void main() {

expect(
transformBuilder.query,
'select=id,name,age&order=name.desc.nullslast',
'select=id,name,custom_age&order=name.desc.nullslast',
);
});

Expand All @@ -193,7 +193,7 @@ void main() {

expect(
transformBuilder.query,
'select=id,name,age&foreign_tables.order=name.desc.nullslast',
'select=id,name,custom_age&foreign_tables.order=name.desc.nullslast',
);
});

Expand All @@ -204,7 +204,7 @@ void main() {
queryTransformer.select(_supabaseClient.from(DemoAdapter().supabaseTableName));
final transformBuilder = queryTransformer.applyProviderArgs(filterBuilder);

expect(transformBuilder.query, 'select=id,name,age&limit=10');
expect(transformBuilder.query, 'select=id,name,custom_age&limit=10');
});

test('limit with referenced table', () {
Expand All @@ -214,7 +214,7 @@ void main() {
queryTransformer.select(_supabaseClient.from(DemoAdapter().supabaseTableName));
final transformBuilder = queryTransformer.applyProviderArgs(filterBuilder);

expect(transformBuilder.query, 'select=id,name,age&foreign_tables.limit=10');
expect(transformBuilder.query, 'select=id,name,custom_age&foreign_tables.limit=10');
});

test('combined orderBy and limit', () {
Expand All @@ -226,7 +226,7 @@ void main() {

expect(
transformBuilder.query,
'select=id,name,age&order=name.desc.nullslast&limit=20',
'select=id,name,custom_age&order=name.desc.nullslast&limit=20',
);
});
});
Expand All @@ -239,7 +239,7 @@ void main() {
);
expect(
result,
containsAll(['id', 'name', 'assoc_id:demos!assoc_id(id,name,age)']),
containsAll(['id', 'name', 'assoc_id:demos!assoc_id(id,name,custom_age)']),
);
});

Expand All @@ -250,7 +250,7 @@ void main() {
);
expect(
result,
containsAll(['id', 'name', 'assoc_id:demos!assoc_id(id,name,age)']),
containsAll(['id', 'name', 'assoc_id:demos!assoc_id(id,name,custom_age)']),
);
});

Expand All @@ -263,8 +263,7 @@ void main() {
result,
containsAll([
'id',
'name',
'nested_column:demo_associations(id,name,assoc_id:demos!assoc_id(id,name,age),assocs:demos(id,name,age))',
'nested_column:demo_associations(id,name,assoc_id:demos!assoc_id(id,name,custom_age),assocs:demos(id,name,custom_age))',
]),
);
});
Expand Down
4 changes: 4 additions & 0 deletions packages/brick_supabase_generators/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
## Unreleased

## 1.0.2

- Interpret `@Supabase(query:)` in `SupabaseFields`

## 1.0.1

- Apply `@Supabase(foreignKey:)` to `RuntimeSupabaseColumnDefinition#foreignKey`
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ class SupabaseAnnotationFinder extends AnnotationFinder<Supabase>
SupabaseSerializable.defaults.fieldRename,
),
nullable: obj.getField('nullable')!.toBoolValue() ?? Supabase.defaults.nullable,
query: obj.getField('query')?.toStringValue(),
toGenerator: obj.getField('toGenerator')!.toStringValue(),
unique: obj.getField('unique')!.toBoolValue() ?? Supabase.defaults.unique,
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ class SupabaseSerialize extends SupabaseSerdesGenerator
if (isAssociation) definition += 'associationType: ${checker.withoutNullResultType},';
if (isAssociation) definition += 'associationIsNullable: ${checker.isNullable},';
if (annotation.foreignKey != null) definition += "foreignKey: '${annotation.foreignKey}',";
if (annotation.query != null) definition += "query: '''${annotation.query}''',";
definition += ')';
fieldsToColumns.add(definition);

Expand Down
4 changes: 2 additions & 2 deletions packages/brick_supabase_generators/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ homepage: https://github.com/GetDutchie/brick/tree/main/packages/brick_supabase_
issue_tracker: https://github.com/GetDutchie/brick/issues
repository: https://github.com/GetDutchie/brick

version: 1.0.1+3
version: 1.0.2

environment:
sdk: ">=3.0.0 <4.0.0"
Expand All @@ -14,7 +14,7 @@ dependencies:
brick_build: ">=3.2.0 <4.0.0"
brick_core: ">=1.2.1 <2.0.0"
brick_json_generators: ">=3.1.0 <4.0.0"
brick_supabase: ">=1.0.2+1 <2.0.0"
brick_supabase: ">=1.1.3 <2.0.0"
build: ">=2.0.0 <3.0.0"
dart_style: ">=2.0.0 <3.0.0"
source_gen: ">=1.2.2 <2.0.0"
Expand Down
Loading

0 comments on commit a7a77b0

Please sign in to comment.