Skip to content
This repository was archived by the owner on Oct 9, 2025. It is now read-only.

Commit d56d69a

Browse files
committed
feat: add vertical filtering on CUD
1 parent 11d9366 commit d56d69a

File tree

6 files changed

+86
-11
lines changed

6 files changed

+86
-11
lines changed

src/PostgrestClient.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import PostgrestQueryBuilder from './lib/PostgrestQueryBuilder'
2+
import PostgrestTransformBuilder from './lib/PostgrestTransformBuilder'
23
import { PostgrestBuilder } from './lib/types'
34

45
export default class PostgrestClient {
@@ -48,7 +49,7 @@ export default class PostgrestClient {
4849
* @param fn The function name to call.
4950
* @param params The parameters to pass to the function call.
5051
*/
51-
rpc<T = any>(fn: string, params?: object): PostgrestBuilder<T> {
52+
rpc<T = any>(fn: string, params?: object): PostgrestTransformBuilder<T> {
5253
const url = `${this.url}/rpc/${fn}`
5354
return new PostgrestQueryBuilder<T>(url, { headers: this.headers, schema: this.schema }).rpc(
5455
params

src/lib/PostgrestQueryBuilder.ts

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,6 @@
11
import { PostgrestBuilder } from './types'
22
import PostgrestFilterBuilder from './PostgrestFilterBuilder'
3-
4-
/**
5-
* CRUD
6-
*/
3+
import PostgrestTransformBuilder from './PostgrestTransformBuilder'
74

85
export default class PostgrestQueryBuilder<T> extends PostgrestBuilder<T> {
96
constructor(
@@ -17,7 +14,7 @@ export default class PostgrestQueryBuilder<T> extends PostgrestBuilder<T> {
1714
}
1815

1916
/**
20-
* Performs horizontal filtering with SELECT.
17+
* Performs vertical filtering with SELECT.
2118
*
2219
* @param columns The columns to retrieve, separated by commas.
2320
*/
@@ -103,9 +100,9 @@ export default class PostgrestQueryBuilder<T> extends PostgrestBuilder<T> {
103100
}
104101

105102
/** @internal */
106-
rpc(params?: object): PostgrestBuilder<T> {
103+
rpc(params?: object): PostgrestTransformBuilder<T> {
107104
this.method = 'POST'
108105
this.body = params
109-
return this
106+
return new PostgrestTransformBuilder(this)
110107
}
111108
}

src/lib/PostgrestTransformBuilder.ts

Lines changed: 27 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,30 @@ import { PostgrestBuilder, PostgrestSingleResponse } from './types'
55
*/
66

77
export default class PostgrestTransformBuilder<T> extends PostgrestBuilder<T> {
8+
/**
9+
* Performs vertical filtering with SELECT.
10+
*
11+
* @param columns The columns to retrieve, separated by commas.
12+
*/
13+
select(columns = '*'): this {
14+
// Remove whitespaces except when quoted
15+
let quoted = false
16+
const cleanedColumns = columns
17+
.split('')
18+
.map((c) => {
19+
if (/\s/.test(c) && !quoted) {
20+
return ''
21+
}
22+
if (c === '"') {
23+
quoted = !quoted
24+
}
25+
return c
26+
})
27+
.join('')
28+
this.url.searchParams.set('select', cleanedColumns)
29+
return this
30+
}
31+
832
/**
933
* Orders the result with the specified `column`.
1034
*
@@ -20,7 +44,7 @@ export default class PostgrestTransformBuilder<T> extends PostgrestBuilder<T> {
2044
nullsFirst = false,
2145
foreignTable,
2246
}: { ascending?: boolean; nullsFirst?: boolean; foreignTable?: string } = {}
23-
): PostgrestTransformBuilder<T> {
47+
): this {
2448
const key = typeof foreignTable === 'undefined' ? 'order' : `"${foreignTable}".order`
2549
this.url.searchParams.set(
2650
key,
@@ -38,7 +62,7 @@ export default class PostgrestTransformBuilder<T> extends PostgrestBuilder<T> {
3862
limit(
3963
count: number,
4064
{ foreignTable }: { foreignTable?: string } = {}
41-
): PostgrestTransformBuilder<T> {
65+
): this {
4266
const key = typeof foreignTable === 'undefined' ? 'limit' : `"${foreignTable}".limit`
4367
this.url.searchParams.set(key, `${count}`)
4468
return this
@@ -55,7 +79,7 @@ export default class PostgrestTransformBuilder<T> extends PostgrestBuilder<T> {
5579
from: number,
5680
to: number,
5781
{ foreignTable }: { foreignTable?: string } = {}
58-
): PostgrestTransformBuilder<T> {
82+
): this {
5983
const keyOffset = typeof foreignTable === 'undefined' ? 'offset' : `"${foreignTable}".offset`
6084
const keyLimit = typeof foreignTable === 'undefined' ? 'limit' : `"${foreignTable}".limit`
6185
this.url.searchParams.set(keyOffset, `${from}`)

test/__snapshots__/index.test.ts.snap

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1970,6 +1970,42 @@ Object {
19701970
}
19711971
`;
19721972

1973+
exports[`select on insert 1`] = `
1974+
Object {
1975+
"body": Array [
1976+
Object {
1977+
"status": "ONLINE",
1978+
},
1979+
],
1980+
"data": Array [
1981+
Object {
1982+
"status": "ONLINE",
1983+
},
1984+
],
1985+
"error": null,
1986+
"status": 201,
1987+
"statusText": "Created",
1988+
}
1989+
`;
1990+
1991+
exports[`select on stored procedure 1`] = `
1992+
Object {
1993+
"body": Array [
1994+
Object {
1995+
"status": "ONLINE",
1996+
},
1997+
],
1998+
"data": Array [
1999+
Object {
2000+
"status": "ONLINE",
2001+
},
2002+
],
2003+
"error": null,
2004+
"status": 200,
2005+
"statusText": "OK",
2006+
}
2007+
`;
2008+
19732009
exports[`single 1`] = `
19742010
Object {
19752011
"body": Object {

test/db/00-schema.sql

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,11 @@ RETURNS user_status AS $$
4242
SELECT status from users WHERE username=name_param;
4343
$$ LANGUAGE SQL IMMUTABLE;
4444

45+
CREATE FUNCTION public.get_username_and_status(name_param text)
46+
RETURNS TABLE(username text, status user_status) AS $$
47+
SELECT username, status from users WHERE username=name_param;
48+
$$ LANGUAGE SQL IMMUTABLE;
49+
4550
-- SECOND SCHEMA USERS
4651
CREATE TYPE personal.user_status AS ENUM ('ONLINE', 'OFFLINE');
4752
CREATE TABLE personal.users(

test/transforms.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,3 +28,15 @@ test('single on insert', async () => {
2828

2929
await postgrest.from('users').delete().eq('username', 'foo')
3030
})
31+
32+
test('select on insert', async () => {
33+
const res = await postgrest.from('users').insert({ username: 'foo' }).select('status')
34+
expect(res).toMatchSnapshot()
35+
36+
await postgrest.from('users').delete().eq('username', 'foo')
37+
})
38+
39+
test('select on stored procedure', async () => {
40+
const res = await postgrest.rpc('get_username_and_status', { name_param: 'supabot' }).select('status')
41+
expect(res).toMatchSnapshot()
42+
})

0 commit comments

Comments
 (0)