From 3cacb80c9b5fa3aa71c9d24d43cbcc10c89c8a32 Mon Sep 17 00:00:00 2001 From: Benjamin Tan Date: Thu, 8 Feb 2024 20:19:59 +0800 Subject: [PATCH] Add support for `...` spread operator --- src/select-query-parser.ts | 19 +++++++++++++++++++ test/index.test-d.ts | 26 ++++++++++++++++++++++++++ 2 files changed, 45 insertions(+) diff --git a/src/select-query-parser.ts b/src/select-query-parser.ts index 114d59d5..e44e1e44 100644 --- a/src/select-query-parser.ts +++ b/src/select-query-parser.ts @@ -191,6 +191,17 @@ type ConstructFieldDefinition< Field > = Field extends { star: true } ? Row + : Field extends { spread: true; original: string; children: unknown[] } + ? GetResultHelper< + Schema, + (Schema['Tables'] & Schema['Views'])[Field['original']]['Row'], + Field['original'], + (Schema['Tables'] & Schema['Views'])[Field['original']] extends { Relationships: infer R } + ? R + : unknown, + Field['children'], + unknown + > : Field extends { name: string; original: string; hint: string; children: unknown[] } ? { [_ in Field['name']]: GetResultHelper< @@ -394,12 +405,20 @@ type ParseField = Input extends '' * - `*` * - a field, as defined above * - a renamed field, `renamed_field:field` + * - a spread field, `...field` */ type ParseNode = Input extends '' ? ParserError<'Empty string'> : // `*` Input extends `*${infer Remainder}` ? [{ star: true }, EatWhitespace] + : // `...field` + Input extends `...${infer Remainder}` + ? ParseField> extends [infer Field, `${infer Remainder}`] + ? Field extends { children: unknown[] } + ? [Prettify<{ spread: true } & Field>, EatWhitespace] + : ParserError<'Unable to parse spread resource'> + : ParserError<'Unable to parse spread resource'> : ParseIdentifier extends [infer Name, `${infer Remainder}`] ? EatWhitespace extends `::${infer _Remainder}` ? // `field::` diff --git a/test/index.test-d.ts b/test/index.test-d.ts index 68c6350e..0129f5bd 100644 --- a/test/index.test-d.ts +++ b/test/index.test-d.ts @@ -1,6 +1,7 @@ import { expectError, expectType } from 'tsd' import { PostgrestClient, PostgrestSingleResponse } from '../src/index' import { SelectQueryError } from '../src/select-query-parser' +import { Prettify } from '../src/types' import { Database, Json } from './types' const REST_URL = 'http://localhost:3000' @@ -53,6 +54,31 @@ const postgrest = new PostgrestClient(REST_URL) expectError(postgrest.from('updatable_view').update({ non_updatable_column: 0 })) } +// spread resource with single column in select query +{ + const { data, error } = await postgrest + .from('messages') + .select('message, ...users(status)') + .single() + if (error) { + throw new Error(error.message) + } + expectType<{ message: string | null; status: Database['public']['Enums']['user_status'] | null }>( + data + ) +} + +// spread resource with all columns in select query +{ + const { data, error } = await postgrest.from('messages').select('message, ...users(*)').single() + if (error) { + throw new Error(error.message) + } + expectType>( + data + ) +} + // json accessor in select query { const { data, error } = await postgrest