From 14910bf7bbaf0b19459d4b961ff3bcce8f64a6c5 Mon Sep 17 00:00:00 2001 From: Benjamin Tan Date: Thu, 8 Feb 2024 20:40:38 +0800 Subject: [PATCH] feat: query parser: handle empty embedded resources `()` Closes #445. --- src/select-query-parser.ts | 15 ++++++++++----- test/index.test-d.ts | 9 +++++++++ 2 files changed, 19 insertions(+), 5 deletions(-) diff --git a/src/select-query-parser.ts b/src/select-query-parser.ts index e44e1e44..2e798e29 100644 --- a/src/select-query-parser.ts +++ b/src/select-query-parser.ts @@ -202,6 +202,8 @@ type ConstructFieldDefinition< Field['children'], unknown > + : Field extends { children: [] } + ? {} : Field extends { name: string; original: string; hint: string; children: unknown[] } ? { [_ in Field['name']]: GetResultHelper< @@ -460,7 +462,7 @@ type ParseJsonAccessor = Input extends `->${infer Remainde /** * Parses an embedded resource, which is an opening `(`, followed by a sequence of - * nodes, separated by `,`, then a closing `)`. + * 0 or more nodes separated by `,`, then a closing `)`. * * Returns a tuple of ["Parsed fields", "Remainder of text"], an error, * or the original string input indicating that no opening `(` was found. @@ -468,11 +470,14 @@ type ParseJsonAccessor = Input extends `->${infer Remainde type ParseEmbeddedResource = Input extends `(${infer Remainder}` ? ParseNodes> extends [infer Fields, `${infer Remainder}`] ? EatWhitespace extends `)${infer Remainder}` - ? Fields extends [] - ? ParserError<'Expected fields after `(`'> - : [Fields, EatWhitespace] + ? [Fields, EatWhitespace] : ParserError<`Expected ")"`> - : ParseNodes> + : // If no nodes were detected, check for `)` for empty embedded resources `()`. + ParseNodes> extends ParserError + ? EatWhitespace extends `)${infer Remainder}` + ? [[], EatWhitespace] + : ParseNodes> + : ParserError<'Expected embedded resource fields or `)`'> : Input /** diff --git a/test/index.test-d.ts b/test/index.test-d.ts index 0129f5bd..3bd61e23 100644 --- a/test/index.test-d.ts +++ b/test/index.test-d.ts @@ -79,6 +79,15 @@ const postgrest = new PostgrestClient(REST_URL) ) } +// embedded resource with no fields +{ + const { data, error } = await postgrest.from('messages').select('message, users()').single() + if (error) { + throw new Error(error.message) + } + expectType<{ message: string | null }>(data) +} + // json accessor in select query { const { data, error } = await postgrest