@@ -40,6 +40,68 @@ type Letter = Alphabet | Digit | '_'
40
40
41
41
type Json = string | number | boolean | null | { [ key : string ] : Json } | Json [ ]
42
42
43
+ type SingleValuePostgreSQLTypes =
44
+ | 'bool'
45
+ | 'int2'
46
+ | 'int4'
47
+ | 'int8'
48
+ | 'float4'
49
+ | 'float8'
50
+ | 'numeric'
51
+ | 'bytea'
52
+ | 'bpchar'
53
+ | 'varchar'
54
+ | 'date'
55
+ | 'text'
56
+ | 'citext'
57
+ | 'time'
58
+ | 'timetz'
59
+ | 'timestamp'
60
+ | 'timestamptz'
61
+ | 'uuid'
62
+ | 'vector'
63
+ | 'json'
64
+ | 'jsonb'
65
+ | 'void'
66
+ | 'record'
67
+ | string
68
+
69
+ type ArrayPostgreSQLTypes = `_${SingleValuePostgreSQLTypes } `
70
+
71
+ type PostgreSQLTypes = SingleValuePostgreSQLTypes | ArrayPostgreSQLTypes
72
+
73
+ type TypeScriptSingleValueTypes < T extends SingleValuePostgreSQLTypes > = T extends 'bool'
74
+ ? boolean
75
+ : T extends 'int2' | 'int4' | 'int8' | 'float4' | 'float8' | 'numeric'
76
+ ? number
77
+ : T extends
78
+ | 'bytea'
79
+ | 'bpchar'
80
+ | 'varchar'
81
+ | 'date'
82
+ | 'text'
83
+ | 'citext'
84
+ | 'time'
85
+ | 'timetz'
86
+ | 'timestamp'
87
+ | 'timestamptz'
88
+ | 'uuid'
89
+ | 'vector'
90
+ ? string
91
+ : T extends 'json' | 'jsonb'
92
+ ? Json
93
+ : T extends 'void'
94
+ ? undefined
95
+ : T extends 'record'
96
+ ? Record < string , unknown >
97
+ : unknown
98
+
99
+ type StripUnderscore < T extends string > = T extends `_${infer U } ` ? U : T
100
+
101
+ type TypeScriptTypes < T extends PostgreSQLTypes > = T extends ArrayPostgreSQLTypes
102
+ ? TypeScriptSingleValueTypes < StripUnderscore < Extract < T , SingleValuePostgreSQLTypes > > > [ ]
103
+ : TypeScriptSingleValueTypes < T >
104
+
43
105
/**
44
106
* Parser errors.
45
107
*/
@@ -243,27 +305,36 @@ type ParseIdentifier<Input extends string> = ReadLetters<Input> extends [
243
305
* A node is one of the following:
244
306
* - `*`
245
307
* - `field`
308
+ * - `field::type`
246
309
* - `field->json...`
247
310
* - `field(nodes)`
248
311
* - `field!hint(nodes)`
249
312
* - `field!inner(nodes)`
250
313
* - `field!hint!inner(nodes)`
251
314
* - `renamed_field:field`
315
+ * - `renamed_field:field::type`
252
316
* - `renamed_field:field->json...`
253
317
* - `renamed_field:field(nodes)`
254
318
* - `renamed_field:field!hint(nodes)`
255
319
* - `renamed_field:field!inner(nodes)`
256
320
* - `renamed_field:field!hint!inner(nodes)`
257
321
*
258
- * TODO: casting operators `::text`, more support for JSON operators `->`, `->>`.
322
+ * TODO: more support for JSON operators `->`, `->>`.
259
323
*/
260
324
type ParseNode < Input extends string > = Input extends ''
261
325
? ParserError < 'Empty string' >
262
326
: // `*`
263
327
Input extends `*${infer Remainder } `
264
328
? [ { star : true } , EatWhitespace < Remainder > ]
265
329
: ParseIdentifier < Input > extends [ infer Name , `${infer Remainder } `]
266
- ? EatWhitespace < Remainder > extends `!inner${infer Remainder } `
330
+ ? EatWhitespace < Remainder > extends `::${infer Remainder } `
331
+ ? ParseIdentifier < Remainder > extends [ infer CastType , `${infer Remainder } `]
332
+ ? // `field::type`
333
+ CastType extends PostgreSQLTypes
334
+ ? [ { name : Name ; type : TypeScriptTypes < CastType > } , EatWhitespace < Remainder > ]
335
+ : never
336
+ : ParserError < `Unexpected type cast at \`${Input } \``>
337
+ : EatWhitespace < Remainder > extends `!inner${infer Remainder } `
267
338
? ParseEmbeddedResource < EatWhitespace < Remainder > > extends [ infer Fields , `${infer Remainder } `]
268
339
? // `field!inner(nodes)`
269
340
[ { name : Name ; original : Name ; children : Fields } , EatWhitespace < Remainder > ]
@@ -294,7 +365,14 @@ type ParseNode<Input extends string> = Input extends ''
294
365
: ParserError < 'Expected identifier after `!`' >
295
366
: EatWhitespace < Remainder > extends `:${infer Remainder } `
296
367
? ParseIdentifier < EatWhitespace < Remainder > > extends [ infer OriginalName , `${infer Remainder } `]
297
- ? EatWhitespace < Remainder > extends `!inner${infer Remainder } `
368
+ ? EatWhitespace < Remainder > extends `::${infer Remainder } `
369
+ ? ParseIdentifier < Remainder > extends [ infer CastType , `${infer Remainder } `]
370
+ ? // `renamed_field:field::type`
371
+ CastType extends PostgreSQLTypes
372
+ ? [ { name : Name ; type : TypeScriptTypes < CastType > } , EatWhitespace < Remainder > ]
373
+ : never
374
+ : ParserError < `Unexpected type cast at \`${Input } \``>
375
+ : EatWhitespace < Remainder > extends `!inner${infer Remainder } `
298
376
? ParseEmbeddedResource < EatWhitespace < Remainder > > extends [
299
377
infer Fields ,
300
378
`${infer Remainder } `
0 commit comments