@uwdata/mosaic-sql
Version:
SQL query construction and analysis.
105 lines (95 loc) • 3.85 kB
text/typescript
import type { ColumnRefNode } from '../ast/column-ref.js';
import type { TableRefNode } from '../ast/table-ref.js';
import { ExprNode, type SQLNode } from '../ast/node.js';
import { ParamNode } from '../ast/param.js';
import { WindowDefNode } from '../ast/window.js';
import { column } from '../functions/column.js';
import { literal, verbatim } from '../functions/literal.js';
import { tableRef } from '../functions/table-ref.js';
import { parseIdentifier } from './string.js';
import { isArray, isParamLike, isString } from './type-check.js';
/**
* Interpret a value as a SQL AST node. String values are assumed to be
* column references. All other primitive values are interpreted as
* SQL literals. Dynamic parameters are interpreted as param AST nodes,
* while existing AST nodes are left as-is.
* @param value The value to interpret as a SQL AST node.
*/
export function asNode(value: unknown): ExprNode {
return isString(value)
? parseColumnRef(value)
: asLiteral(value);
}
/**
* Interpret a value as a verbatim SQL AST node. String values will be
* passed through to queries as verbatim text. All other primitive values
* are interpreted as SQL literals. Dynamic parameters are interpreted
* as param AST nodes, while existing AST nodes are left as-is.
* @param value The value to interpret as a verbatim AST node.
*/
export function asVerbatim(value: unknown): ExprNode {
return isString(value)
? verbatim(value)
: asLiteral(value);
}
/**
* Interpret a value as a literal AST node. All other primitive values
* are interpreted as SQL literals. Dynamic parameters are interpreted
* as param AST nodes, while existing AST nodes are left as-is.
* @param value The value to interpret as a literal AST node.
*/
export function asLiteral(value: unknown): ExprNode {
return value instanceof ExprNode ? value
: isParamLike(value) ? new ParamNode(value)
: literal(value);
}
/**
* Interpret a value as a table reference AST node. String values are parsed
* assuming dot ('.') delimiters (as in `schema.table`). Array values are
* interpreted as pre-parsed name paths (as in `['schema', 'table']`). Any
* other values are left as-is.
* @param value The value to interpret as a table reference AST node.
*/
export function asTableRef(value?: string | string[] | TableRefNode): TableRefNode | undefined {
return getTableRef(value);
}
/**
* Try to interpret a value as a table reference AST node. String values are
* parsed assuming dot ('.') delimiters (as in `schema.table`). Array values
* are interpreted as pre-parsed name paths (as in `['schema', 'table']`). Any
* other values are left as-is.
* @param value The value to interpret as a table reference.
*/
export function maybeTableRef(value: string | string[] | SQLNode): SQLNode {
return getTableRef(value)!;
}
function getTableRef<T>(value?: string | string[] | T): TableRefNode | T | undefined {
return isString(value) ? parseTableRef(value)
: isArray(value) ? tableRef(value)!
: value;
}
/**
* Parse a string as a column reference, potentially with
* dot ('.') delimited table, schema, and database references.
* @param ref The column reference string.
*/
export function parseColumnRef(ref: string): ColumnRefNode {
const ids = parseIdentifier(ref);
return column(ids.pop()!, tableRef(ids));
}
/**
* Parse a string as a table reference, potentially with
* dot ('.') delimited schema and database references.
* @param ref The table reference string.
*/
export function parseTableRef(ref: string): TableRefNode {
return tableRef(parseIdentifier(ref))!;
}
/**
* Create a new window definition node. The return value is an empty
* window definition. Use chained calls such as `partitionby` and `orderby`
* to specify the window settings.
*/
export function over() {
return new WindowDefNode();
}