diff --git a/packages/core/postgrest-js/src/PostgrestFilterBuilder.ts b/packages/core/postgrest-js/src/PostgrestFilterBuilder.ts index 395a8fc1e..60e6ef1dd 100644 --- a/packages/core/postgrest-js/src/PostgrestFilterBuilder.ts +++ b/packages/core/postgrest-js/src/PostgrestFilterBuilder.ts @@ -12,6 +12,7 @@ type FilterOperator = | 'like' | 'ilike' | 'is' + | 'isdistinct' | 'in' | 'cs' | 'cd' @@ -25,6 +26,8 @@ type FilterOperator = | 'plfts' | 'phfts' | 'wfts' + | 'match' + | 'imatch' export type IsStringOperator = Path extends `${string}->>${string}` ? true @@ -273,6 +276,34 @@ export default class PostgrestFilterBuilder< return this } + regexMatch(column: ColumnName, pattern: string): this + regexMatch(column: string, pattern: string): this + /** + * Match only rows where `column` matches the PostgreSQL regex `pattern` + * case-sensitively (using the `~` operator). + * + * @param column - The column to filter on + * @param pattern - The PostgreSQL regular expression pattern to match with + */ + regexMatch(column: string, pattern: string): this { + this.url.searchParams.append(column, `match.${pattern}`) + return this + } + + regexIMatch(column: ColumnName, pattern: string): this + regexIMatch(column: string, pattern: string): this + /** + * Match only rows where `column` matches the PostgreSQL regex `pattern` + * case-insensitively (using the `~*` operator). + * + * @param column - The column to filter on + * @param pattern - The PostgreSQL regular expression pattern to match with + */ + regexIMatch(column: string, pattern: string): this { + this.url.searchParams.append(column, `imatch.${pattern}`) + return this + } + is( column: ColumnName, value: Row[ColumnName] & (boolean | null) @@ -295,6 +326,28 @@ export default class PostgrestFilterBuilder< return this } + /** + * Match only rows where `column` IS DISTINCT FROM `value`. + * + * Unlike `.neq()`, this treats `NULL` as a comparable value. Two `NULL` values + * are considered equal (not distinct), and comparing `NULL` with any non-NULL + * value returns true (distinct). + * + * @param column - The column to filter on + * @param value - The value to filter with + */ + isDistinct( + column: ColumnName, + value: ResolveFilterValue extends never + ? unknown + : ResolveFilterValue extends infer ResolvedFilterValue + ? ResolvedFilterValue + : never + ): this { + this.url.searchParams.append(column, `isdistinct.${value}`) + return this + } + /** * Match only rows where `column` is included in the `values` array. * diff --git a/packages/core/postgrest-js/test/filters.test.ts b/packages/core/postgrest-js/test/filters.test.ts index edf93db3c..1e6580196 100644 --- a/packages/core/postgrest-js/test/filters.test.ts +++ b/packages/core/postgrest-js/test/filters.test.ts @@ -778,3 +778,54 @@ test('filter on rpc', async () => { } `) }) + +test('isDistinct', async () => { + const res = await postgrest.from('users').select('username').isDistinct('status', 'ONLINE') + expect(res).toMatchInlineSnapshot(` + { + "count": null, + "data": [ + { + "username": "kiwicopple", + }, + ], + "error": null, + "status": 200, + "statusText": "OK", + } + `) +}) + +test('regexMatch', async () => { + const res = await postgrest.from('users').select('username').regexMatch('username', '^sup') + expect(res).toMatchInlineSnapshot(` + { + "count": null, + "data": [ + { + "username": "supabot", + }, + ], + "error": null, + "status": 200, + "statusText": "OK", + } + `) +}) + +test('regexIMatch', async () => { + const res = await postgrest.from('users').select('username').regexIMatch('username', '^SUP') + expect(res).toMatchInlineSnapshot(` + { + "count": null, + "data": [ + { + "username": "supabot", + }, + ], + "error": null, + "status": 200, + "statusText": "OK", + } + `) +})