rawsql-ts
Version:
[beta]High-performance SQL parser and AST analyzer written in TypeScript. Provides fast parsing and advanced transformation capabilities.
150 lines • 7.01 kB
JavaScript
import { SqlPrintTokenType, SqlPrintTokenContainerType } from "../models/SqlPrintToken";
import { LinePrinter } from "./LinePrinter";
/**
* SqlPrinter formats a SqlPrintToken tree into a SQL string with flexible style options.
*/
export class SqlPrinter {
/**
* @param options Optional style settings for pretty printing
*/
constructor(options) {
var _a, _b, _c, _d, _e, _f, _g;
this.indentChar = (_a = options === null || options === void 0 ? void 0 : options.indentChar) !== null && _a !== void 0 ? _a : '';
this.indentSize = (_b = options === null || options === void 0 ? void 0 : options.indentSize) !== null && _b !== void 0 ? _b : 0;
// The default newline character is set to a blank space (' ') to enable one-liner formatting.
// This is intentional and differs from the LinePrinter default of '\r\n'.
this.newline = (_c = options === null || options === void 0 ? void 0 : options.newline) !== null && _c !== void 0 ? _c : ' ';
this.commaBreak = (_d = options === null || options === void 0 ? void 0 : options.commaBreak) !== null && _d !== void 0 ? _d : 'none';
this.andBreak = (_e = options === null || options === void 0 ? void 0 : options.andBreak) !== null && _e !== void 0 ? _e : 'none';
this.keywordCase = (_f = options === null || options === void 0 ? void 0 : options.keywordCase) !== null && _f !== void 0 ? _f : 'none';
this.linePrinter = new LinePrinter(this.indentChar, this.indentSize, this.newline);
// Initialize
this.indentIncrementContainers = new Set((_g = options === null || options === void 0 ? void 0 : options.indentIncrementContainerTypes) !== null && _g !== void 0 ? _g : [
SqlPrintTokenContainerType.SelectClause,
SqlPrintTokenContainerType.FromClause,
SqlPrintTokenContainerType.WhereClause,
SqlPrintTokenContainerType.GroupByClause,
SqlPrintTokenContainerType.HavingClause,
SqlPrintTokenContainerType.WindowFrameExpression,
SqlPrintTokenContainerType.PartitionByClause,
SqlPrintTokenContainerType.OrderByClause,
SqlPrintTokenContainerType.WindowClause,
SqlPrintTokenContainerType.LimitClause,
SqlPrintTokenContainerType.OffsetClause,
SqlPrintTokenContainerType.SubQuerySource,
SqlPrintTokenContainerType.BinarySelectQueryOperator, SqlPrintTokenContainerType.Values,
SqlPrintTokenContainerType.WithClause,
SqlPrintTokenContainerType.SwitchCaseArgument,
SqlPrintTokenContainerType.CaseKeyValuePair,
SqlPrintTokenContainerType.CaseThenValue,
SqlPrintTokenContainerType.ElseClause,
SqlPrintTokenContainerType.CaseElseValue
// CaseExpression, SwitchCaseArgument, CaseKeyValuePair, and ElseClause
// are not included by default to maintain backward compatibility with tests
//SqlPrintTokenContainerType.CommonTable
]);
}
/**
* Converts a SqlPrintToken tree to a formatted SQL string.
* @param token The root SqlPrintToken
* @param level Indentation level (default: 0)
*/
print(token, level = 0) {
// initialize
this.linePrinter = new LinePrinter(this.indentChar, this.indentSize, this.newline);
if (this.linePrinter.lines.length > 0 && level !== this.linePrinter.lines[0].level) {
this.linePrinter.lines[0].level = level;
}
this.appendToken(token, level);
return this.linePrinter.print();
}
appendToken(token, level) {
if (!token.innerTokens || token.innerTokens.length === 0) {
if (token.text === '') {
return;
}
}
const current = this.linePrinter.getCurrentLine();
if (token.type === SqlPrintTokenType.keyword) {
let text = token.text;
if (this.keywordCase === 'upper') {
text = text.toUpperCase();
}
else if (this.keywordCase === 'lower') {
text = text.toLowerCase();
}
this.linePrinter.appendText(text);
}
else if (token.type === SqlPrintTokenType.comma) {
let text = token.text;
if (this.commaBreak === 'before') {
this.linePrinter.appendNewline(level);
this.linePrinter.appendText(text);
}
else if (this.commaBreak === 'after') {
this.linePrinter.appendText(text);
this.linePrinter.appendNewline(level);
}
else {
this.linePrinter.appendText(text);
}
}
else if (token.type === SqlPrintTokenType.operator && token.text.toLowerCase() === 'and') {
let text = token.text;
if (this.keywordCase === 'upper') {
text = text.toUpperCase();
}
else if (this.keywordCase === 'lower') {
text = text.toLowerCase();
}
if (this.andBreak === 'before') {
this.linePrinter.appendNewline(level);
this.linePrinter.appendText(text);
}
else if (this.andBreak === 'after') {
this.linePrinter.appendText(text);
this.linePrinter.appendNewline(level);
}
else {
this.linePrinter.appendText(text);
}
}
else if (token.containerType === "JoinClause") {
let text = token.text;
if (this.keywordCase === 'upper') {
text = text.toUpperCase();
}
else if (this.keywordCase === 'lower') {
text = text.toLowerCase();
}
// before join clause, add newline
this.linePrinter.appendNewline(level);
this.linePrinter.appendText(text);
}
else {
this.linePrinter.appendText(token.text);
}
// append keyword tokens(not indented)
if (token.keywordTokens && token.keywordTokens.length > 0) {
for (let i = 0; i < token.keywordTokens.length; i++) {
const keywordToken = token.keywordTokens[i];
this.appendToken(keywordToken, level);
}
}
let innerLevel = level;
// indent level up
if (this.newline !== ' ' && current.text !== '' && this.indentIncrementContainers.has(token.containerType)) { // Changed condition
innerLevel++;
this.linePrinter.appendNewline(innerLevel);
}
for (let i = 0; i < token.innerTokens.length; i++) {
const child = token.innerTokens[i];
this.appendToken(child, innerLevel);
}
// indent level down
if (innerLevel !== level) {
this.linePrinter.appendNewline(level);
}
}
}
//# sourceMappingURL=SqlPrinter.js.map