UNPKG

rawsql-ts

Version:

[beta]High-performance SQL parser and AST analyzer written in TypeScript. Provides fast parsing and advanced transformation capabilities.

889 lines 60.9 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.SqlPrintTokenParser = exports.PRESETS = exports.ParameterStyle = void 0; const Clause_1 = require("../models/Clause"); const SelectQuery_1 = require("../models/SelectQuery"); const SqlPrintToken_1 = require("../models/SqlPrintToken"); const ValueComponent_1 = require("../models/ValueComponent"); const ParameterCollector_1 = require("../transformers/ParameterCollector"); const IdentifierDecorator_1 = require("./IdentifierDecorator"); const ParameterDecorator_1 = require("./ParameterDecorator"); const InsertQuery_1 = require("../models/InsertQuery"); const UpdateQuery_1 = require("../models/UpdateQuery"); const CreateTableQuery_1 = require("../models/CreateTableQuery"); var ParameterStyle; (function (ParameterStyle) { ParameterStyle["Anonymous"] = "anonymous"; ParameterStyle["Indexed"] = "indexed"; ParameterStyle["Named"] = "named"; })(ParameterStyle || (exports.ParameterStyle = ParameterStyle = {})); exports.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, }, }; 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 = { ...preset, ...options }; } this.parameterDecorator = new ParameterDecorator_1.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_1.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(ValueComponent_1.ValueList.kind, (expr) => this.visitValueList(expr)); this.handlers.set(ValueComponent_1.ColumnReference.kind, (expr) => this.visitColumnReference(expr)); this.handlers.set(ValueComponent_1.QualifiedName.kind, (expr) => this.visitQualifiedName(expr)); this.handlers.set(ValueComponent_1.FunctionCall.kind, (expr) => this.visitFunctionCall(expr)); this.handlers.set(ValueComponent_1.UnaryExpression.kind, (expr) => this.visitUnaryExpression(expr)); this.handlers.set(ValueComponent_1.BinaryExpression.kind, (expr) => this.visitBinaryExpression(expr)); this.handlers.set(ValueComponent_1.LiteralValue.kind, (expr) => this.visitLiteralValue(expr)); this.handlers.set(ValueComponent_1.ParameterExpression.kind, (expr) => this.visitParameterExpression(expr)); this.handlers.set(ValueComponent_1.SwitchCaseArgument.kind, (expr) => this.visitSwitchCaseArgument(expr)); this.handlers.set(ValueComponent_1.CaseKeyValuePair.kind, (expr) => this.visitCaseKeyValuePair(expr)); this.handlers.set(ValueComponent_1.RawString.kind, (expr) => this.visitRawString(expr)); this.handlers.set(ValueComponent_1.IdentifierString.kind, (expr) => this.visitIdentifierString(expr)); this.handlers.set(ValueComponent_1.ParenExpression.kind, (expr) => this.visitParenExpression(expr)); this.handlers.set(ValueComponent_1.CastExpression.kind, (expr) => this.visitCastExpression(expr)); this.handlers.set(ValueComponent_1.CaseExpression.kind, (expr) => this.visitCaseExpression(expr)); this.handlers.set(ValueComponent_1.ArrayExpression.kind, (expr) => this.visitArrayExpression(expr)); this.handlers.set(ValueComponent_1.ArrayQueryExpression.kind, (expr) => this.visitArrayQueryExpression(expr)); this.handlers.set(ValueComponent_1.BetweenExpression.kind, (expr) => this.visitBetweenExpression(expr)); this.handlers.set(ValueComponent_1.StringSpecifierExpression.kind, (expr) => this.visitStringSpecifierExpression(expr)); this.handlers.set(ValueComponent_1.TypeValue.kind, (expr) => this.visitTypeValue(expr)); this.handlers.set(ValueComponent_1.TupleExpression.kind, (expr) => this.visitTupleExpression(expr)); this.handlers.set(ValueComponent_1.InlineQuery.kind, (expr) => this.visitInlineQuery(expr)); this.handlers.set(ValueComponent_1.WindowFrameExpression.kind, (expr) => this.visitWindowFrameExpression(expr)); this.handlers.set(ValueComponent_1.WindowFrameSpec.kind, (expr) => this.visitWindowFrameSpec(expr)); this.handlers.set(ValueComponent_1.WindowFrameBoundStatic.kind, (expr) => this.visitWindowFrameBoundStatic(expr)); this.handlers.set(ValueComponent_1.WindowFrameBoundaryValue.kind, (expr) => this.visitWindowFrameBoundaryValue(expr)); this.handlers.set(Clause_1.PartitionByClause.kind, (expr) => this.visitPartitionByClause(expr)); this.handlers.set(Clause_1.OrderByClause.kind, (expr) => this.visitOrderByClause(expr)); this.handlers.set(Clause_1.OrderByItem.kind, (expr) => this.visitOrderByItem(expr)); // select this.handlers.set(Clause_1.SelectItem.kind, (expr) => this.visitSelectItem(expr)); this.handlers.set(Clause_1.SelectClause.kind, (expr) => this.visitSelectClause(expr)); this.handlers.set(Clause_1.Distinct.kind, (expr) => this.visitDistinct(expr)); this.handlers.set(Clause_1.DistinctOn.kind, (expr) => this.visitDistinctOn(expr)); // from this.handlers.set(Clause_1.TableSource.kind, (expr) => this.visitTableSource(expr)); this.handlers.set(Clause_1.FunctionSource.kind, (expr) => this.visitFunctionSource(expr)); this.handlers.set(Clause_1.SourceExpression.kind, (expr) => this.visitSourceExpression(expr)); this.handlers.set(Clause_1.SourceAliasExpression.kind, (expr) => this.visitSourceAliasExpression(expr)); this.handlers.set(Clause_1.FromClause.kind, (expr) => this.visitFromClause(expr)); this.handlers.set(Clause_1.JoinClause.kind, (expr) => this.visitJoinClause(expr)); this.handlers.set(Clause_1.JoinOnClause.kind, (expr) => this.visitJoinOnClause(expr)); this.handlers.set(Clause_1.JoinUsingClause.kind, (expr) => this.visitJoinUsingClause(expr)); // where this.handlers.set(Clause_1.WhereClause.kind, (expr) => this.visitWhereClause(expr)); // group this.handlers.set(Clause_1.GroupByClause.kind, (expr) => this.visitGroupByClause(expr)); this.handlers.set(Clause_1.HavingClause.kind, (expr) => this.visitHavingClause(expr)); this.handlers.set(Clause_1.WindowsClause.kind, (expr) => this.visitWindowClause(expr)); this.handlers.set(Clause_1.WindowFrameClause.kind, (expr) => this.visitWindowFrameClause(expr)); this.handlers.set(Clause_1.LimitClause.kind, (expr) => this.visitLimitClause(expr)); this.handlers.set(Clause_1.OffsetClause.kind, (expr) => this.visitOffsetClause(expr)); this.handlers.set(Clause_1.FetchClause.kind, (expr) => this.visitFetchClause(expr)); this.handlers.set(Clause_1.FetchExpression.kind, (expr) => this.visitFetchExpression(expr)); this.handlers.set(Clause_1.ForClause.kind, (expr) => this.visitForClause(expr)); // With this.handlers.set(Clause_1.WithClause.kind, (expr) => this.visitWithClause(expr)); this.handlers.set(Clause_1.CommonTable.kind, (expr) => this.visitCommonTable(expr)); // Query this.handlers.set(SelectQuery_1.SimpleSelectQuery.kind, (expr) => this.visitSimpleQuery(expr)); this.handlers.set(Clause_1.SubQuerySource.kind, (expr) => this.visitSubQuerySource(expr)); this.handlers.set(SelectQuery_1.BinarySelectQuery.kind, (expr) => this.visitBinarySelectQuery(expr)); this.handlers.set(SelectQuery_1.ValuesQuery.kind, (expr) => this.visitValuesQuery(expr)); this.handlers.set(ValueComponent_1.TupleExpression.kind, (expr) => this.visitTupleExpression(expr)); this.handlers.set(InsertQuery_1.InsertQuery.kind, (expr) => this.visitInsertQuery(expr)); this.handlers.set(Clause_1.InsertClause.kind, (expr) => this.visitInsertClause(expr)); this.handlers.set(UpdateQuery_1.UpdateQuery.kind, (expr) => this.visitUpdateQuery(expr)); this.handlers.set(Clause_1.UpdateClause.kind, (expr) => this.visitUpdateClause(expr)); this.handlers.set(Clause_1.SetClause.kind, (expr) => this.visitSetClause(expr)); this.handlers.set(Clause_1.SetClauseItem.kind, (expr) => this.visitSetClauseItem(expr)); this.handlers.set(Clause_1.ReturningClause.kind, (expr) => this.visitReturningClause(expr)); this.handlers.set(CreateTableQuery_1.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_1.SqlPrintToken(SqlPrintToken_1.SqlPrintTokenType.container, ''); token.innerTokens.push(this.visit(arg.left)); token.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN); token.innerTokens.push(new SqlPrintToken_1.SqlPrintToken(SqlPrintToken_1.SqlPrintTokenType.keyword, arg.operator.value, SqlPrintToken_1.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_1.SqlPrintToken(SqlPrintToken_1.SqlPrintTokenType.container, '', SqlPrintToken_1.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_1.SqlPrintToken(SqlPrintToken_1.SqlPrintTokenType.keyword, 'partition by', SqlPrintToken_1.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_1.SqlPrintToken(SqlPrintToken_1.SqlPrintTokenType.keyword, 'order by', SqlPrintToken_1.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_1.SqlPrintToken(SqlPrintToken_1.SqlPrintTokenType.container, '', SqlPrintToken_1.SqlPrintTokenContainerType.OrderByItem); token.innerTokens.push(this.visit(arg.value)); if (arg.sortDirection && arg.sortDirection !== Clause_1.SortDirection.Ascending) { token.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN); token.innerTokens.push(new SqlPrintToken_1.SqlPrintToken(SqlPrintToken_1.SqlPrintTokenType.keyword, 'desc')); } if (arg.nullsPosition) { if (arg.nullsPosition === Clause_1.NullsSortDirection.First) { token.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN); token.innerTokens.push(new SqlPrintToken_1.SqlPrintToken(SqlPrintToken_1.SqlPrintTokenType.keyword, 'nulls first')); } else if (arg.nullsPosition === Clause_1.NullsSortDirection.Last) { token.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN); token.innerTokens.push(new SqlPrintToken_1.SqlPrintToken(SqlPrintToken_1.SqlPrintTokenType.keyword, 'nulls last')); } } return token; } parse(arg) { // reset parameter index before parsing this.index = 1; const token = this.visit(arg); const paramsRaw = ParameterCollector_1.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_1.SqlPrintToken(SqlPrintToken_1.SqlPrintTokenType.container, '', SqlPrintToken_1.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_1.SqlPrintToken(SqlPrintToken_1.SqlPrintTokenType.container, '', SqlPrintToken_1.SqlPrintTokenContainerType.ColumnReference); token.innerTokens.push(arg.qualifiedName.accept(this)); return token; } visitFunctionCall(arg) { const token = new SqlPrintToken_1.SqlPrintToken(SqlPrintToken_1.SqlPrintTokenType.container, '', SqlPrintToken_1.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_1.SqlPrintToken(SqlPrintToken_1.SqlPrintTokenType.keyword, 'over')); if (arg.over instanceof ValueComponent_1.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_1.SqlPrintToken(SqlPrintToken_1.SqlPrintTokenType.container, '', SqlPrintToken_1.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_1.SqlPrintToken(SqlPrintToken_1.SqlPrintTokenType.container, '', SqlPrintToken_1.SqlPrintTokenContainerType.BinaryExpression); token.innerTokens.push(this.visit(arg.left)); token.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN); token.innerTokens.push(new SqlPrintToken_1.SqlPrintToken(SqlPrintToken_1.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_1.SqlPrintToken(SqlPrintToken_1.SqlPrintTokenType.value, text, SqlPrintToken_1.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_1.SqlPrintToken(SqlPrintToken_1.SqlPrintTokenType.parameter, text); this.index++; return token; } visitSwitchCaseArgument(arg) { const token = new SqlPrintToken_1.SqlPrintToken(SqlPrintToken_1.SqlPrintTokenType.container, '', SqlPrintToken_1.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_1.SqlPrintToken(SqlPrintToken_1.SqlPrintTokenType.container, '', SqlPrintToken_1.SqlPrintTokenContainerType.ElseClause); // Add the ELSE keyword elseToken.innerTokens.push(new SqlPrintToken_1.SqlPrintToken(SqlPrintToken_1.SqlPrintTokenType.keyword, 'else')); // Create a container for the ELSE value to enable proper indentation elseToken.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN); const elseValueContainer = new SqlPrintToken_1.SqlPrintToken(SqlPrintToken_1.SqlPrintTokenType.container, '', SqlPrintToken_1.SqlPrintTokenContainerType.CaseElseValue); elseValueContainer.innerTokens.push(this.visit(elseValue)); elseToken.innerTokens.push(elseValueContainer); return elseToken; } visitCaseKeyValuePair(arg) { const token = new SqlPrintToken_1.SqlPrintToken(SqlPrintToken_1.SqlPrintTokenType.container, '', SqlPrintToken_1.SqlPrintTokenContainerType.CaseKeyValuePair); // Create WHEN clause token.innerTokens.push(new SqlPrintToken_1.SqlPrintToken(SqlPrintToken_1.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_1.SqlPrintToken(SqlPrintToken_1.SqlPrintTokenType.keyword, 'then')); // Create a container for the THEN value to enable proper indentation token.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN); const thenValueContainer = new SqlPrintToken_1.SqlPrintToken(SqlPrintToken_1.SqlPrintTokenType.container, '', SqlPrintToken_1.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_1.SqlPrintToken(SqlPrintToken_1.SqlPrintTokenType.value, arg.value, SqlPrintToken_1.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_1.SqlPrintToken(SqlPrintToken_1.SqlPrintTokenType.value, text, SqlPrintToken_1.SqlPrintTokenContainerType.IdentifierString); return token; } visitParenExpression(arg) { const token = new SqlPrintToken_1.SqlPrintToken(SqlPrintToken_1.SqlPrintTokenType.container, '', SqlPrintToken_1.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_1.SqlPrintToken(SqlPrintToken_1.SqlPrintTokenType.container, '', SqlPrintToken_1.SqlPrintTokenContainerType.CastExpression); token.innerTokens.push(this.visit(arg.input)); token.innerTokens.push(new SqlPrintToken_1.SqlPrintToken(SqlPrintToken_1.SqlPrintTokenType.operator, '::')); token.innerTokens.push(this.visit(arg.castType)); return token; } visitCaseExpression(arg) { const token = new SqlPrintToken_1.SqlPrintToken(SqlPrintToken_1.SqlPrintTokenType.container, '', SqlPrintToken_1.SqlPrintTokenContainerType.CaseExpression); // Add the CASE keyword token.innerTokens.push(new SqlPrintToken_1.SqlPrintToken(SqlPrintToken_1.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_1.SqlPrintToken(SqlPrintToken_1.SqlPrintTokenType.keyword, 'end')); return token; } visitArrayExpression(arg) { const token = new SqlPrintToken_1.SqlPrintToken(SqlPrintToken_1.SqlPrintTokenType.container, '', SqlPrintToken_1.SqlPrintTokenContainerType.ArrayExpression); token.innerTokens.push(new SqlPrintToken_1.SqlPrintToken(SqlPrintToken_1.SqlPrintTokenType.keyword, 'array')); token.innerTokens.push(new SqlPrintToken_1.SqlPrintToken(SqlPrintToken_1.SqlPrintTokenType.parenthesis, '[')); token.innerTokens.push(this.visit(arg.expression)); token.innerTokens.push(new SqlPrintToken_1.SqlPrintToken(SqlPrintToken_1.SqlPrintTokenType.parenthesis, ']')); return token; } visitArrayQueryExpression(arg) { const token = new SqlPrintToken_1.SqlPrintToken(SqlPrintToken_1.SqlPrintTokenType.container, '', SqlPrintToken_1.SqlPrintTokenContainerType.ArrayExpression); token.innerTokens.push(new SqlPrintToken_1.SqlPrintToken(SqlPrintToken_1.SqlPrintTokenType.keyword, 'array')); // ARRAY(SELECT ...) token.innerTokens.push(new SqlPrintToken_1.SqlPrintToken(SqlPrintToken_1.SqlPrintTokenType.parenthesis, '(')); token.innerTokens.push(this.visit(arg.query)); token.innerTokens.push(new SqlPrintToken_1.SqlPrintToken(SqlPrintToken_1.SqlPrintTokenType.parenthesis, ')')); return token; } visitBetweenExpression(arg) { const token = new SqlPrintToken_1.SqlPrintToken(SqlPrintToken_1.SqlPrintTokenType.container, '', SqlPrintToken_1.SqlPrintTokenContainerType.BetweenExpression); token.innerTokens.push(this.visit(arg.expression)); token.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN); if (arg.negated) { token.innerTokens.push(new SqlPrintToken_1.SqlPrintToken(SqlPrintToken_1.SqlPrintTokenType.keyword, 'not')); token.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN); } token.innerTokens.push(new SqlPrintToken_1.SqlPrintToken(SqlPrintToken_1.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_1.SqlPrintToken(SqlPrintToken_1.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_1.SqlPrintToken(SqlPrintToken_1.SqlPrintTokenType.value, specifier + value, SqlPrintToken_1.SqlPrintTokenContainerType.StringSpecifierExpression); } visitTypeValue(arg) { const token = new SqlPrintToken_1.SqlPrintToken(SqlPrintToken_1.SqlPrintTokenType.container, '', SqlPrintToken_1.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_1.SqlPrintToken(SqlPrintToken_1.SqlPrintTokenType.container, '', SqlPrintToken_1.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_1.SqlPrintToken(SqlPrintToken_1.SqlPrintTokenType.container, '', SqlPrintToken_1.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_1.SqlPrintToken(SqlPrintToken_1.SqlPrintTokenType.container, '', SqlPrintToken_1.SqlPrintTokenContainerType.WindowFrameSpec); // Add frame type (e.g., "rows", "range", "groups") token.innerTokens.push(new SqlPrintToken_1.SqlPrintToken(SqlPrintToken_1.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_1.SqlPrintToken(SqlPrintToken_1.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_1.SqlPrintToken(SqlPrintToken_1.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_1.SqlPrintToken(SqlPrintToken_1.SqlPrintTokenType.container, '', SqlPrintToken_1.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_1.SqlPrintToken(SqlPrintToken_1.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_1.SqlPrintToken(SqlPrintToken_1.SqlPrintTokenType.keyword, arg.bound); return token; } visitSelectItem(arg) { const token = new SqlPrintToken_1.SqlPrintToken(SqlPrintToken_1.SqlPrintTokenType.container, '', SqlPrintToken_1.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 ValueComponent_1.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_1.SqlPrintToken(SqlPrintToken_1.SqlPrintTokenType.keyword, 'as')); token.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN); token.innerTokens.push(this.visit(arg.identifier)); return token; } visitSelectClause(arg) { const token = new SqlPrintToken_1.SqlPrintToken(SqlPrintToken_1.SqlPrintTokenType.keyword, 'select', SqlPrintToken_1.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_1.SqlPrintToken(SqlPrintToken_1.SqlPrintTokenType.keyword, 'distinct'); return token; } visitDistinctOn(arg) { const token = new SqlPrintToken_1.SqlPrintToken(SqlPrintToken_1.SqlPrintTokenType.container, '', SqlPrintToken_1.SqlPrintTokenContainerType.DistinctOn); token.innerTokens.push(new SqlPrintToken_1.SqlPrintToken(SqlPrintToken_1.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_1.SqlPrintToken(SqlPrintToken_1.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_1.SqlPrintToken(SqlPrintToken_1.SqlPrintTokenType.container, '', SqlPrintToken_1.SqlPrintTokenContainerType.SourceExpression); token.innerTokens.push(arg.datasource.accept(this)); if (!arg.aliasExpression) { return token; } if (arg.datasource instanceof Clause_1.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_1.SqlPrintToken(SqlPrintToken_1.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_1.SqlPrintToken(SqlPrintToken_1.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_1.SqlPrintToken(SqlPrintToken_1.SqlPrintTokenType.keyword, 'from', SqlPrintToken_1.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_1.SqlPrintToken(SqlPrintToken_1.SqlPrintTokenType.container, '', SqlPrintToken_1.SqlPrintTokenContainerType.JoinClause); // join type (e.g. inner join, left join, etc) token.innerTokens.push(new SqlPrintToken_1.SqlPrintToken(SqlPrintToken_1.SqlPrintTokenType.keyword, arg.joinType.value)); if (arg.lateral) { token.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN); token.innerTokens.push(new SqlPrintToken_1.SqlPrintToken(SqlPrintToken_1.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_1.SqlPrintToken(SqlPrintToken_1.SqlPrintTokenType.container, '', SqlPrintToken_1.SqlPrintTokenContainerType.JoinOnClause); token.innerTokens.push(new SqlPrintToken_1.SqlPrintToken(SqlPrintToken_1.SqlPrintTokenType.keyword, 'on')); token.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN); token.innerTokens.push(this.visit(arg.condition)); return token; } visitJoinUsingClause(arg) { const token = new SqlPrintToken_1.SqlPrintToken(SqlPrintToken_1.SqlPrintTokenType.container, '', SqlPrintToken_1.SqlPrintTokenContainerType.JoinUsingClause); token.innerTokens.push(new SqlPrintToken_1.SqlPrintToken(SqlPrintToken_1.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_1.SqlPrintToken(SqlPrintToken_1.SqlPrintTokenType.container, '', SqlPrintToken_1.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_1.SqlPrintToken(SqlPrintToken_1.SqlPrintTokenType.container, '', SqlPrintToken_1.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_1.SqlPrintToken(SqlPrintToken_1.SqlPrintTokenType.keyword, 'where', SqlPrintToken_1.SqlPrintTokenContainerType.WhereClause); token.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN); token.innerTokens.push(this.visit(arg.condition)); return token; } visitGroupByClause(arg) { const token = new SqlPrintToken_1.SqlPrintToken(SqlPrintToken_1.SqlPrintTokenType.keyword, 'group by', SqlPrintToken_1.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_1.SqlPrintToken(SqlPrintToken_1.SqlPrintTokenType.keyword, 'having', SqlPrintToken_1.SqlPrintTokenContainerType.HavingClause); token.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN); token.innerTokens.push(this.visit(arg.condition)); return token; } visitWindowClause(arg) { const token = new SqlPrintToken_1.SqlPrintToken(SqlPrintToken_1.SqlPrintTokenType.keyword, 'window', SqlPrintToken_1.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_1.SqlPrintToken(SqlPrintToken_1.SqlPrintTokenType.container, '', SqlPrintToken_1.SqlPrintTokenContainerType.WindowFrameClause); token.innerTokens.push(arg.name.accept(this)); token.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN); token.innerTokens.push(new SqlPrintToken_1.SqlPrintToken(SqlPrintToken_1.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_1.SqlPrintToken(SqlPrintToken_1.SqlPrintTokenType.keyword, 'limit', SqlPrintToken_1.SqlPrintTokenContainerType.LimitClause); token.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN); token.innerTokens.push(this.visit(arg.value)); return token; } visitOffsetClause(arg) { const token = new SqlPrintToken_1.SqlPrintToken(SqlPrintToken_1.SqlPrintTokenType.keyword, 'offset', SqlPrintToken_1.SqlPrintTokenContainerType.OffsetClause); token.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN); token.innerTokens.push(this.visit(arg.value)); return token; } visitFetchClause(arg) { const token = new SqlPrintToken_1.SqlPrintToken(SqlPrintToken_1.SqlPrintTokenType.keyword, 'fetch', SqlPrintToken_1.SqlPrintTokenContainerType.FetchClause); token.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN); token.innerTokens.push(this.visit(arg.expression)); return token; } visitFetchExpression(arg) { const token = new SqlPrintToken_1.SqlPrintToken(SqlPrintToken_1.SqlPrintTokenType.container, '', SqlPrintToken_1.SqlPrintTokenContainerType.FetchExpression); token.innerTokens.push(new SqlPrintToken_1.SqlPrintToken(SqlPrintToken_1.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_1.SqlPrintToken(SqlPrintToken_1.SqlPrintTokenType.keyword, arg.unit)); } return token; } visitForClause(arg) { const token = new SqlPrintToken_1.SqlPrintToken(SqlPrintToken_1.SqlPrintTokenType.keyword, 'for', SqlPrintToken_1.SqlPrintTokenContainerType.ForClause); token.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN); token.innerTokens.push(new SqlPrintToken_1.SqlPrintToken(SqlPrintToken_1.SqlPrintTokenType.keyword, arg.lockMode)); return token; } visitWithClause(arg) { const token = new SqlPrintToken_1.SqlPrintToken(SqlPrintToken_1.SqlPrintTokenType.keyword, 'with', SqlPrintToken_1.SqlPrintTokenContainerType.WithClause); token.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN); if (arg.recursive) { token.innerTokens.push(new SqlPrintToken_1.SqlPrintToken(SqlPrintToken_1.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_1.SqlPrintToken(SqlPrintToken_1.SqlPrintTokenType.container, '', SqlPrintToken_1.SqlPrintTokenContainerType.CommonTable); token.innerTokens.push(arg.aliasExpression.accept(this)); token.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN); token.innerTokens.push(new SqlPrintToken_1.SqlPrintToken(SqlPrintToken_1.SqlPrintTokenType.keyword, 'as')); token.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN); if (arg.materialized !== null) { if (arg.materialized) { token.innerTokens.push(new SqlPrintToken_1.SqlPrintToken(SqlPrintToken_1.SqlPrintTokenType.keyword, 'materialized')); } else { token.inner