Skip to content

Commit 9b38343

Browse files
committed
Add ParseField helper
This removes the duplication of parsing required for renamed fields and non-renamed fields.
1 parent 71fa773 commit 9b38343

File tree

1 file changed

+31
-83
lines changed

1 file changed

+31
-83
lines changed

src/select-query-parser.ts

Lines changed: 31 additions & 83 deletions
Original file line numberDiff line numberDiff line change
@@ -141,12 +141,12 @@ type ConstructFieldDefinition<
141141
: Child[]
142142
: never
143143
}
144+
: Field extends { name: string; type: infer T }
145+
? { [K in Field['name']]: T }
144146
: Field extends { name: string; original: string }
145147
? Field['original'] extends keyof Row
146148
? { [K in Field['name']]: Row[Field['original']] }
147149
: SelectQueryError<`Referencing missing column \`${Field['original']}\``>
148-
: Field extends { name: string; type: infer T }
149-
? { [K in Field['name']]: T }
150150
: Record<string, unknown>
151151

152152
/**
@@ -210,29 +210,19 @@ type ParseIdentifier<Input extends string> = ReadLetters<Input> extends [
210210
: ParserError<`No (possibly double-quoted) identifier at \`${Input}\``>
211211

212212
/**
213-
* Parses a node.
214-
* A node is one of the following:
215-
* - `*`
213+
* Parses a field without preceding field renaming.
214+
* A field is one of the following:
216215
* - `field`
217216
* - `field->json...`
218217
* - `field(nodes)`
219218
* - `field!hint(nodes)`
220219
* - `field!inner(nodes)`
221220
* - `field!hint!inner(nodes)`
222-
* - `renamed_field:field`
223-
* - `renamed_field:field->json...`
224-
* - `renamed_field:field(nodes)`
225-
* - `renamed_field:field!hint(nodes)`
226-
* - `renamed_field:field!inner(nodes)`
227-
* - `renamed_field:field!hint!inner(nodes)`
228221
*
229-
* TODO: casting operators `::text`, more support for JSON operators `->`, `->>`.
222+
* TODO: casting operators `::text`
230223
*/
231-
type ParseNode<Input extends string> = Input extends ''
224+
type ParseField<Input extends string> = Input extends ''
232225
? ParserError<'Empty string'>
233-
: // `*`
234-
Input extends `*${infer Remainder}`
235-
? [{ star: true }, EatWhitespace<Remainder>]
236226
: ParseIdentifier<Input> extends [infer Name, `${infer Remainder}`]
237227
? EatWhitespace<Remainder> extends `!inner${infer Remainder}`
238228
? ParseEmbeddedResource<EatWhitespace<Remainder>> extends [infer Fields, `${infer Remainder}`]
@@ -266,72 +256,6 @@ type ParseNode<Input extends string> = Input extends ''
266256
'Expected embedded resource after `!hint`'
267257
>
268258
: ParserError<'Expected identifier after `!`'>
269-
: EatWhitespace<Remainder> extends `:${infer Remainder}`
270-
? ParseIdentifier<EatWhitespace<Remainder>> extends [infer OriginalName, `${infer Remainder}`]
271-
? EatWhitespace<Remainder> extends `!inner${infer Remainder}`
272-
? ParseEmbeddedResource<EatWhitespace<Remainder>> extends [
273-
infer Fields,
274-
`${infer Remainder}`
275-
]
276-
? // `renamed_field:field!inner(nodes)`
277-
[{ name: Name; original: OriginalName; children: Fields }, EatWhitespace<Remainder>]
278-
: CreateParserErrorIfRequired<
279-
ParseEmbeddedResource<EatWhitespace<Remainder>>,
280-
'Expected embedded resource after `!inner`'
281-
>
282-
: EatWhitespace<Remainder> extends `!${infer Remainder}`
283-
? ParseIdentifier<EatWhitespace<Remainder>> extends [infer Hint, `${infer Remainder}`]
284-
? EatWhitespace<Remainder> extends `!inner${infer Remainder}`
285-
? ParseEmbeddedResource<EatWhitespace<Remainder>> extends [
286-
infer Fields,
287-
`${infer Remainder}`
288-
]
289-
? // `renamed_field:field!hint!inner(nodes)`
290-
[
291-
{ name: Name; original: OriginalName; hint: Hint; children: Fields },
292-
EatWhitespace<Remainder>
293-
]
294-
: CreateParserErrorIfRequired<
295-
ParseEmbeddedResource<EatWhitespace<Remainder>>,
296-
'Expected embedded resource after `!inner`'
297-
>
298-
: ParseEmbeddedResource<EatWhitespace<Remainder>> extends [
299-
infer Fields,
300-
`${infer Remainder}`
301-
]
302-
? // `renamed_field:field!hint(nodes)`
303-
[
304-
{
305-
name: Name
306-
original: OriginalName
307-
hint: Hint
308-
children: Fields
309-
},
310-
EatWhitespace<Remainder>
311-
]
312-
: CreateParserErrorIfRequired<
313-
ParseEmbeddedResource<EatWhitespace<Remainder>>,
314-
'Expected embedded resource after `!hint`'
315-
>
316-
: ParserError<'Expected identifier after `!`'>
317-
: ParseEmbeddedResource<EatWhitespace<Remainder>> extends [
318-
infer Fields,
319-
`${infer Remainder}`
320-
]
321-
? // `renamed_field:field(nodes)`
322-
[{ name: Name; original: OriginalName; children: Fields }, EatWhitespace<Remainder>]
323-
: ParseJsonAccessor<EatWhitespace<Remainder>> extends [
324-
infer _PropertyName,
325-
infer PropertyType,
326-
`${infer Remainder}`
327-
]
328-
? // `renamed_field:field->json...`
329-
[{ name: Name; type: PropertyType }, EatWhitespace<Remainder>]
330-
: ParseEmbeddedResource<EatWhitespace<Remainder>> extends ParserError<string>
331-
? ParseEmbeddedResource<EatWhitespace<Remainder>>
332-
: // `renamed_field:field`
333-
[{ name: Name; original: OriginalName }, EatWhitespace<Remainder>]
334-
: ParseIdentifier<EatWhitespace<Remainder>>
335259
: ParseEmbeddedResource<EatWhitespace<Remainder>> extends [infer Fields, `${infer Remainder}`]
336260
? // `field(nodes)`
337261
[{ name: Name; original: Name; children: Fields }, EatWhitespace<Remainder>]
@@ -341,13 +265,37 @@ type ParseNode<Input extends string> = Input extends ''
341265
`${infer Remainder}`
342266
]
343267
? // `field->json...`
344-
[{ name: PropertyName; type: PropertyType }, EatWhitespace<Remainder>]
268+
[{ name: PropertyName; original: PropertyName; type: PropertyType }, EatWhitespace<Remainder>]
345269
: ParseEmbeddedResource<EatWhitespace<Remainder>> extends ParserError<string>
346270
? ParseEmbeddedResource<EatWhitespace<Remainder>>
347271
: // `field`
348272
[{ name: Name; original: Name }, EatWhitespace<Remainder>]
349273
: ParserError<`Expected identifier at \`${Input}\``>
350274

275+
/**
276+
* Parses a node.
277+
* A node is one of the following:
278+
* - `*`
279+
* - a field, as defined above
280+
* - a renamed field, `renamed_field:field`
281+
*/
282+
type ParseNode<Input extends string> = Input extends ''
283+
? ParserError<'Empty string'>
284+
: // `*`
285+
Input extends `*${infer Remainder}`
286+
? [{ star: true }, EatWhitespace<Remainder>]
287+
: ParseIdentifier<Input> extends [infer Name, `${infer Remainder}`]
288+
? EatWhitespace<Remainder> extends `:${infer Remainder}`
289+
? // `renamed_field:`
290+
ParseField<EatWhitespace<Remainder>> extends [infer Field, `${infer Remainder}`]
291+
? Field extends { name: string }
292+
? [Prettify<Omit<Field, 'name'> & { name: Name }>, EatWhitespace<Remainder>]
293+
: ParserError<`Unable to parse renamed field`>
294+
: ParserError<`Unable to parse renamed field`>
295+
: // Otherwise, just parse it as a field without renaming.
296+
ParseField<Input>
297+
: ParserError<`Expected identifier at \`${Input}\``>
298+
351299
/**
352300
* Parses a JSON property accessor of the shape `->a->b->c`. The last accessor in
353301
* the series may convert to text by using the ->> operator instead of ->.

0 commit comments

Comments
 (0)