Skip to content

Commit 8228938

Browse files
grdsdevclaude
andcommitted
feat(postgrest): add missing PostgREST v12 operators
Adds three missing operators from PostgREST v12 specification: - matchRegex: PostgreSQL regex matching (~) - case sensitive - imatchRegex: PostgreSQL regex matching (~*) - case insensitive - isDistinct: IS DISTINCT FROM - treats NULL as comparable value All existing operators were reviewed and verified against v12 docs. Tests added for all new operators. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]>
1 parent cd4d6da commit 8228938

File tree

2 files changed

+75
-0
lines changed

2 files changed

+75
-0
lines changed

packages/postgrest/lib/src/postgrest_filter_builder.dart

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -476,6 +476,45 @@ class PostgrestFilterBuilder<T> extends PostgrestTransformBuilder<T> {
476476
return copyWithUrl(url);
477477
}
478478

479+
/// Finds all rows whose value in the stated [column] matches the supplied [pattern] using PostgreSQL regular expression (case sensitive).
480+
///
481+
/// ```dart
482+
/// await supabase
483+
/// .from('users')
484+
/// .select()
485+
/// .matchRegex('username', '^sup.*');
486+
/// ```
487+
PostgrestFilterBuilder<T> matchRegex(String column, String pattern) {
488+
return copyWithUrl(appendSearchParams(column, 'match.$pattern'));
489+
}
490+
491+
/// Finds all rows whose value in the stated [column] matches the supplied [pattern] using PostgreSQL regular expression (case insensitive).
492+
///
493+
/// ```dart
494+
/// await supabase
495+
/// .from('users')
496+
/// .select()
497+
/// .imatchRegex('username', '^SUP.*');
498+
/// ```
499+
PostgrestFilterBuilder<T> imatchRegex(String column, String pattern) {
500+
return copyWithUrl(appendSearchParams(column, 'imatch.$pattern'));
501+
}
502+
503+
/// Finds all rows whose value on the stated [column] is not equal to the specified [value], treating `NULL` as a comparable value.
504+
///
505+
/// This is different from [neq] which treats `NULL` specially.
506+
///
507+
/// ```dart
508+
/// await supabase
509+
/// .from('users')
510+
/// .select()
511+
/// .isDistinct('age', null);
512+
/// ```
513+
// ignore: non_constant_identifier_names
514+
PostgrestFilterBuilder<T> isDistinct(String column, Object? value) {
515+
return copyWithUrl(appendSearchParams(column, 'isdistinct.$value'));
516+
}
517+
479518
@override
480519
PostgrestFilterBuilder<T> setHeader(String key, String value) {
481520
return PostgrestFilterBuilder(

packages/postgrest/test/filter_test.dart

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -477,6 +477,42 @@ void main() {
477477
expect(res[0]['username'], 'supabot');
478478
});
479479

480+
test('matchRegex - regex match (case sensitive)', () async {
481+
final res = await postgrest
482+
.from('users')
483+
.select('username')
484+
.matchRegex('username', '^supa.*');
485+
expect(res, isNotEmpty);
486+
for (final item in res) {
487+
expect((item['username'] as String).startsWith('supa'), true);
488+
}
489+
});
490+
491+
test('imatchRegex - regex match (case insensitive)', () async {
492+
final res = await postgrest
493+
.from('users')
494+
.select('username')
495+
.imatchRegex('username', '^SUPA.*');
496+
expect(res, isNotEmpty);
497+
for (final item in res) {
498+
expect(
499+
(item['username'] as String).toLowerCase().startsWith('supa'), true);
500+
}
501+
});
502+
503+
test('isDistinct - treats NULL as comparable', () async {
504+
final res = await postgrest
505+
.from('users')
506+
.select('username, data')
507+
.isDistinct('data', null);
508+
expect(res, isNotEmpty);
509+
// isDistinct should return rows where data IS DISTINCT FROM null
510+
// which means rows where data is NOT null
511+
for (final item in res) {
512+
expect(item['data'] != null, true);
513+
}
514+
});
515+
480516
test('filter on rpc', () async {
481517
final List res = await postgrest.rpc('get_username_and_status',
482518
params: {'name_param': 'supabot'}).neq('status', 'ONLINE');

0 commit comments

Comments
 (0)