@miuiu/postgrest
Version:
Isomorphic PostgREST client
272 lines • 13.3 kB
TypeScript
import { GenericSchema, Prettify } from "./types";
declare type Whitespace = " " | "\n" | "\t";
declare type LowerAlphabet = "a" | "b" | "c" | "d" | "e" | "f" | "g" | "h" | "i" | "j" | "k" | "l" | "m" | "n" | "o" | "p" | "q" | "r" | "s" | "t" | "u" | "v" | "w" | "x" | "y" | "z";
declare type Alphabet = LowerAlphabet | Uppercase<LowerAlphabet>;
declare type Digit = "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9" | "0";
declare type Letter = Alphabet | Digit | "_";
declare type Json = string | number | boolean | null | {
[key: string]: Json;
} | Json[];
/**
* Parser errors.
*/
declare type ParserError<Message extends string> = {
error: true;
} & Message;
declare type GenericStringError = ParserError<"Received a generic string">;
/**
* Trims whitespace from the left of the input.
*/
declare type EatWhitespace<Input extends string> = string extends Input ? GenericStringError : Input extends `${Whitespace}${infer Remainder}` ? EatWhitespace<Remainder> : Input;
/**
* Constructs a type definition for a single field of an object.
*
* @param Definitions Record of definitions, possibly generated from PostgREST's OpenAPI spec.
* @param Name Name of the table being queried.
* @param Field Single field parsed by `ParseQuery`.
*/
declare type ConstructFieldDefinition<Schema extends GenericSchema, Row extends Record<string, unknown>, Field> = Field extends {
star: true;
} ? Row : Field extends {
name: string;
original: string;
children: unknown[];
} ? {
[_ in Field["name"]]: GetResultHelper<Schema, (Schema["Tables"] & Schema["Views"])[Field["original"]]["Row"], Field["children"], unknown> extends infer Child ? Child | Child[] | null : never;
} : Field extends {
name: string;
original: string;
} ? {
[K in Field["name"]]: Row[Field["original"]];
} : Field extends {
name: string;
type: infer T;
} ? {
[K in Field["name"]]: T;
} : Record<string, unknown>;
/**
* Notes: all `Parse*` types assume that their input strings have their whitespace
* removed. They return tuples of ["Return Value", "Remainder of text"] or
* a `ParserError`.
*/
/**
* Reads a consecutive sequence of more than 1 letter,
* where letters are `[0-9a-zA-Z_]`.
*/
declare type ReadLetters<Input extends string> = string extends Input ? GenericStringError : ReadLettersHelper<Input, ""> extends [
`${infer Letters}`,
`${infer Remainder}`
] ? Letters extends "" ? ParserError<`Expected letter at \`${Input}\``> : [Letters, Remainder] : ReadLettersHelper<Input, "">;
declare type ReadLettersHelper<Input extends string, Acc extends string> = string extends Input ? GenericStringError : Input extends `${infer L}${infer Remainder}` ? L extends Letter ? ReadLettersHelper<Remainder, `${Acc}${L}`> : [Acc, Input] : [Acc, ""];
/**
* Reads a consecutive sequence of more than 1 double-quoted letters,
* where letters are `[^"]`.
*/
declare type ReadQuotedLetters<Input extends string> = string extends Input ? GenericStringError : Input extends `"${infer Remainder}` ? ReadQuotedLettersHelper<Remainder, ""> extends [
`${infer Letters}`,
`${infer Remainder}`
] ? Letters extends "" ? ParserError<`Expected string at \`${Remainder}\``> : [Letters, Remainder] : ReadQuotedLettersHelper<Remainder, ""> : ParserError<`Not a double-quoted string at \`${Input}\``>;
declare type ReadQuotedLettersHelper<Input extends string, Acc extends string> = string extends Input ? GenericStringError : Input extends `${infer L}${infer Remainder}` ? L extends '"' ? [Acc, Remainder] : ReadQuotedLettersHelper<Remainder, `${Acc}${L}`> : ParserError<`Missing closing double-quote in \`"${Acc}${Input}\``>;
/**
* Parses a (possibly double-quoted) identifier.
* For now, identifiers are just sequences of more than 1 letter.
*/
declare type ParseIdentifier<Input extends string> = ReadLetters<Input> extends [
infer Name,
`${infer Remainder}`
] ? [Name, `${Remainder}`] : ReadQuotedLetters<Input> extends [infer Name, `${infer Remainder}`] ? [Name, `${Remainder}`] : ParserError<`No (possibly double-quoted) identifier at \`${Input}\``>;
/**
* Parses a node.
* A node is one of the following:
* - `*`
* - `field`
* - `field->json...`
* - `field(nodes)`
* - `field!hint(nodes)`
* - `field!inner(nodes)`
* - `field!hint!inner(nodes)`
* - `renamed_field:field`
* - `renamed_field:field->json...`
* - `renamed_field:field(nodes)`
* - `renamed_field:field!hint(nodes)`
* - `renamed_field:field!inner(nodes)`
* - `renamed_field:field!hint!inner(nodes)`
*
* TODO: casting operators `::text`, more support for JSON operators `->`, `->>`.
*/
declare type ParseNode<Input extends string> = Input extends "" ? ParserError<"Empty string"> : Input extends `*${infer Remainder}` ? [{
star: true;
}, EatWhitespace<Remainder>] : ParseIdentifier<Input> extends [infer Name, `${infer Remainder}`] ? EatWhitespace<Remainder> extends `!inner${infer Remainder}` ? ParseEmbeddedResource<EatWhitespace<Remainder>> extends [
infer Fields,
`${infer Remainder}`
] ? [
{
name: Name;
original: Name;
children: Fields;
},
EatWhitespace<Remainder>
] : ParseEmbeddedResource<EatWhitespace<Remainder>> extends ParserError<string> ? ParseEmbeddedResource<EatWhitespace<Remainder>> : ParserError<"Expected embedded resource after `!inner`"> : EatWhitespace<Remainder> extends `!${infer Remainder}` ? ParseIdentifier<EatWhitespace<Remainder>> extends [
infer _Hint,
`${infer Remainder}`
] ? EatWhitespace<Remainder> extends `!inner${infer Remainder}` ? ParseEmbeddedResource<EatWhitespace<Remainder>> extends [
infer Fields,
`${infer Remainder}`
] ? [
{
name: Name;
original: Name;
children: Fields;
},
EatWhitespace<Remainder>
] : ParseEmbeddedResource<EatWhitespace<Remainder>> extends ParserError<string> ? ParseEmbeddedResource<EatWhitespace<Remainder>> : ParserError<"Expected embedded resource after `!inner`"> : ParseEmbeddedResource<EatWhitespace<Remainder>> extends [
infer Fields,
`${infer Remainder}`
] ? [
{
name: Name;
original: Name;
children: Fields;
},
EatWhitespace<Remainder>
] : ParseEmbeddedResource<EatWhitespace<Remainder>> extends ParserError<string> ? ParseEmbeddedResource<EatWhitespace<Remainder>> : ParserError<"Expected embedded resource after `!hint`"> : ParserError<"Expected identifier after `!`"> : EatWhitespace<Remainder> extends `:${infer Remainder}` ? ParseIdentifier<EatWhitespace<Remainder>> extends [
infer OriginalName,
`${infer Remainder}`
] ? EatWhitespace<Remainder> extends `!inner${infer Remainder}` ? ParseEmbeddedResource<EatWhitespace<Remainder>> extends [
infer Fields,
`${infer Remainder}`
] ? [
{
name: Name;
original: OriginalName;
children: Fields;
},
EatWhitespace<Remainder>
] : ParseEmbeddedResource<EatWhitespace<Remainder>> extends ParserError<string> ? ParseEmbeddedResource<EatWhitespace<Remainder>> : ParserError<"Expected embedded resource after `!inner`"> : EatWhitespace<Remainder> extends `!${infer Remainder}` ? ParseIdentifier<EatWhitespace<Remainder>> extends [
infer _Hint,
`${infer Remainder}`
] ? EatWhitespace<Remainder> extends `!inner${infer Remainder}` ? ParseEmbeddedResource<EatWhitespace<Remainder>> extends [
infer Fields,
`${infer Remainder}`
] ? [
{
name: Name;
original: OriginalName;
children: Fields;
},
EatWhitespace<Remainder>
] : ParseEmbeddedResource<EatWhitespace<Remainder>> extends ParserError<string> ? ParseEmbeddedResource<EatWhitespace<Remainder>> : ParserError<"Expected embedded resource after `!inner`"> : ParseEmbeddedResource<EatWhitespace<Remainder>> extends [
infer Fields,
`${infer Remainder}`
] ? [
{
name: Name;
original: OriginalName;
children: Fields;
},
EatWhitespace<Remainder>
] : ParseEmbeddedResource<EatWhitespace<Remainder>> extends ParserError<string> ? ParseEmbeddedResource<EatWhitespace<Remainder>> : ParserError<"Expected embedded resource after `!hint`"> : ParserError<"Expected identifier after `!`"> : ParseEmbeddedResource<EatWhitespace<Remainder>> extends [
infer Fields,
`${infer Remainder}`
] ? [
{
name: Name;
original: OriginalName;
children: Fields;
},
EatWhitespace<Remainder>
] : ParseJsonAccessor<EatWhitespace<Remainder>> extends [
infer _PropertyName,
infer PropertyType,
`${infer Remainder}`
] ? [
{
name: Name;
type: PropertyType;
},
EatWhitespace<Remainder>
] : ParseEmbeddedResource<EatWhitespace<Remainder>> extends ParserError<string> ? ParseEmbeddedResource<EatWhitespace<Remainder>> : [
{
name: Name;
original: OriginalName;
},
EatWhitespace<Remainder>
] : ParseIdentifier<EatWhitespace<Remainder>> : ParseEmbeddedResource<EatWhitespace<Remainder>> extends [
infer Fields,
`${infer Remainder}`
] ? [
{
name: Name;
original: Name;
children: Fields;
},
EatWhitespace<Remainder>
] : ParseJsonAccessor<EatWhitespace<Remainder>> extends [
infer PropertyName,
infer PropertyType,
`${infer Remainder}`
] ? [
{
name: PropertyName;
type: PropertyType;
},
EatWhitespace<Remainder>
] : ParseEmbeddedResource<EatWhitespace<Remainder>> extends ParserError<string> ? ParseEmbeddedResource<EatWhitespace<Remainder>> : [
{
name: Name;
original: Name;
},
EatWhitespace<Remainder>
] : ParserError<`Expected identifier at \`${Input}\``>;
/**
* Parses a JSON property accessor of the shape `->a->b->c`. The last accessor in
* the series may convert to text by using the ->> operator instead of ->.
*
* Returns a tuple of ["Last property name", "Last property type", "Remainder of text"]
* or the original string input indicating that no opening `->` was found.
*/
declare type ParseJsonAccessor<Input extends string> = Input extends `->${infer Remainder}` ? Remainder extends `>${infer Remainder}` ? ParseIdentifier<Remainder> extends [infer Name, `${infer Remainder}`] ? [Name, string, EatWhitespace<Remainder>] : ParserError<"Expected property name after `->>`"> : ParseIdentifier<Remainder> extends [infer Name, `${infer Remainder}`] ? ParseJsonAccessor<Remainder> extends [
infer PropertyName,
infer PropertyType,
`${infer Remainder}`
] ? [PropertyName, PropertyType, EatWhitespace<Remainder>] : [Name, Json, EatWhitespace<Remainder>] : ParserError<"Expected property name after `->`"> : Input;
/**
* Parses an embedded resource, which is an opening `(`, followed by a sequence of
* 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.
*/
declare type ParseEmbeddedResource<Input extends string> = Input extends `(${infer Remainder}` ? ParseNodes<EatWhitespace<Remainder>> extends [
infer Fields,
`${infer Remainder}`
] ? EatWhitespace<Remainder> extends `)${infer Remainder}` ? Fields extends [] ? ParserError<"Expected fields after `(`"> : [Fields, EatWhitespace<Remainder>] : ParserError<`Expected ")"`> : ParseNodes<EatWhitespace<Remainder>> : Input;
/**
* Parses a sequence of nodes, separated by `,`.
*
* Returns a tuple of ["Parsed fields", "Remainder of text"] or an error.
*/
declare type ParseNodes<Input extends string> = string extends Input ? GenericStringError : ParseNodesHelper<Input, []>;
declare type ParseNodesHelper<Input extends string, Fields extends unknown[]> = ParseNode<Input> extends [infer Field, `${infer Remainder}`] ? EatWhitespace<Remainder> extends `,${infer Remainder}` ? ParseNodesHelper<EatWhitespace<Remainder>, [Field, ...Fields]> : [[Field, ...Fields], EatWhitespace<Remainder>] : ParseNode<Input>;
/**
* Parses a query.
* A query is a sequence of nodes, separated by `,`, ensuring that there is
* no remaining input after all nodes have been parsed.
*
* Returns an array of parsed nodes, or an error.
*/
declare type ParseQuery<Query extends string> = string extends Query ? GenericStringError : ParseNodes<EatWhitespace<Query>> extends [
infer Fields,
`${infer Remainder}`
] ? EatWhitespace<Remainder> extends "" ? Fields : ParserError<`Unexpected input: ${Remainder}`> : ParseNodes<EatWhitespace<Query>>;
declare type GetResultHelper<Schema extends GenericSchema, Row extends Record<string, unknown>, Fields extends unknown[], Acc> = Fields extends [infer R] ? GetResultHelper<Schema, Row, [
], ConstructFieldDefinition<Schema, Row, R> & Acc> : Fields extends [infer R, ...infer Rest] ? GetResultHelper<Schema, Row, Rest, ConstructFieldDefinition<Schema, Row, R> & Acc> : Prettify<Acc>;
/**
* Constructs a type definition for an object based on a given PostgREST query.
*
* @param Row Record<string, unknown>.
* @param Query Select query string literal to parse.
*/
export declare type GetResult<Schema extends GenericSchema, Row extends Record<string, unknown>, Query extends string> = ParseQuery<Query> extends unknown[] ? GetResultHelper<Schema, Row, ParseQuery<Query>, unknown> : ParseQuery<Query>;
export {};
//# sourceMappingURL=select-query-parser.d.ts.map