diff --git a/packages/postgrest/lib/src/postgrest_filter_builder.dart b/packages/postgrest/lib/src/postgrest_filter_builder.dart index 97798fe6a..b922903ba 100644 --- a/packages/postgrest/lib/src/postgrest_filter_builder.dart +++ b/packages/postgrest/lib/src/postgrest_filter_builder.dart @@ -476,6 +476,45 @@ class PostgrestFilterBuilder extends PostgrestTransformBuilder { return copyWithUrl(url); } + /// Finds all rows whose value in the stated [column] matches the supplied [pattern] using PostgreSQL regular expression (case sensitive). + /// + /// ```dart + /// await supabase + /// .from('users') + /// .select() + /// .matchRegex('username', '^sup.*'); + /// ``` + PostgrestFilterBuilder matchRegex(String column, String pattern) { + return copyWithUrl(appendSearchParams(column, 'match.$pattern')); + } + + /// Finds all rows whose value in the stated [column] matches the supplied [pattern] using PostgreSQL regular expression (case insensitive). + /// + /// ```dart + /// await supabase + /// .from('users') + /// .select() + /// .imatchRegex('username', '^SUP.*'); + /// ``` + PostgrestFilterBuilder imatchRegex(String column, String pattern) { + return copyWithUrl(appendSearchParams(column, 'imatch.$pattern')); + } + + /// Finds all rows whose value on the stated [column] is not equal to the specified [value], treating `NULL` as a comparable value. + /// + /// This is different from [neq] which treats `NULL` specially. + /// + /// ```dart + /// await supabase + /// .from('users') + /// .select() + /// .isDistinct('age', null); + /// ``` + // ignore: non_constant_identifier_names + PostgrestFilterBuilder isDistinct(String column, Object? value) { + return copyWithUrl(appendSearchParams(column, 'isdistinct.$value')); + } + @override PostgrestFilterBuilder setHeader(String key, String value) { return PostgrestFilterBuilder( diff --git a/packages/postgrest/test/filter_test.dart b/packages/postgrest/test/filter_test.dart index 606a3ac6f..220c27d15 100644 --- a/packages/postgrest/test/filter_test.dart +++ b/packages/postgrest/test/filter_test.dart @@ -477,6 +477,42 @@ void main() { expect(res[0]['username'], 'supabot'); }); + test('matchRegex - regex match (case sensitive)', () async { + final res = await postgrest + .from('users') + .select('username') + .matchRegex('username', '^supa.*'); + expect(res, isNotEmpty); + for (final item in res) { + expect((item['username'] as String).startsWith('supa'), true); + } + }); + + test('imatchRegex - regex match (case insensitive)', () async { + final res = await postgrest + .from('users') + .select('username') + .imatchRegex('username', '^SUPA.*'); + expect(res, isNotEmpty); + for (final item in res) { + expect( + (item['username'] as String).toLowerCase().startsWith('supa'), true); + } + }); + + test('isDistinct - treats NULL as comparable', () async { + final res = await postgrest + .from('users') + .select('username, data') + .isDistinct('data', null); + expect(res, isNotEmpty); + // isDistinct should return rows where data IS DISTINCT FROM null + // which means rows where data is NOT null + for (final item in res) { + expect(item['data'] != null, true); + } + }); + test('filter on rpc', () async { final List res = await postgrest.rpc('get_username_and_status', params: {'name_param': 'supabot'}).neq('status', 'ONLINE');