Skip to content

Commit bcbd0f4

Browse files
committed
Add support for ... spread operator
1 parent 9b38343 commit bcbd0f4

File tree

2 files changed

+44
-0
lines changed

2 files changed

+44
-0
lines changed

src/select-query-parser.ts

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,16 @@ type ConstructFieldDefinition<
105105
Field
106106
> = Field extends { star: true }
107107
? Row
108+
: Field extends { spread: true; original: string; children: unknown[] }
109+
? GetResultHelper<
110+
Schema,
111+
(Schema['Tables'] & Schema['Views'])[Field['original']]['Row'],
112+
(Schema['Tables'] & Schema['Views'])[Field['original']] extends { Relationships: infer R }
113+
? R
114+
: unknown,
115+
Field['children'],
116+
unknown
117+
>
108118
: Field extends { name: string; original: string; hint: string; children: unknown[] }
109119
? {
110120
[_ in Field['name']]: GetResultHelper<
@@ -278,12 +288,20 @@ type ParseField<Input extends string> = Input extends ''
278288
* - `*`
279289
* - a field, as defined above
280290
* - a renamed field, `renamed_field:field`
291+
* - a spread field, `...field`
281292
*/
282293
type ParseNode<Input extends string> = Input extends ''
283294
? ParserError<'Empty string'>
284295
: // `*`
285296
Input extends `*${infer Remainder}`
286297
? [{ star: true }, EatWhitespace<Remainder>]
298+
: // `...field`
299+
Input extends `...${infer Remainder}`
300+
? ParseField<EatWhitespace<Remainder>> extends [infer Field, `${infer Remainder}`]
301+
? Field extends { children: unknown[] }
302+
? [Prettify<{ spread: true } & Field>, EatWhitespace<Remainder>]
303+
: ParserError<'Unable to parse spread resource'>
304+
: ParserError<'Unable to parse spread resource'>
287305
: ParseIdentifier<Input> extends [infer Name, `${infer Remainder}`]
288306
? EatWhitespace<Remainder> extends `:${infer Remainder}`
289307
? // `renamed_field:`

test/index.test-d.ts

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { expectError, expectType } from 'tsd'
22
import { PostgrestClient, PostgrestSingleResponse } from '../src/index'
33
import { SelectQueryError } from '../src/select-query-parser'
4+
import { Prettify } from '../src/types'
45
import { Database, Json } from './types'
56

67
const REST_URL = 'http://localhost:3000'
@@ -53,6 +54,31 @@ const postgrest = new PostgrestClient<Database>(REST_URL)
5354
expectError(postgrest.from('updatable_view').update({ non_updatable_column: 0 }))
5455
}
5556

57+
// spread resource with single column in select query
58+
{
59+
const { data, error } = await postgrest
60+
.from('messages')
61+
.select('message, ...users(status)')
62+
.single()
63+
if (error) {
64+
throw new Error(error.message)
65+
}
66+
expectType<{ message: string | null; status: Database['public']['Enums']['user_status'] | null }>(
67+
data
68+
)
69+
}
70+
71+
// spread resource with all columns in select query
72+
{
73+
const { data, error } = await postgrest.from('messages').select('message, ...users(*)').single()
74+
if (error) {
75+
throw new Error(error.message)
76+
}
77+
expectType<Prettify<{ message: string | null } & Database['public']['Tables']['users']['Row']>>(
78+
data
79+
)
80+
}
81+
5682
// json accessor in select query
5783
{
5884
const { data, error } = await postgrest

0 commit comments

Comments
 (0)