Skip to content

Commit da38938

Browse files
authored
feat(postgrest): add isdistinct and regex pattern matching operators (#1875)
1 parent 5383755 commit da38938

File tree

2 files changed

+104
-0
lines changed

2 files changed

+104
-0
lines changed

packages/core/postgrest-js/src/PostgrestFilterBuilder.ts

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ type FilterOperator =
1212
| 'like'
1313
| 'ilike'
1414
| 'is'
15+
| 'isdistinct'
1516
| 'in'
1617
| 'cs'
1718
| 'cd'
@@ -25,6 +26,8 @@ type FilterOperator =
2526
| 'plfts'
2627
| 'phfts'
2728
| 'wfts'
29+
| 'match'
30+
| 'imatch'
2831

2932
export type IsStringOperator<Path extends string> = Path extends `${string}->>${string}`
3033
? true
@@ -273,6 +276,34 @@ export default class PostgrestFilterBuilder<
273276
return this
274277
}
275278

279+
regexMatch<ColumnName extends string & keyof Row>(column: ColumnName, pattern: string): this
280+
regexMatch(column: string, pattern: string): this
281+
/**
282+
* Match only rows where `column` matches the PostgreSQL regex `pattern`
283+
* case-sensitively (using the `~` operator).
284+
*
285+
* @param column - The column to filter on
286+
* @param pattern - The PostgreSQL regular expression pattern to match with
287+
*/
288+
regexMatch(column: string, pattern: string): this {
289+
this.url.searchParams.append(column, `match.${pattern}`)
290+
return this
291+
}
292+
293+
regexIMatch<ColumnName extends string & keyof Row>(column: ColumnName, pattern: string): this
294+
regexIMatch(column: string, pattern: string): this
295+
/**
296+
* Match only rows where `column` matches the PostgreSQL regex `pattern`
297+
* case-insensitively (using the `~*` operator).
298+
*
299+
* @param column - The column to filter on
300+
* @param pattern - The PostgreSQL regular expression pattern to match with
301+
*/
302+
regexIMatch(column: string, pattern: string): this {
303+
this.url.searchParams.append(column, `imatch.${pattern}`)
304+
return this
305+
}
306+
276307
is<ColumnName extends string & keyof Row>(
277308
column: ColumnName,
278309
value: Row[ColumnName] & (boolean | null)
@@ -295,6 +326,28 @@ export default class PostgrestFilterBuilder<
295326
return this
296327
}
297328

329+
/**
330+
* Match only rows where `column` IS DISTINCT FROM `value`.
331+
*
332+
* Unlike `.neq()`, this treats `NULL` as a comparable value. Two `NULL` values
333+
* are considered equal (not distinct), and comparing `NULL` with any non-NULL
334+
* value returns true (distinct).
335+
*
336+
* @param column - The column to filter on
337+
* @param value - The value to filter with
338+
*/
339+
isDistinct<ColumnName extends string>(
340+
column: ColumnName,
341+
value: ResolveFilterValue<Schema, Row, ColumnName> extends never
342+
? unknown
343+
: ResolveFilterValue<Schema, Row, ColumnName> extends infer ResolvedFilterValue
344+
? ResolvedFilterValue
345+
: never
346+
): this {
347+
this.url.searchParams.append(column, `isdistinct.${value}`)
348+
return this
349+
}
350+
298351
/**
299352
* Match only rows where `column` is included in the `values` array.
300353
*

packages/core/postgrest-js/test/filters.test.ts

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -778,3 +778,54 @@ test('filter on rpc', async () => {
778778
}
779779
`)
780780
})
781+
782+
test('isDistinct', async () => {
783+
const res = await postgrest.from('users').select('username').isDistinct('status', 'ONLINE')
784+
expect(res).toMatchInlineSnapshot(`
785+
{
786+
"count": null,
787+
"data": [
788+
{
789+
"username": "kiwicopple",
790+
},
791+
],
792+
"error": null,
793+
"status": 200,
794+
"statusText": "OK",
795+
}
796+
`)
797+
})
798+
799+
test('regexMatch', async () => {
800+
const res = await postgrest.from('users').select('username').regexMatch('username', '^sup')
801+
expect(res).toMatchInlineSnapshot(`
802+
{
803+
"count": null,
804+
"data": [
805+
{
806+
"username": "supabot",
807+
},
808+
],
809+
"error": null,
810+
"status": 200,
811+
"statusText": "OK",
812+
}
813+
`)
814+
})
815+
816+
test('regexIMatch', async () => {
817+
const res = await postgrest.from('users').select('username').regexIMatch('username', '^SUP')
818+
expect(res).toMatchInlineSnapshot(`
819+
{
820+
"count": null,
821+
"data": [
822+
{
823+
"username": "supabot",
824+
},
825+
],
826+
"error": null,
827+
"status": 200,
828+
"statusText": "OK",
829+
}
830+
`)
831+
})

0 commit comments

Comments
 (0)