rawsql-ts
Version:
[beta]High-performance SQL parser and AST analyzer written in TypeScript. Provides fast parsing and advanced transformation capabilities.
973 lines (972 loc) • 55.1 kB
JavaScript
import { PartitionByClause, OrderByClause, OrderByItem, SelectClause, SelectItem, Distinct, DistinctOn, SortDirection, NullsSortDirection, TableSource, SourceExpression, FromClause, JoinClause, JoinOnClause, JoinUsingClause, FunctionSource, SourceAliasExpression, WhereClause, GroupByClause, HavingClause, SubQuerySource, WindowFrameClause, LimitClause, ForClause, OffsetClause, WindowsClause as WindowClause, CommonTable, WithClause, FetchClause, FetchExpression, InsertClause, UpdateClause, SetClause, ReturningClause, SetClauseItem } from "../models/Clause";
import { BinarySelectQuery, SimpleSelectQuery, ValuesQuery } from "../models/SelectQuery";
import { SqlPrintToken, SqlPrintTokenType, SqlPrintTokenContainerType } from "../models/SqlPrintToken";
import { ValueList, ColumnReference, FunctionCall, UnaryExpression, BinaryExpression, LiteralValue, ParameterExpression, SwitchCaseArgument, CaseKeyValuePair, RawString, IdentifierString, ParenExpression, CastExpression, CaseExpression, ArrayExpression, BetweenExpression, StringSpecifierExpression, TypeValue, TupleExpression, WindowFrameExpression, QualifiedName, InlineQuery, WindowFrameSpec, WindowFrameBoundStatic, WindowFrameBoundaryValue } from "../models/ValueComponent";
import { ParameterCollector } from "../transformers/ParameterCollector";
import { IdentifierDecorator } from "./IdentifierDecorator";
import { ParameterDecorator } from "./ParameterDecorator";
import { InsertQuery } from "../models/InsertQuery";
import { UpdateQuery } from "../models/UpdateQuery";
import { CreateTableQuery } from "../models/CreateTableQuery";
export var ParameterStyle;
(function (ParameterStyle) {
ParameterStyle["Anonymous"] = "anonymous";
ParameterStyle["Indexed"] = "indexed";
ParameterStyle["Named"] = "named";
})(ParameterStyle || (ParameterStyle = {}));
export const PRESETS = {
mysql: {
identifierEscape: { start: '`', end: '`' },
parameterSymbol: '?',
parameterStyle: ParameterStyle.Anonymous,
},
postgres: {
identifierEscape: { start: '"', end: '"' },
parameterSymbol: '$',
parameterStyle: ParameterStyle.Indexed,
},
postgresWithNamedParams: {
identifierEscape: { start: '"', end: '"' },
parameterSymbol: ':',
parameterStyle: ParameterStyle.Named,
},
sqlserver: {
identifierEscape: { start: '[', end: ']' },
parameterSymbol: '@',
parameterStyle: ParameterStyle.Named,
},
sqlite: {
identifierEscape: { start: '"', end: '"' },
parameterSymbol: ':',
parameterStyle: ParameterStyle.Named,
},
oracle: {
identifierEscape: { start: '"', end: '"' },
parameterSymbol: ':',
parameterStyle: ParameterStyle.Named,
},
clickhouse: {
identifierEscape: { start: '`', end: '`' },
parameterSymbol: '?',
parameterStyle: ParameterStyle.Anonymous,
},
firebird: {
identifierEscape: { start: '"', end: '"' },
parameterSymbol: '?',
parameterStyle: ParameterStyle.Anonymous,
},
db2: {
identifierEscape: { start: '"', end: '"' },
parameterSymbol: '?',
parameterStyle: ParameterStyle.Anonymous,
},
snowflake: {
identifierEscape: { start: '"', end: '"' },
parameterSymbol: '?',
parameterStyle: ParameterStyle.Anonymous,
},
cloudspanner: {
identifierEscape: { start: '`', end: '`' },
parameterSymbol: '@',
parameterStyle: ParameterStyle.Named,
},
duckdb: {
identifierEscape: { start: '"', end: '"' },
parameterSymbol: '?',
parameterStyle: ParameterStyle.Anonymous,
},
cockroachdb: {
identifierEscape: { start: '"', end: '"' },
parameterSymbol: '$',
parameterStyle: ParameterStyle.Indexed,
},
athena: {
identifierEscape: { start: '"', end: '"' },
parameterSymbol: '?',
parameterStyle: ParameterStyle.Anonymous,
},
bigquery: {
identifierEscape: { start: '`', end: '`' },
parameterSymbol: '@',
parameterStyle: ParameterStyle.Named,
},
hive: {
identifierEscape: { start: '`', end: '`' },
parameterSymbol: '?',
parameterStyle: ParameterStyle.Anonymous,
},
mariadb: {
identifierEscape: { start: '`', end: '`' },
parameterSymbol: '?',
parameterStyle: ParameterStyle.Anonymous,
},
redshift: {
identifierEscape: { start: '"', end: '"' },
parameterSymbol: '$',
parameterStyle: ParameterStyle.Indexed,
},
flinksql: {
identifierEscape: { start: '`', end: '`' },
parameterSymbol: '?',
parameterStyle: ParameterStyle.Anonymous,
},
mongodb: {
identifierEscape: { start: '"', end: '"' },
parameterSymbol: '?',
parameterStyle: ParameterStyle.Anonymous,
},
};
export class SqlPrintTokenParser {
constructor(options) {
var _a, _b, _c, _d, _e, _f, _g;
this.handlers = new Map();
this.index = 1;
if (options === null || options === void 0 ? void 0 : options.preset) {
const preset = options.preset;
options = Object.assign(Object.assign({}, preset), options);
}
this.parameterDecorator = new ParameterDecorator({
prefix: typeof (options === null || options === void 0 ? void 0 : options.parameterSymbol) === 'string' ? options.parameterSymbol : (_b = (_a = options === null || options === void 0 ? void 0 : options.parameterSymbol) === null || _a === void 0 ? void 0 : _a.start) !== null && _b !== void 0 ? _b : ':',
suffix: typeof (options === null || options === void 0 ? void 0 : options.parameterSymbol) === 'object' ? options.parameterSymbol.end : '',
style: (_c = options === null || options === void 0 ? void 0 : options.parameterStyle) !== null && _c !== void 0 ? _c : 'named'
});
this.identifierDecorator = new IdentifierDecorator({
start: (_e = (_d = options === null || options === void 0 ? void 0 : options.identifierEscape) === null || _d === void 0 ? void 0 : _d.start) !== null && _e !== void 0 ? _e : '"',
end: (_g = (_f = options === null || options === void 0 ? void 0 : options.identifierEscape) === null || _f === void 0 ? void 0 : _f.end) !== null && _g !== void 0 ? _g : '"'
});
this.handlers.set(ValueList.kind, (expr) => this.visitValueList(expr));
this.handlers.set(ColumnReference.kind, (expr) => this.visitColumnReference(expr));
this.handlers.set(QualifiedName.kind, (expr) => this.visitQualifiedName(expr));
this.handlers.set(FunctionCall.kind, (expr) => this.visitFunctionCall(expr));
this.handlers.set(UnaryExpression.kind, (expr) => this.visitUnaryExpression(expr));
this.handlers.set(BinaryExpression.kind, (expr) => this.visitBinaryExpression(expr));
this.handlers.set(LiteralValue.kind, (expr) => this.visitLiteralValue(expr));
this.handlers.set(ParameterExpression.kind, (expr) => this.visitParameterExpression(expr));
this.handlers.set(SwitchCaseArgument.kind, (expr) => this.visitSwitchCaseArgument(expr));
this.handlers.set(CaseKeyValuePair.kind, (expr) => this.visitCaseKeyValuePair(expr));
this.handlers.set(RawString.kind, (expr) => this.visitRawString(expr));
this.handlers.set(IdentifierString.kind, (expr) => this.visitIdentifierString(expr));
this.handlers.set(ParenExpression.kind, (expr) => this.visitParenExpression(expr));
this.handlers.set(CastExpression.kind, (expr) => this.visitCastExpression(expr));
this.handlers.set(CaseExpression.kind, (expr) => this.visitCaseExpression(expr));
this.handlers.set(ArrayExpression.kind, (expr) => this.visitArrayExpression(expr));
this.handlers.set(BetweenExpression.kind, (expr) => this.visitBetweenExpression(expr));
this.handlers.set(StringSpecifierExpression.kind, (expr) => this.visitStringSpecifierExpression(expr));
this.handlers.set(TypeValue.kind, (expr) => this.visitTypeValue(expr));
this.handlers.set(TupleExpression.kind, (expr) => this.visitTupleExpression(expr));
this.handlers.set(InlineQuery.kind, (expr) => this.visitInlineQuery(expr));
this.handlers.set(WindowFrameExpression.kind, (expr) => this.visitWindowFrameExpression(expr));
this.handlers.set(WindowFrameSpec.kind, (expr) => this.visitWindowFrameSpec(expr));
this.handlers.set(WindowFrameBoundStatic.kind, (expr) => this.visitWindowFrameBoundStatic(expr));
this.handlers.set(WindowFrameBoundaryValue.kind, (expr) => this.visitWindowFrameBoundaryValue(expr));
this.handlers.set(PartitionByClause.kind, (expr) => this.visitPartitionByClause(expr));
this.handlers.set(OrderByClause.kind, (expr) => this.visitOrderByClause(expr));
this.handlers.set(OrderByItem.kind, (expr) => this.visitOrderByItem(expr));
// select
this.handlers.set(SelectItem.kind, (expr) => this.visitSelectItem(expr));
this.handlers.set(SelectClause.kind, (expr) => this.visitSelectClause(expr));
this.handlers.set(Distinct.kind, (expr) => this.visitDistinct(expr));
this.handlers.set(DistinctOn.kind, (expr) => this.visitDistinctOn(expr));
// from
this.handlers.set(TableSource.kind, (expr) => this.visitTableSource(expr));
this.handlers.set(FunctionSource.kind, (expr) => this.visitFunctionSource(expr));
this.handlers.set(SourceExpression.kind, (expr) => this.visitSourceExpression(expr));
this.handlers.set(SourceAliasExpression.kind, (expr) => this.visitSourceAliasExpression(expr));
this.handlers.set(FromClause.kind, (expr) => this.visitFromClause(expr));
this.handlers.set(JoinClause.kind, (expr) => this.visitJoinClause(expr));
this.handlers.set(JoinOnClause.kind, (expr) => this.visitJoinOnClause(expr));
this.handlers.set(JoinUsingClause.kind, (expr) => this.visitJoinUsingClause(expr));
// where
this.handlers.set(WhereClause.kind, (expr) => this.visitWhereClause(expr));
// group
this.handlers.set(GroupByClause.kind, (expr) => this.visitGroupByClause(expr));
this.handlers.set(HavingClause.kind, (expr) => this.visitHavingClause(expr));
this.handlers.set(WindowClause.kind, (expr) => this.visitWindowClause(expr));
this.handlers.set(WindowFrameClause.kind, (expr) => this.visitWindowFrameClause(expr));
this.handlers.set(LimitClause.kind, (expr) => this.visitLimitClause(expr));
this.handlers.set(OffsetClause.kind, (expr) => this.visitOffsetClause(expr));
this.handlers.set(FetchClause.kind, (expr) => this.visitFetchClause(expr));
this.handlers.set(FetchExpression.kind, (expr) => this.visitFetchExpression(expr));
this.handlers.set(ForClause.kind, (expr) => this.visitForClause(expr));
// With
this.handlers.set(WithClause.kind, (expr) => this.visitWithClause(expr));
this.handlers.set(CommonTable.kind, (expr) => this.visitCommonTable(expr));
// Query
this.handlers.set(SimpleSelectQuery.kind, (expr) => this.visitSimpleQuery(expr));
this.handlers.set(SubQuerySource.kind, (expr) => this.visitSubQuerySource(expr));
this.handlers.set(BinarySelectQuery.kind, (expr) => this.visitBinarySelectQuery(expr));
this.handlers.set(ValuesQuery.kind, (expr) => this.visitValuesQuery(expr));
this.handlers.set(TupleExpression.kind, (expr) => this.visitTupleExpression(expr));
this.handlers.set(InsertQuery.kind, (expr) => this.visitInsertQuery(expr));
this.handlers.set(InsertClause.kind, (expr) => this.visitInsertClause(expr));
this.handlers.set(UpdateQuery.kind, (expr) => this.visitUpdateQuery(expr));
this.handlers.set(UpdateClause.kind, (expr) => this.visitUpdateClause(expr));
this.handlers.set(SetClause.kind, (expr) => this.visitSetClause(expr));
this.handlers.set(SetClauseItem.kind, (expr) => this.visitSetClauseItem(expr));
this.handlers.set(ReturningClause.kind, (expr) => this.visitReturningClause(expr));
this.handlers.set(CreateTableQuery.kind, (expr) => this.visitCreateTableQuery(expr));
}
/**
* Pretty-prints a BinarySelectQuery (e.g., UNION, INTERSECT, EXCEPT).
* This will recursively print left and right queries, separated by the operator.
* @param arg BinarySelectQuery
*/
visitBinarySelectQuery(arg) {
const token = new SqlPrintToken(SqlPrintTokenType.container, '');
token.innerTokens.push(this.visit(arg.left));
token.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN);
token.innerTokens.push(new SqlPrintToken(SqlPrintTokenType.keyword, arg.operator.value, SqlPrintTokenContainerType.BinarySelectQueryOperator));
token.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN);
token.innerTokens.push(this.visit(arg.right));
return token;
}
/**
* Returns an array of tokens representing a comma followed by a space.
* This is a common pattern in SQL pretty-printing.
*/
static commaSpaceTokens() {
return [SqlPrintTokenParser.COMMA_TOKEN, SqlPrintTokenParser.SPACE_TOKEN];
}
static argumentCommaSpaceTokens() {
return [SqlPrintTokenParser.ARGUMENT_SPLIT_COMMA_TOKEN, SqlPrintTokenParser.SPACE_TOKEN];
}
visitQualifiedName(arg) {
const token = new SqlPrintToken(SqlPrintTokenType.container, '', SqlPrintTokenContainerType.QualifiedName);
if (arg.namespaces) {
for (let i = 0; i < arg.namespaces.length; i++) {
token.innerTokens.push(arg.namespaces[i].accept(this));
token.innerTokens.push(SqlPrintTokenParser.DOT_TOKEN);
}
}
token.innerTokens.push(arg.name.accept(this));
return token;
}
visitPartitionByClause(arg) {
// Print as: partition by ...
const token = new SqlPrintToken(SqlPrintTokenType.keyword, 'partition by', SqlPrintTokenContainerType.PartitionByClause);
token.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN);
token.innerTokens.push(this.visit(arg.value));
return token;
}
visitOrderByClause(arg) {
// Print as: order by ...
const token = new SqlPrintToken(SqlPrintTokenType.keyword, 'order by', SqlPrintTokenContainerType.OrderByClause);
token.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN);
for (let i = 0; i < arg.order.length; i++) {
if (i > 0)
token.innerTokens.push(...SqlPrintTokenParser.commaSpaceTokens());
token.innerTokens.push(this.visit(arg.order[i]));
}
return token;
}
/**
* Print an OrderByItem (expression [asc|desc] [nulls first|last])
*/
visitOrderByItem(arg) {
// arg: OrderByItem
const token = new SqlPrintToken(SqlPrintTokenType.container, '', SqlPrintTokenContainerType.OrderByItem);
token.innerTokens.push(this.visit(arg.value));
if (arg.sortDirection && arg.sortDirection !== SortDirection.Ascending) {
token.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN);
token.innerTokens.push(new SqlPrintToken(SqlPrintTokenType.keyword, 'desc'));
}
if (arg.nullsPosition) {
if (arg.nullsPosition === NullsSortDirection.First) {
token.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN);
token.innerTokens.push(new SqlPrintToken(SqlPrintTokenType.keyword, 'nulls first'));
}
else if (arg.nullsPosition === NullsSortDirection.Last) {
token.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN);
token.innerTokens.push(new SqlPrintToken(SqlPrintTokenType.keyword, 'nulls last'));
}
}
return token;
}
parse(arg) {
const token = this.visit(arg);
const paramsRaw = ParameterCollector.collect(arg).sort((a, b) => { var _a, _b; return ((_a = a.index) !== null && _a !== void 0 ? _a : 0) - ((_b = b.index) !== null && _b !== void 0 ? _b : 0); });
const style = this.parameterDecorator.style;
if (style === ParameterStyle.Named) {
// Named: { name: value, ... }
const paramsObj = {};
for (const p of paramsRaw) {
const key = p.name.value;
if (paramsObj.hasOwnProperty(key)) {
if (paramsObj[key] !== p.value) {
throw new Error(`Duplicate parameter name '${key}' with different values detected during query composition.`);
}
// If value is the same, skip (already set)
continue;
}
paramsObj[key] = p.value;
}
return { token, params: paramsObj };
}
else if (style === ParameterStyle.Indexed) {
// Indexed: [value1, value2, ...] (sorted by index)
const paramsArr = paramsRaw.map(p => p.value);
return { token, params: paramsArr };
}
else if (style === ParameterStyle.Anonymous) {
// Anonymous: [value1, value2, ...] (sorted by index, name is empty)
const paramsArr = paramsRaw.map(p => p.value);
return { token, params: paramsArr };
}
// Fallback (just in case)
return { token, params: [] };
}
visit(arg) {
const handler = this.handlers.get(arg.getKind());
if (handler) {
return handler(arg);
}
throw new Error(`[SqlPrintTokenParser] No handler for kind: ${arg.getKind().toString()}`);
}
visitValueList(arg) {
const token = new SqlPrintToken(SqlPrintTokenType.container, '', SqlPrintTokenContainerType.ValueList);
for (let i = 0; i < arg.values.length; i++) {
if (i > 0) {
token.innerTokens.push(...SqlPrintTokenParser.argumentCommaSpaceTokens());
}
token.innerTokens.push(this.visit(arg.values[i]));
}
return token;
}
visitColumnReference(arg) {
const token = new SqlPrintToken(SqlPrintTokenType.container, '', SqlPrintTokenContainerType.ColumnReference);
token.innerTokens.push(arg.qualifiedName.accept(this));
return token;
}
visitFunctionCall(arg) {
const token = new SqlPrintToken(SqlPrintTokenType.container, '', SqlPrintTokenContainerType.FunctionCall);
token.innerTokens.push(arg.qualifiedName.accept(this));
token.innerTokens.push(SqlPrintTokenParser.PAREN_OPEN_TOKEN);
if (arg.argument) {
token.innerTokens.push(this.visit(arg.argument));
}
token.innerTokens.push(SqlPrintTokenParser.PAREN_CLOSE_TOKEN);
if (arg.over) {
token.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN);
token.innerTokens.push(new SqlPrintToken(SqlPrintTokenType.keyword, 'over'));
if (arg.over instanceof IdentifierString) {
token.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN);
token.innerTokens.push(arg.over.accept(this));
}
else {
token.innerTokens.push(SqlPrintTokenParser.PAREN_OPEN_TOKEN);
token.innerTokens.push(this.visit(arg.over));
token.innerTokens.push(SqlPrintTokenParser.PAREN_CLOSE_TOKEN);
}
}
return token;
}
visitUnaryExpression(arg) {
const token = new SqlPrintToken(SqlPrintTokenType.container, '', SqlPrintTokenContainerType.UnaryExpression);
token.innerTokens.push(this.visit(arg.operator));
token.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN);
token.innerTokens.push(this.visit(arg.expression));
return token;
}
visitBinaryExpression(arg) {
const token = new SqlPrintToken(SqlPrintTokenType.container, '', SqlPrintTokenContainerType.BinaryExpression);
token.innerTokens.push(this.visit(arg.left));
token.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN);
token.innerTokens.push(new SqlPrintToken(SqlPrintTokenType.operator, arg.operator.value));
token.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN);
token.innerTokens.push(this.visit(arg.right));
return token;
}
visitLiteralValue(arg) {
let text;
if (typeof arg.value === "string") {
text = `'${arg.value.replace(/'/g, "''")}'`;
}
else if (arg.value === null) {
text = "null";
}
else {
text = arg.value.toString();
}
return new SqlPrintToken(SqlPrintTokenType.value, text, SqlPrintTokenContainerType.LiteralValue);
}
visitParameterExpression(arg) {
// Create a parameter token and decorate it using the parameterDecorator
arg.index = this.index;
const text = this.parameterDecorator.decorate(arg.name.value, arg.index);
const token = new SqlPrintToken(SqlPrintTokenType.parameter, text);
this.index++;
return token;
}
visitSwitchCaseArgument(arg) {
const token = new SqlPrintToken(SqlPrintTokenType.container, '', SqlPrintTokenContainerType.SwitchCaseArgument);
// Add each WHEN/THEN clause
for (const kv of arg.cases) {
// Create a new line for each WHEN clause
token.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN);
token.innerTokens.push(kv.accept(this));
}
// Add ELSE clause if present
if (arg.elseValue) {
token.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN);
token.innerTokens.push(this.createElseToken(arg.elseValue));
}
return token;
}
createElseToken(elseValue) {
// Creates a token for the ELSE clause in a CASE expression.
const elseToken = new SqlPrintToken(SqlPrintTokenType.container, '', SqlPrintTokenContainerType.ElseClause); // Add the ELSE keyword
elseToken.innerTokens.push(new SqlPrintToken(SqlPrintTokenType.keyword, 'else'));
// Create a container for the ELSE value to enable proper indentation
elseToken.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN);
const elseValueContainer = new SqlPrintToken(SqlPrintTokenType.container, '', SqlPrintTokenContainerType.CaseElseValue);
elseValueContainer.innerTokens.push(this.visit(elseValue));
elseToken.innerTokens.push(elseValueContainer);
return elseToken;
}
visitCaseKeyValuePair(arg) {
const token = new SqlPrintToken(SqlPrintTokenType.container, '', SqlPrintTokenContainerType.CaseKeyValuePair);
// Create WHEN clause
token.innerTokens.push(new SqlPrintToken(SqlPrintTokenType.keyword, 'when'));
token.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN);
token.innerTokens.push(this.visit(arg.key)); // Create THEN clause
token.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN);
token.innerTokens.push(new SqlPrintToken(SqlPrintTokenType.keyword, 'then'));
// Create a container for the THEN value to enable proper indentation
token.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN);
const thenValueContainer = new SqlPrintToken(SqlPrintTokenType.container, '', SqlPrintTokenContainerType.CaseThenValue);
thenValueContainer.innerTokens.push(this.visit(arg.value));
token.innerTokens.push(thenValueContainer);
return token;
}
visitRawString(arg) {
// Even for non-container tokens, set the container type for context
return new SqlPrintToken(SqlPrintTokenType.value, arg.value, SqlPrintTokenContainerType.RawString);
}
visitIdentifierString(arg) {
// Create an identifier token and decorate it using the identifierDecorator
const text = arg.name === "*" ? arg.name : this.identifierDecorator.decorate(arg.name);
const token = new SqlPrintToken(SqlPrintTokenType.value, text, SqlPrintTokenContainerType.IdentifierString);
return token;
}
visitParenExpression(arg) {
const token = new SqlPrintToken(SqlPrintTokenType.container, '', SqlPrintTokenContainerType.ParenExpression);
token.innerTokens.push(SqlPrintTokenParser.PAREN_OPEN_TOKEN);
token.innerTokens.push(this.visit(arg.expression));
token.innerTokens.push(SqlPrintTokenParser.PAREN_CLOSE_TOKEN);
return token;
}
visitCastExpression(arg) {
const token = new SqlPrintToken(SqlPrintTokenType.container, '', SqlPrintTokenContainerType.CastExpression);
token.innerTokens.push(this.visit(arg.input));
token.innerTokens.push(new SqlPrintToken(SqlPrintTokenType.operator, '::'));
token.innerTokens.push(this.visit(arg.castType));
return token;
}
visitCaseExpression(arg) {
const token = new SqlPrintToken(SqlPrintTokenType.container, '', SqlPrintTokenContainerType.CaseExpression);
// Add the CASE keyword
token.innerTokens.push(new SqlPrintToken(SqlPrintTokenType.keyword, 'case'));
// Add the condition if exists
if (arg.condition) {
token.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN);
token.innerTokens.push(this.visit(arg.condition));
}
// Add the WHEN/THEN pairs and ELSE
token.innerTokens.push(this.visit(arg.switchCase));
// Add the END keyword
token.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN);
token.innerTokens.push(new SqlPrintToken(SqlPrintTokenType.keyword, 'end'));
return token;
}
visitArrayExpression(arg) {
const token = new SqlPrintToken(SqlPrintTokenType.container, '', SqlPrintTokenContainerType.ArrayExpression);
token.innerTokens.push(new SqlPrintToken(SqlPrintTokenType.keyword, 'array'));
token.innerTokens.push(new SqlPrintToken(SqlPrintTokenType.parenthesis, '['));
token.innerTokens.push(this.visit(arg.expression));
token.innerTokens.push(new SqlPrintToken(SqlPrintTokenType.parenthesis, ']'));
return token;
}
visitBetweenExpression(arg) {
const token = new SqlPrintToken(SqlPrintTokenType.container, '', SqlPrintTokenContainerType.BetweenExpression);
token.innerTokens.push(this.visit(arg.expression));
token.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN);
if (arg.negated) {
token.innerTokens.push(new SqlPrintToken(SqlPrintTokenType.keyword, 'not'));
token.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN);
}
token.innerTokens.push(new SqlPrintToken(SqlPrintTokenType.keyword, 'between'));
token.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN);
token.innerTokens.push(this.visit(arg.lower));
token.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN);
token.innerTokens.push(new SqlPrintToken(SqlPrintTokenType.keyword, 'and'));
token.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN);
token.innerTokens.push(this.visit(arg.upper));
return token;
}
visitStringSpecifierExpression(arg) {
// Combine specifier and value into a single token
const specifier = arg.specifier.accept(this).text;
const value = arg.value.accept(this).text;
return new SqlPrintToken(SqlPrintTokenType.value, specifier + value, SqlPrintTokenContainerType.StringSpecifierExpression);
}
visitTypeValue(arg) {
const token = new SqlPrintToken(SqlPrintTokenType.container, '', SqlPrintTokenContainerType.TypeValue);
token.innerTokens.push(arg.qualifiedName.accept(this));
if (arg.argument) {
token.innerTokens.push(SqlPrintTokenParser.PAREN_OPEN_TOKEN);
token.innerTokens.push(this.visit(arg.argument));
token.innerTokens.push(SqlPrintTokenParser.PAREN_CLOSE_TOKEN);
}
return token;
}
visitTupleExpression(arg) {
const token = new SqlPrintToken(SqlPrintTokenType.container, '', SqlPrintTokenContainerType.TupleExpression);
token.innerTokens.push(SqlPrintTokenParser.PAREN_OPEN_TOKEN);
for (let i = 0; i < arg.values.length; i++) {
if (i > 0) {
token.innerTokens.push(...SqlPrintTokenParser.argumentCommaSpaceTokens());
}
token.innerTokens.push(this.visit(arg.values[i]));
}
token.innerTokens.push(SqlPrintTokenParser.PAREN_CLOSE_TOKEN);
return token;
}
visitWindowFrameExpression(arg) {
// Compose window frame expression: over(partition by ... order by ... rows ...)
const token = new SqlPrintToken(SqlPrintTokenType.container, '', SqlPrintTokenContainerType.WindowFrameExpression);
let first = true;
if (arg.partition) {
token.innerTokens.push(this.visit(arg.partition));
first = false;
}
if (arg.order) {
if (!first) {
token.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN);
}
else {
first = false;
}
token.innerTokens.push(this.visit(arg.order));
}
if (arg.frameSpec) {
if (!first) {
token.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN);
}
else {
first = false;
}
token.innerTokens.push(this.visit(arg.frameSpec));
}
return token;
}
visitWindowFrameSpec(arg) {
// This method prints a window frame specification, such as "rows between ... and ..." or "range ...".
const token = new SqlPrintToken(SqlPrintTokenType.container, '', SqlPrintTokenContainerType.WindowFrameSpec);
// Add frame type (e.g., "rows", "range", "groups")
token.innerTokens.push(new SqlPrintToken(SqlPrintTokenType.keyword, arg.frameType));
if (arg.endBound === null) {
// Only start bound: e.g., "rows unbounded preceding"
token.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN);
token.innerTokens.push(arg.startBound.accept(this));
}
else {
// Between: e.g., "rows between unbounded preceding and current row"
token.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN);
token.innerTokens.push(new SqlPrintToken(SqlPrintTokenType.keyword, 'between'));
token.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN);
token.innerTokens.push(arg.startBound.accept(this));
token.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN);
token.innerTokens.push(new SqlPrintToken(SqlPrintTokenType.keyword, 'and'));
token.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN);
token.innerTokens.push(arg.endBound.accept(this));
}
return token;
}
/**
* Prints a window frame boundary value, such as "5 preceding" or "3 following".
* @param arg WindowFrameBoundaryValue
*/
visitWindowFrameBoundaryValue(arg) {
const token = new SqlPrintToken(SqlPrintTokenType.container, '', SqlPrintTokenContainerType.WindowFrameBoundaryValue);
token.innerTokens.push(arg.value.accept(this));
token.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN);
// true for "FOLLOWING", false for "PRECEDING"
token.innerTokens.push(new SqlPrintToken(SqlPrintTokenType.keyword, arg.isFollowing ? 'following' : 'preceding'));
return token;
}
/**
* Prints a static window frame bound, such as "unbounded preceding", "current row", or "unbounded following".
* @param arg WindowFrameBoundStatic
*/
visitWindowFrameBoundStatic(arg) {
const token = new SqlPrintToken(SqlPrintTokenType.keyword, arg.bound);
return token;
}
visitSelectItem(arg) {
const token = new SqlPrintToken(SqlPrintTokenType.container, '', SqlPrintTokenContainerType.SelectItem);
token.innerTokens.push(this.visit(arg.value));
if (!arg.identifier) {
return token;
}
// No alias needed if it matches the default name
if (arg.value instanceof ColumnReference) {
const defaultName = arg.value.column.name;
if (arg.identifier.name === defaultName) {
return token;
}
}
// Add alias if it is different from the default name
token.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN);
token.innerTokens.push(new SqlPrintToken(SqlPrintTokenType.keyword, 'as'));
token.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN);
token.innerTokens.push(this.visit(arg.identifier));
return token;
}
visitSelectClause(arg) {
const token = new SqlPrintToken(SqlPrintTokenType.keyword, 'select', SqlPrintTokenContainerType.SelectClause);
token.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN);
if (arg.distinct) {
token.keywordTokens = [];
token.keywordTokens.push(SqlPrintTokenParser.SPACE_TOKEN);
token.keywordTokens.push(arg.distinct.accept(this));
}
for (let i = 0; i < arg.items.length; i++) {
if (i > 0) {
token.innerTokens.push(...SqlPrintTokenParser.commaSpaceTokens());
}
token.innerTokens.push(this.visit(arg.items[i]));
}
return token;
}
visitDistinct(arg) {
const token = new SqlPrintToken(SqlPrintTokenType.keyword, 'distinct');
return token;
}
visitDistinctOn(arg) {
const token = new SqlPrintToken(SqlPrintTokenType.container, '', SqlPrintTokenContainerType.DistinctOn);
token.innerTokens.push(new SqlPrintToken(SqlPrintTokenType.keyword, 'distinct on'));
token.innerTokens.push(SqlPrintTokenParser.PAREN_OPEN_TOKEN);
token.innerTokens.push(arg.value.accept(this));
token.innerTokens.push(SqlPrintTokenParser.PAREN_CLOSE_TOKEN);
return token;
}
visitTableSource(arg) {
// Print table name with optional namespaces and alias
let fullName = '';
if (Array.isArray(arg.namespaces) && arg.namespaces.length > 0) {
fullName = arg.namespaces.map(ns => ns.accept(this).text).join('.') + '.';
}
fullName += arg.table.accept(this).text;
const token = new SqlPrintToken(SqlPrintTokenType.value, fullName);
// alias (if present and different from table name)
if (arg.identifier && arg.identifier.name !== arg.table.name) {
}
return token;
}
visitSourceExpression(arg) {
// Print source expression (e.g. "table", "table as t", "schema.table t")
const token = new SqlPrintToken(SqlPrintTokenType.container, '', SqlPrintTokenContainerType.SourceExpression);
token.innerTokens.push(arg.datasource.accept(this));
if (!arg.aliasExpression) {
return token;
}
if (arg.datasource instanceof TableSource) {
// No alias needed if it matches the default name
const defaultName = arg.datasource.table.name;
if (arg.aliasExpression.table.name === defaultName) {
return token;
}
token.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN);
token.innerTokens.push(new SqlPrintToken(SqlPrintTokenType.keyword, 'as'));
token.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN);
// exclude column aliases
token.innerTokens.push(arg.aliasExpression.accept(this));
return token;
}
else {
// For other source types, just print the alias
token.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN);
token.innerTokens.push(new SqlPrintToken(SqlPrintTokenType.keyword, 'as'));
token.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN);
// included column aliases
token.innerTokens.push(arg.aliasExpression.accept(this));
return token;
}
}
visitFromClause(arg) {
const token = new SqlPrintToken(SqlPrintTokenType.keyword, 'from', SqlPrintTokenContainerType.FromClause);
token.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN);
token.innerTokens.push(this.visit(arg.source));
if (arg.joins) {
for (let i = 0; i < arg.joins.length; i++) {
token.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN);
token.innerTokens.push(this.visit(arg.joins[i]));
}
}
return token;
}
visitJoinClause(arg) {
// Print join clause: [joinType] [lateral] [source] [on/using ...]
const token = new SqlPrintToken(SqlPrintTokenType.container, '', SqlPrintTokenContainerType.JoinClause);
// join type (e.g. inner join, left join, etc)
token.innerTokens.push(new SqlPrintToken(SqlPrintTokenType.keyword, arg.joinType.value));
if (arg.lateral) {
token.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN);
token.innerTokens.push(new SqlPrintToken(SqlPrintTokenType.keyword, 'lateral'));
}
token.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN);
token.innerTokens.push(this.visit(arg.source));
if (arg.condition) {
token.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN);
token.innerTokens.push(this.visit(arg.condition));
}
return token;
}
visitJoinOnClause(arg) {
const token = new SqlPrintToken(SqlPrintTokenType.container, '', SqlPrintTokenContainerType.JoinOnClause);
token.innerTokens.push(new SqlPrintToken(SqlPrintTokenType.keyword, 'on'));
token.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN);
token.innerTokens.push(this.visit(arg.condition));
return token;
}
visitJoinUsingClause(arg) {
const token = new SqlPrintToken(SqlPrintTokenType.container, '', SqlPrintTokenContainerType.JoinUsingClause);
token.innerTokens.push(new SqlPrintToken(SqlPrintTokenType.keyword, 'using'));
token.innerTokens.push(SqlPrintTokenParser.PAREN_OPEN_TOKEN);
token.innerTokens.push(this.visit(arg.condition));
token.innerTokens.push(SqlPrintTokenParser.PAREN_CLOSE_TOKEN);
return token;
}
visitFunctionSource(arg) {
// Print function source: [functionName]([args])
const token = new SqlPrintToken(SqlPrintTokenType.container, '', SqlPrintTokenContainerType.FunctionSource);
token.innerTokens.push(arg.qualifiedName.accept(this));
token.innerTokens.push(SqlPrintTokenParser.PAREN_OPEN_TOKEN);
if (arg.argument) {
token.innerTokens.push(this.visit(arg.argument));
}
token.innerTokens.push(SqlPrintTokenParser.PAREN_CLOSE_TOKEN);
return token;
}
visitSourceAliasExpression(arg) {
// Print source alias expression: [source] as [alias]
const token = new SqlPrintToken(SqlPrintTokenType.container, '', SqlPrintTokenContainerType.SourceAliasExpression);
token.innerTokens.push(this.visit(arg.table));
if (arg.columns) {
token.innerTokens.push(SqlPrintTokenParser.PAREN_OPEN_TOKEN);
for (let i = 0; i < arg.columns.length; i++) {
if (i > 0) {
token.innerTokens.push(...SqlPrintTokenParser.argumentCommaSpaceTokens());
}
token.innerTokens.push(this.visit(arg.columns[i]));
}
token.innerTokens.push(SqlPrintTokenParser.PAREN_CLOSE_TOKEN);
}
return token;
}
visitWhereClause(arg) {
const token = new SqlPrintToken(SqlPrintTokenType.keyword, 'where', SqlPrintTokenContainerType.WhereClause);
token.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN);
token.innerTokens.push(this.visit(arg.condition));
return token;
}
visitGroupByClause(arg) {
const token = new SqlPrintToken(SqlPrintTokenType.keyword, 'group by', SqlPrintTokenContainerType.GroupByClause);
token.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN);
for (let i = 0; i < arg.grouping.length; i++) {
if (i > 0) {
token.innerTokens.push(...SqlPrintTokenParser.commaSpaceTokens());
}
token.innerTokens.push(this.visit(arg.grouping[i]));
}
return token;
}
visitHavingClause(arg) {
const token = new SqlPrintToken(SqlPrintTokenType.keyword, 'having', SqlPrintTokenContainerType.HavingClause);
token.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN);
token.innerTokens.push(this.visit(arg.condition));
return token;
}
visitWindowClause(arg) {
const token = new SqlPrintToken(SqlPrintTokenType.keyword, 'window', SqlPrintTokenContainerType.WindowClause);
token.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN);
for (let i = 0; i < arg.windows.length; i++) {
if (i > 0) {
token.innerTokens.push(...SqlPrintTokenParser.commaSpaceTokens());
}
token.innerTokens.push(this.visit(arg.windows[i]));
}
return token;
}
visitWindowFrameClause(arg) {
const token = new SqlPrintToken(SqlPrintTokenType.container, '', SqlPrintTokenContainerType.WindowFrameClause);
token.innerTokens.push(arg.name.accept(this));
token.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN);
token.innerTokens.push(new SqlPrintToken(SqlPrintTokenType.keyword, 'as'));
token.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN);
token.innerTokens.push(SqlPrintTokenParser.PAREN_OPEN_TOKEN);
token.innerTokens.push(this.visit(arg.expression));
token.innerTokens.push(SqlPrintTokenParser.PAREN_CLOSE_TOKEN);
return token;
}
visitLimitClause(arg) {
const token = new SqlPrintToken(SqlPrintTokenType.keyword, 'limit', SqlPrintTokenContainerType.LimitClause);
token.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN);
token.innerTokens.push(this.visit(arg.value));
return token;
}
visitOffsetClause(arg) {
const token = new SqlPrintToken(SqlPrintTokenType.keyword, 'offset', SqlPrintTokenContainerType.OffsetClause);
token.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN);
token.innerTokens.push(this.visit(arg.value));
return token;
}
visitFetchClause(arg) {
const token = new SqlPrintToken(SqlPrintTokenType.keyword, 'fetch', SqlPrintTokenContainerType.FetchClause);
token.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN);
token.innerTokens.push(this.visit(arg.expression));
return token;
}
visitFetchExpression(arg) {
const token = new SqlPrintToken(SqlPrintTokenType.container, '', SqlPrintTokenContainerType.FetchExpression);
token.innerTokens.push(new SqlPrintToken(SqlPrintTokenType.keyword, arg.type));
token.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN);
token.innerTokens.push(arg.count.accept(this));
if (arg.unit) {
token.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN);
token.innerTokens.push(new SqlPrintToken(SqlPrintTokenType.keyword, arg.unit));
}
return token;
}
visitForClause(arg) {
const token = new SqlPrintToken(SqlPrintTokenType.keyword, 'for', SqlPrintTokenContainerType.ForClause);
token.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN);
token.innerTokens.push(new SqlPrintToken(SqlPrintTokenType.keyword, arg.lockMode));
return token;
}
visitWithClause(arg) {
const token = new SqlPrintToken(SqlPrintTokenType.keyword, 'with', SqlPrintTokenContainerType.WithClause);
token.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN);
if (arg.recursive) {
token.innerTokens.push(new SqlPrintToken(SqlPrintTokenType.keyword, 'recursive'));
token.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN);
}
for (let i = 0; i < arg.tables.length; i++) {
if (i > 0) {
token.innerTokens.push(...SqlPrintTokenParser.commaSpaceTokens());
}
token.innerTokens.push(arg.tables[i].accept(this));
}
token.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN);
return token;
}
visitCommonTable(arg) {
const token = new SqlPrintToken(SqlPrintTokenType.container, '', SqlPrintTokenContainerType.CommonTable);
token.innerTokens.push(arg.aliasExpression.accept(this));
token.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN);
token.innerTokens.push(new SqlPrintToken(SqlPrintTokenType.keyword, 'as'));
token.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN);
if (arg.materialized !== null) {
if (arg.materialized) {
token.innerTokens.push(new SqlPrintToken(SqlPrintTokenType.keyword, 'materialized'));
}
else {
token.innerTokens.push(new SqlPrintToken(SqlPrintTokenType.keyword, 'not materialized'));
}
token.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN);
}
token.innerTokens.push(SqlPrintTokenParser.PAREN_OPEN_TOKEN);
const query = new SqlPrintToken(SqlPrintTokenType.container, '', SqlPrintTokenContainerType.SubQuerySource);
query.innerTokens.push(arg.query.accept(this));
token.innerTokens.push(query);
token.innerTokens.push(SqlPrintTokenParser.PAREN_CLOSE_TOKEN);
return token;
}
// query
visitSimpleQuery(arg) {
const token = new SqlPrintToken(SqlPrintTokenType.container, '', SqlPrintTokenContainerType.SimpleSelectQuery);
if (arg.withClause) {
token.innerTokens.push(arg.withClause.accept(this));
}
token.innerTokens.push(arg.selectClause.accept(this));
if (!arg.fromClause) {
return token;
}
token.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN);
token.innerTokens.push(arg.fromClause.accept(this));
if (arg.whereClause) {
token.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN);
token.innerTokens.push(arg.whereClause.accept(this));
}
if (arg.groupByClause) {
token.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN);
token.innerTokens.push(arg.groupByClause.accept(this));
}
if (arg.havingClause) {
token.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN);
token.innerTokens.push(arg.havingClause.accept(this));
}
if (arg.orderByClause) {
token.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN);
token.innerTokens.push(arg.orderByClause.accept(this));
}
if (arg.windowClause) {
token.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN);
token.innerTokens.push(arg.windowClause.accept(this));
}
if (arg.limitClause) {
token.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN);
token.innerTokens.push(arg.limitClause.accept(this));
}
if (arg.offsetClause) {
token.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN);
token.innerTokens.push(arg.offsetClause.accept(this));
}
if (arg.fetchClause) {
token.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN);
token.innerTokens.push(arg.fetchClause.accept(this));
}
if (arg.forClause) {
token.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN);
token.innerTokens.push(arg.forClause.accept(this));
}
return token;
}
visitSubQuerySource(arg) {
const token = new SqlPrintToken(SqlPrintTokenType.container, '');
token.innerTokens.push(SqlPrintTokenParser.PAREN_OPEN_TOKEN);
const subQuery = new SqlPrintToken(SqlPrintTokenType.container, '', SqlPrintTokenContainerType.SubQuerySource);
subQuery.innerTokens.push(arg.query.accept(this));
token.innerTokens.push(subQuery);
token.innerTokens.push(SqlPrintTokenParser.PAREN_CLOSE_TOKEN);
return token;
}
visitValuesQuery(arg) {
const token = new SqlPrintToken(SqlPrintTokenType.keyword, 'values', SqlPrintTokenContainerType.ValuesQuery);
token.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN);
const values = new SqlPrintToken(SqlPrintTokenType.container, '', SqlPrintTokenContainerType.Values);
for (let i = 0; i < arg.tuples.length; i++) {
if (i > 0) {
values.innerTokens.push(...SqlPrintTokenParser.commaSpaceTokens());
}
values.innerTokens.push(arg.tuples[i].accept(this));
}
token.innerTokens.push(values);
return token;
}
visitInlineQuery(arg) {
const token = new SqlPrintToken(SqlPrintTokenType.container, '');
token.innerTokens.push(SqlPrintTokenParser.PAREN_OPEN_TOKEN);
const queryToken = new SqlPrintToken(SqlPrintTokenType.container, '', SqlPrintTokenContainerType.InlineQuery);
queryToken.innerTokens.push(arg.selectQuery.accept(this));
token.innerTokens.push(queryToken);
token.innerTokens.push(SqlPrintTokenParser.PAREN_CLOSE_TOKEN);
return token;
}
visitInsertQuery(arg) {
const token = new SqlPrintToken(SqlPrintTokenType.container, '', SqlPrintTokenContainerType.InsertQuery);
// Process the insert clause
token.innerTokens.push(this.visit(arg.insertClause));
// Process the select query if present
if (arg.selectQuery) {
token.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN);