/** * Reads what a SQL statement touches: which tables, which fields, and * what it picks rows by. * * A pack that finds a query written as SQL instead of through an ORM * passes the text here and gets back the same `SqlAccess` records its * own recognizer would have produced. The statement is parsed with a * grammar, so a join contributes every table it reads and a `WHERE` * contributes a selector. * * A statement the grammar rejects is rewritten and tried again. If it * still fails the result is empty, and nothing is guessed from the * words in the text. The README lists the dialects and what is left out. */ /** One table a statement touches, and what it does to it. */ interface SqlAccess { table: string; /** * The namespaces written in front of the table, outermost first. * BigQuery writes `project.dataset.table`, and keeping the whole * string as the table would record a name no provider declares. A * part the caller could not resolve, and every part outside it, is * left out. */ qualifier: string[]; kind: "read" | "write"; /** The fields the statement lists, or `["*"]` for a whole row. */ fields: string[]; /** The fields it picks rows by. */ selector: string[]; /** * The placeholder that gives a column its value, where the statement * writes one: `tenant_id = $1` in a `WHERE`, a column of an `INSERT` * and its place under `VALUES`, an assignment in a `SET`. Present only * when the caller asked for it and a column is given one. */ placeholders?: SqlPlaceholder[]; } /** One column the statement gives a placeholder's value. */ interface SqlPlaceholder { field: string; /** Which of the access's lists the column is in. */ clause: "fields" | "selector"; /** `$1` is 1, counted the way the driver counts; `:tenant` is `tenant`. */ placeholder: number | string; } interface SqlReadOptions { /** Which dialect the statement is written in. */ dialect?: string; /** Whether to say which placeholder gives each column its value. */ placeholders?: boolean; } /** Every table a statement touches. Empty when the dialect is unknown or the statement cannot be parsed. */ declare function readSqlAccess(sql: string, options?: SqlReadOptions): SqlAccess[]; /** A table name, split from the namespaces written in front of it. */ interface QualifiedTable { table: string; /** The namespaces in front of the table, outermost first. */ qualifier: string[]; } /** * Splits a table name from the namespaces written in front of it. * Returns null when the table itself came through as a parameter. A * pack that reads a table off a call's argument splits it here too, so * the result matches the same table read out of a statement. */ declare function splitQualifiedTable(name: string): QualifiedTable | null; /** * Joins a tagged template's parts into SQL, writing each interpolation * as a parameter (`$1`, `$2`). A query interpolates a value nearly every * time, and a parameter is how the statement would pass a value anyway, * so the text parses with the meaning it has at run time. * * `substitutions` replaces a hole wherever it is, for a caller that * knows the hole is a table, such as an interpolated schema object. * `settled` replaces a hole only where the statement writes a name. * Any other hole stays a parameter, and a statement with a parameter * where the grammar does not allow one parses to no accesses. */ declare function sqlFromParts(parts: readonly string[], substitutions?: ReadonlyArray, settled?: ReadonlyArray): string; export { type QualifiedTable, type SqlAccess, type SqlPlaceholder, type SqlReadOptions, readSqlAccess, splitQualifiedTable, sqlFromParts };