rawsql-ts 0.11.1-beta → 0.11.2-beta
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/esm/index.js +7 -2
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/index.min.js +45 -11
- package/dist/esm/index.min.js.map +4 -4
- package/dist/esm/src/index.js +7 -2
- package/dist/esm/src/index.js.map +1 -1
- package/dist/esm/src/parsers/ValueParser.js +86 -4
- package/dist/esm/src/parsers/ValueParser.js.map +1 -1
- package/dist/esm/src/transformers/DynamicQueryBuilder.js.map +1 -1
- package/dist/esm/src/transformers/EnhancedJsonMapping.js +217 -0
- package/dist/esm/src/transformers/EnhancedJsonMapping.js.map +1 -0
- package/dist/esm/src/transformers/JsonMappingConverter.js +388 -0
- package/dist/esm/src/transformers/JsonMappingConverter.js.map +1 -0
- package/dist/esm/src/transformers/JsonMappingUnifier.js +36 -46
- package/dist/esm/src/transformers/JsonMappingUnifier.js.map +1 -1
- package/dist/esm/src/transformers/ModelDrivenJsonMapping.js +14 -2
- package/dist/esm/src/transformers/ModelDrivenJsonMapping.js.map +1 -1
- package/dist/esm/src/transformers/PostgresArrayEntityCteBuilder.js +132 -97
- package/dist/esm/src/transformers/PostgresArrayEntityCteBuilder.js.map +1 -1
- package/dist/esm/src/transformers/PostgresJsonQueryBuilder.js +21 -11
- package/dist/esm/src/transformers/PostgresJsonQueryBuilder.js.map +1 -1
- package/dist/esm/src/transformers/PostgresObjectEntityCteBuilder.js +71 -14
- package/dist/esm/src/transformers/PostgresObjectEntityCteBuilder.js.map +1 -1
- package/dist/esm/src/transformers/SqlParamInjector.js +189 -108
- package/dist/esm/src/transformers/SqlParamInjector.js.map +1 -1
- package/dist/esm/src/transformers/UpstreamSelectQueryFinder.js +43 -2
- package/dist/esm/src/transformers/UpstreamSelectQueryFinder.js.map +1 -1
- package/dist/esm/tsconfig.browser.tsbuildinfo +1 -1
- package/dist/esm/types/src/index.d.ts +7 -2
- package/dist/esm/types/src/parsers/ValueParser.d.ts +8 -0
- package/dist/esm/types/src/transformers/DynamicQueryBuilder.d.ts +6 -0
- package/dist/esm/types/src/transformers/EnhancedJsonMapping.d.ts +194 -0
- package/dist/esm/types/src/transformers/JsonMappingConverter.d.ts +200 -0
- package/dist/esm/types/src/transformers/JsonMappingUnifier.d.ts +5 -0
- package/dist/esm/types/src/transformers/PostgresArrayEntityCteBuilder.d.ts +39 -77
- package/dist/esm/types/src/transformers/PostgresJsonQueryBuilder.d.ts +3 -2
- package/dist/esm/types/src/transformers/PostgresObjectEntityCteBuilder.d.ts +31 -6
- package/dist/esm/types/src/transformers/SqlParamInjector.d.ts +48 -0
- package/dist/esm/types/src/transformers/UpstreamSelectQueryFinder.d.ts +8 -0
- package/dist/index.min.js +45 -11
- package/dist/index.min.js.map +4 -4
- package/dist/src/index.d.ts +7 -2
- package/dist/src/index.js +7 -3
- package/dist/src/index.js.map +1 -1
- package/dist/src/parsers/ValueParser.d.ts +8 -0
- package/dist/src/parsers/ValueParser.js +86 -4
- package/dist/src/parsers/ValueParser.js.map +1 -1
- package/dist/src/transformers/DynamicQueryBuilder.d.ts +6 -0
- package/dist/src/transformers/DynamicQueryBuilder.js.map +1 -1
- package/dist/src/transformers/EnhancedJsonMapping.d.ts +194 -0
- package/dist/src/transformers/EnhancedJsonMapping.js +223 -0
- package/dist/src/transformers/EnhancedJsonMapping.js.map +1 -0
- package/dist/src/transformers/JsonMappingConverter.d.ts +200 -0
- package/dist/src/transformers/JsonMappingConverter.js +392 -0
- package/dist/src/transformers/JsonMappingConverter.js.map +1 -0
- package/dist/src/transformers/JsonMappingUnifier.d.ts +5 -0
- package/dist/src/transformers/JsonMappingUnifier.js +36 -46
- package/dist/src/transformers/JsonMappingUnifier.js.map +1 -1
- package/dist/src/transformers/ModelDrivenJsonMapping.js +14 -2
- package/dist/src/transformers/ModelDrivenJsonMapping.js.map +1 -1
- package/dist/src/transformers/PostgresArrayEntityCteBuilder.d.ts +39 -77
- package/dist/src/transformers/PostgresArrayEntityCteBuilder.js +132 -97
- package/dist/src/transformers/PostgresArrayEntityCteBuilder.js.map +1 -1
- package/dist/src/transformers/PostgresJsonQueryBuilder.d.ts +3 -2
- package/dist/src/transformers/PostgresJsonQueryBuilder.js +21 -11
- package/dist/src/transformers/PostgresJsonQueryBuilder.js.map +1 -1
- package/dist/src/transformers/PostgresObjectEntityCteBuilder.d.ts +31 -6
- package/dist/src/transformers/PostgresObjectEntityCteBuilder.js +71 -14
- package/dist/src/transformers/PostgresObjectEntityCteBuilder.js.map +1 -1
- package/dist/src/transformers/SqlParamInjector.d.ts +48 -0
- package/dist/src/transformers/SqlParamInjector.js +189 -108
- package/dist/src/transformers/SqlParamInjector.js.map +1 -1
- package/dist/src/transformers/UpstreamSelectQueryFinder.d.ts +8 -0
- package/dist/src/transformers/UpstreamSelectQueryFinder.js +43 -2
- package/dist/src/transformers/UpstreamSelectQueryFinder.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +1 -1
package/dist/index.min.js.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
|
-
"sources": ["../src/index.ts", "../src/models/SqlComponent.ts", "../src/models/InsertQuery.ts", "../src/models/ValueComponent.ts", "../src/models/Clause.ts", "../src/models/Lexeme.ts", "../src/utils/charLookupTable.ts", "../src/utils/stringUtils.ts", "../src/tokenReaders/BaseTokenReader.ts", "../src/tokenReaders/IdentifierTokenReader.ts", "../src/parsers/KeywordParser.ts", "../src/models/KeywordTrie.ts", "../src/tokenReaders/LiteralTokenReader.ts", "../src/tokenReaders/ParameterTokenReader.ts", "../src/tokenReaders/SymbolTokenReader.ts", "../src/tokenReaders/TokenReaderManager.ts", "../src/tokenReaders/OperatorTokenReader.ts", "../src/tokenReaders/CommandTokenReader.ts", "../src/tokenReaders/StringSpecifierTokenReader.ts", "../src/tokenReaders/FunctionTokenReader.ts", "../src/tokenReaders/TypeTokenReader.ts", "../src/tokenReaders/EscapedIdentifierTokenReader.ts", "../src/parsers/SqlTokenizer.ts", "../src/parsers/FullNameParser.ts", "../src/parsers/IdentifierParser.ts", "../src/parsers/LiteralParser.ts", "../src/parsers/ParenExpressionParser.ts", "../src/parsers/UnaryExpressionParser.ts", "../src/parsers/ParameterExpressionParser.ts", "../src/parsers/StringSpecifierExpressionParser.ts", "../src/parsers/CommandExpressionParser.ts", "../src/parsers/OrderByClauseParser.ts", "../src/parsers/PartitionByParser.ts", "../src/parsers/WindowExpressionParser.ts", "../src/parsers/OverExpressionParser.ts", "../src/parsers/FunctionExpressionParser.ts", "../src/parsers/ParseError.ts", "../src/utils/OperatorPrecedence.ts", "../src/parsers/ValueParser.ts", "../src/transformers/CTECollector.ts", "../src/transformers/CTEDisabler.ts", "../src/transformers/TableSourceCollector.ts", "../src/models/SqlPrintToken.ts", "../src/transformers/ParameterCollector.ts", "../src/parsers/IdentifierDecorator.ts", "../src/parsers/ParameterDecorator.ts", "../src/models/UpdateQuery.ts", "../src/transformers/SelectValueCollector.ts", "../src/models/CreateTableQuery.ts", "../src/parsers/SqlPrintTokenParser.ts", "../src/transformers/LinePrinter.ts", "../src/transformers/SqlPrinter.ts", "../src/transformers/SqlFormatter.ts", "../src/transformers/Formatter.ts", "../src/transformers/CTEBuilder.ts", "../src/transformers/CTEInjector.ts", "../src/transformers/CTENormalizer.ts", "../src/transformers/SelectableColumnCollector.ts", "../src/parsers/SourceParser.ts", "../src/transformers/UpstreamSelectQueryFinder.ts", "../src/parsers/SourceAliasExpressionParser.ts", "../src/parsers/SourceExpressionParser.ts", "../src/transformers/QueryBuilder.ts", "../src/utils/ParameterHelper.ts", "../src/models/SimpleSelectQuery.ts", "../src/models/BinarySelectQuery.ts", "../src/models/ValuesQuery.ts", "../src/parsers/SelectClauseParser.ts", "../src/parsers/JoinOnClauseParser.ts", "../src/parsers/JoinUsingClauseParser.ts", "../src/parsers/JoinClauseParser.ts", "../src/parsers/FromClauseParser.ts", "../src/parsers/WhereClauseParser.ts", "../src/parsers/GroupByParser.ts", "../src/parsers/HavingParser.ts", "../src/parsers/WindowClauseParser.ts", "../src/parsers/LimitClauseParser.ts", "../src/parsers/ForClauseParser.ts", "../src/parsers/CommonTableParser.ts", "../src/parsers/WithClauseParser.ts", "../src/parsers/ValuesQueryParser.ts", "../src/parsers/FetchClauseParser.ts", "../src/parsers/OffsetClauseParser.ts", "../src/parsers/SelectQueryParser.ts", "../src/parsers/InsertQueryParser.ts", "../src/transformers/PostgresObjectEntityCteBuilder.ts", "../src/transformers/PostgresArrayEntityCteBuilder.ts", "../src/transformers/PostgresJsonQueryBuilder.ts", "../src/transformers/
|
|
4
|
-
"sourcesContent": ["// Entry point for rawsql-ts package\r\nexport * from './parsers/SelectQueryParser';\r\nexport * from './parsers/InsertQueryParser';\r\n\r\nexport * from './models/BinarySelectQuery';\r\nexport * from './models/SelectQuery';\r\nexport * from './models/ValueComponent';\r\nexport * from './models/ValuesQuery';\r\n\r\nexport * from './transformers/CTECollector';\r\nexport * from './transformers/CTENormalizer';\r\nexport * from './transformers/Formatter';\r\nexport * from './transformers/SqlFormatter';\r\nexport * from './transformers/PostgresJsonQueryBuilder';\r\nexport * from './transformers/QueryBuilder'; // old name:QueryConverter\r\nexport * from './transformers/SelectValueCollector';\r\nexport * from './transformers/SelectableColumnCollector';\r\nexport * from './transformers/TableColumnResolver';\r\nexport * from './transformers/TableSourceCollector';\r\nexport * from './transformers/UnifiedJsonMapping';\r\nexport {\r\n ModelDrivenJsonMapping,\r\n convertModelDrivenMapping,\r\n validateModelDrivenMapping,\r\n FieldMapping,\r\n NestedStructure,\r\n StructureFields,\r\n FieldType\r\n} from './transformers/ModelDrivenJsonMapping';\r\nexport {\r\n processJsonMapping,\r\n unifyJsonMapping,\r\n isModelDrivenFormat,\r\n isUnifiedFormat,\r\n isLegacyFormat\r\n} from './transformers/JsonMappingUnifier';\r\nexport * from './transformers/UpstreamSelectQueryFinder';\r\nexport * from './transformers/TypeTransformationPostProcessor';\r\n\r\nexport * from './transformers/SchemaCollector';\r\nexport * from './transformers/SqlParamInjector';\r\nexport * from './transformers/SqlSortInjector';\r\nexport * from './transformers/SqlPaginationInjector';\r\nexport * from './transformers/DynamicQueryBuilder';\r\n\r\nexport * from './utils/SqlSchemaValidator';\r\nexport * from './utils/JsonSchemaValidator';\r\nexport * from './utils/SchemaManager';\r\n// Add more exports here if you want to expose additional public API\r\n", "\uFEFFexport abstract class SqlComponent {\r\n // `kind` is declared abstractly and defined concretely in a subclass.\r\n static kind: symbol;\r\n\r\n getKind(): symbol {\r\n return (this.constructor as typeof SqlComponent).kind;\r\n }\r\n\r\n accept<T>(visitor: SqlComponentVisitor<T>): T {\r\n return visitor.visit(this);\r\n }\r\n\r\n toSqlString(formatter: SqlComponentVisitor<string>): string {\r\n return this.accept(formatter);\r\n }\r\n\r\n comments: string[] | null = null;\r\n}\r\n\r\nexport interface SqlComponentVisitor<T> {\r\n visit(expr: SqlComponent): T;\r\n}\r\n\r\nexport class SqlDialectConfiguration {\r\n public parameterSymbol: string = \":\";\r\n public identifierEscape = { start: '\"', end: '\"' };\r\n public exportComment: boolean = true;\r\n}\r\n", "// Represents an INSERT query in SQL.\r\n// Supports single/multi-row VALUES and INSERT ... SELECT.\r\nimport { SqlComponent } from \"./SqlComponent\";\r\nimport { SelectQuery } from \"./SelectQuery\";\r\nimport { InsertClause } from \"./Clause\";\r\n\r\nexport class InsertQuery extends SqlComponent {\r\n static kind = Symbol(\"InsertQuery\");\r\n insertClause: InsertClause;\r\n selectQuery: SelectQuery | null;\r\n\r\n /**\r\n * @param params.insertClause InsertClause instance (target table and columns)\r\n * @param params.selectQuery SELECT/VALUES query (required)\r\n */\r\n constructor(params: {\r\n insertClause: InsertClause;\r\n selectQuery?: SelectQuery | null;\r\n }) {\r\n super();\r\n this.insertClause = params.insertClause;\r\n this.selectQuery = params.selectQuery ?? null;\r\n }\r\n}", "import { PartitionByClause, OrderByClause } from \"./Clause\";\r\nimport { SelectQuery, SimpleSelectQuery } from \"./SelectQuery\";\r\nimport { SqlComponent } from \"./SqlComponent\";\r\n\r\nexport type ValueComponent = ValueList |\r\n ColumnReference |\r\n FunctionCall |\r\n UnaryExpression |\r\n BinaryExpression |\r\n LiteralValue |\r\n ParameterExpression |\r\n SwitchCaseArgument |\r\n CaseKeyValuePair |\r\n RawString |\r\n IdentifierString |\r\n ParenExpression |\r\n CastExpression |\r\n CaseExpression |\r\n ArrayExpression |\r\n ArrayQueryExpression |\r\n BetweenExpression |\r\n InlineQuery |\r\n StringSpecifierExpression |\r\n TypeValue |\r\n TupleExpression;\r\n\r\nexport class InlineQuery extends SqlComponent {\r\n static kind = Symbol(\"InlineQuery\");\r\n selectQuery: SelectQuery;\r\n constructor(selectQuery: SelectQuery) {\r\n super();\r\n this.selectQuery = selectQuery;\r\n }\r\n}\r\n\r\nexport class ValueList extends SqlComponent {\r\n static kind = Symbol(\"ValueList\");\r\n values: ValueComponent[];\r\n constructor(values: ValueComponent[]) {\r\n super();\r\n this.values = values;\r\n }\r\n}\r\n\r\nexport class ColumnReference extends SqlComponent {\r\n /**\r\n * For backward compatibility: returns the namespaces as IdentifierString[] | null (readonly)\r\n */\r\n get namespaces(): IdentifierString[] | null {\r\n return this.qualifiedName.namespaces;\r\n }\r\n /**\r\n * For backward compatibility: returns the column name as IdentifierString (readonly)\r\n */\r\n get column(): IdentifierString {\r\n // If the name is RawString, convert to IdentifierString for compatibility\r\n if (this.qualifiedName.name instanceof IdentifierString) {\r\n return this.qualifiedName.name;\r\n } else {\r\n return new IdentifierString(this.qualifiedName.name.value);\r\n }\r\n }\r\n static kind = Symbol(\"ColumnReference\");\r\n qualifiedName: QualifiedName; constructor(namespaces: string | string[] | IdentifierString[] | null, column: string | IdentifierString) {\r\n super();\r\n const col = typeof column === \"string\" ? new IdentifierString(column) : column;\r\n this.qualifiedName = new QualifiedName(toIdentifierStringArray(namespaces), col);\r\n }\r\n\r\n public toString(): string {\r\n return this.qualifiedName.toString();\r\n }\r\n public getNamespace(): string {\r\n if (this.qualifiedName.namespaces) {\r\n return this.qualifiedName.namespaces.map((namespace) => namespace.name).join(\".\");\r\n } else {\r\n return '';\r\n }\r\n }\r\n}\r\n\r\nexport class FunctionCall extends SqlComponent {\r\n static kind = Symbol(\"FunctionCall\");\r\n qualifiedName: QualifiedName;\r\n argument: ValueComponent | null;\r\n over: OverExpression | null; constructor(\r\n namespaces: string | string[] | IdentifierString[] | null,\r\n name: string | RawString | IdentifierString,\r\n argument: ValueComponent | null,\r\n over: OverExpression | null\r\n ) {\r\n super();\r\n this.qualifiedName = new QualifiedName(namespaces, name);\r\n this.argument = argument;\r\n this.over = over;\r\n }\r\n\r\n /**\r\n * For backward compatibility: returns the namespaces as IdentifierString[] | null (readonly)\r\n */\r\n get namespaces(): IdentifierString[] | null {\r\n return this.qualifiedName.namespaces;\r\n }\r\n /**\r\n * For backward compatibility: returns the function name as RawString | IdentifierString (readonly)\r\n */\r\n get name(): RawString | IdentifierString {\r\n return this.qualifiedName.name;\r\n }\r\n}\r\n\r\nexport type OverExpression = WindowFrameExpression | IdentifierString;\r\n\r\nexport enum WindowFrameType {\r\n Rows = \"rows\",\r\n Range = \"range\",\r\n Groups = \"groups\",\r\n}\r\n\r\nexport enum WindowFrameBound {\r\n UnboundedPreceding = \"unbounded preceding\",\r\n UnboundedFollowing = \"unbounded following\",\r\n CurrentRow = \"current row\",\r\n}\r\n\r\nexport type FrameBoundaryComponent = WindowFrameBoundStatic | WindowFrameBoundaryValue;\r\n\r\nexport class WindowFrameBoundStatic extends SqlComponent {\r\n static kind = Symbol(\"WindowFrameStaticBound\");\r\n bound: WindowFrameBound;\r\n constructor(bound: WindowFrameBound) {\r\n super();\r\n this.bound = bound;\r\n }\r\n}\r\n\r\nexport class WindowFrameBoundaryValue extends SqlComponent {\r\n static kind = Symbol(\"WindowFrameBoundary\");\r\n value: ValueComponent;\r\n isFollowing: boolean; // true for \"FOLLOWING\", false for \"PRECEDING\"\r\n constructor(value: ValueComponent, isFollowing: boolean) {\r\n super();\r\n this.value = value;\r\n this.isFollowing = isFollowing;\r\n }\r\n}\r\n\r\nexport class WindowFrameSpec extends SqlComponent {\r\n static kind = Symbol(\"WindowFrameSpec\");\r\n frameType: WindowFrameType;\r\n startBound: FrameBoundaryComponent;\r\n endBound: FrameBoundaryComponent | null; // null for single boundary specification\r\n constructor(frameType: WindowFrameType, startBound: FrameBoundaryComponent, endBound: FrameBoundaryComponent | null) {\r\n super();\r\n this.frameType = frameType;\r\n this.startBound = startBound;\r\n this.endBound = endBound;\r\n }\r\n}\r\n\r\nexport class WindowFrameExpression extends SqlComponent {\r\n static kind = Symbol(\"WindowFrameExpression\");\r\n partition: PartitionByClause | null;\r\n order: OrderByClause | null;\r\n frameSpec: WindowFrameSpec | null;\r\n constructor(partition: PartitionByClause | null, order: OrderByClause | null, frameSpec: WindowFrameSpec | null = null) {\r\n super();\r\n this.partition = partition;\r\n this.order = order;\r\n this.frameSpec = frameSpec;\r\n }\r\n}\r\n\r\nexport class UnaryExpression extends SqlComponent {\r\n static kind = Symbol(\"UnaryExpression\");\r\n operator: RawString;\r\n expression: ValueComponent;\r\n constructor(operator: string, expression: ValueComponent) {\r\n super();\r\n this.operator = new RawString(operator);\r\n this.expression = expression;\r\n }\r\n}\r\n\r\nexport class BinaryExpression extends SqlComponent {\r\n static kind = Symbol(\"BinaryExpression\");\r\n left: ValueComponent;\r\n operator: RawString;\r\n right: ValueComponent;\r\n constructor(left: ValueComponent, operator: string, right: ValueComponent) {\r\n super();\r\n this.left = left;\r\n this.operator = new RawString(operator);\r\n this.right = right;\r\n }\r\n}\r\n\r\nexport class LiteralValue extends SqlComponent {\r\n static kind = Symbol(\"LiteralExpression\");\r\n // Use the string type instead of the RawString type because it has its own escaping process.\r\n value: string | number | boolean | null;\r\n constructor(value: string | number | boolean | null) {\r\n super();\r\n this.value = value;\r\n }\r\n}\r\n\r\nexport class ParameterExpression extends SqlComponent {\r\n static kind = Symbol(\"ParameterExpression\");\r\n name: RawString;\r\n value: any | null; // Holds the parameter value; can be provided via second argument.\r\n /**\r\n * The index assigned by the formatter when generating parameterized queries.\r\n * Used for naming parameters like $1, $2, etc.\r\n */\r\n index: number | null;\r\n constructor(name: string, value: any | null = null) {\r\n super();\r\n this.name = new RawString(name);\r\n this.value = value; // Value is now accepted as a second argument (optional)\r\n this.index = null;\r\n }\r\n}\r\n\r\nexport class SwitchCaseArgument extends SqlComponent {\r\n static kind = Symbol(\"SwitchCaseArgument\");\r\n cases: CaseKeyValuePair[];\r\n elseValue: ValueComponent | null;\r\n constructor(cases: CaseKeyValuePair[], elseValue: ValueComponent | null = null) {\r\n super();\r\n this.cases = cases;\r\n this.elseValue = elseValue;\r\n }\r\n}\r\n\r\nexport class CaseKeyValuePair extends SqlComponent {\r\n static kind = Symbol(\"CaseKeyValuePair\");\r\n key: ValueComponent;\r\n value: ValueComponent;\r\n constructor(key: ValueComponent, value: ValueComponent) {\r\n super();\r\n this.key = key;\r\n this.value = value;\r\n }\r\n}\r\n\r\n/*\r\n * Values \u200B\u200Bthat must be hard-coded, such as type names and function names.\r\n * A simple check is performed when decoding.\r\n */\r\nexport class RawString extends SqlComponent {\r\n static kind = Symbol(\"RawString\");\r\n value: string;\r\n constructor(value: string) {\r\n super();\r\n this.value = value;\r\n }\r\n}\r\n\r\nexport class IdentifierString extends SqlComponent {\r\n static kind = Symbol(\"IdentifierString\");\r\n name: string;\r\n constructor(alias: string) {\r\n super();\r\n this.name = alias;\r\n }\r\n}\r\n\r\nexport class ParenExpression extends SqlComponent {\r\n static kind = Symbol(\"ParenExpression\");\r\n expression: ValueComponent;\r\n constructor(expression: ValueComponent) {\r\n super();\r\n this.expression = expression;\r\n }\r\n}\r\n\r\nexport class CastExpression extends SqlComponent {\r\n static kind = Symbol(\"CastExpression\");\r\n input: ValueComponent;\r\n castType: TypeValue;\r\n constructor(input: ValueComponent, castType: TypeValue) {\r\n super();\r\n this.input = input;\r\n this.castType = castType;\r\n }\r\n}\r\n\r\nexport class CaseExpression extends SqlComponent {\r\n static kind = Symbol(\"CaseExpression\");\r\n condition: ValueComponent | null;\r\n switchCase: SwitchCaseArgument;\r\n\r\n constructor(condition: ValueComponent | null, switchCase: SwitchCaseArgument) {\r\n super();\r\n this.condition = condition;\r\n this.switchCase = switchCase;\r\n }\r\n}\r\n\r\nexport class ArrayExpression extends SqlComponent {\r\n static kind = Symbol(\"ArrayExpression\");\r\n expression: ValueComponent;\r\n constructor(expression: ValueComponent) {\r\n super();\r\n this.expression = expression;\r\n }\r\n}\r\n\r\nexport class ArrayQueryExpression extends SqlComponent {\r\n static kind = Symbol(\"ArrayQueryExpression\");\r\n query: SelectQuery;\r\n constructor(query: SelectQuery) {\r\n super();\r\n this.query = query;\r\n }\r\n}\r\n\r\nexport class BetweenExpression extends SqlComponent {\r\n static kind = Symbol(\"BetweenExpression\");\r\n expression: ValueComponent;\r\n lower: ValueComponent;\r\n upper: ValueComponent;\r\n negated: boolean;\r\n constructor(expression: ValueComponent, lower: ValueComponent, upper: ValueComponent, negated: boolean) {\r\n super();\r\n this.expression = expression;\r\n this.lower = lower;\r\n this.upper = upper;\r\n this.negated = negated;\r\n }\r\n}\r\n\r\nexport class StringSpecifierExpression extends SqlComponent {\r\n static kind = Symbol(\"StringSpecifierExpression\");\r\n // e.g. 'E', 'X', 'U&'\r\n specifier: RawString;\r\n value: LiteralValue;\r\n constructor(specifier: string, value: string) {\r\n super();\r\n this.specifier = new RawString(specifier);\r\n this.value = new LiteralValue(value);\r\n }\r\n}\r\n\r\n// other\r\n\r\nexport class TypeValue extends SqlComponent {\r\n static kind = Symbol(\"TypeValue\");\r\n qualifiedName: QualifiedName;\r\n argument: ValueComponent | null;\r\n constructor(namespaces: string[] | IdentifierString[] | null, name: string | RawString | IdentifierString, argument: ValueComponent | null = null) {\r\n super();\r\n this.qualifiedName = new QualifiedName(namespaces, name);\r\n this.argument = argument;\r\n }\r\n /**\r\n * For backward compatibility: returns the namespaces as IdentifierString[] | null (readonly)\r\n */\r\n get namespaces(): IdentifierString[] | null {\r\n return this.qualifiedName.namespaces;\r\n }\r\n /**\r\n * For backward compatibility: returns the type name as RawString | IdentifierString (readonly)\r\n */\r\n get name(): RawString | IdentifierString {\r\n return this.qualifiedName.name;\r\n }\r\n public getTypeName(): string {\r\n const nameValue = this.qualifiedName.name instanceof RawString ? this.qualifiedName.name.value : this.qualifiedName.name.name;\r\n if (this.qualifiedName.namespaces && this.qualifiedName.namespaces.length > 0) {\r\n return this.qualifiedName.namespaces.map(ns => ns.name).join(\".\") + \".\" + nameValue;\r\n } else {\r\n return nameValue;\r\n }\r\n }\r\n}\r\n\r\nexport class TupleExpression extends SqlComponent {\r\n static kind = Symbol(\"TupleExpression\");\r\n values: ValueComponent[];\r\n constructor(values: ValueComponent[]) {\r\n super();\r\n this.values = values;\r\n }\r\n}\r\n\r\nfunction toIdentifierStringArray(input: string | string[] | IdentifierString[] | null): IdentifierString[] | null {\r\n if (input == null) return null;\r\n\r\n if (typeof input === \"string\") {\r\n // Empty string should be treated as null\r\n return input.trim() === \"\" ? null : [new IdentifierString(input)];\r\n }\r\n\r\n if (Array.isArray(input)) {\r\n if (input.length === 0) return null;\r\n\r\n if (typeof input[0] === \"string\") {\r\n // Filter out empty strings from string array\r\n const filteredStrings = (input as string[]).filter(ns => ns.trim() !== \"\");\r\n return filteredStrings.length === 0 ? null : filteredStrings.map(ns => new IdentifierString(ns));\r\n } else {\r\n // Filter out empty IdentifierStrings from IdentifierString array\r\n const filteredIdentifiers = (input as IdentifierString[]).filter(ns => ns.name.trim() !== \"\");\r\n return filteredIdentifiers.length === 0 ? null : filteredIdentifiers;\r\n }\r\n }\r\n\r\n return null;\r\n}\r\n\r\n/**\r\n * Represents a qualified name with optional namespaces (e.g. schema.table, db.schema.function)\r\n */\r\nexport class QualifiedName extends SqlComponent {\r\n static kind = Symbol(\"QualifiedName\");\r\n\r\n /** List of namespaces (e.g. schema, database) */\r\n namespaces: IdentifierString[] | null;\r\n /** The actual name (e.g. table, function, type, column) */\r\n name: RawString | IdentifierString;\r\n\r\n constructor(namespaces: string | string[] | IdentifierString[] | null, name: string | RawString | IdentifierString) {\r\n super();\r\n this.namespaces = toIdentifierStringArray(namespaces);\r\n if (typeof name === \"string\") {\r\n this.name = new RawString(name);\r\n } else {\r\n this.name = name;\r\n }\r\n }\r\n\r\n /** Returns the full qualified name as a string (dot-separated) */\r\n toString(): string {\r\n const nameValue = this.name instanceof RawString ? this.name.value : this.name.name;\r\n if (this.namespaces && this.namespaces.length > 0) {\r\n return this.namespaces.map(ns => ns.name).join(\".\") + \".\" + nameValue;\r\n } else {\r\n return nameValue;\r\n }\r\n }\r\n}", "import { SelectQuery, SimpleSelectQuery } from \"./SelectQuery\";\r\nimport { SqlComponent } from \"./SqlComponent\";\r\nimport { IdentifierString, RawString, TupleExpression, ValueComponent, WindowFrameExpression, QualifiedName } from \"./ValueComponent\";\r\n\r\nexport class SelectItem extends SqlComponent {\r\n static kind = Symbol(\"SelectItem\");\r\n value: ValueComponent;\r\n identifier: IdentifierString | null;\r\n constructor(value: ValueComponent, name: string | null = null) {\r\n super();\r\n this.value = value;\r\n this.identifier = name ? new IdentifierString(name) : null;\r\n }\r\n}\r\n\r\nexport class SelectClause extends SqlComponent {\r\n static kind = Symbol(\"SelectClause\");\r\n items: SelectItem[];\r\n distinct: DistinctComponent | null;\r\n constructor(items: SelectItem[], distinct: DistinctComponent | null = null) {\r\n super();\r\n this.items = items;\r\n this.distinct = distinct;\r\n }\r\n}\r\n\r\nexport type DistinctComponent = Distinct | DistinctOn;\r\n\r\nexport class Distinct extends SqlComponent {\r\n static kind = Symbol(\"Distinct\");\r\n constructor() {\r\n super();\r\n }\r\n}\r\n\r\nexport class DistinctOn extends SqlComponent {\r\n static kind = Symbol(\"DistinctOn\");\r\n value: ValueComponent;\r\n constructor(value: ValueComponent) {\r\n super();\r\n this.value = value;\r\n }\r\n}\r\n\r\n\r\nexport class WhereClause extends SqlComponent {\r\n static kind = Symbol(\"WhereClause\");\r\n condition: ValueComponent;\r\n constructor(condition: ValueComponent) {\r\n super();\r\n this.condition = condition;\r\n }\r\n}\r\n\r\nexport class PartitionByClause extends SqlComponent {\r\n static kind = Symbol(\"PartitionByClause\");\r\n value: ValueComponent;\r\n constructor(value: ValueComponent) {\r\n super();\r\n this.value = value;\r\n }\r\n}\r\n\r\nexport class WindowFrameClause extends SqlComponent {\r\n static kind = Symbol(\"WindowFrameClause\");\r\n name: IdentifierString;\r\n expression: WindowFrameExpression;\r\n constructor(name: string, expression: WindowFrameExpression) {\r\n super();\r\n this.name = new IdentifierString(name);\r\n this.expression = expression;\r\n }\r\n}\r\n\r\n/**\r\n * Represents a collection of window definitions (WINDOW clause in SQL).\r\n * @param windows Array of WindowFrameClause\r\n */\r\nexport class WindowsClause extends SqlComponent {\r\n static kind = Symbol(\"WindowsClause\");\r\n windows: WindowFrameClause[];\r\n constructor(windows: WindowFrameClause[]) {\r\n super();\r\n this.windows = windows;\r\n }\r\n}\r\n\r\nexport enum SortDirection {\r\n Ascending = \"asc\",\r\n Descending = \"desc\",\r\n}\r\nexport enum NullsSortDirection {\r\n First = \"first\",\r\n Last = \"last\",\r\n}\r\n\r\nexport type OrderByComponent = OrderByItem | ValueComponent;\r\n\r\nexport class OrderByClause extends SqlComponent {\r\n static kind = Symbol(\"OrderByClause\");\r\n order: OrderByComponent[];\r\n constructor(items: OrderByComponent[]) {\r\n super();\r\n this.order = items;\r\n }\r\n}\r\n\r\nexport class OrderByItem extends SqlComponent {\r\n static kind = Symbol(\"OrderByItem\");\r\n value: ValueComponent;\r\n sortDirection: SortDirection;\r\n nullsPosition: NullsSortDirection | null;\r\n constructor(expression: ValueComponent, sortDirection: SortDirection | null, nullsPosition: NullsSortDirection | null) {\r\n super();\r\n this.value = expression;\r\n this.sortDirection = sortDirection === null ? SortDirection.Ascending : sortDirection;\r\n this.nullsPosition = nullsPosition;\r\n }\r\n}\r\n\r\nexport class GroupByClause extends SqlComponent {\r\n static kind = Symbol(\"GroupByClause\");\r\n grouping: ValueComponent[];\r\n constructor(expression: ValueComponent[]) {\r\n super();\r\n this.grouping = expression;\r\n }\r\n}\r\n\r\nexport class HavingClause extends SqlComponent {\r\n static kind = Symbol(\"HavingClause\");\r\n condition: ValueComponent;\r\n constructor(condition: ValueComponent) {\r\n super();\r\n this.condition = condition;\r\n }\r\n}\r\n\r\nexport type SourceComponent = TableSource |\r\n FunctionSource |\r\n SubQuerySource |\r\n ParenSource;\r\n\r\nexport class TableSource extends SqlComponent {\r\n static kind = Symbol(\"TableSource\");\r\n qualifiedName: QualifiedName;\r\n /**\r\n * For backward compatibility: returns the namespaces as IdentifierString[] | null (readonly)\r\n */\r\n get namespaces(): IdentifierString[] | null {\r\n return this.qualifiedName.namespaces;\r\n }\r\n /**\r\n * For backward compatibility: returns the table name as IdentifierString (readonly)\r\n */\r\n get table(): IdentifierString {\r\n // If the name is RawString, convert to IdentifierString for compatibility\r\n if (this.qualifiedName.name instanceof IdentifierString) {\r\n return this.qualifiedName.name;\r\n } else {\r\n return new IdentifierString(this.qualifiedName.name.value);\r\n }\r\n }\r\n /**\r\n * For backward compatibility: returns the table name as IdentifierString (readonly)\r\n */\r\n get identifier(): IdentifierString {\r\n return this.table;\r\n }\r\n constructor(namespaces: string[] | IdentifierString[] | null, table: string | IdentifierString) {\r\n super();\r\n // Convert the table name to an IdentifierString if it is provided as a string.\r\n const tbl = typeof table === \"string\" ? new IdentifierString(table) : table;\r\n // Wrap the namespaces and table name in a QualifiedName object.\r\n // This design choice ensures backward compatibility by allowing the namespaces\r\n // and table name to be accessed in a way consistent with the previous implementation.\r\n this.qualifiedName = new QualifiedName(namespaces, tbl);\r\n }\r\n public getSourceName(): string {\r\n if (this.qualifiedName.namespaces && this.qualifiedName.namespaces.length > 0) {\r\n return this.qualifiedName.namespaces.map((namespace) => namespace.name).join(\".\") + \".\" + (this.qualifiedName.name instanceof RawString ? this.qualifiedName.name.value : this.qualifiedName.name.name);\r\n } else {\r\n return this.qualifiedName.name instanceof RawString ? this.qualifiedName.name.value : this.qualifiedName.name.name;\r\n }\r\n }\r\n}\r\n\r\nexport class FunctionSource extends SqlComponent {\r\n static kind = Symbol(\"FunctionSource\");\r\n qualifiedName: QualifiedName;\r\n argument: ValueComponent | null;\r\n constructor(\r\n name: string | IdentifierString | { namespaces: string[] | IdentifierString[] | null, name: string | RawString | IdentifierString },\r\n argument: ValueComponent | null\r\n ) {\r\n super();\r\n if (typeof name === \"object\" && name !== null && \"name\" in name) {\r\n // Accepts { namespaces, name }\r\n const nameObj = name as { namespaces: string[] | IdentifierString[] | null, name: string | RawString | IdentifierString };\r\n this.qualifiedName = new QualifiedName(nameObj.namespaces, nameObj.name);\r\n } else {\r\n this.qualifiedName = new QualifiedName(null, name as string | RawString | IdentifierString);\r\n }\r\n this.argument = argument;\r\n }\r\n\r\n /**\r\n * For backward compatibility: returns the namespaces as IdentifierString[] | null (readonly)\r\n */\r\n get namespaces(): IdentifierString[] | null {\r\n return this.qualifiedName.namespaces;\r\n }\r\n /**\r\n * For backward compatibility: returns the function name as RawString | IdentifierString (readonly)\r\n */\r\n get name(): RawString | IdentifierString {\r\n return this.qualifiedName.name;\r\n }\r\n}\r\n\r\nexport class ParenSource extends SqlComponent {\r\n static kind = Symbol(\"ParenSource\");\r\n source: SourceComponent;\r\n constructor(source: SourceComponent) {\r\n super();\r\n this.source = source;\r\n }\r\n}\r\n\r\nexport class SubQuerySource extends SqlComponent {\r\n static kind = Symbol(\"SubQuerySource\");\r\n query: SelectQuery;\r\n constructor(query: SelectQuery) {\r\n super();\r\n this.query = query;\r\n }\r\n}\r\n\r\nexport class SourceExpression extends SqlComponent {\r\n static kind = Symbol(\"SourceExpression\");\r\n datasource: SourceComponent;\r\n aliasExpression: SourceAliasExpression | null;\r\n constructor(datasource: SourceComponent, aliasExpression: SourceAliasExpression | null) {\r\n super();\r\n this.datasource = datasource;\r\n this.aliasExpression = aliasExpression;\r\n }\r\n public getAliasName(): string | null {\r\n if (this.aliasExpression) {\r\n return this.aliasExpression.table.name;\r\n }\r\n else if (this.datasource instanceof TableSource) {\r\n return this.datasource.getSourceName();\r\n }\r\n return null;\r\n }\r\n}\r\n\r\nexport type JoinConditionComponent = JoinOnClause | JoinUsingClause;\r\n\r\nexport class JoinOnClause extends SqlComponent {\r\n static kind = Symbol(\"JoinOnClause\");\r\n condition: ValueComponent;\r\n constructor(condition: ValueComponent) {\r\n super();\r\n this.condition = condition;\r\n }\r\n}\r\n\r\nexport class JoinUsingClause extends SqlComponent {\r\n static kind = Symbol(\"JoinUsingClause\");\r\n condition: ValueComponent;\r\n constructor(condition: ValueComponent) {\r\n super();\r\n this.condition = condition;\r\n }\r\n}\r\n\r\nexport class JoinClause extends SqlComponent {\r\n static kind = Symbol(\"JoinItem\");\r\n joinType: RawString;\r\n source: SourceExpression;\r\n condition: JoinConditionComponent | null;\r\n lateral: boolean;\r\n constructor(joinType: string, source: SourceExpression, condition: JoinConditionComponent | null, lateral: boolean) {\r\n super();\r\n this.joinType = new RawString(joinType);\r\n this.source = source;\r\n this.condition = condition;\r\n this.lateral = lateral;\r\n }\r\n public getSourceAliasName(): string | null {\r\n if (this.source.aliasExpression) {\r\n return this.source.aliasExpression.table.name;\r\n }\r\n else if (this.source instanceof TableSource) {\r\n return this.source.table.name;\r\n }\r\n return null;\r\n }\r\n}\r\n\r\nexport class FromClause extends SqlComponent {\r\n static kind = Symbol(\"FromClause\");\r\n source: SourceExpression;\r\n joins: JoinClause[] | null;\r\n constructor(source: SourceExpression, join: JoinClause[] | null) {\r\n super();\r\n this.source = source;\r\n this.joins = join;\r\n }\r\n public getSourceAliasName(): string | null {\r\n if (this.source.aliasExpression) {\r\n return this.source.aliasExpression.table.name;\r\n }\r\n else if (this.source.datasource instanceof TableSource) {\r\n return this.source.datasource.table.name;\r\n }\r\n return null;\r\n }\r\n /**\r\n * Returns all SourceExpression objects in this FROM clause, including main source and all JOIN sources.\r\n */\r\n public getSources(): SourceExpression[] {\r\n const sources: SourceExpression[] = [this.source];\r\n if (this.joins) {\r\n for (const join of this.joins) {\r\n sources.push(join.source);\r\n }\r\n }\r\n return sources;\r\n }\r\n}\r\n\r\nexport class CommonTable extends SqlComponent {\r\n static kind = Symbol(\"CommonTable\");\r\n query: SelectQuery;\r\n materialized: boolean | null;\r\n aliasExpression: SourceAliasExpression;\r\n constructor(query: SelectQuery, aliasExpression: SourceAliasExpression | string, materialized: boolean | null) {\r\n super();\r\n this.query = query;\r\n this.materialized = materialized;\r\n if (typeof aliasExpression === \"string\") {\r\n this.aliasExpression = new SourceAliasExpression(aliasExpression, null);\r\n } else {\r\n this.aliasExpression = aliasExpression;\r\n }\r\n }\r\n public getSourceAliasName(): string {\r\n return this.aliasExpression.table.name;\r\n }\r\n}\r\n\r\nexport class WithClause extends SqlComponent {\r\n static kind = Symbol(\"WithClause\");\r\n recursive: boolean;\r\n tables: CommonTable[];\r\n constructor(recursive: boolean, tables: CommonTable[]) {\r\n super();\r\n this.recursive = recursive;\r\n this.tables = tables;\r\n }\r\n}\r\n\r\nexport class LimitClause extends SqlComponent {\r\n static kind = Symbol(\"LimitClause\");\r\n value: ValueComponent;\r\n constructor(limit: ValueComponent) {\r\n super();\r\n this.value = limit;\r\n }\r\n}\r\n\r\nexport enum FetchType {\r\n Next = \"next\",\r\n First = \"first\",\r\n}\r\n\r\nexport enum FetchUnit {\r\n RowsOnly = \"rows only\",\r\n Percent = \"percent\",\r\n PercentWithTies = \"percent with ties\",\r\n}\r\n\r\n\r\nexport class OffsetClause extends SqlComponent {\r\n static kind = Symbol(\"OffsetClause\");\r\n value: ValueComponent;\r\n constructor(value: ValueComponent) {\r\n super();\r\n this.value = value;\r\n }\r\n}\r\n\r\nexport class FetchClause extends SqlComponent {\r\n static kind = Symbol(\"FetchClause\");\r\n expression: FetchExpression;\r\n constructor(expression: FetchExpression) {\r\n super();\r\n this.expression = expression;\r\n }\r\n}\r\n\r\nexport class FetchExpression extends SqlComponent {\r\n static kind = Symbol(\"FetchExpression\");\r\n // type count unit\r\n type: FetchType;\r\n count: ValueComponent;\r\n unit: FetchUnit | null;\r\n constructor(type: FetchType, count: ValueComponent, unit: FetchUnit | null) {\r\n super();\r\n this.type = type;\r\n this.count = count;\r\n this.unit = unit;\r\n }\r\n}\r\n\r\nexport enum LockMode {\r\n Update = \"update\",\r\n Share = \"share\",\r\n KeyShare = \"key share\",\r\n NokeyUpdate = \"no key update\",\r\n}\r\n\r\nexport class ForClause extends SqlComponent {\r\n static kind = Symbol(\"ForClause\");\r\n lockMode: LockMode;\r\n constructor(lockMode: LockMode) {\r\n super();\r\n this.lockMode = lockMode;\r\n }\r\n}\r\n\r\nexport class SourceAliasExpression extends SqlComponent {\r\n static kind = Symbol(\"SourceAliasExpression\");\r\n table: IdentifierString;\r\n columns: IdentifierString[] | null;\r\n constructor(alias: string, columnAlias: string[] | null) {\r\n super();\r\n this.table = new IdentifierString(alias);\r\n this.columns = columnAlias !== null ? columnAlias.map((alias) => new IdentifierString(alias)) : null;\r\n }\r\n}\r\n\r\nexport class ReturningClause extends SqlComponent {\r\n static kind = Symbol(\"ReturningClause\");\r\n columns: IdentifierString[];\r\n /**\r\n * Constructs a ReturningClause.\r\n * @param columns Array of IdentifierString or string representing column names.\r\n */\r\n constructor(columns: (IdentifierString | string)[]) {\r\n super();\r\n this.columns = columns.map(col => typeof col === \"string\" ? new IdentifierString(col) : col);\r\n }\r\n}\r\n\r\nexport class SetClause extends SqlComponent {\r\n static kind = Symbol(\"SetClause\");\r\n items: SetClauseItem[];\r\n constructor(items: (SetClauseItem | { column: string | IdentifierString, value: ValueComponent })[]) {\r\n super();\r\n this.items = items.map(item => item instanceof SetClauseItem ? item : new SetClauseItem(item.column, item.value));\r\n }\r\n}\r\n\r\n/**\r\n * Represents a single SET clause item in an UPDATE statement.\r\n */\r\n/**\r\n * Represents a single SET clause item in an UPDATE statement.\r\n * Now supports namespaces for fully qualified column names (e.g. schema.table.column).\r\n */\r\n/**\r\n * Represents a single SET clause item in an UPDATE statement.\r\n * Now supports namespaces for fully qualified column names (e.g. schema.table.column).\r\n * Refactored to use QualifiedName for unified name/namespace handling.\r\n */\r\nexport class SetClauseItem extends SqlComponent {\r\n static kind = Symbol(\"SetClauseItem\");\r\n qualifiedName: QualifiedName;\r\n value: ValueComponent;\r\n constructor(\r\n column: string | IdentifierString | { namespaces: string[] | IdentifierString[] | null, column: string | IdentifierString },\r\n value: ValueComponent\r\n ) {\r\n super();\r\n // Accepts { namespaces, column } or just column\r\n if (typeof column === \"object\" && column !== null && \"column\" in column) {\r\n const colObj = column as { namespaces: string[] | IdentifierString[] | null, column: string | IdentifierString };\r\n const col = typeof colObj.column === \"string\" ? new IdentifierString(colObj.column) : colObj.column;\r\n this.qualifiedName = new QualifiedName(colObj.namespaces, col);\r\n } else {\r\n const col = typeof column === \"string\" ? new IdentifierString(column) : column as IdentifierString;\r\n this.qualifiedName = new QualifiedName(null, col);\r\n }\r\n this.value = value;\r\n }\r\n /**\r\n * For backward compatibility: returns the namespaces as IdentifierString[] | null (readonly)\r\n */\r\n get namespaces(): IdentifierString[] | null {\r\n return this.qualifiedName.namespaces;\r\n }\r\n /**\r\n * For backward compatibility: returns the column name as IdentifierString (readonly)\r\n */\r\n get column(): IdentifierString {\r\n if (this.qualifiedName.name instanceof IdentifierString) {\r\n return this.qualifiedName.name;\r\n } else {\r\n return new IdentifierString(this.qualifiedName.name.value);\r\n }\r\n }\r\n /**\r\n * Returns the fully qualified column name as a string.\r\n */\r\n public getFullName(): string {\r\n return this.qualifiedName.toString();\r\n }\r\n}\r\n\r\nexport class UpdateClause extends SqlComponent {\r\n static kind = Symbol(\"UpdateClause\");\r\n source: SourceExpression;\r\n constructor(source: SourceExpression) {\r\n super();\r\n this.source = source;\r\n }\r\n public getSourceAliasName() {\r\n if (this.source.aliasExpression) {\r\n return this.source.aliasExpression.table.name;\r\n }\r\n else if (this.source.datasource instanceof TableSource) {\r\n return this.source.datasource.table.name;\r\n }\r\n return null;\r\n }\r\n}\r\n\r\n/**\r\n * Represents the target table (with optional alias/schema) and columns for an INSERT statement.\r\n * @param source The target table as a SourceExpression (can include schema, alias, etc.)\r\n * @param columns Array of column names (as strings)\r\n */\r\nexport class InsertClause extends SqlComponent {\r\n source: SourceExpression;\r\n columns: IdentifierString[];\r\n\r\n constructor(source: SourceExpression, columns: string[]) {\r\n super();\r\n this.source = source;\r\n this.columns = columns.map((col) => new IdentifierString(col));\r\n }\r\n}", "\uFEFFexport enum TokenType {\r\n None = 0,\r\n Literal = 1 << 0,\r\n Operator = 1 << 1,\r\n OpenParen = 1 << 2,\r\n CloseParen = 1 << 3,\r\n Comma = 1 << 4,\r\n Dot = 1 << 5,\r\n Identifier = 1 << 6,\r\n Command = 1 << 7, // select, from, where as, on, array etc\r\n Parameter = 1 << 8,\r\n OpenBracket = 1 << 9,\r\n CloseBracket = 1 << 10,\r\n Function = 1 << 11, // next token is open paren\r\n StringSpecifier = 1 << 12, // next token is string literal\r\n Type = 1 << 13,\r\n}\r\n\r\n/**\r\n * Represents a lexical token in SQL parsing\r\n */\r\nexport interface Lexeme {\r\n type: number; // Bit flags for TokenType\r\n value: string;\r\n comments: string[] | null;\r\n}\r\n", "\uFEFF/**\r\n * Fast character classification utilities for SQL tokenization\r\n */\r\nexport class CharLookupTable {\r\n public static isWhitespace(char: string): boolean {\r\n if (char.length !== 1) return false;\r\n const code = char.charCodeAt(0);\r\n // Check for space(32), tab(9), line feed(10), carriage return(13)\r\n return code === 32 || code === 9 || code === 10 || code === 13;\r\n }\r\n\r\n public static isDigit(char: string): boolean {\r\n if (char.length !== 1) return false;\r\n const code = char.charCodeAt(0);\r\n // Check if within '0'(48) to '9'(57) range\r\n return code >= 48 && code <= 57;\r\n }\r\n\r\n public static isHexChar(char: string): boolean {\r\n if (char.length !== 1) return false;\r\n const code = char.charCodeAt(0);\r\n // Check if '0'(48) to '9'(57) or 'a'(97) to 'f'(102) or 'A'(65) to 'F'(70)\r\n return (code >= 48 && code <= 57) ||\r\n (code >= 97 && code <= 102) ||\r\n (code >= 65 && code <= 70);\r\n }\r\n\r\n public static isOperatorSymbol(char: string): boolean {\r\n if (char.length !== 1) return false;\r\n const code = char.charCodeAt(0);\r\n\r\n // Check for specific operator character codes\r\n // '+'=43, '-'=45, '*'=42, '/'=47, '%'=37, '~'=126, '@'=64, '#'=35, '^'=94, \r\n // '&'=38, ':'=58, '!'=33, '<'=60, '>'=62, '='=61, '|'=124\r\n return code === 43 || code === 45 || code === 42 || code === 47 ||\r\n code === 37 || code === 126 || code === 64 || code === 35 ||\r\n code === 94 || code === 38 || code === 58 || code === 33 ||\r\n code === 60 || code === 62 || code === 61 || code === 124;\r\n }\r\n\r\n public static isDelimiter(char: string): boolean {\r\n if (char.length !== 1) return false;\r\n const code = char.charCodeAt(0);\r\n\r\n // First check delimiters: '.'=46, ','=44, '('=40, ')'=41, '['=91, ']'=93, '{'=123, '}'=125, ';'=59\r\n if (code === 46 || code === 44 || code === 40 || code === 41 ||\r\n code === 91 || code === 93 || code === 123 || code === 125 || code === 59) {\r\n return true;\r\n }\r\n\r\n // Then check for whitespace: ' '=32, '\\t'=9, '\\n'=10, '\\r'=13\r\n if (code === 32 || code === 9 || code === 10 || code === 13) {\r\n return true;\r\n }\r\n\r\n // Finally check for operator symbols\r\n // '+'=43, '-'=45, '*'=42, '/'=47, '%'=37, '~'=126, '@'=64, '#'=35, '^'=94, \r\n // '&'=38, ':'=58, '!'=33, '<'=60, '>'=62, '='=61, '|'=124\r\n return code === 43 || code === 45 || code === 42 || code === 47 ||\r\n code === 37 || code === 126 || code === 64 || code === 35 ||\r\n code === 94 || code === 38 || code === 58 || code === 33 ||\r\n code === 60 || code === 62 || code === 61 || code === 124;\r\n }\r\n\r\n public static isNamedParameterPrefix(char: string): boolean {\r\n if (char.length !== 1) return false;\r\n const code = char.charCodeAt(0);\r\n\r\n // Check for parameter prefix characters: '@'=64, ':'=58, '$'=36\r\n return code === 64 || code === 58 || code === 36;\r\n }\r\n}\r\n", "\uFEFFimport { CharLookupTable } from \"./charLookupTable\";\r\n\r\n/**\r\n * Utilities for string operations during tokenization\r\n */\r\nexport class StringUtils {\r\n /**\r\n * Creates a visual representation of an error position in text\r\n * @param input The input text\r\n * @param errPosition The error position\r\n * @returns A string with a caret pointing to the error position\r\n */\r\n public static getDebugPositionInfo(input: string, errPosition: number): string {\r\n // Get 5 characters before and after the error\r\n // If the start and end points are out of the string range, keep them within the range\r\n // Display ^ at the error position on the next line\r\n const start = Math.max(0, errPosition - 5);\r\n const end = Math.min(input.length, errPosition + 5);\r\n const debugInfo = input.slice(start, end);\r\n const caret = ' '.repeat(errPosition - start) + '^';\r\n return `${debugInfo}\\n${caret}`;\r\n }\r\n\r\n /**\r\n * Skip white space characters.\r\n */\r\n private static skipWhiteSpace(input: string, position: number): number {\r\n const length = input.length;\r\n\r\n /*\r\n * Optimization: Try to skip 4 spaces at once (for 4-space indents).\r\n * This is effective when SQL is deeply nested and uses 4-space indentation.\r\n * In typical cases, charCodeAt in a loop is fastest, but for large/indented SQL,\r\n * this can reduce the number of iterations and improve stability (lower error/deviation in benchmarks).\r\n * If indentation is not 4 spaces, this check is skipped quickly, so overhead is minimal.\r\n *\r\n * Even for 2-space indents or mixed indents (2, 4, tab),\r\n * the remaining whitespace is handled by the following loop, so there is no performance loss.\r\n *\r\n * Benchmark results show that this optimization does not slow down short queries,\r\n * and can make long/indented queries more stable and slightly faster.\r\n */\r\n while (position + 4 <= length && input.slice(position, position + 4) === ' ') {\r\n position += 4;\r\n }\r\n\r\n // Then skip remaining whitespace one by one (space, tab, newline, carriage return)\r\n while (position < length) {\r\n const charCode = input.charCodeAt(position);\r\n // ' '=32, '\\t'=9, '\\n'=10, '\\r'=13\r\n if (charCode !== 32 && charCode !== 9 && charCode !== 10 && charCode !== 13) {\r\n break;\r\n }\r\n position++;\r\n }\r\n\r\n return position;\r\n }\r\n\r\n /**\r\n * Skip line comment.\r\n */\r\n private static readLineComment(input: string, position: number): { newPosition: number, comment: string | null } {\r\n if (position + 1 >= input.length) {\r\n return { newPosition: position, comment: null };\r\n }\r\n\r\n // '-'=45\r\n if (input.charCodeAt(position) === 45 && input.charCodeAt(position + 1) === 45) {\r\n const start = position;\r\n position += 2;\r\n\r\n // '\\n'=10\r\n while (position < input.length && input.charCodeAt(position) !== 10) {\r\n position++;\r\n }\r\n\r\n // Return the trimmed comment content (excluding -- tokens)\r\n const comment = input.slice(start + 2, position).trim();\r\n return { newPosition: position, comment };\r\n }\r\n return { newPosition: position, comment: null };\r\n }\r\n\r\n /**\r\n * Skip block comment.\r\n */\r\n private static readBlockComment(input: string, position: number): { newPosition: number, comments: string[] | null } {\r\n if (position + 3 >= input.length) {\r\n return { newPosition: position, comments: null };\r\n }\r\n\r\n // '/'=47, '*'=42, '+'=43\r\n if (input.charCodeAt(position) === 47 && input.charCodeAt(position + 1) === 42 && input.charCodeAt(position + 2) !== 43) {\r\n const start = position;\r\n position += 2;\r\n\r\n while (position + 1 < input.length) {\r\n // '*'=42, '/'=47\r\n if (input.charCodeAt(position) === 42 && input.charCodeAt(position + 1) === 47) {\r\n position += 2;\r\n\r\n // Process the comment content\r\n const lines = input.slice(start + 2, position - 2).replace(/\\r/g, '').split('\\n');\r\n for (let i = 0; i < lines.length; i++) {\r\n lines[i] = lines[i].trim();\r\n }\r\n\r\n // Remove empty lines, but only at the beginning and end\r\n while (lines.length > 0 && lines[0] === '') {\r\n lines.shift();\r\n }\r\n while (lines.length > 0 && lines[lines.length - 1] === '') {\r\n lines.pop();\r\n }\r\n\r\n return { newPosition: position, comments: lines };\r\n }\r\n position++;\r\n }\r\n throw new Error(`Block comment is not closed. position: ${position}`);\r\n }\r\n return { newPosition: position, comments: null };\r\n }\r\n\r\n /**\r\n * Skip white space characters and SQL comments.\r\n * @returns Object containing the new position and an array of skipped comments\r\n */\r\n public static readWhiteSpaceAndComment(input: string, position: number): { position: number, lines: string[] } {\r\n const lines: string[] = [];\r\n const length = input.length;\r\n\r\n while (position < length) {\r\n // Store current position\r\n const oldPosition = position;\r\n\r\n // Skip whitespace first\r\n position = StringUtils.skipWhiteSpace(input, position);\r\n if (position !== oldPosition) {\r\n continue;\r\n }\r\n\r\n // Fast character code check\r\n const charCode = input.charCodeAt(position);\r\n\r\n // '-'=45 (Line comment)\r\n if (charCode === 45) {\r\n const lineCommentResult = StringUtils.readLineComment(input, position);\r\n if (lineCommentResult.newPosition !== position) {\r\n position = lineCommentResult.newPosition;\r\n if (lineCommentResult.comment) {\r\n lines.push(lineCommentResult.comment.trim());\r\n }\r\n continue;\r\n }\r\n }\r\n // '/'=47 (Block comment)\r\n else if (charCode === 47) {\r\n const blockCommentResult = StringUtils.readBlockComment(input, position);\r\n if (blockCommentResult.newPosition !== position) {\r\n position = blockCommentResult.newPosition;\r\n if (blockCommentResult.comments) {\r\n lines.push(...blockCommentResult.comments);\r\n }\r\n continue;\r\n }\r\n }\r\n\r\n // No more whitespace or comments found\r\n break;\r\n }\r\n\r\n return { position, lines: lines };\r\n }\r\n\r\n /**\r\n * Read a regular identifier.\r\n */\r\n public static readRegularIdentifier(input: string, position: number): { identifier: string, newPosition: number } {\r\n const result = this.tryReadRegularIdentifier(input, position);\r\n\r\n if (!result) {\r\n throw new Error(`Unexpected character. position: ${position}\\n${StringUtils.getDebugPositionInfo(input, position)}`);\r\n }\r\n\r\n return result;\r\n }\r\n\r\n public static tryReadRegularIdentifier(input: string, position: number): { identifier: string, newPosition: number } | null {\r\n const start = position;\r\n\r\n while (position < input.length) {\r\n if (CharLookupTable.isDelimiter(input[position])) {\r\n break;\r\n }\r\n position++;\r\n }\r\n\r\n if (start === position) {\r\n return null;\r\n }\r\n\r\n // Check index range before checking for [] (array type)\r\n while (\r\n position + 1 < input.length &&\r\n input[position] === '[' &&\r\n input[position + 1] === ']'\r\n ) {\r\n position += 2; // Skip the []\r\n }\r\n\r\n return {\r\n identifier: input.slice(start, position),\r\n newPosition: position\r\n };\r\n }\r\n}\r\n", "\uFEFFimport { Lexeme, TokenType } from '../models/Lexeme';\r\nimport { StringUtils } from '../utils/stringUtils';\r\n\r\n/**\r\n * Base class for token readers\r\n */\r\nexport abstract class BaseTokenReader {\r\n protected input: string;\r\n protected position: number;\r\n\r\n constructor(input: string, position: number = 0) {\r\n this.input = input;\r\n this.position = position;\r\n }\r\n\r\n /**\r\n * Get the current position in the input\r\n */\r\n public getPosition(): number {\r\n return this.position;\r\n }\r\n\r\n /**\r\n * Set the position in the input\r\n */\r\n public setPosition(position: number): void {\r\n this.position = position;\r\n }\r\n\r\n /**\r\n * Check if we've reached the end of input\r\n */\r\n protected isEndOfInput(shift: number = 0): boolean {\r\n return this.position + shift >= this.input.length;\r\n }\r\n\r\n /**\r\n * Check if we can read more characters\r\n */\r\n protected canRead(shift: number = 0): boolean {\r\n return !this.isEndOfInput(shift);\r\n }\r\n\r\n /**\r\n * Read an expected character\r\n */\r\n protected read(expectChar: string): string {\r\n if (this.isEndOfInput()) {\r\n throw new Error(`Unexpected character. expect: ${expectChar}, actual: EndOfInput, position: ${this.position}`);\r\n }\r\n\r\n const char = this.input[this.position];\r\n if (char !== expectChar) {\r\n throw new Error(`Unexpected character. expect: ${expectChar}, actual: ${char}, position: ${this.position}`);\r\n }\r\n\r\n this.position++;\r\n return char;\r\n }\r\n\r\n /**\r\n * Create a lexeme with the specified type and value\r\n */\r\n protected createLexeme(type: TokenType, value: string, comments: string[] | null = null): Lexeme {\r\n if (type === TokenType.Command || type === TokenType.Operator || type === TokenType.Function) {\r\n // Benchmark tests showed that directly calling toLowerCase() is ~5x faster\r\n // than first checking if the string is already lowercase.\r\n // See benchmarks/lowercase-benchmark.js for detailed performance analysis.\r\n return {\r\n type,\r\n value: value.toLowerCase(),\r\n comments: comments,\r\n };\r\n }\r\n return {\r\n type,\r\n value,\r\n comments: comments,\r\n };\r\n }\r\n\r\n /**\r\n * Get debug info for error reporting\r\n */\r\n protected getDebugPositionInfo(errPosition: number): string {\r\n return StringUtils.getDebugPositionInfo(this.input, errPosition);\r\n }\r\n\r\n /**\r\n * Try to read a token from the current position\r\n * @param previous The previous token, if available\r\n * @returns The read token or null if no token could be read\r\n */\r\n public abstract tryRead(previous: Lexeme | null): Lexeme | null;\r\n}\r\n", "\uFEFFimport { BaseTokenReader } from './BaseTokenReader';\r\nimport { Lexeme, TokenType } from '../models/Lexeme';\r\nimport { StringUtils } from '../utils/stringUtils';\r\n\r\n/**\r\n * Reads SQL identifier tokens\r\n */\r\nexport class IdentifierTokenReader extends BaseTokenReader {\r\n /**\r\n * Try to read an identifier token\r\n */\r\n public tryRead(previous: Lexeme | null): Lexeme | null {\r\n if (this.isEndOfInput()) {\r\n return null;\r\n }\r\n\r\n const char = this.input[this.position];\r\n\r\n // wildcard identifier\r\n if (char === '*') {\r\n // Assume that the OperatorTokenReader is executed before the IdentifierTokenReader.\r\n // Since we have determined that the OperatorTokenReader is not an Operator,\r\n // we treat '*' here as a wildcard identifier.\r\n this.position++;\r\n return this.createLexeme(TokenType.Identifier, char);\r\n }\r\n\r\n // Regular identifier\r\n const result = StringUtils.readRegularIdentifier(this.input, this.position);\r\n this.position = result.newPosition;\r\n return this.createLexeme(TokenType.Identifier, result.identifier);\r\n }\r\n}\r\n", "\uFEFFimport { KeywordTrie } from \"../models/KeywordTrie\";\r\nimport { StringUtils } from \"../utils/stringUtils\";\r\n\r\nexport enum KeywordMatchResult {\r\n NotAKeyword, // \"Not recognized as a keyword\"\r\n PartialOnly, // \"Partial match (this will not be the end)\"\r\n PartialOrFinal, // \"Partial or complete match (it can stop here)\"\r\n Final // \"Complete match (no longer keywords after this)\"\r\n}\r\n\r\nexport class KeywordParser {\r\n private trie: KeywordTrie;\r\n\r\n constructor(trie: KeywordTrie) {\r\n this.trie = trie;\r\n }\r\n\r\n private isEndOfInput(input: string, position: number, shift: number = 0): boolean {\r\n return position + shift >= input.length;\r\n }\r\n\r\n private canParse(input: string, position: number, shift: number = 0): boolean {\r\n return !this.isEndOfInput(input, position, shift);\r\n }\r\n\r\n public parse(input: string, position: number): { keyword: string, newPosition: number } | null {\r\n if (this.isEndOfInput(input, position)) {\r\n return null;\r\n }\r\n\r\n // reset trie node\r\n this.trie.reset();\r\n const result = StringUtils.tryReadRegularIdentifier(input, position);\r\n\r\n if (result === null) {\r\n return null;\r\n }\r\n\r\n let matchResult = this.trie.pushLexeme(result.identifier.toLowerCase());\r\n\r\n if (matchResult === KeywordMatchResult.NotAKeyword) {\r\n return null;\r\n }\r\n\r\n if (matchResult === KeywordMatchResult.Final) {\r\n return {\r\n keyword: result.identifier,\r\n newPosition: result.newPosition\r\n };\r\n }\r\n\r\n // multi-word keyword\r\n let lexeme = result.identifier;\r\n position = StringUtils.readWhiteSpaceAndComment(input, result.newPosition).position;\r\n\r\n // end of input\r\n if (this.isEndOfInput(input, position)) {\r\n if (matchResult === KeywordMatchResult.PartialOrFinal) {\r\n // if the last match was partial or final, it means that the keyword is finished\r\n return {\r\n keyword: lexeme,\r\n newPosition: position\r\n };\r\n } else {\r\n\r\n return null;\r\n }\r\n }\r\n\r\n while (this.canParse(input, position)) {\r\n const previousMatchResult = matchResult;\r\n\r\n const result = StringUtils.tryReadRegularIdentifier(input, position);\r\n\r\n if (result !== null) {\r\n matchResult = this.trie.pushLexeme(result.identifier.toLowerCase());\r\n\r\n if (matchResult === KeywordMatchResult.NotAKeyword) {\r\n if (previousMatchResult === KeywordMatchResult.PartialOrFinal) {\r\n break;\r\n } else {\r\n return null;\r\n }\r\n }\r\n\r\n lexeme += ' ' + result.identifier;\r\n position = StringUtils.readWhiteSpaceAndComment(input, result.newPosition).position;\r\n\r\n if (matchResult === KeywordMatchResult.Final) {\r\n break;\r\n }\r\n } else if (previousMatchResult === KeywordMatchResult.PartialOrFinal) {\r\n break;\r\n } else {\r\n return null;\r\n }\r\n }\r\n\r\n return {\r\n keyword: lexeme,\r\n newPosition: position\r\n };\r\n }\r\n}\r\n\r\n", "\uFEFFimport { KeywordMatchResult } from \"../parsers/KeywordParser\";\r\n\r\n// Note: An object-based trie (string-keyed object) was tested, but benchmark results showed no improvement and sometimes worse performance for long queries.\r\n// Therefore, the original Map-based implementation is retained for best stability and speed.\r\n\r\nexport class KeywordTrie {\r\n private root: Map<string, any> = new Map();\r\n private currentNode: Map<string, any>;\r\n\r\n // cache properties\r\n private hasEndProperty: boolean = false;\r\n private hasMoreProperties: boolean = false;\r\n\r\n constructor(keywords: string[][]) {\r\n // initialize root node\r\n for (const keyword of keywords) {\r\n this.addKeyword(keyword);\r\n }\r\n // set current node to root\r\n this.currentNode = this.root;\r\n }\r\n\r\n private addKeyword(keyword: string[]) {\r\n let node = this.root;\r\n for (const word of keyword) {\r\n if (!node.has(word)) {\r\n node.set(word, new Map());\r\n }\r\n node = node.get(word);\r\n }\r\n node.set(\"__end__\", true);\r\n }\r\n\r\n public reset(): void {\r\n this.currentNode = this.root;\r\n this.hasEndProperty = false;\r\n this.hasMoreProperties = false;\r\n }\r\n\r\n public pushLexeme(lexeme: string): KeywordMatchResult {\r\n if (!this.currentNode.has(lexeme)) {\r\n return KeywordMatchResult.NotAKeyword;\r\n }\r\n\r\n // move to next node\r\n this.currentNode = this.currentNode.get(lexeme);\r\n\r\n // Cache property checks to avoid repeated operations\r\n this.hasEndProperty = this.currentNode.has(\"__end__\");\r\n this.hasMoreProperties = this.currentNode.size > (this.hasEndProperty ? 1 : 0);\r\n\r\n if (this.hasEndProperty && !this.hasMoreProperties) {\r\n return KeywordMatchResult.Final;\r\n }\r\n if (this.hasEndProperty && this.hasMoreProperties) {\r\n return KeywordMatchResult.PartialOrFinal;\r\n }\r\n\r\n return KeywordMatchResult.PartialOnly;\r\n }\r\n}\r\n", "\uFEFFimport { BaseTokenReader } from './BaseTokenReader';\r\nimport { Lexeme, TokenType } from '../models/Lexeme';\r\nimport { CharLookupTable } from '../utils/charLookupTable';\r\nimport { KeywordParser } from '../parsers/KeywordParser';\r\nimport { KeywordTrie } from '../models/KeywordTrie';\r\n\r\n/**\r\n * Reads SQL literal tokens (numbers, strings)\r\n */\r\n\r\nconst keywords = [\r\n [\"null\"],\r\n [\"true\"],\r\n [\"false\"],\r\n [\"current_date\"],\r\n [\"current_time\"],\r\n [\"current_timestamp\"],\r\n [\"localtime\"],\r\n [\"localtimestamp\"],\r\n [\"unbounded\"],\r\n [\"normalized\"],\r\n [\"nfc\", \"normalized\"],\r\n [\"nfd\", \"normalized\"],\r\n [\"nfkc\", \"normalized\"],\r\n [\"nfkd\", \"normalized\"],\r\n [\"nfc\"],\r\n [\"nfd\"],\r\n [\"nfkc\"],\r\n [\"nfkd\"],\r\n];\r\nconst trie = new KeywordTrie(keywords);\r\nexport const literalKeywordParser = new KeywordParser(trie);\r\n\r\nexport class LiteralTokenReader extends BaseTokenReader {\r\n /**\r\n * Try to read a literal token\r\n */\r\n public tryRead(previous: Lexeme | null): Lexeme | null {\r\n if (this.isEndOfInput()) {\r\n return null;\r\n }\r\n\r\n const char = this.input[this.position];\r\n\r\n // Check for keyword literals \r\n const keyword = this.tryReadKeyword();\r\n if (keyword) {\r\n return keyword;\r\n }\r\n\r\n // Decimal token starting with a dot\r\n if (char === '.' && this.canRead(1) && CharLookupTable.isDigit(this.input[this.position + 1])) {\r\n return this.createLexeme(TokenType.Literal, this.readDigit());\r\n }\r\n\r\n // String literal\r\n if (char === '\\'') {\r\n const value = this.readSingleQuotedString(false);\r\n return this.createLexeme(TokenType.Literal, value);\r\n }\r\n\r\n // Digit tokens\r\n if (CharLookupTable.isDigit(char)) {\r\n return this.createLexeme(TokenType.Literal, this.readDigit());\r\n }\r\n\r\n // Signed number\r\n if ((char === '+' || char === '-') && this.determineSignOrOperator(previous) === \"sign\") {\r\n const sign = char;\r\n this.position++;\r\n\r\n // Skip whitespace after sign\r\n const pos = this.position;\r\n while (this.canRead() && CharLookupTable.isWhitespace(this.input[this.position])) {\r\n this.position++;\r\n }\r\n\r\n if (this.canRead() && (\r\n CharLookupTable.isDigit(this.input[this.position]) ||\r\n (this.input[this.position] === '.' &&\r\n this.canRead(1) &&\r\n CharLookupTable.isDigit(this.input[this.position + 1]))\r\n )) {\r\n return this.createLexeme(\r\n TokenType.Literal,\r\n sign === '-' ? sign + this.readDigit() : this.readDigit()\r\n );\r\n }\r\n\r\n // Not a number, restore position\r\n this.position = pos - 1; // Adjust for the increment at the beginning\r\n }\r\n\r\n return null;\r\n }\r\n\r\n private tryReadKeyword(): Lexeme | null {\r\n // Check for keyword literals\r\n const result = literalKeywordParser.parse(this.input, this.position);\r\n if (result) {\r\n this.position = result.newPosition;\r\n return this.createLexeme(TokenType.Literal, result.keyword);\r\n }\r\n return null;\r\n }\r\n\r\n /**\r\n * Determines if the current context treats '+' or '-' as a numeric sign or an operator.\r\n * This method is used to differentiate between operators and numeric signs (e.g., '+' or '-').\r\n *\r\n * For example:\r\n * - In `1-1`, the '-' is treated as an operator, so the expression is split into `1`, `-`, and `1`.\r\n * - In `-1`, the '-' is treated as a sign, making `-1` a single, indivisible literal.\r\n *\r\n * The logic for determining whether '+' or '-' is a sign or an operator is as follows:\r\n * - If there is no previous lexeme, it is considered the start of the input, so the sign is valid.\r\n * - If the previous lexeme is a literal, identifier, parameter, or closing parenthesis, the sign is treated as an operator.\r\n *\r\n * @param previous The previous lexeme in the input stream.\r\n * @returns \"sign\" if the context allows for a numeric sign, otherwise \"operator\".\r\n */\r\n private determineSignOrOperator(previous: Lexeme | null): \"sign\" | \"operator\" {\r\n // If there is no previous lexeme, treat as a sign\r\n if (previous === null) {\r\n return \"sign\";\r\n }\r\n\r\n // If the previous lexeme is a literal, identifier, parameter, or closing parenthesis, treat as an operator\r\n const isOperatorContext = (previous.type & TokenType.Literal) || \r\n (previous.type & TokenType.Identifier) || \r\n (previous.type & TokenType.Parameter) || \r\n (previous.type & TokenType.CloseParen);\r\n return isOperatorContext ? \"operator\" : \"sign\";\r\n }\r\n\r\n /**\r\n * Read a numeric value\r\n */\r\n private readDigit(): string {\r\n const start = this.position;\r\n let hasDot = false;\r\n let hasExponent = false;\r\n\r\n // Consider 0x, 0b, 0o\r\n if (this.canRead(1) &&\r\n this.input[this.position] === '0' &&\r\n \"xbo\".includes(this.input[this.position + 1].toLowerCase())) {\r\n\r\n const prefixType = this.input[this.position + 1].toLowerCase();\r\n this.position += 2;\r\n\r\n // Continue to get numeric and hexadecimal notation strings\r\n const isHex = prefixType === 'x';\r\n while (this.canRead()) {\r\n const c = this.input[this.position];\r\n if (CharLookupTable.isDigit(c) || (isHex && CharLookupTable.isHexChar(c))) {\r\n this.position++;\r\n } else {\r\n break;\r\n }\r\n }\r\n\r\n return this.input.slice(start, this.position);\r\n }\r\n\r\n // If starting with dot, note it\r\n if (this.input[start] === '.') {\r\n hasDot = true;\r\n this.position++;\r\n }\r\n\r\n // Consider decimal point and exponential notation\r\n while (this.canRead()) {\r\n const char = this.input[this.position];\r\n\r\n if (char === '.' && !hasDot) {\r\n hasDot = true;\r\n } else if ((char === 'e' || char === 'E') && !hasExponent) {\r\n hasExponent = true;\r\n if (this.canRead(1) && (this.input[this.position + 1] === '+' || this.input[this.position + 1] === '-')) {\r\n this.position++;\r\n }\r\n } else if (!CharLookupTable.isDigit(char)) {\r\n break;\r\n }\r\n\r\n this.position++;\r\n }\r\n\r\n if (start === this.position) {\r\n throw new Error(`Unexpected character. position: ${start}\\n${this.getDebugPositionInfo(start)}`);\r\n }\r\n\r\n if (this.input[start] === '.') {\r\n // If the number starts with a dot, add 0 to the front\r\n return '0' + this.input.slice(start, this.position);\r\n }\r\n\r\n return this.input.slice(start, this.position);\r\n }\r\n\r\n /**\r\n * Read a string literal\r\n */\r\n private readSingleQuotedString(includeSingleQuote: boolean): string {\r\n const start = this.position;\r\n let closed = false;\r\n this.read(\"'\");\r\n\r\n while (this.canRead()) {\r\n const char = this.input[this.position];\r\n this.position++;\r\n\r\n // escape character check\r\n if (char === \"\\\\\" && this.canRead(1)) {\r\n this.position++;\r\n continue;\r\n }\r\n else if (char === '\\'') {\r\n closed = true;\r\n break;\r\n }\r\n }\r\n\r\n if (closed === false) {\r\n throw new Error(`Single quote is not closed. position: ${start}\\n${this.getDebugPositionInfo(start)}`);\r\n }\r\n\r\n if (includeSingleQuote) {\r\n const value = this.input.slice(start, this.position);\r\n return value;\r\n } else {\r\n const value = this.input.slice(start + 1, this.position - 1);\r\n return value;\r\n }\r\n }\r\n}\r\n", "\uFEFFimport { BaseTokenReader } from './BaseTokenReader';\r\nimport { Lexeme, TokenType } from '../models/Lexeme';\r\nimport { CharLookupTable } from '../utils/charLookupTable';\r\n\r\n/**\r\n * Reads SQL parameter tokens (@param, :param, $param, ?, ${param})\r\n */\r\nexport class ParameterTokenReader extends BaseTokenReader {\r\n constructor(input: string) {\r\n super(input);\r\n }\r\n\r\n /**\r\n * Try to read a parameter token\r\n */\r\n public tryRead(previous: Lexeme | null): Lexeme | null {\r\n if (this.isEndOfInput()) {\r\n return null;\r\n }\r\n\r\n // parameter with suffix (${param}) - check this first\r\n if (this.canRead(1) && this.input[this.position] === '$' && this.input[this.position + 1] === '{') {\r\n this.position += 2; // Skip ${\r\n const start = this.position;\r\n while (this.canRead() && this.input[this.position] !== '}') {\r\n this.position++;\r\n }\r\n if (this.isEndOfInput()) {\r\n throw new Error(`Unexpected end of input. Expected closing '}' for parameter at position ${start}`);\r\n }\r\n\r\n const identifier = this.input.slice(start, this.position);\r\n if (identifier.length === 0) {\r\n throw new Error('Empty parameter name is not allowed: found ${} at position ' + (start - 2));\r\n }\r\n\r\n this.position++; // Skip }\r\n return this.createLexeme(TokenType.Parameter, '${' + identifier + '}');\r\n }\r\n\r\n const char = this.input[this.position];\r\n\r\n // named parameter (@param, :param, $param)\r\n if (CharLookupTable.isNamedParameterPrefix(char)) {\r\n\r\n // However, do not recognize as a parameter if the next character is an operator symbol\r\n // To avoid postgres `::`\r\n if (this.canRead(1) && CharLookupTable.isOperatorSymbol(this.input[this.position + 1])) {\r\n return null;\r\n }\r\n\r\n this.position++;\r\n\r\n // Read the identifier part after the prefix\r\n const start = this.position;\r\n while (this.canRead() && !CharLookupTable.isDelimiter(this.input[this.position])) {\r\n this.position++;\r\n }\r\n\r\n const identifier = this.input.slice(start, this.position);\r\n return this.createLexeme(TokenType.Parameter, char + identifier);\r\n }\r\n\r\n // nameless parameter (?)\r\n if (char === '?') {\r\n this.position++;\r\n return this.createLexeme(TokenType.Parameter, char);\r\n }\r\n\r\n return null;\r\n }\r\n}\r\n", "\uFEFFimport { BaseTokenReader } from './BaseTokenReader';\r\nimport { Lexeme, TokenType } from '../models/Lexeme';\r\n\r\n/**\r\n * Reads SQL symbol tokens (., ,, (, ))\r\n */\r\nexport class SpecialSymbolTokenReader extends BaseTokenReader {\r\n private static readonly SPECIAL_SYMBOL_TOKENS: Record<string, TokenType> = {\r\n '.': TokenType.Dot,\r\n ',': TokenType.Comma,\r\n '(': TokenType.OpenParen,\r\n ')': TokenType.CloseParen,\r\n '[': TokenType.OpenBracket,\r\n ']': TokenType.CloseBracket,\r\n };\r\n\r\n /**\r\n * Try to read a symbol token\r\n */\r\n public tryRead(previous: Lexeme | null): Lexeme | null {\r\n if (this.isEndOfInput()) {\r\n return null;\r\n }\r\n\r\n const char = this.input[this.position];\r\n\r\n // symbol tokens\r\n if (char in SpecialSymbolTokenReader.SPECIAL_SYMBOL_TOKENS) {\r\n this.position++;\r\n return this.createLexeme(\r\n SpecialSymbolTokenReader.SPECIAL_SYMBOL_TOKENS[char],\r\n char\r\n );\r\n }\r\n return null;\r\n }\r\n}\r\n", "\uFEFFimport { BaseTokenReader } from './BaseTokenReader';\r\nimport { Lexeme, TokenType } from '../models/Lexeme';\r\n\r\n/**\r\n * Manages and coordinates multiple token readers\r\n */\r\nexport class TokenReaderManager {\r\n private readers: BaseTokenReader[];\r\n private input: string;\r\n private position: number;\r\n private tokenCache: Map<number, Lexeme | null>;\r\n private cacheHits: number = 0;\r\n private cacheMisses: number = 0;\r\n\r\n constructor(input: string, position: number = 0) {\r\n this.input = input;\r\n this.position = position;\r\n this.readers = [];\r\n this.tokenCache = new Map();\r\n }\r\n\r\n /**\r\n * Register a token reader\r\n * @param reader The reader to register\r\n * @returns This manager instance for chaining\r\n */\r\n public register(reader: BaseTokenReader): TokenReaderManager {\r\n this.readers.push(reader);\r\n return this;\r\n }\r\n\r\n /**\r\n * Register multiple token readers\r\n * @param readers The readers to register\r\n * @returns This manager instance for chaining\r\n */\r\n public registerAll(readers: BaseTokenReader[]): TokenReaderManager {\r\n readers.forEach(reader => this.register(reader));\r\n return this;\r\n }\r\n\r\n /**\r\n * Update the position for all readers\r\n */\r\n private setPosition(position: number): void {\r\n this.position = position;\r\n for (const reader of this.readers) {\r\n reader.setPosition(position);\r\n }\r\n }\r\n\r\n /**\r\n * Try to read a token using all registered readers\r\n * @param position The position to read from\r\n * @param previous The previous token, if any\r\n * @returns The lexeme if a reader could read it, null otherwise\r\n */\r\n public tryRead(position: number, previous: Lexeme | null): Lexeme | null {\r\n // Check cache - using position as the key\r\n if (this.tokenCache.has(position)) {\r\n // Cache hit\r\n this.cacheHits++;\r\n const lexeme = this.tokenCache.get(position) || null;\r\n return lexeme;\r\n }\r\n\r\n // Cache miss - create new entry\r\n this.cacheMisses++;\r\n this.setPosition(position);\r\n\r\n // Try to read with each reader\r\n let lexeme: Lexeme | null = null;\r\n for (const reader of this.readers) {\r\n lexeme = reader.tryRead(previous);\r\n if (lexeme) {\r\n this.position = reader.getPosition();\r\n break;\r\n }\r\n }\r\n\r\n // Update all readers' positions\r\n for (const reader of this.readers) {\r\n reader.setPosition(this.position);\r\n }\r\n\r\n // Save to cache (even if null)\r\n this.tokenCache.set(position, lexeme);\r\n return lexeme;\r\n }\r\n\r\n /**\r\n * Get the maximum position among all readers\r\n */\r\n public getMaxPosition(): number {\r\n let maxPosition = this.position;\r\n for (const reader of this.readers) {\r\n const position = reader.getPosition();\r\n if (position > maxPosition) {\r\n maxPosition = position;\r\n }\r\n }\r\n return maxPosition;\r\n }\r\n\r\n /**\r\n * Get the input string\r\n */\r\n public getInput(): string {\r\n return this.input;\r\n }\r\n\r\n /**\r\n * Get cache statistics\r\n */\r\n public getCacheStats(): { hits: number, misses: number, ratio: number } {\r\n const total = this.cacheHits + this.cacheMisses;\r\n const ratio = total > 0 ? this.cacheHits / total : 0;\r\n return {\r\n hits: this.cacheHits,\r\n misses: this.cacheMisses,\r\n ratio: ratio\r\n };\r\n }\r\n}\r\n", "\uFEFFimport { BaseTokenReader } from './BaseTokenReader';\r\nimport { Lexeme, TokenType } from '../models/Lexeme';\r\nimport { CharLookupTable } from '../utils/charLookupTable';\r\nimport { KeywordParser } from '../parsers/KeywordParser';\r\nimport { KeywordTrie } from '../models/KeywordTrie';\r\n\r\nconst trie = new KeywordTrie([\r\n // binary\r\n [\"and\"],\r\n [\"or\"],\r\n [\"is\"],\r\n [\"is\", \"not\"],\r\n [\"is\", \"distinct\", \"from\"],\r\n [\"is\", \"not\", \"distinct\", \"from\"],\r\n [\"like\"],\r\n [\"ilike\"],\r\n [\"in\"],\r\n [\"exists\"],\r\n [\"between\"],\r\n [\"not\", \"like\"],\r\n [\"not\", \"ilike\"],\r\n [\"not\", \"in\"],\r\n [\"not\", \"exists\"],\r\n [\"not\", \"between\"],\r\n [\"escape\"], // e.g. '10% OFF on all items' like '10\\%%' escape '\\'\r\n [\"uescape\"], // e.g. U&'d!0061t!+000061' uescape '!'\r\n [\"similar\", \"to\"], // e.g. name similar to 'J(ohn|ane)%'\r\n [\"not\", \"similar\", \"to\"], // e.g. name not similar to 'J(ohn|ane)%'\r\n [\"similar\"], // e.g. substring('abcdef' similar '%#\"cd#\"%' escape '#')\r\n [\"placing\"], // e.g. overlay('abcdef' placing 'cd' from 3 for 2)\r\n // unary\r\n [\"not\"],\r\n // unary - trim\r\n [\"both\"],\r\n [\"leading\"],\r\n [\"trailing\"],\r\n [\"both\", \"from\"], // Postgres\r\n [\"leading\", \"from\"], // Postgres\r\n [\"trailing\", \"from\"], // Postgres\r\n // unary - extract\r\n [\"year\", \"from\"],\r\n [\"month\", \"from\"],\r\n [\"day\", \"from\"],\r\n [\"hour\", \"from\"],\r\n [\"minute\", \"from\"],\r\n [\"second\", \"from\"],\r\n [\"dow\", \"from\"],\r\n [\"doy\", \"from\"],\r\n [\"isodow\", \"from\"],\r\n [\"quarter\", \"from\"],\r\n [\"week\", \"from\"],\r\n [\"epoch\", \"from\"],\r\n [\"at\", \"time\", \"zone\"],\r\n // The following are not considered operators.\r\n // [\"from\"], can be used as an operator only within the substring function, but it cannot be distinguished from the Form Clause. This will be resolved with a dedicated substring parser.\r\n // [\"for\"], can be used as an operator only within the substring function, but it cannot be distinguished from the For Clause. This will be resolved with a dedicated substring parser.\r\n]);\r\n\r\n// Typed literal format\r\nconst operatorOrTypeTrie = new KeywordTrie([\r\n [\"date\"],\r\n [\"time\"],\r\n [\"timestamp\"],\r\n [\"timestamptz\"],// timestamp with time zone\r\n [\"timetz\"], // time with time zone\r\n [\"interval\"],\r\n [\"boolean\"],\r\n [\"integer\"],\r\n [\"bigint\"],\r\n [\"smallint\"],\r\n [\"numeric\"],\r\n [\"decimal\"],\r\n [\"real\"],\r\n [\"double\", \"precision\"],\r\n [\"double\", \"precision\"],\r\n [\"character\", \"varying\"],\r\n [\"time\", \"without\", \"time\", \"zone\"],\r\n [\"time\", \"with\", \"time\", \"zone\"],\r\n [\"timestamp\", \"without\", \"time\", \"zone\"],\r\n [\"timestamp\", \"with\", \"time\", \"zone\"],\r\n]);\r\n\r\nconst keywordParser = new KeywordParser(trie);\r\nconst operatorOrTypeParser = new KeywordParser(operatorOrTypeTrie);\r\n\r\n// Indicates the token may also represent a type (e.g., 'interval')\r\nconst MAYBE_TYPE = true;\r\n\r\nexport class OperatorTokenReader extends BaseTokenReader {\r\n public tryRead(previous: Lexeme | null): Lexeme | null {\r\n if (this.isEndOfInput()) {\r\n return null;\r\n }\r\n\r\n /*\r\n NOTE:\r\n Asterisks could potentially be wildcard identifiers,\r\n but since they're indistinguishable at this stage, they're treated as Operators at the token level.\r\n The Parser needs to determine whether they are appropriate Operators or Identifiers.\r\n */\r\n\r\n const char = this.input[this.position];\r\n\r\n if (CharLookupTable.isOperatorSymbol(char)) {\r\n const start = this.position;\r\n\r\n while (this.canRead() && CharLookupTable.isOperatorSymbol(this.input[this.position])) {\r\n // check for `--` and `/*` comments\r\n if (this.canRead(1)) {\r\n const current = this.input[this.position];\r\n if (current === '-' && this.input[this.position + 1] === '-') {\r\n break;\r\n } else if (current === '/' && this.input[this.position + 1] === '*') {\r\n break; // end of operator\r\n }\r\n }\r\n\r\n this.position++;\r\n }\r\n const resut = this.input.slice(start, this.position);\r\n return this.createLexeme(TokenType.Operator, resut);\r\n }\r\n\r\n // Logical operators\r\n let result = operatorOrTypeParser.parse(this.input, this.position);\r\n if (result !== null) {\r\n // Special handling for typed literal format.\r\n // Treated as an operator in cases like `interval '2 days'`,\r\n // but can also be used as a type in expressions like `'1 month'::interval`,\r\n // so we return it as both Operator and Type.\r\n this.position = result.newPosition;\r\n return this.createLexeme(TokenType.Operator | TokenType.Type | TokenType.Identifier, result.keyword);\r\n }\r\n\r\n result = keywordParser.parse(this.input, this.position);\r\n if (result !== null) {\r\n this.position = result.newPosition;\r\n return this.createLexeme(TokenType.Operator, result.keyword);\r\n }\r\n\r\n return null;\r\n }\r\n}\r\n", "\uFEFFimport { BaseTokenReader } from \"./BaseTokenReader\";\r\nimport { Lexeme, TokenType } from '../models/Lexeme';\r\nimport { KeywordTrie } from \"../models/KeywordTrie\";\r\nimport { KeywordParser } from \"../parsers/KeywordParser\";\r\n\r\n// Commands are those that require a dedicated parser.\r\n// Keywords composed of multiple words are also considered commands.\r\n// The exception is \"type\". Since types can be user-defined and cannot be accurately identified, they are treated as Identifiers.\r\n\r\nconst joinTrie = new KeywordTrie([\r\n [\"join\"],\r\n [\"inner\", \"join\"],\r\n [\"cross\", \"join\"],\r\n [\"left\", \"join\"],\r\n [\"left\", \"outer\", \"join\"],\r\n [\"right\", \"join\"],\r\n [\"right\", \"outer\", \"join\"],\r\n [\"full\", \"join\"],\r\n [\"full\", \"outer\", \"join\"],\r\n\r\n [\"natural\", \"join\"],\r\n [\"natural\", \"inner\", \"join\"],\r\n [\"natural\", \"left\", \"join\"],\r\n [\"natural\", \"left\", \"outer\", \"join\"],\r\n [\"natural\", \"right\", \"join\"],\r\n [\"natural\", \"right\", \"outer\", \"join\"],\r\n [\"natural\", \"full\", \"join\"],\r\n [\"natural\", \"full\", \"outer\", \"join\"],\r\n]);\r\nconst keywordTrie = new KeywordTrie([\r\n [\"with\"],\r\n [\"recursive\"],\r\n [\"materialized\"],\r\n [\"not\", \"materialized\"],\r\n [\"select\"],\r\n [\"from\"],\r\n [\"distinct\"],\r\n [\"distinct\", \"on\"],\r\n [\"where\"],\r\n [\"group\", \"by\"],\r\n [\"having\"],\r\n [\"order\", \"by\"],\r\n [\"limit\"],\r\n [\"offset\"],\r\n [\"fetch\"],\r\n [\"first\"],\r\n [\"next\"],\r\n [\"row\"],\r\n [\"row\", \"only\"],\r\n [\"rows\", \"only\"],\r\n [\"percent\"],\r\n [\"percent\", \"with\", \"ties\"],\r\n // for\r\n [\"for\"],\r\n [\"update\"],\r\n [\"share\"],\r\n [\"key\", \"share\"],\r\n [\"no\", \"key\", \"update\"],\r\n // set operations\r\n [\"union\"],\r\n [\"union\", \"all\"],\r\n [\"intersect\"],\r\n [\"intersect\", \"all\"],\r\n [\"except\"],\r\n [\"except\", \"all\"],\r\n // between and\r\n [\"beteen\"],\r\n // window functions\r\n [\"window\"],\r\n [\"over\"],\r\n [\"partition\", \"by\"],\r\n [\"range\"],\r\n [\"rows\"],\r\n [\"groups\"],\r\n // window frame\r\n [\"current\", \"row\"],\r\n [\"unbounded\", \"preceding\"],\r\n [\"unbounded\", \"following\"],\r\n [\"preceding\"],\r\n [\"following\"],\r\n // table join commands\r\n [\"on\"],\r\n [\"using\"],\r\n [\"lateral\"],\r\n // case \r\n [\"case\"],\r\n [\"case\", \"when\"],\r\n [\"when\"],\r\n [\"then\"],\r\n [\"else\"],\r\n [\"end\"],\r\n // others\r\n [\"insert\", \"into\"],\r\n [\"update\"],\r\n [\"delete\", \"from\"],\r\n [\"merge\", \"into\"],\r\n [\"matched\"],\r\n [\"not\", \"matched\"],\r\n [\"update\", \"set\"],\r\n [\"do\", \"nothing\"],\r\n [\"values\"],\r\n [\"set\"],\r\n [\"returning\"],\r\n [\"create\", \"table\"],\r\n [\"create\", \"temporary\", \"table\"],\r\n [\"tablesample\"],\r\n // cast\r\n [\"as\"],\r\n // odrder\r\n [\"asc\"],\r\n [\"desc\"],\r\n [\"nulls\", \"first\"],\r\n [\"nulls\", \"last\"],\r\n]);\r\nconst keywordParser = new KeywordParser(keywordTrie);\r\nexport const joinkeywordParser = new KeywordParser(joinTrie);\r\n\r\nexport class CommandTokenReader extends BaseTokenReader {\r\n public tryRead(previous: Lexeme | null): Lexeme | null {\r\n if (this.isEndOfInput()) {\r\n return null;\r\n }\r\n\r\n const keywordJoin = joinkeywordParser.parse(this.input, this.position);\r\n if (keywordJoin !== null) {\r\n this.position = keywordJoin.newPosition;\r\n return this.createLexeme(TokenType.Command, keywordJoin.keyword);\r\n }\r\n\r\n // Check for keyword identifiers\r\n const keyword = keywordParser.parse(this.input, this.position);\r\n if (keyword !== null) {\r\n this.position = keyword.newPosition;\r\n return this.createLexeme(TokenType.Command, keyword.keyword);\r\n }\r\n\r\n // check hint clause\r\n if (this.canRead(2) && this.input[this.position] === '/' && this.input[this.position + 1] === '*' && this.input[this.position + 2] === '+') {\r\n this.position += 3;\r\n const start = this.position;\r\n while (this.position + 1 < this.input.length) {\r\n if (this.input[this.position] === '*' && this.input[this.position + 1] === '/') {\r\n this.position += 2;\r\n return this.createLexeme(TokenType.Command, '/*+ ' + this.input.slice(start, this.position - 2).trim() + ' */');\r\n }\r\n this.position++;\r\n }\r\n throw new Error(`Block comment is not closed. position: ${this.position}`);\r\n }\r\n\r\n return null;\r\n }\r\n}\r\n", "import { Lexeme, TokenType } from '../models/Lexeme';\r\nimport { BaseTokenReader } from './BaseTokenReader';\r\n\r\n// Prefix sets for quick checks\r\nconst STRING_SPECIFIERS = new Set(['e\\'', 'E\\'', 'x\\'', 'X\\'', 'b\\'', 'B\\'']);\r\nconst UNICODE_STRING_SPECIFIERS = new Set(['u&\\'', 'U&\\'']);\r\n\r\nexport class StringSpecifierTokenReader extends BaseTokenReader {\r\n\r\n /**\r\n * Try to read an escaped literal like e'...', x'...', etc.\r\n */\r\n public tryRead(previous: Lexeme | null): Lexeme | null {\r\n const start = this.position;\r\n\r\n // Check for prefixed literals: e', x', b'\r\n if (this.canRead(1) && STRING_SPECIFIERS.has(this.input.slice(start, start + 2))) {\r\n this.position += 1;\r\n const result = this.createLexeme(TokenType.StringSpecifier, this.input.slice(start, this.position));\r\n return result;\r\n }\r\n\r\n // Check for unicode literal: u&'\r\n if (this.canRead(2) && UNICODE_STRING_SPECIFIERS.has(this.input.slice(start, start + 3))) {\r\n this.position += 2;\r\n const result = this.createLexeme(TokenType.StringSpecifier, this.input.slice(start, this.position));\r\n return result;\r\n }\r\n\r\n return null;\r\n }\r\n}\r\n", "\uFEFFimport { BaseTokenReader } from './BaseTokenReader';\r\nimport { Lexeme, TokenType } from '../models/Lexeme';\r\nimport { StringUtils } from '../utils/stringUtils';\r\nimport { KeywordTrie } from '../models/KeywordTrie';\r\nimport { KeywordParser } from '../parsers/KeywordParser';\r\n\r\nconst trie = new KeywordTrie([\r\n [\"grouping\", \"sets\"],\r\n // ARRAY has special syntax with [] arguments, so it is forcibly treated as a function\r\n [\"array\"],\r\n]);\r\nconst keywordParser = new KeywordParser(trie);\r\n\r\n/**\r\n * Reads SQL identifier tokens\r\n */\r\nexport class FunctionTokenReader extends BaseTokenReader {\r\n /**\r\n * Try to read an identifier token\r\n */\r\n public tryRead(previous: Lexeme | null): Lexeme | null {\r\n if (this.isEndOfInput()) {\r\n return null;\r\n }\r\n\r\n // Check for keyword identifiers\r\n const keyword = keywordParser.parse(this.input, this.position);\r\n if (keyword !== null) {\r\n this.position = keyword.newPosition;\r\n return this.createLexeme(TokenType.Function, keyword.keyword);\r\n }\r\n\r\n // Regular identifier\r\n const result = StringUtils.tryReadRegularIdentifier(this.input, this.position);\r\n if (!result) {\r\n return null;\r\n }\r\n this.position = result.newPosition;\r\n\r\n // peek next token \r\n var shift = StringUtils.readWhiteSpaceAndComment(this.input, this.position).position - this.position;\r\n\r\n if (this.canRead(shift) && this.input[this.position + shift] === '(') {\r\n return this.createLexeme(TokenType.Function, result.identifier);\r\n }\r\n return null;\r\n }\r\n}\r\n", "\uFEFFimport { BaseTokenReader } from './BaseTokenReader';\r\nimport { Lexeme, TokenType } from '../models/Lexeme';\r\nimport { StringUtils } from '../utils/stringUtils';\r\nimport { KeywordTrie } from '../models/KeywordTrie';\r\nimport { KeywordParser } from '../parsers/KeywordParser';\r\n\r\n// Use KeywordTrie to identify type names composed of multiple words.\r\nconst trie = new KeywordTrie([\r\n // type\r\n [\"double\", \"precision\"],\r\n [\"character\", \"varying\"],\r\n [\"time\", \"without\", \"time\", \"zone\"],\r\n [\"time\", \"with\", \"time\", \"zone\"],\r\n [\"timestamp\", \"without\", \"time\", \"zone\"],\r\n [\"timestamp\", \"with\", \"time\", \"zone\"],\r\n]);\r\nconst typeParser = new KeywordParser(trie);\r\n\r\n/**\r\n * Reads SQL identifier tokens\r\n */\r\nexport class TypeTokenReader extends BaseTokenReader {\r\n /**\r\n * Try to read an identifier token\r\n */\r\n public tryRead(previous: Lexeme | null): Lexeme | null {\r\n if (this.isEndOfInput()) {\r\n return null;\r\n }\r\n\r\n // Check for keyword identifiers\r\n const keyword = typeParser.parse(this.input, this.position);\r\n if (keyword !== null) {\r\n this.position = keyword.newPosition;\r\n return this.createLexeme(TokenType.Type, keyword.keyword);\r\n }\r\n\r\n // check pervious token\r\n if (previous === null) {\r\n return null;\r\n }\r\n\r\n const result = StringUtils.tryReadRegularIdentifier(this.input, this.position);\r\n if (!result) {\r\n return null;\r\n }\r\n this.position = result.newPosition;\r\n\r\n // type cast command\r\n if (previous.type & TokenType.Command && previous.value === \"as\") {\r\n // If the previous token is the `as` keyword, it could be a type cast or an identifier\r\n return this.createLexeme(TokenType.Identifier | TokenType.Type, result.identifier);\r\n }\r\n\r\n // postgres type conversion\r\n if (previous.type & TokenType.Operator && previous.value === \"::\") {\r\n return this.createLexeme(TokenType.Type, result.identifier);\r\n }\r\n\r\n return null;\r\n }\r\n}\r\n", "import { BaseTokenReader } from './BaseTokenReader';\r\nimport { Lexeme, TokenType } from '../models/Lexeme';\r\nimport { StringUtils } from '../utils/stringUtils';\r\n\r\n/**\r\n * Reads SQL identifier tokens\r\n */\r\nexport class EscapedIdentifierTokenReader extends BaseTokenReader {\r\n /**\r\n * Try to read an identifier token\r\n */\r\n public tryRead(previous: Lexeme | null): Lexeme | null {\r\n if (this.isEndOfInput()) {\r\n return null;\r\n }\r\n\r\n const char = this.input[this.position];\r\n\r\n // MySQL escaped identifier (escape character is backtick)\r\n if (char === '`') {\r\n const identifier = this.readEscapedIdentifier('`');\r\n return this.createLexeme(TokenType.Identifier, identifier);\r\n }\r\n\r\n // Postgres escaped identifier (escape character is double quote)\r\n if (char === '\"') {\r\n const identifier = this.readEscapedIdentifier('\"');\r\n return this.createLexeme(TokenType.Identifier, identifier);\r\n }\r\n\r\n // SQLServer escaped identifier (escape character is square bracket)\r\n if (char === '[' && (previous === null || previous.value !== \"array\")) {\r\n const identifier = this.readEscapedIdentifier(']');\r\n return this.createLexeme(TokenType.Identifier, identifier);\r\n }\r\n\r\n return null;\r\n }\r\n\r\n /**\r\n * Read an escaped identifier (surrounded by delimiters)\r\n */\r\n private readEscapedIdentifier(delimiter: string): string {\r\n const start = this.position;\r\n\r\n // Skip the opening delimiter\r\n this.position++;\r\n\r\n while (this.canRead()) {\r\n if (this.input[this.position] === delimiter) {\r\n break;\r\n }\r\n this.position++;\r\n }\r\n\r\n if (start === this.position) {\r\n throw new Error(`Closing delimiter is not found. position: ${start}, delimiter: ${delimiter}\\n${this.getDebugPositionInfo(start)}`);\r\n }\r\n\r\n // Skip the closing delimiter\r\n this.position++;\r\n\r\n // exclude the delimiter\r\n return this.input.slice(start + 1, this.position - 1);\r\n }\r\n}\r\n", "\uFEFFimport { Lexeme, TokenType } from '../models/Lexeme';\r\nimport { IdentifierTokenReader } from '../tokenReaders/IdentifierTokenReader';\r\nimport { LiteralTokenReader } from '../tokenReaders/LiteralTokenReader';\r\nimport { ParameterTokenReader } from '../tokenReaders/ParameterTokenReader';\r\nimport { SpecialSymbolTokenReader } from '../tokenReaders/SymbolTokenReader';\r\nimport { TokenReaderManager } from '../tokenReaders/TokenReaderManager';\r\nimport { OperatorTokenReader } from '../tokenReaders/OperatorTokenReader';\r\nimport { StringUtils } from '../utils/stringUtils';\r\nimport { CommandTokenReader } from '../tokenReaders/CommandTokenReader';\r\nimport { StringSpecifierTokenReader } from '../tokenReaders/StringSpecifierTokenReader';\r\nimport { FunctionTokenReader } from '../tokenReaders/FunctionTokenReader';\r\nimport { TypeTokenReader } from '../tokenReaders/TypeTokenReader';\r\nimport { EscapedIdentifierTokenReader } from '../tokenReaders/EscapedIdentifierTokenReader';\r\n\r\n/**\r\n * Class responsible for tokenizing SQL input.\r\n */\r\nexport class SqlTokenizer {\r\n /**\r\n * The input SQL string to be tokenized.\r\n */\r\n private input: string;\r\n\r\n /**\r\n * Current position within the input string.\r\n */\r\n private position: number;\r\n\r\n /**\r\n * Manager responsible for handling token readers.\r\n */\r\n private readerManager: TokenReaderManager;\r\n\r\n /**\r\n * Initializes a new instance of the SqlTokenizer.\r\n */\r\n constructor(input: string) {\r\n this.input = input;\r\n this.position = 0;\r\n\r\n // Initialize the token reader manager and register all readers\r\n this.readerManager = new TokenReaderManager(input)\r\n .register(new EscapedIdentifierTokenReader(input))\r\n .register(new ParameterTokenReader(input))\r\n .register(new StringSpecifierTokenReader(input))\r\n // LiteralTokenReader should be registered before SpecialSymbolTokenReader and OperatorTokenReader\r\n // Reason: To prevent numeric literals starting with a dot or sign from being misrecognized as operators\r\n // e.g. `1.0` is a literal, not an operator\r\n .register(new LiteralTokenReader(input))\r\n .register(new SpecialSymbolTokenReader(input))\r\n .register(new CommandTokenReader(input))\r\n .register(new OperatorTokenReader(input))\r\n // TypeTokenReader should be registered before FunctionTokenReader\r\n // Reason: To prevent types containing parentheses from being misrecognized as functions\r\n // e.g. `numeric(10, 2)` is a type, not a function\r\n .register(new TypeTokenReader(input))\r\n .register(new FunctionTokenReader(input))\r\n .register(new IdentifierTokenReader(input)) // IdentifierTokenReader should be registered last\r\n ;\r\n }\r\n\r\n /**\r\n * Checks if the end of input is reached.\r\n * \r\n * @param shift - The shift to consider beyond the current position.\r\n * @returns True if the end of input is reached; otherwise, false.\r\n */\r\n private isEndOfInput(shift: number = 0): boolean {\r\n return this.position + shift >= this.input.length;\r\n }\r\n\r\n /**\r\n * Checks if more input can be read.\r\n * \r\n * @param shift - The shift to consider beyond the current position.\r\n * @returns True if more input can be read; otherwise, false.\r\n */\r\n private canRead(shift: number = 0): boolean {\r\n return !this.isEndOfInput(shift);\r\n }\r\n\r\n /**\r\n * Reads the lexemes from the input string.\r\n * \r\n * @returns An array of lexemes extracted from the input string.\r\n * @throws Error if an unexpected character is encountered.\r\n */\r\n public readLexmes(): Lexeme[] {\r\n // Pre-allocate array with estimated capacity for better performance\r\n const estimatedTokens = Math.ceil(this.input.length / 8); // Assuming average token length of 8 chars\r\n const lexemes: Lexeme[] = new Array(estimatedTokens);\r\n let lexemeCount = 0;\r\n\r\n // Read initial prefix comments\r\n const comment = this.readComment();\r\n let pendingComments = comment.lines;\r\n this.position = comment.position;\r\n\r\n // Track the previous token\r\n let previous: Lexeme | null = null;\r\n\r\n // Read tokens until the end of input is reached\r\n while (this.canRead()) {\r\n // Semicolon is a delimiter, so stop reading\r\n if (this.input[this.position] === ';') {\r\n break;\r\n }\r\n\r\n // Read using the token reader manager\r\n const lexeme = this.readerManager.tryRead(this.position, previous);\r\n\r\n if (lexeme === null) {\r\n throw new Error(`Unexpected character. actual: ${this.input[this.position]}, position: ${this.position}\\n${this.getDebugPositionInfo(this.position)}`);\r\n }\r\n\r\n // Update position\r\n this.position = this.readerManager.getMaxPosition();\r\n\r\n // Read suffix comments\r\n const currentComment = this.readComment();\r\n this.position = currentComment.position;\r\n\r\n if ((lexeme.type & TokenType.Comma) || (lexeme.type & TokenType.Operator)) {\r\n // Carry over comments after commas or operators\r\n if (currentComment.lines.length > 0) {\r\n pendingComments.push(...currentComment.lines);\r\n }\r\n } else {\r\n // Add comments to the current token if any\r\n const hasComments = pendingComments.length > 0 || currentComment.lines.length > 0;\r\n if (hasComments) {\r\n this.addCommentsToToken(lexeme, pendingComments, currentComment.lines);\r\n }\r\n pendingComments = []; // Clear as they are processed\r\n }\r\n\r\n lexemes[lexemeCount++] = lexeme;\r\n previous = lexeme;\r\n }\r\n\r\n // Add any pending comments to the last token\r\n if (pendingComments.length > 0 && lexemeCount > 0) {\r\n const lastToken = lexemes[lexemeCount - 1];\r\n if (lastToken.comments === null) {\r\n lastToken.comments = [];\r\n }\r\n lastToken.comments.push(...pendingComments);\r\n }\r\n\r\n // Trim the array to actual size used\r\n return lexemeCount === estimatedTokens ? lexemes : lexemes.slice(0, lexemeCount);\r\n }\r\n\r\n /**\r\n * Adds pending comments to the last token.\r\n */\r\n private addPendingCommentsToLastToken(lexemes: Lexeme[], pendingComments: string[]): void {\r\n if (pendingComments.length > 0 && lexemes.length > 0) {\r\n const lastToken = lexemes[lexemes.length - 1];\r\n if (lastToken.comments === null) {\r\n lastToken.comments = [];\r\n }\r\n lastToken.comments.push(...pendingComments);\r\n }\r\n }\r\n\r\n /**\r\n * Adds comments to the token.\r\n */\r\n private addCommentsToToken(lexeme: Lexeme, prefixComments: string[], suffixComments: string[]): void {\r\n const hasComments = prefixComments.length > 0 || suffixComments.length > 0;\r\n\r\n if (hasComments) {\r\n if (lexeme.comments === null) {\r\n lexeme.comments = [];\r\n }\r\n\r\n // Add prefix comments to the beginning.\r\n if (prefixComments.length > 0) {\r\n lexeme.comments.unshift(...prefixComments);\r\n }\r\n\r\n // Add suffix comments to the end.\r\n if (suffixComments.length > 0) {\r\n lexeme.comments.push(...suffixComments);\r\n }\r\n }\r\n }\r\n\r\n /**\r\n * Skips whitespace characters and SQL comments in the input.\r\n * \r\n * @remarks This method updates the position pointer.\r\n */\r\n private readComment(): { position: number, lines: string[] } {\r\n return StringUtils.readWhiteSpaceAndComment(this.input, this.position);\r\n }\r\n\r\n /**\r\n * Gets debug information for error reporting.\r\n * \r\n * @param errPosition - The position where the error occurred.\r\n * @returns A string containing the debug position information.\r\n */\r\n private getDebugPositionInfo(errPosition: number): string {\r\n return StringUtils.getDebugPositionInfo(this.input, errPosition);\r\n }\r\n}\r\n", "import { Lexeme, TokenType } from \"../models/Lexeme\";\r\nimport { IdentifierString } from \"../models/ValueComponent\";\r\nimport { SqlTokenizer } from \"./SqlTokenizer\";\r\n\r\n/**\r\n * Utility class for parsing fully qualified names (e.g. db.schema.table or db.schema.table.column_name)\r\n * This can be used for both table and column references.\r\n */\r\nexport class FullNameParser {\r\n /**\r\n * Parses a fully qualified name from lexemes, returning namespaces, table, and new index.\r\n */\r\n public static parseFromLexeme(lexemes: Lexeme[], index: number): { namespaces: string[] | null, name: IdentifierString, newIndex: number, lastTokenType: number } {\r\n const { identifiers, newIndex } = FullNameParser.parseEscapedOrDotSeparatedIdentifiers(lexemes, index);\r\n const { namespaces, name } = FullNameParser.extractNamespacesAndName(identifiers);\r\n // Returns the type of the last token in the identifier sequence\r\n let lastTokenType = 0;\r\n if (newIndex > index) {\r\n lastTokenType = lexemes[newIndex - 1].type;\r\n }\r\n return { namespaces, name: new IdentifierString(name), newIndex, lastTokenType };\r\n }\r\n\r\n /**\r\n * Parses a fully qualified name from a string (e.g. 'db.schema.table')\r\n * Returns { namespaces, name }\r\n */\r\n public static parse(str: string): { namespaces: string[] | null, name: IdentifierString } {\r\n const tokenizer = new SqlTokenizer(str);\r\n const lexemes = tokenizer.readLexmes();\r\n const result = this.parseFromLexeme(lexemes, 0);\r\n if (result.newIndex < lexemes.length) {\r\n // Use a context-agnostic error message since FullNameParser is used in multiple query types\r\n throw new Error(`Syntax error: Unexpected token \"${lexemes[result.newIndex].value}\" at position ${result.newIndex}. The name is complete but additional tokens were found.`);\r\n }\r\n return { namespaces: result.namespaces, name: result.name };\r\n }\r\n\r\n // Parses SQL Server-style escaped identifiers ([table]) and dot-separated identifiers, including namespaced wildcards (e.g., db.schema.*, [db].[schema].*)\r\n private static parseEscapedOrDotSeparatedIdentifiers(lexemes: Lexeme[], index: number): { identifiers: string[]; newIndex: number } {\r\n let idx = index;\r\n const identifiers: string[] = [];\r\n while (idx < lexemes.length) {\r\n if (lexemes[idx].type & TokenType.OpenBracket) {\r\n idx++; // skip [\r\n if (idx >= lexemes.length || !((lexemes[idx].type & TokenType.Identifier) || (lexemes[idx].type & TokenType.Command))) {\r\n throw new Error(`Expected identifier after '[' at position ${idx}`);\r\n }\r\n identifiers.push(lexemes[idx].value);\r\n idx++;\r\n if (idx >= lexemes.length || lexemes[idx].value !== \"]\") {\r\n throw new Error(`Expected closing ']' after identifier at position ${idx}`);\r\n }\r\n idx++; // skip ]\r\n } else if (lexemes[idx].type & TokenType.Identifier) {\r\n identifiers.push(lexemes[idx].value);\r\n idx++;\r\n } else if (lexemes[idx].type & TokenType.Function) {\r\n identifiers.push(lexemes[idx].value);\r\n idx++;\r\n } else if (lexemes[idx].type & TokenType.Type) {\r\n identifiers.push(lexemes[idx].value);\r\n idx++;\r\n } else if (lexemes[idx].value === \"*\") {\r\n // The wildcard '*' is always treated as the terminal part of a qualified name in SQL (e.g., db.schema.* or [db].[schema].*).\r\n // No valid SQL syntax allows a wildcard in the middle of a multi-part name.\r\n identifiers.push(lexemes[idx].value);\r\n idx++;\r\n break;\r\n }\r\n // Handle dot for schema.table or db.schema.table\r\n if (idx < lexemes.length && (lexemes[idx].type & TokenType.Dot)) {\r\n idx++; // skip dot\r\n } else {\r\n break;\r\n }\r\n }\r\n return { identifiers, newIndex: idx };\r\n }\r\n\r\n // Utility to extract namespaces and the final name from an array of identifiers\r\n // Example: [\"db\", \"schema\", \"users\"] => { namespaces: [\"db\", \"schema\"], name: \"users\" }\r\n private static extractNamespacesAndName(identifiers: string[]): { namespaces: string[] | null, name: string } {\r\n if (!identifiers || identifiers.length === 0) {\r\n throw new Error(\"Identifier list is empty\");\r\n }\r\n if (identifiers.length === 1) {\r\n return { namespaces: null, name: identifiers[0] };\r\n }\r\n return { namespaces: identifiers.slice(0, -1), name: identifiers[identifiers.length - 1] };\r\n }\r\n}\r\n", "import { FullNameParser } from \"./FullNameParser\";\r\nimport { Lexeme } from \"../models/Lexeme\";\r\nimport { ColumnReference, ValueComponent } from \"../models/ValueComponent\";\r\n\r\nexport class IdentifierParser {\r\n public static parseFromLexeme(lexemes: Lexeme[], index: number): { value: ValueComponent; newIndex: number } {\r\n // Use FullNameParser to robustly parse qualified identifiers, including wildcards and escaped names.\r\n const { namespaces, name, newIndex } = FullNameParser.parseFromLexeme(lexemes, index);\r\n const value = new ColumnReference(namespaces, name);\r\n return { value, newIndex };\r\n }\r\n}", "import { Lexeme } from \"../models/Lexeme\";\r\nimport { LiteralValue, RawString, ValueComponent } from \"../models/ValueComponent\";\r\nimport { literalKeywordParser } from \"../tokenReaders/LiteralTokenReader\";\r\n\r\nexport class LiteralParser {\r\n public static parseFromLexeme(lexemes: Lexeme[], index: number): { value: ValueComponent; newIndex: number } {\r\n // Process literal value\r\n let idx = index;\r\n const valueText = lexemes[idx].value;\r\n let parsedValue: string | number | boolean | null;\r\n\r\n const lex = literalKeywordParser.parse(valueText.toLowerCase(), 0);\r\n if (lex) {\r\n const value = new RawString(lex.keyword);\r\n idx++\r\n return { value, newIndex: idx };\r\n }\r\n\r\n // Check if it is a number\r\n if (/^[+-]?\\d+(\\.\\d+)?([eE][+-]?\\d+)?$/.test(valueText)) {\r\n parsedValue = Number(valueText);\r\n }\r\n // Otherwise, treat it as a string\r\n else {\r\n // Remove single quotes if enclosed\r\n if (valueText.startsWith(\"'\") && valueText.endsWith(\"'\")) {\r\n parsedValue = valueText.slice(1, -1);\r\n } else {\r\n parsedValue = valueText;\r\n }\r\n }\r\n idx++\r\n const value = new LiteralValue(parsedValue);\r\n return { value, newIndex: idx };\r\n }\r\n}", "import { Lexeme, TokenType } from \"../models/Lexeme\";\r\nimport { InlineQuery, ParenExpression, ValueComponent } from \"../models/ValueComponent\";\r\nimport { SelectQueryParser } from \"./SelectQueryParser\";\r\nimport { ValueParser } from \"./ValueParser\";\r\n\r\nexport class ParenExpressionParser {\r\n public static parseFromLexeme(lexemes: Lexeme[], index: number): { value: ValueComponent; newIndex: number } {\r\n let idx = index;\r\n\r\n // check inline query\r\n if (idx + 1 < lexemes.length && lexemes[idx].type & TokenType.OpenParen && (\r\n lexemes[idx + 1].value === \"select\" || lexemes[idx + 1].value === \"values\" || lexemes[idx + 1].value === \"with\"\r\n )) {\r\n idx += 1; // Skip the '(' token\r\n const result = SelectQueryParser.parseFromLexeme(lexemes, idx);\r\n idx = result.newIndex;\r\n\r\n // Check for closing parenthesis\r\n if (idx >= lexemes.length || lexemes[idx].type !== TokenType.CloseParen) {\r\n throw new Error(`Expected ')' at index ${idx}, but found ${lexemes[idx].value}`);\r\n }\r\n idx++; // Skip the ')' token\r\n\r\n const value = new InlineQuery(result.value);\r\n return { value, newIndex: idx };\r\n } else {\r\n const result = ValueParser.parseArgument(TokenType.OpenParen, TokenType.CloseParen, lexemes, index);\r\n idx = result.newIndex;\r\n\r\n const value = new ParenExpression(result.value);\r\n return { value, newIndex: idx };\r\n }\r\n }\r\n}", "import { Lexeme, TokenType } from \"../models/Lexeme\";\r\nimport { ColumnReference, IdentifierString, UnaryExpression, ValueComponent } from \"../models/ValueComponent\";\r\nimport { ValueParser } from \"./ValueParser\";\r\n\r\nexport class UnaryExpressionParser {\r\n public static parseFromLexeme(lexemes: Lexeme[], index: number): { value: ValueComponent; newIndex: number } {\r\n let idx = index;\r\n\r\n // Process unary operator\r\n if (idx < lexemes.length && (lexemes[idx].type & TokenType.Operator)) {\r\n const operator = lexemes[idx].value;\r\n idx++;\r\n\r\n // Treat the asterisk as an Identifier, not as a unary operator\r\n if (operator === '*') {\r\n const v = new ColumnReference(null, '*');\r\n return { value: v, newIndex: idx };\r\n }\r\n\r\n // Get the right-hand side value of the unary operator\r\n const result = ValueParser.parseFromLexeme(lexemes, idx);\r\n idx = result.newIndex;\r\n\r\n // Create unary expression\r\n const value = new UnaryExpression(operator, result.value);\r\n return { value, newIndex: idx };\r\n }\r\n\r\n throw new Error(`Invalid unary expression at index ${index}: ${lexemes[index].value}`);\r\n }\r\n}", "import { Lexeme } from \"../models/Lexeme\";\r\nimport { ParameterExpression, ValueComponent } from \"../models/ValueComponent\";\r\n\r\nexport class ParameterExpressionParser {\r\n public static parseFromLexeme(lexemes: Lexeme[], index: number): { value: ValueComponent; newIndex: number } {\r\n let idx = index;\r\n let paramName = lexemes[idx].value;\r\n\r\n // Normalize parameter: Remove the parameter symbol and extract the parameter name.\r\n if (paramName.startsWith('${') && paramName.endsWith('}')) {\r\n // ${name} \u2192 name\r\n paramName = paramName.slice(2, -1);\r\n } else {\r\n // :name \u2192 name\r\n paramName = paramName.slice(1);\r\n }\r\n\r\n const value = new ParameterExpression(paramName);\r\n idx++;\r\n return { value, newIndex: idx };\r\n }\r\n}", "import { Lexeme, TokenType } from \"../models/Lexeme\";\r\nimport { StringSpecifierExpression, ValueComponent } from \"../models/ValueComponent\";\r\n\r\nexport class StringSpecifierExpressionParser {\r\n public static parseFromLexeme(lexemes: Lexeme[], index: number): { value: ValueComponent; newIndex: number } {\r\n let idx = index;\r\n const specifer = lexemes[idx].value;\r\n idx++;\r\n if (idx >= lexemes.length || lexemes[idx].type !== TokenType.Literal) {\r\n throw new Error(`Expected string literal after string specifier at index ${idx}`);\r\n }\r\n const value = lexemes[idx].value;\r\n idx++;\r\n // Create StringSpecifierExpression\r\n const result = new StringSpecifierExpression(specifer, value);\r\n\r\n return { value: result, newIndex: idx };\r\n }\r\n}", "import { Lexeme, TokenType } from \"../models/Lexeme\";\r\nimport { ArrayExpression, CaseExpression, CaseKeyValuePair, SwitchCaseArgument, UnaryExpression, ValueComponent } from \"../models/ValueComponent\";\r\nimport { ValueParser } from \"./ValueParser\";\r\n\r\nexport class CommandExpressionParser {\r\n public static parseFromLexeme(lexemes: Lexeme[], index: number): { value: ValueComponent; newIndex: number } {\r\n let idx = index;\r\n const current = lexemes[idx];\r\n if (current.value === \"case\") {\r\n idx++;\r\n return this.parseCaseExpression(lexemes, idx);\r\n } else if (current.value === \"case when\") {\r\n idx++;\r\n return this.parseCaseWhenExpression(lexemes, idx);\r\n }\r\n\r\n return this.parseModifierUnaryExpression(lexemes, idx);\r\n }\r\n\r\n private static parseModifierUnaryExpression(lexemes: Lexeme[], index: number): { value: ValueComponent; newIndex: number; } {\r\n let idx = index;\r\n // Check for modifier unary expression\r\n if (idx < lexemes.length && (lexemes[idx].type & TokenType.Command)) {\r\n const command = lexemes[idx].value;\r\n idx++;\r\n const result = ValueParser.parseFromLexeme(lexemes, idx);\r\n return { value: new UnaryExpression(command!, result.value), newIndex: result.newIndex };\r\n }\r\n throw new Error(`Invalid modifier unary expression at index ${idx}, Lexeme: ${lexemes[idx].value}`);\r\n }\r\n\r\n private static parseCaseExpression(lexemes: Lexeme[], index: number): { value: ValueComponent; newIndex: number; } {\r\n let idx = index;\r\n const condition = ValueParser.parseFromLexeme(lexemes, idx);\r\n idx = condition.newIndex;\r\n\r\n const switchCaseResult = this.parseSwitchCaseArgument(lexemes, idx, []);\r\n idx = switchCaseResult.newIndex;\r\n\r\n // Create CASE expression\r\n const result = new CaseExpression(condition.value, switchCaseResult.value);\r\n return { value: result, newIndex: idx };\r\n }\r\n\r\n private static parseCaseWhenExpression(lexemes: Lexeme[], index: number): { value: ValueComponent; newIndex: number; } {\r\n let idx = index;\r\n\r\n // Parse the first WHEN clause\r\n const casewhenResult = this.parseCaseConditionValuePair(lexemes, idx);\r\n idx = casewhenResult.newIndex;\r\n\r\n // Add the initial WHEN-THEN pair to the list\r\n const caseWhenList = [casewhenResult.value];\r\n\r\n // Process remaining WHEN-ELSE-END parts\r\n const switchCaseResult = this.parseSwitchCaseArgument(lexemes, idx, caseWhenList);\r\n idx = switchCaseResult.newIndex;\r\n\r\n // Create CASE expression with condition null (uses WHEN conditions instead of a simple CASE)\r\n const result = new CaseExpression(null, switchCaseResult.value);\r\n return { value: result, newIndex: idx };\r\n }\r\n\r\n // parseSwitchCaseArgument method processes the WHEN, ELSE, and END clauses of a CASE expression.\r\n private static parseSwitchCaseArgument(\r\n lexemes: Lexeme[],\r\n index: number,\r\n initialWhenThenList: CaseKeyValuePair[]\r\n ): { value: SwitchCaseArgument; newIndex: number; } {\r\n let idx = index;\r\n const whenThenList = [...initialWhenThenList];\r\n let elseValue = null;\r\n\r\n // Process WHEN clauses\r\n while (idx < lexemes.length && this.isCommandWithValue(lexemes[idx], \"when\")) {\r\n idx++;\r\n const whenResult = this.parseCaseConditionValuePair(lexemes, idx);\r\n idx = whenResult.newIndex;\r\n whenThenList.push(whenResult.value);\r\n }\r\n\r\n // Process ELSE\r\n if (idx < lexemes.length && this.isCommandWithValue(lexemes[idx], \"else\")) {\r\n idx++;\r\n const elseResult = ValueParser.parseFromLexeme(lexemes, idx);\r\n elseValue = elseResult.value;\r\n idx = elseResult.newIndex;\r\n }\r\n\r\n // Process END\r\n if (idx < lexemes.length && this.isCommandWithValue(lexemes[idx], \"end\")) {\r\n idx++;\r\n } else {\r\n throw new Error(`The CASE expression requires 'end' keyword at the end (index ${idx})`);\r\n }\r\n\r\n if (whenThenList.length === 0) {\r\n throw new Error(`The CASE expression requires at least one WHEN clause (index ${idx})`);\r\n }\r\n\r\n // Create SwitchCaseArgument\r\n const value = new SwitchCaseArgument(whenThenList, elseValue);\r\n return { value, newIndex: idx };\r\n }\r\n\r\n // Helper method: Check if a lexeme is a Command token with the specified value\r\n private static isCommandWithValue(lexeme: Lexeme, value: string): boolean {\r\n return ((lexeme.type & TokenType.Command) !== 0) && lexeme.value === value;\r\n }\r\n\r\n private static parseCaseConditionValuePair(lexemes: Lexeme[], index: number): { value: CaseKeyValuePair; newIndex: number; } {\r\n let idx = index;\r\n const condition = ValueParser.parseFromLexeme(lexemes, idx);\r\n idx = condition.newIndex;\r\n\r\n // Check for the existence of the THEN keyword\r\n if (idx >= lexemes.length || !(lexemes[idx].type & TokenType.Command) || lexemes[idx].value !== \"then\") {\r\n throw new Error(`Expected 'then' after WHEN condition at index ${idx}`);\r\n }\r\n idx++; // Skip the THEN keyword\r\n\r\n // Parse the value after THEN\r\n const value = ValueParser.parseFromLexeme(lexemes, idx);\r\n idx = value.newIndex;\r\n\r\n return { value: new CaseKeyValuePair(condition.value, value.value), newIndex: idx };\r\n }\r\n}", "import { NullsSortDirection, OrderByClause, OrderByComponent, OrderByItem, SortDirection } from \"../models/Clause\";\r\nimport { Lexeme, TokenType } from \"../models/Lexeme\";\r\nimport { SqlTokenizer } from \"./SqlTokenizer\";\r\nimport { ValueParser } from \"./ValueParser\";\r\n\r\nexport class OrderByClauseParser {\r\n // Parse SQL string to AST (was: parse)\r\n public static parse(query: string): OrderByClause {\r\n const tokenizer = new SqlTokenizer(query); // Initialize tokenizer\r\n const lexemes = tokenizer.readLexmes(); // Get tokens\r\n\r\n // Parse\r\n const result = this.parseFromLexeme(lexemes, 0);\r\n\r\n // Error if there are remaining tokens\r\n if (result.newIndex < lexemes.length) {\r\n throw new Error(`Syntax error: Unexpected token \"${lexemes[result.newIndex].value}\" at position ${result.newIndex}. The ORDER BY clause is complete but there are additional tokens.`);\r\n }\r\n\r\n return result.value;\r\n }\r\n\r\n // Parse from lexeme array (was: parse)\r\n public static parseFromLexeme(lexemes: Lexeme[], index: number): { value: OrderByClause; newIndex: number } {\r\n let idx = index;\r\n\r\n if (lexemes[idx].value !== 'order by') {\r\n throw new Error(`Syntax error at position ${idx}: Expected 'ORDER BY' keyword but found \"${lexemes[idx].value}\". ORDER BY clauses must start with the ORDER BY keywords.`);\r\n }\r\n idx++;\r\n\r\n const items: OrderByComponent[] = [];\r\n const item = this.parseItem(lexemes, idx);\r\n items.push(item.value);\r\n idx = item.newIndex;\r\n\r\n while (idx < lexemes.length && (lexemes[idx].type & TokenType.Comma)) {\r\n idx++;\r\n const item = this.parseItem(lexemes, idx);\r\n items.push(item.value);\r\n idx = item.newIndex;\r\n }\r\n\r\n if (items.length === 0) {\r\n throw new Error(`Syntax error at position ${index}: No ordering expressions found. The ORDER BY clause requires at least one expression to order by.`);\r\n } else {\r\n const clause = new OrderByClause(items);\r\n return { value: clause, newIndex: idx };\r\n }\r\n }\r\n\r\n private static parseItem(lexemes: Lexeme[], index: number): { value: OrderByComponent; newIndex: number } {\r\n let idx = index;\r\n const parsedValue = ValueParser.parseFromLexeme(lexemes, idx);\r\n const value = parsedValue.value;\r\n idx = parsedValue.newIndex;\r\n if (idx >= lexemes.length) {\r\n return { value: value, newIndex: idx };\r\n }\r\n\r\n // asc, desc\r\n const sortDirection = idx >= lexemes.length\r\n ? null\r\n : lexemes[idx].value === 'asc'\r\n ? (idx++, SortDirection.Ascending)\r\n : lexemes[idx].value === 'desc'\r\n ? (idx++, SortDirection.Descending)\r\n : null;\r\n\r\n // nulls first, nulls last\r\n const nullsSortDirection = idx >= lexemes.length\r\n ? null\r\n : lexemes[idx].value === 'nulls first'\r\n ? (idx++, NullsSortDirection.First)\r\n : lexemes[idx].value === 'nulls last'\r\n ? (idx++, NullsSortDirection.Last)\r\n : null;\r\n\r\n if (sortDirection === null && nullsSortDirection === null) {\r\n return { value: value, newIndex: idx };\r\n }\r\n\r\n return { value: new OrderByItem(value, sortDirection, nullsSortDirection), newIndex: idx };\r\n }\r\n}\r\n", "import { PartitionByClause } from \"../models/Clause\";\r\nimport { Lexeme, TokenType } from \"../models/Lexeme\";\r\nimport { ValueComponent, ValueList } from \"../models/ValueComponent\";\r\nimport { SqlTokenizer } from \"./SqlTokenizer\";\r\nimport { ValueParser } from \"./ValueParser\";\r\n\r\nexport class PartitionByParser {\r\n // Parse SQL string to AST (was: parse)\r\n public static parse(query: string): PartitionByClause {\r\n const tokenizer = new SqlTokenizer(query); // Initialize tokenizer\r\n const lexemes = tokenizer.readLexmes(); // Get tokens\r\n\r\n // Parse\r\n const result = this.parseFromLexeme(lexemes, 0);\r\n\r\n // Error if there are remaining tokens\r\n if (result.newIndex < lexemes.length) {\r\n throw new Error(`Syntax error: Unexpected token \"${lexemes[result.newIndex].value}\" at position ${result.newIndex}. The PARTITION BY clause is complete but there are additional tokens.`);\r\n }\r\n\r\n return result.value;\r\n }\r\n\r\n // Parse from lexeme array (was: parse)\r\n public static parseFromLexeme(lexemes: Lexeme[], index: number): { value: PartitionByClause; newIndex: number } {\r\n let idx = index;\r\n if (lexemes[idx].value !== 'partition by') {\r\n throw new Error(`Syntax error at position ${idx}: Expected 'PARTITION BY' keyword but found \"${lexemes[idx].value}\". PARTITION BY clauses must start with the PARTITION BY keywords.`);\r\n }\r\n idx++;\r\n const items: ValueComponent[] = [];\r\n const item = ValueParser.parseFromLexeme(lexemes, idx);\r\n items.push(item.value);\r\n idx = item.newIndex;\r\n while (idx < lexemes.length && (lexemes[idx].type & TokenType.Comma)) {\r\n idx++;\r\n const item = ValueParser.parseFromLexeme(lexemes, idx);\r\n items.push(item.value);\r\n idx = item.newIndex;\r\n }\r\n if (items.length === 0) {\r\n throw new Error(`Syntax error at position ${index}: No partition expressions found. The PARTITION BY clause requires at least one expression to partition by.`);\r\n } else if (items.length === 1) {\r\n const clause = new PartitionByClause(items[0]);\r\n return { value: clause, newIndex: idx };\r\n } else {\r\n const clause = new PartitionByClause(new ValueList(items));\r\n return { value: clause, newIndex: idx };\r\n }\r\n }\r\n}\r\n", "import { OrderByClause, PartitionByClause } from \"../models/Clause\";\r\nimport { Lexeme, TokenType } from \"../models/Lexeme\";\r\nimport { WindowFrameBound, WindowFrameBoundaryValue, FrameBoundaryComponent, WindowFrameExpression, WindowFrameSpec, WindowFrameType, WindowFrameBoundStatic } from \"../models/ValueComponent\";\r\nimport { OrderByClauseParser } from \"./OrderByClauseParser\";\r\nimport { PartitionByParser } from \"./PartitionByParser\";\r\nimport { SqlTokenizer } from \"./SqlTokenizer\";\r\nimport { ValueParser } from \"./ValueParser\";\r\n\r\nexport class WindowExpressionParser {\r\n // Parse SQL string to AST (was: parse)\r\n public static parse(query: string): WindowFrameExpression {\r\n const tokenizer = new SqlTokenizer(query); // Initialize tokenizer\r\n const lexemes = tokenizer.readLexmes(); // Get tokens\r\n\r\n // Parse\r\n const result = this.parseFromLexeme(lexemes, 0);\r\n\r\n // Error if there are remaining tokens\r\n if (result.newIndex < lexemes.length) {\r\n throw new Error(`Syntax error: Unexpected token \"${lexemes[result.newIndex].value}\" at position ${result.newIndex}. The window frame expression is complete but there are additional tokens.`);\r\n }\r\n\r\n return result.value;\r\n }\r\n\r\n // Parse from lexeme array (was: parse)\r\n public static parseFromLexeme(lexemes: Lexeme[], index: number): { value: WindowFrameExpression; newIndex: number } {\r\n let idx = index;\r\n if (lexemes[idx].type !== TokenType.OpenParen) {\r\n throw new Error(`Syntax error at position ${idx}: Expected opening parenthesis '(' but found \"${lexemes[idx].value}\".`);\r\n }\r\n idx++;\r\n let partition: PartitionByClause | null = null;\r\n let order: OrderByClause | null = null;\r\n let frameSpec: WindowFrameSpec | null = null;\r\n if (idx < lexemes.length && lexemes[idx].value === 'partition by') {\r\n const partitionResult = PartitionByParser.parseFromLexeme(lexemes, idx);\r\n partition = partitionResult.value;\r\n idx = partitionResult.newIndex;\r\n }\r\n if (idx < lexemes.length && lexemes[idx].value === 'order by') {\r\n const orderResult = OrderByClauseParser.parseFromLexeme(lexemes, idx);\r\n order = orderResult.value;\r\n idx = orderResult.newIndex;\r\n }\r\n // Parse frame clause (ROWS/RANGE/GROUPS)\r\n if (idx < lexemes.length && this.isFrameTypeKeyword(lexemes[idx].value)) {\r\n const frameSpecResult = this.parseFrameSpec(lexemes, idx);\r\n frameSpec = frameSpecResult.value;\r\n idx = frameSpecResult.newIndex;\r\n }\r\n if (idx >= lexemes.length || lexemes[idx].type !== TokenType.CloseParen) {\r\n throw new Error(`Syntax error at position ${idx}: Missing closing parenthesis ')' for window frame. Each opening parenthesis must have a matching closing parenthesis.`);\r\n }\r\n // Read close paren\r\n idx++;\r\n\r\n return { value: new WindowFrameExpression(partition, order, frameSpec), newIndex: idx };\r\n }\r\n\r\n private static isFrameTypeKeyword(value: string): boolean {\r\n const lowerValue = value;\r\n return lowerValue === 'rows' || lowerValue === 'range' || lowerValue === 'groups';\r\n }\r\n\r\n private static parseFrameSpec(lexemes: Lexeme[], index: number): { value: WindowFrameSpec; newIndex: number } {\r\n let idx = index;\r\n\r\n // Determine frame type (ROWS/RANGE/GROUPS)\r\n const frameTypeStr = lexemes[idx].value;\r\n let frameType: WindowFrameType;\r\n\r\n switch (frameTypeStr) {\r\n case 'rows':\r\n frameType = WindowFrameType.Rows;\r\n break;\r\n case 'range':\r\n frameType = WindowFrameType.Range;\r\n break;\r\n case 'groups':\r\n frameType = WindowFrameType.Groups;\r\n break;\r\n default:\r\n throw new Error(`Syntax error at position ${idx}: Invalid frame type \"${lexemes[idx].value}\". Expected one of: ROWS, RANGE, GROUPS.`);\r\n }\r\n idx++;\r\n\r\n // Check for BETWEEN ... AND ... syntax\r\n if (idx < lexemes.length && lexemes[idx].value === 'between') {\r\n // BETWEEN ... AND ... syntax\r\n idx++;\r\n\r\n // Parse start boundary\r\n const startBoundResult = this.parseFrameBoundary(lexemes, idx);\r\n const startBound = startBoundResult.value;\r\n idx = startBoundResult.newIndex;\r\n\r\n // Check for AND keyword - may be recognized as a separate token or part of a compound token\r\n if (idx >= lexemes.length || (lexemes[idx].value !== 'and')) {\r\n throw new Error(`Syntax error at position ${idx}: Expected 'AND' keyword in BETWEEN clause.`);\r\n }\r\n idx++; // Skip AND\r\n\r\n // Parse end boundary\r\n const endBoundResult = this.parseFrameBoundary(lexemes, idx);\r\n const endBound = endBoundResult.value;\r\n idx = endBoundResult.newIndex;\r\n\r\n return {\r\n value: new WindowFrameSpec(frameType, startBound, endBound),\r\n newIndex: idx\r\n };\r\n } else {\r\n // Single boundary specification\r\n const boundaryResult = this.parseFrameBoundary(lexemes, idx);\r\n const startBound = boundaryResult.value;\r\n idx = boundaryResult.newIndex;\r\n\r\n return {\r\n value: new WindowFrameSpec(frameType, startBound, null),\r\n newIndex: idx\r\n };\r\n }\r\n }\r\n\r\n private static parseFrameBoundary(lexemes: Lexeme[], index: number): { value: FrameBoundaryComponent, newIndex: number } {\r\n let idx = index;\r\n // Check for predefined boundaries\r\n if (idx < lexemes.length && (lexemes[idx].type & TokenType.Command)) {\r\n const currentValue = lexemes[idx].value;\r\n let frameBound: WindowFrameBound;\r\n switch (currentValue) {\r\n case 'current row':\r\n frameBound = WindowFrameBound.CurrentRow;\r\n break;\r\n case 'unbounded preceding':\r\n frameBound = WindowFrameBound.UnboundedPreceding;\r\n break;\r\n case 'unbounded following':\r\n frameBound = WindowFrameBound.UnboundedFollowing;\r\n break;\r\n default:\r\n throw new Error(`Syntax error at position ${idx}: Invalid frame type \"${lexemes[idx].value}\". Expected one of: ROWS, RANGE, GROUPS.`);\r\n }\r\n const bound = new WindowFrameBoundStatic(frameBound);\r\n return { value: bound, newIndex: idx + 1 };\r\n } else if (idx < lexemes.length && (lexemes[idx].type & TokenType.Literal)) {\r\n // Parse the numeric/literal value\r\n const valueResult = ValueParser.parseFromLexeme(lexemes, idx);\r\n idx = valueResult.newIndex;\r\n // Next token must be 'preceding' or 'following'\r\n if (idx < lexemes.length && (lexemes[idx].type & TokenType.Command)) {\r\n const direction = lexemes[idx].value;\r\n let isFollowing: boolean;\r\n if (direction === 'preceding') {\r\n isFollowing = false;\r\n } else if (direction === 'following') {\r\n isFollowing = true;\r\n } else {\r\n throw new Error(`Syntax error at position ${idx}: Expected 'preceding' or 'following' after numeric value in window frame boundary.`);\r\n }\r\n idx++;\r\n const bound = new WindowFrameBoundaryValue(valueResult.value, isFollowing);\r\n return { value: bound, newIndex: idx };\r\n } else {\r\n throw new Error(`Syntax error at position ${idx}: Expected 'preceding' or 'following' after numeric value in window frame boundary.`);\r\n }\r\n }\r\n throw new Error(`Syntax error at position ${idx}: Expected a valid frame boundary component.`);\r\n }\r\n}", "import { Lexeme, TokenType } from \"../models/Lexeme\";\r\nimport { IdentifierString, OverExpression } from \"../models/ValueComponent\";\r\nimport { SqlTokenizer } from \"./SqlTokenizer\";\r\nimport { WindowExpressionParser } from \"./WindowExpressionParser\";\r\n\r\nexport class OverExpressionParser {\r\n public static parse(query: string): OverExpression {\r\n const tokenizer = new SqlTokenizer(query); // Initialize tokenizer\r\n const lexemes = tokenizer.readLexmes(); // Get tokens\r\n\r\n // Parse\r\n const result = this.parseFromLexeme(lexemes, 0);\r\n\r\n // Error if there are remaining tokens\r\n if (result.newIndex < lexemes.length) {\r\n throw new Error(`Syntax error: Unexpected token \"${lexemes[result.newIndex].value}\" at position ${result.newIndex}. The OVER expression is complete but there are additional tokens.`);\r\n }\r\n\r\n return result.value;\r\n }\r\n\r\n public static parseFromLexeme(lexemes: Lexeme[], index: number): { value: OverExpression; newIndex: number } {\r\n let idx = index;\r\n\r\n if (lexemes[idx].value !== 'over') {\r\n throw new Error(`Syntax error at position ${idx}: Expected 'OVER' keyword but found \"${lexemes[idx].value}\". OVER expressions must start with the OVER keyword.`);\r\n }\r\n idx++;\r\n\r\n if (idx >= lexemes.length) {\r\n throw new Error(`Syntax error: Unexpected end of input after 'OVER' keyword. Expected either a window name or an opening parenthesis '('.`);\r\n }\r\n\r\n if (lexemes[idx].type & TokenType.Identifier) {\r\n // named window frame\r\n const name = lexemes[idx].value;\r\n idx++;\r\n return { value: new IdentifierString(name), newIndex: idx };\r\n }\r\n\r\n if (lexemes[idx].type & TokenType.OpenParen) {\r\n // Delegate processing to WindowFrameExpressionParser\r\n const result = WindowExpressionParser.parseFromLexeme(lexemes, idx);\r\n return result;\r\n }\r\n\r\n throw new Error(`Syntax error at position ${idx}: Expected a window name or opening parenthesis '(' after OVER keyword, but found \"${lexemes[idx].value}\".`);\r\n }\r\n}\r\n", "import { Lexeme, TokenType } from \"../models/Lexeme\";\r\nimport { FunctionCall, ValueComponent, BinaryExpression, TypeValue, CastExpression, BetweenExpression, RawString, ArrayExpression, ArrayQueryExpression } from \"../models/ValueComponent\";\r\nimport { SelectQuery } from \"../models/SelectQuery\";\r\nimport { OverExpressionParser } from \"./OverExpressionParser\";\r\nimport { ValueParser } from \"./ValueParser\";\r\nimport { FullNameParser } from \"./FullNameParser\";\r\nimport { SelectQueryParser } from \"./SelectQueryParser\";\r\n\r\nexport class FunctionExpressionParser {\r\n /**\r\n * Parse ARRAY expressions - handles both ARRAY[...] (literal) and ARRAY(...) (query) syntax\r\n * @param lexemes Array of lexemes to parse\r\n * @param index Current parsing index\r\n * @returns Parsed array expression and new index\r\n */\r\n private static parseArrayExpression(lexemes: Lexeme[], index: number): { value: ValueComponent; newIndex: number } {\r\n let idx = index;\r\n\r\n // Check if this is array literal (ARRAY[...]) or function call (ARRAY(...))\r\n if (idx + 1 < lexemes.length && (lexemes[idx + 1].type & TokenType.OpenBracket)) {\r\n idx++;\r\n const arg = ValueParser.parseArgument(TokenType.OpenBracket, TokenType.CloseBracket, lexemes, idx);\r\n idx = arg.newIndex;\r\n const value = new ArrayExpression(arg.value);\r\n return { value, newIndex: idx };\r\n } else if (idx + 1 < lexemes.length && (lexemes[idx + 1].type & TokenType.OpenParen)) {\r\n idx++;\r\n idx++; // Skip the opening parenthesis\r\n const arg = SelectQueryParser.parseFromLexeme(lexemes, idx);\r\n idx = arg.newIndex;\r\n idx++; // Skip the closing parenthesis\r\n const value = new ArrayQueryExpression(arg.value);\r\n return { value, newIndex: idx };\r\n }\r\n\r\n throw new Error(`Invalid ARRAY syntax at index ${idx}, expected ARRAY[... or ARRAY(...)`);\r\n }\r\n\r\n public static parseFromLexeme(lexemes: Lexeme[], index: number): { value: ValueComponent; newIndex: number } {\r\n let idx = index;\r\n const current = lexemes[idx];\r\n\r\n if (current.value === \"array\") {\r\n return this.parseArrayExpression(lexemes, idx);\r\n } else if (current.value === \"substring\" || current.value === \"overlay\") {\r\n return this.parseKeywordFunction(lexemes, idx, [\r\n { key: \"from\", required: false },\r\n { key: \"for\", required: false }\r\n ]);\r\n } else if (current.value === \"cast\") {\r\n return this.parseKeywordFunction(lexemes, idx, [\r\n { key: \"as\", required: true }\r\n ]);\r\n } else if (current.value === \"trim\") {\r\n return this.parseKeywordFunction(lexemes, idx, [\r\n { key: \"from\", required: false }\r\n ]);\r\n }\r\n\r\n return this.parseFunctionCall(lexemes, idx);\r\n }\r\n\r\n public static tryParseBinaryExpression(lexemes: Lexeme[], index: number, left: ValueComponent, allowAndOperator: boolean = true, allowOrOperator: boolean = true): { value: ValueComponent; newIndex: number } | null {\r\n let idx = index;\r\n\r\n // If the next element is an operator, process it as a binary expression\r\n if (idx < lexemes.length && (lexemes[idx].type & TokenType.Operator)) {\r\n const operator = lexemes[idx].value.toLowerCase();\r\n\r\n if (!allowAndOperator && operator === \"and\") {\r\n // Handle special case for \"and\" operator\r\n return null;\r\n }\r\n\r\n if (!allowOrOperator && operator === \"or\") {\r\n // Handle special case for \"or\" operator\r\n return null;\r\n }\r\n\r\n idx++;\r\n\r\n // between\r\n if (operator === \"between\") {\r\n return this.parseBetweenExpression(lexemes, idx, left, false);\r\n } else if (operator === \"not between\") {\r\n return this.parseBetweenExpression(lexemes, idx, left, true);\r\n }\r\n\r\n // ::\r\n if (operator === \"::\") {\r\n const typeValue = this.parseTypeValue(lexemes, idx);\r\n idx = typeValue.newIndex;\r\n const exp = new CastExpression(left, typeValue.value);\r\n return { value: exp, newIndex: idx };\r\n }\r\n\r\n // Get the right-hand side value\r\n const rightResult = ValueParser.parseFromLexeme(lexemes, idx);\r\n idx = rightResult.newIndex;\r\n\r\n // Create binary expression\r\n const value = new BinaryExpression(left, operator, rightResult.value);\r\n return { value, newIndex: idx };\r\n }\r\n\r\n return null;\r\n }\r\n\r\n public static parseBetweenExpression(lexemes: Lexeme[], index: number, value: ValueComponent, negated: boolean): { value: ValueComponent; newIndex: number; } {\r\n let idx = index;\r\n const lower = ValueParser.parseFromLexeme(lexemes, idx, false);\r\n idx = lower.newIndex;\r\n\r\n if (idx < lexemes.length && (lexemes[idx].type & TokenType.Operator) && lexemes[idx].value !== \"and\") {\r\n throw new Error(`Expected 'and' after 'between' at index ${idx}`);\r\n }\r\n idx++;\r\n\r\n // Parse upper bound with restricted scope - stop at logical operators\r\n const upper = this.parseBetweenUpperBound(lexemes, idx);\r\n idx = upper.newIndex;\r\n const result = new BetweenExpression(value, lower.value, upper.value, negated);\r\n return { value: result, newIndex: idx };\r\n }\r\n\r\n /**\r\n * Parse the upper bound of a BETWEEN expression with logical operator precedence\r\n * This stops parsing when it encounters AND/OR operators at the same level\r\n */\r\n private static parseBetweenUpperBound(lexemes: Lexeme[], index: number): { value: ValueComponent; newIndex: number } {\r\n // Parse with higher precedence than AND/OR to ensure BETWEEN binds tighter\r\n // Use precedence 3 (higher than AND=2, OR=1) as minimum to stop at logical operators\r\n return ValueParser.parseFromLexeme(lexemes, index, false, false);\r\n }\r\n\r\n private static parseFunctionCall(lexemes: Lexeme[], index: number): { value: ValueComponent; newIndex: number } {\r\n let idx = index;\r\n // Parse namespaced function name (e.g., myschema.myfunc, dbo.util.myfunc)\r\n // Use FullNameParser to get namespaces and function name\r\n const fullNameResult = FullNameParser.parseFromLexeme(lexemes, idx);\r\n const namespaces = fullNameResult.namespaces;\r\n const name = fullNameResult.name;\r\n idx = fullNameResult.newIndex;\r\n\r\n if (idx < lexemes.length && (lexemes[idx].type & TokenType.OpenParen)) {\r\n // General argument parsing\r\n const arg = ValueParser.parseArgument(TokenType.OpenParen, TokenType.CloseParen, lexemes, idx);\r\n idx = arg.newIndex;\r\n\r\n if (idx < lexemes.length && lexemes[idx].value === \"over\") {\r\n const over = OverExpressionParser.parseFromLexeme(lexemes, idx);\r\n idx = over.newIndex;\r\n const value = new FunctionCall(namespaces, name.name, arg.value, over.value);\r\n return { value, newIndex: idx };\r\n } else {\r\n const value = new FunctionCall(namespaces, name.name, arg.value, null);\r\n return { value, newIndex: idx };\r\n }\r\n } else {\r\n throw new Error(`Expected opening parenthesis after function name '${name.name}' at index ${idx}`);\r\n }\r\n }\r\n\r\n private static parseKeywordFunction(\r\n lexemes: Lexeme[],\r\n index: number,\r\n keywords: { key: string, required: boolean }[]\r\n ): { value: ValueComponent; newIndex: number; } {\r\n let idx = index;\r\n // Parse function name and namespaces at the beginning for consistent usage\r\n const fullNameResult = FullNameParser.parseFromLexeme(lexemes, idx);\r\n const namespaces = fullNameResult.namespaces;\r\n const name = fullNameResult.name;\r\n idx = fullNameResult.newIndex;\r\n\r\n if (idx < lexemes.length && (lexemes[idx].type & TokenType.OpenParen)) {\r\n idx++;\r\n\r\n const input = ValueParser.parseFromLexeme(lexemes, idx);\r\n let arg = input.value;\r\n idx = input.newIndex;\r\n\r\n // Delegate to the standard function parser if parsing by comma\r\n if (idx < lexemes.length && (lexemes[idx].type & TokenType.Comma)) {\r\n return this.parseFunctionCall(lexemes, index);\r\n }\r\n\r\n // Check for required/optional keywords in function arguments\r\n for (const { key, required } of keywords) {\r\n if (idx < lexemes.length && (lexemes[idx].type & TokenType.Command) && lexemes[idx].value === key) {\r\n idx++;\r\n\r\n if (idx < lexemes.length && (lexemes[idx].type & TokenType.Type)) {\r\n const typeValue = this.parseTypeValue(lexemes, idx);\r\n arg = new BinaryExpression(arg, key, typeValue.value);\r\n idx = typeValue.newIndex;\r\n } else {\r\n const right = ValueParser.parseFromLexeme(lexemes, idx);\r\n arg = new BinaryExpression(arg, key, right.value);\r\n idx = right.newIndex;\r\n }\r\n\r\n } else if (required) {\r\n throw new Error(`Keyword '${key}' is required at index ${idx}`);\r\n }\r\n }\r\n\r\n if (idx < lexemes.length && (lexemes[idx].type & TokenType.CloseParen)) {\r\n idx++;\r\n // Use the previously parsed namespaces and function name for consistency\r\n if (idx < lexemes.length && lexemes[idx].value === \"over\") {\r\n idx++;\r\n const over = OverExpressionParser.parseFromLexeme(lexemes, idx);\r\n idx = over.newIndex;\r\n const value = new FunctionCall(namespaces, name.name, arg, over.value);\r\n return { value, newIndex: idx };\r\n } else {\r\n const value = new FunctionCall(namespaces, name.name, arg, null);\r\n return { value, newIndex: idx };\r\n }\r\n } else {\r\n throw new Error(`Missing closing parenthesis for function '${name.name}' at index ${idx}`);\r\n }\r\n } else {\r\n throw new Error(`Missing opening parenthesis for function '${name.name}' at index ${idx}`);\r\n }\r\n }\r\n\r\n public static parseTypeValue(lexemes: Lexeme[], index: number): { value: TypeValue; newIndex: number; } {\r\n let idx = index;\r\n\r\n const { namespaces, name, newIndex } = FullNameParser.parseFromLexeme(lexemes, idx);\r\n idx = newIndex;\r\n\r\n if (idx < lexemes.length && (lexemes[idx].type & TokenType.OpenParen)) {\r\n const arg = ValueParser.parseArgument(TokenType.OpenParen, TokenType.CloseParen, lexemes, idx);\r\n idx = arg.newIndex;\r\n const value = new TypeValue(namespaces, new RawString(name.name), arg.value);\r\n return { value, newIndex: idx };\r\n } else {\r\n const value = new TypeValue(namespaces, new RawString(name.name));\r\n return { value, newIndex: idx };\r\n }\r\n }\r\n}", "import { Lexeme, TokenType } from \"../models/Lexeme\";\r\n\r\nexport class ParseError extends Error {\r\n constructor(message: string, public index: number, public context: string) {\r\n super(message);\r\n this.name = \"ParseError\";\r\n }\r\n\r\n public static fromUnparsedLexemes(lexemes: Lexeme[], index: number, messagePrefix: string): ParseError {\r\n const start = Math.max(0, index - 2);\r\n const end = Math.min(lexemes.length, index + 3);\r\n const context = lexemes.slice(start, end).map((lexeme, idx) => {\r\n const marker = idx + start === index ? '>' : ' ';\r\n const typeName = TokenType[lexeme.type] || lexeme.type; // Convert type to name if possible\r\n return `${marker} ${idx + start}:${lexeme.value} [${typeName}]`;\r\n }).join('\\n');\r\n\r\n const message = `${messagePrefix} Unparsed lexeme remains at index ${index}: ${lexemes[index].value}\\nContext:\\n${context}`;\r\n return new ParseError(message, index, context);\r\n }\r\n}\r\n", "/**\r\n * SQL operator precedence definitions\r\n * Higher numbers indicate higher precedence (tighter binding)\r\n */\r\nexport class OperatorPrecedence {\r\n private static readonly precedenceMap: Record<string, number> = {\r\n // Logical operators (lowest precedence)\r\n 'or': 1,\r\n 'and': 2,\r\n\r\n // Comparison operators\r\n '=': 10,\r\n '!=': 10,\r\n '<>': 10,\r\n '<': 10,\r\n '<=': 10,\r\n '>': 10,\r\n '>=': 10,\r\n 'like': 10,\r\n 'ilike': 10,\r\n 'not like': 10,\r\n 'not ilike': 10,\r\n 'similar to': 10,\r\n 'not similar to': 10,\r\n 'in': 10,\r\n 'not in': 10,\r\n 'is': 10,\r\n 'is not': 10,\r\n 'between': 15, // BETWEEN has higher precedence than logical operators\r\n 'not between': 15,\r\n\r\n // Arithmetic operators\r\n '+': 20,\r\n '-': 20,\r\n '*': 30,\r\n '/': 30,\r\n '%': 30,\r\n '^': 40,\r\n\r\n // Type casting\r\n '::': 50,\r\n\r\n // Highest precedence operators\r\n 'unary+': 100,\r\n 'unary-': 100,\r\n 'not': 100\r\n };\r\n\r\n /**\r\n * Get the precedence of an operator\r\n * @param operator The operator string\r\n * @returns The precedence number (higher = tighter binding)\r\n */\r\n public static getPrecedence(operator: string): number {\r\n const precedence = this.precedenceMap[operator.toLowerCase()];\r\n return precedence !== undefined ? precedence : 0;\r\n }\r\n\r\n /**\r\n * Check if operator1 has higher or equal precedence than operator2\r\n */\r\n public static hasHigherOrEqualPrecedence(operator1: string, operator2: string): boolean {\r\n return this.getPrecedence(operator1) >= this.getPrecedence(operator2);\r\n }\r\n\r\n /**\r\n * Check if an operator is a logical operator (AND/OR)\r\n */\r\n public static isLogicalOperator(operator: string): boolean {\r\n const op = operator.toLowerCase();\r\n return op === 'and' || op === 'or';\r\n }\r\n\r\n /**\r\n * Check if an operator is a BETWEEN operator\r\n */\r\n public static isBetweenOperator(operator: string): boolean {\r\n const op = operator.toLowerCase();\r\n return op === 'between' || op === 'not between';\r\n }\r\n\r\n /**\r\n * Check if a string is a comparison operator\r\n */\r\n public static isComparisonOperator(operator: string): boolean {\r\n const lowerOp = operator.toLowerCase();\r\n return ['=', '!=', '<>', '<', '>', '<=', '>=', 'like', 'ilike', 'similar to', 'in', 'not in'].includes(lowerOp);\r\n }\r\n}\r\n", "import { Lexeme, TokenType } from \"../models/Lexeme\";\r\nimport { ColumnReference, TypeValue, UnaryExpression, ValueComponent, ValueList, BinaryExpression, CastExpression } from \"../models/ValueComponent\";\r\nimport { SqlTokenizer } from \"./SqlTokenizer\";\r\nimport { IdentifierParser } from \"./IdentifierParser\";\r\nimport { LiteralParser } from \"./LiteralParser\";\r\nimport { ParenExpressionParser } from \"./ParenExpressionParser\";\r\nimport { UnaryExpressionParser } from \"./UnaryExpressionParser\";\r\nimport { ParameterExpressionParser } from \"./ParameterExpressionParser\";\r\nimport { StringSpecifierExpressionParser } from \"./StringSpecifierExpressionParser\";\r\nimport { CommandExpressionParser } from \"./CommandExpressionParser\";\r\nimport { FunctionExpressionParser } from \"./FunctionExpressionParser\";\r\nimport { FullNameParser } from \"./FullNameParser\";\r\nimport { ParseError } from \"./ParseError\";\r\nimport { OperatorPrecedence } from \"../utils/OperatorPrecedence\";\r\n\r\nexport class ValueParser {\r\n // Parse SQL string to AST (was: parse)\r\n public static parse(query: string): ValueComponent {\r\n const tokenizer = new SqlTokenizer(query); // Initialize tokenizer\r\n const lexemes = tokenizer.readLexmes(); // Get tokens\r\n\r\n // Parse\r\n const result = this.parseFromLexeme(lexemes, 0);\r\n\r\n // Error if there are remaining tokens\r\n if (result.newIndex < lexemes.length) {\r\n throw ParseError.fromUnparsedLexemes(\r\n lexemes,\r\n result.newIndex,\r\n `[ValueParser]`\r\n );\r\n }\r\n\r\n return result.value;\r\n }\r\n\r\n /**\r\n * Parse from lexeme array with logical operator controls\r\n */\r\n public static parseFromLexeme(lexemes: Lexeme[], index: number, allowAndOperator: boolean = true, allowOrOperator: boolean = true): { value: ValueComponent; newIndex: number } {\r\n return this.parseExpressionWithPrecedence(lexemes, index, 0, allowAndOperator, allowOrOperator);\r\n }\r\n\r\n /**\r\n * Parse expressions with operator precedence handling\r\n * Uses precedence climbing algorithm\r\n */\r\n private static parseExpressionWithPrecedence(\r\n lexemes: Lexeme[],\r\n index: number,\r\n minPrecedence: number,\r\n allowAndOperator: boolean = true,\r\n allowOrOperator: boolean = true\r\n ): { value: ValueComponent; newIndex: number } {\r\n let idx = index;\r\n\r\n // Parse the primary expression (left side)\r\n const comment = lexemes[idx].comments;\r\n const left = this.parseItem(lexemes, idx);\r\n left.value.comments = comment;\r\n idx = left.newIndex;\r\n\r\n let result = left.value;\r\n\r\n // Process operators with precedence\r\n while (idx < lexemes.length && (lexemes[idx].type & TokenType.Operator)) {\r\n const operatorToken = lexemes[idx];\r\n const operator = operatorToken.value;\r\n\r\n // Check if this operator is allowed\r\n if (!allowAndOperator && operator.toLowerCase() === \"and\") {\r\n break;\r\n }\r\n if (!allowOrOperator && operator.toLowerCase() === \"or\") {\r\n break;\r\n }\r\n\r\n // Get operator precedence\r\n const precedence = OperatorPrecedence.getPrecedence(operator);\r\n\r\n // If this operator has lower precedence than minimum, stop\r\n if (precedence < minPrecedence) {\r\n break;\r\n }\r\n\r\n idx++; // consume operator // Handle BETWEEN specially as it has different syntax\r\n if (OperatorPrecedence.isBetweenOperator(operator)) {\r\n const betweenResult = FunctionExpressionParser.parseBetweenExpression(\r\n lexemes, idx, result, operator.toLowerCase().includes('not')\r\n );\r\n result = betweenResult.value;\r\n idx = betweenResult.newIndex;\r\n continue;\r\n }\r\n\r\n // Handle :: (cast) operator specially\r\n if (operator === \"::\") {\r\n const typeValue = FunctionExpressionParser.parseTypeValue(lexemes, idx);\r\n result = new CastExpression(result, typeValue.value);\r\n idx = typeValue.newIndex;\r\n continue;\r\n }\r\n\r\n // For left-associative operators, use precedence + 1\r\n const nextMinPrecedence = precedence + 1;\r\n\r\n // Parse the right-hand side with higher precedence\r\n const rightResult = this.parseExpressionWithPrecedence(\r\n lexemes, idx, nextMinPrecedence, allowAndOperator, allowOrOperator\r\n );\r\n idx = rightResult.newIndex;\r\n\r\n // Create binary expression directly\r\n result = new BinaryExpression(result, operator, rightResult.value);\r\n }\r\n\r\n return { value: result, newIndex: idx };\r\n }\r\n\r\n private static parseItem(lexemes: Lexeme[], index: number): { value: ValueComponent; newIndex: number } {\r\n let idx = index;\r\n\r\n // Range check\r\n if (idx >= lexemes.length) {\r\n throw new Error(`Unexpected end of lexemes at index ${index}`);\r\n }\r\n\r\n const current = lexemes[idx];\r\n\r\n if (current.type & TokenType.Identifier && current.type & TokenType.Operator && current.type & TokenType.Type) {\r\n // Typed literal format pattern\r\n // e.g., `interval '2 days'`\r\n const first = IdentifierParser.parseFromLexeme(lexemes, idx);\r\n if (first.newIndex >= lexemes.length) {\r\n return first;\r\n }\r\n const next = lexemes[first.newIndex];\r\n if (next.type & TokenType.Literal) {\r\n // Typed literal format\r\n const second = LiteralParser.parseFromLexeme(lexemes, first.newIndex);\r\n const result = new UnaryExpression(lexemes[idx].value, second.value);\r\n return { value: result, newIndex: second.newIndex };\r\n }\r\n return first;\r\n } else if (current.type & TokenType.Identifier) {\r\n const { namespaces, name, newIndex } = FullNameParser.parseFromLexeme(lexemes, idx);\r\n // Namespace is also recognized as Identifier.\r\n // Since functions and types, as well as columns (tables), can have namespaces,\r\n // it is necessary to determine by the last element of the identifier.\r\n if (lexemes[newIndex - 1].type & (TokenType.Function | TokenType.Type)) {\r\n return FunctionExpressionParser.parseFromLexeme(lexemes, idx);\r\n }\r\n const value = new ColumnReference(namespaces, name);\r\n return { value, newIndex };\r\n } else if (current.type & TokenType.Literal) {\r\n return LiteralParser.parseFromLexeme(lexemes, idx);\r\n } else if (current.type & TokenType.OpenParen) {\r\n return ParenExpressionParser.parseFromLexeme(lexemes, idx);\r\n } else if (current.type & TokenType.Function) {\r\n return FunctionExpressionParser.parseFromLexeme(lexemes, idx);\r\n } else if (current.type & TokenType.Operator) {\r\n return UnaryExpressionParser.parseFromLexeme(lexemes, idx);\r\n } else if (current.type & TokenType.Parameter) {\r\n return ParameterExpressionParser.parseFromLexeme(lexemes, idx);\r\n } else if (current.type & TokenType.StringSpecifier) {\r\n return StringSpecifierExpressionParser.parseFromLexeme(lexemes, idx);\r\n } else if (current.type & TokenType.Command) {\r\n return CommandExpressionParser.parseFromLexeme(lexemes, idx);\r\n } else if (current.type & TokenType.OpenBracket) {\r\n // SQLServer escape identifier format. e.g. [dbo] or [dbo].[table]\r\n const { namespaces, name, newIndex } = FullNameParser.parseFromLexeme(lexemes, idx);\r\n const value = new ColumnReference(namespaces, name);\r\n return { value, newIndex };\r\n } else if (current.type & TokenType.Type) {\r\n // Handle standalone type tokens\r\n const { namespaces, name, newIndex } = FullNameParser.parseFromLexeme(lexemes, idx);\r\n const value = new TypeValue(namespaces, name);\r\n return { value, newIndex };\r\n }\r\n\r\n throw new Error(`[ValueParser] Invalid lexeme. index: ${idx}, type: ${lexemes[idx].type}, value: ${lexemes[idx].value}`);\r\n }\r\n\r\n public static parseArgument(openToken: TokenType, closeToken: TokenType, lexemes: Lexeme[], index: number): { value: ValueComponent; newIndex: number } {\r\n let idx = index;\r\n const args: ValueComponent[] = [];\r\n\r\n // Check for opening parenthesis\r\n if (idx < lexemes.length && lexemes[idx].type === openToken) {\r\n idx++;\r\n\r\n if (idx < lexemes.length && lexemes[idx].type === closeToken) {\r\n // If there are no arguments, return an empty ValueList\r\n idx++;\r\n return { value: new ValueList([]), newIndex: idx };\r\n }\r\n\r\n // If the next element is `*`, treat `*` as an Identifier\r\n if (idx < lexemes.length && lexemes[idx].value === \"*\") {\r\n const wildcard = new ColumnReference(null, \"*\");\r\n idx++;\r\n // The next element must be closeToken\r\n if (idx < lexemes.length && lexemes[idx].type === closeToken) {\r\n idx++;\r\n return { value: wildcard, newIndex: idx };\r\n } else {\r\n throw new Error(`Expected closing parenthesis at index ${idx}`);\r\n }\r\n }\r\n\r\n // Parse the value inside\r\n const result = this.parseFromLexeme(lexemes, idx);\r\n idx = result.newIndex;\r\n args.push(result.value);\r\n\r\n // Continue reading if the next element is a comma\r\n while (idx < lexemes.length && (lexemes[idx].type & TokenType.Comma)) {\r\n idx++;\r\n const argResult = this.parseFromLexeme(lexemes, idx);\r\n idx = argResult.newIndex;\r\n args.push(argResult.value);\r\n }\r\n\r\n // Check for closing parenthesis\r\n if (idx < lexemes.length && lexemes[idx].type === closeToken) {\r\n idx++;\r\n if (args.length === 1) {\r\n // Return as is if there is only one argument\r\n return { value: args[0], newIndex: idx };\r\n }\r\n // Create ValueCollection if there are multiple arguments\r\n const value = new ValueList(args);\r\n return { value, newIndex: idx };\r\n } else {\r\n throw new Error(`Missing closing parenthesis at index ${idx}`);\r\n }\r\n }\r\n\r\n throw new Error(`Expected opening parenthesis at index ${index}`);\r\n }\r\n}\r\n", "import { CommonTable, ForClause, FromClause, FunctionSource, GroupByClause, HavingClause, JoinClause, JoinOnClause, JoinUsingClause, LimitClause, OrderByClause, OrderByItem, ParenSource, PartitionByClause, SelectClause, SelectItem, SourceExpression, SubQuerySource, TableSource, WhereClause, WindowFrameClause, WindowsClause, WithClause } from \"../models/Clause\";\r\nimport { BinarySelectQuery, SimpleSelectQuery, SelectQuery, ValuesQuery } from \"../models/SelectQuery\";\r\nimport { SqlComponent, SqlComponentVisitor } from \"../models/SqlComponent\";\r\nimport {\r\n ArrayExpression, ArrayQueryExpression, BetweenExpression, BinaryExpression, CaseExpression, CaseKeyValuePair,\r\n CastExpression, ColumnReference, FunctionCall, InlineQuery, ParenExpression,\r\n ParameterExpression, SwitchCaseArgument, TupleExpression, UnaryExpression, ValueComponent,\r\n OverExpression, WindowFrameExpression, IdentifierString, RawString,\r\n WindowFrameSpec,\r\n LiteralValue,\r\n TypeValue,\r\n ValueList,\r\n StringSpecifierExpression\r\n} from \"../models/ValueComponent\";\r\n\r\n/**\r\n * A visitor that collects all CommonTable instances from a SQL query structure.\r\n * This includes tables from:\r\n * - WITH clauses\r\n * - Subqueries\r\n * - Inline queries\r\n * - UNION queries\r\n * - Value components that may contain queries\r\n */\r\nexport class CTECollector implements SqlComponentVisitor<void> {\r\n private handlers: Map<symbol, (arg: any) => void>;\r\n private commonTables: CommonTable[] = [];\r\n private visitedNodes: Set<SqlComponent> = new Set();\r\n private isRootVisit: boolean = true;\r\n\r\n constructor() {\r\n this.handlers = new Map<symbol, (arg: any) => void>();\r\n\r\n // Setup handlers for all component types that might contain CommonTables\r\n\r\n // SelectQuery types\r\n this.handlers.set(SimpleSelectQuery.kind, (expr) => this.visitSimpleSelectQuery(expr as SimpleSelectQuery));\r\n this.handlers.set(BinarySelectQuery.kind, (expr) => this.visitBinarySelectQuery(expr as BinarySelectQuery));\r\n this.handlers.set(ValuesQuery.kind, (expr) => this.visitValuesQuery(expr as ValuesQuery));\r\n\r\n // WITH clause that directly contains CommonTables\r\n this.handlers.set(WithClause.kind, (expr) => this.visitWithClause(expr as WithClause));\r\n this.handlers.set(CommonTable.kind, (expr) => this.visitCommonTable(expr as CommonTable));\r\n\r\n // SelectComponent types\r\n this.handlers.set(SelectItem.kind, (expr) => this.visitSelectItem(expr as SelectItem));\r\n\r\n // Identifiers and raw strings (leaf nodes that don't need traversal)\r\n this.handlers.set(IdentifierString.kind, (expr) => this.visitIdentifierString(expr as IdentifierString));\r\n this.handlers.set(RawString.kind, (expr) => this.visitRawString(expr as RawString));\r\n this.handlers.set(ColumnReference.kind, (expr) => this.visitColumnReference(expr as ColumnReference));\r\n this.handlers.set(ParameterExpression.kind, (expr) => this.visitParameterExpression(expr as ParameterExpression));\r\n this.handlers.set(LiteralValue.kind, (expr) => this.visitLiteralValue(expr as LiteralValue));\r\n\r\n // Source components\r\n this.handlers.set(SourceExpression.kind, (expr) => this.visitSourceExpression(expr as SourceExpression));\r\n this.handlers.set(TableSource.kind, (expr) => this.visitTableSource(expr as TableSource));\r\n this.handlers.set(FunctionSource.kind, (expr) => this.visitFunctionSource(expr as FunctionSource));\r\n this.handlers.set(ParenSource.kind, (expr) => this.visitParenSource(expr as ParenSource));\r\n\r\n // Subqueries and inline queries\r\n this.handlers.set(SubQuerySource.kind, (expr) => this.visitSubQuerySource(expr as SubQuerySource));\r\n this.handlers.set(InlineQuery.kind, (expr) => this.visitInlineQuery(expr as InlineQuery));\r\n\r\n // FROM and JOIN clauses\r\n this.handlers.set(FromClause.kind, (expr) => this.visitFromClause(expr as FromClause));\r\n this.handlers.set(JoinClause.kind, (expr) => this.visitJoinClause(expr as JoinClause));\r\n this.handlers.set(JoinOnClause.kind, (expr) => this.visitJoinOnClause(expr as JoinOnClause));\r\n this.handlers.set(JoinUsingClause.kind, (expr) => this.visitJoinUsingClause(expr as JoinUsingClause));\r\n\r\n // WHERE clause\r\n this.handlers.set(WhereClause.kind, (expr) => this.visitWhereClause(expr as WhereClause));\r\n\r\n // Value components that might contain subqueries\r\n this.handlers.set(ParenExpression.kind, (expr) => this.visitParenExpression(expr as ParenExpression));\r\n this.handlers.set(BinaryExpression.kind, (expr) => this.visitBinaryExpression(expr as BinaryExpression));\r\n this.handlers.set(UnaryExpression.kind, (expr) => this.visitUnaryExpression(expr as UnaryExpression));\r\n this.handlers.set(CaseExpression.kind, (expr) => this.visitCaseExpression(expr as CaseExpression));\r\n this.handlers.set(CaseKeyValuePair.kind, (expr) => this.visitCaseKeyValuePair(expr as CaseKeyValuePair));\r\n this.handlers.set(SwitchCaseArgument.kind, (expr) => this.visitSwitchCaseArgument(expr as SwitchCaseArgument));\r\n this.handlers.set(BetweenExpression.kind, (expr) => this.visitBetweenExpression(expr as BetweenExpression));\r\n this.handlers.set(FunctionCall.kind, (expr) => this.visitFunctionCall(expr as FunctionCall));\r\n this.handlers.set(ArrayExpression.kind, (expr) => this.visitArrayExpression(expr as ArrayExpression));\r\n this.handlers.set(ArrayQueryExpression.kind, (expr) => this.visitArrayQueryExpression(expr as ArrayQueryExpression));\r\n this.handlers.set(TupleExpression.kind, (expr) => this.visitTupleExpression(expr as TupleExpression));\r\n this.handlers.set(CastExpression.kind, (expr) => this.visitCastExpression(expr as CastExpression));\r\n this.handlers.set(WindowFrameExpression.kind, (expr) => this.visitWindowFrameExpression(expr as WindowFrameExpression));\r\n this.handlers.set(WindowFrameSpec.kind, (expr) => this.visitWindowFrameSpec(expr as WindowFrameSpec));\r\n this.handlers.set(TypeValue.kind, (expr) => this.visitTypeValue(expr as TypeValue));\r\n this.handlers.set(ValueList.kind, (expr) => this.visitValueList(expr as ValueList));\r\n this.handlers.set(StringSpecifierExpression.kind, (expr) => this.visitStringSpecifierExpression(expr as StringSpecifierExpression));\r\n\r\n // Add handlers for other clause types\r\n this.handlers.set(SelectClause.kind, (expr) => this.visitSelectClause(expr as SelectClause));\r\n this.handlers.set(GroupByClause.kind, (expr) => this.visitGroupByClause(expr as GroupByClause));\r\n this.handlers.set(HavingClause.kind, (expr) => this.visitHavingClause(expr as HavingClause));\r\n this.handlers.set(OrderByClause.kind, (expr) => this.visitOrderByClause(expr as OrderByClause));\r\n this.handlers.set(WindowFrameClause.kind, (expr) => this.visitWindowFrameClause(expr as WindowFrameClause));\r\n this.handlers.set(LimitClause.kind, (expr) => this.visitLimitClause(expr as LimitClause));\r\n this.handlers.set(ForClause.kind, (expr) => this.visitForClause(expr as ForClause));\r\n this.handlers.set(OrderByItem.kind, (expr) => this.visitOrderByItem(expr as OrderByItem));\r\n this.handlers.set(PartitionByClause.kind, (expr) => this.visitPartitionByClause(expr as PartitionByClause));\r\n }\r\n\r\n /**\r\n * Get all collected CommonTables\r\n */\r\n public getCommonTables(): CommonTable[] {\r\n return this.commonTables;\r\n }\r\n\r\n /**\r\n * Reset the collection of CommonTables\r\n */\r\n private reset(): void {\r\n this.commonTables = [];\r\n this.visitedNodes.clear();\r\n }\r\n\r\n public collect(query: SelectQuery): CommonTable[] {\r\n // Visit the query to collect all CommonTables\r\n this.visit(query);\r\n return this.getCommonTables();\r\n }\r\n\r\n /**\r\n * Main entry point for the visitor pattern.\r\n * Implements the shallow visit pattern to distinguish between root and recursive visits.\r\n */\r\n public visit(arg: SqlComponent): void {\r\n // If not a root visit, just visit the node and return\r\n if (!this.isRootVisit) {\r\n this.visitNode(arg);\r\n return;\r\n }\r\n\r\n // If this is a root visit, we need to reset the state\r\n this.reset();\r\n this.isRootVisit = false;\r\n\r\n try {\r\n this.visitNode(arg);\r\n } finally {\r\n // Regardless of success or failure, reset the root visit flag\r\n this.isRootVisit = true;\r\n }\r\n }\r\n\r\n /**\r\n * Internal visit method used for all nodes.\r\n * This separates the visit flag management from the actual node visitation logic.\r\n */\r\n private visitNode(arg: SqlComponent): void {\r\n // Skip if we've already visited this node to prevent infinite recursion\r\n if (this.visitedNodes.has(arg)) {\r\n return;\r\n }\r\n\r\n // Mark as visited\r\n this.visitedNodes.add(arg);\r\n\r\n const handler = this.handlers.get(arg.getKind());\r\n if (handler) {\r\n handler(arg);\r\n return;\r\n }\r\n\r\n // Provide more detailed error message\r\n const kindSymbol = arg.getKind()?.toString() || 'unknown';\r\n const constructor = arg.constructor?.name || 'unknown';\r\n throw new Error(`[CTECollector] No handler for ${constructor} with kind ${kindSymbol}.`);\r\n }\r\n\r\n private visitSimpleSelectQuery(query: SimpleSelectQuery): void {\r\n // The order matters here!\r\n // First, visit all clauses that might contain nested CTEs\r\n // to ensure inner CTEs are collected before outer CTEs\r\n\r\n // Check FROM clause first (can contain subqueries with nested CTEs)\r\n if (query.fromClause) {\r\n query.fromClause.accept(this);\r\n }\r\n\r\n // Check WHERE clause (can contain subqueries with WITH clauses)\r\n if (query.whereClause) {\r\n query.whereClause.accept(this);\r\n }\r\n\r\n // Check other clauses that might contain CTEs\r\n if (query.groupByClause) {\r\n query.groupByClause.accept(this);\r\n }\r\n\r\n if (query.havingClause) {\r\n query.havingClause.accept(this);\r\n }\r\n\r\n if (query.orderByClause) {\r\n query.orderByClause.accept(this);\r\n }\r\n\r\n if (query.windowClause) {\r\n for (const win of query.windowClause.windows) {\r\n win.accept(this);\r\n }\r\n }\r\n\r\n if (query.limitClause) {\r\n query.limitClause.accept(this);\r\n }\r\n\r\n if (query.forClause) {\r\n query.forClause.accept(this);\r\n }\r\n\r\n // Check SELECT clause\r\n query.selectClause.accept(this);\r\n\r\n // Finally check the WITH clause after all nested CTEs have been collected\r\n // This ensures inner CTEs are collected before outer CTEs\r\n if (query.withClause) {\r\n query.withClause.accept(this);\r\n }\r\n\r\n }\r\n\r\n private visitBinarySelectQuery(query: BinarySelectQuery): void {\r\n // Visit both sides of the binary query (UNION, EXCEPT, etc.)\r\n query.left.accept(this);\r\n query.right.accept(this);\r\n }\r\n\r\n private visitValuesQuery(query: ValuesQuery): void {\r\n // VALUES queries might contain subqueries in tuple expressions\r\n for (const tuple of query.tuples) {\r\n tuple.accept(this);\r\n }\r\n }\r\n\r\n private visitWithClause(withClause: WithClause): void {\r\n // Visit each CommonTable\r\n // Simply process tables in sequence\r\n // Note: visitCommonTable already handles nested CTEs\r\n for (let i = 0; i < withClause.tables.length; i++) {\r\n const commonTable = withClause.tables[i];\r\n commonTable.accept(this);\r\n }\r\n }\r\n\r\n private visitCommonTable(commonTable: CommonTable): void {\r\n // Process CommonTable directly within the query\r\n // Use the same instance to process the query instead of creating another Collector\r\n commonTable.query.accept(this);\r\n\r\n // Add current CTE after all nested CTEs have been added\r\n this.commonTables.push(commonTable);\r\n }\r\n\r\n private visitSelectClause(clause: SelectClause): void {\r\n // Check each item in the select clause\r\n for (const item of clause.items) {\r\n item.accept(this);\r\n }\r\n }\r\n\r\n private visitSelectItem(item: SelectItem): void {\r\n // Select items might contain subqueries\r\n item.value.accept(this);\r\n }\r\n\r\n private visitFromClause(fromClause: FromClause): void {\r\n // Check the source\r\n fromClause.source.accept(this);\r\n\r\n // Check joins\r\n if (fromClause.joins) {\r\n for (const join of fromClause.joins) {\r\n join.accept(this);\r\n }\r\n }\r\n }\r\n\r\n private visitSourceExpression(source: SourceExpression): void {\r\n source.datasource.accept(this);\r\n // The alias part doesn't contain subqueries so we skip it\r\n }\r\n\r\n private visitTableSource(source: TableSource): void {\r\n // Table sources don't contain subqueries, nothing to do\r\n }\r\n\r\n private visitFunctionSource(source: FunctionSource): void {\r\n // Function sources may have arguments that could contain subqueries\r\n if (source.argument) {\r\n source.argument.accept(this);\r\n }\r\n }\r\n\r\n private visitParenSource(source: ParenSource): void {\r\n source.source.accept(this);\r\n }\r\n\r\n private visitSubQuerySource(subQuery: SubQuerySource): void {\r\n subQuery.query.accept(this);\r\n }\r\n\r\n private visitInlineQuery(inlineQuery: InlineQuery): void {\r\n inlineQuery.selectQuery.accept(this);\r\n }\r\n\r\n private visitJoinClause(joinClause: JoinClause): void {\r\n // Check join source\r\n joinClause.source.accept(this);\r\n\r\n // Check join condition\r\n if (joinClause.condition) {\r\n joinClause.condition.accept(this);\r\n }\r\n }\r\n\r\n private visitJoinOnClause(joinOn: JoinOnClause): void {\r\n joinOn.condition.accept(this);\r\n }\r\n\r\n private visitJoinUsingClause(joinUsing: JoinUsingClause): void {\r\n joinUsing.condition.accept(this);\r\n }\r\n\r\n private visitWhereClause(whereClause: WhereClause): void {\r\n whereClause.condition.accept(this);\r\n }\r\n\r\n private visitGroupByClause(clause: GroupByClause): void {\r\n for (const item of clause.grouping) {\r\n item.accept(this);\r\n }\r\n }\r\n\r\n private visitHavingClause(clause: HavingClause): void {\r\n clause.condition.accept(this);\r\n }\r\n\r\n private visitOrderByClause(clause: OrderByClause): void {\r\n for (const item of clause.order) {\r\n item.accept(this);\r\n }\r\n }\r\n\r\n private visitWindowFrameClause(clause: WindowFrameClause): void {\r\n clause.expression.accept(this);\r\n }\r\n\r\n private visitLimitClause(clause: LimitClause): void {\r\n clause.value.accept(this);\r\n }\r\n\r\n private visitForClause(clause: ForClause): void {\r\n // FOR clause doesn't contain subqueries\r\n }\r\n\r\n private visitOrderByItem(item: OrderByItem): void {\r\n item.value.accept(this);\r\n }\r\n\r\n private visitParenExpression(expr: ParenExpression): void {\r\n expr.expression.accept(this);\r\n }\r\n\r\n private visitBinaryExpression(expr: BinaryExpression): void {\r\n expr.left.accept(this);\r\n expr.right.accept(this);\r\n }\r\n\r\n private visitUnaryExpression(expr: UnaryExpression): void {\r\n expr.expression.accept(this);\r\n }\r\n\r\n private visitCaseExpression(expr: CaseExpression): void {\r\n if (expr.condition) {\r\n expr.condition.accept(this);\r\n }\r\n expr.switchCase.accept(this);\r\n }\r\n\r\n private visitSwitchCaseArgument(switchCase: SwitchCaseArgument): void {\r\n // Check all case expressions\r\n for (const caseItem of switchCase.cases) {\r\n caseItem.accept(this);\r\n }\r\n\r\n // Check ELSE expression\r\n if (switchCase.elseValue) {\r\n switchCase.elseValue.accept(this);\r\n }\r\n }\r\n\r\n private visitCaseKeyValuePair(pair: CaseKeyValuePair): void {\r\n // Check the WHEN condition\r\n pair.key.accept(this);\r\n // Check the THEN value\r\n pair.value.accept(this);\r\n }\r\n\r\n private visitBetweenExpression(expr: BetweenExpression): void {\r\n expr.expression.accept(this);\r\n expr.lower.accept(this);\r\n expr.upper.accept(this);\r\n }\r\n\r\n private visitFunctionCall(func: FunctionCall): void {\r\n if (func.argument) {\r\n func.argument.accept(this);\r\n }\r\n\r\n // Check OVER clause if present\r\n if (func.over) {\r\n func.over.accept(this);\r\n }\r\n }\r\n\r\n private visitArrayExpression(expr: ArrayExpression): void {\r\n expr.expression.accept(this);\r\n }\r\n\r\n private visitArrayQueryExpression(expr: ArrayQueryExpression): void {\r\n expr.query.accept(this);\r\n }\r\n\r\n private visitTupleExpression(expr: TupleExpression): void {\r\n // Check each value in the tuple for possible subqueries\r\n for (const value of expr.values) {\r\n value.accept(this);\r\n }\r\n }\r\n\r\n private visitCastExpression(expr: CastExpression): void {\r\n // Check the input expression\r\n expr.input.accept(this);\r\n // Check the type expression\r\n expr.castType.accept(this);\r\n }\r\n\r\n private visitTypeValue(expr: TypeValue): void {\r\n // Visit the argument if present\r\n if (expr.argument) {\r\n expr.argument.accept(this);\r\n }\r\n // The type itself doesn't contain subqueries\r\n }\r\n\r\n private visitWindowFrameExpression(expr: WindowFrameExpression): void {\r\n if (expr.partition) {\r\n expr.partition.accept(this);\r\n }\r\n if (expr.order) {\r\n expr.order.accept(this);\r\n }\r\n if (expr.frameSpec) {\r\n expr.frameSpec.accept(this);\r\n }\r\n }\r\n\r\n private visitWindowFrameSpec(spec: WindowFrameSpec): void {\r\n // WindowFrameSpec is a simple value object, nothing to traverse\r\n }\r\n\r\n private visitIdentifierString(ident: IdentifierString): void {\r\n // Leaf node, nothing to traverse\r\n }\r\n\r\n private visitRawString(raw: RawString): void {\r\n // Leaf node, nothing to traverse\r\n }\r\n\r\n private visitColumnReference(column: ColumnReference): void {\r\n // Column references don't have subqueries\r\n }\r\n\r\n private visitParameterExpression(param: ParameterExpression): void {\r\n // Parameter expressions don't have child components\r\n }\r\n\r\n private visitLiteralValue(value: LiteralValue): void {\r\n // Literal values are leaf nodes\r\n }\r\n\r\n public visitPartitionByClause(partitionBy: PartitionByClause): void {\r\n // don't have subqueries\r\n }\r\n\r\n public visitValueList(valueList: ValueList): void {\r\n for (const value of valueList.values) {\r\n value.accept(this);\r\n }\r\n }\r\n\r\n private visitStringSpecifierExpression(expr: StringSpecifierExpression): void {\r\n // StringSpecifierExpression contains RawString and LiteralValue which are leaf nodes\r\n // No need to visit children as they don't contain subqueries\r\n }\r\n}", "import { CommonTable, ForClause, FromClause, GroupByClause, HavingClause, JoinClause, JoinConditionComponent, JoinOnClause, JoinUsingClause, LimitClause, OrderByClause, OrderByComponent, OrderByItem, ParenSource, PartitionByClause, SelectClause, SelectItem, SourceAliasExpression, SourceComponent, SourceExpression, SubQuerySource, TableSource, WhereClause, WindowFrameClause, WindowsClause, WithClause } from \"../models/Clause\";\r\nimport { BinarySelectQuery, SimpleSelectQuery, SelectQuery, ValuesQuery } from \"../models/SelectQuery\";\r\nimport { SqlComponent, SqlComponentVisitor } from \"../models/SqlComponent\";\r\nimport {\r\n ArrayExpression, ArrayQueryExpression, BetweenExpression, BinaryExpression, CaseExpression, CaseKeyValuePair,\r\n CastExpression, ColumnReference, FunctionCall, InlineQuery, ParenExpression,\r\n ParameterExpression, SwitchCaseArgument, TupleExpression, UnaryExpression, ValueComponent,\r\n OverExpression, WindowFrameExpression, IdentifierString, RawString,\r\n WindowFrameSpec,\r\n LiteralValue,\r\n TypeValue\r\n} from \"../models/ValueComponent\";\r\n\r\n/**\r\n * A visitor that disables all WITH clauses in a SQL query structure.\r\n * This processes and removes WITH clauses from:\r\n * - Simple SELECT queries\r\n * - Binary queries (UNION, EXCEPT, etc.)\r\n * - Subqueries\r\n * - Inline queries\r\n * \r\n * It maintains the CTE queries themselves but restructures the query to not use\r\n * the WITH clause syntactical construct.\r\n */\r\nexport class CTEDisabler implements SqlComponentVisitor<SqlComponent> {\r\n private handlers: Map<symbol, (arg: any) => SqlComponent>;\r\n private visitedNodes: Set<SqlComponent> = new Set();\r\n private isRootVisit: boolean = true;\r\n\r\n constructor() {\r\n this.handlers = new Map<symbol, (arg: any) => SqlComponent>();\r\n\r\n // Setup handlers for all component types that might contain WITH clauses\r\n\r\n // SelectQuery types\r\n this.handlers.set(SimpleSelectQuery.kind, (expr) => this.visitSimpleSelectQuery(expr as SimpleSelectQuery));\r\n this.handlers.set(BinarySelectQuery.kind, (expr) => this.visitBinarySelectQuery(expr as BinarySelectQuery));\r\n this.handlers.set(ValuesQuery.kind, (expr) => this.visitValuesQuery(expr as ValuesQuery));\r\n\r\n // SelectComponent types\r\n this.handlers.set(SelectItem.kind, (expr) => this.visitSelectItem(expr as SelectItem));\r\n\r\n // Identifiers and raw strings\r\n this.handlers.set(IdentifierString.kind, (expr) => this.visitIdentifierString(expr as IdentifierString));\r\n this.handlers.set(RawString.kind, (expr) => this.visitRawString(expr as RawString));\r\n this.handlers.set(ColumnReference.kind, (expr) => this.visitColumnReference(expr as ColumnReference));\r\n this.handlers.set(ParameterExpression.kind, (expr) => this.visitParameterExpression(expr as ParameterExpression));\r\n this.handlers.set(LiteralValue.kind, (expr) => this.visitLiteralValue(expr as LiteralValue));\r\n\r\n // Source components\r\n this.handlers.set(SourceExpression.kind, (expr) => this.visitSourceExpression(expr as SourceExpression));\r\n this.handlers.set(TableSource.kind, (expr) => this.visitTableSource(expr as TableSource));\r\n this.handlers.set(ParenSource.kind, (expr) => this.visitParenSource(expr as ParenSource));\r\n\r\n // Subqueries and inline queries\r\n this.handlers.set(SubQuerySource.kind, (expr) => this.visitSubQuerySource(expr as SubQuerySource));\r\n this.handlers.set(InlineQuery.kind, (expr) => this.visitInlineQuery(expr as InlineQuery));\r\n\r\n // FROM and JOIN clauses\r\n this.handlers.set(FromClause.kind, (expr) => this.visitFromClause(expr as FromClause));\r\n this.handlers.set(JoinClause.kind, (expr) => this.visitJoinClause(expr as JoinClause));\r\n this.handlers.set(JoinOnClause.kind, (expr) => this.visitJoinOnClause(expr as JoinOnClause));\r\n this.handlers.set(JoinUsingClause.kind, (expr) => this.visitJoinUsingClause(expr as JoinUsingClause));\r\n\r\n // WHERE clause\r\n this.handlers.set(WhereClause.kind, (expr) => this.visitWhereClause(expr as WhereClause));\r\n\r\n // Value components that might contain subqueries\r\n this.handlers.set(ParenExpression.kind, (expr) => this.visitParenExpression(expr as ParenExpression));\r\n this.handlers.set(BinaryExpression.kind, (expr) => this.visitBinaryExpression(expr as BinaryExpression));\r\n this.handlers.set(UnaryExpression.kind, (expr) => this.visitUnaryExpression(expr as UnaryExpression));\r\n this.handlers.set(CaseExpression.kind, (expr) => this.visitCaseExpression(expr as CaseExpression));\r\n this.handlers.set(CaseKeyValuePair.kind, (expr) => this.visitCaseKeyValuePair(expr as CaseKeyValuePair));\r\n this.handlers.set(SwitchCaseArgument.kind, (expr) => this.visitSwitchCaseArgument(expr as SwitchCaseArgument));\r\n this.handlers.set(BetweenExpression.kind, (expr) => this.visitBetweenExpression(expr as BetweenExpression));\r\n this.handlers.set(FunctionCall.kind, (expr) => this.visitFunctionCall(expr as FunctionCall));\r\n this.handlers.set(ArrayExpression.kind, (expr) => this.visitArrayExpression(expr as ArrayExpression));\r\n this.handlers.set(ArrayQueryExpression.kind, (expr) => this.visitArrayQueryExpression(expr as ArrayQueryExpression));\r\n this.handlers.set(TupleExpression.kind, (expr) => this.visitTupleExpression(expr as TupleExpression));\r\n this.handlers.set(CastExpression.kind, (expr) => this.visitCastExpression(expr as CastExpression));\r\n this.handlers.set(WindowFrameExpression.kind, (expr) => this.visitWindowFrameExpression(expr as WindowFrameExpression));\r\n this.handlers.set(WindowFrameSpec.kind, (expr) => this.visitWindowFrameSpec(expr as WindowFrameSpec));\r\n this.handlers.set(TypeValue.kind, (expr) => this.visitTypeValue(expr as TypeValue));\r\n\r\n // Add handlers for other clause types\r\n this.handlers.set(SelectClause.kind, (expr) => this.visitSelectClause(expr as SelectClause));\r\n this.handlers.set(GroupByClause.kind, (expr) => this.visitGroupByClause(expr as GroupByClause));\r\n this.handlers.set(HavingClause.kind, (expr) => this.visitHavingClause(expr as HavingClause));\r\n this.handlers.set(OrderByClause.kind, (expr) => this.visitOrderByClause(expr as OrderByClause));\r\n this.handlers.set(WindowFrameClause.kind, (expr) => this.visitWindowFrameClause(expr as WindowFrameClause));\r\n this.handlers.set(LimitClause.kind, (expr) => this.visitLimitClause(expr as LimitClause));\r\n this.handlers.set(ForClause.kind, (expr) => this.visitForClause(expr as ForClause));\r\n this.handlers.set(OrderByItem.kind, (expr) => this.visitOrderByItem(expr as OrderByItem));\r\n }\r\n\r\n /**\r\n * Reset the visited nodes tracking\r\n */\r\n private reset(): void {\r\n this.visitedNodes.clear();\r\n }\r\n\r\n public execute(arg: SqlComponent): SelectQuery {\r\n // Reset the visited nodes before starting the visit\r\n this.reset();\r\n return this.visit(arg) as SelectQuery;\r\n }\r\n\r\n /**\r\n * Main entry point for the visitor pattern.\r\n * Implements the shallow visit pattern to distinguish between root and recursive visits.\r\n */\r\n public visit(arg: SqlComponent): SqlComponent {\r\n // If not a root visit, just visit the node and return\r\n if (!this.isRootVisit) {\r\n return this.visitNode(arg);\r\n }\r\n\r\n // If this is a root visit, we need to reset the state\r\n this.reset();\r\n this.isRootVisit = false;\r\n\r\n try {\r\n return this.visitNode(arg);\r\n } finally {\r\n // Regardless of success or failure, reset the root visit flag\r\n this.isRootVisit = true;\r\n }\r\n }\r\n\r\n /**\r\n * Internal visit method used for all nodes.\r\n * This separates the visit flag management from the actual node visitation logic.\r\n */\r\n private visitNode(arg: SqlComponent): SqlComponent {\r\n // Check for circular references - if node already visited, return as is\r\n if (this.visitedNodes.has(arg)) {\r\n return arg;\r\n }\r\n\r\n // Mark as visited node\r\n this.visitedNodes.add(arg);\r\n\r\n const handler = this.handlers.get(arg.getKind());\r\n if (handler) {\r\n return handler(arg);\r\n }\r\n\r\n // Provide more detailed error message\r\n const kindSymbol = arg.getKind()?.toString() || 'unknown';\r\n const constructor = arg.constructor?.name || 'unknown';\r\n throw new Error(`[CTEDisabler] No handler for ${constructor} with kind ${kindSymbol}.`);\r\n }\r\n\r\n visitSimpleSelectQuery(arg: SimpleSelectQuery): SqlComponent {\r\n if (arg.withClause) {\r\n arg.withClause.tables.forEach(table => {\r\n this.visit(table.query);\r\n });\r\n }\r\n\r\n arg.withClause = null; // Explicitly remove WITH clause\r\n\r\n // Visit the components of the SimpleSelectQuery\r\n arg.selectClause = this.visit(arg.selectClause) as SelectClause;\r\n arg.fromClause = arg.fromClause ? this.visit(arg.fromClause) as FromClause : null;\r\n arg.whereClause = arg.whereClause ? this.visit(arg.whereClause) as WhereClause : null;\r\n arg.groupByClause = arg.groupByClause ? this.visit(arg.groupByClause) as GroupByClause : null;\r\n arg.havingClause = arg.havingClause ? this.visit(arg.havingClause) as HavingClause : null;\r\n arg.orderByClause = arg.orderByClause ? this.visit(arg.orderByClause) as OrderByClause : null;\r\n if (arg.windowClause) {\r\n arg.windowClause = new WindowsClause(arg.windowClause.windows.map(w => this.visit(w) as WindowFrameClause));\r\n }\r\n arg.limitClause = arg.limitClause ? this.visit(arg.limitClause) as LimitClause : null;\r\n arg.forClause = arg.forClause ? this.visit(arg.forClause) as ForClause : null;\r\n return arg;\r\n }\r\n\r\n visitBinarySelectQuery(query: BinarySelectQuery): SqlComponent {\r\n query.left = this.visit(query.left) as SelectQuery;\r\n query.right = this.visit(query.right) as SelectQuery;\r\n return query;\r\n }\r\n\r\n visitValuesQuery(query: ValuesQuery): SqlComponent {\r\n const newTuples = query.tuples.map(tuple => this.visit(tuple) as TupleExpression);\r\n return new ValuesQuery(newTuples);\r\n }\r\n\r\n visitSelectClause(clause: SelectClause): SqlComponent {\r\n const newItems = clause.items.map(item => {\r\n return this.visit(item) as SelectItem;\r\n });\r\n\r\n return new SelectClause(\r\n newItems,\r\n clause.distinct,\r\n );\r\n }\r\n\r\n visitFromClause(clause: FromClause): SqlComponent {\r\n const newSource = this.visit(clause.source) as SourceExpression;\r\n const newJoins = clause.joins ? clause.joins.map(join => this.visit(join) as JoinClause) : null;\r\n\r\n return new FromClause(newSource, newJoins);\r\n }\r\n\r\n visitSubQuerySource(subQuery: SubQuerySource): SqlComponent {\r\n const newQuery = this.visit(subQuery.query) as SelectQuery;\r\n return new SubQuerySource(newQuery);\r\n }\r\n\r\n visitInlineQuery(inlineQuery: InlineQuery): SqlComponent {\r\n const newQuery = this.visit(inlineQuery.selectQuery) as SelectQuery;\r\n return new InlineQuery(newQuery);\r\n }\r\n\r\n visitJoinClause(joinClause: JoinClause): SqlComponent {\r\n const newSource = this.visit(joinClause.source) as SourceExpression;\r\n const newCondition = joinClause.condition ? this.visit(joinClause.condition) as JoinConditionComponent : null;\r\n\r\n return new JoinClause(\r\n joinClause.joinType.value,\r\n newSource,\r\n newCondition,\r\n joinClause.lateral,\r\n );\r\n }\r\n\r\n visitJoinOnClause(joinOn: JoinOnClause): SqlComponent {\r\n const newCondition = this.visit(joinOn.condition) as ValueComponent;\r\n return new JoinOnClause(newCondition);\r\n }\r\n\r\n visitJoinUsingClause(joinUsing: JoinUsingClause): SqlComponent {\r\n const newCondition = this.visit(joinUsing.condition) as ValueComponent;\r\n return new JoinUsingClause(newCondition);\r\n }\r\n\r\n visitWhereClause(whereClause: WhereClause): SqlComponent {\r\n const newCondition = this.visit(whereClause.condition) as ValueComponent;\r\n return new WhereClause(newCondition);\r\n }\r\n\r\n visitGroupByClause(clause: GroupByClause): SqlComponent {\r\n const newGrouping = clause.grouping.map(item => this.visit(item) as ValueComponent);\r\n return new GroupByClause(newGrouping);\r\n }\r\n\r\n visitHavingClause(clause: HavingClause): SqlComponent {\r\n const newCondition = this.visit(clause.condition) as ValueComponent;\r\n return new HavingClause(newCondition);\r\n }\r\n\r\n visitOrderByClause(clause: OrderByClause): SqlComponent {\r\n const newOrder = clause.order.map(item => this.visit(item) as OrderByComponent);\r\n return new OrderByClause(newOrder);\r\n }\r\n\r\n visitWindowFrameClause(clause: WindowFrameClause): SqlComponent {\r\n const newExpression = this.visit(clause.expression) as WindowFrameExpression;\r\n return new WindowFrameClause(clause.name.name, newExpression);\r\n }\r\n\r\n visitLimitClause(clause: LimitClause): SqlComponent {\r\n const newLimit = this.visit(clause.value) as ValueComponent;\r\n return new LimitClause(newLimit);\r\n }\r\n\r\n visitForClause(clause: ForClause): SqlComponent {\r\n return new ForClause(clause.lockMode);\r\n }\r\n\r\n visitParenExpression(expr: ParenExpression): SqlComponent {\r\n const newExpression = this.visit(expr.expression) as ValueComponent;\r\n return new ParenExpression(newExpression);\r\n }\r\n\r\n visitBinaryExpression(expr: BinaryExpression): SqlComponent {\r\n const newLeft = this.visit(expr.left) as ValueComponent;\r\n const newRight = this.visit(expr.right) as ValueComponent;\r\n return new BinaryExpression(newLeft, expr.operator.value, newRight);\r\n }\r\n\r\n visitUnaryExpression(expr: UnaryExpression): SqlComponent {\r\n const newExpression = this.visit(expr.expression) as ValueComponent;\r\n return new UnaryExpression(expr.operator.value, newExpression);\r\n }\r\n\r\n visitCaseExpression(expr: CaseExpression): SqlComponent {\r\n const newCondition = expr.condition ? this.visit(expr.condition) as ValueComponent : null;\r\n const newSwitchCase = this.visit(expr.switchCase) as SwitchCaseArgument;\r\n return new CaseExpression(newCondition, newSwitchCase);\r\n }\r\n\r\n visitSwitchCaseArgument(switchCase: SwitchCaseArgument): SqlComponent {\r\n const newCases = switchCase.cases.map(caseItem => this.visit(caseItem) as CaseKeyValuePair);\r\n const newElseValue = switchCase.elseValue ? this.visit(switchCase.elseValue) as ValueComponent : null;\r\n return new SwitchCaseArgument(newCases, newElseValue);\r\n }\r\n\r\n visitCaseKeyValuePair(pair: CaseKeyValuePair): SqlComponent {\r\n const newKey = this.visit(pair.key) as ValueComponent;\r\n const newValue = this.visit(pair.value) as ValueComponent;\r\n return new CaseKeyValuePair(newKey, newValue);\r\n }\r\n\r\n visitBetweenExpression(expr: BetweenExpression): SqlComponent {\r\n const newExpression = this.visit(expr.expression) as ValueComponent;\r\n const newLower = this.visit(expr.lower) as ValueComponent;\r\n const newUpper = this.visit(expr.upper) as ValueComponent;\r\n return new BetweenExpression(newExpression, newLower, newUpper, expr.negated);\r\n }\r\n\r\n visitFunctionCall(func: FunctionCall): SqlComponent {\r\n const newArgument = func.argument ? this.visit(func.argument) as ValueComponent : null;\r\n const newOver = func.over ? this.visit(func.over) as OverExpression : null;\r\n return new FunctionCall(func.namespaces, func.name, newArgument, newOver);\r\n }\r\n\r\n visitArrayExpression(expr: ArrayExpression): SqlComponent {\r\n const newExpression = this.visit(expr.expression) as ValueComponent;\r\n return new ArrayExpression(newExpression);\r\n }\r\n\r\n visitArrayQueryExpression(expr: ArrayQueryExpression): SqlComponent {\r\n const newQuery = this.visit(expr.query) as SelectQuery;\r\n return new ArrayQueryExpression(newQuery);\r\n }\r\n\r\n visitTupleExpression(expr: TupleExpression): SqlComponent {\r\n const newValues = expr.values.map(value => this.visit(value) as ValueComponent);\r\n return new TupleExpression(newValues);\r\n }\r\n\r\n visitCastExpression(expr: CastExpression): SqlComponent {\r\n const newInput = this.visit(expr.input) as ValueComponent;\r\n const newCastType = this.visit(expr.castType) as TypeValue;\r\n return new CastExpression(newInput, newCastType);\r\n }\r\n\r\n visitTypeValue(typeValue: TypeValue): SqlComponent {\r\n const newArgument = typeValue.argument ? this.visit(typeValue.argument) as ValueComponent : null;\r\n return new TypeValue(typeValue.namespaces, typeValue.name, newArgument);\r\n }\r\n\r\n visitSelectItem(item: SelectItem): SqlComponent {\r\n const newValue = this.visit(item.value) as ValueComponent;\r\n return new SelectItem(newValue, item.identifier?.name);\r\n }\r\n\r\n visitIdentifierString(ident: IdentifierString): SqlComponent {\r\n // Identifiers don't have child components, so just return as-is\r\n return ident;\r\n }\r\n\r\n visitRawString(raw: RawString): SqlComponent {\r\n // Raw strings don't have child components, so just return as-is\r\n return raw;\r\n }\r\n\r\n visitColumnReference(column: ColumnReference): SqlComponent {\r\n // Column references don't have subqueries, so just return as-is\r\n return column;\r\n }\r\n\r\n visitSourceExpression(source: SourceExpression): SqlComponent {\r\n const newSource = this.visit(source.datasource) as SourceComponent;\r\n // SourceAliasEpression don't contain subqueries, so just return as-is\r\n const newAlias = source.aliasExpression;\r\n return new SourceExpression(newSource, newAlias);\r\n }\r\n\r\n visitTableSource(source: TableSource): SqlComponent {\r\n // Table sources don't contain subqueries, so just return as-is\r\n return source;\r\n }\r\n\r\n visitParenSource(source: ParenSource): SqlComponent {\r\n const newSource = this.visit(source.source) as SourceComponent;\r\n return new ParenSource(newSource);\r\n }\r\n\r\n visitParameterExpression(param: ParameterExpression): SqlComponent {\r\n // Parameter expressions don't have child components, so just return as-is\r\n return param;\r\n }\r\n\r\n visitWindowFrameExpression(expr: WindowFrameExpression): SqlComponent {\r\n const newPartition = expr.partition ? this.visit(expr.partition) as PartitionByClause : null;\r\n const newOrder = expr.order ? this.visit(expr.order) as OrderByClause : null;\r\n const newFrameSpec = expr.frameSpec ? this.visit(expr.frameSpec) as WindowFrameSpec : null;\r\n\r\n return new WindowFrameExpression(\r\n newPartition,\r\n newOrder,\r\n newFrameSpec\r\n );\r\n }\r\n\r\n visitWindowFrameSpec(spec: WindowFrameSpec): SqlComponent {\r\n // WindowFrameSpec is a simple value object, so return as-is\r\n return spec;\r\n }\r\n\r\n visitLiteralValue(value: ValueComponent): SqlComponent {\r\n // Literal values are returned as-is\r\n return value;\r\n }\r\n\r\n visitOrderByItem(item: OrderByItem): SqlComponent {\r\n const newValue = this.visit(item.value) as ValueComponent;\r\n return new OrderByItem(newValue, item.sortDirection, item.nullsPosition);\r\n }\r\n}", "import { CommonTable, FetchClause, ForClause, FromClause, FunctionSource, GroupByClause, HavingClause, JoinClause, JoinOnClause, JoinUsingClause, LimitClause, OffsetClause, OrderByClause, OrderByItem, ParenSource, PartitionByClause, SelectClause, SelectItem, SourceExpression, SubQuerySource, TableSource, WhereClause, WindowFrameClause, WindowsClause, WithClause } from \"../models/Clause\";\r\nimport { BinarySelectQuery, SelectQuery, SimpleSelectQuery, ValuesQuery } from \"../models/SelectQuery\";\r\nimport { SqlComponent, SqlComponentVisitor } from \"../models/SqlComponent\";\r\nimport {\r\n ArrayExpression, ArrayQueryExpression, BetweenExpression, BinaryExpression, CaseExpression, CaseKeyValuePair,\r\n CastExpression, ColumnReference, FunctionCall, InlineQuery, ParenExpression,\r\n ParameterExpression, SwitchCaseArgument, TupleExpression, UnaryExpression, ValueComponent, ValueList,\r\n OverExpression, WindowFrameExpression, IdentifierString, RawString,\r\n WindowFrameSpec,\r\n LiteralValue,\r\n TypeValue,\r\n StringSpecifierExpression\r\n} from \"../models/ValueComponent\";\r\nimport { CTECollector } from \"./CTECollector\";\r\n\r\n/**\r\n * A visitor that collects all table source names from a SQL query structure.\r\n * \r\n * When selectableOnly is true (default behavior):\r\n * - Includes only table sources from FROM and JOIN clauses\r\n * - Excludes inline queries, subqueries, and CTEs\r\n * \r\n * When selectableOnly is false:\r\n * - Scans all parts of the query including WITH clauses, subqueries, etc.\r\n * - Collects all table sources from the entire query\r\n * - Excludes tables that are managed by CTEs\r\n * \r\n * For UNION-like queries, it scans both the left and right parts.\r\n */\r\nexport class TableSourceCollector implements SqlComponentVisitor<void> {\r\n private handlers: Map<symbol, (arg: any) => void>;\r\n private tableSources: TableSource[] = [];\r\n private visitedNodes: Set<SqlComponent> = new Set();\r\n private tableNameMap: Map<string, boolean> = new Map<string, boolean>();\r\n private selectableOnly: boolean;\r\n private cteNames: Set<string> = new Set<string>();\r\n private isRootVisit: boolean = true;\r\n\r\n constructor(selectableOnly: boolean = true) {\r\n this.selectableOnly = selectableOnly;\r\n this.handlers = new Map<symbol, (arg: any) => void>();\r\n\r\n // Setup handlers for query components\r\n this.handlers.set(SimpleSelectQuery.kind, (expr) => this.visitSimpleSelectQuery(expr as SimpleSelectQuery));\r\n this.handlers.set(BinarySelectQuery.kind, (expr) => this.visitBinarySelectQuery(expr as BinarySelectQuery));\r\n this.handlers.set(ValuesQuery.kind, (expr) => this.visitValuesQuery(expr as ValuesQuery));\r\n\r\n // WITH clause and common tables\r\n this.handlers.set(WithClause.kind, (expr) => this.visitWithClause(expr as WithClause));\r\n this.handlers.set(CommonTable.kind, (expr) => this.visitCommonTable(expr as CommonTable));\r\n\r\n // Handlers for FROM and JOIN components\r\n this.handlers.set(FromClause.kind, (expr) => this.visitFromClause(expr as FromClause));\r\n this.handlers.set(JoinClause.kind, (expr) => this.visitJoinClause(expr as JoinClause));\r\n this.handlers.set(JoinOnClause.kind, (expr) => this.visitJoinOnClause(expr as JoinOnClause));\r\n this.handlers.set(JoinUsingClause.kind, (expr) => this.visitJoinUsingClause(expr as JoinUsingClause));\r\n\r\n // Source components\r\n this.handlers.set(SourceExpression.kind, (expr) => this.visitSourceExpression(expr as SourceExpression));\r\n this.handlers.set(TableSource.kind, (expr) => this.visitTableSource(expr as TableSource));\r\n this.handlers.set(FunctionSource.kind, (expr) => this.visitFunctionSource(expr as FunctionSource));\r\n this.handlers.set(ParenSource.kind, (expr) => this.visitParenSource(expr as ParenSource));\r\n this.handlers.set(SubQuerySource.kind, (expr) => this.visitSubQuerySource(expr as SubQuerySource));\r\n this.handlers.set(InlineQuery.kind, (expr) => this.visitInlineQuery(expr as InlineQuery));\r\n\r\n // Only register these handlers when not in selectableOnly mode\r\n if (!selectableOnly) {\r\n // Additional clause handlers for full scanning\r\n this.handlers.set(WhereClause.kind, (expr) => this.visitWhereClause(expr as WhereClause));\r\n this.handlers.set(GroupByClause.kind, (expr) => this.visitGroupByClause(expr as GroupByClause));\r\n this.handlers.set(HavingClause.kind, (expr) => this.visitHavingClause(expr as HavingClause));\r\n this.handlers.set(OrderByClause.kind, (expr) => this.visitOrderByClause(expr as OrderByClause));\r\n this.handlers.set(WindowFrameClause.kind, (expr) => this.visitWindowFrameClause(expr as WindowFrameClause));\r\n this.handlers.set(LimitClause.kind, (expr) => this.visitLimitClause(expr as LimitClause));\r\n this.handlers.set(OffsetClause.kind, (expr) => this.visitOffsetClause(expr as OffsetClause));\r\n this.handlers.set(FetchClause.kind, (expr) => this.visitFetchClause(expr as FetchClause));\r\n this.handlers.set(ForClause.kind, (expr) => this.visitForClause(expr as ForClause));\r\n this.handlers.set(OrderByItem.kind, (expr) => this.visitOrderByItem(expr as OrderByItem));\r\n this.handlers.set(SelectClause.kind, (expr) => this.visitSelectClause(expr as SelectClause));\r\n this.handlers.set(SelectItem.kind, (expr) => this.visitSelectItem(expr as SelectItem));\r\n\r\n // Value components that might contain table references\r\n this.handlers.set(ParenExpression.kind, (expr) => this.visitParenExpression(expr as ParenExpression));\r\n this.handlers.set(BinaryExpression.kind, (expr) => this.visitBinaryExpression(expr as BinaryExpression));\r\n this.handlers.set(UnaryExpression.kind, (expr) => this.visitUnaryExpression(expr as UnaryExpression));\r\n this.handlers.set(CaseExpression.kind, (expr) => this.visitCaseExpression(expr as CaseExpression));\r\n this.handlers.set(CaseKeyValuePair.kind, (expr) => this.visitCaseKeyValuePair(expr as CaseKeyValuePair));\r\n this.handlers.set(SwitchCaseArgument.kind, (expr) => this.visitSwitchCaseArgument(expr as SwitchCaseArgument));\r\n this.handlers.set(BetweenExpression.kind, (expr) => this.visitBetweenExpression(expr as BetweenExpression));\r\n this.handlers.set(FunctionCall.kind, (expr) => this.visitFunctionCall(expr as FunctionCall));\r\n this.handlers.set(ArrayExpression.kind, (expr) => this.visitArrayExpression(expr as ArrayExpression));\r\n this.handlers.set(ArrayQueryExpression.kind, (expr) => this.visitArrayQueryExpression(expr as ArrayQueryExpression));\r\n this.handlers.set(TupleExpression.kind, (expr) => this.visitTupleExpression(expr as TupleExpression));\r\n this.handlers.set(CastExpression.kind, (expr) => this.visitCastExpression(expr as CastExpression));\r\n this.handlers.set(ValueList.kind, (expr) => this.visitValueList(expr as ValueList));\r\n this.handlers.set(StringSpecifierExpression.kind, (expr) => this.visitStringSpecifierExpression(expr as StringSpecifierExpression));\r\n }\r\n }\r\n\r\n /**\r\n * Gets all collected table sources\r\n */\r\n public getTableSources(): TableSource[] {\r\n return this.tableSources;\r\n }\r\n\r\n /**\r\n * Reset the collection of table sources\r\n */\r\n private reset(): void {\r\n this.tableSources = [];\r\n this.tableNameMap.clear();\r\n this.visitedNodes.clear();\r\n this.cteNames.clear();\r\n }\r\n\r\n /**\r\n * Gets a unique identifier for a table source\r\n */\r\n private getTableIdentifier(source: TableSource): string {\r\n // Use QualifiedName for identifier (dot-joined string)\r\n if (source.qualifiedName.namespaces && source.qualifiedName.namespaces.length > 0) {\r\n return source.qualifiedName.namespaces.map(ns => ns.name).join('.') + '.' + (source.qualifiedName.name instanceof RawString ? source.qualifiedName.name.value : source.qualifiedName.name.name);\r\n } else {\r\n return source.qualifiedName.name instanceof RawString ? source.qualifiedName.name.value : source.qualifiedName.name.name;\r\n }\r\n }\r\n\r\n public collect(query: SqlComponent): TableSource[] {\r\n // Visit the SQL component to collect table sources\r\n this.visit(query);\r\n return this.getTableSources();\r\n }\r\n\r\n /**\r\n * Main entry point for the visitor pattern.\r\n * Implements the shallow visit pattern to distinguish between root and recursive visits.\r\n */\r\n public visit(arg: SqlComponent): void {\r\n // If not a root visit, just visit the node and return\r\n if (!this.isRootVisit) {\r\n this.visitNode(arg);\r\n return;\r\n }\r\n\r\n // If this is a root visit, we need to reset the state\r\n this.reset();\r\n this.isRootVisit = false;\r\n\r\n try {\r\n // When in full scan mode, collect CTEs first to exclude them from table sources\r\n if (!this.selectableOnly) {\r\n this.collectCTEs(arg);\r\n }\r\n this.visitNode(arg);\r\n } finally {\r\n // Regardless of success or failure, reset the root visit flag\r\n this.isRootVisit = true;\r\n }\r\n }\r\n\r\n /**\r\n * Internal visit method used for all nodes.\r\n * This separates the visit flag management from the actual node visitation logic.\r\n */\r\n private visitNode(arg: SqlComponent): void {\r\n // Skip if we've already visited this node to prevent infinite recursion\r\n if (this.visitedNodes.has(arg)) {\r\n return;\r\n }\r\n\r\n // Mark as visited\r\n this.visitedNodes.add(arg);\r\n\r\n const handler = this.handlers.get(arg.getKind());\r\n if (handler) {\r\n handler(arg);\r\n return;\r\n }\r\n\r\n // If no handler found, that's ok - we only care about specific components\r\n }\r\n\r\n /**\r\n * Collects all CTE names to exclude them from real table sources\r\n */\r\n private collectCTEs(query: SqlComponent): void {\r\n // Use CommonTableCollector to get all CTEs\r\n const cteCollector = new CTECollector();\r\n cteCollector.visit(query);\r\n const commonTables = cteCollector.getCommonTables();\r\n\r\n // Add CTE names to the set\r\n for (const cte of commonTables) {\r\n // aliasExpression.table is TableSource, so use .table getter (IdentifierString)\r\n this.cteNames.add(cte.aliasExpression.table.name);\r\n }\r\n }\r\n\r\n private visitSimpleSelectQuery(query: SimpleSelectQuery): void {\r\n // Process the FROM and JOIN clauses\r\n if (query.fromClause) {\r\n query.fromClause.accept(this);\r\n }\r\n\r\n // If in full scan mode, visit all other clauses too\r\n if (!this.selectableOnly) {\r\n if (query.withClause) {\r\n query.withClause.accept(this);\r\n }\r\n\r\n if (query.whereClause) {\r\n query.whereClause.accept(this);\r\n }\r\n\r\n if (query.groupByClause) {\r\n query.groupByClause.accept(this);\r\n }\r\n\r\n if (query.havingClause) {\r\n query.havingClause.accept(this);\r\n }\r\n\r\n if (query.orderByClause) {\r\n query.orderByClause.accept(this);\r\n }\r\n\r\n if (query.windowClause) {\r\n for (const win of query.windowClause.windows) {\r\n win.accept(this);\r\n }\r\n }\r\n\r\n if (query.limitClause) {\r\n query.limitClause.accept(this);\r\n }\r\n\r\n if (query.offsetClause) {\r\n query.offsetClause.accept(this);\r\n }\r\n\r\n if (query.fetchClause) {\r\n query.fetchClause.accept(this);\r\n }\r\n\r\n if (query.forClause) {\r\n query.forClause.accept(this);\r\n }\r\n\r\n query.selectClause.accept(this);\r\n }\r\n }\r\n\r\n private visitBinarySelectQuery(query: BinarySelectQuery): void {\r\n // For UNION-like queries, visit both sides\r\n query.left.accept(this);\r\n query.right.accept(this);\r\n }\r\n\r\n private visitValuesQuery(query: ValuesQuery): void {\r\n if (!this.selectableOnly) {\r\n // VALUES queries might contain subqueries in tuple expressions\r\n for (const tuple of query.tuples) {\r\n tuple.accept(this);\r\n }\r\n }\r\n }\r\n\r\n private visitWithClause(withClause: WithClause): void {\r\n if (!this.selectableOnly) {\r\n // Visit each CommonTable\r\n for (const table of withClause.tables) {\r\n table.accept(this);\r\n }\r\n }\r\n }\r\n\r\n private visitCommonTable(commonTable: CommonTable): void {\r\n if (!this.selectableOnly) {\r\n // Process the query within the common table\r\n commonTable.query.accept(this);\r\n }\r\n }\r\n\r\n private visitFromClause(fromClause: FromClause): void {\r\n // Check the main source in FROM clause\r\n fromClause.source.accept(this);\r\n\r\n // Check all JOIN clauses\r\n if (fromClause.joins) {\r\n for (const join of fromClause.joins) {\r\n join.accept(this);\r\n }\r\n }\r\n }\r\n\r\n private visitSourceExpression(source: SourceExpression): void {\r\n // Process the actual data source, ignoring aliases\r\n source.datasource.accept(this);\r\n }\r\n\r\n private visitTableSource(source: TableSource): void {\r\n // Get the table identifier for uniqueness check\r\n const identifier = this.getTableIdentifier(source);\r\n\r\n // Check if this is a table managed by a CTE\r\n if (!this.tableNameMap.has(identifier) && !this.isCTETable(source.table.name)) {\r\n this.tableNameMap.set(identifier, true);\r\n this.tableSources.push(source);\r\n }\r\n }\r\n\r\n private visitFunctionSource(source: FunctionSource): void {\r\n // Function sources are not regular table sources, but may contain subqueries in their arguments\r\n if (source.argument) {\r\n // Special handling for function arguments to ensure we traverse nested structures\r\n this.visitValueComponent(source.argument);\r\n }\r\n // Function sources themselves are not collected as table sources\r\n }\r\n\r\n /**\r\n * Helper method to visit value components, handling special cases like TupleExpression, ParenExpression, InlineQuery, and ArrayQueryExpression\r\n * even in selectableOnly mode when they appear in function arguments\r\n */\r\n private visitValueComponent(value: ValueComponent): void {\r\n // Always use the normal accept pattern - let handlers deal with the logic\r\n value.accept(this);\r\n }\r\n\r\n /**\r\n * Checks if a table name is a CTE name\r\n */\r\n private isCTETable(tableName: string): boolean {\r\n return this.cteNames.has(tableName);\r\n }\r\n\r\n private visitParenSource(source: ParenSource): void {\r\n // For parenthesized sources, visit the inner source\r\n source.source.accept(this);\r\n }\r\n\r\n private visitSubQuerySource(subQuery: SubQuerySource): void {\r\n if (!this.selectableOnly) {\r\n // In full scan mode, we also check subqueries\r\n subQuery.query.accept(this);\r\n }\r\n // In selectableOnly mode, we don't collect sources from subqueries\r\n }\r\n\r\n private visitInlineQuery(inlineQuery: InlineQuery): void {\r\n if (!this.selectableOnly) {\r\n // In full scan mode, visit inline queries too\r\n inlineQuery.selectQuery.accept(this);\r\n }\r\n }\r\n\r\n private visitJoinClause(joinClause: JoinClause): void {\r\n // Visit the source being joined\r\n joinClause.source.accept(this);\r\n\r\n // If full scanning, also visit the join condition\r\n if (!this.selectableOnly && joinClause.condition) {\r\n joinClause.condition.accept(this);\r\n }\r\n }\r\n\r\n private visitJoinOnClause(joinOn: JoinOnClause): void {\r\n if (!this.selectableOnly) {\r\n // In full scan mode, check ON condition for table references\r\n joinOn.condition.accept(this);\r\n }\r\n }\r\n\r\n private visitJoinUsingClause(joinUsing: JoinUsingClause): void {\r\n if (!this.selectableOnly) {\r\n // In full scan mode, check USING condition for table references\r\n joinUsing.condition.accept(this);\r\n }\r\n }\r\n\r\n // Additional visitor methods only used in full scan mode\r\n\r\n private visitWhereClause(whereClause: WhereClause): void {\r\n whereClause.condition.accept(this);\r\n }\r\n\r\n private visitGroupByClause(clause: GroupByClause): void {\r\n for (const item of clause.grouping) {\r\n item.accept(this);\r\n }\r\n }\r\n\r\n private visitHavingClause(clause: HavingClause): void {\r\n clause.condition.accept(this);\r\n }\r\n\r\n private visitOrderByClause(clause: OrderByClause): void {\r\n for (const item of clause.order) {\r\n item.accept(this);\r\n }\r\n }\r\n\r\n private visitWindowFrameClause(clause: WindowFrameClause): void {\r\n clause.expression.accept(this);\r\n }\r\n\r\n private visitLimitClause(clause: LimitClause): void {\r\n clause.value.accept(this);\r\n }\r\n\r\n private visitOffsetClause(clause: OffsetClause): void {\r\n clause.value.accept(this);\r\n }\r\n\r\n private visitFetchClause(clause: FetchClause): void {\r\n clause.expression.accept(this);\r\n }\r\n\r\n private visitForClause(clause: ForClause): void {\r\n // FOR clause doesn't contain table sources\r\n }\r\n\r\n private visitOrderByItem(item: OrderByItem): void {\r\n item.value.accept(this);\r\n }\r\n\r\n private visitSelectClause(clause: SelectClause): void {\r\n for (const item of clause.items) {\r\n item.accept(this);\r\n }\r\n }\r\n\r\n private visitSelectItem(item: SelectItem): void {\r\n item.value.accept(this);\r\n }\r\n\r\n private visitParenExpression(expr: ParenExpression): void {\r\n expr.expression.accept(this);\r\n }\r\n\r\n private visitBinaryExpression(expr: BinaryExpression): void {\r\n expr.left.accept(this);\r\n expr.right.accept(this);\r\n }\r\n\r\n private visitUnaryExpression(expr: UnaryExpression): void {\r\n expr.expression.accept(this);\r\n }\r\n\r\n private visitCaseExpression(expr: CaseExpression): void {\r\n if (expr.condition) {\r\n expr.condition.accept(this);\r\n }\r\n expr.switchCase.accept(this);\r\n }\r\n\r\n private visitSwitchCaseArgument(switchCase: SwitchCaseArgument): void {\r\n for (const caseItem of switchCase.cases) {\r\n caseItem.accept(this);\r\n }\r\n\r\n if (switchCase.elseValue) {\r\n switchCase.elseValue.accept(this);\r\n }\r\n }\r\n\r\n private visitCaseKeyValuePair(pair: CaseKeyValuePair): void {\r\n pair.key.accept(this);\r\n pair.value.accept(this);\r\n }\r\n\r\n private visitBetweenExpression(expr: BetweenExpression): void {\r\n expr.expression.accept(this);\r\n expr.lower.accept(this);\r\n expr.upper.accept(this);\r\n }\r\n\r\n private visitFunctionCall(func: FunctionCall): void {\r\n if (func.argument) {\r\n func.argument.accept(this);\r\n }\r\n\r\n if (func.over) {\r\n func.over.accept(this);\r\n }\r\n }\r\n\r\n private visitArrayExpression(expr: ArrayExpression): void {\r\n expr.expression.accept(this);\r\n }\r\n\r\n private visitArrayQueryExpression(expr: ArrayQueryExpression): void {\r\n expr.query.accept(this);\r\n }\r\n\r\n private visitTupleExpression(expr: TupleExpression): void {\r\n for (const value of expr.values) {\r\n value.accept(this);\r\n }\r\n }\r\n\r\n private visitCastExpression(expr: CastExpression): void {\r\n expr.input.accept(this);\r\n expr.castType.accept(this);\r\n }\r\n\r\n private visitValueList(valueList: ValueList): void {\r\n // Process all values in the list, this may include InlineQuery and other table-referencing components\r\n for (const value of valueList.values) {\r\n value.accept(this);\r\n }\r\n }\r\n\r\n // Handle StringSpecifierExpression (PostgreSQL E-strings)\r\n private visitStringSpecifierExpression(expr: StringSpecifierExpression): void {\r\n // StringSpecifierExpression is just a literal string with an escape specifier\r\n // It doesn't contain table references, so we don't need to visit any children\r\n // This is a no-op method to prevent \"No handler\" errors\r\n }\r\n}", "export enum SqlPrintTokenType {\r\n container = 0,\r\n keyword,\r\n value, // Represents non-keyword elements such as table names\r\n comma, // Represents comma ','\r\n parenthesis, // Represents parentheses: ( ) { } [ ]\r\n operator, // Represents operators such as +, -, *, /\r\n comment,\r\n parameter,\r\n dot,\r\n type,\r\n space,\r\n argumentSplitter,\r\n}\r\n\r\n// Enum for container type, used for formatting and context\r\nexport enum SqlPrintTokenContainerType {\r\n ColumnReference = 'ColumnReference',\r\n LiteralValue = 'LiteralValue',\r\n IdentifierString = 'IdentifierString',\r\n InlineQuery = 'InlineQuery',\r\n StringSpecifierExpression = 'StringSpecifierExpression',\r\n None = '',\r\n ValueList = 'ValueList',\r\n OrderByItem = 'OrderByItem',\r\n FunctionCall = 'FunctionCall',\r\n UnaryExpression = 'UnaryExpression',\r\n BinaryExpression = 'BinaryExpression',\r\n SwitchCaseArgument = 'SwitchCaseArgument',\r\n ElseClause = 'ElseClause',\r\n CaseKeyValuePair = 'CaseKeyValuePair',\r\n CaseThenValue = 'CaseThenValue',\r\n CaseElseValue = 'CaseElseValue',\r\n ParenExpression = 'ParenExpression',\r\n CastExpression = 'CastExpression',\r\n CaseExpression = 'CaseExpression',\r\n ArrayExpression = 'ArrayExpression',\r\n BetweenExpression = 'BetweenExpression',\r\n TypeValue = 'TypeValue',\r\n TupleExpression = 'TupleExpression',\r\n WindowFrameExpression = 'WindowFrameExpression',\r\n SelectItem = 'SelectItem',\r\n SelectClause = 'SelectClause',\r\n DistinctOn = 'DistinctOn',\r\n SourceExpression = 'SourceExpression',\r\n FromClause = 'FromClause',\r\n JoinClause = 'JoinClause',\r\n JoinOnClause = 'JoinOnClause',\r\n JoinUsingClause = 'JoinUsingClause',\r\n FunctionSource = 'FunctionSource',\r\n SourceAliasExpression = 'SourceAliasExpression',\r\n RawString = 'RawString',\r\n QualifiedName = \"QualifiedName\",\r\n WhereClause = \"WhereClause\",\r\n SimpleSelectQuery = \"SimpleSelectQuery\",\r\n OrderByClause = \"OrderByClause\",\r\n GroupByClause = \"GroupByClause\",\r\n HavingClause = \"HavingClause\",\r\n SubQuerySource = \"SubQuerySource\",\r\n PartitionByClause = \"PartitionByClause\",\r\n WindowFrameClause = \"WindowFrameClause\",\r\n LimitClause = \"LimitClause\",\r\n OffsetClause = \"OffsetClause\",\r\n ForClause = \"ForClause\",\r\n WindowClause = \"WindowClause\",\r\n BinarySelectQueryOperator = \"BinarySelectQueryOperator\",\r\n Values = \"Values\",\r\n ValuesQuery = \"ValuesQuery\",\r\n WithClause = \"WithClause\",\r\n CommonTable = \"CommonTable\",\r\n WindowFrameSpec = \"WindowFrameSpec\",\r\n WindowFrameBoundStatic = \"WindowFrameBoundStatic\",\r\n WindowFrameBoundaryValue = \"WindowFrameBoundaryValue\",\r\n FetchClause = \"FetchClause\",\r\n FetchExpression = \"FetchExpression\",\r\n InsertQuery = \"InsertQuery\",\r\n UpdateQuery = \"UpdateQuery\",\r\n UpdateClause = \"UpdateClause\",\r\n ReturningClause = \"ReturningClause\",\r\n SetClauseItem = \"SetClauseItem\",\r\n CreateTableQuery = \"CreateTableQuery\",\r\n // Add more as needed\r\n}\r\n\r\nexport class SqlPrintToken {\r\n /**\r\n * The type of this token, representing the general category (e.g. keyword, value, operator).\r\n */\r\n type: SqlPrintTokenType;\r\n /**\r\n * The actual text content of this token, following SQL syntax.\r\n */\r\n text: string;\r\n /**\r\n * The type of the container this token belongs to. Used for clauses, functions, or other groupings.\r\n */\r\n containerType: SqlPrintTokenContainerType;\r\n\r\n /**\r\n * Optional. Keywords that are part of this token, like DISTINCT in a SELECT clause.\r\n * These should typically be processed before innerTokens.\r\n */\r\n keywordTokens?: SqlPrintToken[];\r\n\r\n /**\r\n * Child tokens that belong to this container.\r\n */\r\n innerTokens: SqlPrintToken[] = [];\r\n\r\n constructor(type: SqlPrintTokenType, text: string = '', containerType: SqlPrintTokenContainerType = SqlPrintTokenContainerType.None) {\r\n this.type = type;\r\n this.text = text;\r\n this.containerType = containerType;\r\n }\r\n}\r\n", "import { ParameterExpression } from \"../models/ValueComponent\";\r\n\r\n/**\r\n * Utility class to collect all ParameterExpression nodes from an AST.\r\n */\r\nexport class ParameterCollector {\r\n /**\r\n * Recursively collect all ParameterExpression nodes from AST.\r\n * @param node AST root\r\n * @returns ParameterExpression[]\r\n */\r\n static collect(node: any): ParameterExpression[] {\r\n const result: ParameterExpression[] = [];\r\n function walk(n: any) {\r\n if (!n || typeof n !== 'object') return;\r\n if (n.constructor && n.constructor.kind === ParameterExpression.kind) {\r\n result.push(n);\r\n }\r\n for (const key of Object.keys(n)) {\r\n const v = n[key];\r\n if (Array.isArray(v)) {\r\n v.forEach(walk);\r\n } else if (v && typeof v === 'object' && v.constructor && v.constructor.kind) {\r\n walk(v);\r\n }\r\n }\r\n }\r\n walk(node);\r\n return result;\r\n }\r\n}\r\n", "export class IdentifierDecorator {\r\n start: string;\r\n end: string;\r\n\r\n constructor(identifierEscape?: { start?: string; end?: string }) {\r\n this.start = identifierEscape?.start ?? '\"';\r\n this.end = identifierEscape?.end ?? '\"';\r\n }\r\n\r\n decorate(text: string): string {\r\n // override\r\n text = this.start + text + this.end;\r\n return text;\r\n }\r\n}\r\n", "/**\r\n * This decorator formats parameter tokens according to DBMS-specific rules.\r\n * It supports prefix/suffix, and parameter style (named, indexed, anonymous).\r\n */\r\nexport class ParameterDecorator {\r\n prefix: string;\r\n suffix: string;\r\n style: 'named' | 'indexed' | 'anonymous';\r\n\r\n constructor(options?: { prefix?: string; suffix?: string; style?: 'named' | 'indexed' | 'anonymous' }) {\r\n this.prefix = options?.prefix ?? ':';\r\n this.suffix = options?.suffix ?? '';\r\n this.style = options?.style ?? 'named';\r\n }\r\n\r\n /**\r\n * Decorate a parameter token with DBMS-specific format.\r\n * @param token The parameter token\r\n * @param index The parameter index (for indexed/anonymous)\r\n */\r\n decorate(text: string, index: number): string {\r\n let paramText = '';\r\n if (this.style === 'anonymous') {\r\n // e.g. ?\r\n paramText = this.prefix;\r\n } else if (this.style === 'indexed') {\r\n // e.g. $1, ?1, :1\r\n paramText = this.prefix + index;\r\n } else if (this.style === 'named') {\r\n // e.g. :name, @name, ${name}\r\n paramText = this.prefix + text + this.suffix;\r\n }\r\n\r\n // override \r\n text = paramText;\r\n return text;\r\n }\r\n}\r\n", "// Represents an UPDATE query in SQL.\r\n// Supports SET, WHERE, and optional FROM/RETURNING clauses.\r\nimport { SqlComponent } from \"./SqlComponent\";\r\nimport { IdentifierString, ValueComponent } from \"./ValueComponent\";\r\nimport { FromClause, ReturningClause, SetClause, WhereClause, SourceExpression, UpdateClause } from \"./Clause\";\r\nimport { WithClause } from \"./Clause\";\r\n\r\nexport class UpdateQuery extends SqlComponent {\r\n static kind = Symbol(\"UpdateQuery\");\r\n withClause: WithClause | null;\r\n updateClause: UpdateClause;\r\n setClause: SetClause;\r\n whereClause: WhereClause | null;\r\n fromClause: FromClause | null;\r\n returningClause: ReturningClause | null;\r\n\r\n /**\r\n * @param params.source SourceExpression (table or subquery with optional alias)\r\n * @param params.setClause SetClause instance or array of {column, value} pairs\r\n * @param params.where WHERE clause (optional)\r\n * @param params.from FROM clause (optional)\r\n * @param params.returning RETURNING clause (optional)\r\n */\r\n\r\n constructor(params: {\r\n withClause?: WithClause | null;\r\n updateClause: UpdateClause;\r\n setClause: SetClause | { column: string | IdentifierString, value: ValueComponent }[];\r\n whereClause?: WhereClause | null;\r\n fromClause?: FromClause | null;\r\n returning?: ReturningClause | null;\r\n }) {\r\n super();\r\n this.withClause = params.withClause ?? null;\r\n this.updateClause = params.updateClause;\r\n this.setClause = params.setClause instanceof SetClause ? params.setClause : new SetClause(params.setClause);\r\n this.whereClause = params.whereClause ?? null;\r\n this.fromClause = params.fromClause ?? null;\r\n this.returningClause = params.returning ?? null;\r\n }\r\n}\r\n", "import { CommonTable, FromClause, JoinClause, ParenSource, SelectClause, SelectItem, SourceExpression, SubQuerySource, TableSource } from \"../models/Clause\";\r\nimport { BinarySelectQuery, SimpleSelectQuery, SelectQuery, ValuesQuery } from \"../models/SelectQuery\";\r\nimport { SqlComponent, SqlComponentVisitor } from \"../models/SqlComponent\";\r\nimport { ColumnReference, InlineQuery, LiteralValue, ValueComponent } from \"../models/ValueComponent\";\r\nimport { CTECollector } from \"./CTECollector\";\r\nimport { TableColumnResolver } from \"./TableColumnResolver\";\r\n\r\n/**\r\n * A visitor that collects all SelectItem instances from a SQL query structure.\r\n * This visitor scans through select clauses and collects all the SelectItem objects.\r\n * It can also resolve wildcard selectors (table.* or *) using a provided table column resolver.\r\n */\r\nexport class SelectValueCollector implements SqlComponentVisitor<void> {\r\n private handlers: Map<symbol, (arg: any) => void>;\r\n private selectValues: { name: string, value: ValueComponent }[] = [];\r\n private visitedNodes: Set<SqlComponent> = new Set();\r\n private isRootVisit: boolean = true;\r\n private tableColumnResolver: TableColumnResolver | null;\r\n private commonTableCollector: CTECollector;\r\n private commonTables: CommonTable[];\r\n public initialCommonTables: CommonTable[] | null;\r\n\r\n constructor(tableColumnResolver: TableColumnResolver | null = null, initialCommonTables: CommonTable[] | null = null) {\r\n this.tableColumnResolver = tableColumnResolver ?? null;\r\n this.commonTableCollector = new CTECollector();\r\n this.commonTables = [];\r\n this.initialCommonTables = initialCommonTables;\r\n\r\n this.handlers = new Map<symbol, (arg: any) => void>();\r\n\r\n this.handlers.set(SimpleSelectQuery.kind, (expr) => this.visitSimpleSelectQuery(expr as SimpleSelectQuery));\r\n this.handlers.set(SelectClause.kind, (expr) => this.visitSelectClause(expr as SelectClause));\r\n this.handlers.set(SourceExpression.kind, (expr) => this.visitSourceExpression(expr as SourceExpression));\r\n this.handlers.set(FromClause.kind, (expr) => this.visitFromClause(expr as FromClause));\r\n }\r\n\r\n /**\r\n * Get all collected SelectItems as an array of objects with name and value properties\r\n * @returns An array of objects with name (string) and value (ValueComponent) properties\r\n */\r\n public getValues(): { name: string, value: ValueComponent }[] {\r\n return this.selectValues;\r\n }\r\n\r\n /**\r\n * Reset the collection of SelectItems\r\n */\r\n private reset(): void {\r\n this.selectValues = [];\r\n this.visitedNodes.clear();\r\n if (this.initialCommonTables) {\r\n this.commonTables = this.initialCommonTables;\r\n } else {\r\n this.commonTables = [];\r\n }\r\n }\r\n\r\n public collect(arg: SqlComponent): { name: string, value: ValueComponent }[] {\r\n // Visit the component and return the collected select items\r\n this.visit(arg);\r\n const items = this.getValues();\r\n this.reset(); // Reset after collection\r\n return items;\r\n }\r\n\r\n /**\r\n * Main entry point for the visitor pattern.\r\n * Implements the shallow visit pattern to distinguish between root and recursive visits.\r\n */\r\n public visit(arg: SqlComponent): void {\r\n // If not a root visit, just visit the node and return\r\n if (!this.isRootVisit) {\r\n this.visitNode(arg);\r\n return;\r\n }\r\n\r\n // If this is a root visit, we need to reset the state\r\n this.reset();\r\n this.isRootVisit = false;\r\n\r\n try {\r\n this.visitNode(arg);\r\n } finally {\r\n // Regardless of success or failure, reset the root visit flag\r\n this.isRootVisit = true;\r\n }\r\n }\r\n\r\n /**\r\n * Internal visit method used for all nodes.\r\n * This separates the visit flag management from the actual node visitation logic.\r\n */\r\n private visitNode(arg: SqlComponent): void {\r\n // Skip if we've already visited this node to prevent infinite recursion\r\n if (this.visitedNodes.has(arg)) {\r\n return;\r\n }\r\n\r\n // Mark as visited\r\n this.visitedNodes.add(arg);\r\n\r\n const handler = this.handlers.get(arg.getKind());\r\n if (handler) {\r\n handler(arg);\r\n return;\r\n }\r\n }\r\n\r\n /**\r\n * Process a SimpleSelectQuery to collect data and store the current context\r\n */\r\n private visitSimpleSelectQuery(query: SimpleSelectQuery): void {\r\n if (this.commonTables.length === 0 && this.initialCommonTables === null) {\r\n this.commonTables = this.commonTableCollector.collect(query);\r\n }\r\n\r\n if (query.selectClause) {\r\n query.selectClause.accept(this);\r\n }\r\n\r\n // no wildcard \r\n const wildcards = this.selectValues.filter(item => item.name === '*');\r\n if (wildcards.length === 0) {\r\n return;\r\n }\r\n\r\n // full wildcard\r\n if (this.selectValues.some(item => item.value instanceof ColumnReference && item.value.namespaces === null)) {\r\n if (query.fromClause) {\r\n this.processFromClause(query.fromClause, true);\r\n }\r\n // remove wildcard\r\n this.selectValues = this.selectValues.filter(item => item.name !== '*');\r\n return;\r\n };\r\n\r\n // table wildcard\r\n const wildSourceNames = wildcards.filter(item => item.value instanceof ColumnReference && item.value.namespaces)\r\n .map(item => (item.value as ColumnReference).getNamespace());\r\n\r\n if (query.fromClause) {\r\n const fromSourceName = query.fromClause.getSourceAliasName();\r\n if (fromSourceName && wildSourceNames.includes(fromSourceName)) {\r\n this.processFromClause(query.fromClause, false);\r\n }\r\n if (query.fromClause.joins) {\r\n for (const join of query.fromClause.joins) {\r\n const joinSourceName = join.getSourceAliasName();\r\n if (joinSourceName && wildSourceNames.includes(joinSourceName)) {\r\n this.processJoinClause(join);\r\n }\r\n }\r\n }\r\n }\r\n // remove wildcard\r\n this.selectValues = this.selectValues.filter(item => item.name !== '*');\r\n return;\r\n }\r\n\r\n private processFromClause(clause: FromClause, joinCascade: boolean): void {\r\n if (clause) {\r\n const fromSourceName = clause.getSourceAliasName();\r\n this.processSourceExpression(fromSourceName, clause.source);\r\n\r\n if (clause.joins && joinCascade) {\r\n for (const join of clause.joins) {\r\n this.processJoinClause(join);\r\n }\r\n }\r\n }\r\n return;\r\n }\r\n\r\n private processJoinClause(clause: JoinClause): void {\r\n const sourceName = clause.getSourceAliasName();\r\n this.processSourceExpression(sourceName, clause.source);\r\n }\r\n\r\n private processSourceExpression(sourceName: string | null, source: SourceExpression) {\r\n // check common table\r\n const commonTable = this.commonTables.find(item => item.aliasExpression.table.name === sourceName);\r\n if (commonTable) {\r\n // Exclude this CTE from consideration to prevent self-reference\r\n const innerCommonTables = this.commonTables.filter(item => item.aliasExpression.table.name !== sourceName);\r\n\r\n const innerCollector = new SelectValueCollector(this.tableColumnResolver, innerCommonTables);\r\n const innerSelected = innerCollector.collect(commonTable.query);\r\n innerSelected.forEach(item => {\r\n this.addSelectValueAsUnique(item.name, new ColumnReference(sourceName ? [sourceName] : null, item.name));\r\n });\r\n } else {\r\n const innerCollector = new SelectValueCollector(this.tableColumnResolver, this.commonTables);\r\n const innerSelected = innerCollector.collect(source);\r\n innerSelected.forEach(item => {\r\n this.addSelectValueAsUnique(item.name, new ColumnReference(sourceName ? [sourceName] : null, item.name));\r\n });\r\n }\r\n }\r\n\r\n private visitSelectClause(clause: SelectClause): void {\r\n for (const item of clause.items) {\r\n this.processSelectItem(item);\r\n }\r\n }\r\n\r\n private processSelectItem(item: SelectItem): void {\r\n if (item.identifier) {\r\n this.addSelectValueAsUnique(item.identifier.name, item.value);\r\n }\r\n else if (item.value instanceof ColumnReference) { // Handle column reference\r\n // columnName can be '*'\r\n const columnName = item.value.column.name;\r\n if (columnName === '*') {\r\n // Force add without checking duplicates\r\n this.selectValues.push({ name: columnName, value: item.value });\r\n }\r\n else {\r\n // Add with duplicate checking\r\n this.addSelectValueAsUnique(columnName, item.value);\r\n }\r\n }\r\n }\r\n\r\n private visitSourceExpression(source: SourceExpression): void {\r\n // Column aliases have the highest priority if present\r\n // For physical tables, use external function to get column names\r\n // For subqueries, instantiate a new collector and get column names from the subquery\r\n // For parenthesized expressions, treat them the same as subqueries\r\n\r\n if (source.aliasExpression && source.aliasExpression.columns) {\r\n const sourceName = source.getAliasName();\r\n source.aliasExpression.columns.forEach(column => {\r\n this.addSelectValueAsUnique(column.name, new ColumnReference(sourceName ? [sourceName] : null, column.name));\r\n });\r\n return;\r\n } else if (source.datasource instanceof TableSource) {\r\n if (this.tableColumnResolver) {\r\n const sourceName = source.datasource.getSourceName();\r\n this.tableColumnResolver(sourceName).forEach(column => {\r\n this.addSelectValueAsUnique(column, new ColumnReference([sourceName], column));\r\n });\r\n }\r\n return;\r\n } else if (source.datasource instanceof SubQuerySource) {\r\n const sourceName = source.getAliasName();\r\n const innerCollector = new SelectValueCollector(this.tableColumnResolver, this.commonTables);\r\n const innerSelected = innerCollector.collect(source.datasource.query);\r\n innerSelected.forEach(item => {\r\n this.addSelectValueAsUnique(item.name, new ColumnReference(sourceName ? [sourceName] : null, item.name));\r\n });\r\n return;\r\n } else if (source.datasource instanceof ParenSource) {\r\n return this.visit(source.datasource.source);\r\n }\r\n }\r\n\r\n private visitFromClause(clause: FromClause): void {\r\n if (clause) {\r\n this.processFromClause(clause, true);\r\n }\r\n }\r\n\r\n private addSelectValueAsUnique(name: string, value: ValueComponent): void {\r\n // Check if a select value with the same name already exists before adding\r\n if (!this.selectValues.some(item => item.name === name)) {\r\n this.selectValues.push({ name, value });\r\n }\r\n }\r\n}\r\n", "import { SqlComponent } from \"./SqlComponent\";\r\nimport type { SelectQuery } from \"./SelectQuery\";\r\nimport { ColumnReference, FunctionCall, IdentifierString, RawString } from \"./ValueComponent\";\r\nimport { SimpleSelectQuery } from \"./SimpleSelectQuery\";\r\nimport { SelectClause, SelectItem, FromClause, TableSource, SourceExpression } from \"./Clause\";\r\nimport { SelectValueCollector } from \"../transformers/SelectValueCollector\";\r\n\r\n// Represents a CREATE TABLE query model\r\n// Supports temporary tables and AS SELECT ...\r\nexport class CreateTableQuery extends SqlComponent {\r\n /** SqlComponent kind symbol for visitor pattern */\r\n static kind = Symbol(\"CreateTableQuery\");\r\n /** Table name (with optional schema) */\r\n tableName: IdentifierString;\r\n /** If true, this is a temporary table */\r\n isTemporary: boolean;\r\n /** Optional: SELECT query for AS SELECT ... */\r\n asSelectQuery?: SelectQuery;\r\n\r\n constructor(params: {\r\n tableName: string;\r\n isTemporary?: boolean;\r\n asSelectQuery?: SelectQuery;\r\n }) {\r\n super();\r\n this.tableName = new IdentifierString(params.tableName);\r\n this.isTemporary = params.isTemporary ?? false;\r\n this.asSelectQuery = params.asSelectQuery;\r\n }\r\n\r\n /**\r\n * Returns a SelectQuery that selects all columns from this table.\r\n */\r\n getSelectQuery(): SimpleSelectQuery {\r\n let selectItems: SelectItem[];\r\n if (this.asSelectQuery) {\r\n // Use SelectValueCollector to get columns from asSelectQuery\r\n const collector = new SelectValueCollector();\r\n const values = collector.collect(this.asSelectQuery);\r\n selectItems = values.map(val => new SelectItem(val.value, val.name));\r\n } else {\r\n // fallback: wildcard\r\n selectItems = [new SelectItem(new RawString(\"*\"))];\r\n }\r\n return new SimpleSelectQuery({\r\n selectClause: new SelectClause(selectItems),\r\n fromClause: new FromClause(\r\n new SourceExpression(\r\n new TableSource(null, this.tableName.name),\r\n null\r\n ),\r\n null // joins\r\n ),\r\n });\r\n }\r\n\r\n /**\r\n * Returns a SelectQuery that counts all rows in this table.\r\n */\r\n getCountQuery(): SimpleSelectQuery {\r\n return new SimpleSelectQuery({\r\n selectClause: new SelectClause([\r\n new SelectItem(new FunctionCall(null, \"count\", new ColumnReference(null, \"*\"), null))\r\n ]),\r\n fromClause: new FromClause(\r\n new SourceExpression(\r\n new TableSource(null, this.tableName.name),\r\n null\r\n ),\r\n null // joins\r\n ),\r\n });\r\n }\r\n}\r\n", "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\";\r\nimport { BinarySelectQuery, SimpleSelectQuery, ValuesQuery } from \"../models/SelectQuery\";\r\nimport { SqlComponent, SqlComponentVisitor } from \"../models/SqlComponent\";\r\nimport { SqlPrintToken, SqlPrintTokenType, SqlPrintTokenContainerType } from \"../models/SqlPrintToken\";\r\nimport {\r\n ValueList,\r\n ColumnReference,\r\n FunctionCall,\r\n UnaryExpression,\r\n BinaryExpression,\r\n LiteralValue,\r\n ParameterExpression,\r\n SwitchCaseArgument,\r\n CaseKeyValuePair,\r\n RawString,\r\n IdentifierString,\r\n ParenExpression,\r\n CastExpression,\r\n CaseExpression,\r\n ArrayExpression,\r\n ArrayQueryExpression,\r\n BetweenExpression,\r\n StringSpecifierExpression,\r\n TypeValue,\r\n TupleExpression,\r\n WindowFrameExpression,\r\n QualifiedName,\r\n InlineQuery,\r\n WindowFrameSpec,\r\n WindowFrameBoundStatic,\r\n WindowFrameBoundaryValue\r\n} from \"../models/ValueComponent\";\r\nimport { ParameterCollector } from \"../transformers/ParameterCollector\";\r\nimport { IdentifierDecorator } from \"./IdentifierDecorator\";\r\nimport { ParameterDecorator } from \"./ParameterDecorator\";\r\nimport { InsertQuery } from \"../models/InsertQuery\";\r\nimport { UpdateQuery } from \"../models/UpdateQuery\";\r\nimport { CreateTableQuery } from \"../models/CreateTableQuery\";\r\n\r\nexport enum ParameterStyle {\r\n Anonymous = 'anonymous',\r\n Indexed = 'indexed',\r\n Named = 'named'\r\n}\r\n\r\nexport interface FormatterConfig {\r\n identifierEscape?: {\r\n start: string;\r\n end: string;\r\n };\r\n parameterSymbol?: string | { start: string; end: string };\r\n /**\r\n * Parameter style: anonymous (?), indexed ($1), or named (:name)\r\n */\r\n parameterStyle?: ParameterStyle;\r\n}\r\n\r\nexport const PRESETS: Record<string, FormatterConfig> = {\r\n mysql: {\r\n identifierEscape: { start: '`', end: '`' },\r\n parameterSymbol: '?',\r\n parameterStyle: ParameterStyle.Anonymous,\r\n },\r\n postgres: {\r\n identifierEscape: { start: '\"', end: '\"' },\r\n parameterSymbol: '$',\r\n parameterStyle: ParameterStyle.Indexed,\r\n },\r\n postgresWithNamedParams: {\r\n identifierEscape: { start: '\"', end: '\"' },\r\n parameterSymbol: ':',\r\n parameterStyle: ParameterStyle.Named,\r\n },\r\n sqlserver: {\r\n identifierEscape: { start: '[', end: ']' },\r\n parameterSymbol: '@',\r\n parameterStyle: ParameterStyle.Named,\r\n },\r\n sqlite: {\r\n identifierEscape: { start: '\"', end: '\"' },\r\n parameterSymbol: ':',\r\n parameterStyle: ParameterStyle.Named,\r\n },\r\n oracle: {\r\n identifierEscape: { start: '\"', end: '\"' },\r\n parameterSymbol: ':',\r\n parameterStyle: ParameterStyle.Named,\r\n },\r\n clickhouse: {\r\n identifierEscape: { start: '`', end: '`' },\r\n parameterSymbol: '?',\r\n parameterStyle: ParameterStyle.Anonymous,\r\n },\r\n firebird: {\r\n identifierEscape: { start: '\"', end: '\"' },\r\n parameterSymbol: '?',\r\n parameterStyle: ParameterStyle.Anonymous,\r\n },\r\n db2: {\r\n identifierEscape: { start: '\"', end: '\"' },\r\n parameterSymbol: '?',\r\n parameterStyle: ParameterStyle.Anonymous,\r\n },\r\n snowflake: {\r\n identifierEscape: { start: '\"', end: '\"' },\r\n parameterSymbol: '?',\r\n parameterStyle: ParameterStyle.Anonymous,\r\n },\r\n cloudspanner: {\r\n identifierEscape: { start: '`', end: '`' },\r\n parameterSymbol: '@',\r\n parameterStyle: ParameterStyle.Named,\r\n },\r\n duckdb: {\r\n identifierEscape: { start: '\"', end: '\"' },\r\n parameterSymbol: '?',\r\n parameterStyle: ParameterStyle.Anonymous,\r\n },\r\n cockroachdb: {\r\n identifierEscape: { start: '\"', end: '\"' },\r\n parameterSymbol: '$',\r\n parameterStyle: ParameterStyle.Indexed,\r\n },\r\n athena: {\r\n identifierEscape: { start: '\"', end: '\"' },\r\n parameterSymbol: '?',\r\n parameterStyle: ParameterStyle.Anonymous,\r\n },\r\n bigquery: {\r\n identifierEscape: { start: '`', end: '`' },\r\n parameterSymbol: '@',\r\n parameterStyle: ParameterStyle.Named,\r\n },\r\n hive: {\r\n identifierEscape: { start: '`', end: '`' },\r\n parameterSymbol: '?',\r\n parameterStyle: ParameterStyle.Anonymous,\r\n },\r\n mariadb: {\r\n identifierEscape: { start: '`', end: '`' },\r\n parameterSymbol: '?',\r\n parameterStyle: ParameterStyle.Anonymous,\r\n },\r\n redshift: {\r\n identifierEscape: { start: '\"', end: '\"' },\r\n parameterSymbol: '$',\r\n parameterStyle: ParameterStyle.Indexed,\r\n },\r\n flinksql: {\r\n identifierEscape: { start: '`', end: '`' },\r\n parameterSymbol: '?',\r\n parameterStyle: ParameterStyle.Anonymous,\r\n },\r\n mongodb: {\r\n identifierEscape: { start: '\"', end: '\"' },\r\n parameterSymbol: '?',\r\n parameterStyle: ParameterStyle.Anonymous,\r\n },\r\n};\r\n\r\nexport class SqlPrintTokenParser implements SqlComponentVisitor<SqlPrintToken> {\r\n // Static tokens for common symbols\r\n private static readonly SPACE_TOKEN = new SqlPrintToken(SqlPrintTokenType.space, ' ');\r\n private static readonly COMMA_TOKEN = new SqlPrintToken(SqlPrintTokenType.comma, ',');\r\n private static readonly ARGUMENT_SPLIT_COMMA_TOKEN = new SqlPrintToken(SqlPrintTokenType.argumentSplitter, ',');\r\n private static readonly PAREN_OPEN_TOKEN = new SqlPrintToken(SqlPrintTokenType.parenthesis, '(');\r\n private static readonly PAREN_CLOSE_TOKEN = new SqlPrintToken(SqlPrintTokenType.parenthesis, ')');\r\n private static readonly DOT_TOKEN = new SqlPrintToken(SqlPrintTokenType.dot, '.');\r\n\r\n private handlers: Map<symbol, (arg: any) => SqlPrintToken> = new Map();\r\n parameterDecorator: ParameterDecorator;\r\n identifierDecorator: IdentifierDecorator;\r\n index: number = 1;\r\n\r\n constructor(options?: {\r\n preset?: FormatterConfig,\r\n identifierEscape?: { start: string; end: string },\r\n parameterSymbol?: string | { start: string; end: string },\r\n parameterStyle?: 'anonymous' | 'indexed' | 'named'\r\n }) {\r\n if (options?.preset) {\r\n const preset = options.preset\r\n options = { ...preset, ...options };\r\n }\r\n\r\n this.parameterDecorator = new ParameterDecorator({\r\n prefix: typeof options?.parameterSymbol === 'string' ? options.parameterSymbol : options?.parameterSymbol?.start ?? ':',\r\n suffix: typeof options?.parameterSymbol === 'object' ? options.parameterSymbol.end : '',\r\n style: options?.parameterStyle ?? 'named'\r\n });\r\n\r\n this.identifierDecorator = new IdentifierDecorator({\r\n start: options?.identifierEscape?.start ?? '\"',\r\n end: options?.identifierEscape?.end ?? '\"'\r\n });\r\n\r\n this.handlers.set(ValueList.kind, (expr) => this.visitValueList(expr as ValueList));\r\n this.handlers.set(ColumnReference.kind, (expr) => this.visitColumnReference(expr as ColumnReference));\r\n this.handlers.set(QualifiedName.kind, (expr) => this.visitQualifiedName(expr as QualifiedName));\r\n this.handlers.set(FunctionCall.kind, (expr) => this.visitFunctionCall(expr as FunctionCall));\r\n this.handlers.set(UnaryExpression.kind, (expr) => this.visitUnaryExpression(expr as UnaryExpression));\r\n this.handlers.set(BinaryExpression.kind, (expr) => this.visitBinaryExpression(expr as BinaryExpression));\r\n this.handlers.set(LiteralValue.kind, (expr) => this.visitLiteralValue(expr as LiteralValue));\r\n this.handlers.set(ParameterExpression.kind, (expr) => this.visitParameterExpression(expr as ParameterExpression));\r\n this.handlers.set(SwitchCaseArgument.kind, (expr) => this.visitSwitchCaseArgument(expr as SwitchCaseArgument));\r\n this.handlers.set(CaseKeyValuePair.kind, (expr) => this.visitCaseKeyValuePair(expr as CaseKeyValuePair));\r\n this.handlers.set(RawString.kind, (expr) => this.visitRawString(expr as RawString));\r\n this.handlers.set(IdentifierString.kind, (expr) => this.visitIdentifierString(expr as IdentifierString));\r\n this.handlers.set(ParenExpression.kind, (expr) => this.visitParenExpression(expr as ParenExpression));\r\n this.handlers.set(CastExpression.kind, (expr) => this.visitCastExpression(expr as CastExpression));\r\n this.handlers.set(CaseExpression.kind, (expr) => this.visitCaseExpression(expr as CaseExpression));\r\n this.handlers.set(ArrayExpression.kind, (expr) => this.visitArrayExpression(expr as ArrayExpression));\r\n this.handlers.set(ArrayQueryExpression.kind, (expr) => this.visitArrayQueryExpression(expr as ArrayQueryExpression));\r\n this.handlers.set(BetweenExpression.kind, (expr) => this.visitBetweenExpression(expr as BetweenExpression));\r\n this.handlers.set(StringSpecifierExpression.kind, (expr) => this.visitStringSpecifierExpression(expr as StringSpecifierExpression));\r\n this.handlers.set(TypeValue.kind, (expr) => this.visitTypeValue(expr as TypeValue));\r\n this.handlers.set(TupleExpression.kind, (expr) => this.visitTupleExpression(expr as TupleExpression));\r\n this.handlers.set(InlineQuery.kind, (expr) => this.visitInlineQuery(expr as InlineQuery));\r\n\r\n this.handlers.set(WindowFrameExpression.kind, (expr) => this.visitWindowFrameExpression(expr as WindowFrameExpression));\r\n this.handlers.set(WindowFrameSpec.kind, (expr) => this.visitWindowFrameSpec(expr as WindowFrameSpec));\r\n this.handlers.set(WindowFrameBoundStatic.kind, (expr) => this.visitWindowFrameBoundStatic(expr as WindowFrameBoundStatic));\r\n this.handlers.set(WindowFrameBoundaryValue.kind, (expr) => this.visitWindowFrameBoundaryValue(expr as WindowFrameBoundaryValue));\r\n this.handlers.set(PartitionByClause.kind, (expr) => this.visitPartitionByClause(expr as PartitionByClause));\r\n this.handlers.set(OrderByClause.kind, (expr) => this.visitOrderByClause(expr as OrderByClause));\r\n this.handlers.set(OrderByItem.kind, (expr) => this.visitOrderByItem(expr));\r\n\r\n // select\r\n this.handlers.set(SelectItem.kind, (expr) => this.visitSelectItem(expr as SelectItem));\r\n this.handlers.set(SelectClause.kind, (expr) => this.visitSelectClause(expr as SelectClause));\r\n this.handlers.set(Distinct.kind, (expr) => this.visitDistinct(expr as Distinct));\r\n this.handlers.set(DistinctOn.kind, (expr) => this.visitDistinctOn(expr as DistinctOn));\r\n\r\n // from\r\n this.handlers.set(TableSource.kind, (expr) => this.visitTableSource(expr as TableSource));\r\n this.handlers.set(FunctionSource.kind, (expr) => this.visitFunctionSource(expr as FunctionSource));\r\n this.handlers.set(SourceExpression.kind, (expr) => this.visitSourceExpression(expr as SourceExpression));\r\n this.handlers.set(SourceAliasExpression.kind, (expr) => this.visitSourceAliasExpression(expr as SourceAliasExpression));\r\n this.handlers.set(FromClause.kind, (expr) => this.visitFromClause(expr as FromClause));\r\n this.handlers.set(JoinClause.kind, (expr) => this.visitJoinClause(expr as JoinClause));\r\n this.handlers.set(JoinOnClause.kind, (expr) => this.visitJoinOnClause(expr as JoinOnClause));\r\n this.handlers.set(JoinUsingClause.kind, (expr) => this.visitJoinUsingClause(expr as JoinUsingClause));\r\n\r\n // where\r\n this.handlers.set(WhereClause.kind, (expr) => this.visitWhereClause(expr as WhereClause));\r\n\r\n // group\r\n this.handlers.set(GroupByClause.kind, (expr) => this.visitGroupByClause(expr as GroupByClause));\r\n this.handlers.set(HavingClause.kind, (expr) => this.visitHavingClause(expr as HavingClause));\r\n\r\n this.handlers.set(WindowClause.kind, (expr) => this.visitWindowClause(expr as WindowClause));\r\n this.handlers.set(WindowFrameClause.kind, (expr) => this.visitWindowFrameClause(expr as WindowFrameClause));\r\n this.handlers.set(LimitClause.kind, (expr) => this.visitLimitClause(expr as LimitClause));\r\n this.handlers.set(OffsetClause.kind, (expr) => this.visitOffsetClause(expr as OffsetClause));\r\n this.handlers.set(FetchClause.kind, (expr) => this.visitFetchClause(expr as FetchClause));\r\n this.handlers.set(FetchExpression.kind, (expr) => this.visitFetchExpression(expr as FetchExpression));\r\n this.handlers.set(ForClause.kind, (expr) => this.visitForClause(expr as ForClause));\r\n\r\n // With\r\n this.handlers.set(WithClause.kind, (expr) => this.visitWithClause(expr as WithClause));\r\n this.handlers.set(CommonTable.kind, (expr) => this.visitCommonTable(expr as CommonTable));\r\n\r\n // Query\r\n this.handlers.set(SimpleSelectQuery.kind, (expr) => this.visitSimpleQuery(expr as SimpleSelectQuery));\r\n this.handlers.set(SubQuerySource.kind, (expr) => this.visitSubQuerySource(expr as SubQuerySource));\r\n this.handlers.set(BinarySelectQuery.kind, (expr) => this.visitBinarySelectQuery(expr));\r\n this.handlers.set(ValuesQuery.kind, (expr) => this.visitValuesQuery(expr as ValuesQuery));\r\n this.handlers.set(TupleExpression.kind, (expr) => this.visitTupleExpression(expr as TupleExpression));\r\n\r\n this.handlers.set(InsertQuery.kind, (expr) => this.visitInsertQuery(expr as InsertQuery));\r\n this.handlers.set(InsertClause.kind, (expr) => this.visitInsertClause(expr as InsertClause));\r\n this.handlers.set(UpdateQuery.kind, (expr) => this.visitUpdateQuery(expr as UpdateQuery));\r\n this.handlers.set(UpdateClause.kind, (expr) => this.visitUpdateClause(expr as UpdateClause));\r\n this.handlers.set(SetClause.kind, (expr) => this.visitSetClause(expr as SetClause));\r\n this.handlers.set(SetClauseItem.kind, (expr) => this.visitSetClauseItem(expr as SetClauseItem));\r\n this.handlers.set(ReturningClause.kind, (expr) => this.visitReturningClause(expr as ReturningClause));\r\n this.handlers.set(CreateTableQuery.kind, (expr) => this.visitCreateTableQuery(expr as CreateTableQuery));\r\n }\r\n\r\n /**\r\n * Pretty-prints a BinarySelectQuery (e.g., UNION, INTERSECT, EXCEPT).\r\n * This will recursively print left and right queries, separated by the operator.\r\n * @param arg BinarySelectQuery\r\n */\r\n private visitBinarySelectQuery(arg: BinarySelectQuery): SqlPrintToken {\r\n const token = new SqlPrintToken(SqlPrintTokenType.container, '');\r\n\r\n token.innerTokens.push(this.visit(arg.left));\r\n token.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN);\r\n\r\n token.innerTokens.push(new SqlPrintToken(SqlPrintTokenType.keyword, arg.operator.value, SqlPrintTokenContainerType.BinarySelectQueryOperator));\r\n\r\n token.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN);\r\n token.innerTokens.push(this.visit(arg.right));\r\n\r\n return token;\r\n }\r\n\r\n /**\r\n * Returns an array of tokens representing a comma followed by a space.\r\n * This is a common pattern in SQL pretty-printing.\r\n */\r\n private static commaSpaceTokens(): SqlPrintToken[] {\r\n return [SqlPrintTokenParser.COMMA_TOKEN, SqlPrintTokenParser.SPACE_TOKEN];\r\n }\r\n\r\n private static argumentCommaSpaceTokens(): SqlPrintToken[] {\r\n return [SqlPrintTokenParser.ARGUMENT_SPLIT_COMMA_TOKEN, SqlPrintTokenParser.SPACE_TOKEN];\r\n }\r\n\r\n\r\n private visitQualifiedName(arg: QualifiedName): SqlPrintToken {\r\n const token = new SqlPrintToken(SqlPrintTokenType.container, '', SqlPrintTokenContainerType.QualifiedName);\r\n\r\n if (arg.namespaces) {\r\n for (let i = 0; i < arg.namespaces.length; i++) {\r\n token.innerTokens.push(arg.namespaces[i].accept(this));\r\n token.innerTokens.push(SqlPrintTokenParser.DOT_TOKEN);\r\n }\r\n }\r\n token.innerTokens.push(arg.name.accept(this));\r\n\r\n return token;\r\n }\r\n\r\n private visitPartitionByClause(arg: PartitionByClause): SqlPrintToken {\r\n // Print as: partition by ...\r\n const token = new SqlPrintToken(SqlPrintTokenType.keyword, 'partition by', SqlPrintTokenContainerType.PartitionByClause);\r\n token.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN);\r\n token.innerTokens.push(this.visit(arg.value));\r\n return token;\r\n }\r\n\r\n private visitOrderByClause(arg: OrderByClause): SqlPrintToken {\r\n // Print as: order by ...\r\n const token = new SqlPrintToken(SqlPrintTokenType.keyword, 'order by', SqlPrintTokenContainerType.OrderByClause);\r\n token.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN);\r\n for (let i = 0; i < arg.order.length; i++) {\r\n if (i > 0) token.innerTokens.push(...SqlPrintTokenParser.commaSpaceTokens());\r\n token.innerTokens.push(this.visit(arg.order[i]));\r\n }\r\n return token;\r\n }\r\n\r\n /**\r\n * Print an OrderByItem (expression [asc|desc] [nulls first|last])\r\n */\r\n private visitOrderByItem(arg: OrderByItem): SqlPrintToken {\r\n // arg: OrderByItem\r\n const token = new SqlPrintToken(SqlPrintTokenType.container, '', SqlPrintTokenContainerType.OrderByItem);\r\n token.innerTokens.push(this.visit(arg.value));\r\n\r\n if (arg.sortDirection && arg.sortDirection !== SortDirection.Ascending) {\r\n token.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN);\r\n token.innerTokens.push(new SqlPrintToken(SqlPrintTokenType.keyword, 'desc'));\r\n }\r\n\r\n if (arg.nullsPosition) {\r\n if (arg.nullsPosition === NullsSortDirection.First) {\r\n token.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN);\r\n token.innerTokens.push(new SqlPrintToken(SqlPrintTokenType.keyword, 'nulls first'));\r\n } else if (arg.nullsPosition === NullsSortDirection.Last) {\r\n token.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN);\r\n token.innerTokens.push(new SqlPrintToken(SqlPrintTokenType.keyword, 'nulls last'));\r\n }\r\n }\r\n return token;\r\n }\r\n\r\n public parse(arg: SqlComponent): { token: SqlPrintToken, params: any[] | Record<string, any>[] | Record<string, any> } {\r\n // reset parameter index before parsing\r\n this.index = 1;\r\n\r\n const token = this.visit(arg);\r\n const paramsRaw = ParameterCollector.collect(arg).sort((a, b) => (a.index ?? 0) - (b.index ?? 0));\r\n\r\n const style = this.parameterDecorator.style;\r\n if (style === ParameterStyle.Named) {\r\n // Named: { name: value, ... }\r\n const paramsObj: Record<string, any> = {};\r\n for (const p of paramsRaw) {\r\n const key = p.name.value;\r\n if (paramsObj.hasOwnProperty(key)) {\r\n if (paramsObj[key] !== p.value) {\r\n throw new Error(`Duplicate parameter name '${key}' with different values detected during query composition.`);\r\n }\r\n // If value is the same, skip (already set)\r\n continue;\r\n }\r\n paramsObj[key] = p.value;\r\n }\r\n return { token, params: paramsObj };\r\n } else if (style === ParameterStyle.Indexed) {\r\n // Indexed: [value1, value2, ...] (sorted by index)\r\n const paramsArr = paramsRaw.map(p => p.value);\r\n return { token, params: paramsArr };\r\n } else if (style === ParameterStyle.Anonymous) {\r\n // Anonymous: [value1, value2, ...] (sorted by index, name is empty)\r\n const paramsArr = paramsRaw.map(p => p.value);\r\n return { token, params: paramsArr };\r\n }\r\n\r\n // Fallback (just in case)\r\n return { token, params: [] };\r\n }\r\n\r\n public visit(arg: SqlComponent): SqlPrintToken {\r\n const handler = this.handlers.get(arg.getKind());\r\n if (handler) {\r\n return handler(arg);\r\n }\r\n throw new Error(`[SqlPrintTokenParser] No handler for kind: ${arg.getKind().toString()}`);\r\n }\r\n\r\n private visitValueList(arg: ValueList): SqlPrintToken {\r\n const token = new SqlPrintToken(SqlPrintTokenType.container, '', SqlPrintTokenContainerType.ValueList);\r\n for (let i = 0; i < arg.values.length; i++) {\r\n if (i > 0) {\r\n token.innerTokens.push(...SqlPrintTokenParser.argumentCommaSpaceTokens());\r\n }\r\n token.innerTokens.push(this.visit(arg.values[i]));\r\n }\r\n return token;\r\n }\r\n\r\n private visitColumnReference(arg: ColumnReference): SqlPrintToken {\r\n const token = new SqlPrintToken(SqlPrintTokenType.container, '', SqlPrintTokenContainerType.ColumnReference);\r\n token.innerTokens.push(arg.qualifiedName.accept(this));\r\n return token;\r\n }\r\n\r\n private visitFunctionCall(arg: FunctionCall): SqlPrintToken {\r\n const token = new SqlPrintToken(SqlPrintTokenType.container, '', SqlPrintTokenContainerType.FunctionCall);\r\n\r\n token.innerTokens.push(arg.qualifiedName.accept(this));\r\n token.innerTokens.push(SqlPrintTokenParser.PAREN_OPEN_TOKEN);\r\n if (arg.argument) {\r\n token.innerTokens.push(this.visit(arg.argument));\r\n }\r\n token.innerTokens.push(SqlPrintTokenParser.PAREN_CLOSE_TOKEN);\r\n if (arg.over) {\r\n token.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN);\r\n token.innerTokens.push(new SqlPrintToken(SqlPrintTokenType.keyword, 'over'));\r\n\r\n if (arg.over instanceof IdentifierString) {\r\n token.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN);\r\n token.innerTokens.push(arg.over.accept(this));\r\n }\r\n else {\r\n token.innerTokens.push(SqlPrintTokenParser.PAREN_OPEN_TOKEN);\r\n token.innerTokens.push(this.visit(arg.over));\r\n token.innerTokens.push(SqlPrintTokenParser.PAREN_CLOSE_TOKEN);\r\n }\r\n }\r\n\r\n return token;\r\n }\r\n\r\n private visitUnaryExpression(arg: UnaryExpression): SqlPrintToken {\r\n const token = new SqlPrintToken(SqlPrintTokenType.container, '', SqlPrintTokenContainerType.UnaryExpression);\r\n\r\n token.innerTokens.push(this.visit(arg.operator));\r\n token.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN);\r\n token.innerTokens.push(this.visit(arg.expression));\r\n\r\n return token;\r\n }\r\n\r\n private visitBinaryExpression(arg: BinaryExpression): SqlPrintToken {\r\n const token = new SqlPrintToken(SqlPrintTokenType.container, '', SqlPrintTokenContainerType.BinaryExpression);\r\n\r\n token.innerTokens.push(this.visit(arg.left));\r\n token.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN);\r\n token.innerTokens.push(new SqlPrintToken(SqlPrintTokenType.operator, arg.operator.value));\r\n token.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN);\r\n token.innerTokens.push(this.visit(arg.right));\r\n\r\n return token;\r\n }\r\n\r\n private visitLiteralValue(arg: LiteralValue): SqlPrintToken {\r\n let text;\r\n if (typeof arg.value === \"string\") {\r\n text = `'${arg.value.replace(/'/g, \"''\")}'`;\r\n } else if (arg.value === null) {\r\n text = \"null\";\r\n } else {\r\n text = arg.value.toString();\r\n }\r\n return new SqlPrintToken(\r\n SqlPrintTokenType.value,\r\n text,\r\n SqlPrintTokenContainerType.LiteralValue\r\n );\r\n }\r\n\r\n private visitParameterExpression(arg: ParameterExpression): SqlPrintToken {\r\n // Create a parameter token and decorate it using the parameterDecorator\r\n arg.index = this.index;\r\n const text = this.parameterDecorator.decorate(arg.name.value, arg.index)\r\n const token = new SqlPrintToken(SqlPrintTokenType.parameter, text);\r\n\r\n this.index++;\r\n return token;\r\n }\r\n\r\n private visitSwitchCaseArgument(arg: SwitchCaseArgument): SqlPrintToken {\r\n const token = new SqlPrintToken(SqlPrintTokenType.container, '', SqlPrintTokenContainerType.SwitchCaseArgument);\r\n\r\n // Add each WHEN/THEN clause\r\n for (const kv of arg.cases) {\r\n // Create a new line for each WHEN clause\r\n token.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN);\r\n token.innerTokens.push(kv.accept(this));\r\n }\r\n\r\n // Add ELSE clause if present\r\n if (arg.elseValue) {\r\n token.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN);\r\n token.innerTokens.push(this.createElseToken(arg.elseValue));\r\n }\r\n return token;\r\n }\r\n\r\n private createElseToken(elseValue: SqlComponent): SqlPrintToken {\r\n // Creates a token for the ELSE clause in a CASE expression.\r\n const elseToken = new SqlPrintToken(SqlPrintTokenType.container, '', SqlPrintTokenContainerType.ElseClause); // Add the ELSE keyword\r\n elseToken.innerTokens.push(new SqlPrintToken(SqlPrintTokenType.keyword, 'else'));\r\n\r\n // Create a container for the ELSE value to enable proper indentation\r\n elseToken.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN);\r\n const elseValueContainer = new SqlPrintToken(SqlPrintTokenType.container, '', SqlPrintTokenContainerType.CaseElseValue);\r\n elseValueContainer.innerTokens.push(this.visit(elseValue));\r\n elseToken.innerTokens.push(elseValueContainer);\r\n\r\n return elseToken;\r\n }\r\n\r\n private visitCaseKeyValuePair(arg: CaseKeyValuePair): SqlPrintToken {\r\n const token = new SqlPrintToken(SqlPrintTokenType.container, '', SqlPrintTokenContainerType.CaseKeyValuePair);\r\n\r\n // Create WHEN clause\r\n token.innerTokens.push(new SqlPrintToken(SqlPrintTokenType.keyword, 'when'));\r\n token.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN);\r\n token.innerTokens.push(this.visit(arg.key)); // Create THEN clause\r\n token.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN);\r\n token.innerTokens.push(new SqlPrintToken(SqlPrintTokenType.keyword, 'then'));\r\n\r\n // Create a container for the THEN value to enable proper indentation\r\n token.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN);\r\n const thenValueContainer = new SqlPrintToken(SqlPrintTokenType.container, '', SqlPrintTokenContainerType.CaseThenValue);\r\n thenValueContainer.innerTokens.push(this.visit(arg.value));\r\n token.innerTokens.push(thenValueContainer);\r\n\r\n return token;\r\n }\r\n\r\n private visitRawString(arg: RawString): SqlPrintToken {\r\n // Even for non-container tokens, set the container type for context\r\n return new SqlPrintToken(\r\n SqlPrintTokenType.value,\r\n arg.value,\r\n SqlPrintTokenContainerType.RawString\r\n );\r\n }\r\n\r\n private visitIdentifierString(arg: IdentifierString): SqlPrintToken {\r\n // Create an identifier token and decorate it using the identifierDecorator\r\n const text = arg.name === \"*\" ? arg.name : this.identifierDecorator.decorate(arg.name)\r\n const token = new SqlPrintToken(\r\n SqlPrintTokenType.value,\r\n text,\r\n SqlPrintTokenContainerType.IdentifierString\r\n );\r\n return token;\r\n }\r\n\r\n private visitParenExpression(arg: ParenExpression): SqlPrintToken {\r\n const token = new SqlPrintToken(SqlPrintTokenType.container, '', SqlPrintTokenContainerType.ParenExpression);\r\n\r\n token.innerTokens.push(SqlPrintTokenParser.PAREN_OPEN_TOKEN);\r\n token.innerTokens.push(this.visit(arg.expression));\r\n token.innerTokens.push(SqlPrintTokenParser.PAREN_CLOSE_TOKEN);\r\n\r\n return token;\r\n }\r\n\r\n private visitCastExpression(arg: CastExpression): SqlPrintToken {\r\n const token = new SqlPrintToken(SqlPrintTokenType.container, '', SqlPrintTokenContainerType.CastExpression);\r\n\r\n token.innerTokens.push(this.visit(arg.input));\r\n token.innerTokens.push(new SqlPrintToken(SqlPrintTokenType.operator, '::'));\r\n token.innerTokens.push(this.visit(arg.castType));\r\n\r\n return token;\r\n }\r\n\r\n private visitCaseExpression(arg: CaseExpression): SqlPrintToken {\r\n const token = new SqlPrintToken(SqlPrintTokenType.container, '', SqlPrintTokenContainerType.CaseExpression);\r\n\r\n // Add the CASE keyword\r\n token.innerTokens.push(new SqlPrintToken(SqlPrintTokenType.keyword, 'case'));\r\n\r\n // Add the condition if exists\r\n if (arg.condition) {\r\n token.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN);\r\n token.innerTokens.push(this.visit(arg.condition));\r\n }\r\n\r\n // Add the WHEN/THEN pairs and ELSE\r\n token.innerTokens.push(this.visit(arg.switchCase));\r\n\r\n // Add the END keyword\r\n token.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN);\r\n token.innerTokens.push(new SqlPrintToken(SqlPrintTokenType.keyword, 'end'));\r\n\r\n return token;\r\n }\r\n\r\n private visitArrayExpression(arg: ArrayExpression): SqlPrintToken {\r\n const token = new SqlPrintToken(SqlPrintTokenType.container, '', SqlPrintTokenContainerType.ArrayExpression);\r\n\r\n token.innerTokens.push(new SqlPrintToken(SqlPrintTokenType.keyword, 'array'));\r\n token.innerTokens.push(new SqlPrintToken(SqlPrintTokenType.parenthesis, '['));\r\n token.innerTokens.push(this.visit(arg.expression));\r\n token.innerTokens.push(new SqlPrintToken(SqlPrintTokenType.parenthesis, ']'));\r\n\r\n return token;\r\n }\r\n\r\n private visitArrayQueryExpression(arg: ArrayQueryExpression): SqlPrintToken {\r\n const token = new SqlPrintToken(SqlPrintTokenType.container, '', SqlPrintTokenContainerType.ArrayExpression);\r\n\r\n token.innerTokens.push(new SqlPrintToken(SqlPrintTokenType.keyword, 'array'));\r\n // ARRAY(SELECT ...)\r\n token.innerTokens.push(new SqlPrintToken(SqlPrintTokenType.parenthesis, '('));\r\n token.innerTokens.push(this.visit(arg.query));\r\n token.innerTokens.push(new SqlPrintToken(SqlPrintTokenType.parenthesis, ')'));\r\n\r\n return token;\r\n }\r\n\r\n private visitBetweenExpression(arg: BetweenExpression): SqlPrintToken {\r\n const token = new SqlPrintToken(SqlPrintTokenType.container, '', SqlPrintTokenContainerType.BetweenExpression);\r\n\r\n token.innerTokens.push(this.visit(arg.expression));\r\n token.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN);\r\n if (arg.negated) {\r\n token.innerTokens.push(new SqlPrintToken(SqlPrintTokenType.keyword, 'not'));\r\n token.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN);\r\n }\r\n token.innerTokens.push(new SqlPrintToken(SqlPrintTokenType.keyword, 'between'));\r\n token.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN);\r\n token.innerTokens.push(this.visit(arg.lower));\r\n token.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN);\r\n token.innerTokens.push(new SqlPrintToken(SqlPrintTokenType.keyword, 'and'));\r\n token.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN);\r\n token.innerTokens.push(this.visit(arg.upper));\r\n\r\n return token;\r\n }\r\n\r\n private visitStringSpecifierExpression(arg: StringSpecifierExpression): SqlPrintToken {\r\n // Combine specifier and value into a single token\r\n const specifier = arg.specifier.accept(this).text;\r\n const value = arg.value.accept(this).text;\r\n return new SqlPrintToken(\r\n SqlPrintTokenType.value,\r\n specifier + value,\r\n SqlPrintTokenContainerType.StringSpecifierExpression\r\n );\r\n }\r\n\r\n private visitTypeValue(arg: TypeValue): SqlPrintToken {\r\n const token = new SqlPrintToken(SqlPrintTokenType.container, '', SqlPrintTokenContainerType.TypeValue);\r\n\r\n token.innerTokens.push(arg.qualifiedName.accept(this));\r\n if (arg.argument) {\r\n token.innerTokens.push(SqlPrintTokenParser.PAREN_OPEN_TOKEN);\r\n token.innerTokens.push(this.visit(arg.argument));\r\n token.innerTokens.push(SqlPrintTokenParser.PAREN_CLOSE_TOKEN);\r\n }\r\n\r\n return token;\r\n }\r\n\r\n private visitTupleExpression(arg: TupleExpression): SqlPrintToken {\r\n const token = new SqlPrintToken(SqlPrintTokenType.container, '', SqlPrintTokenContainerType.TupleExpression);\r\n\r\n token.innerTokens.push(SqlPrintTokenParser.PAREN_OPEN_TOKEN);\r\n for (let i = 0; i < arg.values.length; i++) {\r\n if (i > 0) {\r\n token.innerTokens.push(...SqlPrintTokenParser.argumentCommaSpaceTokens());\r\n }\r\n token.innerTokens.push(this.visit(arg.values[i]));\r\n }\r\n token.innerTokens.push(SqlPrintTokenParser.PAREN_CLOSE_TOKEN);\r\n\r\n return token;\r\n }\r\n\r\n private visitWindowFrameExpression(arg: WindowFrameExpression): SqlPrintToken {\r\n // Compose window frame expression: over(partition by ... order by ... rows ...)\r\n const token = new SqlPrintToken(SqlPrintTokenType.container, '', SqlPrintTokenContainerType.WindowFrameExpression);\r\n\r\n let first = true;\r\n if (arg.partition) {\r\n token.innerTokens.push(this.visit(arg.partition));\r\n first = false;\r\n }\r\n if (arg.order) {\r\n if (!first) {\r\n token.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN);\r\n } else {\r\n first = false;\r\n }\r\n token.innerTokens.push(this.visit(arg.order));\r\n }\r\n if (arg.frameSpec) {\r\n if (!first) {\r\n token.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN);\r\n } else {\r\n first = false;\r\n }\r\n token.innerTokens.push(this.visit(arg.frameSpec));\r\n }\r\n\r\n return token;\r\n }\r\n\r\n private visitWindowFrameSpec(arg: WindowFrameSpec): SqlPrintToken {\r\n // This method prints a window frame specification, such as \"rows between ... and ...\" or \"range ...\".\r\n const token = new SqlPrintToken(SqlPrintTokenType.container, '', SqlPrintTokenContainerType.WindowFrameSpec);\r\n\r\n // Add frame type (e.g., \"rows\", \"range\", \"groups\")\r\n token.innerTokens.push(new SqlPrintToken(SqlPrintTokenType.keyword, arg.frameType));\r\n\r\n if (arg.endBound === null) {\r\n // Only start bound: e.g., \"rows unbounded preceding\"\r\n token.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN);\r\n token.innerTokens.push(arg.startBound.accept(this));\r\n } else {\r\n // Between: e.g., \"rows between unbounded preceding and current row\"\r\n token.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN);\r\n token.innerTokens.push(new SqlPrintToken(SqlPrintTokenType.keyword, 'between'));\r\n token.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN);\r\n token.innerTokens.push(arg.startBound.accept(this));\r\n token.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN);\r\n token.innerTokens.push(new SqlPrintToken(SqlPrintTokenType.keyword, 'and'));\r\n token.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN);\r\n token.innerTokens.push(arg.endBound.accept(this));\r\n }\r\n\r\n return token;\r\n }\r\n\r\n /**\r\n * Prints a window frame boundary value, such as \"5 preceding\" or \"3 following\".\r\n * @param arg WindowFrameBoundaryValue\r\n */\r\n private visitWindowFrameBoundaryValue(arg: WindowFrameBoundaryValue): SqlPrintToken {\r\n const token = new SqlPrintToken(SqlPrintTokenType.container, '', SqlPrintTokenContainerType.WindowFrameBoundaryValue);\r\n\r\n token.innerTokens.push(arg.value.accept(this));\r\n token.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN);\r\n // true for \"FOLLOWING\", false for \"PRECEDING\"\r\n token.innerTokens.push(new SqlPrintToken(SqlPrintTokenType.keyword, arg.isFollowing ? 'following' : 'preceding'));\r\n\r\n return token;\r\n }\r\n\r\n /**\r\n * Prints a static window frame bound, such as \"unbounded preceding\", \"current row\", or \"unbounded following\".\r\n * @param arg WindowFrameBoundStatic\r\n */\r\n private visitWindowFrameBoundStatic(arg: WindowFrameBoundStatic): SqlPrintToken {\r\n const token = new SqlPrintToken(SqlPrintTokenType.keyword, arg.bound);\r\n return token;\r\n }\r\n\r\n private visitSelectItem(arg: SelectItem): SqlPrintToken {\r\n const token = new SqlPrintToken(SqlPrintTokenType.container, '', SqlPrintTokenContainerType.SelectItem);\r\n\r\n token.innerTokens.push(this.visit(arg.value));\r\n\r\n if (!arg.identifier) {\r\n return token;\r\n }\r\n\r\n // No alias needed if it matches the default name\r\n if (arg.value instanceof ColumnReference) {\r\n const defaultName = arg.value.column.name;\r\n if (arg.identifier.name === defaultName) {\r\n return token;\r\n }\r\n }\r\n\r\n // Add alias if it is different from the default name\r\n token.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN);\r\n token.innerTokens.push(new SqlPrintToken(SqlPrintTokenType.keyword, 'as'));\r\n token.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN);\r\n token.innerTokens.push(this.visit(arg.identifier));\r\n return token;\r\n }\r\n\r\n private visitSelectClause(arg: SelectClause): SqlPrintToken {\r\n const token = new SqlPrintToken(SqlPrintTokenType.keyword, 'select', SqlPrintTokenContainerType.SelectClause);\r\n\r\n token.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN);\r\n\r\n if (arg.distinct) {\r\n token.keywordTokens = [];\r\n token.keywordTokens.push(SqlPrintTokenParser.SPACE_TOKEN);\r\n token.keywordTokens.push(arg.distinct.accept(this));\r\n }\r\n\r\n for (let i = 0; i < arg.items.length; i++) {\r\n if (i > 0) {\r\n token.innerTokens.push(...SqlPrintTokenParser.commaSpaceTokens());\r\n }\r\n token.innerTokens.push(this.visit(arg.items[i]));\r\n }\r\n\r\n return token;\r\n }\r\n\r\n private visitDistinct(arg: Distinct): SqlPrintToken {\r\n const token = new SqlPrintToken(SqlPrintTokenType.keyword, 'distinct');\r\n return token;\r\n }\r\n\r\n private visitDistinctOn(arg: DistinctOn): SqlPrintToken {\r\n const token = new SqlPrintToken(SqlPrintTokenType.container, '', SqlPrintTokenContainerType.DistinctOn);\r\n\r\n token.innerTokens.push(new SqlPrintToken(SqlPrintTokenType.keyword, 'distinct on'));\r\n token.innerTokens.push(SqlPrintTokenParser.PAREN_OPEN_TOKEN);\r\n token.innerTokens.push(arg.value.accept(this));\r\n token.innerTokens.push(SqlPrintTokenParser.PAREN_CLOSE_TOKEN);\r\n\r\n return token;\r\n }\r\n\r\n private visitTableSource(arg: TableSource): SqlPrintToken {\r\n // Print table name with optional namespaces and alias\r\n let fullName = '';\r\n if (Array.isArray(arg.namespaces) && arg.namespaces.length > 0) {\r\n fullName = arg.namespaces.map(ns => ns.accept(this).text).join('.') + '.';\r\n }\r\n fullName += arg.table.accept(this).text;\r\n const token = new SqlPrintToken(SqlPrintTokenType.value, fullName);\r\n // alias (if present and different from table name)\r\n if (arg.identifier && arg.identifier.name !== arg.table.name) {\r\n\r\n }\r\n return token;\r\n }\r\n\r\n private visitSourceExpression(arg: SourceExpression): SqlPrintToken {\r\n // Print source expression (e.g. \"table\", \"table as t\", \"schema.table t\")\r\n const token = new SqlPrintToken(SqlPrintTokenType.container, '', SqlPrintTokenContainerType.SourceExpression);\r\n token.innerTokens.push(arg.datasource.accept(this));\r\n\r\n if (!arg.aliasExpression) {\r\n return token;\r\n }\r\n\r\n if (arg.datasource instanceof TableSource) {\r\n // No alias needed if it matches the default name\r\n const defaultName = arg.datasource.table.name;\r\n if (arg.aliasExpression.table.name === defaultName) {\r\n return token;\r\n }\r\n token.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN);\r\n token.innerTokens.push(new SqlPrintToken(SqlPrintTokenType.keyword, 'as'));\r\n token.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN);\r\n // exclude column aliases\r\n token.innerTokens.push(arg.aliasExpression.accept(this));\r\n return token;\r\n } else {\r\n // For other source types, just print the alias\r\n token.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN);\r\n token.innerTokens.push(new SqlPrintToken(SqlPrintTokenType.keyword, 'as'));\r\n token.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN);\r\n // included column aliases\r\n token.innerTokens.push(arg.aliasExpression.accept(this));\r\n return token;\r\n }\r\n }\r\n\r\n public visitFromClause(arg: FromClause): SqlPrintToken {\r\n const token = new SqlPrintToken(SqlPrintTokenType.keyword, 'from', SqlPrintTokenContainerType.FromClause);\r\n\r\n token.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN);\r\n token.innerTokens.push(this.visit(arg.source));\r\n\r\n if (arg.joins) {\r\n for (let i = 0; i < arg.joins.length; i++) {\r\n token.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN);\r\n token.innerTokens.push(this.visit(arg.joins[i]));\r\n }\r\n }\r\n\r\n return token;\r\n }\r\n\r\n public visitJoinClause(arg: JoinClause): SqlPrintToken {\r\n // Print join clause: [joinType] [lateral] [source] [on/using ...]\r\n const token = new SqlPrintToken(SqlPrintTokenType.container, '', SqlPrintTokenContainerType.JoinClause);\r\n\r\n // join type (e.g. inner join, left join, etc)\r\n token.innerTokens.push(new SqlPrintToken(SqlPrintTokenType.keyword, arg.joinType.value));\r\n if (arg.lateral) {\r\n token.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN);\r\n token.innerTokens.push(new SqlPrintToken(SqlPrintTokenType.keyword, 'lateral'));\r\n }\r\n token.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN);\r\n token.innerTokens.push(this.visit(arg.source));\r\n\r\n if (arg.condition) {\r\n token.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN);\r\n token.innerTokens.push(this.visit(arg.condition));\r\n }\r\n\r\n return token;\r\n }\r\n\r\n public visitJoinOnClause(arg: JoinOnClause): SqlPrintToken {\r\n const token = new SqlPrintToken(SqlPrintTokenType.container, '', SqlPrintTokenContainerType.JoinOnClause);\r\n\r\n token.innerTokens.push(new SqlPrintToken(SqlPrintTokenType.keyword, 'on'));\r\n token.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN);\r\n token.innerTokens.push(this.visit(arg.condition));\r\n\r\n return token;\r\n }\r\n\r\n public visitJoinUsingClause(arg: JoinUsingClause): SqlPrintToken {\r\n const token = new SqlPrintToken(SqlPrintTokenType.container, '', SqlPrintTokenContainerType.JoinUsingClause);\r\n\r\n token.innerTokens.push(new SqlPrintToken(SqlPrintTokenType.keyword, 'using'));\r\n token.innerTokens.push(SqlPrintTokenParser.PAREN_OPEN_TOKEN);\r\n token.innerTokens.push(this.visit(arg.condition));\r\n token.innerTokens.push(SqlPrintTokenParser.PAREN_CLOSE_TOKEN);\r\n\r\n return token;\r\n }\r\n\r\n public visitFunctionSource(arg: FunctionSource): SqlPrintToken {\r\n // Print function source: [functionName]([args])\r\n const token = new SqlPrintToken(SqlPrintTokenType.container, '', SqlPrintTokenContainerType.FunctionSource);\r\n\r\n token.innerTokens.push(arg.qualifiedName.accept(this));\r\n token.innerTokens.push(SqlPrintTokenParser.PAREN_OPEN_TOKEN);\r\n if (arg.argument) {\r\n token.innerTokens.push(this.visit(arg.argument));\r\n }\r\n token.innerTokens.push(SqlPrintTokenParser.PAREN_CLOSE_TOKEN);\r\n return token;\r\n }\r\n\r\n public visitSourceAliasExpression(arg: SourceAliasExpression): SqlPrintToken {\r\n // Print source alias expression: [source] as [alias]\r\n const token = new SqlPrintToken(\r\n SqlPrintTokenType.container,\r\n '',\r\n SqlPrintTokenContainerType.SourceAliasExpression\r\n );\r\n\r\n token.innerTokens.push(this.visit(arg.table));\r\n\r\n if (arg.columns) {\r\n token.innerTokens.push(SqlPrintTokenParser.PAREN_OPEN_TOKEN);\r\n for (let i = 0; i < arg.columns.length; i++) {\r\n if (i > 0) {\r\n token.innerTokens.push(...SqlPrintTokenParser.argumentCommaSpaceTokens());\r\n }\r\n token.innerTokens.push(this.visit(arg.columns[i]));\r\n }\r\n token.innerTokens.push(SqlPrintTokenParser.PAREN_CLOSE_TOKEN);\r\n }\r\n\r\n return token;\r\n }\r\n\r\n public visitWhereClause(arg: WhereClause): SqlPrintToken {\r\n const token = new SqlPrintToken(SqlPrintTokenType.keyword, 'where', SqlPrintTokenContainerType.WhereClause);\r\n\r\n token.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN);\r\n token.innerTokens.push(this.visit(arg.condition));\r\n\r\n return token;\r\n }\r\n\r\n public visitGroupByClause(arg: GroupByClause): SqlPrintToken {\r\n const token = new SqlPrintToken(SqlPrintTokenType.keyword, 'group by', SqlPrintTokenContainerType.GroupByClause);\r\n\r\n token.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN);\r\n for (let i = 0; i < arg.grouping.length; i++) {\r\n if (i > 0) {\r\n token.innerTokens.push(...SqlPrintTokenParser.commaSpaceTokens());\r\n }\r\n token.innerTokens.push(this.visit(arg.grouping[i]));\r\n }\r\n\r\n return token;\r\n }\r\n\r\n public visitHavingClause(arg: HavingClause): SqlPrintToken {\r\n const token = new SqlPrintToken(SqlPrintTokenType.keyword, 'having', SqlPrintTokenContainerType.HavingClause);\r\n\r\n token.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN);\r\n token.innerTokens.push(this.visit(arg.condition));\r\n\r\n return token;\r\n }\r\n\r\n public visitWindowClause(arg: WindowClause): SqlPrintToken {\r\n const token = new SqlPrintToken(SqlPrintTokenType.keyword, 'window', SqlPrintTokenContainerType.WindowClause);\r\n\r\n token.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN);\r\n for (let i = 0; i < arg.windows.length; i++) {\r\n if (i > 0) {\r\n token.innerTokens.push(...SqlPrintTokenParser.commaSpaceTokens());\r\n }\r\n token.innerTokens.push(this.visit(arg.windows[i]));\r\n }\r\n\r\n return token;\r\n }\r\n\r\n public visitWindowFrameClause(arg: WindowFrameClause): SqlPrintToken {\r\n const token = new SqlPrintToken(SqlPrintTokenType.container, '', SqlPrintTokenContainerType.WindowFrameClause);\r\n\r\n token.innerTokens.push(arg.name.accept(this));\r\n token.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN);\r\n token.innerTokens.push(new SqlPrintToken(SqlPrintTokenType.keyword, 'as'));\r\n token.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN);\r\n token.innerTokens.push(SqlPrintTokenParser.PAREN_OPEN_TOKEN);\r\n token.innerTokens.push(this.visit(arg.expression));\r\n token.innerTokens.push(SqlPrintTokenParser.PAREN_CLOSE_TOKEN);\r\n\r\n return token;\r\n }\r\n\r\n public visitLimitClause(arg: LimitClause): SqlPrintToken {\r\n const token = new SqlPrintToken(SqlPrintTokenType.keyword, 'limit', SqlPrintTokenContainerType.LimitClause);\r\n\r\n token.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN);\r\n token.innerTokens.push(this.visit(arg.value));\r\n\r\n return token;\r\n }\r\n\r\n public visitOffsetClause(arg: OffsetClause): SqlPrintToken {\r\n const token = new SqlPrintToken(SqlPrintTokenType.keyword, 'offset', SqlPrintTokenContainerType.OffsetClause);\r\n\r\n token.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN);\r\n token.innerTokens.push(this.visit(arg.value));\r\n\r\n return token;\r\n }\r\n\r\n public visitFetchClause(arg: FetchClause): SqlPrintToken {\r\n const token = new SqlPrintToken(SqlPrintTokenType.keyword, 'fetch', SqlPrintTokenContainerType.FetchClause);\r\n\r\n token.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN);\r\n token.innerTokens.push(this.visit(arg.expression));\r\n\r\n return token;\r\n }\r\n\r\n public visitFetchExpression(arg: FetchExpression): SqlPrintToken {\r\n const token = new SqlPrintToken(SqlPrintTokenType.container, '', SqlPrintTokenContainerType.FetchExpression);\r\n\r\n token.innerTokens.push(new SqlPrintToken(SqlPrintTokenType.keyword, arg.type));\r\n token.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN);\r\n token.innerTokens.push(arg.count.accept(this));\r\n\r\n if (arg.unit) {\r\n token.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN);\r\n token.innerTokens.push(new SqlPrintToken(SqlPrintTokenType.keyword, arg.unit));\r\n }\r\n\r\n return token;\r\n }\r\n\r\n public visitForClause(arg: ForClause): SqlPrintToken {\r\n const token = new SqlPrintToken(SqlPrintTokenType.keyword, 'for', SqlPrintTokenContainerType.ForClause);\r\n\r\n token.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN);\r\n token.innerTokens.push(new SqlPrintToken(SqlPrintTokenType.keyword, arg.lockMode));\r\n\r\n return token;\r\n }\r\n\r\n public visitWithClause(arg: WithClause): SqlPrintToken {\r\n const token = new SqlPrintToken(SqlPrintTokenType.keyword, 'with', SqlPrintTokenContainerType.WithClause);\r\n\r\n token.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN);\r\n if (arg.recursive) {\r\n token.innerTokens.push(new SqlPrintToken(SqlPrintTokenType.keyword, 'recursive'));\r\n token.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN);\r\n }\r\n\r\n for (let i = 0; i < arg.tables.length; i++) {\r\n if (i > 0) {\r\n token.innerTokens.push(...SqlPrintTokenParser.commaSpaceTokens());\r\n }\r\n token.innerTokens.push(arg.tables[i].accept(this));\r\n }\r\n\r\n token.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN);\r\n return token;\r\n }\r\n\r\n public visitCommonTable(arg: CommonTable): SqlPrintToken {\r\n const token = new SqlPrintToken(SqlPrintTokenType.container, '', SqlPrintTokenContainerType.CommonTable);\r\n\r\n token.innerTokens.push(arg.aliasExpression.accept(this));\r\n token.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN);\r\n token.innerTokens.push(new SqlPrintToken(SqlPrintTokenType.keyword, 'as'));\r\n token.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN);\r\n\r\n if (arg.materialized !== null) {\r\n if (arg.materialized) {\r\n token.innerTokens.push(new SqlPrintToken(SqlPrintTokenType.keyword, 'materialized'));\r\n } else {\r\n token.innerTokens.push(new SqlPrintToken(SqlPrintTokenType.keyword, 'not materialized'));\r\n }\r\n token.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN);\r\n }\r\n\r\n token.innerTokens.push(SqlPrintTokenParser.PAREN_OPEN_TOKEN);\r\n\r\n const query = new SqlPrintToken(SqlPrintTokenType.container, '', SqlPrintTokenContainerType.SubQuerySource);\r\n query.innerTokens.push(arg.query.accept(this));\r\n\r\n token.innerTokens.push(query);\r\n token.innerTokens.push(SqlPrintTokenParser.PAREN_CLOSE_TOKEN);\r\n\r\n return token;\r\n }\r\n\r\n // query\r\n public visitSimpleQuery(arg: SimpleSelectQuery): SqlPrintToken {\r\n const token = new SqlPrintToken(SqlPrintTokenType.container, '', SqlPrintTokenContainerType.SimpleSelectQuery);\r\n\r\n if (arg.withClause) {\r\n token.innerTokens.push(arg.withClause.accept(this));\r\n }\r\n\r\n token.innerTokens.push(arg.selectClause.accept(this));\r\n\r\n if (!arg.fromClause) {\r\n return token;\r\n }\r\n\r\n token.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN);\r\n token.innerTokens.push(arg.fromClause.accept(this));\r\n\r\n if (arg.whereClause) {\r\n token.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN);\r\n token.innerTokens.push(arg.whereClause.accept(this));\r\n }\r\n\r\n if (arg.groupByClause) {\r\n token.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN);\r\n token.innerTokens.push(arg.groupByClause.accept(this));\r\n }\r\n\r\n if (arg.havingClause) {\r\n token.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN);\r\n token.innerTokens.push(arg.havingClause.accept(this));\r\n }\r\n\r\n if (arg.orderByClause) {\r\n token.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN);\r\n token.innerTokens.push(arg.orderByClause.accept(this));\r\n }\r\n\r\n if (arg.windowClause) {\r\n token.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN);\r\n token.innerTokens.push(arg.windowClause.accept(this));\r\n }\r\n\r\n if (arg.limitClause) {\r\n token.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN);\r\n token.innerTokens.push(arg.limitClause.accept(this));\r\n }\r\n\r\n if (arg.offsetClause) {\r\n token.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN);\r\n token.innerTokens.push(arg.offsetClause.accept(this));\r\n }\r\n\r\n if (arg.fetchClause) {\r\n token.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN);\r\n token.innerTokens.push(arg.fetchClause.accept(this));\r\n }\r\n\r\n if (arg.forClause) {\r\n token.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN);\r\n token.innerTokens.push(arg.forClause.accept(this));\r\n }\r\n\r\n return token;\r\n }\r\n\r\n public visitSubQuerySource(arg: SubQuerySource): SqlPrintToken {\r\n const token = new SqlPrintToken(SqlPrintTokenType.container, '');\r\n\r\n token.innerTokens.push(SqlPrintTokenParser.PAREN_OPEN_TOKEN);\r\n\r\n const subQuery = new SqlPrintToken(SqlPrintTokenType.container, '', SqlPrintTokenContainerType.SubQuerySource);\r\n subQuery.innerTokens.push(arg.query.accept(this));\r\n\r\n token.innerTokens.push(subQuery);\r\n token.innerTokens.push(SqlPrintTokenParser.PAREN_CLOSE_TOKEN);\r\n\r\n return token;\r\n }\r\n\r\n public visitValuesQuery(arg: ValuesQuery): SqlPrintToken {\r\n const token = new SqlPrintToken(SqlPrintTokenType.keyword, 'values', SqlPrintTokenContainerType.ValuesQuery);\r\n token.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN);\r\n\r\n const values = new SqlPrintToken(SqlPrintTokenType.container, '', SqlPrintTokenContainerType.Values);\r\n for (let i = 0; i < arg.tuples.length; i++) {\r\n if (i > 0) {\r\n values.innerTokens.push(...SqlPrintTokenParser.commaSpaceTokens());\r\n }\r\n values.innerTokens.push(arg.tuples[i].accept(this));\r\n }\r\n\r\n token.innerTokens.push(values);\r\n return token;\r\n }\r\n\r\n public visitInlineQuery(arg: InlineQuery): SqlPrintToken {\r\n const token = new SqlPrintToken(SqlPrintTokenType.container, '');\r\n\r\n token.innerTokens.push(SqlPrintTokenParser.PAREN_OPEN_TOKEN);\r\n\r\n const queryToken = new SqlPrintToken(SqlPrintTokenType.container, '', SqlPrintTokenContainerType.InlineQuery);\r\n queryToken.innerTokens.push(arg.selectQuery.accept(this));\r\n\r\n token.innerTokens.push(queryToken);\r\n token.innerTokens.push(SqlPrintTokenParser.PAREN_CLOSE_TOKEN);\r\n\r\n return token;\r\n }\r\n\r\n private visitInsertQuery(arg: InsertQuery): SqlPrintToken {\r\n const token = new SqlPrintToken(SqlPrintTokenType.container, '', SqlPrintTokenContainerType.InsertQuery);\r\n\r\n // Process the insert clause\r\n token.innerTokens.push(this.visit(arg.insertClause));\r\n\r\n // Process the select query if present\r\n if (arg.selectQuery) {\r\n token.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN);\r\n token.innerTokens.push(this.visit(arg.selectQuery));\r\n }\r\n\r\n return token;\r\n }\r\n\r\n private visitInsertClause(arg: InsertClause): SqlPrintToken {\r\n const token = new SqlPrintToken(SqlPrintTokenType.container, '');\r\n\r\n token.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN);\r\n token.innerTokens.push(new SqlPrintToken(SqlPrintTokenType.keyword, 'insert into'));\r\n token.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN);\r\n token.innerTokens.push(arg.source.accept(this));\r\n\r\n if (arg.columns.length > 0) {\r\n token.innerTokens.push(SqlPrintTokenParser.PAREN_OPEN_TOKEN);\r\n for (let i = 0; i < arg.columns.length; i++) {\r\n if (i > 0) {\r\n token.innerTokens.push(...SqlPrintTokenParser.commaSpaceTokens());\r\n }\r\n token.innerTokens.push(arg.columns[i].accept(this));\r\n }\r\n token.innerTokens.push(SqlPrintTokenParser.PAREN_CLOSE_TOKEN);\r\n }\r\n\r\n return token;\r\n }\r\n\r\n private visitUpdateQuery(arg: UpdateQuery): SqlPrintToken {\r\n const token = new SqlPrintToken(SqlPrintTokenType.container, '', SqlPrintTokenContainerType.UpdateQuery);\r\n\r\n if (arg.withClause) {\r\n token.innerTokens.push(arg.withClause.accept(this));\r\n }\r\n\r\n token.innerTokens.push(arg.updateClause.accept(this));\r\n token.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN);\r\n token.innerTokens.push(arg.setClause.accept(this));\r\n\r\n if (arg.fromClause) {\r\n token.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN);\r\n token.innerTokens.push(arg.fromClause.accept(this));\r\n }\r\n\r\n if (arg.whereClause) {\r\n token.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN);\r\n token.innerTokens.push(arg.whereClause.accept(this));\r\n }\r\n\r\n if (arg.returningClause) {\r\n token.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN);\r\n token.innerTokens.push(arg.returningClause.accept(this));\r\n }\r\n\r\n return token;\r\n }\r\n\r\n public visitUpdateClause(arg: UpdateClause): SqlPrintToken {\r\n const token = new SqlPrintToken(SqlPrintTokenType.keyword, 'update', SqlPrintTokenContainerType.UpdateClause);\r\n\r\n token.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN);\r\n token.innerTokens.push(arg.source.accept(this));\r\n\r\n return token;\r\n }\r\n\r\n public visitSetClause(arg: SetClause): SqlPrintToken {\r\n const token = new SqlPrintToken(SqlPrintTokenType.keyword, 'set', SqlPrintTokenContainerType.SelectClause);\r\n\r\n token.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN);\r\n for (let i = 0; i < arg.items.length; i++) {\r\n if (i > 0) {\r\n token.innerTokens.push(...SqlPrintTokenParser.commaSpaceTokens());\r\n }\r\n token.innerTokens.push(this.visit(arg.items[i]));\r\n }\r\n\r\n return token;\r\n }\r\n\r\n public visitSetClauseItem(arg: SetClauseItem): SqlPrintToken {\r\n const token = new SqlPrintToken(SqlPrintTokenType.container, '', SqlPrintTokenContainerType.SetClauseItem);\r\n\r\n token.innerTokens.push(arg.column.accept(this));\r\n token.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN);\r\n token.innerTokens.push(new SqlPrintToken(SqlPrintTokenType.operator, '='));\r\n token.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN);\r\n token.innerTokens.push(arg.value.accept(this));\r\n\r\n return token;\r\n }\r\n\r\n public visitReturningClause(arg: ReturningClause): SqlPrintToken {\r\n const token = new SqlPrintToken(SqlPrintTokenType.keyword, 'returning', SqlPrintTokenContainerType.ReturningClause);\r\n\r\n token.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN);\r\n for (let i = 0; i < arg.columns.length; i++) {\r\n if (i > 0) {\r\n token.innerTokens.push(...SqlPrintTokenParser.commaSpaceTokens());\r\n }\r\n token.innerTokens.push(this.visit(arg.columns[i]));\r\n }\r\n\r\n return token;\r\n }\r\n\r\n public visitCreateTableQuery(arg: CreateTableQuery): SqlPrintToken {\r\n const token = new SqlPrintToken(SqlPrintTokenType.keyword, arg.isTemporary ? 'create temporary table' : 'create table', SqlPrintTokenContainerType.CreateTableQuery);\r\n\r\n token.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN);\r\n token.innerTokens.push(arg.tableName.accept(this));\r\n\r\n if (arg.asSelectQuery) {\r\n token.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN);\r\n token.innerTokens.push(new SqlPrintToken(SqlPrintTokenType.keyword, 'as'));\r\n token.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN);\r\n token.innerTokens.push(arg.asSelectQuery.accept(this));\r\n }\r\n\r\n return token;\r\n }\r\n}\r\n", "// Define the allowed newline options\r\nexport type NewlineOption = ' ' | '\\n' | '\\r\\n';\r\n\r\n// Define the allowed indent character options\r\nexport type IndentCharOption = '' | ' ' | '\\t';\r\n\r\n/**\r\n * SqlPrintHelper provides utility methods for SQL pretty printing.\r\n */\r\nexport class LinePrinter {\r\n indentChar: IndentCharOption; // Changed type to IndentCharOption\r\n indentSize: number;\r\n newline: NewlineOption; // Changed type to NewlineOption\r\n lines: PrintLine[];\r\n /**\r\n * @param indentChar Character used for indentation (default: ' ') // Updated comment to reflect options\r\n * @param indentSize Number of indentChar per level (default: 0)\r\n * @param newline Newline string (default: '\\r\\n') // Changed type and default value\r\n */\r\n constructor(indentChar: IndentCharOption = ' ', indentSize: number = 0, newline: NewlineOption = '\\r\\n') { // Changed type for indentChar\r\n this.indentChar = indentChar;\r\n this.indentSize = indentSize;\r\n this.newline = newline;\r\n this.lines = [];\r\n this.appendNewline(0);\r\n }\r\n\r\n public print(): string {\r\n let result = '';\r\n for (const line of this.lines) {\r\n if (line.text !== '') {\r\n // append indent and text\r\n result += this.indent(line.level) + line.text;\r\n }\r\n }\r\n return result.trimEnd();\r\n }\r\n\r\n /**\r\n * Returns the indent string for a given level.\r\n * @param level Indentation level\r\n */\r\n private indent(level: number): string {\r\n return this.indentChar.repeat(this.indentSize * level);\r\n }\r\n\r\n /**\r\n * Appends a newline token to the given tokens array if newline is set, or adds an empty line if tokens is empty.\r\n * @param tokens Array of token objects with 'level' and 'text' property\r\n * @param level Indentation level\r\n */\r\n appendNewline(level: number): void {\r\n if (this.lines.length > 0) {\r\n const current = this.lines[this.lines.length - 1];\r\n if (current.text !== '') {\r\n current.text = current.text.trimEnd() + this.newline;\r\n }\r\n }\r\n this.lines.push(new PrintLine(level, ''));\r\n }\r\n\r\n /**\r\n * Appends text to the last element of tokens array.\r\n * @param tokens Array of token objects with 'text' property\r\n * @param text Text to append\r\n */\r\n appendText(text: string): void {\r\n if (this.lines.length > 0) {\r\n const workingIndex = this.lines.length - 1;\r\n const workLine = this.lines[workingIndex]\r\n // Leading space is not needed\r\n if (!(text === ' ' && workLine.text === '')) {\r\n workLine.text += text;\r\n }\r\n } else {\r\n throw new Error('No tokens to append to.');\r\n }\r\n }\r\n\r\n getCurrentLine(): PrintLine {\r\n if (this.lines.length > 0) {\r\n return this.lines[this.lines.length - 1];\r\n } else {\r\n throw new Error('No tokens to get current line from.');\r\n }\r\n }\r\n}\r\n\r\nexport class PrintLine {\r\n level: number;\r\n text: string;\r\n\r\n constructor(level: number, text: string) {\r\n this.level = level;\r\n this.text = text;\r\n }\r\n}", "import { SqlPrintToken, SqlPrintTokenType, SqlPrintTokenContainerType } from \"../models/SqlPrintToken\";\r\nimport { IndentCharOption, LinePrinter, NewlineOption } from \"./LinePrinter\";\r\n\r\n/**\r\n * CommaBreakStyle determines how commas are placed in formatted SQL output.\r\n * - 'none': No line break for commas\r\n * - 'before': Line break before comma\r\n * - 'after': Line break after comma\r\n */\r\nexport type CommaBreakStyle = 'none' | 'before' | 'after';\r\n\r\n/**\r\n * AndBreakStyle determines how AND operators are placed in formatted SQL output.\r\n * - 'none': No line break for AND\r\n * - 'before': Line break before AND\r\n * - 'after': Line break after AND\r\n */\r\nexport type AndBreakStyle = 'none' | 'before' | 'after';\r\n\r\n/**\r\n * SqlPrinter formats a SqlPrintToken tree into a SQL string with flexible style options.\r\n */\r\nexport class SqlPrinter {\r\n /** Indent character (e.g., ' ' or '\\\\t') */\r\n indentChar: IndentCharOption; // Changed type from string\r\n /** Indent size (number of indentChar repetitions per level) */\r\n indentSize: number;\r\n /** Newline character (e.g., '\\\\n' or '\\\\r\\\\n') */\r\n newline: NewlineOption; // Changed type from string\r\n /** Comma break style: 'none', 'before', or 'after' */\r\n commaBreak: CommaBreakStyle;\r\n /** AND break style: 'none', 'before', or 'after' */\r\n andBreak: AndBreakStyle;\r\n\r\n /** Keyword case style: 'none', 'upper' | 'lower' */\r\n keywordCase: 'none' | 'upper' | 'lower';\r\n\r\n private linePrinter: LinePrinter;\r\n private indentIncrementContainers: Set<SqlPrintTokenContainerType>;\r\n\r\n /**\r\n * @param options Optional style settings for pretty printing\r\n */\r\n constructor(options?: {\r\n indentChar?: IndentCharOption;\r\n indentSize?: number;\r\n newline?: NewlineOption;\r\n commaBreak?: CommaBreakStyle;\r\n andBreak?: AndBreakStyle;\r\n keywordCase?: 'none' | 'upper' | 'lower';\r\n indentIncrementContainerTypes?: string[]; // Option to customize\r\n }) {\r\n this.indentChar = options?.indentChar ?? '';\r\n this.indentSize = options?.indentSize ?? 0;\r\n\r\n // The default newline character is set to a blank space (' ') to enable one-liner formatting.\r\n // This is intentional and differs from the LinePrinter default of '\\r\\n'.\r\n this.newline = options?.newline ?? ' ';\r\n\r\n this.commaBreak = options?.commaBreak ?? 'none';\r\n this.andBreak = options?.andBreak ?? 'none';\r\n this.keywordCase = options?.keywordCase ?? 'none';\r\n this.linePrinter = new LinePrinter(this.indentChar, this.indentSize, this.newline);\r\n\r\n // Initialize\r\n this.indentIncrementContainers = new Set(\r\n (options?.indentIncrementContainerTypes as SqlPrintTokenContainerType[] | undefined) ?? [\r\n SqlPrintTokenContainerType.SelectClause,\r\n SqlPrintTokenContainerType.FromClause,\r\n SqlPrintTokenContainerType.WhereClause,\r\n SqlPrintTokenContainerType.GroupByClause,\r\n SqlPrintTokenContainerType.HavingClause,\r\n SqlPrintTokenContainerType.WindowFrameExpression,\r\n SqlPrintTokenContainerType.PartitionByClause,\r\n SqlPrintTokenContainerType.OrderByClause,\r\n SqlPrintTokenContainerType.WindowClause,\r\n SqlPrintTokenContainerType.LimitClause,\r\n SqlPrintTokenContainerType.OffsetClause,\r\n SqlPrintTokenContainerType.SubQuerySource,\r\n SqlPrintTokenContainerType.BinarySelectQueryOperator, SqlPrintTokenContainerType.Values,\r\n SqlPrintTokenContainerType.WithClause,\r\n SqlPrintTokenContainerType.SwitchCaseArgument,\r\n SqlPrintTokenContainerType.CaseKeyValuePair,\r\n SqlPrintTokenContainerType.CaseThenValue,\r\n SqlPrintTokenContainerType.ElseClause,\r\n SqlPrintTokenContainerType.CaseElseValue\r\n // CaseExpression, SwitchCaseArgument, CaseKeyValuePair, and ElseClause\r\n // are not included by default to maintain backward compatibility with tests\r\n //SqlPrintTokenContainerType.CommonTable\r\n ]\r\n );\r\n }\r\n\r\n /**\r\n * Converts a SqlPrintToken tree to a formatted SQL string.\r\n * @param token The root SqlPrintToken\r\n * @param level Indentation level (default: 0)\r\n */\r\n print(token: SqlPrintToken, level: number = 0): string {\r\n // initialize\r\n this.linePrinter = new LinePrinter(this.indentChar, this.indentSize, this.newline);\r\n if (this.linePrinter.lines.length > 0 && level !== this.linePrinter.lines[0].level) {\r\n this.linePrinter.lines[0].level = level;\r\n }\r\n\r\n this.appendToken(token, level);\r\n\r\n return this.linePrinter.print();\r\n }\r\n\r\n private appendToken(token: SqlPrintToken, level: number) {\r\n if (!token.innerTokens || token.innerTokens.length === 0) {\r\n if (token.text === '') {\r\n return;\r\n }\r\n }\r\n\r\n const current = this.linePrinter.getCurrentLine();\r\n\r\n if (token.type === SqlPrintTokenType.keyword) {\r\n let text = token.text;\r\n if (this.keywordCase === 'upper') {\r\n text = text.toUpperCase();\r\n } else if (this.keywordCase === 'lower') {\r\n text = text.toLowerCase();\r\n }\r\n this.linePrinter.appendText(text);\r\n } else if (token.type === SqlPrintTokenType.comma) {\r\n let text = token.text;\r\n if (this.commaBreak === 'before') {\r\n this.linePrinter.appendNewline(level);\r\n this.linePrinter.appendText(text);\r\n } else if (this.commaBreak === 'after') {\r\n this.linePrinter.appendText(text);\r\n this.linePrinter.appendNewline(level);\r\n } else {\r\n this.linePrinter.appendText(text);\r\n }\r\n } else if (token.type === SqlPrintTokenType.operator && token.text.toLowerCase() === 'and') {\r\n let text = token.text;\r\n if (this.keywordCase === 'upper') {\r\n text = text.toUpperCase();\r\n } else if (this.keywordCase === 'lower') {\r\n text = text.toLowerCase();\r\n }\r\n\r\n if (this.andBreak === 'before') {\r\n this.linePrinter.appendNewline(level);\r\n this.linePrinter.appendText(text);\r\n } else if (this.andBreak === 'after') {\r\n this.linePrinter.appendText(text);\r\n this.linePrinter.appendNewline(level);\r\n } else {\r\n this.linePrinter.appendText(text);\r\n }\r\n } else if (token.containerType === \"JoinClause\") {\r\n let text = token.text;\r\n if (this.keywordCase === 'upper') {\r\n text = text.toUpperCase();\r\n } else if (this.keywordCase === 'lower') {\r\n text = text.toLowerCase();\r\n }\r\n // before join clause, add newline\r\n this.linePrinter.appendNewline(level);\r\n this.linePrinter.appendText(text);\r\n } else {\r\n this.linePrinter.appendText(token.text);\r\n }\r\n\r\n // append keyword tokens(not indented)\r\n if (token.keywordTokens && token.keywordTokens.length > 0) {\r\n for (let i = 0; i < token.keywordTokens.length; i++) {\r\n const keywordToken = token.keywordTokens[i];\r\n this.appendToken(keywordToken, level);\r\n }\r\n }\r\n\r\n let innerLevel = level;\r\n\r\n // indent level up\r\n if (this.newline !== ' ' && current.text !== '' && this.indentIncrementContainers.has(token.containerType)) { // Changed condition\r\n innerLevel++;\r\n this.linePrinter.appendNewline(innerLevel);\r\n }\r\n\r\n for (let i = 0; i < token.innerTokens.length; i++) {\r\n const child = token.innerTokens[i];\r\n this.appendToken(child, innerLevel);\r\n }\r\n\r\n // indent level down\r\n if (innerLevel !== level) {\r\n this.linePrinter.appendNewline(level);\r\n }\r\n }\r\n}", "import { SqlPrintTokenParser, FormatterConfig, PRESETS } from '../parsers/SqlPrintTokenParser';\r\nimport { SqlPrinter, CommaBreakStyle, AndBreakStyle } from './SqlPrinter';\r\nimport { IndentCharOption, NewlineOption } from './LinePrinter'; // Import types for compatibility\r\nimport { SelectQuery } from '../models/SelectQuery';\r\nimport { SqlComponent } from '../models/SqlComponent';\r\n\r\n// Define valid preset names as a union type\r\nexport const VALID_PRESETS = ['mysql', 'postgres', 'sqlserver', 'sqlite'] as const;\r\nexport type PresetName = (typeof VALID_PRESETS)[number];\r\n\r\n/**\r\n * SqlFormatter class combines parsing and printing of SQL queries into a single interface.\r\n */\r\nexport class SqlFormatter {\r\n private parser: SqlPrintTokenParser;\r\n private printer: SqlPrinter;\r\n\r\n constructor(options: {\r\n preset?: PresetName; // Restrict preset to specific strings\r\n identifierEscape?: { start: string; end: string }; // Allow custom identifier escape\r\n parameterSymbol?: string | { start: string; end: string }; // Allow custom parameter symbol\r\n parameterStyle?: 'anonymous' | 'indexed' | 'named'; // Allow custom parameter style\r\n indentSize?: number;\r\n indentChar?: IndentCharOption; // Updated type\r\n newline?: NewlineOption; // Updated type\r\n keywordCase?: 'none' | 'upper' | 'lower'; // Updated type\r\n commaBreak?: CommaBreakStyle; // Updated type\r\n andBreak?: AndBreakStyle; // Updated type\r\n } = {}) { // Default to 'sqlserver' if options is empty\r\n\r\n const presetConfig = options.preset ? PRESETS[options.preset] : undefined;\r\n\r\n if (options.preset && !presetConfig) {\r\n throw new Error(`Invalid preset: ${options.preset}`); // Throw error for invalid preset\r\n }\r\n\r\n const parserOptions = {\r\n ...presetConfig, // Apply preset configuration\r\n identifierEscape: options.identifierEscape ?? presetConfig?.identifierEscape,\r\n parameterSymbol: options.parameterSymbol ?? presetConfig?.parameterSymbol,\r\n parameterStyle: options.parameterStyle ?? presetConfig?.parameterStyle,\r\n };\r\n\r\n this.parser = new SqlPrintTokenParser(parserOptions);\r\n this.printer = new SqlPrinter(options);\r\n } /**\r\n * Formats a SQL query string with the given parameters.\r\n * @param sqlText The SQL query string to format.\r\n * @param parameters A dictionary of parameters to replace in the query.\r\n * @returns An object containing the formatted SQL string and the parameters.\r\n */\r\n format(sql: SqlComponent): { formattedSql: string; params: any[] | Record<string, any> } {\r\n const { token, params } = this.parser.parse(sql);\r\n const formattedSql = this.printer.print(token);\r\n\r\n return { formattedSql, params };\r\n }\r\n}\r\n", "import { SqlFormatter } from './SqlFormatter';\r\nimport { SelectQuery } from '../models/SelectQuery';\r\nimport { SqlComponent, SqlComponentVisitor } from '../models/SqlComponent';\r\nimport { FormatterConfig } from '../parsers/SqlPrintTokenParser';\r\n\r\n/**\r\n * @deprecated The Formatter class is deprecated. Use SqlFormatter instead.\r\n */\r\nexport class Formatter implements SqlComponentVisitor<string> {\r\n private sqlFormatter: SqlFormatter;\r\n\r\n constructor() {\r\n this.sqlFormatter = new SqlFormatter({\r\n identifierEscape: { start: '\"', end: '\"' },\r\n parameterSymbol: ':',\r\n parameterStyle: 'named' // Default to 'named' for backward compatibility\r\n });\r\n }\r\n\r\n public format(arg: SqlComponent, config: FormatterConfig | null = null): string {\r\n // Use the sqlFormatter instance to format the SQL component\r\n if (config) {\r\n this.sqlFormatter = new SqlFormatter(config);\r\n }\r\n const result = this.sqlFormatter.format(arg);\r\n return result.formattedSql;\r\n }\r\n\r\n public formatWithParameters(arg: SqlComponent, config: FormatterConfig | null = null): { sql: string, params: any[] | Record<string, any>[] | Record<string, any> } {\r\n // Use the sqlFormatter instance to format the SQL component with parameters\r\n if (config) {\r\n this.sqlFormatter = new SqlFormatter(config);\r\n }\r\n const result = this.sqlFormatter.format(arg);\r\n return { sql: result.formattedSql, params: result.params };\r\n }\r\n\r\n public visit(arg: SqlComponent): string {\r\n return this.format(arg);\r\n }\r\n}\r\n\r\nexport { SqlFormatter };", "import { CommonTable, WithClause } from \"../models/Clause\";\r\nimport { CTECollector } from \"./CTECollector\";\r\nimport { TableSourceCollector } from \"./TableSourceCollector\";\r\nimport { Formatter } from \"./Formatter\";\r\n\r\n/**\r\n * CTENameConflictResolver is responsible for resolving name conflicts among Common Table Expressions (CTEs).\r\n * It also sorts the tables in the proper order based on dependencies and recursiveness.\r\n */\r\nexport class CTEBuilder {\r\n private sourceCollector: TableSourceCollector;\r\n private cteCollector: CTECollector;\r\n private formatter: Formatter;\r\n\r\n constructor() {\r\n this.sourceCollector = new TableSourceCollector(true);\r\n this.cteCollector = new CTECollector();\r\n this.formatter = new Formatter();\r\n }\r\n\r\n /**\r\n * Resolves name conflicts among CommonTables.\r\n * If there are duplicate CTE names, they must have identical definitions.\r\n * Also sorts the tables so that:\r\n * 1. Recursive CTEs come first (CTEs that reference themselves)\r\n * 2. Then remaining tables are sorted so inner (deeper) CTEs come before outer CTEs\r\n * \r\n * @param commonTables The list of CommonTables to check for name conflicts\r\n * @returns An object containing:\r\n * - needRecursive: boolean indicating if any recursive CTEs are present\r\n * - commonTables: A new list of CommonTables with resolved name conflicts and proper order\r\n * @throws Error if there are duplicate CTE names with different definitions\r\n */\r\n public build(commonTables: CommonTable[]): WithClause {\r\n // Early return for empty CTEs\r\n // Note:\r\n // Although it may seem reasonable to return early when there is only one element,\r\n // the 'recursive' property is determined dynamically. Therefore, if there is at least one element,\r\n // the CTEs must be rebuilt to ensure correct recursive detection.\r\n if (commonTables.length === 0) {\r\n return new WithClause(\r\n false,\r\n commonTables\r\n );\r\n }\r\n\r\n // Step 1: Resolve name conflicts\r\n const resolvedTables = this.resolveDuplicateNames(commonTables);\r\n\r\n // Step 2: Identify recursive CTEs and build dependency graph\r\n const { tableMap, recursiveCTEs, dependencies } = this.buildDependencyGraph(resolvedTables);\r\n\r\n // Step 3: Sort tables according to dependencies and recursiveness\r\n const sortedTables = this.sortCommonTables(resolvedTables, tableMap, recursiveCTEs, dependencies);\r\n\r\n return new WithClause(\r\n recursiveCTEs.size > 0,\r\n sortedTables\r\n );\r\n }\r\n\r\n /**\r\n * Resolves duplicate CTE names by checking if they have identical definitions.\r\n * If definitions differ, throws an error.\r\n * \r\n * @param commonTables The list of CTEs to check for duplicates\r\n * @returns A list of CTEs with duplicates removed\r\n * @throws Error if there are duplicate CTE names with different definitions\r\n */\r\n private resolveDuplicateNames(commonTables: CommonTable[]): CommonTable[] {\r\n // Group CTEs by their names\r\n const ctesByName = new Map<string, CommonTable[]>();\r\n for (const table of commonTables) {\r\n const tableName = table.aliasExpression.table.name;\r\n if (!ctesByName.has(tableName)) {\r\n ctesByName.set(tableName, []);\r\n }\r\n ctesByName.get(tableName)!.push(table);\r\n }\r\n\r\n // Resolve name duplications\r\n const resolvedTables: CommonTable[] = [];\r\n for (const [name, tables] of ctesByName.entries()) {\r\n if (tables.length === 1) {\r\n // No duplication\r\n resolvedTables.push(tables[0]);\r\n continue;\r\n }\r\n\r\n // For duplicate names, check if definitions are identical\r\n const definitions = tables.map(table => this.formatter.format(table.query));\r\n const uniqueDefinitions = new Set(definitions);\r\n\r\n if (uniqueDefinitions.size === 1) {\r\n // If all definitions are identical, use only the first one\r\n resolvedTables.push(tables[0]);\r\n } else {\r\n // Error if definitions differ\r\n throw new Error(`CTE name conflict detected: '${name}' has multiple different definitions`);\r\n }\r\n }\r\n\r\n return resolvedTables;\r\n }\r\n\r\n /**\r\n * Builds a dependency graph of CTEs and identifies recursive CTEs.\r\n * \r\n * @param tables The list of CTEs to analyze\r\n * @returns Object containing the table map, set of recursive CTEs, and dependency map\r\n */\r\n private buildDependencyGraph(tables: CommonTable[]): {\r\n tableMap: Map<string, CommonTable>,\r\n recursiveCTEs: Set<string>,\r\n dependencies: Map<string, Set<string>>\r\n } {\r\n // Create a map of table names for quick lookup\r\n const tableMap = new Map<string, CommonTable>();\r\n for (const table of tables) {\r\n tableMap.set(table.aliasExpression.table.name, table);\r\n }\r\n\r\n // Identify recursive CTEs (those that reference themselves)\r\n const recursiveCTEs = new Set<string>();\r\n\r\n // Build dependency graph: which tables reference which other tables\r\n const dependencies = new Map<string, Set<string>>();\r\n const referencedBy = new Map<string, Set<string>>();\r\n\r\n for (const table of tables) {\r\n const tableName = table.aliasExpression.table.name;\r\n\r\n // Check for self-references (recursive CTEs)\r\n const referencedTables = this.sourceCollector.collect(table.query);\r\n\r\n // Check if this CTE references itself\r\n for (const referencedTable of referencedTables) {\r\n if (referencedTable.table.name === tableName) {\r\n recursiveCTEs.add(tableName);\r\n break;\r\n }\r\n }\r\n\r\n // Setup dependencies\r\n if (!dependencies.has(tableName)) {\r\n dependencies.set(tableName, new Set<string>());\r\n }\r\n\r\n // Find any references to other CTEs in this table's query\r\n const referencedCTEs = this.cteCollector.collect(table.query);\r\n\r\n for (const referencedCTE of referencedCTEs) {\r\n const referencedName = referencedCTE.aliasExpression.table.name;\r\n\r\n // Only consider references to tables in our collection\r\n if (tableMap.has(referencedName)) {\r\n dependencies.get(tableName)!.add(referencedName);\r\n\r\n // Add the reverse relationship\r\n if (!referencedBy.has(referencedName)) {\r\n referencedBy.set(referencedName, new Set<string>());\r\n }\r\n referencedBy.get(referencedName)!.add(tableName);\r\n }\r\n }\r\n }\r\n\r\n return { tableMap, recursiveCTEs, dependencies };\r\n }\r\n\r\n /**\r\n * Sorts the CTEs using topological sort, with recursive CTEs coming first.\r\n * \r\n * @param tables The list of CTEs to sort\r\n * @param tableMap Map of table names to their CommonTable objects\r\n * @param recursiveCTEs Set of table names that are recursive (self-referential)\r\n * @param dependencies Map of table dependencies\r\n * @returns Sorted list of CTEs\r\n * @throws Error if a circular reference is detected\r\n */\r\n private sortCommonTables(\r\n tables: CommonTable[],\r\n tableMap: Map<string, CommonTable>,\r\n recursiveCTEs: Set<string>,\r\n dependencies: Map<string, Set<string>>\r\n ): CommonTable[] {\r\n const recursiveResult: CommonTable[] = [];\r\n const nonRecursiveResult: CommonTable[] = [];\r\n const visited = new Set<string>();\r\n const visiting = new Set<string>();\r\n\r\n // Topological sort function\r\n const visit = (tableName: string) => {\r\n if (visited.has(tableName)) return;\r\n if (visiting.has(tableName)) {\r\n throw new Error(`Circular reference detected in CTE: ${tableName}`);\r\n }\r\n\r\n visiting.add(tableName);\r\n\r\n // Process dependencies first (inner CTEs)\r\n const deps = dependencies.get(tableName) || new Set<string>();\r\n for (const dep of deps) {\r\n visit(dep);\r\n }\r\n\r\n visiting.delete(tableName);\r\n visited.add(tableName);\r\n\r\n // Add this table after its dependencies\r\n // Recursive CTEs go to recursiveResult, others to nonRecursiveResult\r\n if (recursiveCTEs.has(tableName)) {\r\n recursiveResult.push(tableMap.get(tableName)!);\r\n } else {\r\n nonRecursiveResult.push(tableMap.get(tableName)!);\r\n }\r\n };\r\n\r\n // Process all tables\r\n for (const table of tables) {\r\n const tableName = table.aliasExpression.table.name;\r\n if (!visited.has(tableName)) {\r\n visit(tableName);\r\n }\r\n }\r\n\r\n // Combine the results: recursive CTEs first, then non-recursive CTEs\r\n return [...recursiveResult, ...nonRecursiveResult];\r\n }\r\n}\r\n", "import { CommonTable, WithClause } from \"../models/Clause\";\r\nimport { BinarySelectQuery, SelectQuery, SimpleSelectQuery, ValuesQuery } from \"../models/SelectQuery\";\r\nimport { CTECollector } from \"./CTECollector\";\r\nimport { CTEBuilder } from \"./CTEBuilder\";\r\n\r\n/**\r\n * CTEInjector accepts a SelectQuery object and an array of CommonTables,\r\n * and inserts Common Table Expressions into the query.\r\n * For BinarySelectQuery, CTEs are inserted into the left query.\r\n * \r\n * Uses CTENameConflictResolver to resolve naming conflicts between CTEs.\r\n */\r\nexport class CTEInjector {\r\n private nameConflictResolver: CTEBuilder;\r\n private cteCollector: CTECollector;\r\n\r\n constructor() {\r\n this.nameConflictResolver = new CTEBuilder();\r\n this.cteCollector = new CTECollector();\r\n }\r\n\r\n /**\r\n * Inserts Common Table Expressions into a SelectQuery object.\r\n * \r\n * @param query The query to inject CTEs into\r\n * @param commonTables Array of CommonTables to be inserted\r\n * @returns A new query with the injected CTEs\r\n */\r\n public inject(query: SelectQuery, commonTables: CommonTable[]): SelectQuery {\r\n // If the array is empty, return the query as is\r\n if (commonTables.length === 0) {\r\n return query;\r\n }\r\n\r\n // Collect CTEs from the query\r\n commonTables.push(...this.cteCollector.collect(query));\r\n\r\n // Use CTENameConflictResolver to resolve duplicates and sort in appropriate order\r\n const resolvedWithCaluse = this.nameConflictResolver.build(commonTables);\r\n\r\n // Process based on query type\r\n if (query instanceof SimpleSelectQuery) {\r\n return this.injectIntoSimpleQuery(query, resolvedWithCaluse);\r\n } else if (query instanceof BinarySelectQuery) {\r\n return this.injectIntoBinaryQuery(query, resolvedWithCaluse);\r\n }\r\n\r\n // Unsupported query type\r\n throw new Error(\"Unsupported query type\");\r\n }\r\n\r\n /**\r\n * Inserts Common Table Expressions into a SimpleSelectQuery.\r\n * \r\n * @param query The SimpleSelectQuery to inject CTEs into\r\n * @param commonTables Array of CommonTables to be inserted\r\n * @param needRecursive Boolean indicating if recursive WITH clause is needed\r\n * @returns A new SimpleSelectQuery with the injected CTEs\r\n */\r\n private injectIntoSimpleQuery(query: SimpleSelectQuery, withClause: WithClause): SimpleSelectQuery {\r\n if (query.withClause) {\r\n throw new Error(\"The query already has a WITH clause. Please remove it before injecting new CTEs.\");\r\n }\r\n // If the query doesn't have a WITH clause, set the new one\r\n query.withClause = withClause;\r\n return query;\r\n }\r\n\r\n /**\r\n * Inserts Common Table Expressions into the left query of a BinarySelectQuery.\r\n * \r\n * @param query The BinarySelectQuery to inject CTEs into\r\n * @param commonTables Array of CommonTables to be inserted\r\n * @param needRecursive Boolean indicating if recursive WITH clause is needed\r\n * @returns A new BinarySelectQuery with the injected CTEs\r\n */\r\n private injectIntoBinaryQuery(query: BinarySelectQuery, withClause: WithClause): BinarySelectQuery {\r\n // Insert CTEs into the left query\r\n if (query.left instanceof SimpleSelectQuery) {\r\n this.injectIntoSimpleQuery(query.left, withClause);\r\n return query;\r\n } else if (query.left instanceof BinarySelectQuery) {\r\n this.injectIntoBinaryQuery(query.left, withClause);\r\n return query;\r\n }\r\n throw new Error(\"Unsupported query type for BinarySelectQuery left side\");\r\n }\r\n}\r\n", "import { CommonTable, WithClause } from \"../models/Clause\";\r\nimport { BinarySelectQuery, SelectQuery, SimpleSelectQuery, ValuesQuery } from \"../models/SelectQuery\";\r\nimport { CTECollector } from \"./CTECollector\";\r\nimport { TableSourceCollector } from \"./TableSourceCollector\";\r\nimport { CTEDisabler } from \"./CTEDisabler\";\r\nimport { Formatter } from \"./Formatter\";\r\nimport { CTEBuilder } from \"./CTEBuilder\";\r\nimport { CTEInjector } from \"./CTEInjector\";\r\n\r\n/**\r\n * CTENormalizer is responsible for normalizing Common Table Expressions (CTEs) within SQL queries.\r\n * It collects all CTEs from various parts of the query and consolidates them into a single WITH clause\r\n * at the root level of the query.\r\n * \r\n * This implementation uses:\r\n * 1. CommonTableCollector - to gather all CTEs from the query structure\r\n * 2. WithClauseDisabler - to remove all original WITH clauses from the query\r\n * 3. CTENameConflictResolver - to resolve name conflicts among CTEs and sort them properly\r\n */\r\nexport class CTENormalizer {\r\n /**\r\n * Private constructor to prevent instantiation of this utility class.\r\n */\r\n private constructor() {\r\n // This class is not meant to be instantiated.\r\n }\r\n /**\r\n * Normalizes a SQL query by consolidating all CTEs into a single WITH clause\r\n * at the root level of the query.\r\n * \r\n * @param query The query to normalize\r\n * @returns A new normalized query with all CTEs at the root level\r\n */\r\n public static normalize(query: SelectQuery): SelectQuery {\r\n // No need to normalize if the query doesn't have any CTEs\r\n const cteCollector = new CTECollector();\r\n const allCommonTables = cteCollector.collect(query);\r\n\r\n if (allCommonTables.length === 0) {\r\n return query;\r\n }\r\n\r\n // Remove all WITH clauses from the original query\r\n const cteDisabler = new CTEDisabler();\r\n cteDisabler.execute(query);\r\n\r\n const injector = new CTEInjector();\r\n return injector.inject(query, allCommonTables);\r\n }\r\n}", "/**\r\n * Enum for duplicate detection modes in SelectableColumnCollector.\r\n * Determines how duplicates are identified during column collection.\r\n */\r\nexport enum DuplicateDetectionMode {\r\n /**\r\n * Detect duplicates based only on column names.\r\n * This mode ignores the table name, so columns with the same name\r\n * from different tables are considered duplicates.\r\n */\r\n ColumnNameOnly = 'columnNameOnly',\r\n /**\r\n * Detect duplicates based on both table and column names.\r\n * This mode ensures that columns with the same name from different\r\n * tables are treated as distinct.\r\n */\r\n FullName = 'fullName',\r\n}\r\nimport { CommonTable, ForClause, FromClause, GroupByClause, HavingClause, LimitClause, OrderByClause, SelectClause, WhereClause, WindowFrameClause, WindowsClause, JoinClause, JoinOnClause, JoinUsingClause, TableSource, SubQuerySource, SourceExpression, SelectItem, PartitionByClause, FetchClause, OffsetClause } from \"../models/Clause\";\r\nimport { SimpleSelectQuery, BinarySelectQuery } from \"../models/SelectQuery\";\r\nimport { SqlComponent, SqlComponentVisitor } from \"../models/SqlComponent\";\r\nimport { ArrayExpression, ArrayQueryExpression, BetweenExpression, BinaryExpression, CaseExpression, CastExpression, ColumnReference, FunctionCall, InlineQuery, ParenExpression, UnaryExpression, ValueComponent, ValueList, WindowFrameExpression } from \"../models/ValueComponent\";\r\nimport { CTECollector } from \"./CTECollector\";\r\nimport { SelectValueCollector } from \"./SelectValueCollector\";\r\nimport { TableColumnResolver } from \"./TableColumnResolver\";\r\n\r\n/**\r\n * A visitor that collects all ColumnReference instances from SimpleSelectQuery structures.\r\n * This visitor scans through all clauses and collects all unique ColumnReference objects.\r\n * It does not scan Common Table Expressions (CTEs) or subqueries.\r\n * \r\n * IMPORTANT: This collector only supports SimpleSelectQuery. BinarySelectQuery \r\n * (UNION/INTERSECT/EXCEPT) will throw an error and should be decomposed into \r\n * individual SimpleSelectQuery branches before using this collector.\r\n * \r\n * Behavioral notes:\r\n * - Only collects column references to tables defined in the root FROM/JOIN clauses\r\n * - For aliased columns (e.g., 'title as name'), collects both the original column \r\n * reference ('title') AND the alias ('name') to enable complete dependency tracking\r\n * \r\n * Use cases:\r\n * - Dependency analysis and schema migration tools\r\n * - Column usage tracking within individual SELECT branches\r\n * - Security analysis for column-level access control\r\n */\r\nexport class SelectableColumnCollector implements SqlComponentVisitor<void> {\r\n private handlers: Map<symbol, (arg: any) => void>;\r\n private selectValues: { name: string, value: ValueComponent }[] = [];\r\n private visitedNodes: Set<SqlComponent> = new Set();\r\n private isRootVisit: boolean = true;\r\n private tableColumnResolver: TableColumnResolver | null = null;\r\n private commonTableCollector: CTECollector;\r\n private commonTables: CommonTable[] = [];\r\n private includeWildCard: boolean; // This option controls whether wildcard columns are included in the collection.\r\n private duplicateDetection: DuplicateDetectionMode;\r\n private options: { ignoreCaseAndUnderscore?: boolean };\r\n\r\n /**\r\n * Creates a new instance of SelectableColumnCollector.\r\n *\r\n * @param {TableColumnResolver | null} [tableColumnResolver=null] - The resolver used to resolve column references to their respective tables.\r\n * @param {boolean} [includeWildCard=false] - If true, wildcard columns (e.g., `*`) are included in the collection.\r\n * @param {DuplicateDetectionMode} [duplicateDetection=DuplicateDetectionMode.ColumnNameOnly] - Specifies the duplicate detection mode: 'columnNameOnly' (default, only column name is used), or 'fullName' (table name + column name).\r\n * @param {Object} [options={}] - Additional options for the collector.\r\n * @param {boolean} [options.ignoreCaseAndUnderscore=false] - If true, column names are compared without considering case and underscores.\r\n */\r\n constructor(\r\n tableColumnResolver?: TableColumnResolver | null,\r\n includeWildCard: boolean = false,\r\n duplicateDetection: DuplicateDetectionMode = DuplicateDetectionMode.ColumnNameOnly,\r\n options?: { ignoreCaseAndUnderscore?: boolean }\r\n ) {\r\n this.tableColumnResolver = tableColumnResolver ?? null;\r\n this.includeWildCard = includeWildCard;\r\n this.commonTableCollector = new CTECollector();\r\n this.commonTables = [];\r\n this.duplicateDetection = duplicateDetection;\r\n this.options = options || {};\r\n this.handlers = new Map<symbol, (arg: any) => void>();\r\n\r\n // Main entry point for SimpleSelectQuery only\r\n this.handlers.set(SimpleSelectQuery.kind, (expr) => this.visitSimpleSelectQuery(expr as SimpleSelectQuery));\r\n // NOTE: BinarySelectQuery is NOT supported - it should be decomposed before using this collector\r\n\r\n // Handlers for each clause type that might contain column references\r\n this.handlers.set(SelectClause.kind, (expr) => this.visitSelectClause(expr as SelectClause));\r\n this.handlers.set(FromClause.kind, (expr) => this.visitFromClause(expr as FromClause));\r\n this.handlers.set(WhereClause.kind, (expr) => this.visitWhereClause(expr as WhereClause));\r\n this.handlers.set(GroupByClause.kind, (expr) => this.visitGroupByClause(expr as GroupByClause));\r\n this.handlers.set(HavingClause.kind, (expr) => this.visitHavingClause(expr as HavingClause));\r\n this.handlers.set(OrderByClause.kind, (expr) => this.visitOrderByClause(expr as OrderByClause));\r\n this.handlers.set(WindowFrameClause.kind, (expr) => this.visitWindowFrameClause(expr as WindowFrameClause));\r\n this.handlers.set(LimitClause.kind, (expr) => this.visitLimitClause(expr as LimitClause));\r\n this.handlers.set(OffsetClause.kind, (expr) => this.offsetClause(expr as OffsetClause));\r\n this.handlers.set(FetchClause.kind, (expr) => this.visitFetchClause(expr as FetchClause));\r\n\r\n // Add handlers for JOIN conditions\r\n this.handlers.set(JoinOnClause.kind, (expr) => this.visitJoinOnClause(expr as JoinOnClause));\r\n this.handlers.set(JoinUsingClause.kind, (expr) => this.visitJoinUsingClause(expr as JoinUsingClause));\r\n\r\n // For value components that might contain column references\r\n this.handlers.set(ColumnReference.kind, (expr) => this.visitColumnReference(expr as ColumnReference));\r\n this.handlers.set(BinaryExpression.kind, (expr) => this.visitBinaryExpression(expr as BinaryExpression));\r\n this.handlers.set(UnaryExpression.kind, (expr) => this.visitUnaryExpression(expr as UnaryExpression));\r\n this.handlers.set(FunctionCall.kind, (expr) => this.visitFunctionCall(expr as FunctionCall));\r\n this.handlers.set(ParenExpression.kind, (expr) => this.visitParenExpression(expr as ParenExpression));\r\n this.handlers.set(CaseExpression.kind, (expr) => this.visitCaseExpression(expr as CaseExpression));\r\n this.handlers.set(CastExpression.kind, (expr) => this.visitCastExpression(expr as CastExpression));\r\n this.handlers.set(BetweenExpression.kind, (expr) => this.visitBetweenExpression(expr as BetweenExpression));\r\n this.handlers.set(ArrayExpression.kind, (expr) => this.visitArrayExpression(expr as ArrayExpression));\r\n this.handlers.set(ArrayQueryExpression.kind, (expr) => this.visitArrayQueryExpression(expr as ArrayQueryExpression));\r\n this.handlers.set(ValueList.kind, (expr) => this.visitValueList(expr as ValueList));\r\n this.handlers.set(WindowFrameClause.kind, (expr) => this.visitWindowFrameClause(expr as WindowFrameClause));\r\n this.handlers.set(WindowFrameExpression.kind, (expr) => this.visitWindowFrameExpression(expr as WindowFrameExpression));\r\n this.handlers.set(PartitionByClause.kind, (expr) => this.visitPartitionByClause(expr as PartitionByClause));\r\n }\r\n\r\n public getValues(): { name: string, value: ValueComponent }[] {\r\n return this.selectValues;\r\n }\r\n\r\n public collect(arg: SqlComponent): { name: string, value: ValueComponent }[] {\r\n // Visit the component and return the collected select items\r\n this.visit(arg);\r\n const items = this.getValues();\r\n this.reset(); // Reset after collection\r\n return items;\r\n }\r\n\r\n /**\r\n * Reset the collection of ColumnReferences\r\n */\r\n private reset(): void {\r\n this.selectValues = []\r\n this.visitedNodes.clear();\r\n this.commonTables = [];\r\n }\r\n\r\n /**\r\n * Add a select value as unique, according to the duplicate detection option.\r\n * If duplicateDetection is 'columnNameOnly', only column name is checked.\r\n * If duplicateDetection is 'fullName', both table and column name are checked.\r\n */\r\n private addSelectValueAsUnique(name: string, value: ValueComponent): void {\r\n if (this.duplicateDetection === DuplicateDetectionMode.ColumnNameOnly) {\r\n if (!this.selectValues.some(item => item.name === name)) {\r\n this.selectValues.push({ name, value });\r\n }\r\n } else if (this.duplicateDetection === DuplicateDetectionMode.FullName) {\r\n // Try to get table name from ValueComponent if possible\r\n let tableName = '';\r\n if (value && typeof (value as any).getNamespace === 'function') {\r\n tableName = (value as any).getNamespace() || '';\r\n }\r\n const key = tableName ? tableName + '.' + name : name;\r\n if (!this.selectValues.some(item => {\r\n let itemTable = '';\r\n if (item.value && typeof (item.value as any).getNamespace === 'function') {\r\n itemTable = (item.value as any).getNamespace() || '';\r\n }\r\n const itemKey = itemTable ? itemTable + '.' + item.name : item.name;\r\n return itemKey === key;\r\n })) {\r\n this.selectValues.push({ name, value });\r\n }\r\n }\r\n }\r\n\r\n /**\r\n * Main entry point for the visitor pattern.\r\n * Implements the shallow visit pattern to distinguish between root and recursive visits.\r\n */\r\n public visit(arg: SqlComponent): void {\r\n // If not a root visit, just visit the node and return\r\n if (!this.isRootVisit) {\r\n this.visitNode(arg);\r\n return;\r\n }\r\n\r\n if (!(arg instanceof SimpleSelectQuery)) {\r\n throw new Error(\"Root visit requires a SimpleSelectQuery. Decompose compound queries before collecting columns.\");\r\n }\r\n\r\n // If this is a root visit, we need to reset the state\r\n this.reset();\r\n this.isRootVisit = false;\r\n this.commonTables = this.commonTableCollector.collect(arg);\r\n\r\n try {\r\n this.visitNode(arg);\r\n } finally {\r\n // Regardless of success or failure, reset the root visit flag\r\n this.isRootVisit = true;\r\n }\r\n }\r\n\r\n /**\r\n * Internal visit method used for all nodes.\r\n * This separates the visit flag management from the actual node visitation logic.\r\n */\r\n private visitNode(arg: SqlComponent): void {\r\n // Skip if we've already visited this node to prevent infinite recursion\r\n if (this.visitedNodes.has(arg)) {\r\n return;\r\n }\r\n\r\n // Mark as visited\r\n this.visitedNodes.add(arg);\r\n\r\n const handler = this.handlers.get(arg.getKind());\r\n if (handler) {\r\n handler(arg);\r\n return;\r\n }\r\n\r\n // For any other component types, we don't need to do anything\r\n }\r\n\r\n /**\r\n * Process a SimpleSelectQuery to collect ColumnReferences from all its clauses\r\n */\r\n private visitSimpleSelectQuery(query: SimpleSelectQuery): void {\r\n // Visit all clauses that might contain column references\r\n if (query.selectClause) {\r\n query.selectClause.accept(this);\r\n }\r\n\r\n if (query.fromClause) {\r\n query.fromClause.accept(this);\r\n }\r\n\r\n if (query.whereClause) {\r\n query.whereClause.accept(this);\r\n }\r\n\r\n if (query.groupByClause) {\r\n query.groupByClause.accept(this);\r\n }\r\n\r\n if (query.havingClause) {\r\n query.havingClause.accept(this);\r\n }\r\n\r\n if (query.windowClause) {\r\n for (const win of query.windowClause.windows) {\r\n win.accept(this);\r\n }\r\n }\r\n\r\n if (query.orderByClause) {\r\n query.orderByClause.accept(this);\r\n }\r\n\r\n if (query.limitClause) {\r\n query.limitClause.accept(this);\r\n }\r\n\r\n if (query.offsetClause) {\r\n query.offsetClause.accept(this);\r\n }\r\n\r\n if (query.fetchClause) {\r\n query.fetchClause.accept(this);\r\n }\r\n if (query.forClause) {\r\n query.forClause.accept(this);\r\n }\r\n // Explicitly NOT processing query.WithClause to avoid scanning CTEs\r\n }\r\n\r\n // Clause handlers\r\n private visitSelectClause(clause: SelectClause): void {\r\n for (const item of clause.items) {\r\n if (item.identifier) {\r\n this.addSelectValueAsUnique(item.identifier.name, item.value);\r\n }\r\n item.value.accept(this);\r\n }\r\n }\r\n\r\n private visitFromClause(clause: FromClause): void {\r\n // import source values\r\n const collector = new SelectValueCollector(this.tableColumnResolver, this.commonTables);\r\n const sourceValues = collector.collect(clause);\r\n for (const item of sourceValues) {\r\n // Add the select value as unique to avoid duplicates\r\n this.addSelectValueAsUnique(item.name, item.value);\r\n }\r\n\r\n if (clause.joins) {\r\n for (const join of clause.joins) {\r\n if (join.condition) {\r\n join.condition.accept(this);\r\n }\r\n }\r\n }\r\n }\r\n\r\n private visitWhereClause(clause: WhereClause): void {\r\n if (clause.condition) {\r\n clause.condition.accept(this);\r\n }\r\n }\r\n\r\n private visitGroupByClause(clause: GroupByClause): void {\r\n if (clause.grouping) {\r\n for (const item of clause.grouping) {\r\n item.accept(this);\r\n }\r\n }\r\n }\r\n\r\n private visitHavingClause(clause: HavingClause): void {\r\n if (clause.condition) {\r\n clause.condition.accept(this);\r\n }\r\n }\r\n\r\n private visitOrderByClause(clause: OrderByClause): void {\r\n if (clause.order) {\r\n for (const item of clause.order) {\r\n item.accept(this);\r\n }\r\n }\r\n }\r\n\r\n private visitWindowFrameClause(clause: WindowFrameClause): void {\r\n clause.expression.accept(this);\r\n }\r\n\r\n private visitWindowFrameExpression(expr: WindowFrameExpression): void {\r\n if (expr.partition) {\r\n expr.partition.accept(this);\r\n }\r\n if (expr.order) {\r\n expr.order.accept(this);\r\n }\r\n if (expr.frameSpec) {\r\n expr.frameSpec.accept(this);\r\n }\r\n }\r\n\r\n private visitLimitClause(clause: LimitClause): void {\r\n if (clause.value) {\r\n clause.value.accept(this);\r\n }\r\n }\r\n\r\n private offsetClause(clause: OffsetClause): void {\r\n if (clause.value) {\r\n clause.value.accept(this);\r\n }\r\n }\r\n\r\n private visitFetchClause(clause: FetchClause): void {\r\n if (clause.expression) {\r\n clause.expression.accept(this);\r\n }\r\n }\r\n\r\n private visitJoinOnClause(joinOnClause: JoinOnClause): void {\r\n // Visit the join condition\r\n if (joinOnClause.condition) {\r\n joinOnClause.condition.accept(this);\r\n }\r\n }\r\n\r\n private visitJoinUsingClause(joinUsingClause: JoinUsingClause): void {\r\n // Visit the columns in the USING clause\r\n if (joinUsingClause.condition) {\r\n joinUsingClause.condition.accept(this);\r\n }\r\n }\r\n\r\n // Value component handlers\r\n private visitColumnReference(columnRef: ColumnReference): void {\r\n if (columnRef.column.name !== \"*\") {\r\n this.addSelectValueAsUnique(columnRef.column.name, columnRef);\r\n } else if (!this.includeWildCard) {\r\n return;\r\n } else {\r\n this.addSelectValueAsUnique(columnRef.column.name, columnRef);\r\n }\r\n }\r\n\r\n private visitBinaryExpression(expr: BinaryExpression): void {\r\n // Visit both sides of the expression\r\n if (expr.left) {\r\n expr.left.accept(this);\r\n }\r\n if (expr.right) {\r\n expr.right.accept(this);\r\n }\r\n }\r\n\r\n private visitUnaryExpression(expr: UnaryExpression): void {\r\n if (expr.expression) {\r\n expr.expression.accept(this);\r\n }\r\n }\r\n\r\n private visitFunctionCall(func: FunctionCall): void {\r\n if (func.argument) {\r\n func.argument.accept(this);\r\n }\r\n if (func.over) {\r\n func.over.accept(this);\r\n }\r\n }\r\n\r\n private visitParenExpression(expr: ParenExpression): void {\r\n if (expr.expression) {\r\n expr.expression.accept(this);\r\n }\r\n }\r\n\r\n private visitCaseExpression(expr: CaseExpression): void {\r\n if (expr.condition) {\r\n expr.condition.accept(this);\r\n }\r\n\r\n if (expr.switchCase) {\r\n expr.switchCase.accept(this);\r\n }\r\n }\r\n\r\n private visitCastExpression(expr: CastExpression): void {\r\n if (expr.input) {\r\n expr.input.accept(this);\r\n }\r\n }\r\n\r\n private visitBetweenExpression(expr: BetweenExpression): void {\r\n if (expr.expression) {\r\n expr.expression.accept(this);\r\n }\r\n\r\n if (expr.lower) {\r\n expr.lower.accept(this);\r\n }\r\n\r\n if (expr.upper) {\r\n expr.upper.accept(this);\r\n }\r\n }\r\n\r\n private visitArrayExpression(expr: ArrayExpression): void {\r\n if (expr.expression) {\r\n expr.expression.accept(this);\r\n }\r\n }\r\n\r\n private visitArrayQueryExpression(expr: ArrayQueryExpression): void {\r\n expr.query.accept(this);\r\n }\r\n\r\n private visitValueList(expr: ValueList): void {\r\n if (expr.values) {\r\n for (const value of expr.values) {\r\n value.accept(this);\r\n }\r\n }\r\n }\r\n\r\n private visitPartitionByClause(clause: PartitionByClause): void {\r\n clause.value.accept(this);\r\n }\r\n}", "import { FullNameParser } from \"./FullNameParser\";\r\nimport { FunctionSource, SourceComponent, SubQuerySource, TableSource } from \"../models/Clause\";\r\nimport { Lexeme, TokenType } from \"../models/Lexeme\";\r\nimport { SelectQueryParser } from \"./SelectQueryParser\";\r\nimport { SqlTokenizer } from \"./SqlTokenizer\";\r\nimport { ValueParser } from \"./ValueParser\";\r\n\r\nexport class SourceParser {\r\n // Parse SQL string to AST (was: parse)\r\n public static parse(query: string): SourceComponent {\r\n const tokenizer = new SqlTokenizer(query); // Initialize tokenizer\r\n const lexemes = tokenizer.readLexmes(); // Get tokens\r\n\r\n // Parse\r\n const result = this.parseFromLexeme(lexemes, 0);\r\n\r\n // Error if there are remaining tokens\r\n if (result.newIndex < lexemes.length) {\r\n throw new Error(`Syntax error: Unexpected token \"${lexemes[result.newIndex].value}\" at position ${result.newIndex}. The source component is complete but there are additional tokens.`);\r\n }\r\n\r\n return result.value;\r\n }\r\n\r\n /**\r\n * Parses only a TableSource from the given lexemes, regardless of the presence of parentheses after the identifier.\r\n * This method is specifically used for cases like INSERT queries (e.g., \"insert into table_name (col1, col2)\")\r\n * where a parenthesis immediately following the table name could otherwise be misinterpreted as a function call.\r\n * By using this method, the parser forcibly treats the source as a TableSource.\r\n *\r\n * @param lexemes The array of lexemes to parse.\r\n * @param index The starting index in the lexeme array.\r\n * @returns An object containing the parsed TableSource and the new index.\r\n */\r\n public static parseTableSourceFromLexemes(lexemes: Lexeme[], index: number): { value: SourceComponent; newIndex: number } {\r\n const fullNameResult = FullNameParser.parseFromLexeme(lexemes, index);\r\n return this.parseTableSource(fullNameResult);\r\n }\r\n\r\n // Parse from lexeme array (was: parse)\r\n public static parseFromLexeme(lexemes: Lexeme[], index: number): { value: SourceComponent; newIndex: number } {\r\n let idx = index;\r\n\r\n // Handle subquery\r\n if (idx < lexemes.length && (lexemes[idx].type & TokenType.OpenParen)) {\r\n return this.parseParenSource(lexemes, idx);\r\n }\r\n\r\n // Retrieve the full name only once and reuse the result\r\n const fullNameResult = FullNameParser.parseFromLexeme(lexemes, idx);\r\n\r\n // Handle function-based source (determine by lastTokenType)\r\n if (fullNameResult.lastTokenType & TokenType.Function) {\r\n // Also use fullNameResult as argument for parseFunctionSource\r\n return SourceParser.parseFunctionSource(lexemes, fullNameResult);\r\n }\r\n\r\n // Handle table source (regular table, potentially schema-qualified)\r\n return SourceParser.parseTableSource(fullNameResult);\r\n }\r\n\r\n private static parseTableSource(fullNameResult: { namespaces: string[] | null, name: any, newIndex: number }): { value: TableSource; newIndex: number } {\r\n const { namespaces, name, newIndex } = fullNameResult;\r\n const value = new TableSource(namespaces, name.name);\r\n return { value, newIndex };\r\n }\r\n\r\n private static parseFunctionSource(\r\n lexemes: Lexeme[],\r\n fullNameResult: { namespaces: string[] | null, name: any, newIndex: number }\r\n ): { value: FunctionSource; newIndex: number } {\r\n let idx = fullNameResult.newIndex;\r\n const { namespaces, name } = fullNameResult;\r\n\r\n const argument = ValueParser.parseArgument(TokenType.OpenParen, TokenType.CloseParen, lexemes, idx);\r\n idx = argument.newIndex;\r\n\r\n const functionName = name.name;\r\n const result = new FunctionSource({ namespaces: namespaces, name: functionName }, argument.value);\r\n return { value: result, newIndex: idx };\r\n }\r\n\r\n private static parseParenSource(lexemes: Lexeme[], index: number): { value: SourceComponent; newIndex: number } {\r\n let idx = index;\r\n // skip the open parenthesis\r\n idx++;\r\n if (idx >= lexemes.length) {\r\n throw new Error(`Syntax error: Unexpected end of input at position ${idx}. Expected a subquery or nested expression after opening parenthesis.`);\r\n }\r\n\r\n // Support both SELECT and VALUES in subqueries\r\n const keyword = lexemes[idx].value;\r\n if (keyword === \"select\" || keyword === \"values\" || keyword === \"with\") {\r\n const result = this.parseSubQuerySource(lexemes, idx);\r\n idx = result.newIndex;\r\n if (idx < lexemes.length && lexemes[idx].type == TokenType.CloseParen) {\r\n // skip the closing parenthesis\r\n idx++;\r\n } else {\r\n throw new Error(`Syntax error at position ${idx}: Missing closing parenthesis. Each opening parenthesis must have a matching closing parenthesis.`);\r\n }\r\n return { value: result.value, newIndex: idx };\r\n } else if (lexemes[idx].type == TokenType.OpenParen) {\r\n const result = this.parseParenSource(lexemes, idx);\r\n idx = result.newIndex;\r\n if (idx < lexemes.length && lexemes[idx].type == TokenType.CloseParen) {\r\n // skip the closing parenthesis\r\n idx++;\r\n } else {\r\n throw new Error(`Syntax error at position ${idx}: Missing closing parenthesis. Each opening parenthesis must have a matching closing parenthesis.`);\r\n }\r\n return { value: result.value, newIndex: idx };\r\n }\r\n\r\n throw new Error(`Syntax error at position ${idx}: Expected 'SELECT' keyword, 'VALUES' keyword, or opening parenthesis '(' but found \"${lexemes[idx].value}\".`);\r\n }\r\n\r\n private static parseSubQuerySource(lexemes: Lexeme[], index: number): { value: SubQuerySource; newIndex: number } {\r\n let idx = index;\r\n\r\n // Use the new parseFromLexeme method and destructure the result\r\n const { value: selectQuery, newIndex } = SelectQueryParser.parseFromLexeme(lexemes, idx);\r\n idx = newIndex;\r\n\r\n const subQuerySource = new SubQuerySource(selectQuery);\r\n return { value: subQuerySource, newIndex: idx };\r\n }\r\n}\r\n", "import { SelectQuery, SimpleSelectQuery, BinarySelectQuery, ValuesQuery } from \"../models/SelectQuery\";\r\nimport { CommonTable, SubQuerySource, TableSource, WithClause } from \"../models/Clause\";\r\nimport { SelectableColumnCollector } from \"./SelectableColumnCollector\";\r\nimport { CTECollector } from \"./CTECollector\";\r\n\r\n/**\r\n * UpstreamSelectQueryFinder searches upstream queries for the specified columns.\r\n * If a query (including its upstream CTEs or subqueries) contains all columns,\r\n * it returns the highest such SelectQuery. Otherwise, it searches downstream.\r\n * \r\n * For BinarySelectQuery (UNION/INTERSECT/EXCEPT), this finder processes each branch\r\n * independently, as SelectableColumnCollector is designed for SimpleSelectQuery only.\r\n * This approach ensures accurate column detection within individual SELECT branches\r\n * while maintaining compatibility with compound query structures.\r\n */\r\nexport class UpstreamSelectQueryFinder {\r\n private options: { ignoreCaseAndUnderscore?: boolean };\r\n private tableColumnResolver?: (tableName: string) => string[];\r\n private columnCollector: SelectableColumnCollector;\r\n\r\n constructor(tableColumnResolver?: (tableName: string) => string[], options?: { ignoreCaseAndUnderscore?: boolean }) {\r\n this.options = options || {};\r\n this.tableColumnResolver = tableColumnResolver;\r\n // Pass the tableColumnResolver instead of options to fix type mismatch.\r\n this.columnCollector = new SelectableColumnCollector(this.tableColumnResolver);\r\n }\r\n\r\n /**\r\n * Finds the highest SelectQuery containing all specified columns.\r\n * @param query The root SelectQuery to search.\r\n * @param columnNames A column name or array of column names to check for.\r\n * @returns An array of SelectQuery objects, or an empty array if not found.\r\n */\r\n public find(query: SelectQuery, columnNames: string | string[]): SimpleSelectQuery[] {\r\n // Normalize columnNames to array\r\n const namesArray = typeof columnNames === 'string' ? [columnNames] : columnNames;\r\n // Use CTECollector to collect CTEs from the root query only once and reuse\r\n const cteCollector = new CTECollector();\r\n const ctes = cteCollector.collect(query);\r\n const cteMap: Map<string, CommonTable> = new Map();\r\n for (const cte of ctes) {\r\n cteMap.set(cte.getSourceAliasName(), cte);\r\n }\r\n return this.findUpstream(query, namesArray, cteMap);\r\n }\r\n\r\n private handleTableSource(src: TableSource, columnNames: string[], cteMap: Map<string, CommonTable>): SimpleSelectQuery[] | null {\r\n // Handles the logic for TableSource in findUpstream\r\n const cte = cteMap.get(src.table.name);\r\n if (cte) {\r\n // Remove the current CTE name from the map to prevent infinite recursion\r\n const nextCteMap = new Map(cteMap);\r\n nextCteMap.delete(src.table.name);\r\n const result = this.findUpstream(cte.query, columnNames, nextCteMap);\r\n if (result.length === 0) {\r\n return null;\r\n }\r\n return result;\r\n }\r\n return null;\r\n }\r\n\r\n private handleSubQuerySource(src: SubQuerySource, columnNames: string[], cteMap: Map<string, WithClause[\"tables\"][number]>): SimpleSelectQuery[] | null {\r\n // Handles the logic for SubQuerySource in findUpstream\r\n const result = this.findUpstream(src.query, columnNames, cteMap);\r\n if (result.length === 0) {\r\n return null;\r\n }\r\n return result;\r\n }\r\n\r\n /**\r\n * Processes all source branches in a FROM clause and checks if all upstream queries contain the specified columns.\r\n * Returns a flat array of SelectQuery if all branches are valid, otherwise null.\r\n */\r\n private processFromClauseBranches(\r\n fromClause: any,\r\n columnNames: string[],\r\n cteMap: Map<string, CommonTable>\r\n ): SimpleSelectQuery[] | null {\r\n const sources = fromClause.getSources();\r\n if (sources.length === 0) return null;\r\n\r\n let allBranchResults: SimpleSelectQuery[][] = [];\r\n let allBranchesOk = true;\r\n let validBranchCount = 0; // Count only filterable branches\r\n\r\n for (const sourceExpr of sources) {\r\n const src = sourceExpr.datasource;\r\n let branchResult: SimpleSelectQuery[] | null = null;\r\n if (src instanceof TableSource) {\r\n branchResult = this.handleTableSource(src, columnNames, cteMap);\r\n validBranchCount++;\r\n } else if (src instanceof SubQuerySource) {\r\n branchResult = this.handleSubQuerySource(src, columnNames, cteMap);\r\n validBranchCount++;\r\n } else if (src instanceof ValuesQuery) {\r\n // Skip ValuesQuery: not filterable, do not count as a valid branch\r\n continue;\r\n } else {\r\n allBranchesOk = false;\r\n break;\r\n }\r\n\r\n // If the branch result is null, \r\n // it means it didn't find the required columns in this branch\r\n if (branchResult === null) {\r\n allBranchesOk = false;\r\n break;\r\n }\r\n allBranchResults.push(branchResult);\r\n }\r\n\r\n // Check if all valid (filterable) branches are valid and contain the required columns\r\n if (allBranchesOk && allBranchResults.length === validBranchCount) {\r\n return allBranchResults.flat();\r\n }\r\n return null;\r\n }\r\n\r\n private findUpstream(query: SelectQuery, columnNames: string[], cteMap: Map<string, CommonTable>): SimpleSelectQuery[] {\r\n if (query instanceof SimpleSelectQuery) {\r\n const fromClause = query.fromClause;\r\n if (fromClause) {\r\n const branchResult = this.processFromClauseBranches(fromClause, columnNames, cteMap);\r\n if (branchResult) {\r\n return branchResult;\r\n }\r\n }\r\n const columns = this.columnCollector.collect(query).map(col => col.name);\r\n const normalize = (s: string) =>\r\n this.options.ignoreCaseAndUnderscore ? s.toLowerCase().replace(/_/g, '') : s;\r\n // Normalize both the columns and the required names for comparison.\r\n const hasAll = columnNames.every(name => columns.some(col => normalize(col) === normalize(name)));\r\n if (hasAll) {\r\n return [query];\r\n }\r\n return [];\r\n } else if (query instanceof BinarySelectQuery) {\r\n // Process BinarySelectQuery by decomposing into individual branches.\r\n // SelectableColumnCollector is designed for SimpleSelectQuery only,\r\n // so we handle UNION/INTERSECT/EXCEPT by processing left and right branches separately.\r\n const left = this.findUpstream(query.left, columnNames, cteMap);\r\n const right = this.findUpstream(query.right, columnNames, cteMap);\r\n return [...left, ...right];\r\n }\r\n return [];\r\n }\r\n}\r\n", "import { SourceAliasExpression } from \"../models/Clause\";\r\nimport { Lexeme, TokenType } from \"../models/Lexeme\";\r\n\r\n\r\nexport class SourceAliasExpressionParser {\r\n // Parse from lexeme array (was: parse)\r\n public static parseFromLexeme(lexemes: Lexeme[], index: number): { value: SourceAliasExpression; newIndex: number; } {\r\n let idx = index;\r\n\r\n // If there is a column alias, it may be detected as a function, so functions are also processed.\r\n if (idx < lexemes.length && ((lexemes[idx].type & TokenType.Identifier) || (lexemes[idx].type & TokenType.Function))) {\r\n // Check for alias\r\n const table = lexemes[idx].value;\r\n idx++;\r\n\r\n if (idx < lexemes.length && (lexemes[idx].type & TokenType.OpenParen)) {\r\n // Check for column alias\r\n const columns: string[] = [];\r\n\r\n // Skip the open parenthesis\r\n idx++;\r\n\r\n while (idx < lexemes.length && (lexemes[idx].type & TokenType.Identifier)) {\r\n columns.push(lexemes[idx].value);\r\n idx++;\r\n if (idx < lexemes.length && (lexemes[idx].type & TokenType.Comma)) {\r\n idx++;\r\n } else {\r\n break; // Exit loop if not a comma\r\n }\r\n }\r\n\r\n if (lexemes[idx].type & TokenType.CloseParen) {\r\n // Skip the closing parenthesis\r\n idx++;\r\n } else {\r\n throw new Error(`Syntax error at position ${idx}: Missing closing parenthesis ')' for column alias list. Each opening parenthesis must have a matching closing parenthesis.`);\r\n }\r\n if (columns.length === 0) {\r\n throw new Error(`Syntax error at position ${index}: No column aliases found. Column alias declarations must contain at least one column name.`);\r\n }\r\n\r\n return { value: new SourceAliasExpression(table, columns), newIndex: idx };\r\n }\r\n\r\n return { value: new SourceAliasExpression(table, null), newIndex: idx };\r\n }\r\n\r\n throw new Error(`Syntax error at position ${index}: Expected an identifier for table alias but found \"${lexemes[index]?.value || 'end of input'}\".`);\r\n }\r\n}\r\n", "import { SourceAliasExpression, SourceExpression, TableSource } from \"../models/Clause\";\r\nimport { SqlTokenizer } from \"./SqlTokenizer\";\r\nimport { Lexeme, TokenType } from \"../models/Lexeme\";\r\nimport { SourceParser } from \"./SourceParser\";\r\nimport { SourceAliasExpressionParser } from \"./SourceAliasExpressionParser\";\r\n\r\nexport class SourceExpressionParser {\r\n /**\r\n * Parse SQL string to SourceExpression (e.g. \"table\", \"table as t\", \"schema.table t\")\r\n */\r\n public static parse(query: string): SourceExpression {\r\n const tokenizer = new SqlTokenizer(query);\r\n const lexemes = tokenizer.readLexmes();\r\n const result = this.parseFromLexeme(lexemes, 0);\r\n if (result.newIndex < lexemes.length) {\r\n throw new Error(`Syntax error: Unexpected token \"${lexemes[result.newIndex].value}\" at position ${result.newIndex}. The source expression is complete but there are additional tokens.`);\r\n }\r\n return result.value;\r\n }\r\n\r\n public static parseTableSourceFromLexemes(lexemes: Lexeme[], index: number): { value: SourceExpression; newIndex: number } {\r\n const result = SourceParser.parseTableSourceFromLexemes(lexemes, index);\r\n // No alias for table source\r\n const sourceExpr = new SourceExpression(result.value, null);\r\n return { value: sourceExpr, newIndex: result.newIndex };\r\n }\r\n\r\n // Parse from lexeme array (was: parse)\r\n public static parseFromLexeme(lexemes: Lexeme[], index: number): { value: SourceExpression; newIndex: number; } {\r\n let idx = index;\r\n\r\n const sourceResult = SourceParser.parseFromLexeme(lexemes, idx);\r\n idx = sourceResult.newIndex;\r\n\r\n if (idx < lexemes.length) {\r\n if (lexemes[idx].value === \"as\") {\r\n idx++;\r\n const aliasResult = SourceAliasExpressionParser.parseFromLexeme(lexemes, idx);\r\n idx = aliasResult.newIndex;\r\n const sourceExpr = new SourceExpression(sourceResult.value, aliasResult.value);\r\n return { value: sourceExpr, newIndex: idx };\r\n }\r\n\r\n /**\r\n * Explanation:\r\n * Source aliases are typically identified as TokenType.Identifier.\r\n * However, when the 'AS' keyword is omitted and column alias names are specified,\r\n * they may sometimes be classified as TokenType.Function.\r\n * Since the TokenReader's responsibility is to perform coarse-grained classification,\r\n * the parser must interpret subsequent 'Function' tokens as source alias expressions\r\n * when they follow a source definition.\r\n * Example:\r\n * SQL: select t.* from (values(1)) t(id)\r\n * Explanation: The alias 't' and its column alias 'id' are parsed as a source alias expression.\r\n */\r\n if (idx < lexemes.length && this.isTokenTypeAliasCandidate(lexemes[idx].type)) {\r\n const aliasResult = SourceAliasExpressionParser.parseFromLexeme(lexemes, idx);\r\n idx = aliasResult.newIndex;\r\n const sourceExpr = new SourceExpression(sourceResult.value, aliasResult.value);\r\n return { value: sourceExpr, newIndex: idx };\r\n }\r\n }\r\n\r\n // no alias\r\n const expr = new SourceExpression(sourceResult.value, null);\r\n return { value: expr, newIndex: idx };\r\n }\r\n\r\n private static isTokenTypeAliasCandidate(type: number): boolean {\r\n return (type & TokenType.Identifier) !== 0 || (type & TokenType.Function) !== 0;\r\n }\r\n}\r\n", "import { SetClause, SetClauseItem, FromClause, WhereClause, SelectClause, SelectItem, SourceAliasExpression, SourceExpression, SubQuerySource, WithClause, TableSource, UpdateClause, InsertClause } from '../models/Clause';\r\nimport { UpdateQuery } from '../models/UpdateQuery';\r\nimport { BinaryExpression, ColumnReference } from '../models/ValueComponent';\r\nimport { SelectValueCollector } from './SelectValueCollector';\r\nimport { BinarySelectQuery, SelectQuery, SimpleSelectQuery, ValuesQuery } from \"../models/SelectQuery\";\r\nimport { CTECollector } from \"./CTECollector\";\r\nimport { CTENormalizer } from \"./CTENormalizer\";\r\nimport { CreateTableQuery } from \"../models/CreateTableQuery\";\r\nimport { InsertQuery } from \"../models/InsertQuery\";\r\nimport { CTEDisabler } from './CTEDisabler';\r\nimport { SourceExpressionParser } from '../parsers/SourceExpressionParser';\r\n\r\n/**\r\n * QueryBuilder provides static methods to build or convert various SQL query objects.\r\n */\r\nexport class QueryBuilder {\r\n /**\r\n * Builds a BinarySelectQuery by combining an array of SelectQuery using the specified operator.\r\n * Throws if less than two queries are provided.\r\n * @param queries Array of SelectQuery to combine\r\n * @param operator SQL operator to use (e.g. 'union', 'union all', 'intersect', 'except')\r\n * @returns BinarySelectQuery\r\n */\r\n public static buildBinaryQuery(queries: SelectQuery[], operator: string): BinarySelectQuery {\r\n if (!queries || queries.length === 0) {\r\n throw new Error(\"No queries provided to combine.\");\r\n }\r\n if (queries.length === 1) {\r\n throw new Error(\"At least two queries are required to create a BinarySelectQuery.\");\r\n }\r\n\r\n // Always create a new BinarySelectQuery instance (never mutate input)\r\n const wrap = (q: SelectQuery) => q instanceof ValuesQuery ? QueryBuilder.buildSimpleQuery(q) : q;\r\n let result: BinarySelectQuery = new BinarySelectQuery(wrap(queries[0]), operator, wrap(queries[1]));\r\n CTENormalizer.normalize(result);\r\n\r\n for (let i = 2; i < queries.length; i++) {\r\n result.appendSelectQuery(operator, wrap(queries[i]));\r\n }\r\n\r\n return result;\r\n }\r\n\r\n private constructor() {\r\n // This class is not meant to be instantiated.\r\n }\r\n\r\n /**\r\n * Converts a SELECT query to a standard SimpleSelectQuery form.\r\n * @param query The query to convert\r\n * @returns A SimpleSelectQuery\r\n */\r\n public static buildSimpleQuery(query: SelectQuery): SimpleSelectQuery {\r\n if (query instanceof SimpleSelectQuery) {\r\n return query;\r\n }\r\n else if (query instanceof BinarySelectQuery) {\r\n return QueryBuilder.buildSimpleBinaryQuery(query);\r\n }\r\n else if (query instanceof ValuesQuery) {\r\n return QueryBuilder.buildSimpleValuesQuery(query);\r\n }\r\n throw new Error(\"Unsupported query type for buildSimpleQuery\");\r\n }\r\n\r\n private static buildSimpleBinaryQuery(query: BinarySelectQuery): SimpleSelectQuery {\r\n // Create a subquery source from the binary query\r\n const subQuerySource = new SubQuerySource(query);\r\n\r\n // Create a source expression with alias\r\n const sourceExpr = new SourceExpression(\r\n subQuerySource,\r\n new SourceAliasExpression(\"bq\", null)\r\n );\r\n\r\n // Create FROM clause with the source expression\r\n const fromClause = new FromClause(sourceExpr, null);\r\n\r\n // Create SELECT clause with * (all columns)\r\n const selectClause = QueryBuilder.createSelectAllClause();\r\n\r\n // Create the final simple select query\r\n const q = new SimpleSelectQuery(\r\n {\r\n selectClause,\r\n fromClause\r\n }\r\n );\r\n\r\n return CTENormalizer.normalize(q) as SimpleSelectQuery;\r\n }\r\n\r\n /**\r\n * Converts a ValuesQuery to a SimpleSelectQuery with sequentially numbered columns or user-specified columns\r\n * \r\n * @param query The VALUES query to convert\r\n * @param columns Optional: column names\r\n * @returns A SimpleSelectQuery\r\n */\r\n private static buildSimpleValuesQuery(query: ValuesQuery): SimpleSelectQuery {\r\n // Figure out how many columns are in the VALUES clause\r\n const columnCount = query.tuples.length > 0 ? query.tuples[0].values.length : 0;\r\n if (query.tuples.length === 0) {\r\n throw new Error(\"Empty VALUES clause cannot be converted to a SimpleSelectQuery\");\r\n }\r\n if (!query.columnAliases) {\r\n throw new Error(\"Column aliases are required to convert a VALUES clause to SimpleSelectQuery. Please specify column aliases.\");\r\n }\r\n if (query.columnAliases.length !== columnCount) {\r\n throw new Error(`The number of column aliases (${query.columnAliases.length}) does not match the number of columns in the first tuple (${columnCount}).`);\r\n }\r\n\r\n // Create a subquery source from the VALUES query\r\n const subQuerySource = new SubQuerySource(query);\r\n const sourceExpr = new SourceExpression(\r\n subQuerySource,\r\n new SourceAliasExpression(\"vq\", query.columnAliases)\r\n );\r\n\r\n // Create FROM clause with the source expression\r\n const fromClause = new FromClause(sourceExpr, null);\r\n\r\n // Create SELECT clause with all columns\r\n const selectItems = query.columnAliases.map(name => new SelectItem(new ColumnReference(\"vq\", name), name));\r\n const selectClause = new SelectClause(selectItems, null);\r\n\r\n // Create the final simple select query\r\n return new SimpleSelectQuery(\r\n {\r\n selectClause,\r\n fromClause\r\n }\r\n );\r\n }\r\n\r\n /**\r\n * Creates a SELECT clause with a single * (all columns) item\r\n * \r\n * @returns A SELECT clause with *\r\n */\r\n private static createSelectAllClause(): SelectClause {\r\n // Create a column reference for *\r\n const columnRef = new ColumnReference(null, \"*\");\r\n\r\n // Create a SelectItem with the column reference\r\n const selectItem = new SelectItem(columnRef, \"*\");\r\n\r\n // Create and return a SelectClause with the item\r\n return new SelectClause([selectItem], null);\r\n }\r\n\r\n /**\r\n * Converts a SELECT query to a CREATE TABLE query (CREATE [TEMPORARY] TABLE ... AS SELECT ...)\r\n * @param query The SELECT query to use as the source\r\n * @param tableName The name of the table to create\r\n * @param isTemporary If true, creates a temporary table\r\n * @returns A CreateTableQuery instance\r\n */\r\n public static buildCreateTableQuery(query: SelectQuery, tableName: string, isTemporary: boolean = false): CreateTableQuery {\r\n return new CreateTableQuery({\r\n tableName,\r\n isTemporary,\r\n asSelectQuery: query\r\n });\r\n }\r\n\r\n /**\r\n * Converts a SELECT query to an INSERT query (INSERT INTO ... SELECT ...)\r\n * @param selectQuery The SELECT query to use as the source\r\n * @param tableName The name of the table to insert into\r\n * @param columns Optional: array of column names. If omitted, columns are inferred from the selectQuery\r\n * @returns An InsertQuery instance\r\n */\r\n public static buildInsertQuery(selectQuery: SimpleSelectQuery, tableName: string): InsertQuery {\r\n let cols: string[];\r\n\r\n const count = selectQuery.selectClause.items.length;\r\n\r\n // Try to infer columns from the selectQuery\r\n const collector = new SelectValueCollector();\r\n const items = collector.collect(selectQuery);\r\n cols = items.map(item => item.name);\r\n if (!cols.length || count !== cols.length) {\r\n throw new Error(\r\n `Columns cannot be inferred from the selectQuery. ` +\r\n `Make sure you are not using wildcards or unnamed columns.\\n` +\r\n `Select clause column count: ${count}, ` +\r\n `Columns with valid names: ${cols.length}\\n` +\r\n `Detected column names: [${cols.join(\", \")}]`\r\n );\r\n }\r\n\r\n // Generate SourceExpression (supports only table name, does not support alias or schema)\r\n const sourceExpr = SourceExpressionParser.parse(tableName);\r\n return new InsertQuery({\r\n insertClause: new InsertClause(sourceExpr, cols),\r\n selectQuery: selectQuery\r\n });\r\n }\r\n\r\n /**\r\n * Builds an UPDATE query from a SELECT query, table name, and primary key(s).\r\n * @param selectQuery The SELECT query providing new values (must select all columns to update and PKs)\r\n * @param updateTableExprRaw The table name to update\r\n * @param primaryKeys The primary key column name(s)\r\n * @returns UpdateQuery instance\r\n */\r\n public static buildUpdateQuery(selectQuery: SimpleSelectQuery, selectSourceName: string, updateTableExprRaw: string, primaryKeys: string | string[]) {\r\n const updateClause = new UpdateClause(SourceExpressionParser.parse(updateTableExprRaw));\r\n\r\n const pkArray = Array.isArray(primaryKeys) ? primaryKeys : [primaryKeys];\r\n const selectCollector = new SelectValueCollector();\r\n const selectItems = selectCollector.collect(selectQuery);\r\n\r\n const cteCollector = new CTECollector();\r\n const collectedCTEs = cteCollector.collect(selectQuery);\r\n const cteDisabler = new CTEDisabler();\r\n cteDisabler.execute(selectQuery);\r\n\r\n for (const pk of pkArray) {\r\n if (!selectItems.some(item => item.name === pk)) {\r\n throw new Error(`Primary key column '${pk}' is not present in selectQuery select list.`);\r\n }\r\n }\r\n\r\n const updateSourceName = updateClause.getSourceAliasName();\r\n if (!updateSourceName) {\r\n throw new Error(`Source expression does not have an alias. Please provide an alias for the source expression.`);\r\n }\r\n\r\n const setColumns = selectItems.filter(item => !pkArray.includes(item.name));\r\n const setItems = setColumns.map(col => new SetClauseItem(col.name, new ColumnReference(updateSourceName, col.name)));\r\n const setClause = new SetClause(setItems);\r\n\r\n const from = new FromClause(selectQuery.toSource(selectSourceName), null);\r\n\r\n let where: BinaryExpression | null = null;\r\n for (const pk of pkArray) {\r\n const cond = new BinaryExpression(\r\n new ColumnReference(updateSourceName, pk),\r\n '=',\r\n new ColumnReference(selectSourceName, pk)\r\n );\r\n where = where ? new BinaryExpression(where, 'and', cond) : cond;\r\n }\r\n const whereClause = new WhereClause(where!);\r\n\r\n const updateQuery = new UpdateQuery({\r\n updateClause: updateClause,\r\n setClause: setClause,\r\n fromClause: from,\r\n whereClause: whereClause,\r\n withClause: collectedCTEs.length > 0 ? new WithClause(false, collectedCTEs) : undefined,\r\n });\r\n return updateQuery;\r\n }\r\n}\r\n", "import { ParameterCollector } from \"../transformers/ParameterCollector\";\r\nimport { SqlComponent } from \"../models/SqlComponent\";\r\n\r\n/**\r\n * Utility class for parameter operations on SQL queries.\r\n */\r\nexport class ParameterHelper {\r\n /**\r\n * Sets the value of a parameter by name in the given query.\r\n * Throws an error if the parameter is not found.\r\n * @param query The query object (must be a SqlComponent)\r\n * @param name Parameter name\r\n * @param value Value to set\r\n */\r\n public static set(query: SqlComponent, name: string, value: any): void {\r\n const params = ParameterCollector.collect(query);\r\n\r\n let found = false;\r\n for (const p of params) {\r\n if (p.name.value === name) {\r\n p.value = value;\r\n found = true;\r\n }\r\n }\r\n\r\n if (!found) {\r\n throw new Error(`Parameter '${name}' not found in query.`);\r\n }\r\n }\r\n}\r\n", "import { SqlComponent } from \"./SqlComponent\";\r\nimport { ForClause, FromClause, GroupByClause, HavingClause, JoinClause, JoinOnClause, LimitClause, OrderByClause, SelectClause, SourceExpression, SubQuerySource, SourceAliasExpression, WhereClause, WindowsClause as WindowClause, WithClause, CommonTable, OffsetClause, FetchClause } from \"./Clause\";\r\nimport { BinaryExpression, ColumnReference, ValueComponent } from \"./ValueComponent\";\r\nimport { ValueParser } from \"../parsers/ValueParser\";\r\nimport { CTENormalizer } from \"../transformers/CTENormalizer\";\r\nimport { SelectableColumnCollector } from \"../transformers/SelectableColumnCollector\";\r\nimport { SourceParser } from \"../parsers/SourceParser\";\r\nimport { BinarySelectQuery } from \"./BinarySelectQuery\";\r\nimport type { SelectQuery } from \"./SelectQuery\";\r\nimport { SelectQueryParser } from \"../parsers/SelectQueryParser\";\r\nimport { Formatter } from \"../transformers/Formatter\";\r\nimport { TableColumnResolver } from \"../transformers/TableColumnResolver\";\r\nimport { UpstreamSelectQueryFinder } from \"../transformers/UpstreamSelectQueryFinder\";\r\nimport { QueryBuilder } from \"../transformers/QueryBuilder\";\r\nimport { ParameterHelper } from \"../utils/ParameterHelper\";\r\n\r\n/**\r\n * Represents a simple SELECT query in SQL.\r\n */\r\nexport class SimpleSelectQuery extends SqlComponent implements SelectQuery {\r\n static kind = Symbol(\"SelectQuery\");\r\n withClause: WithClause | null;\r\n selectClause: SelectClause;\r\n fromClause: FromClause | null;\r\n whereClause: WhereClause | null;\r\n groupByClause: GroupByClause | null;\r\n havingClause: HavingClause | null;\r\n orderByClause: OrderByClause | null;\r\n windowClause: WindowClause | null;\r\n limitClause: LimitClause | null;\r\n offsetClause: OffsetClause | null;\r\n fetchClause: FetchClause | null;\r\n forClause: ForClause | null;\r\n\r\n constructor(params: {\r\n selectClause: SelectClause,\r\n fromClause?: FromClause | null,\r\n whereClause?: WhereClause | null,\r\n groupByClause?: GroupByClause | null,\r\n havingClause?: HavingClause | null,\r\n orderByClause?: OrderByClause | null,\r\n windowClause?: WindowClause | null,\r\n limitClause?: LimitClause | null,\r\n offsetClause?: OffsetClause | null,\r\n fetchClause?: FetchClause | null,\r\n forClause?: ForClause | null,\r\n withClause?: WithClause | null,\r\n }) {\r\n super();\r\n this.withClause = params.withClause ?? null;\r\n this.selectClause = params.selectClause;\r\n this.fromClause = params.fromClause ?? null;\r\n this.whereClause = params.whereClause ?? null;\r\n this.groupByClause = params.groupByClause ?? null;\r\n this.havingClause = params.havingClause ?? null;\r\n this.orderByClause = params.orderByClause ?? null;\r\n this.windowClause = params.windowClause ?? null;\r\n this.limitClause = params.limitClause ?? null;\r\n this.offsetClause = params.offsetClause ?? null;\r\n this.fetchClause = params.fetchClause ?? null;\r\n this.forClause = params.forClause ?? null;\r\n }\r\n\r\n /**\r\n * Creates a new BinarySelectQuery with this query as the left side and the provided query as the right side,\r\n * using UNION as the operator.\r\n * \r\n * @param rightQuery The right side of the UNION\r\n * @returns A new BinarySelectQuery representing \"this UNION rightQuery\"\r\n */\r\n public toUnion(rightQuery: SelectQuery): BinarySelectQuery {\r\n return this.toBinaryQuery('union', rightQuery);\r\n }\r\n\r\n /**\r\n * Creates a new BinarySelectQuery with this query as the left side and the provided query as the right side,\r\n * using UNION ALL as the operator.\r\n * \r\n * @param rightQuery The right side of the UNION ALL\r\n * @returns A new BinarySelectQuery representing \"this UNION ALL rightQuery\"\r\n */\r\n public toUnionAll(rightQuery: SelectQuery): BinarySelectQuery {\r\n return this.toBinaryQuery('union all', rightQuery);\r\n }\r\n\r\n /**\r\n * Creates a new BinarySelectQuery with this query as the left side and the provided query as the right side,\r\n * using INTERSECT as the operator.\r\n * \r\n * @param rightQuery The right side of the INTERSECT\r\n * @returns A new BinarySelectQuery representing \"this INTERSECT rightQuery\"\r\n */\r\n public toIntersect(rightQuery: SelectQuery): BinarySelectQuery {\r\n return this.toBinaryQuery('intersect', rightQuery);\r\n }\r\n\r\n /**\r\n * Creates a new BinarySelectQuery with this query as the left side and the provided query as the right side,\r\n * using INTERSECT ALL as the operator.\r\n * \r\n * @param rightQuery The right side of the INTERSECT ALL\r\n * @returns A new BinarySelectQuery representing \"this INTERSECT ALL rightQuery\"\r\n */\r\n public toIntersectAll(rightQuery: SelectQuery): BinarySelectQuery {\r\n return this.toBinaryQuery('intersect all', rightQuery);\r\n }\r\n\r\n /**\r\n * Creates a new BinarySelectQuery with this query as the left side and the provided query as the right side,\r\n * using EXCEPT as the operator.\r\n * \r\n * @param rightQuery The right side of the EXCEPT\r\n * @returns A new BinarySelectQuery representing \"this EXCEPT rightQuery\"\r\n */\r\n public toExcept(rightQuery: SelectQuery): BinarySelectQuery {\r\n return this.toBinaryQuery('except', rightQuery);\r\n }\r\n\r\n /**\r\n * Creates a new BinarySelectQuery with this query as the left side and the provided query as the right side,\r\n * using EXCEPT ALL as the operator.\r\n * \r\n * @param rightQuery The right side of the EXCEPT ALL\r\n * @returns A new BinarySelectQuery representing \"this EXCEPT ALL rightQuery\"\r\n */\r\n public toExceptAll(rightQuery: SelectQuery): BinarySelectQuery {\r\n return this.toBinaryQuery('except all', rightQuery);\r\n }\r\n\r\n /**\r\n * Creates a new BinarySelectQuery with this query as the left side and the provided query as the right side,\r\n * using the specified operator.\r\n * \r\n * @param operator SQL operator to use (e.g. 'union', 'union all', 'intersect', 'except')\r\n * @param rightQuery The right side of the binary operation\r\n * @returns A new BinarySelectQuery representing \"this [operator] rightQuery\"\r\n */\r\n public toBinaryQuery(operator: string, rightQuery: SelectQuery): BinarySelectQuery {\r\n return QueryBuilder.buildBinaryQuery([this, rightQuery], operator);\r\n }\r\n\r\n /**\r\n * Appends a new condition to the query's WHERE clause using AND logic.\r\n * The condition is provided as a raw SQL string which is parsed internally.\r\n * \r\n * @param rawCondition Raw SQL string representing the condition (e.g. \"status = 'active'\")\r\n */\r\n public appendWhereRaw(rawCondition: string): void {\r\n const parsedCondition = ValueParser.parse(rawCondition);\r\n this.appendWhere(parsedCondition);\r\n }\r\n\r\n /**\r\n * Appends a new condition to the query's WHERE clause using AND logic.\r\n * The condition is provided as a ValueComponent object.\r\n * \r\n * @param condition ValueComponent representing the condition\r\n */\r\n public appendWhere(condition: ValueComponent): void {\r\n if (!this.whereClause) {\r\n this.whereClause = new WhereClause(condition);\r\n } else {\r\n this.whereClause.condition = new BinaryExpression(\r\n this.whereClause.condition,\r\n 'and',\r\n condition\r\n );\r\n }\r\n }\r\n\r\n /**\r\n * Appends a new condition to the query's HAVING clause using AND logic.\r\n * The condition is provided as a raw SQL string which is parsed internally.\r\n * \r\n * @param rawCondition Raw SQL string representing the condition (e.g. \"count(*) > 5\")\r\n */\r\n public appendHavingRaw(rawCondition: string): void {\r\n const parsedCondition = ValueParser.parse(rawCondition);\r\n this.appendHaving(parsedCondition);\r\n }\r\n\r\n /**\r\n * Appends a new condition to the query's HAVING clause using AND logic.\r\n * The condition is provided as a ValueComponent object.\r\n * \r\n * @param condition ValueComponent representing the condition\r\n */\r\n public appendHaving(condition: ValueComponent): void {\r\n if (!this.havingClause) {\r\n this.havingClause = new HavingClause(condition);\r\n } else {\r\n this.havingClause.condition = new BinaryExpression(\r\n this.havingClause.condition,\r\n 'and',\r\n condition\r\n );\r\n }\r\n }\r\n\r\n /**\r\n * Appends an INNER JOIN clause to the query.\r\n * @param joinSourceRawText The table source text to join (e.g., \"my_table\", \"schema.my_table\")\r\n * @param alias The alias for the joined table\r\n * @param columns The columns to use for the join condition (e.g. [\"user_id\"] or \"user_id\")\r\n */\r\n public innerJoinRaw(joinSourceRawText: string, alias: string, columns: string | string[], resolver: TableColumnResolver | null = null): void {\r\n this.joinSourceRaw('inner join', joinSourceRawText, alias, columns, resolver);\r\n }\r\n\r\n /**\r\n * Appends a LEFT JOIN clause to the query.\r\n * @param joinSourceRawText The table source text to join\r\n * @param alias The alias for the joined table\r\n * @param columns The columns to use for the join condition\r\n */\r\n public leftJoinRaw(joinSourceRawText: string, alias: string, columns: string | string[], resolver: TableColumnResolver | null = null): void {\r\n this.joinSourceRaw('left join', joinSourceRawText, alias, columns, resolver);\r\n }\r\n\r\n /**\r\n * Appends a RIGHT JOIN clause to the query.\r\n * @param joinSourceRawText The table source text to join\r\n * @param alias The alias for the joined table\r\n * @param columns The columns to use for the join condition\r\n */\r\n public rightJoinRaw(joinSourceRawText: string, alias: string, columns: string | string[], resolver: TableColumnResolver | null = null): void {\r\n this.joinSourceRaw('right join', joinSourceRawText, alias, columns, resolver);\r\n }\r\n\r\n /**\r\n * Appends an INNER JOIN clause to the query using a SourceExpression.\r\n * @param sourceExpr The source expression to join\r\n * @param columns The columns to use for the join condition\r\n */\r\n public innerJoin(sourceExpr: SourceExpression, columns: string | string[], resolver: TableColumnResolver | null = null): void {\r\n this.joinSource('inner join', sourceExpr, columns, resolver);\r\n }\r\n\r\n /**\r\n * Appends a LEFT JOIN clause to the query using a SourceExpression.\r\n * @param sourceExpr The source expression to join\r\n * @param columns The columns to use for the join condition\r\n */\r\n public leftJoin(sourceExpr: SourceExpression, columns: string | string[], resolver: TableColumnResolver | null = null): void {\r\n this.joinSource('left join', sourceExpr, columns, resolver);\r\n }\r\n\r\n /**\r\n * Appends a RIGHT JOIN clause to the query using a SourceExpression.\r\n * @param sourceExpr The source expression to join\r\n * @param columns The columns to use for the join condition\r\n */\r\n public rightJoin(sourceExpr: SourceExpression, columns: string | string[], resolver: TableColumnResolver | null = null): void {\r\n this.joinSource('right join', sourceExpr, columns, resolver);\r\n }\r\n\r\n /**\r\n * Internal helper to append a JOIN clause.\r\n * Parses the table source, finds the corresponding columns in the existing query context,\r\n * and builds the JOIN condition.\r\n * @param joinType Type of join (e.g., 'inner join', 'left join')\r\n * @param joinSourceRawText Raw text for the table/source to join (e.g., \"my_table\", \"schema.another_table\")\r\n * @param alias Alias for the table/source being joined\r\n * @param columns Array or string of column names to join on\r\n */\r\n private joinSourceRaw(joinType: string, joinSourceRawText: string, alias: string, columns: string | string[], resolver: TableColumnResolver | null = null): void {\r\n const tableSource = SourceParser.parse(joinSourceRawText);\r\n const sourceExpr = new SourceExpression(tableSource, new SourceAliasExpression(alias, null));\r\n this.joinSource(joinType, sourceExpr, columns, resolver);\r\n }\r\n\r\n /**\r\n * Internal helper to append a JOIN clause using a SourceExpression.\r\n * @param joinType Type of join (e.g., 'inner join', 'left join')\r\n * @param sourceExpr The source expression to join\r\n * @param columns Array or string of column names to join on\r\n */\r\n private joinSource(joinType: string, sourceExpr: SourceExpression, columns: string | string[], resolver: TableColumnResolver | null = null): void {\r\n if (!this.fromClause) {\r\n throw new Error('A FROM clause is required to add a JOIN condition.');\r\n }\r\n\r\n // Always treat columns as array\r\n const columnsArr = Array.isArray(columns) ? columns : [columns];\r\n\r\n const collector = new SelectableColumnCollector(resolver);\r\n const valueSets = collector.collect(this);\r\n let joinCondition: ValueComponent | null = null;\r\n let count = 0;\r\n\r\n const sourceAlias = sourceExpr.getAliasName();\r\n if (!sourceAlias) {\r\n throw new Error('An alias is required for the source expression to add a JOIN condition.');\r\n }\r\n\r\n for (const valueSet of valueSets) {\r\n if (columnsArr.some(col => col == valueSet.name)) {\r\n const expr = new BinaryExpression(\r\n valueSet.value,\r\n '=',\r\n new ColumnReference([sourceAlias], valueSet.name)\r\n );\r\n if (joinCondition) {\r\n joinCondition = new BinaryExpression(\r\n joinCondition,\r\n 'and',\r\n expr\r\n );\r\n } else {\r\n joinCondition = expr;\r\n }\r\n count++;\r\n }\r\n }\r\n\r\n if (!joinCondition || count !== columnsArr.length) {\r\n throw new Error(`Invalid JOIN condition. The specified columns were not found: ${columnsArr.join(', ')}`);\r\n }\r\n\r\n const joinOnClause = new JoinOnClause(joinCondition);\r\n const joinClause = new JoinClause(joinType, sourceExpr, joinOnClause, false);\r\n\r\n if (this.fromClause) {\r\n if (this.fromClause.joins) {\r\n this.fromClause.joins.push(joinClause);\r\n } else {\r\n this.fromClause.joins = [joinClause];\r\n }\r\n }\r\n\r\n CTENormalizer.normalize(this);\r\n }\r\n\r\n // Returns a SourceExpression wrapping this query as a subquery source.\r\n // Alias is required for correct SQL generation and join logic.\r\n public toSource(alias: string): SourceExpression {\r\n if (!alias || alias.trim() === \"\") {\r\n throw new Error(\"Alias is required for toSource(). Please specify a non-empty alias name.\");\r\n }\r\n return new SourceExpression(\r\n new SubQuerySource(this),\r\n new SourceAliasExpression(alias, null)\r\n );\r\n }\r\n\r\n public appendWith(commonTable: CommonTable | CommonTable[]): void {\r\n // Always treat as array for simplicity\r\n const tables = Array.isArray(commonTable) ? commonTable : [commonTable];\r\n if (!this.withClause) {\r\n this.withClause = new WithClause(false, tables);\r\n } else {\r\n this.withClause.tables.push(...tables);\r\n }\r\n\r\n CTENormalizer.normalize(this);\r\n }\r\n\r\n /**\r\n * Appends a CommonTable (CTE) to the WITH clause from raw SQL text and alias.\r\n * If alias is provided, it will be used as the CTE name.\r\n *\r\n * @param rawText Raw SQL string representing the CTE body (e.g. '(SELECT ...)')\r\n * @param alias Optional alias for the CTE (e.g. 'cte_name')\r\n */\r\n public appendWithRaw(rawText: string, alias: string): void {\r\n const query = SelectQueryParser.parse(rawText);\r\n const commonTable = new CommonTable(query, alias, null);\r\n this.appendWith(commonTable);\r\n }\r\n\r\n /**\r\n * Overrides a select item using a template literal function.\r\n * The callback receives the SQL string of the original expression and must return a new SQL string.\r\n * The result is parsed and set as the new select item value.\r\n *\r\n * Example usage:\r\n * query.overrideSelectItemRaw(\"journal_date\", expr => `greatest(${expr}, DATE '2025-01-01')`)\r\n *\r\n * @param columnName The name of the column to override\r\n * @param fn Callback that receives the SQL string of the original expression and returns a new SQL string\r\n */\r\n public overrideSelectItemExpr(columnName: string, fn: (expr: string) => string): void {\r\n const items = this.selectClause.items.filter(item => item.identifier?.name === columnName);\r\n if (items.length === 0) {\r\n throw new Error(`Column ${columnName} not found in the query`);\r\n }\r\n if (items.length > 1) {\r\n throw new Error(`Duplicate column name ${columnName} found in the query`);\r\n }\r\n const item = items[0];\r\n const formatter = new Formatter();\r\n const exprSql = formatter.visit(item.value);\r\n const newValue = fn(exprSql);\r\n item.value = ValueParser.parse(newValue);\r\n }\r\n\r\n /**\r\n * Appends a WHERE clause using the expression for the specified column.\r\n * If `options.upstream` is true, applies to all upstream queries containing the column.\r\n * If false or omitted, applies only to the current query.\r\n *\r\n * @param columnName The name of the column to target.\r\n * @param exprBuilder Function that receives the column expression as a string and returns the WHERE condition string.\r\n * @param options Optional settings. If `upstream` is true, applies to upstream queries.\r\n */\r\n public appendWhereExpr(\r\n columnName: string,\r\n exprBuilder: (expr: string) => string,\r\n options?: { upstream?: boolean }\r\n ): void {\r\n // If upstream option is true, find all upstream queries containing the column\r\n if (options && options.upstream) {\r\n // Use UpstreamSelectQueryFinder to find all relevant queries\r\n // (Assume UpstreamSelectQueryFinder is imported)\r\n const finder = new UpstreamSelectQueryFinder();\r\n const queries = finder.find(this, [columnName]);\r\n const collector = new SelectableColumnCollector();\r\n const formatter = new Formatter();\r\n for (const q of queries) {\r\n const exprs = collector.collect(q).filter(item => item.name === columnName).map(item => item.value);\r\n if (exprs.length !== 1) {\r\n throw new Error(`Expected exactly one expression for column '${columnName}'`);\r\n }\r\n const exprStr = formatter.format(exprs[0]);\r\n q.appendWhereRaw(exprBuilder(exprStr));\r\n }\r\n } else {\r\n // Only apply to the current query\r\n const collector = new SelectableColumnCollector();\r\n const formatter = new Formatter();\r\n const exprs = collector.collect(this).filter(item => item.name === columnName).map(item => item.value);\r\n if (exprs.length !== 1) {\r\n throw new Error(`Expected exactly one expression for column '${columnName}'`);\r\n }\r\n const exprStr = formatter.format(exprs[0]);\r\n this.appendWhereRaw(exprBuilder(exprStr));\r\n }\r\n }\r\n\r\n /**\r\n * Sets the value of a parameter by name in this query.\r\n * @param name Parameter name\r\n * @param value Value to set\r\n */\r\n public setParameter(name: string, value: any): this {\r\n ParameterHelper.set(this, name, value);\r\n return this;\r\n }\r\n}\r\n", "import { SourceExpression, SubQuerySource, SourceAliasExpression } from \"./Clause\";\r\nimport type { SelectQuery } from \"./SelectQuery\";\r\nimport { SqlComponent } from \"./SqlComponent\";\r\nimport { RawString } from \"./ValueComponent\";\r\nimport { CTENormalizer } from \"../transformers/CTENormalizer\";\r\nimport { SelectQueryParser } from \"../parsers/SelectQueryParser\";\r\nimport { ParameterCollector } from \"../transformers/ParameterCollector\";\r\nimport { ParameterHelper } from \"../utils/ParameterHelper\";\r\n\r\n/**\r\n * Represents a binary SELECT query (e.g., UNION, INTERSECT, EXCEPT).\r\n */\r\nexport class BinarySelectQuery extends SqlComponent implements SelectQuery {\r\n static kind = Symbol(\"BinarySelectQuery\");\r\n left: SelectQuery;\r\n operator: RawString;\r\n right: SelectQuery;\r\n\r\n constructor(left: SelectQuery, operator: string, right: SelectQuery) {\r\n super();\r\n this.left = left;\r\n this.operator = new RawString(operator);\r\n this.right = right;\r\n }\r\n\r\n /**\r\n * Appends another query to this binary query using UNION as the operator.\r\n * This creates a new BinarySelectQuery where the left side is this binary query\r\n * and the right side is the provided query.\r\n * \r\n * @param query The query to append with UNION\r\n * @returns A new BinarySelectQuery representing \"(this) UNION query\"\r\n */\r\n public union(query: SelectQuery): BinarySelectQuery {\r\n return this.appendSelectQuery('union', query);\r\n }\r\n\r\n /**\r\n * Appends another query to this binary query using UNION ALL as the operator.\r\n * This creates a new BinarySelectQuery where the left side is this binary query\r\n * and the right side is the provided query.\r\n * \r\n * @param query The query to append with UNION ALL\r\n * @returns A new BinarySelectQuery representing \"(this) UNION ALL query\"\r\n */\r\n public unionAll(query: SelectQuery): BinarySelectQuery {\r\n return this.appendSelectQuery('union all', query);\r\n }\r\n\r\n /**\r\n * Appends another query to this binary query using INTERSECT as the operator.\r\n * This creates a new BinarySelectQuery where the left side is this binary query\r\n * and the right side is the provided query.\r\n * \r\n * @param query The query to append with INTERSECT\r\n * @returns A new BinarySelectQuery representing \"(this) INTERSECT query\"\r\n */\r\n public intersect(query: SelectQuery): BinarySelectQuery {\r\n return this.appendSelectQuery('intersect', query);\r\n }\r\n\r\n /**\r\n * Appends another query to this binary query using INTERSECT ALL as the operator.\r\n * This creates a new BinarySelectQuery where the left side is this binary query\r\n * and the right side is the provided query.\r\n * \r\n * @param query The query to append with INTERSECT ALL\r\n * @returns A new BinarySelectQuery representing \"(this) INTERSECT ALL query\"\r\n */\r\n public intersectAll(query: SelectQuery): BinarySelectQuery {\r\n return this.appendSelectQuery('intersect all', query);\r\n }\r\n\r\n /**\r\n * Appends another query to this binary query using EXCEPT as the operator.\r\n * This creates a new BinarySelectQuery where the left side is this binary query\r\n * and the right side is the provided query.\r\n * \r\n * @param query The query to append with EXCEPT\r\n * @returns A new BinarySelectQuery representing \"(this) EXCEPT query\"\r\n */\r\n public except(query: SelectQuery): BinarySelectQuery {\r\n return this.appendSelectQuery('except', query);\r\n }\r\n\r\n /**\r\n * Appends another query to this binary query using EXCEPT ALL as the operator.\r\n * This creates a new BinarySelectQuery where the left side is this binary query\r\n * and the right side is the provided query.\r\n * \r\n * @param query The query to append with EXCEPT ALL\r\n * @returns A new BinarySelectQuery representing \"(this) EXCEPT ALL query\"\r\n */\r\n public exceptAll(query: SelectQuery): BinarySelectQuery {\r\n return this.appendSelectQuery('except all', query);\r\n }\r\n\r\n /**\r\n * Appends another query to this binary query using the specified operator.\r\n * This creates a new BinarySelectQuery where the left side is this binary query\r\n * and the right side is the provided query.\r\n * \r\n * @param operator SQL operator to use (e.g. 'union', 'union all', 'intersect', 'except')\r\n * @param query The query to append with the specified operator\r\n * @returns A new BinarySelectQuery representing \"(this) [operator] query\"\r\n */\r\n public appendSelectQuery(operator: string, query: SelectQuery): BinarySelectQuery {\r\n this.left = new BinarySelectQuery(this.left, this.operator.value, this.right);\r\n this.operator = new RawString(operator);\r\n this.right = query;\r\n\r\n CTENormalizer.normalize(this);\r\n\r\n return this;\r\n }\r\n\r\n /**\r\n * Appends another query to this binary query using UNION as the operator, accepting a raw SQL string.\r\n * This method parses the SQL string and appends the resulting query using UNION.\r\n * @param sql The SQL string to parse and union\r\n * @returns A new BinarySelectQuery representing \"(this) UNION (parsed query)\"\r\n */\r\n public unionRaw(sql: string): BinarySelectQuery {\r\n const parsedQuery = SelectQueryParser.parse(sql);\r\n return this.union(parsedQuery);\r\n }\r\n public unionAllRaw(sql: string): BinarySelectQuery {\r\n const parsedQuery = SelectQueryParser.parse(sql);\r\n return this.unionAll(parsedQuery);\r\n }\r\n public intersectRaw(sql: string): BinarySelectQuery {\r\n const parsedQuery = SelectQueryParser.parse(sql);\r\n return this.intersect(parsedQuery);\r\n }\r\n public intersectAllRaw(sql: string): BinarySelectQuery {\r\n const parsedQuery = SelectQueryParser.parse(sql);\r\n return this.intersectAll(parsedQuery);\r\n }\r\n public exceptRaw(sql: string): BinarySelectQuery {\r\n const parsedQuery = SelectQueryParser.parse(sql);\r\n return this.except(parsedQuery);\r\n }\r\n public exceptAllRaw(sql: string): BinarySelectQuery {\r\n const parsedQuery = SelectQueryParser.parse(sql);\r\n return this.exceptAll(parsedQuery);\r\n }\r\n\r\n // Returns a SourceExpression wrapping this query as a subquery source.\r\n // Optionally takes an alias name (default: \"subq\")\r\n public toSource(alias: string = \"subq\"): SourceExpression {\r\n return new SourceExpression(\r\n new SubQuerySource(this),\r\n new SourceAliasExpression(alias, null)\r\n );\r\n }\r\n\r\n /**\r\n * Sets the value of a parameter by name in this query.\r\n * @param name Parameter name\r\n * @param value Value to set\r\n */\r\n public setParameter(name: string, value: any): this {\r\n ParameterHelper.set(this, name, value);\r\n return this;\r\n }\r\n}\r\n", "import { ParameterHelper } from \"../utils/ParameterHelper\";\r\nimport { ParameterCollector } from \"../transformers/ParameterCollector\";\r\nimport { QueryBuilder } from \"../transformers/QueryBuilder\";\r\nimport { SelectQuery } from \"./SelectQuery\";\r\nimport { SimpleSelectQuery } from \"./SimpleSelectQuery\";\r\nimport { SqlComponent } from \"./SqlComponent\";\r\nimport { TupleExpression } from \"./ValueComponent\";\r\n\r\n/**\r\n * Represents a VALUES query in SQL.\r\n */\r\nexport class ValuesQuery extends SqlComponent implements SelectQuery {\r\n static kind = Symbol(\"ValuesQuery\");\r\n tuples: TupleExpression[];\r\n /**\r\n * Column aliases for the VALUES query.\r\n * These represent the logical column names for each value tuple.\r\n * Note: This property is optional and is not referenced during SQL output, but is used when converting to a SimpleSelectQuery.\r\n */\r\n columnAliases: string[] | null;\r\n\r\n constructor(tuples: TupleExpression[], columnAliases: string[] | null = null) {\r\n super();\r\n this.tuples = tuples;\r\n this.columnAliases = columnAliases;\r\n }\r\n\r\n public toSimpleSelectQuery(): SimpleSelectQuery {\r\n return QueryBuilder.buildSimpleQuery(this);\r\n }\r\n\r\n /**\r\n * Sets the value of a parameter by name in this query.\r\n * @param name Parameter name\r\n * @param value Value to set\r\n */\r\n public setParameter(name: string, value: any): this {\r\n ParameterHelper.set(this, name, value);\r\n return this;\r\n }\r\n}\r\n", "import { Distinct, DistinctComponent, DistinctOn, SelectClause, SelectItem } from \"../models/Clause\";\r\nimport { Lexeme, TokenType } from \"../models/Lexeme\";\r\nimport { ColumnReference } from \"../models/ValueComponent\";\r\nimport { SqlTokenizer } from \"./SqlTokenizer\";\r\nimport { ValueParser } from \"./ValueParser\";\r\n\r\nexport class SelectClauseParser {\r\n // Parse SQL string to AST (was: parse)\r\n public static parse(query: string): SelectClause {\r\n const tokenizer = new SqlTokenizer(query); // Initialize tokenizer\r\n const lexemes = tokenizer.readLexmes(); // Get tokens\r\n\r\n // Parse\r\n const result = this.parseFromLexeme(lexemes, 0);\r\n\r\n // Error if there are remaining tokens\r\n if (result.newIndex < lexemes.length) {\r\n throw new Error(`Syntax error: Unexpected token \"${lexemes[result.newIndex].value}\" at position ${result.newIndex}. The SELECT clause is complete but there are additional tokens.`);\r\n }\r\n\r\n return result.value;\r\n }\r\n\r\n // Parse from lexeme array (was: parse)\r\n public static parseFromLexeme(lexemes: Lexeme[], index: number): { value: SelectClause; newIndex: number } {\r\n let idx = index;\r\n let distinct: DistinctComponent | null = null;\r\n\r\n if (lexemes[idx].value !== 'select') {\r\n throw new Error(`Syntax error at position ${idx}: Expected 'SELECT' keyword but found \"${lexemes[idx].value}\". SELECT clauses must start with the SELECT keyword.`);\r\n }\r\n idx++;\r\n\r\n if (idx < lexemes.length && lexemes[idx].value === 'distinct') {\r\n idx++;\r\n distinct = new Distinct();\r\n } else if (idx < lexemes.length && lexemes[idx].value === 'distinct on') {\r\n idx++;\r\n const argument = ValueParser.parseArgument(TokenType.OpenParen, TokenType.CloseParen, lexemes, idx);\r\n distinct = new DistinctOn(argument.value);\r\n idx = argument.newIndex;\r\n }\r\n\r\n const items: SelectItem[] = [];\r\n const item = SelectItemParser.parseItem(lexemes, idx);\r\n items.push(item.value);\r\n idx = item.newIndex;\r\n\r\n while (idx < lexemes.length && (lexemes[idx].type & TokenType.Comma)) {\r\n idx++;\r\n const item = SelectItemParser.parseItem(lexemes, idx);\r\n items.push(item.value);\r\n idx = item.newIndex;\r\n }\r\n\r\n if (items.length === 0) {\r\n throw new Error(`Syntax error at position ${index}: No select items found. The SELECT clause requires at least one expression to select.`);\r\n } else {\r\n const clause = new SelectClause(items, distinct);\r\n return { value: clause, newIndex: idx };\r\n }\r\n }\r\n\r\n}\r\n\r\n// Extracted SelectItemParser for parsing individual select items\r\nexport class SelectItemParser {\r\n /**\r\n * Parses a single select item from a SQL string.\r\n * @param query The SQL string representing a select item (e.g. 'id as user_id').\r\n * @returns The parsed SelectItem instance.\r\n */\r\n public static parse(query: string): SelectItem {\r\n const tokenizer = new SqlTokenizer(query);\r\n const lexemes = tokenizer.readLexmes();\r\n const result = this.parseItem(lexemes, 0);\r\n if (result.newIndex < lexemes.length) {\r\n throw new Error(`Syntax error: Unexpected token \"${lexemes[result.newIndex].value}\" at position ${result.newIndex}. The select item is complete but there are additional tokens.`);\r\n }\r\n return result.value;\r\n }\r\n\r\n /**\r\n * Parses a single select item from lexemes.\r\n * @param lexemes The array of lexemes.\r\n * @param index The starting index.\r\n * @returns An object containing the SelectItem and the new index.\r\n */\r\n public static parseItem(lexemes: Lexeme[], index: number): { value: SelectItem; newIndex: number } {\r\n let idx = index;\r\n const parsedValue = ValueParser.parseFromLexeme(lexemes, idx);\r\n const value = parsedValue.value;\r\n idx = parsedValue.newIndex;\r\n\r\n if (idx < lexemes.length && lexemes[idx].value === 'as') {\r\n // Skip 'AS' keyword\r\n idx++;\r\n }\r\n\r\n if (idx < lexemes.length && (lexemes[idx].type & TokenType.Identifier)) {\r\n const alias = lexemes[idx].value;\r\n idx++;\r\n return {\r\n value: new SelectItem(value, alias),\r\n newIndex: idx,\r\n };\r\n } else if (value instanceof ColumnReference && value.column.name !== \"*\") {\r\n // nameless select item\r\n return {\r\n value: new SelectItem(value, value.column.name),\r\n newIndex: idx,\r\n };\r\n }\r\n // nameless select item\r\n return {\r\n value: new SelectItem(value),\r\n newIndex: idx,\r\n };\r\n }\r\n}", "import { JoinOnClause } from \"../models/Clause\";\r\nimport { Lexeme } from \"../models/Lexeme\";\r\nimport { ValueParser } from \"./ValueParser\";\r\n\r\nexport class JoinOnClauseParser {\r\n public static tryParse(lexemes: Lexeme[], index: number): { value: JoinOnClause; newIndex: number } | null {\r\n let idx = index;\r\n if (idx < lexemes.length && lexemes[idx].value === 'on') {\r\n idx++; // Skip 'on' keyword\r\n // Parse the condition expression\r\n const condition = ValueParser.parseFromLexeme(lexemes, idx);\r\n idx = condition.newIndex;\r\n const joinOn = new JoinOnClause(condition.value);\r\n return { value: joinOn, newIndex: idx };\r\n }\r\n return null;\r\n }\r\n}\r\n", "import { JoinUsingClause } from \"../models/Clause\";\r\nimport { Lexeme, TokenType } from \"../models/Lexeme\";\r\nimport { ValueParser } from \"./ValueParser\";\r\n\r\nexport class JoinUsingClauseParser {\r\n public static tryParse(lexemes: Lexeme[], index: number): { value: JoinUsingClause; newIndex: number } | null {\r\n let idx = index;\r\n if (idx < lexemes.length && lexemes[idx].value === 'using') {\r\n idx++; // Skip 'using' keyword\r\n // Parse the columns in parentheses\r\n const result = ValueParser.parseArgument(TokenType.OpenParen, TokenType.CloseParen, lexemes, idx);\r\n const usingColumns = result.value;\r\n idx = result.newIndex;\r\n const joinUsing = new JoinUsingClause(usingColumns);\r\n return { value: joinUsing, newIndex: idx };\r\n }\r\n return null;\r\n }\r\n}\r\n", "import { JoinClause, SourceExpression } from \"../models/Clause\";\r\nimport { Lexeme, TokenType } from \"../models/Lexeme\";\r\nimport { joinkeywordParser } from \"../tokenReaders/CommandTokenReader\";\r\nimport { SourceExpressionParser } from \"./SourceExpressionParser\";\r\nimport { JoinOnClauseParser } from \"./JoinOnClauseParser\";\r\nimport { JoinUsingClauseParser } from \"./JoinUsingClauseParser\";\r\n\r\nexport class JoinClauseParser {\r\n public static tryParse(lexemes: Lexeme[], index: number): { value: JoinClause[]; newIndex: number } | null {\r\n let idx = index;\r\n const joins: JoinClause[] = [];\r\n\r\n while (this.isJoinCommand(lexemes, idx)) {\r\n const joinClause = this.parseJoinClause(lexemes, idx);\r\n joins.push(joinClause.value);\r\n idx = joinClause.newIndex;\r\n }\r\n\r\n if (joins.length > 0) {\r\n return { value: joins, newIndex: idx };\r\n }\r\n return null;\r\n }\r\n\r\n private static isJoinKeyword(value: string): boolean {\r\n // Although performance is not ideal,\r\n // we use keyword token reader to centralize keyword management\r\n const result = joinkeywordParser.parse(value, 0);\r\n if (result) {\r\n return true;\r\n }\r\n return false;\r\n }\r\n\r\n private static parseLateral(lexemes: Lexeme[], index: number): { value: boolean; newIndex: number } {\r\n let idx = index;\r\n\r\n if (idx < lexemes.length && lexemes[idx].value === 'lateral') {\r\n // Skip 'lateral' keyword\r\n idx++;\r\n return { value: true, newIndex: idx };\r\n }\r\n\r\n return { value: false, newIndex: idx };\r\n }\r\n\r\n private static isJoinCommand(lexemes: Lexeme[], index: number): boolean {\r\n if (index >= lexemes.length) {\r\n return false;\r\n }\r\n\r\n if (lexemes[index].type & TokenType.Comma || this.isJoinKeyword(lexemes[index].value) === true) {\r\n return true;\r\n }\r\n return false;\r\n }\r\n\r\n private static parseJoinClause(lexemes: Lexeme[], index: number): { value: JoinClause; newIndex: number } {\r\n let idx = index;\r\n\r\n // Get the join type\r\n const joinType = lexemes[idx].value === \",\" ? \"cross join\" : lexemes[idx].value;\r\n idx++;\r\n\r\n // Check for lateral join\r\n const lateralResult = this.parseLateral(lexemes, idx);\r\n const lateral = lateralResult.value;\r\n idx = lateralResult.newIndex;\r\n\r\n // Parse the source expression to join with\r\n const sourceResult = SourceExpressionParser.parseFromLexeme(lexemes, idx);\r\n idx = sourceResult.newIndex;\r\n\r\n\r\n if (idx < lexemes.length) {\r\n // JoinOnClauseParser\r\n const onResult = JoinOnClauseParser.tryParse(lexemes, idx);\r\n if (onResult) {\r\n const joinClause = new JoinClause(joinType, sourceResult.value, onResult.value, lateral);\r\n return { value: joinClause, newIndex: onResult.newIndex };\r\n }\r\n // JoinUsingClauseParser\r\n const usingResult = JoinUsingClauseParser.tryParse(lexemes, idx);\r\n if (usingResult) {\r\n const joinClause = new JoinClause(joinType, sourceResult.value, usingResult.value, lateral);\r\n return { value: joinClause, newIndex: usingResult.newIndex };\r\n }\r\n }\r\n\r\n // If we reach the end of the input, we can treat it as a natural join\r\n const joinClause = new JoinClause(joinType, sourceResult.value, null, lateral);\r\n return { value: joinClause, newIndex: idx };\r\n }\r\n}", "import { FromClause } from \"../models/Clause\";\r\nimport { Lexeme } from \"../models/Lexeme\";\r\nimport { SqlTokenizer } from \"./SqlTokenizer\";\r\nimport { JoinClauseParser } from \"./JoinClauseParser\";\r\nimport { SourceExpressionParser } from \"./SourceExpressionParser\";\r\n\r\nexport class FromClauseParser {\r\n // Parse SQL string to AST (was: parse)\r\n public static parse(query: string): FromClause {\r\n const tokenizer = new SqlTokenizer(query); // Initialize tokenizer\r\n const lexemes = tokenizer.readLexmes(); // Get tokens\r\n\r\n // Parse\r\n const result = this.parseFromLexeme(lexemes, 0);\r\n\r\n // Error if there are remaining tokens\r\n if (result.newIndex < lexemes.length) {\r\n throw new Error(`Syntax error: Unexpected token \"${lexemes[result.newIndex].value}\" at position ${result.newIndex}. The FROM clause is complete but there are additional tokens.`);\r\n }\r\n\r\n return result.value;\r\n }\r\n\r\n // Parse from lexeme array (was: parse)\r\n public static parseFromLexeme(lexemes: Lexeme[], index: number): { value: FromClause; newIndex: number } {\r\n let idx = index;\r\n\r\n if (lexemes[idx].value !== 'from') {\r\n throw new Error(`Syntax error at position ${idx}: Expected 'FROM' keyword but found \"${lexemes[idx].value}\". FROM clauses must start with the FROM keyword.`);\r\n }\r\n idx++;\r\n\r\n if (idx >= lexemes.length) {\r\n throw new Error(`Syntax error: Unexpected end of input after 'FROM' keyword. The FROM clause requires a table reference.`);\r\n }\r\n\r\n // Parse the main source expression\r\n const sourceExpression = SourceExpressionParser.parseFromLexeme(lexemes, idx);\r\n idx = sourceExpression.newIndex;\r\n\r\n const join = JoinClauseParser.tryParse(lexemes, idx);\r\n idx = join?.newIndex || idx;\r\n\r\n if (join !== null) {\r\n const clause = new FromClause(sourceExpression.value, join.value);\r\n return { value: clause, newIndex: idx };\r\n } else {\r\n const clause = new FromClause(sourceExpression.value, null);\r\n return { value: clause, newIndex: idx };\r\n }\r\n }\r\n}", "import { WhereClause } from \"../models/Clause\";\r\nimport { Lexeme } from \"../models/Lexeme\";\r\nimport { SqlTokenizer } from \"./SqlTokenizer\";\r\nimport { ValueParser } from \"./ValueParser\";\r\n\r\nexport class WhereClauseParser {\r\n // Parse SQL string to AST (was: parse)\r\n public static parse(query: string): WhereClause {\r\n const tokenizer = new SqlTokenizer(query); // Initialize tokenizer\r\n const lexemes = tokenizer.readLexmes(); // Get tokens\r\n\r\n // Parse\r\n const result = this.parseFromLexeme(lexemes, 0);\r\n\r\n // Error if there are remaining tokens\r\n if (result.newIndex < lexemes.length) {\r\n throw new Error(`Syntax error: Unexpected token \"${lexemes[result.newIndex].value}\" at position ${result.newIndex}. The WHERE clause is complete but there are additional tokens.`);\r\n }\r\n\r\n return result.value;\r\n }\r\n\r\n // Parse from lexeme array (was: parse)\r\n public static parseFromLexeme(lexemes: Lexeme[], index: number): { value: WhereClause; newIndex: number } {\r\n let idx = index;\r\n\r\n if (lexemes[idx].value !== 'where') {\r\n throw new Error(`Syntax error at position ${idx}: Expected 'WHERE' keyword but found \"${lexemes[idx].value}\". WHERE clauses must start with the WHERE keyword.`);\r\n }\r\n idx++;\r\n\r\n if (idx >= lexemes.length) {\r\n throw new Error(`Syntax error: Unexpected end of input after 'WHERE' keyword. The WHERE clause requires a condition expression.`);\r\n }\r\n\r\n const item = ValueParser.parseFromLexeme(lexemes, idx);\r\n const clause = new WhereClause(item.value);\r\n\r\n return { value: clause, newIndex: item.newIndex };\r\n }\r\n}", "import { GroupByClause } from \"../models/Clause\";\r\nimport { Lexeme, TokenType } from \"../models/Lexeme\";\r\nimport { ValueComponent } from \"../models/ValueComponent\";\r\nimport { SqlTokenizer } from \"./SqlTokenizer\";\r\nimport { ValueParser } from \"./ValueParser\";\r\n\r\nexport class GroupByClauseParser {\r\n // Parse SQL string to AST (was: parse)\r\n public static parse(query: string): GroupByClause {\r\n const tokenizer = new SqlTokenizer(query); // Initialize tokenizer\r\n const lexemes = tokenizer.readLexmes(); // Get tokens\r\n\r\n // Parse\r\n const result = this.parseFromLexeme(lexemes, 0);\r\n\r\n // Error if there are remaining tokens\r\n if (result.newIndex < lexemes.length) {\r\n throw new Error(`Syntax error: Unexpected token \"${lexemes[result.newIndex].value}\" at position ${result.newIndex}. The GROUP BY clause is complete but there are additional tokens.`);\r\n }\r\n\r\n return result.value;\r\n }\r\n\r\n // Parse from lexeme array (was: parse)\r\n public static parseFromLexeme(lexemes: Lexeme[], index: number): { value: GroupByClause; newIndex: number } {\r\n let idx = index;\r\n\r\n if (lexemes[idx].value !== 'group by') {\r\n throw new Error(`Syntax error at position ${idx}: Expected 'GROUP BY' keyword but found \"${lexemes[idx].value}\". GROUP BY clauses must start with the GROUP BY keywords.`);\r\n }\r\n idx++;\r\n\r\n if (idx >= lexemes.length) {\r\n throw new Error(`Syntax error: Unexpected end of input after 'GROUP BY' keyword. The GROUP BY clause requires at least one expression to group by.`);\r\n }\r\n\r\n const items: ValueComponent[] = [];\r\n const item = this.parseItem(lexemes, idx);\r\n items.push(item.value);\r\n idx = item.newIndex;\r\n\r\n while (idx < lexemes.length && (lexemes[idx].type & TokenType.Comma)) {\r\n idx++;\r\n const item = this.parseItem(lexemes, idx);\r\n items.push(item.value);\r\n idx = item.newIndex;\r\n }\r\n\r\n if (items.length === 0) {\r\n throw new Error(`Syntax error at position ${index}: No grouping expressions found. The GROUP BY clause requires at least one expression to group by.`);\r\n } else {\r\n const clause = new GroupByClause(items);\r\n return { value: clause, newIndex: idx };\r\n }\r\n }\r\n\r\n private static parseItem(lexemes: Lexeme[], index: number): { value: ValueComponent; newIndex: number } {\r\n let idx = index;\r\n const parsedValue = ValueParser.parseFromLexeme(lexemes, idx);\r\n const value = parsedValue.value;\r\n idx = parsedValue.newIndex;\r\n return { value, newIndex: idx };\r\n }\r\n}", "import { HavingClause } from \"../models/Clause\";\r\nimport { Lexeme } from \"../models/Lexeme\";\r\nimport { SqlTokenizer } from \"./SqlTokenizer\";\r\nimport { ValueParser } from \"./ValueParser\";\r\n\r\nexport class HavingClauseParser {\r\n // Parse SQL string to AST (was: parse)\r\n public static parse(query: string): HavingClause {\r\n const tokenizer = new SqlTokenizer(query); // Initialize tokenizer\r\n const lexemes = tokenizer.readLexmes(); // Get tokens\r\n\r\n // Parse\r\n const result = this.parseFromLexeme(lexemes, 0);\r\n\r\n // Error if there are remaining tokens\r\n if (result.newIndex < lexemes.length) {\r\n throw new Error(`Syntax error: Unexpected token \"${lexemes[result.newIndex].value}\" at position ${result.newIndex}. The HAVING clause is complete but there are additional tokens.`);\r\n }\r\n\r\n return result.value;\r\n }\r\n\r\n // Parse from lexeme array (was: parse)\r\n public static parseFromLexeme(lexemes: Lexeme[], index: number): { value: HavingClause; newIndex: number } {\r\n let idx = index;\r\n\r\n if (lexemes[idx].value !== 'having') {\r\n throw new Error(`Syntax error at position ${idx}: Expected 'HAVING' keyword but found \"${lexemes[idx].value}\". HAVING clauses must start with the HAVING keyword.`);\r\n }\r\n idx++;\r\n\r\n if (idx >= lexemes.length) {\r\n throw new Error(`Syntax error: Unexpected end of input after 'HAVING' keyword. The HAVING clause requires a condition expression.`);\r\n }\r\n\r\n const item = ValueParser.parseFromLexeme(lexemes, idx);\r\n const clause = new HavingClause(item.value);\r\n\r\n return { value: clause, newIndex: item.newIndex };\r\n }\r\n}", "import { WindowFrameClause, WindowsClause } from \"../models/Clause\";\r\nimport { Lexeme, TokenType } from \"../models/Lexeme\";\r\nimport { SqlTokenizer } from \"./SqlTokenizer\";\r\nimport { WindowExpressionParser } from \"./WindowExpressionParser\";\r\n\r\nexport class WindowClauseParser {\r\n // Parse SQL string to AST (was: parse)\r\n public static parse(query: string): WindowsClause {\r\n const tokenizer = new SqlTokenizer(query);\r\n const lexemes = tokenizer.readLexmes();\r\n const result = this.parseFromLexeme(lexemes, 0);\r\n if (result.newIndex < lexemes.length) {\r\n throw new Error(`Syntax error: Unexpected token \"${lexemes[result.newIndex].value}\" at position ${result.newIndex}. The WINDOW clause is complete but there are additional tokens.`);\r\n }\r\n return result.value;\r\n }\r\n\r\n // Parse from lexeme array (was: parse)\r\n public static parseFromLexeme(lexemes: Lexeme[], index: number): { value: WindowsClause; newIndex: number } {\r\n let idx = index;\r\n\r\n if (lexemes[idx].value !== 'window') {\r\n throw new Error(`Syntax error at position ${idx}: Expected 'WINDOW' keyword but found \"${lexemes[idx].value}\". WINDOW clauses must start with the WINDOW keyword.`);\r\n }\r\n idx++;\r\n\r\n if (idx >= lexemes.length) {\r\n throw new Error(`Syntax error: Unexpected end of input after 'WINDOW' keyword. The WINDOW clause requires at least one window definition.`);\r\n }\r\n\r\n const windows: WindowFrameClause[] = [];\r\n while (idx < lexemes.length) {\r\n\r\n if (idx >= lexemes.length || lexemes[idx].type !== TokenType.Identifier) {\r\n throw new Error(`Syntax error: Expected window name after 'WINDOW' keyword.`);\r\n }\r\n const name = lexemes[idx].value;\r\n idx++;\r\n if (idx >= lexemes.length || lexemes[idx].value !== 'as') {\r\n throw new Error(`Syntax error at position ${idx}: Expected 'AS' keyword after window name.`);\r\n }\r\n idx++;\r\n const expr = WindowExpressionParser.parseFromLexeme(lexemes, idx);\r\n idx = expr.newIndex;\r\n windows.push(new WindowFrameClause(name, expr.value));\r\n\r\n if (idx < lexemes.length && lexemes[idx].type & TokenType.Comma) {\r\n idx++;\r\n } else {\r\n break;\r\n }\r\n }\r\n\r\n if (windows.length === 0) {\r\n throw new Error('At least one WINDOW clause is required after WINDOW keyword.');\r\n }\r\n return { value: new WindowsClause(windows), newIndex: idx };\r\n }\r\n}", "import { LimitClause as LimitClause } from \"../models/Clause\";\r\nimport { Lexeme } from \"../models/Lexeme\";\r\nimport { SqlTokenizer } from \"./SqlTokenizer\";\r\nimport { ValueParser } from \"./ValueParser\";\r\n\r\nexport class LimitClauseParser {\r\n // Parse SQL string to AST (was: parse)\r\n public static parse(query: string): LimitClause {\r\n const tokenizer = new SqlTokenizer(query); // Initialize tokenizer\r\n const lexemes = tokenizer.readLexmes(); // Get tokens\r\n\r\n // Parse\r\n const result = this.parseFromLexeme(lexemes, 0);\r\n\r\n // Error if there are remaining tokens\r\n if (result.newIndex < lexemes.length) {\r\n throw new Error(`Syntax error: Unexpected token \"${lexemes[result.newIndex].value}\" at position ${result.newIndex}. The LIMIT clause is complete but there are additional tokens.`);\r\n }\r\n\r\n return result.value;\r\n }\r\n\r\n // Parse from lexeme array (was: parse)\r\n public static parseFromLexeme(lexemes: Lexeme[], index: number): { value: LimitClause; newIndex: number } {\r\n let idx = index;\r\n\r\n if (lexemes[idx].value !== 'limit') {\r\n throw new Error(`Syntax error at position ${idx}: Expected 'LIMIT' keyword but found \"${lexemes[idx].value}\". LIMIT clauses must start with the LIMIT keyword.`);\r\n }\r\n idx++;\r\n\r\n if (idx >= lexemes.length) {\r\n throw new Error(`Syntax error: Unexpected end of input after 'LIMIT' keyword. The LIMIT clause requires a numeric expression.`);\r\n }\r\n\r\n // Parse LIMIT value\r\n const limitItem = ValueParser.parseFromLexeme(lexemes, idx);\r\n idx = limitItem.newIndex;\r\n\r\n const clause = new LimitClause(limitItem.value);\r\n\r\n return { value: clause, newIndex: idx };\r\n }\r\n}", "import { ForClause, LockMode } from \"../models/Clause\";\r\nimport { Lexeme } from \"../models/Lexeme\";\r\nimport { SqlTokenizer } from \"./SqlTokenizer\";\r\n\r\nexport class ForClauseParser {\r\n // Parse SQL string to AST (was: parse)\r\n public static parse(query: string): ForClause {\r\n const tokenizer = new SqlTokenizer(query);\r\n const lexemes = tokenizer.readLexmes();\r\n\r\n // Parse\r\n const result = this.parseFromLexeme(lexemes, 0);\r\n\r\n // Error if there are remaining tokens\r\n if (result.newIndex < lexemes.length) {\r\n throw new Error(`Syntax error: Unexpected token \"${lexemes[result.newIndex].value}\" at position ${result.newIndex}. The FOR clause is complete but there are additional tokens.`);\r\n }\r\n\r\n return result.value;\r\n }\r\n\r\n // Parse from lexeme array (was: parse)\r\n public static parseFromLexeme(lexemes: Lexeme[], index: number): { value: ForClause; newIndex: number } {\r\n let idx = index;\r\n\r\n // Check for FOR keyword\r\n if (lexemes[idx].value.toLowerCase() !== 'for') {\r\n throw new Error(`Syntax error at position ${idx}: Expected 'FOR' keyword but found \"${lexemes[idx].value}\". FOR clauses must start with the FOR keyword.`);\r\n }\r\n idx++;\r\n\r\n if (idx >= lexemes.length) {\r\n throw new Error(`Syntax error: Unexpected end of input after 'FOR' keyword. The FOR clause requires a lock mode specification.`);\r\n }\r\n\r\n // Parse lock mode\r\n const lockModeValue = lexemes[idx].value;\r\n let lockMode: LockMode;\r\n\r\n switch (lockModeValue) {\r\n case 'update':\r\n lockMode = LockMode.Update;\r\n idx++;\r\n break;\r\n case 'share':\r\n lockMode = LockMode.Share;\r\n idx++;\r\n break;\r\n case 'key share':\r\n lockMode = LockMode.KeyShare;\r\n idx++;\r\n break;\r\n case 'no key update':\r\n lockMode = LockMode.NokeyUpdate;\r\n idx++;\r\n break;\r\n default:\r\n throw new Error(`Syntax error at position ${idx}: Invalid lock mode \"${lockModeValue}\". Valid lock modes are: UPDATE, SHARE, KEY SHARE, NO KEY UPDATE.`);\r\n }\r\n\r\n const clause = new ForClause(lockMode);\r\n return { value: clause, newIndex: idx };\r\n }\r\n}", "import { CommonTable } from \"../models/Clause\";\r\nimport { Lexeme, TokenType } from \"../models/Lexeme\";\r\nimport { SqlTokenizer } from \"./SqlTokenizer\";\r\nimport { SelectQueryParser } from \"./SelectQueryParser\";\r\nimport { SourceAliasExpressionParser } from \"./SourceAliasExpressionParser\";\r\n\r\nexport class CommonTableParser {\r\n // Parse SQL string to AST (was: parse)\r\n public static parse(query: string): CommonTable {\r\n const tokenizer = new SqlTokenizer(query); // Initialize tokenizer\r\n const lexemes = tokenizer.readLexmes(); // Get tokens\r\n\r\n // Parse\r\n const result = this.parseFromLexeme(lexemes, 0);\r\n\r\n // Error if there are remaining tokens\r\n if (result.newIndex < lexemes.length) {\r\n throw new Error(`Syntax error: Unexpected token \"${lexemes[result.newIndex].value}\" at position ${result.newIndex}. The CommonTable definition is complete but there are additional tokens.`);\r\n }\r\n\r\n return result.value;\r\n }\r\n\r\n // Parse from lexeme array (was: parse)\r\n public static parseFromLexeme(lexemes: Lexeme[], index: number): { value: CommonTable; newIndex: number } {\r\n let idx = index;\r\n\r\n // Parse alias and optional column aliases\r\n // SourceAliasExpressionParser already handles column aliases if present\r\n const aliasResult = SourceAliasExpressionParser.parseFromLexeme(lexemes, idx);\r\n idx = aliasResult.newIndex;\r\n\r\n if (idx < lexemes.length && lexemes[idx].value !== \"as\") {\r\n throw new Error(`Syntax error at position ${idx}: Expected 'AS' keyword after CTE name but found \"${lexemes[idx].value}\".`);\r\n }\r\n idx++; // Skip 'AS' keyword\r\n\r\n // Materialized flag\r\n let materialized: boolean | null = null;\r\n\r\n // Parse optional MATERIALIZED or NOT MATERIALIZED keywords\r\n if (idx < lexemes.length) {\r\n const currentValue = lexemes[idx].value;\r\n if (currentValue === \"materialized\") {\r\n materialized = true;\r\n idx++;\r\n } else if (currentValue === \"not materialized\") {\r\n materialized = false;\r\n idx++;\r\n }\r\n }\r\n\r\n if (idx < lexemes.length && lexemes[idx].type !== TokenType.OpenParen) {\r\n throw new Error(`Syntax error at position ${idx}: Expected '(' after CTE name but found \"${lexemes[idx].value}\".`);\r\n }\r\n idx++; // Skip opening parenthesis\r\n\r\n const queryResult = SelectQueryParser.parseFromLexeme(lexemes, idx);\r\n idx = queryResult.newIndex;\r\n\r\n if (idx < lexemes.length && lexemes[idx].type !== TokenType.CloseParen) {\r\n throw new Error(`Syntax error at position ${idx}: Expected ')' after CTE query but found \"${lexemes[idx].value}\".`);\r\n }\r\n idx++; // Skip closing parenthesis\r\n\r\n const value = new CommonTable(queryResult.value, aliasResult.value, materialized);\r\n return { value, newIndex: idx };\r\n }\r\n}", "import { CommonTable, WithClause } from \"../models/Clause\";\r\nimport { Lexeme, TokenType } from \"../models/Lexeme\";\r\nimport { SqlTokenizer } from \"./SqlTokenizer\";\r\nimport { CommonTableParser } from \"./CommonTableParser\";\r\n\r\nexport class WithClauseParser {\r\n // Parse SQL string to AST (was: parse)\r\n public static parse(query: string): WithClause {\r\n const tokenizer = new SqlTokenizer(query); // Initialize tokenizer\r\n const lexemes = tokenizer.readLexmes(); // Get tokens\r\n\r\n // Parse\r\n const result = this.parseFromLexeme(lexemes, 0);\r\n\r\n // Error if there are remaining tokens\r\n if (result.newIndex < lexemes.length) {\r\n throw new Error(`Syntax error: Unexpected token \"${lexemes[result.newIndex].value}\" at position ${result.newIndex}. The WITH clause is complete but there are additional tokens.`);\r\n }\r\n\r\n return result.value;\r\n }\r\n\r\n // Parse from lexeme array (was: parse)\r\n public static parseFromLexeme(lexemes: Lexeme[], index: number): { value: WithClause; newIndex: number } {\r\n let idx = index;\r\n\r\n // Expect WITH keyword\r\n if (idx < lexemes.length && lexemes[idx].value.toLowerCase() === \"with\") {\r\n idx++;\r\n } else {\r\n throw new Error(`Syntax error at position ${idx}: Expected WITH keyword.`);\r\n }\r\n\r\n // Check for RECURSIVE keyword\r\n const recursive = idx < lexemes.length && lexemes[idx].value.toLowerCase() === \"recursive\";\r\n if (recursive) {\r\n idx++;\r\n }\r\n\r\n // Parse CTEs\r\n const tables: CommonTable[] = [];\r\n\r\n // Parse first CTE (required)\r\n const firstCte = CommonTableParser.parseFromLexeme(lexemes, idx);\r\n tables.push(firstCte.value);\r\n idx = firstCte.newIndex;\r\n\r\n // Parse additional CTEs (optional)\r\n while (idx < lexemes.length && (lexemes[idx].type & TokenType.Comma)) {\r\n idx++; // Skip comma\r\n const cteResult = CommonTableParser.parseFromLexeme(lexemes, idx);\r\n tables.push(cteResult.value);\r\n idx = cteResult.newIndex;\r\n }\r\n\r\n // Create WITH clause\r\n return {\r\n value: new WithClause(recursive, tables),\r\n newIndex: idx\r\n };\r\n }\r\n}", "import { Lexeme, TokenType } from \"../models/Lexeme\";\r\nimport { ValuesQuery } from \"../models/SelectQuery\";\r\nimport { TupleExpression, ValueComponent } from \"../models/ValueComponent\";\r\nimport { SqlTokenizer } from \"./SqlTokenizer\";\r\nimport { ValueParser } from \"./ValueParser\";\r\n\r\nexport class ValuesQueryParser {\r\n public static parse(query: string): ValuesQuery {\r\n const tokenizer = new SqlTokenizer(query); // Initialize tokenizer\r\n const lexemes = tokenizer.readLexmes(); // Get tokens\r\n\r\n // Parse\r\n const result = this.parseFromLexeme(lexemes, 0);\r\n\r\n // Error if there are remaining tokens\r\n if (result.newIndex < lexemes.length) {\r\n throw new Error(`Syntax error: Unexpected token \"${lexemes[result.newIndex].value}\" at position ${result.newIndex}. The VALUES clause is complete but there are additional tokens.`);\r\n }\r\n\r\n return result.value;\r\n }\r\n\r\n public static parseFromLexeme(lexemes: Lexeme[], index: number): { value: ValuesQuery; newIndex: number } {\r\n let idx = index;\r\n\r\n if (lexemes[idx].value.toLowerCase() !== 'values') {\r\n throw new Error(`Syntax error at position ${idx}: Expected 'VALUES' keyword but found \"${lexemes[idx].value}\". VALUES clauses must start with the VALUES keyword.`);\r\n }\r\n idx++;\r\n\r\n if (idx >= lexemes.length) {\r\n throw new Error(`Syntax error: Unexpected end of input after 'VALUES' keyword. The VALUES clause requires at least one tuple expression.`);\r\n }\r\n\r\n const tuples: TupleExpression[] = [];\r\n\r\n // Parse the first tuple\r\n const firstTuple = this.parseTuple(lexemes, idx);\r\n tuples.push(firstTuple.value);\r\n idx = firstTuple.newIndex;\r\n\r\n // Parse additional tuples if they exist\r\n while (idx < lexemes.length && (lexemes[idx].type & TokenType.Comma)) {\r\n idx++; // Skip comma\r\n const tuple = this.parseTuple(lexemes, idx);\r\n tuples.push(tuple.value);\r\n idx = tuple.newIndex;\r\n }\r\n\r\n const query = new ValuesQuery(tuples);\r\n return { value: query, newIndex: idx };\r\n }\r\n\r\n private static parseTuple(lexemes: Lexeme[], index: number): { value: TupleExpression; newIndex: number } {\r\n let idx = index;\r\n\r\n // Check for opening parenthesis\r\n if (idx >= lexemes.length || lexemes[idx].type !== TokenType.OpenParen) {\r\n throw new Error(`Syntax error at position ${idx}: Expected opening parenthesis but found \"${idx < lexemes.length ? lexemes[idx].value : \"end of input\"}\". Tuple expressions in VALUES clause must be enclosed in parentheses.`);\r\n }\r\n idx++;\r\n\r\n // Parse values inside the tuple\r\n const values: ValueComponent[] = [];\r\n\r\n // Parse first value\r\n if (idx >= lexemes.length) {\r\n throw new Error(`Syntax error: Unexpected end of input after opening parenthesis in tuple expression.`);\r\n }\r\n\r\n // Check for empty tuple case\r\n if (lexemes[idx].type & TokenType.CloseParen) {\r\n idx++; // Skip closing parenthesis\r\n return { value: new TupleExpression([]), newIndex: idx };\r\n }\r\n\r\n // Parse the first value\r\n const firstValue = ValueParser.parseFromLexeme(lexemes, idx);\r\n values.push(firstValue.value);\r\n idx = firstValue.newIndex;\r\n\r\n // Parse additional values\r\n while (idx < lexemes.length && (lexemes[idx].type & TokenType.Comma)) {\r\n idx++; // Skip comma\r\n\r\n if (idx >= lexemes.length) {\r\n throw new Error(`Syntax error: Unexpected end of input after comma in tuple expression.`);\r\n }\r\n\r\n const value = ValueParser.parseFromLexeme(lexemes, idx);\r\n values.push(value.value);\r\n idx = value.newIndex;\r\n }\r\n\r\n // Check for closing parenthesis\r\n if (idx >= lexemes.length || lexemes[idx].type !== TokenType.CloseParen) {\r\n throw new Error(`Syntax error at position ${idx}: Expected closing parenthesis but found \"${idx < lexemes.length ? lexemes[idx].value : \"end of input\"}\". Tuple expressions in VALUES clause must be enclosed in parentheses.`);\r\n }\r\n idx++; // Skip closing parenthesis\r\n\r\n return { value: new TupleExpression(values), newIndex: idx };\r\n }\r\n}", "import { FetchClause, FetchType, FetchUnit, FetchExpression } from \"../models/Clause\";\r\nimport { Lexeme } from \"../models/Lexeme\";\r\nimport { LiteralValue, ValueComponent } from \"../models/ValueComponent\";\r\nimport { ValueParser } from \"./ValueParser\";\r\n\r\nexport class FetchClauseParser {\r\n /**\r\n * Parses a FETCH clause from a lexeme array starting at the given index.\r\n * Supports syntax like: FETCH [FIRST|NEXT] <count> ROWS ONLY\r\n * @param lexemes The array of lexemes\r\n * @param index The starting index\r\n * @returns { value: FetchSpecification, newIndex: number }\r\n */\r\n public static parseFromLexeme(lexemes: Lexeme[], index: number): { value: FetchClause; newIndex: number } {\r\n let idx = index;\r\n if (lexemes[idx].value !== 'fetch') {\r\n throw new Error(`Syntax error at position ${idx}: Expected 'FETCH' keyword but found \"${lexemes[idx].value}\".`);\r\n }\r\n idx++;\r\n if (idx >= lexemes.length) {\r\n throw new Error(`Syntax error: Unexpected end of input after 'FETCH' keyword.`);\r\n }\r\n\r\n const fetchExprResult = FetchExpressionParser.parseFromLexeme(lexemes, idx);\r\n const fetchExpr = fetchExprResult.value;\r\n idx = fetchExprResult.newIndex;\r\n\r\n return { value: new FetchClause(fetchExpr), newIndex: idx };\r\n }\r\n}\r\n\r\n// FetchExpressionParser: parses FETCH [FIRST|NEXT] <count> ROWS ONLY ...\r\nexport class FetchExpressionParser {\r\n /**\r\n * Parses a FETCH expression (not the whole clause, just the fetch part)\r\n */\r\n public static parseFromLexeme(lexemes: Lexeme[], index: number): { value: FetchExpression; newIndex: number } {\r\n let idx = index;\r\n let type: FetchType;\r\n const typeToken = lexemes[idx].value;\r\n if (typeToken === 'first') {\r\n type = FetchType.First;\r\n } else if (typeToken === 'next') {\r\n type = FetchType.Next;\r\n } else {\r\n throw new Error(`Syntax error at position ${idx}: Expected 'FIRST' or 'NEXT' after 'FETCH' but found \"${lexemes[idx].value}\".`);\r\n }\r\n idx++;\r\n if (idx >= lexemes.length) {\r\n throw new Error(`Syntax error: Unexpected end of input after 'FETCH FIRST|NEXT'.`);\r\n }\r\n\r\n let count: ValueComponent | null = null;\r\n let unit: FetchUnit | null = null;\r\n\r\n // Omitted count notation\r\n if (lexemes[idx].value === 'row only' || lexemes[idx].value === 'rows only') {\r\n count = new LiteralValue(1);\r\n unit = FetchUnit.RowsOnly;\r\n idx++;\r\n return { value: new FetchExpression(type, count, unit), newIndex: idx };\r\n }\r\n\r\n // <count>\r\n const countResult = ValueParser.parseFromLexeme(lexemes, idx);\r\n count = countResult.value;\r\n idx = countResult.newIndex;\r\n if (idx >= lexemes.length) {\r\n throw new Error(`Syntax error: Unexpected end of input after 'FETCH FIRST|NEXT <count>'.`);\r\n }\r\n // ROWS ONLY (or other unit)\r\n\r\n if (lexemes[idx].value === 'rows only') {\r\n unit = FetchUnit.RowsOnly;\r\n idx++;\r\n } else if (lexemes[idx].value === 'percent') {\r\n unit = FetchUnit.Percent;\r\n idx++;\r\n } else if (lexemes[idx].value === 'percent with ties') {\r\n unit = FetchUnit.PercentWithTies;\r\n idx++;\r\n }\r\n if (!unit) {\r\n throw new Error(`Syntax error: Expected 'ROWS ONLY', 'PERCENT', or 'PERCENT WITH TIES' after 'FETCH FIRST|NEXT <count>'.`);\r\n }\r\n return { value: new FetchExpression(type, count, unit), newIndex: idx };\r\n }\r\n}\r\n", "import { OffsetClause } from \"../models/Clause\";\r\nimport { Lexeme } from \"../models/Lexeme\";\r\nimport { SqlTokenizer } from \"./SqlTokenizer\";\r\nimport { ValueParser } from \"./ValueParser\";\r\n\r\nexport class OffsetClauseParser {\r\n // Parse SQL string to AST (was: parse)\r\n public static parse(query: string): OffsetClause {\r\n const tokenizer = new SqlTokenizer(query); // Initialize tokenizer\r\n const lexemes = tokenizer.readLexmes(); // Get tokens\r\n\r\n // Parse\r\n const result = this.parseFromLexeme(lexemes, 0);\r\n\r\n // Error if there are remaining tokens\r\n if (result.newIndex < lexemes.length) {\r\n throw new Error(`Syntax error: Unexpected token \"${lexemes[result.newIndex].value}\" at position ${result.newIndex}. The OFFSET clause is complete but there are additional tokens.`);\r\n }\r\n\r\n return result.value;\r\n }\r\n\r\n // Parse from lexeme array (was: parse)\r\n public static parseFromLexeme(lexemes: Lexeme[], index: number): { value: OffsetClause; newIndex: number } {\r\n let idx = index;\r\n\r\n if (lexemes[idx].value !== 'offset') {\r\n throw new Error(`Syntax error at position ${idx}: Expected 'OFFSET' keyword but found \"${lexemes[idx].value}\". OFFSET clauses must start with the OFFSET keyword.`);\r\n }\r\n idx++;\r\n\r\n if (idx >= lexemes.length) {\r\n throw new Error(`Syntax error: Unexpected end of input after 'OFFSET' keyword. The OFFSET clause requires a numeric expression.`);\r\n }\r\n\r\n // Parse OFFSET value\r\n const offsetItem = ValueParser.parseFromLexeme(lexemes, idx);\r\n idx = offsetItem.newIndex;\r\n\r\n // If there is a \"row\" or \"rows\" command, skip it\r\n if (idx < lexemes.length && (lexemes[idx].value === 'row' || lexemes[idx].value === 'rows')) {\r\n idx++;\r\n }\r\n\r\n const clause = new OffsetClause(offsetItem.value);\r\n\r\n return { value: clause, newIndex: idx };\r\n }\r\n}\r\n", "import { Lexeme } from \"../models/Lexeme\";\r\nimport { BinarySelectQuery, SelectQuery, SimpleSelectQuery } from \"../models/SelectQuery\";\r\nimport { SelectClauseParser } from \"./SelectClauseParser\";\r\nimport { FromClauseParser } from \"./FromClauseParser\";\r\nimport { WhereClauseParser } from \"./WhereClauseParser\";\r\nimport { GroupByClauseParser } from \"./GroupByParser\";\r\nimport { HavingClauseParser } from \"./HavingParser\";\r\nimport { OrderByClauseParser } from \"./OrderByClauseParser\";\r\nimport { WindowClauseParser } from \"./WindowClauseParser\";\r\nimport { LimitClauseParser } from \"./LimitClauseParser\";\r\nimport { ForClauseParser } from \"./ForClauseParser\";\r\nimport { SqlTokenizer } from \"./SqlTokenizer\";\r\nimport { WithClauseParser } from \"./WithClauseParser\";\r\nimport { ValuesQueryParser } from \"./ValuesQueryParser\";\r\nimport { FetchClauseParser } from \"./FetchClauseParser\";\r\nimport { OffsetClauseParser } from \"./OffsetClauseParser\";\r\n\r\nexport class SelectQueryParser {\r\n // Parse SQL string to AST (was: parse)\r\n public static parse(query: string): SelectQuery {\r\n const tokenizer = new SqlTokenizer(query);\r\n const lexemes = tokenizer.readLexmes();\r\n\r\n // Parse\r\n const result = this.parseFromLexeme(lexemes, 0);\r\n\r\n // Error if there are remaining tokens\r\n if (result.newIndex < lexemes.length) {\r\n throw new Error(`[SelectQueryParser] Syntax error: Unexpected token \"${lexemes[result.newIndex].value}\" at position ${result.newIndex}. The SELECT query is complete but there are additional tokens.`);\r\n }\r\n\r\n return result.value;\r\n }\r\n\r\n /**\r\n * Asynchronously parse SQL string to AST.\r\n * This method wraps the synchronous parse logic in a Promise for future extensibility.\r\n * @param query SQL string to parse\r\n * @returns Promise<SelectQuery>\r\n */\r\n public static async parseAsync(query: string): Promise<SelectQuery> {\r\n // For now, just wrap the sync parse in a resolved Promise\r\n return Promise.resolve(this.parse(query));\r\n }\r\n\r\n private static unionCommandSet = new Set<string>([\r\n \"union\",\r\n \"union all\",\r\n \"intersect\",\r\n \"intersect all\",\r\n \"except\",\r\n \"except all\",\r\n ]);\r\n private static selectCommandSet = new Set<string>([\"with\", \"select\"]);\r\n\r\n // Parse from lexeme array (was: parse)\r\n public static parseFromLexeme(lexemes: Lexeme[], index: number): { value: SelectQuery; newIndex: number } {\r\n let idx = index;\r\n\r\n if (idx >= lexemes.length) {\r\n throw new Error(`Syntax error: Unexpected end of input at position ${index}.`);\r\n }\r\n\r\n // Check if the first token is a SELECT keyword or VALUES\r\n const firstToken = lexemes[idx].value;\r\n if (!this.selectCommandSet.has(firstToken) && firstToken !== 'values') {\r\n throw new Error(`Syntax error at position ${idx}: Expected 'SELECT' or 'VALUES' keyword but found \"${lexemes[idx].value}\".`);\r\n }\r\n\r\n let firstResult = this.selectCommandSet.has(firstToken)\r\n ? this.parseSimpleSelectQuery(lexemes, idx)\r\n : this.parseValuesQuery(lexemes, idx);\r\n\r\n let query: SelectQuery = firstResult.value;\r\n idx = firstResult.newIndex;\r\n\r\n // check 'union'\r\n while (idx < lexemes.length && this.unionCommandSet.has(lexemes[idx].value.toLowerCase())) {\r\n const operator = lexemes[idx].value.toLowerCase();\r\n idx++;\r\n if (idx >= lexemes.length) {\r\n throw new Error(`Syntax error at position ${idx}: Expected a query after '${operator.toUpperCase()}' but found end of input.`);\r\n }\r\n\r\n const nextToken = lexemes[idx].value.toLowerCase();\r\n if (this.selectCommandSet.has(nextToken)) {\r\n const result = this.parseSimpleSelectQuery(lexemes, idx);\r\n query = new BinarySelectQuery(query, operator, result.value);\r\n idx = result.newIndex;\r\n } else if (nextToken === 'values') {\r\n const result = this.parseValuesQuery(lexemes, idx);\r\n query = new BinarySelectQuery(query, operator, result.value);\r\n idx = result.newIndex;\r\n } else {\r\n throw new Error(`Syntax error at position ${idx}: Expected 'SELECT' or 'VALUES' after '${operator.toUpperCase()}' but found \"${lexemes[idx].value}\".`);\r\n }\r\n }\r\n\r\n return { value: query, newIndex: idx };\r\n }\r\n\r\n private static parseSimpleSelectQuery(lexemes: Lexeme[], index: number): { value: SimpleSelectQuery; newIndex: number } {\r\n let idx = index;\r\n let withClauseResult = null;\r\n\r\n // Parse optional WITH clause\r\n if (idx < lexemes.length && lexemes[idx].value === 'with') {\r\n withClauseResult = WithClauseParser.parseFromLexeme(lexemes, idx);\r\n idx = withClauseResult.newIndex;\r\n }\r\n\r\n // Parse SELECT clause (required)\r\n if (idx >= lexemes.length || lexemes[idx].value !== 'select') {\r\n throw new Error(`Syntax error at position ${idx}: Expected 'SELECT' keyword but found \"${idx < lexemes.length ? lexemes[idx].value : 'end of input'}\". SELECT queries must start with the SELECT keyword.`);\r\n }\r\n\r\n const selectClauseResult = SelectClauseParser.parseFromLexeme(lexemes, idx);\r\n idx = selectClauseResult.newIndex;\r\n\r\n // Parse FROM clause (optional)\r\n let fromClauseResult = null;\r\n if (idx < lexemes.length && lexemes[idx].value === 'from') {\r\n fromClauseResult = FromClauseParser.parseFromLexeme(lexemes, idx);\r\n idx = fromClauseResult.newIndex;\r\n }\r\n\r\n // Parse WHERE clause (optional)\r\n let whereClauseResult = null;\r\n if (idx < lexemes.length && lexemes[idx].value === 'where') {\r\n whereClauseResult = WhereClauseParser.parseFromLexeme(lexemes, idx);\r\n idx = whereClauseResult.newIndex;\r\n }\r\n\r\n // Parse GROUP BY clause (optional)\r\n let groupByClauseResult = null;\r\n if (idx < lexemes.length && lexemes[idx].value === 'group by') {\r\n groupByClauseResult = GroupByClauseParser.parseFromLexeme(lexemes, idx);\r\n idx = groupByClauseResult.newIndex;\r\n }\r\n\r\n // Parse HAVING clause (optional)\r\n let havingClauseResult = null;\r\n if (idx < lexemes.length && lexemes[idx].value === 'having') {\r\n havingClauseResult = HavingClauseParser.parseFromLexeme(lexemes, idx);\r\n idx = havingClauseResult.newIndex;\r\n }\r\n\r\n // Parse WINDOW clause (optional)\r\n let windowClauseResult = null;\r\n if (idx < lexemes.length && lexemes[idx].value === 'window') {\r\n windowClauseResult = WindowClauseParser.parseFromLexeme(lexemes, idx);\r\n idx = windowClauseResult.newIndex;\r\n }\r\n\r\n // Parse ORDER BY clause (optional)\r\n let orderByClauseResult = null;\r\n if (idx < lexemes.length && lexemes[idx].value === 'order by') {\r\n orderByClauseResult = OrderByClauseParser.parseFromLexeme(lexemes, idx);\r\n idx = orderByClauseResult.newIndex;\r\n }\r\n\r\n // Parse LIMIT clause (optional)\r\n let limitClauseResult = null;\r\n if (idx < lexemes.length && lexemes[idx].value === 'limit') {\r\n limitClauseResult = LimitClauseParser.parseFromLexeme(lexemes, idx);\r\n idx = limitClauseResult.newIndex;\r\n }\r\n\r\n // Parse OFFSET clause (optional)\r\n let offsetClauseResult = null;\r\n if (idx < lexemes.length && lexemes[idx].value === 'offset') {\r\n offsetClauseResult = OffsetClauseParser.parseFromLexeme(lexemes, idx);\r\n idx = offsetClauseResult.newIndex;\r\n }\r\n\r\n // Parse FETCH clause (optional)\r\n let fetchClauseResult = null;\r\n if (idx < lexemes.length && lexemes[idx].value === 'fetch') {\r\n fetchClauseResult = FetchClauseParser.parseFromLexeme(lexemes, idx);\r\n idx = fetchClauseResult.newIndex;\r\n }\r\n\r\n // Parse FOR clause (optional)\r\n let forClauseResult = null;\r\n if (idx < lexemes.length && lexemes[idx].value.toLowerCase() === 'for') {\r\n forClauseResult = ForClauseParser.parseFromLexeme(lexemes, idx);\r\n idx = forClauseResult.newIndex;\r\n }\r\n\r\n // Create and return the SelectQuery object\r\n const selectQuery = new SimpleSelectQuery({\r\n withClause: withClauseResult ? withClauseResult.value : null,\r\n selectClause: selectClauseResult.value,\r\n fromClause: fromClauseResult ? fromClauseResult.value : null,\r\n whereClause: whereClauseResult ? whereClauseResult.value : null,\r\n groupByClause: groupByClauseResult ? groupByClauseResult.value : null,\r\n havingClause: havingClauseResult ? havingClauseResult.value : null,\r\n orderByClause: orderByClauseResult ? orderByClauseResult.value : null,\r\n windowClause: windowClauseResult ? windowClauseResult.value : null,\r\n limitClause: limitClauseResult ? limitClauseResult.value : null,\r\n offsetClause: offsetClauseResult ? offsetClauseResult.value : null,\r\n fetchClause: fetchClauseResult ? fetchClauseResult.value : null,\r\n forClause: forClauseResult ? forClauseResult.value : null\r\n });\r\n\r\n return { value: selectQuery, newIndex: idx };\r\n }\r\n\r\n private static parseValuesQuery(lexemes: Lexeme[], index: number): { value: SelectQuery; newIndex: number } {\r\n // Use ValuesQueryParser to parse VALUES clause\r\n const result = ValuesQueryParser.parseFromLexeme(lexemes, index);\r\n\r\n // Return the result from ValuesQueryParser directly\r\n return { value: result.value, newIndex: result.newIndex };\r\n }\r\n}", "// filepath: src/parsers/InsertQueryParser.ts\r\n// Provides parsing for INSERT queries, supporting optional columns and WITH/SELECT/VALUES structure.\r\nimport { InsertQuery } from \"../models/InsertQuery\";\r\nimport { Lexeme, TokenType } from \"../models/Lexeme\";\r\nimport { SqlTokenizer } from \"./SqlTokenizer\";\r\nimport { SelectQueryParser } from \"./SelectQueryParser\";\r\nimport { WithClause } from \"../models/Clause\";\r\nimport { WithClauseParser } from \"./WithClauseParser\";\r\nimport { SimpleSelectQuery } from \"../models/SimpleSelectQuery\";\r\nimport { SourceExpressionParser } from \"./SourceExpressionParser\";\r\nimport { InsertClause } from \"../models/Clause\";\r\n\r\nexport class InsertQueryParser {\r\n /**\r\n * Parse SQL string to InsertQuery AST.\r\n * @param query SQL string\r\n */\r\n public static parse(query: string): InsertQuery {\r\n const tokenizer = new SqlTokenizer(query);\r\n const lexemes = tokenizer.readLexmes();\r\n const result = this.parseFromLexeme(lexemes, 0);\r\n if (result.newIndex < lexemes.length) {\r\n throw new Error(`Syntax error: Unexpected token \"${lexemes[result.newIndex].value}\" at position ${result.newIndex}. The INSERT query is complete but there are additional tokens.`);\r\n }\r\n return result.value;\r\n }\r\n\r\n /**\r\n * Parse from lexeme array (for internal use and tests)\r\n */\r\n public static parseFromLexeme(lexemes: Lexeme[], index: number): { value: InsertQuery; newIndex: number } {\r\n let idx = index;\r\n\r\n let withclause: WithClause | null = null;\r\n if (lexemes[idx].value === \"with\") {\r\n const result = WithClauseParser.parseFromLexeme(lexemes, idx);\r\n withclause = result.value;\r\n idx = result.newIndex;\r\n }\r\n\r\n // Expect INSERT INTO\r\n if (lexemes[idx].value !== \"insert into\") {\r\n throw new Error(`Syntax error at position ${idx}: Expected 'INSERT INTO' but found '${lexemes[idx].value}'.`);\r\n }\r\n idx++;\r\n\r\n // Parse table and optional alias/schema using SourceExpressionParser\r\n const sourceResult = SourceExpressionParser.parseTableSourceFromLexemes(lexemes, idx);\r\n idx = sourceResult.newIndex;\r\n\r\n // Optional columns\r\n let columns: string[] = [];\r\n if (lexemes[idx]?.type === TokenType.OpenParen) {\r\n idx++;\r\n while (idx < lexemes.length && lexemes[idx].type === TokenType.Identifier) {\r\n columns.push(lexemes[idx].value);\r\n idx++;\r\n if (lexemes[idx]?.type === TokenType.Comma) {\r\n idx++;\r\n } else {\r\n break;\r\n }\r\n }\r\n if (lexemes[idx]?.type !== TokenType.CloseParen) {\r\n throw new Error(`Syntax error at position ${idx}: Expected ')' after column list.`);\r\n }\r\n idx++;\r\n }\r\n\r\n const selectResult = SelectQueryParser.parseFromLexeme(lexemes, idx);\r\n if (withclause) {\r\n if (selectResult.value instanceof SimpleSelectQuery) {\r\n selectResult.value.withClause = withclause;\r\n } else {\r\n throw new Error(`WITH clause is not supported in this context.`);\r\n }\r\n }\r\n\r\n idx = selectResult.newIndex;\r\n return {\r\n value: new InsertQuery({\r\n insertClause: new InsertClause(sourceResult.value, columns),\r\n selectQuery: selectResult.value\r\n }),\r\n newIndex: idx\r\n };\r\n }\r\n}\r\n", "import { CommonTable, SourceAliasExpression, SelectItem, SelectClause, FromClause, SourceExpression, TableSource } from '../models/Clause';\r\nimport { SimpleSelectQuery } from '../models/SimpleSelectQuery';\r\nimport { IdentifierString, ValueComponent, ColumnReference, FunctionCall, ValueList, LiteralValue, BinaryExpression, CaseExpression, SwitchCaseArgument, CaseKeyValuePair, RawString } from '../models/ValueComponent';\r\nimport { JsonMapping } from './PostgresJsonQueryBuilder';\r\n\r\n/**\r\n * Entity with processing metadata\r\n */\r\nexport interface ProcessableEntity {\r\n id: string;\r\n name: string;\r\n columns: { [jsonKey: string]: string };\r\n isRoot: boolean;\r\n propertyName: string;\r\n // For nested entities\r\n parentId?: string;\r\n relationshipType?: \"object\" | \"array\";\r\n}\r\n\r\n/**\r\n * Information for object entity processing\r\n */\r\ninterface ObjectEntityProcessingInfo {\r\n entity: ProcessableEntity;\r\n depth: number;\r\n}\r\n\r\n/**\r\n * PostgreSQL-specific builder for creating CTEs for object entities (object relationships).\r\n * This class handles the creation of CTEs that build JSON/JSONB objects for object entities,\r\n * processing them from the deepest level up to ensure proper dependency ordering.\r\n * \r\n * Features:\r\n * - Depth-based CTE naming (cte_object_depth_N)\r\n * - NULL handling for entity columns\r\n * - JSONB/JSON object construction\r\n * - Hierarchical processing of nested objects\r\n * \r\n * Why depth calculation is critical:\r\n * 1. Object entities can be nested at multiple levels. We must process the deepest\r\n * (most distant) objects first to ensure their JSON representations are available\r\n * when building their parent entities.\r\n * 2. Object entity processing is essentially a column compression operation. Entities\r\n * at the same depth level can be processed simultaneously since they don't depend\r\n * on each other.\r\n * \r\n * Example hierarchy:\r\n * Order (root, depth 0)\r\n * \u2514\u2500 Customer (depth 1)\r\n * \u2514\u2500 Address (depth 2)\r\n * \u2514\u2500 Shipping (depth 1)\r\n * \u2514\u2500 Carrier (depth 2)\r\n * \r\n * Processing order: depth 2 \u2192 depth 1 \u2192 depth 0\r\n */\r\nexport class PostgresObjectEntityCteBuilder { // Constants for consistent naming conventions\r\n private static readonly JSON_COLUMN_SUFFIX = '_json';\r\n private static readonly CTE_OBJECT_PREFIX = 'cte_object_depth_';\r\n private static readonly WILDCARD_COLUMN = '*'; /**\r\n * Build CTEs for all object entities in the correct dependency order\r\n * @param initialCte The starting CTE containing all raw data\r\n * @param allEntities Map of all entities in the mapping\r\n * @param mapping The JSON mapping configuration\r\n * @returns Array of CTEs and the alias of the last CTE created\r\n */\r\n public buildObjectEntityCtes(\r\n initialCte: CommonTable,\r\n allEntities: Map<string, ProcessableEntity>,\r\n mapping: JsonMapping\r\n ): { ctes: CommonTable[], lastCteAlias: string } {\r\n const ctes: CommonTable[] = [initialCte];\r\n let previousCteAlias = initialCte.aliasExpression.table.name; // Collect and sort object entities by depth\r\n const objectEntityInfos = this.collectAndSortObjectEntities(mapping, allEntities);\r\n\r\n // Group entities by depth\r\n const entitiesByDepth = this.groupEntitiesByDepth(objectEntityInfos);\r\n\r\n // Process each depth level, starting from the deepest\r\n const depths = Array.from(entitiesByDepth.keys()).sort((a, b) => b - a);\r\n\r\n for (const depth of depths) {\r\n const entitiesAtDepth = entitiesByDepth.get(depth)!;\r\n const cteAlias = `${PostgresObjectEntityCteBuilder.CTE_OBJECT_PREFIX}${depth}`;\r\n\r\n // Build CTE for all entities at this depth\r\n const cte = this.buildDepthCte(\r\n entitiesAtDepth,\r\n previousCteAlias,\r\n cteAlias,\r\n mapping,\r\n allEntities\r\n );\r\n\r\n ctes.push(cte);\r\n previousCteAlias = cteAlias;\r\n }\r\n\r\n return { ctes, lastCteAlias: previousCteAlias };\r\n } /**\r\n * Collect all object entities and calculate their depth from root.\r\n * \r\n * Depth calculation is crucial because:\r\n * - It determines the processing order (deepest first)\r\n * - It ensures dependencies are resolved before an entity is processed\r\n * - It allows parallel processing of entities at the same depth level\r\n * \r\n * @param mapping The JSON mapping configuration\r\n * @param allEntities Map of all entities in the mapping\r\n * @returns Array of object entity information with calculated depths\r\n */\r\n private collectAndSortObjectEntities(\r\n mapping: JsonMapping,\r\n allEntities: Map<string, ProcessableEntity>): ObjectEntityProcessingInfo[] {\r\n const objectInfos: ObjectEntityProcessingInfo[] = [];\r\n\r\n // Helper function to calculate actual object nesting depth for a given OBJECT entity\r\n const calculateActualObjectNestingDepth = (entityIdOfObject: string): number => {\r\n const initialEntity = allEntities.get(entityIdOfObject);\r\n if (!initialEntity) {\r\n throw new Error(`Entity ${entityIdOfObject} not found for depth calculation.`);\r\n }\r\n // If the object itself is root, its depth is 0. (This function should ideally be called for nested entities, not the root itself as a \"parent CTE\" subject)\r\n if (initialEntity.isRoot) return 0;\r\n\r\n // If the object is not root and has no parentId, it's considered a top-level object, depth 1.\r\n if (!initialEntity.parentId) {\r\n return 1;\r\n }\r\n\r\n let currentParentIdInHierarchy: string | undefined = initialEntity.parentId;\r\n let calculatedObjectDepth = 0;\r\n const visitedInPath = new Set<string>();\r\n visitedInPath.add(entityIdOfObject); // Add the starting object itself to detect cycles\r\n\r\n while (currentParentIdInHierarchy) {\r\n if (visitedInPath.has(currentParentIdInHierarchy)) {\r\n throw new Error(`Circular dependency detected: ${currentParentIdInHierarchy} already visited in path for ${entityIdOfObject}`);\r\n }\r\n visitedInPath.add(currentParentIdInHierarchy);\r\n\r\n const parentEntityData = allEntities.get(currentParentIdInHierarchy);\r\n if (!parentEntityData) {\r\n throw new Error(`Parent entity ${currentParentIdInHierarchy} not found during depth calculation for ${entityIdOfObject}`);\r\n }\r\n\r\n let parentIsConsideredAnObjectForNesting = false;\r\n if (parentEntityData.isRoot) {\r\n parentIsConsideredAnObjectForNesting = true; // Root counts as an object ancestor\r\n } else {\r\n // For non-root parents, find their definition in nestedEntities to check their type\r\n const parentDefinition = mapping.nestedEntities.find(ne => ne.id === currentParentIdInHierarchy);\r\n if (parentDefinition) {\r\n if (parentDefinition.relationshipType === \"object\") {\r\n parentIsConsideredAnObjectForNesting = true;\r\n }\r\n // If parentDefinition.relationshipType === \"array\", it's not an object ancestor for depth counting\r\n } else {\r\n // This implies currentParentIdInHierarchy refers to an entity not defined as root or in nestedEntities\r\n // This should ideally not happen with a consistent mapping.\r\n throw new Error(`Parent entity ${currentParentIdInHierarchy} (ancestor of ${entityIdOfObject}) has no definition in mapping.nestedEntities and is not root.`);\r\n }\r\n }\r\n\r\n if (parentIsConsideredAnObjectForNesting) {\r\n calculatedObjectDepth++;\r\n }\r\n\r\n if (parentEntityData.isRoot) {\r\n break; // Stop when the root is processed as the highest object ancestor\r\n }\r\n currentParentIdInHierarchy = parentEntityData.parentId; // Move to the next ancestor\r\n }\r\n return calculatedObjectDepth;\r\n };\r\n\r\n mapping.nestedEntities.forEach(nestedEntity => {\r\n if (nestedEntity.relationshipType === \"object\") {\r\n const entity = allEntities.get(nestedEntity.id);\r\n // Ensure we don't process the root entity itself as a \"parent\" CTE,\r\n // and that the entity actually exists.\r\n if (entity && !entity.isRoot) {\r\n objectInfos.push({\r\n entity,\r\n depth: calculateActualObjectNestingDepth(nestedEntity.id)\r\n });\r\n }\r\n }\r\n });\r\n\r\n // The existing grouping and sorting by depth (b - a for descending) should still work correctly\r\n // as it processes deepest levels first, regardless of the absolute depth numbers.\r\n return objectInfos;\r\n }\r\n\r\n /**\r\n * Group entities by their depth level.\r\n * \r\n * Grouping by depth allows us to:\r\n * - Process all entities at the same level in a single CTE\r\n * - Optimize query performance by reducing the number of CTEs\r\n * - Maintain clear dependency ordering\r\n * \r\n * @param parentInfos Array of parent entity information with depths\r\n * @returns Map of depth level to entities at that depth\r\n */ private groupEntitiesByDepth(\r\n objectInfos: ObjectEntityProcessingInfo[]\r\n ): Map<number, ObjectEntityProcessingInfo[]> {\r\n const entitiesByDepth = new Map<number, ObjectEntityProcessingInfo[]>();\r\n\r\n objectInfos.forEach(info => {\r\n const depth = info.depth;\r\n if (!entitiesByDepth.has(depth)) {\r\n entitiesByDepth.set(depth, []);\r\n }\r\n entitiesByDepth.get(depth)!.push(info);\r\n });\r\n\r\n return entitiesByDepth;\r\n }\r\n\r\n /**\r\n * Build a CTE that processes all entities at a specific depth level\r\n */\r\n private buildDepthCte(\r\n entitiesAtDepth: ObjectEntityProcessingInfo[],\r\n previousCteAlias: string,\r\n cteAlias: string,\r\n mapping: JsonMapping,\r\n allEntities: Map<string, ProcessableEntity>\r\n ): CommonTable {\r\n // Build SELECT items: * and JSON objects for all entities at this depth\r\n const selectItems: SelectItem[] = [\r\n // Select all columns from previous CTE\r\n new SelectItem(new ColumnReference(null, new IdentifierString(PostgresObjectEntityCteBuilder.WILDCARD_COLUMN)))\r\n ];\r\n\r\n // Process each entity at this depth\r\n for (const { entity } of entitiesAtDepth) {\r\n const jsonColumn = this.buildEntityJsonColumn(entity, mapping, allEntities);\r\n selectItems.push(jsonColumn);\r\n }\r\n\r\n // Create CTE that selects from previous CTE\r\n const cteSelect = new SimpleSelectQuery({\r\n selectClause: new SelectClause(selectItems),\r\n fromClause: new FromClause(\r\n new SourceExpression(\r\n new TableSource(null, new IdentifierString(previousCteAlias)),\r\n null\r\n ),\r\n null\r\n )\r\n });\r\n\r\n return new CommonTable(cteSelect, new SourceAliasExpression(cteAlias, null), null);\r\n }\r\n\r\n /**\r\n * Build JSON column for a single entity with NULL handling\r\n */\r\n private buildEntityJsonColumn(\r\n entity: ProcessableEntity,\r\n mapping: JsonMapping,\r\n allEntities: Map<string, ProcessableEntity>\r\n ): SelectItem {\r\n // Build JSON object arguments and NULL checks\r\n const { jsonObjectArgs, nullChecks } = this.prepareEntityColumns(entity);\r\n\r\n // Add child object relationships\r\n this.addChildObjectRelationships(entity, jsonObjectArgs, mapping, allEntities);\r\n // Create JSON object\r\n const jsonObject = this.createJsonObject(jsonObjectArgs);\r\n\r\n // Build NULL condition and CASE expression\r\n const nullCondition = this.buildNullCondition(nullChecks);\r\n const caseExpr = this.createCaseExpression(nullCondition, jsonObject);\r\n\r\n // Add JSON object as named column\r\n // Use entity ID instead of name to avoid naming conflicts\r\n const jsonColumnName = `${entity.id.toLowerCase()}${PostgresObjectEntityCteBuilder.JSON_COLUMN_SUFFIX}`;\r\n return new SelectItem(caseExpr, jsonColumnName);\r\n }\r\n\r\n /**\r\n * Prepare entity columns and NULL checks.\r\n * \r\n * This method extracts column data and creates NULL checks for each column.\r\n * The NULL checking is essential for handling outer joins correctly.\r\n * \r\n * In outer join scenarios, when there's no matching row in the joined table,\r\n * all columns from that table will be NULL. Instead of creating an empty object\r\n * with all NULL properties (e.g., {id: null, name: null, email: null}),\r\n * we want to represent the absence of the entity as NULL itself.\r\n * \r\n * This ensures cleaner JSON output where missing relationships are represented\r\n * as NULL rather than objects with all NULL fields.\r\n * \r\n * @param entity The entity whose columns are being processed\r\n * @returns Object containing arrays of JSON object arguments and NULL check conditions\r\n */\r\n private prepareEntityColumns(entity: ProcessableEntity): {\r\n jsonObjectArgs: ValueComponent[],\r\n nullChecks: ValueComponent[]\r\n } {\r\n const jsonObjectArgs: ValueComponent[] = [];\r\n const nullChecks: ValueComponent[] = [];\r\n\r\n Object.entries(entity.columns).forEach(([jsonKey, sqlColumn]) => {\r\n jsonObjectArgs.push(new LiteralValue(jsonKey));\r\n jsonObjectArgs.push(new ColumnReference(null, new IdentifierString(sqlColumn)));\r\n\r\n // Collect NULL checks for each column\r\n nullChecks.push(\r\n new BinaryExpression(\r\n new ColumnReference(null, new IdentifierString(sqlColumn)),\r\n \"is\",\r\n new LiteralValue(null)\r\n )\r\n );\r\n });\r\n\r\n return { jsonObjectArgs, nullChecks };\r\n }\r\n\r\n /**\r\n * Add child object relationships to JSON object arguments.\r\n * \r\n * This method processes nested object-type entities that are direct children of the current entity.\r\n * For each child entity, it adds the property name and corresponding JSON column reference\r\n * to the arguments array that will be used to build the parent's JSON object.\r\n * \r\n * The child JSON columns are expected to already exist in the data source (created by deeper\r\n * level CTEs), as we process from the deepest level up to the root.\r\n * \r\n * Note: In this context, \"child\" refers to entities that have an object relationship (0..1)\r\n * with their parent. From a data perspective, these are typically entities referenced via\r\n * foreign keys, representing \"parent\" entities in traditional database terminology.\r\n * \r\n * @param entity The current entity being processed\r\n * @param jsonObjectArgs Array to which JSON object arguments will be added\r\n * @param mapping The JSON mapping configuration\r\n * @param allEntities Map of all entities in the mapping\r\n */\r\n private addChildObjectRelationships(\r\n entity: ProcessableEntity,\r\n jsonObjectArgs: ValueComponent[],\r\n mapping: JsonMapping,\r\n allEntities: Map<string, ProcessableEntity>\r\n ): void {\r\n const childEntities = mapping.nestedEntities.filter(ne =>\r\n ne.parentId === entity.id && ne.relationshipType === \"object\"\r\n );\r\n\r\n childEntities.forEach(childEntity => {\r\n const child = allEntities.get(childEntity.id);\r\n if (child) {\r\n jsonObjectArgs.push(new LiteralValue(childEntity.propertyName));\r\n // Use entity ID instead of name to avoid naming conflicts\r\n const jsonColumnName = `${child.id.toLowerCase()}${PostgresObjectEntityCteBuilder.JSON_COLUMN_SUFFIX}`;\r\n jsonObjectArgs.push(new ColumnReference(null, new IdentifierString(jsonColumnName)));\r\n }\r\n });\r\n }\r\n\r\n /**\r\n * Create JSON object function call\r\n */\r\n private createJsonObject(args: ValueComponent[]): FunctionCall {\r\n const jsonBuildFunction = \"jsonb_build_object\";\r\n // Always use JSONB\r\n return new FunctionCall(\r\n null,\r\n new RawString(jsonBuildFunction),\r\n new ValueList(args),\r\n null\r\n );\r\n }\r\n\r\n /**\r\n * Build NULL condition from NULL checks\r\n */\r\n private buildNullCondition(nullChecks: ValueComponent[]): ValueComponent {\r\n return nullChecks.reduce((acc, check) =>\r\n acc ? new BinaryExpression(acc, \"and\", check) : check\r\n );\r\n }\r\n\r\n /**\r\n * Create CASE expression with NULL handling\r\n */\r\n private createCaseExpression(nullCondition: ValueComponent, jsonObject: ValueComponent): CaseExpression {\r\n return new CaseExpression(\r\n null,\r\n new SwitchCaseArgument(\r\n [new CaseKeyValuePair(nullCondition, new LiteralValue(null))],\r\n jsonObject // ELSE return the JSON object\r\n )\r\n );\r\n }\r\n}\r\n", "import { CommonTable, SourceAliasExpression, SelectItem, SelectClause, FromClause, SourceExpression, TableSource, GroupByClause } from '../models/Clause';\r\nimport { SimpleSelectQuery } from '../models/SimpleSelectQuery';\r\nimport { IdentifierString, ValueComponent, ColumnReference, FunctionCall, ValueList, LiteralValue, RawString, CastExpression, TypeValue } from '../models/ValueComponent';\r\nimport { JsonMapping } from './PostgresJsonQueryBuilder';\r\nimport { ProcessableEntity } from './PostgresObjectEntityCteBuilder';\r\nimport { SelectValueCollector } from './SelectValueCollector';\r\n\r\n/**\r\n * Information for array entity processing\r\n */\r\ninterface ArrayEntityProcessingInfo {\r\n entity: ProcessableEntity;\r\n parentEntity: ProcessableEntity;\r\n parentIdColumnSqlName: string;\r\n depth: number;\r\n}\r\n\r\n/**\r\n * PostgreSQL-specific builder for creating CTEs for array entities (array relationships).\r\n * This class handles the creation of CTEs that build JSON/JSONB arrays for child entities,\r\n * processing them from the deepest level up to ensure proper dependency ordering.\r\n * \r\n * Features:\r\n * - Depth-based CTE naming (cte_array_depth_N)\r\n * - Row compression using GROUP BY operations\r\n * - JSONB/JSON array aggregation\r\n * - Hierarchical processing of nested arrays\r\n * - Column exclusion to avoid duplication\r\n * \r\n * Why depth calculation is critical:\r\n * 1. Array entities can be nested at multiple levels. We must process the deepest\r\n * (most distant) arrays first to ensure their JSON representations are available\r\n * when building their parent arrays.\r\n * 2. Array entity processing is essentially a row compression operation using GROUP BY.\r\n * Unlike parent entities which use column compression, arrays require grouping\r\n * to aggregate multiple rows into JSON arrays.\r\n * \r\n * Example hierarchy:\r\n * Order (root, depth 0)\r\n * \u2514\u2500 Items (array, depth 1)\r\n * \u2514\u2500 Details (array, depth 2)\r\n * \r\n * Processing order: depth 2 \u2192 depth 1 \u2192 depth 0\r\n */\r\nexport class PostgresArrayEntityCteBuilder {\r\n // Constants for consistent naming conventions\r\n private static readonly CTE_ARRAY_PREFIX = 'cte_array_depth_';\r\n\r\n /**\r\n * Build CTEs for all array entities in the correct dependency order\r\n * @param ctesSoFar Array of CTEs built so far (starts with the initial CTE)\r\n * @param aliasOfCteToBuildUpon Alias of the CTE from which the current array CTE will select\r\n * @param allEntities Map of all entities in the mapping\r\n * @param mapping The JSON mapping configuration\r\n * @returns Object containing the updated list of all CTEs and the alias of the last CTE created\r\n */\r\n public buildArrayEntityCtes(\r\n ctesSoFar: CommonTable[],\r\n aliasOfCteToBuildUpon: string,\r\n allEntities: Map<string, ProcessableEntity>,\r\n mapping: JsonMapping\r\n ): { updatedCtes: CommonTable[], lastCteAlias: string } {\r\n let currentCtes = [...ctesSoFar];\r\n let currentCteAlias = aliasOfCteToBuildUpon;\r\n\r\n // Collect and sort array entities by depth\r\n const sortedArrayInfos = this.collectAndSortArrayEntities(mapping, allEntities);\r\n\r\n if (sortedArrayInfos.length === 0) {\r\n return { updatedCtes: currentCtes, lastCteAlias: currentCteAlias };\r\n }\r\n\r\n // Group array entities by depth level for batch processing\r\n const entitiesByDepth = this.groupEntitiesByDepth(sortedArrayInfos);\r\n\r\n // Process from deepest to shallowest (depth-first)\r\n const depths = Array.from(entitiesByDepth.keys()).sort((a, b) => b - a);\r\n\r\n for (const depth of depths) {\r\n const infos = entitiesByDepth.get(depth)!;\r\n\r\n // Build CTE for all entities at this depth\r\n const { cte, newCteAlias } = this.buildDepthCte(\r\n infos,\r\n currentCteAlias,\r\n currentCtes,\r\n depth,\r\n mapping\r\n );\r\n\r\n currentCtes.push(cte);\r\n currentCteAlias = newCteAlias;\r\n }\r\n\r\n return { updatedCtes: currentCtes, lastCteAlias: currentCteAlias };\r\n }\r\n\r\n /**\r\n * Collect all array entities and calculate their depth from root.\r\n * \r\n * Depth calculation ensures proper processing order where deeper nested\r\n * arrays are processed first, making their aggregated data available\r\n * for parent array processing.\r\n * \r\n * @param mapping The JSON mapping configuration\r\n * @param allEntities Map of all entities in the mapping\r\n * @returns Array of array entity information with calculated depths, sorted deepest first\r\n */\r\n private collectAndSortArrayEntities(\r\n mapping: JsonMapping,\r\n allEntities: Map<string, ProcessableEntity>\r\n ): ArrayEntityProcessingInfo[] {\r\n const arrayEntityInfos: ArrayEntityProcessingInfo[] = [];\r\n\r\n // Helper function to calculate depth for an entity\r\n const getDepth = (entityId: string): number => {\r\n const entity = allEntities.get(entityId);\r\n if (!entity || entity.isRoot) return 0;\r\n if (!entity.parentId) return 1;\r\n return 1 + getDepth(entity.parentId);\r\n };\r\n\r\n // Collect all array-type nested entities\r\n mapping.nestedEntities.forEach(ne => {\r\n if (ne.relationshipType === \"array\") {\r\n const currentArrayEntity = allEntities.get(ne.id);\r\n const parentEntity = allEntities.get(ne.parentId!);\r\n\r\n if (!currentArrayEntity || !parentEntity) {\r\n throw new Error(`Configuration error: Array entity '${ne.id}' or its parent '${ne.parentId}' not found.`);\r\n }\r\n\r\n // Determine the linking column from parent entity\r\n // This assumes the first column of the parent is a suitable key for linking.\r\n // More robust linking might require explicit configuration in the mapping.\r\n const parentSqlColumns = Object.values(parentEntity.columns);\r\n if (parentSqlColumns.length === 0) {\r\n throw new Error(`Configuration error: Parent entity '${parentEntity.name}' (ID: ${parentEntity.id}) must have at least one column defined to serve as a linking key for child array '${ne.name}'.`);\r\n }\r\n const parentIdColumnSqlName = parentSqlColumns[0];\r\n\r\n arrayEntityInfos.push({\r\n entity: currentArrayEntity,\r\n parentEntity: parentEntity,\r\n parentIdColumnSqlName: parentIdColumnSqlName,\r\n depth: getDepth(ne.id)\r\n });\r\n }\r\n });\r\n\r\n // Sort by depth, deepest arrays (higher depth number) processed first (bottom-up for arrays)\r\n arrayEntityInfos.sort((a, b) => b.depth - a.depth);\r\n return arrayEntityInfos;\r\n }\r\n\r\n /**\r\n * Group array entities by their depth level.\r\n * \r\n * Grouping by depth allows us to:\r\n * - Process all entities at the same level in a single CTE\r\n * - Optimize query performance by reducing the number of CTEs\r\n * - Maintain clear dependency ordering\r\n * \r\n * @param arrayInfos Array of array entity information with depths\r\n * @returns Map of depth level to entities at that depth\r\n */\r\n private groupEntitiesByDepth(\r\n arrayInfos: ArrayEntityProcessingInfo[]\r\n ): Map<number, ArrayEntityProcessingInfo[]> {\r\n const entitiesByDepth = new Map<number, ArrayEntityProcessingInfo[]>();\r\n\r\n arrayInfos.forEach(info => {\r\n const depth = info.depth;\r\n if (!entitiesByDepth.has(depth)) {\r\n entitiesByDepth.set(depth, []);\r\n }\r\n entitiesByDepth.get(depth)!.push(info);\r\n });\r\n\r\n return entitiesByDepth;\r\n }\r\n\r\n /**\r\n * Build a CTE that processes all array entities at a specific depth level.\r\n * \r\n * This method creates a single CTE that aggregates multiple array entities\r\n * at the same depth, using GROUP BY to compress rows into JSON arrays.\r\n * \r\n * @param infos Array entities at this depth level\r\n * @param currentCteAlias Alias of the CTE to build upon\r\n * @param currentCtes All CTEs built so far\r\n * @param depth Current depth level being processed\r\n * @param mapping JSON mapping configuration\r\n * @returns The new CTE and its alias\r\n */\r\n private buildDepthCte(\r\n infos: ArrayEntityProcessingInfo[],\r\n currentCteAlias: string,\r\n currentCtes: CommonTable[],\r\n depth: number,\r\n mapping: JsonMapping\r\n ): { cte: CommonTable, newCteAlias: string } {\r\n // Collect columns that will be compressed into arrays\r\n // This includes both direct columns and columns from nested entities within the array\r\n const arrayColumns = new Set<string>();\r\n infos.forEach(info => {\r\n // Add direct columns from the array entity\r\n Object.values(info.entity.columns).forEach(col => arrayColumns.add(col));\r\n\r\n // Also add columns from all nested entities within this array entity\r\n const collectNestedColumns = (parentEntityId: string) => {\r\n mapping.nestedEntities\r\n .filter(nestedEntity => nestedEntity.parentId === parentEntityId)\r\n .forEach(nestedEntity => {\r\n Object.values(nestedEntity.columns).forEach(column => {\r\n const columnName = typeof column === 'string' ? column : (column as any).column;\r\n arrayColumns.add(columnName);\r\n });\r\n // Recursively collect from deeper nested entities\r\n collectNestedColumns(nestedEntity.id);\r\n });\r\n };\r\n\r\n collectNestedColumns(info.entity.id);\r\n });\r\n\r\n // Get columns from previous CTE\r\n const prevCte = currentCtes.find(c => c.aliasExpression.table.name === currentCteAlias)?.query;\r\n if (!prevCte) {\r\n throw new Error(`CTE not found: ${currentCteAlias}`);\r\n }\r\n const prevSelects = new SelectValueCollector(null, currentCtes).collect(prevCte); // Build SELECT items: columns that are NOT being compressed (for GROUP BY)\r\n const groupByItems: ValueComponent[] = [];\r\n const selectItems: SelectItem[] = [];\r\n\r\n // Get columns from the current level's array entities that will be aggregated\r\n // These should be included in GROUP BY since they're being processed at this level\r\n const currentLevelArrayColumns = new Set<string>();\r\n infos.forEach(info => {\r\n Object.values(info.entity.columns).forEach(col => currentLevelArrayColumns.add(col));\r\n });\r\n\r\n // Collect array entity columns organized by depth for GROUP BY exclusion strategy\r\n const arrayEntityColumns = this.collectArrayEntityColumnsByDepth(mapping, depth);\r\n\r\n // Process existing SELECT variables to determine which should be included in GROUP BY\r\n this.processSelectVariablesForGroupBy(\r\n prevSelects,\r\n arrayColumns,\r\n arrayEntityColumns,\r\n depth,\r\n selectItems,\r\n groupByItems\r\n );\r\n\r\n // Add JSON aggregation columns for each array entity at this depth\r\n for (const info of infos) {\r\n const agg = this.buildAggregationDetailsForArrayEntity(\r\n info.entity,\r\n mapping.nestedEntities,\r\n new Map() // allEntities - not needed for array aggregation\r\n );\r\n selectItems.push(new SelectItem(agg.jsonAgg, info.entity.propertyName));\r\n }\r\n\r\n // Create the new CTE\r\n const cteAlias = `${PostgresArrayEntityCteBuilder.CTE_ARRAY_PREFIX}${depth}`;\r\n const cteSelect = new SimpleSelectQuery({\r\n selectClause: new SelectClause(selectItems),\r\n fromClause: new FromClause(\r\n new SourceExpression(\r\n new TableSource(null, new IdentifierString(currentCteAlias)),\r\n null\r\n ),\r\n null\r\n ),\r\n groupByClause: groupByItems.length > 0 ? new GroupByClause(groupByItems) : null,\r\n });\r\n\r\n const cte = new CommonTable(cteSelect, new SourceAliasExpression(cteAlias, null), null);\r\n\r\n return { cte, newCteAlias: cteAlias };\r\n }\r\n\r\n /**\r\n * Build JSON aggregation function for an array entity.\r\n * \r\n * This method creates a jsonb_agg or json_agg function call that aggregates\r\n * the entity's columns into a JSON array. It also handles nested relationships\r\n * by including child entity properties in the JSON object.\r\n * \r\n * @param entity The array entity being processed\r\n * @param nestedEntities All nested entities from the mapping\r\n * @param allEntities Map of all entities (not used in current implementation)\r\n * @returns Object containing the JSON aggregation function\r\n */\r\n private buildAggregationDetailsForArrayEntity(\r\n entity: ProcessableEntity,\r\n nestedEntities: any[],\r\n allEntities: Map<string, ProcessableEntity>\r\n ): { jsonAgg: ValueComponent } {\r\n // Build JSON object for array elements using JSONB functions\r\n const jsonBuildFunction = \"jsonb_build_object\";\r\n const args: ValueComponent[] = [];\r\n\r\n // Add the entity's own columns\r\n Object.entries(entity.columns).forEach(([jsonKey, sqlColumn]) => {\r\n args.push(new LiteralValue(jsonKey));\r\n args.push(new ColumnReference(null, new IdentifierString(sqlColumn)));\r\n });\r\n\r\n // Find and process child entities (both object and array types)\r\n const childEntities = nestedEntities.filter((ne) => ne.parentId === entity.id); childEntities.forEach((childEntity) => {\r\n args.push(new LiteralValue(childEntity.propertyName));\r\n\r\n if (childEntity.relationshipType === \"object\") {\r\n // For object relationships, use pre-computed JSON column\r\n // Use entity ID instead of name to avoid naming conflicts\r\n const jsonColumnName = `${childEntity.id.toLowerCase()}_json`;\r\n args.push(new ColumnReference(null, new IdentifierString(jsonColumnName)));\r\n } else if (childEntity.relationshipType === \"array\") {\r\n // For array relationships, use the column directly\r\n args.push(new ColumnReference(null, new IdentifierString(childEntity.propertyName)));\r\n }\r\n });\r\n\r\n // Create JSON object\r\n const jsonObject = new FunctionCall(null, new RawString(jsonBuildFunction), new ValueList(args), null);\r\n\r\n // Create JSON aggregation using JSONB with NULL filtering\r\n // Use FILTER clause to exclude rows where primary key is NULL (no actual data)\r\n const jsonAggFunction = \"jsonb_agg\";\r\n\r\n // Find the primary column (typically the first column) to use for NULL filtering\r\n const primaryColumn = Object.values(entity.columns)[0];\r\n\r\n // For now, create standard jsonb_agg and handle NULL filtering in post-processing\r\n // TODO: Implement proper FILTER clause support in SQL AST\r\n const jsonAgg = new FunctionCall(\r\n null,\r\n new RawString(jsonAggFunction),\r\n new ValueList([jsonObject]),\r\n null\r\n );\r\n\r\n return { jsonAgg };\r\n }\r\n\r\n /**\r\n * Collects array entity columns organized by depth for the GROUP BY exclusion strategy.\r\n * \r\n * This method creates a mapping from depth levels to sets of column names that belong to\r\n * array entities at each depth. This is used to determine which columns should be excluded\r\n * from GROUP BY clauses when performing array aggregation at specific depths.\r\n * \r\n * @param mapping The JSON mapping configuration containing all entities\r\n * @param currentDepth The current aggregation depth being processed\r\n * @returns A map where keys are depth levels and values are sets of column names\r\n */\r\n private collectArrayEntityColumnsByDepth(\r\n mapping: JsonMapping,\r\n currentDepth: number\r\n ): Map<number, Set<string>> {\r\n const arrayEntitiesByDepth = new Map<number, Set<string>>(); // Initialize depth maps for current and deeper levels\r\n // Use a reasonable maximum depth limit to avoid infinite loops\r\n const maxDepth = Math.max(currentDepth + 3, 5); // Allow up to 3 additional levels or minimum 5 levels\r\n for (let d = currentDepth; d <= maxDepth; d++) {\r\n arrayEntitiesByDepth.set(d, new Set());\r\n }\r\n\r\n // Process all array entities to collect their columns by depth\r\n mapping.nestedEntities\r\n .filter(entity => entity.relationshipType === 'array')\r\n .forEach(entity => {\r\n // Calculate entity depth in the hierarchy\r\n const entityDepth = this.calculateEntityDepth(entity, mapping);\r\n\r\n if (!arrayEntitiesByDepth.has(entityDepth)) {\r\n arrayEntitiesByDepth.set(entityDepth, new Set());\r\n }\r\n\r\n // Add direct columns from the array entity\r\n this.addEntityColumnsToDepthSet(entity, entityDepth, arrayEntitiesByDepth);\r\n\r\n // Collect columns from all descendant entities recursively\r\n this.collectDescendantColumns(entity.id, entityDepth, mapping, arrayEntitiesByDepth);\r\n });\r\n\r\n return arrayEntitiesByDepth;\r\n }\r\n\r\n /**\r\n * Calculates the depth of an entity in the hierarchy by traversing up to the root.\r\n * \r\n * @param entity The entity to calculate depth for\r\n * @param mapping The JSON mapping containing all entities\r\n * @returns The depth level (0 for root level, 1 for first level, etc.)\r\n */\r\n private calculateEntityDepth(entity: any, mapping: JsonMapping): number {\r\n let entityDepth = 0;\r\n let currentEntity = entity;\r\n\r\n while (currentEntity.parentId && currentEntity.parentId !== mapping.rootEntity.id) {\r\n entityDepth++;\r\n currentEntity = mapping.nestedEntities.find(e => e.id === currentEntity.parentId) || currentEntity;\r\n }\r\n\r\n return entityDepth;\r\n }\r\n\r\n /**\r\n * Adds all columns from an entity to the specified depth set.\r\n * \r\n * @param entity The entity whose columns should be added\r\n * @param depth The depth level to add columns to\r\n * @param arrayEntitiesByDepth The map to update\r\n */\r\n private addEntityColumnsToDepthSet(\r\n entity: any,\r\n depth: number,\r\n arrayEntitiesByDepth: Map<number, Set<string>>\r\n ): void {\r\n Object.values(entity.columns).forEach(column => {\r\n const columnName = typeof column === 'string' ? column : (column as any).column;\r\n arrayEntitiesByDepth.get(depth)!.add(columnName);\r\n });\r\n }\r\n\r\n /**\r\n * Recursively collects columns from all descendant entities under a parent entity.\r\n * \r\n * This method ensures that all nested entities (at any depth) under an array entity\r\n * have their columns properly categorized by the array entity's depth level.\r\n * \r\n * @param parentEntityId The ID of the parent entity\r\n * @param targetDepth The depth level to assign collected columns to\r\n * @param mapping The JSON mapping containing all entities\r\n * @param arrayEntitiesByDepth The map to update with collected columns\r\n */\r\n private collectDescendantColumns(\r\n parentEntityId: string,\r\n targetDepth: number,\r\n mapping: JsonMapping,\r\n arrayEntitiesByDepth: Map<number, Set<string>>\r\n ): void {\r\n mapping.nestedEntities\r\n .filter(nestedEntity => nestedEntity.parentId === parentEntityId)\r\n .forEach(nestedEntity => {\r\n // Add all columns from this descendant to the target depth\r\n this.addEntityColumnsToDepthSet(nestedEntity, targetDepth, arrayEntitiesByDepth);\r\n\r\n // Recursively collect from deeper nested entities\r\n this.collectDescendantColumns(nestedEntity.id, targetDepth, mapping, arrayEntitiesByDepth);\r\n });\r\n }\r\n\r\n /**\r\n * Processes SELECT variables to determine which should be included in GROUP BY clauses.\r\n * \r\n * This method implements the core logic for deciding which columns from previous CTEs\r\n * should be included in the GROUP BY clause when performing array aggregation. It handles\r\n * special cases for JSON columns and applies depth-based filtering to prevent over-grouping.\r\n * \r\n * @param prevSelects SELECT variables from the previous CTE\r\n * @param arrayColumns Columns that are being aggregated (should be excluded from GROUP BY)\r\n * @param arrayEntitiesByDepth Map of depth levels to their column sets\r\n * @param currentDepth The current aggregation depth being processed\r\n * @param selectItems Output array for SELECT items\r\n * @param groupByItems Output array for GROUP BY items\r\n */\r\n private processSelectVariablesForGroupBy(\r\n prevSelects: any[],\r\n arrayColumns: Set<string>,\r\n arrayEntitiesByDepth: Map<number, Set<string>>,\r\n currentDepth: number,\r\n selectItems: SelectItem[],\r\n groupByItems: ValueComponent[]\r\n ): void {\r\n prevSelects.forEach(sv => {\r\n if (!arrayColumns.has(sv.name)) {\r\n const shouldInclude = this.shouldIncludeColumnInGroupBy(\r\n sv.name,\r\n arrayEntitiesByDepth,\r\n currentDepth\r\n );\r\n\r\n if (shouldInclude) {\r\n selectItems.push(new SelectItem(\r\n new ColumnReference(null, new IdentifierString(sv.name)),\r\n sv.name\r\n ));\r\n groupByItems.push(new ColumnReference(null, new IdentifierString(sv.name)));\r\n }\r\n }\r\n });\r\n }\r\n\r\n /**\r\n * Determines whether a column should be included in the GROUP BY clause.\r\n * \r\n * This method applies depth-based filtering and special handling for JSON columns\r\n * to prevent over-grouping during array aggregation. It implements heuristics for\r\n * excluding columns that belong to nested entities within array contexts.\r\n * \r\n * @param columnName The name of the column to evaluate\r\n * @param arrayEntitiesByDepth Map of depth levels to their column sets\r\n * @param currentDepth The current aggregation depth\r\n * @returns True if the column should be included in GROUP BY, false otherwise\r\n */\r\n private shouldIncludeColumnInGroupBy(\r\n columnName: string,\r\n arrayEntitiesByDepth: Map<number, Set<string>>,\r\n currentDepth: number\r\n ): boolean {\r\n const isJsonColumn = columnName.endsWith('_json');\r\n let shouldInclude = true;\r\n\r\n // Check if this column belongs to array entities at current depth or deeper\r\n // These columns are being aggregated and should not be in GROUP BY\r\n for (const [entityDepth, columns] of arrayEntitiesByDepth.entries()) {\r\n if (entityDepth >= currentDepth && columns.has(columnName)) {\r\n shouldInclude = false;\r\n break;\r\n }\r\n }\r\n\r\n // Special handling for JSON columns to prevent over-grouping\r\n if (isJsonColumn && columnName.startsWith('entity_')) {\r\n shouldInclude = this.shouldIncludeJsonColumn(columnName, currentDepth);\r\n }\r\n\r\n // Always include non-entity JSON columns (e.g., computed columns)\r\n return shouldInclude || (isJsonColumn && !columnName.startsWith('entity_'));\r\n }\r\n\r\n /**\r\n * Applies heuristics to determine if an entity JSON column should be included in GROUP BY.\r\n * \r\n * This method uses entity numbering patterns to identify deeply nested entities\r\n * that should be excluded from GROUP BY when processing array aggregations.\r\n * This is a simplified heuristic approach that works for current use cases.\r\n * \r\n * @param columnName The JSON column name (expected format: entity_N_json)\r\n * @param currentDepth The current aggregation depth\r\n * @returns True if the JSON column should be included, false otherwise\r\n */\r\n private shouldIncludeJsonColumn(columnName: string, currentDepth: number): boolean {\r\n const entityMatch = columnName.match(/entity_(\\d+)_json/);\r\n if (!entityMatch) {\r\n return true;\r\n }\r\n\r\n // For depth > 0, exclude JSON columns from highly nested entities\r\n // This heuristic assumes entities with higher numbers are more deeply nested\r\n if (currentDepth > 0) {\r\n const entityNumber = parseInt(entityMatch[1]);\r\n // Entities with numbers > 2 are typically nested within arrays and should be excluded\r\n return entityNumber <= 2;\r\n }\r\n\r\n return true;\r\n }\r\n}\r\n", "import { CommonTable, SourceAliasExpression, SelectItem, SelectClause, FromClause, SourceExpression, TableSource, GroupByClause, WithClause, SubQuerySource, LimitClause } from '../models/Clause';\r\nimport { SimpleSelectQuery } from '../models/SimpleSelectQuery';\r\nimport { SelectQuery } from '../models/SelectQuery';\r\nimport { IdentifierString, ValueComponent, ColumnReference, FunctionCall, ValueList, LiteralValue, BinaryExpression, CaseExpression, SwitchCaseArgument, CaseKeyValuePair, RawString, UnaryExpression } from '../models/ValueComponent';\r\nimport { SelectValueCollector } from \"./SelectValueCollector\";\r\nimport { PostgresObjectEntityCteBuilder, ProcessableEntity } from './PostgresObjectEntityCteBuilder';\r\nimport { PostgresArrayEntityCteBuilder } from './PostgresArrayEntityCteBuilder';\r\nimport { QueryBuilder } from './QueryBuilder';\r\n\r\n/**\r\n * Universal JSON mapping definition for creating any level of JSON structures.\r\n * Supports flat arrays, nested objects, and unlimited hierarchical structures.\r\n */\r\nexport interface JsonMapping {\r\n rootName: string;\r\n rootEntity: {\r\n id: string;\r\n name: string;\r\n columns: { [jsonKey: string]: string };\r\n };\r\n nestedEntities: Array<{\r\n id: string;\r\n name: string;\r\n parentId: string;\r\n propertyName: string;\r\n relationshipType?: \"object\" | \"array\";\r\n columns: { [jsonKey: string]: string };\r\n }>;\r\n resultFormat?: \"array\" | \"single\";\r\n emptyResult?: string;\r\n}\r\n\r\n/**\r\n * PostgreSQL JSON query builder that transforms SimpleSelectQuery into queries\r\n * that return JSON arrays or single JSON objects using PostgreSQL JSON functions.\r\n */\r\nexport class PostgresJsonQueryBuilder {\r\n private selectValueCollector: SelectValueCollector;\r\n private objectEntityCteBuilder: PostgresObjectEntityCteBuilder;\r\n private arrayEntityCteBuilder: PostgresArrayEntityCteBuilder;\r\n\r\n constructor() {\r\n this.selectValueCollector = new SelectValueCollector(null);\r\n this.objectEntityCteBuilder = new PostgresObjectEntityCteBuilder();\r\n this.arrayEntityCteBuilder = new PostgresArrayEntityCteBuilder();\r\n }\r\n\r\n /**\r\n * Validates the JSON mapping and the original query.\r\n * @param query Original query to transform\r\n * @param mapping JSON mapping configuration\r\n */\r\n private validateMapping(query: SimpleSelectQuery, mapping: JsonMapping): void {\r\n const collector = new SelectValueCollector();\r\n const selectedValues = collector.collect(query);\r\n\r\n // sv.name is the alias or derived name\r\n const availableColumns = new Set(selectedValues.map(sv => sv.name)); // Check root entity columns\r\n for (const jsonKey in mapping.rootEntity.columns) {\r\n const columnDef = mapping.rootEntity.columns[jsonKey];\r\n // Handle both string and object formats\r\n const sourceColumn = typeof columnDef === 'string' ? columnDef : (columnDef as any).column;\r\n if (!availableColumns.has(sourceColumn)) {\r\n throw new Error(`Validation Error: Column \"${sourceColumn}\" for JSON key \"${jsonKey}\" in root entity \"${mapping.rootEntity.name}\" not found in the query's select list.`);\r\n }\r\n }\r\n\r\n // Check nested entity columns and parent-child relationships\r\n const entityIds = new Set<string>([mapping.rootEntity.id]);\r\n const parentToChildrenMap = new Map<string, string[]>();\r\n\r\n mapping.nestedEntities.forEach(ne => {\r\n entityIds.add(ne.id);\r\n if (!parentToChildrenMap.has(ne.parentId)) {\r\n parentToChildrenMap.set(ne.parentId, []);\r\n }\r\n parentToChildrenMap.get(ne.parentId)!.push(ne.id);\r\n });\r\n\r\n for (const entity of mapping.nestedEntities) {\r\n if (!entityIds.has(entity.parentId)) {\r\n throw new Error(`Validation Error: Parent entity with ID \"${entity.parentId}\" for nested entity \"${entity.name}\" (ID: ${entity.id}) not found.`);\r\n }\r\n\r\n for (const jsonKey in entity.columns) {\r\n const columnDef = entity.columns[jsonKey];\r\n // Handle both string and object formats\r\n const sourceColumn = typeof columnDef === 'string' ? columnDef : (columnDef as any).column;\r\n if (!availableColumns.has(sourceColumn)) {\r\n throw new Error(`Validation Error: Column \"${sourceColumn}\" for JSON key \"${jsonKey}\" in nested entity \"${entity.name}\" (ID: ${entity.id}) not found in the query's select list.`);\r\n }\r\n }\r\n }\r\n\r\n // Validate: An entity should not have multiple direct array children.\r\n // Validate: Child propertyNames under a single parent must be unique.\r\n const allParentIds = new Set([mapping.rootEntity.id, ...mapping.nestedEntities.map(ne => ne.parentId)]);\r\n for (const parentId of allParentIds) {\r\n const directChildren = mapping.nestedEntities.filter(ne => ne.parentId === parentId);\r\n const directArrayChildrenCount = directChildren.filter(c => c.relationshipType === 'array').length;\r\n if (directArrayChildrenCount > 1) {\r\n const parentName = parentId === mapping.rootEntity.id ? mapping.rootEntity.name : mapping.nestedEntities.find(ne => ne.id === parentId)?.name;\r\n throw new Error(`Validation Error: Parent entity \"${parentName}\" (ID: ${parentId}) has multiple direct array children. This is not supported.`);\r\n }\r\n\r\n const propertyNames = new Set<string>();\r\n for (const child of directChildren) {\r\n if (propertyNames.has(child.propertyName)) {\r\n const parentName = parentId === mapping.rootEntity.id ? mapping.rootEntity.name : mapping.nestedEntities.find(ne => ne.id === parentId)?.name;\r\n throw new Error(`Validation Error: Parent entity \"${parentName}\" (ID: ${parentId}) has duplicate property name \"${child.propertyName}\" for its children.`);\r\n }\r\n propertyNames.add(child.propertyName);\r\n }\r\n }\r\n }\r\n\r\n /**\r\n * Build JSON query from original query and mapping configuration.\r\n * @param originalQuery Original query to transform (can be any SelectQuery type)\r\n * @param mapping JSON mapping configuration\r\n * @returns Transformed query with JSON aggregation\r\n */\r\n public buildJsonQuery(originalQuery: SelectQuery, mapping: JsonMapping): SimpleSelectQuery;\r\n public buildJsonQuery(originalQuery: SimpleSelectQuery, mapping: JsonMapping): SimpleSelectQuery;\r\n public buildJsonQuery(originalQuery: SelectQuery | SimpleSelectQuery, mapping: JsonMapping): SimpleSelectQuery {\r\n // Convert any SelectQuery to SimpleSelectQuery using QueryBuilder\r\n const simpleQuery = originalQuery instanceof SimpleSelectQuery\r\n ? originalQuery\r\n : QueryBuilder.buildSimpleQuery(originalQuery);\r\n\r\n return this.buildJsonWithCteStrategy(simpleQuery, mapping);\r\n }\r\n\r\n /**\r\n * Build JSON query from original query and mapping configuration.\r\n * @deprecated Use buildJsonQuery instead. This method will be removed in a future version.\r\n * @param originalQuery Original query to transform\r\n * @param mapping JSON mapping configuration\r\n * @returns Transformed query with JSON aggregation\r\n */\r\n public buildJson(originalQuery: SimpleSelectQuery, mapping: JsonMapping): SimpleSelectQuery {\r\n console.warn('buildJson is deprecated. Use buildJsonQuery instead.');\r\n return this.buildJsonQuery(originalQuery, mapping);\r\n }\r\n\r\n /**\r\n * Builds the JSON structure using a unified CTE-based strategy.\r\n * @param originalQuery Original query\r\n * @param mapping JSON mapping configuration\r\n * @returns Query with CTE-based JSON aggregation\r\n */\r\n private buildJsonWithCteStrategy(\r\n originalQuery: SimpleSelectQuery,\r\n mapping: JsonMapping,\r\n ): SimpleSelectQuery {\r\n this.validateMapping(originalQuery, mapping);\r\n\r\n // Step 1: Create the initial CTE from the original query\r\n const { initialCte, initialCteAlias } = this.createInitialCte(originalQuery);\r\n\r\n let ctesForProcessing: CommonTable[] = [initialCte];\r\n let currentAliasToBuildUpon = initialCteAlias;\r\n\r\n // Step 2: Prepare entity information\r\n const allEntities = new Map<string, ProcessableEntity>();\r\n allEntities.set(mapping.rootEntity.id, { ...mapping.rootEntity, isRoot: true, propertyName: mapping.rootName });\r\n mapping.nestedEntities.forEach(ne => allEntities.set(ne.id, { ...ne, isRoot: false, propertyName: ne.propertyName })); // Step 2.5: Build CTEs for object entities using dedicated builder\r\n const objectEntityResult = this.objectEntityCteBuilder.buildObjectEntityCtes(\r\n initialCte,\r\n allEntities,\r\n mapping\r\n );\r\n // Important: Replace the entire CTE list with the result from object entity builder\r\n // The object entity builder returns all CTEs including the initial one\r\n ctesForProcessing = objectEntityResult.ctes;\r\n currentAliasToBuildUpon = objectEntityResult.lastCteAlias;\r\n\r\n // Step 3: Build CTEs for array entities using dedicated builder\r\n const arrayCteBuildResult = this.arrayEntityCteBuilder.buildArrayEntityCtes(\r\n ctesForProcessing,\r\n currentAliasToBuildUpon,\r\n allEntities,\r\n mapping\r\n );\r\n ctesForProcessing = arrayCteBuildResult.updatedCtes;\r\n currentAliasToBuildUpon = arrayCteBuildResult.lastCteAlias;\r\n\r\n // Step 4: Build the final SELECT query using all generated CTEs\r\n return this.buildFinalSelectQuery(\r\n ctesForProcessing,\r\n currentAliasToBuildUpon,\r\n allEntities,\r\n mapping\r\n );\r\n }\r\n\r\n /**\r\n * Creates the initial Common Table Expression (CTE) from the original query.\r\n * @param originalQuery The base SimpleSelectQuery.\r\n * @returns An object containing the initial CTE and its alias.\r\n */\r\n private createInitialCte(originalQuery: SimpleSelectQuery): { initialCte: CommonTable, initialCteAlias: string } {\r\n const originCteAlias = \"origin_query\";\r\n const originCte = new CommonTable(\r\n originalQuery,\r\n new SourceAliasExpression(originCteAlias, null),\r\n null\r\n );\r\n return { initialCte: originCte, initialCteAlias: originCteAlias };\r\n }\r\n\r\n /**\r\n * Builds the final SELECT query that constructs the root JSON object (or array of objects).\r\n * This query uses all previously generated CTEs.\r\n * @param finalCtesList The complete list of all CTEs (initial and array CTEs).\r\n * @param lastCteAliasForFromClause Alias of the final CTE from which the root object will be built.\r\n * @param allEntities Map of all processable entities.\r\n * @param mapping JSON mapping configuration.\r\n * @returns The final SimpleSelectQuery.\r\n */\r\n private buildFinalSelectQuery(\r\n finalCtesList: CommonTable[],\r\n lastCteAliasForFromClause: string,\r\n allEntities: Map<string, ProcessableEntity>,\r\n mapping: JsonMapping\r\n ): SimpleSelectQuery {\r\n const currentCtes = [...finalCtesList];\r\n\r\n // Define rootObjectCteAlias outside of if block\r\n const rootObjectCteAlias = `cte_root_${mapping.rootName.toLowerCase().replace(/[^a-z0-9_]/g, '_')}`;\r\n const rootEntity = allEntities.get(mapping.rootEntity.id);\r\n if (!rootEntity) {\r\n throw new Error(`Root entity ${mapping.rootEntity.id} not found`);\r\n }\r\n if (mapping.resultFormat === \"array\" || !mapping.resultFormat) {\r\n // Step 4.1a: Create a CTE that wraps the final result as the root object // No alias needed for single table SELECT\r\n const rootObjectBuilderExpression = this.buildEntityJsonObject(\r\n rootEntity,\r\n null, // No source alias for single table\r\n mapping.nestedEntities,\r\n allEntities\r\n );\r\n\r\n const rootObjectSelectItem = new SelectItem(rootObjectBuilderExpression, mapping.rootName);\r\n const rootObjectCte = new CommonTable(\r\n new SimpleSelectQuery({\r\n selectClause: new SelectClause([rootObjectSelectItem]),\r\n fromClause: new FromClause(\r\n new SourceExpression(\r\n new TableSource(null, new IdentifierString(lastCteAliasForFromClause)),\r\n null // No alias\r\n ),\r\n null\r\n ),\r\n }),\r\n new SourceAliasExpression(rootObjectCteAlias, null),\r\n null\r\n );\r\n currentCtes.push(rootObjectCte);\r\n\r\n // Step 4.1b: Aggregate all the root objects\r\n const aggregationFunc = \"jsonb_agg\"; // Always use JSONB\r\n const aggregateExpression = new FunctionCall(\r\n null,\r\n new RawString(aggregationFunc),\r\n new ValueList([new ColumnReference(null, new IdentifierString(mapping.rootName))]),\r\n null\r\n );\r\n\r\n return new SimpleSelectQuery({\r\n withClause: new WithClause(false, currentCtes),\r\n selectClause: new SelectClause([\r\n new SelectItem(aggregateExpression, `${mapping.rootName}_array`)\r\n ]),\r\n fromClause: new FromClause(\r\n new SourceExpression(new TableSource(null, new IdentifierString(rootObjectCteAlias)), null),\r\n null\r\n ),\r\n });\r\n } else {\r\n // For a single object result, create root object CTE without alias\r\n const rootObjectBuilderExpression = this.buildEntityJsonObject(\r\n rootEntity,\r\n null, // No source alias for single table\r\n mapping.nestedEntities,\r\n allEntities\r\n );\r\n\r\n const rootObjectSelectItem = new SelectItem(rootObjectBuilderExpression, mapping.rootName);\r\n const rootObjectCte = new CommonTable(\r\n new SimpleSelectQuery({\r\n selectClause: new SelectClause([rootObjectSelectItem]),\r\n fromClause: new FromClause(\r\n new SourceExpression(\r\n new TableSource(null, new IdentifierString(lastCteAliasForFromClause)),\r\n null // No alias\r\n ),\r\n null\r\n ),\r\n }),\r\n new SourceAliasExpression(rootObjectCteAlias, null),\r\n null\r\n );\r\n currentCtes.push(rootObjectCte);\r\n\r\n // Select directly from the root_object_cte with LIMIT 1\r\n return new SimpleSelectQuery({\r\n withClause: new WithClause(false, currentCtes),\r\n selectClause: new SelectClause([\r\n new SelectItem(new ColumnReference(null, new IdentifierString(mapping.rootName)), mapping.rootName)\r\n ]),\r\n fromClause: new FromClause(\r\n new SourceExpression(new TableSource(null, new IdentifierString(rootObjectCteAlias)), null),\r\n null\r\n ),\r\n limitClause: new LimitClause(new LiteralValue(1)) // Correctly use LimitClause\r\n });\r\n }\r\n }\r\n\r\n /**\r\n * Build JSON object for entity, using parent JSON columns when available\r\n */\r\n private buildEntityJsonObject(\r\n entity: ProcessableEntity,\r\n sourceAlias: string | null,\r\n nestedEntities: JsonMapping['nestedEntities'],\r\n allEntities: Map<string, ProcessableEntity>\r\n ): ValueComponent {\r\n const jsonBuildFunction = \"jsonb_build_object\";\r\n const args: ValueComponent[] = [];\r\n\r\n // Add the entity's own columns\r\n Object.entries(entity.columns).forEach(([jsonKey, columnDef]) => {\r\n // Handle both string and object formats\r\n const sqlColumn = typeof columnDef === 'string' ? columnDef : (columnDef as any).column;\r\n args.push(new LiteralValue(jsonKey));\r\n args.push(new ColumnReference(null, new IdentifierString(sqlColumn)));\r\n });\r\n\r\n // Find and process child entities (both object and array types)\r\n const childEntities = nestedEntities.filter((ne) => ne.parentId === entity.id);\r\n\r\n childEntities.forEach((childEntity) => {\r\n const child = allEntities.get(childEntity.id);\r\n if (!child) return;\r\n\r\n args.push(new LiteralValue(childEntity.propertyName)); if (childEntity.relationshipType === \"object\") {\r\n // For object relationships, use pre-computed JSON column\r\n // Use entity ID instead of name to avoid naming conflicts\r\n const jsonColumnName = `${child.id.toLowerCase()}_json`;\r\n args.push(new ColumnReference(null, new IdentifierString(jsonColumnName)));\r\n } else if (childEntity.relationshipType === \"array\") {\r\n // For array relationships, use the column directly\r\n args.push(new ColumnReference(null, new IdentifierString(childEntity.propertyName)));\r\n }\r\n });\r\n\r\n return new FunctionCall(null, new RawString(jsonBuildFunction), new ValueList(args), null);\r\n }\r\n}", "/**\r\n * Enhanced JSON mapping structure that integrates column mapping and type protection configuration.\r\n * This unified approach eliminates the need for separate .types.json files.\r\n */\r\n\r\nimport { JsonMapping } from './PostgresJsonQueryBuilder';\r\n\r\n/**\r\n * Supported column type enforcement options.\r\n */\r\nexport type ColumnType = 'string' | 'auto';\r\n\r\n/**\r\n * Column configuration that can either be a simple string mapping or an enhanced mapping with type control.\r\n */\r\nexport type ColumnMappingConfig = string | {\r\n column: string;\r\n type?: ColumnType;\r\n};\r\n\r\n/**\r\n * Enhanced JSON mapping configuration with integrated type protection.\r\n */\r\nexport interface UnifiedJsonMapping {\r\n rootName: string;\r\n typeInfo?: {\r\n interface: string;\r\n importPath: string;\r\n };\r\n rootEntity: {\r\n id: string;\r\n name: string;\r\n columns: Record<string, ColumnMappingConfig>;\r\n };\r\n nestedEntities?: Array<{\r\n id: string;\r\n name: string;\r\n parentId: string;\r\n propertyName: string; relationshipType: 'object' | 'array';\r\n columns: Record<string, ColumnMappingConfig>;\r\n }>;\r\n}\r\n\r\n/**\r\n * Type protection configuration extracted from the unified mapping.\r\n */\r\nexport interface TypeProtectionConfig {\r\n protectedStringFields: string[];\r\n}\r\n\r\n/**\r\n * Convert a unified JSON mapping to separate JsonMapping and TypeProtectionConfig.\r\n * This enables backward compatibility with existing code while supporting the new unified structure.\r\n */\r\nexport function convertUnifiedMapping(unified: UnifiedJsonMapping): {\r\n jsonMapping: JsonMapping;\r\n typeProtection: TypeProtectionConfig;\r\n} {\r\n const protectedStringFields: string[] = [];\r\n\r\n // Helper function to process columns and extract string protection settings\r\n const processColumns = (columns: Record<string, ColumnMappingConfig>): Record<string, string> => {\r\n const result: Record<string, string> = {};\r\n\r\n for (const [key, config] of Object.entries(columns)) {\r\n if (typeof config === 'string') {\r\n result[key] = config;\r\n } else {\r\n result[key] = config.column;\r\n if (config.type === 'string') {\r\n protectedStringFields.push(config.column);\r\n }\r\n }\r\n }\r\n\r\n return result;\r\n };\r\n\r\n // Convert the unified mapping to traditional JsonMapping\r\n const jsonMapping: JsonMapping = {\r\n rootName: unified.rootName,\r\n rootEntity: {\r\n id: unified.rootEntity.id,\r\n name: unified.rootEntity.name, columns: processColumns(unified.rootEntity.columns)\r\n },\r\n nestedEntities: [] // Initialize as empty array\r\n };\r\n\r\n // Add typeInfo if it exists\r\n if (unified.typeInfo) {\r\n // Note: JsonMapping doesn't have typeInfo in core, but we preserve it for backward compatibility\r\n (jsonMapping as any).typeInfo = unified.typeInfo;\r\n }\r\n\r\n // Process nested entities if they exist\r\n if (unified.nestedEntities) {\r\n jsonMapping.nestedEntities = unified.nestedEntities.map(entity => ({\r\n id: entity.id,\r\n name: entity.name,\r\n parentId: entity.parentId,\r\n propertyName: entity.propertyName,\r\n relationshipType: entity.relationshipType,\r\n columns: processColumns(entity.columns)\r\n }));\r\n }\r\n\r\n return {\r\n jsonMapping,\r\n typeProtection: { protectedStringFields }\r\n };\r\n}\r\n", "/**\r\n * Model-driven JSON mapping structure that mirrors TypeScript model definitions.\r\n * This approach provides intuitive, hierarchical mapping that closely resembles the target data structure.\r\n */\r\n\r\nimport { JsonMapping } from './PostgresJsonQueryBuilder';\r\n\r\n/**\r\n * Supported field types for database column mapping.\r\n */\r\nexport type FieldType = 'string' | 'number' | 'boolean' | 'object' | 'array' | 'auto';\r\n\r\n/**\r\n * Field mapping configuration that can be either a simple column name or enhanced mapping with type control.\r\n */\r\nexport type FieldMapping = string | {\r\n column: string;\r\n type?: FieldType;\r\n} | {\r\n from: string; // Legacy support\r\n type?: FieldType;\r\n};\r\n\r\n/**\r\n * Nested object or array structure definition.\r\n */\r\nexport interface NestedStructure {\r\n type: 'object' | 'array';\r\n from: string; // SQL table alias\r\n structure: StructureFields;\r\n}\r\n\r\n/**\r\n * Structure fields can contain either field mappings or nested structures.\r\n */\r\nexport type StructureFields = {\r\n [key: string]: FieldMapping | NestedStructure;\r\n};\r\n\r\n/**\r\n * Model-driven JSON mapping that mirrors TypeScript interface structure.\r\n * This design makes it easy to understand the relationship between models and database columns.\r\n */\r\nexport interface ModelDrivenJsonMapping {\r\n typeInfo: {\r\n interface: string;\r\n importPath: string;\r\n };\r\n structure: StructureFields;\r\n}\r\n\r\n/**\r\n * Type protection configuration extracted from the model-driven mapping.\r\n */\r\nexport interface TypeProtectionConfig {\r\n protectedStringFields: string[];\r\n}\r\n\r\n/**\r\n * Convert a model-driven JSON mapping to the traditional JsonMapping format.\r\n * This enables backward compatibility with existing PostgresJsonQueryBuilder.\r\n */\r\nexport function convertModelDrivenMapping(modelMapping: ModelDrivenJsonMapping): {\r\n jsonMapping: JsonMapping;\r\n typeProtection: TypeProtectionConfig;\r\n} {\r\n const protectedStringFields: string[] = [];\r\n let entityIdCounter = 0;\r\n\r\n // Generate unique entity IDs\r\n const generateEntityId = () => `entity_${++entityIdCounter}`;\r\n // Helper function to process structure fields and extract entities\r\n const processStructure = (\r\n structure: StructureFields,\r\n parentId: string | null = null\r\n ): {\r\n columns: Record<string, string>;\r\n nestedEntities: any[];\r\n } => {\r\n const columns: Record<string, string> = {};\r\n const nestedEntities: any[] = []; for (const [fieldName, config] of Object.entries(structure)) {\r\n if (typeof config === 'string') {\r\n // Simple field mapping: \"fieldName\": \"column_name\"\r\n columns[fieldName] = config;\r\n } else if ('column' in config && typeof config.column === 'string' && !('type' in config && (config.type === 'object' || config.type === 'array'))) {\r\n // Enhanced field mapping: \"fieldName\": { \"column\": \"column_name\", \"type\": \"string\" }\r\n const fieldConfig = config as FieldMapping;\r\n if (typeof fieldConfig === 'object' && 'column' in fieldConfig) {\r\n columns[fieldName] = fieldConfig.column;\r\n if (fieldConfig.type === 'string') {\r\n protectedStringFields.push(fieldConfig.column);\r\n }\r\n }\r\n } else if ('from' in config && typeof config.from === 'string' && !('type' in config && (config.type === 'object' || config.type === 'array'))) {\r\n // Legacy field mapping: \"fieldName\": { \"from\": \"column_name\", \"type\": \"string\" }\r\n const fieldConfig = config as FieldMapping;\r\n if (typeof fieldConfig === 'object' && 'from' in fieldConfig) {\r\n columns[fieldName] = fieldConfig.from;\r\n if (fieldConfig.type === 'string') {\r\n protectedStringFields.push(fieldConfig.from);\r\n }\r\n }\r\n } else if ('type' in config && (config.type === 'object' || config.type === 'array')) {\r\n // Nested structure: object or array\r\n const nestedStructure = config as NestedStructure;\r\n const entityId = generateEntityId();\r\n\r\n const processedNested = processStructure(nestedStructure.structure, entityId);\r\n\r\n nestedEntities.push({\r\n id: entityId,\r\n name: fieldName.charAt(0).toUpperCase() + fieldName.slice(1), // Capitalize first letter\r\n parentId: parentId || 'root',\r\n propertyName: fieldName,\r\n relationshipType: nestedStructure.type,\r\n columns: processedNested.columns\r\n });\r\n\r\n // Add nested entities from deeper levels\r\n nestedEntities.push(...processedNested.nestedEntities.map(entity => ({\r\n ...entity,\r\n parentId: entity.parentId === 'root' ? entityId : entity.parentId\r\n })));\r\n }\r\n }\r\n\r\n return { columns, nestedEntities };\r\n };\r\n\r\n // Process the root structure\r\n const processed = processStructure(modelMapping.structure); // Build the traditional JsonMapping\r\n const jsonMapping: JsonMapping = {\r\n rootName: 'root', // Default root name\r\n rootEntity: {\r\n id: 'root',\r\n name: 'Root',\r\n columns: processed.columns\r\n },\r\n nestedEntities: processed.nestedEntities\r\n };\r\n\r\n // Add typeInfo for backward compatibility\r\n (jsonMapping as any).typeInfo = modelMapping.typeInfo;\r\n\r\n return {\r\n jsonMapping,\r\n typeProtection: { protectedStringFields }\r\n };\r\n}\r\n\r\n/**\r\n * Validate that a model-driven mapping structure is well-formed.\r\n */\r\nexport function validateModelDrivenMapping(mapping: ModelDrivenJsonMapping): string[] {\r\n const errors: string[] = [];\r\n\r\n // Validate typeInfo\r\n if (!mapping.typeInfo) {\r\n errors.push('typeInfo is required');\r\n } else {\r\n if (!mapping.typeInfo.interface) {\r\n errors.push('typeInfo.interface is required');\r\n }\r\n if (!mapping.typeInfo.importPath) {\r\n errors.push('typeInfo.importPath is required');\r\n }\r\n }\r\n\r\n // Validate structure\r\n if (!mapping.structure || typeof mapping.structure !== 'object') {\r\n errors.push('structure is required and must be an object');\r\n }\r\n\r\n return errors;\r\n}\r\n", "/**\r\n * Unified JSON Mapping processor that supports both legacy and model-driven formats.\r\n * \r\n * This module provides backward compatibility while encouraging migration to the model-driven format.\r\n * It automatically detects the input format and normalizes to a consistent internal representation.\r\n */\r\n\r\nimport { JsonMapping } from './PostgresJsonQueryBuilder';\r\nimport { ModelDrivenJsonMapping, convertModelDrivenMapping } from './ModelDrivenJsonMapping';\r\n\r\n/**\r\n * Unified mapping format that can handle both legacy and model-driven inputs.\r\n */\r\nexport interface UnifiedMappingInput {\r\n // Model-driven format\r\n typeInfo?: {\r\n interface: string;\r\n importPath: string;\r\n };\r\n structure?: any;\r\n protectedStringFields?: string[];\r\n\r\n // Legacy format detection fields\r\n rootName?: string;\r\n rootEntity?: any;\r\n nestedEntities?: any[];\r\n\r\n // Direct JsonMapping fields (for backward compatibility)\r\n columns?: any;\r\n relationships?: any;\r\n}\r\n\r\n/**\r\n * Result of mapping format detection and conversion.\r\n */\r\nexport interface MappingProcessResult {\r\n format: 'model-driven' | 'unified' | 'legacy';\r\n jsonMapping: JsonMapping;\r\n originalInput: UnifiedMappingInput;\r\n metadata?: {\r\n typeInfo?: {\r\n interface: string;\r\n importPath: string;\r\n };\r\n protectedStringFields?: string[];\r\n typeProtection?: any; // From model-driven conversion\r\n };\r\n}\r\n\r\n/**\r\n * Detects the format of a JSON mapping configuration.\r\n * \r\n * @param input - The mapping configuration to analyze\r\n * @returns The detected format type\r\n */\r\nexport function detectMappingFormat(input: UnifiedMappingInput): 'model-driven' | 'unified' | 'legacy' {\r\n // Model-driven format: has typeInfo and structure\r\n if (input.typeInfo && input.structure) {\r\n return 'model-driven';\r\n }\r\n\r\n // Unified format: has rootName and rootEntity\r\n if (input.rootName && input.rootEntity) {\r\n return 'unified';\r\n }\r\n\r\n // Legacy format: direct JsonMapping structure\r\n if (input.columns || input.relationships) {\r\n return 'legacy';\r\n }\r\n\r\n // Default fallback\r\n return 'legacy';\r\n}\r\n\r\n/**\r\n * Converts legacy unified format to JsonMapping.\r\n * \r\n * @param input - Unified format mapping configuration\r\n * @returns Converted JsonMapping\r\n */\r\nfunction convertUnifiedFormat(input: UnifiedMappingInput): JsonMapping {\r\n if (!input.rootEntity) {\r\n throw new Error('Unified format requires rootEntity');\r\n }\r\n\r\n const result: JsonMapping = {\r\n rootName: input.rootName || 'root',\r\n rootEntity: {\r\n id: input.rootEntity.id || 'root',\r\n name: input.rootEntity.name || 'Root',\r\n columns: input.rootEntity.columns || {}\r\n },\r\n nestedEntities: []\r\n };\r\n\r\n // Convert nestedEntities\r\n if (input.nestedEntities && Array.isArray(input.nestedEntities)) {\r\n result.nestedEntities = input.nestedEntities.map(entity => ({\r\n id: entity.id || entity.propertyName || 'nested',\r\n name: entity.name || entity.propertyName || 'Nested',\r\n parentId: entity.parentId || result.rootEntity.id,\r\n propertyName: entity.propertyName || 'nested',\r\n relationshipType: entity.relationshipType || 'object',\r\n columns: entity.columns || {}\r\n }));\r\n }\r\n\r\n return result;\r\n}\r\n\r\n/**\r\n * Converts legacy format directly to JsonMapping.\r\n * \r\n * @param input - Legacy format mapping configuration\r\n * @returns JsonMapping\r\n */\r\nfunction convertLegacyFormat(input: UnifiedMappingInput): JsonMapping {\r\n const result: JsonMapping = {\r\n rootName: input.rootName || 'root',\r\n rootEntity: {\r\n id: 'root',\r\n name: input.rootName || 'Root',\r\n columns: input.columns || {}\r\n },\r\n nestedEntities: []\r\n };\r\n // Convert relationships to nestedEntities\r\n if (input.relationships && typeof input.relationships === 'object') {\r\n for (const [propertyName, relationship] of Object.entries(input.relationships)) {\r\n // Type assertion for legacy relationship format\r\n const rel = relationship as any;\r\n result.nestedEntities.push({\r\n id: propertyName,\r\n name: propertyName.charAt(0).toUpperCase() + propertyName.slice(1),\r\n parentId: 'root',\r\n propertyName,\r\n relationshipType: rel.type === 'hasMany' ? 'array' : 'object',\r\n columns: rel.columns || {}\r\n });\r\n }\r\n }\r\n\r\n return result;\r\n}\r\n\r\n/**\r\n * Main processor that unifies all JSON mapping formats into a consistent JsonMapping.\r\n * \r\n * Features:\r\n * - Automatic format detection\r\n * - Backward compatibility with all existing formats\r\n * - Metadata preservation for advanced features\r\n * - Zero external dependencies\r\n * \r\n * @param input - Any supported JSON mapping format\r\n * @returns Unified processing result with JsonMapping and metadata\r\n */\r\nexport function processJsonMapping(input: UnifiedMappingInput): MappingProcessResult {\r\n const format = detectMappingFormat(input);\r\n let jsonMapping: JsonMapping;\r\n let metadata: MappingProcessResult['metadata'] = {};\r\n try {\r\n switch (format) {\r\n case 'model-driven':\r\n // Validate model-driven input\r\n if (!input.typeInfo || !input.structure) {\r\n throw new Error('Model-driven format requires typeInfo and structure fields');\r\n }\r\n\r\n // Convert model-driven to JsonMapping\r\n const modelDrivenInput: ModelDrivenJsonMapping = {\r\n typeInfo: input.typeInfo!,\r\n structure: input.structure!\r\n };\r\n\r\n const converted = convertModelDrivenMapping(modelDrivenInput);\r\n jsonMapping = converted.jsonMapping;\r\n\r\n // Preserve metadata\r\n metadata = {\r\n typeInfo: input.typeInfo,\r\n typeProtection: converted.typeProtection\r\n };\r\n break;\r\n\r\n case 'unified':\r\n // Validate unified input\r\n if (!input.rootEntity) {\r\n throw new Error('Unified format requires rootEntity field');\r\n }\r\n\r\n jsonMapping = convertUnifiedFormat(input);\r\n break;\r\n\r\n case 'legacy':\r\n // Validate legacy input\r\n if (!input.columns && !input.relationships) {\r\n throw new Error('Legacy format requires at least columns or relationships field');\r\n }\r\n\r\n jsonMapping = convertLegacyFormat(input);\r\n break;\r\n\r\n default:\r\n throw new Error(`Unsupported mapping format: ${format}`);\r\n }\r\n\r\n return {\r\n format,\r\n jsonMapping,\r\n originalInput: input,\r\n metadata\r\n };\r\n\r\n } catch (error) {\r\n throw new Error(`Failed to process JSON mapping (format: ${format}): ${error instanceof Error ? error.message : String(error)}`);\r\n }\r\n}\r\n\r\n/**\r\n * Convenience function for direct JsonMapping extraction.\r\n * \r\n * @param input - Any supported JSON mapping format\r\n * @returns JsonMapping ready for use with PostgresJsonQueryBuilder\r\n */\r\nexport function unifyJsonMapping(input: UnifiedMappingInput): JsonMapping {\r\n return processJsonMapping(input).jsonMapping;\r\n}\r\n\r\n/**\r\n * Type guard to check if input uses model-driven format.\r\n * \r\n * @param input - Mapping input to check\r\n * @returns True if input is model-driven format\r\n */\r\nexport function isModelDrivenFormat(input: UnifiedMappingInput): input is ModelDrivenJsonMapping {\r\n return detectMappingFormat(input) === 'model-driven';\r\n}\r\n\r\n/**\r\n * Type guard to check if input uses unified format.\r\n * \r\n * @param input - Mapping input to check\r\n * @returns True if input is unified format\r\n */\r\nexport function isUnifiedFormat(input: UnifiedMappingInput): boolean {\r\n return detectMappingFormat(input) === 'unified';\r\n}\r\n\r\n/**\r\n * Type guard to check if input uses legacy format.\r\n * \r\n * @param input - Mapping input to check\r\n * @returns True if input is legacy format\r\n */\r\nexport function isLegacyFormat(input: UnifiedMappingInput): boolean {\r\n return detectMappingFormat(input) === 'legacy';\r\n}\r\n\r\n/**\r\n * Migration helper that suggests upgrading to model-driven format.\r\n * \r\n * @param input - Current mapping configuration\r\n * @returns Suggestions for migration (if applicable)\r\n */\r\nexport function suggestModelDrivenMigration(input: UnifiedMappingInput): string[] {\r\n const format = detectMappingFormat(input);\r\n const suggestions: string[] = [];\r\n\r\n if (format !== 'model-driven') {\r\n suggestions.push('Consider migrating to model-driven JSON mapping format');\r\n suggestions.push('Benefits: Better type safety, IDE support, and future-proof design');\r\n suggestions.push('See: Model-Driven JSON Mapping Guide for migration instructions');\r\n\r\n if (format === 'unified') {\r\n suggestions.push('Your current unified format can be automatically converted');\r\n }\r\n\r\n if (format === 'legacy') {\r\n suggestions.push('Legacy format support will be maintained but new features target model-driven format');\r\n }\r\n }\r\n\r\n return suggestions;\r\n}\r\n", "/**\r\n * Post-processor for transforming database values to appropriate TypeScript types\r\n * after JSON serialization from PostgreSQL\r\n */\r\n\r\nexport interface TypeTransformationConfig {\r\n /** Column transformations mapping - takes precedence over value-based detection */\r\n columnTransformations?: {\r\n [columnName: string]: TypeTransformation;\r\n };\r\n /** Global transformation rules by SQL data type */\r\n globalTransformations?: {\r\n [sqlType: string]: TypeTransformation;\r\n };\r\n /** Custom transformation functions */\r\n customTransformers?: {\r\n [transformerName: string]: (value: any) => any;\r\n };\r\n /** Enable value-based type detection when column mapping is not provided (default: true) */\r\n enableValueBasedDetection?: boolean;\r\n /** Strict date detection - only convert ISO 8601 with 'T' separator (default: false) */\r\n strictDateDetection?: boolean;\r\n}\r\n\r\nexport interface TypeTransformation {\r\n /** Source SQL data type */\r\n sourceType: 'DATE' | 'TIMESTAMP' | 'BIGINT' | 'NUMERIC' | 'JSONB' | 'custom';\r\n /** Target TypeScript type representation */\r\n targetType: 'Date' | 'bigint' | 'string' | 'number' | 'object' | 'custom';\r\n /** Custom transformer function name (for custom type) */\r\n customTransformer?: string;\r\n /** Whether to handle null values (default: true) */\r\n handleNull?: boolean;\r\n /** Validation function for the value */\r\n validator?: (value: any) => boolean;\r\n}\r\n\r\n/**\r\n * Applies type transformations to JSON results from PostgreSQL\r\n */\r\nexport class TypeTransformationPostProcessor {\r\n private config: TypeTransformationConfig; constructor(config: TypeTransformationConfig = {}) {\r\n this.config = {\r\n enableValueBasedDetection: true,\r\n strictDateDetection: false,\r\n ...config\r\n };\r\n }\r\n\r\n /**\r\n * Transform a single result object\r\n * @param result The result object from PostgreSQL JSON query\r\n * @returns Transformed result with proper TypeScript types\r\n */\r\n public transformResult<T = any>(result: any): T {\r\n if (result === null || result === undefined) {\r\n return result;\r\n }\r\n\r\n if (Array.isArray(result)) {\r\n return result.map(item => this.transformSingleObject(item)) as T;\r\n }\r\n\r\n return this.transformSingleObject(result) as T;\r\n }\r\n\r\n /**\r\n * Transform a single object recursively\r\n */\r\n private transformSingleObject(obj: any): any {\r\n if (obj === null || obj === undefined || typeof obj !== 'object') {\r\n return obj;\r\n }\r\n\r\n if (Array.isArray(obj)) {\r\n return obj.map(item => this.transformSingleObject(item));\r\n }\r\n\r\n const transformed: any = {};\r\n\r\n for (const [key, value] of Object.entries(obj)) {\r\n if (value === null || value === undefined) {\r\n transformed[key] = value;\r\n continue;\r\n } // Check for column-specific transformation first (takes precedence)\r\n const columnTransform = this.config.columnTransformations?.[key];\r\n if (columnTransform) {\r\n transformed[key] = this.applyTransformation(value, columnTransform);\r\n continue;\r\n }\r\n\r\n // Only apply value-based detection if enabled and no column mapping exists\r\n if (this.config.enableValueBasedDetection) {\r\n const detectedTransform = this.detectValueBasedTransformation(value);\r\n if (detectedTransform) {\r\n transformed[key] = this.applyTransformation(value, detectedTransform);\r\n continue;\r\n }\r\n }\r\n\r\n // Apply global transformations based on SQL type (if available)\r\n const globalTransform = this.config.globalTransformations &&\r\n this.getGlobalTransformationForValue(value);\r\n if (globalTransform) {\r\n transformed[key] = this.applyTransformation(value, globalTransform);\r\n continue;\r\n }\r\n\r\n // Recursively transform nested objects\r\n if (typeof value === 'object' && !Array.isArray(value)) {\r\n transformed[key] = this.transformSingleObject(value);\r\n continue;\r\n }\r\n\r\n if (Array.isArray(value)) {\r\n transformed[key] = value.map(item =>\r\n typeof item === 'object' ? this.transformSingleObject(item) : item\r\n );\r\n continue;\r\n }\r\n\r\n // No transformation needed\r\n transformed[key] = value;\r\n }\r\n\r\n return transformed;\r\n }\r\n\r\n /**\r\n * Detect value type and create appropriate transformation based on value characteristics\r\n * This is the core value-based detection logic\r\n */\r\n private detectValueBasedTransformation(value: any): TypeTransformation | null {\r\n // Date string detection\r\n if (typeof value === 'string' && this.isDateString(value)) {\r\n return {\r\n sourceType: 'TIMESTAMP',\r\n targetType: 'Date',\r\n handleNull: true,\r\n validator: (v) => typeof v === 'string' && !isNaN(Date.parse(v))\r\n };\r\n }\r\n\r\n // BigInt detection (number > MAX_SAFE_INTEGER)\r\n if (typeof value === 'number' && !Number.isSafeInteger(value)) {\r\n return {\r\n sourceType: 'BIGINT',\r\n targetType: 'bigint',\r\n handleNull: true,\r\n validator: (v) => {\r\n try {\r\n BigInt(v);\r\n return true;\r\n } catch {\r\n return false;\r\n }\r\n }\r\n };\r\n }\r\n\r\n // Large string number detection (potential BIGINT)\r\n if (typeof value === 'string' && /^\\d{16,}$/.test(value)) {\r\n return {\r\n sourceType: 'BIGINT',\r\n targetType: 'bigint',\r\n handleNull: true,\r\n validator: (v) => {\r\n try {\r\n BigInt(v);\r\n return true;\r\n } catch {\r\n return false;\r\n }\r\n }\r\n };\r\n }\r\n\r\n return null;\r\n }\r\n\r\n /**\r\n * Get global transformation for a specific value (if any match)\r\n * This is separate from value-based detection and relies on configured global rules\r\n */\r\n private getGlobalTransformationForValue(value: any): TypeTransformation | null {\r\n if (!this.config.globalTransformations) {\r\n return null;\r\n }\r\n\r\n // This could be extended to match values against configured global rules\r\n // For now, it's a placeholder for future SQL-type-based global transformations\r\n return null;\r\n }\r\n\r\n /**\r\n * @deprecated Use detectValueBasedTransformation instead\r\n * Detect value type and get appropriate global transformation\r\n */\r\n private detectAndGetGlobalTransformation(value: any): TypeTransformation | null {\r\n return this.detectValueBasedTransformation(value);\r\n }\r\n\r\n /**\r\n * Check if string is a valid date string\r\n * Supports both strict (ISO 8601 with T separator) and loose detection\r\n */\r\n private isDateString(value: string): boolean {\r\n if (this.config.strictDateDetection) {\r\n // Strict: Only ISO 8601 with T separator (safer for user input)\r\n const strictIsoPattern = /^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}(?:\\.\\d{3})?(?:Z|[+-]\\d{2}:\\d{2})?$/;\r\n if (!strictIsoPattern.test(value)) {\r\n return false;\r\n }\r\n } else {\r\n // Loose: ISO 8601 date pattern (includes date-only strings)\r\n const isoDatePattern = /^\\d{4}-\\d{2}-\\d{2}(?:T\\d{2}:\\d{2}:\\d{2}(?:\\.\\d{3})?(?:Z|[+-]\\d{2}:\\d{2})?)?$/;\r\n if (!isoDatePattern.test(value)) {\r\n return false;\r\n }\r\n }\r\n\r\n const date = new Date(value);\r\n return !isNaN(date.getTime());\r\n }\r\n\r\n /**\r\n * Apply a specific transformation to a value\r\n */\r\n private applyTransformation(value: any, transformation: TypeTransformation): any {\r\n // Handle null values\r\n if (value === null || value === undefined) {\r\n return transformation.handleNull !== false ? value : null;\r\n }\r\n\r\n // Validate value if validator is provided\r\n if (transformation.validator && !transformation.validator(value)) {\r\n console.warn(`TypeTransformationPostProcessor: Value validation failed for ${value}`);\r\n return value;\r\n }\r\n\r\n try {\r\n switch (transformation.targetType) {\r\n case 'Date':\r\n return new Date(value); case 'bigint':\r\n // Handle both string and number inputs for BIGINT\r\n // For scientific notation numbers, convert to integer first\r\n if (typeof value === 'number') {\r\n // Convert scientific notation to integer string\r\n const integerValue = Math.trunc(value);\r\n return BigInt(integerValue.toString());\r\n }\r\n return BigInt(value);\r\n\r\n case 'string':\r\n return value.toString();\r\n\r\n case 'number':\r\n return typeof value === 'string' ? parseFloat(value) : Number(value);\r\n\r\n case 'object':\r\n return typeof value === 'string' ? JSON.parse(value) : value;\r\n\r\n case 'custom':\r\n if (transformation.customTransformer &&\r\n this.config.customTransformers?.[transformation.customTransformer]) {\r\n return this.config.customTransformers[transformation.customTransformer](value);\r\n }\r\n break;\r\n\r\n default:\r\n return value;\r\n }\r\n } catch (error) {\r\n console.warn(`TypeTransformationPostProcessor: Transformation failed for ${value}:`, error);\r\n return value;\r\n }\r\n\r\n return value;\r\n }\r\n\r\n /**\r\n * Create a default configuration for common PostgreSQL types\r\n * Enables value-based detection with loose date detection by default\r\n */\r\n public static createDefaultConfig(): TypeTransformationConfig {\r\n return {\r\n enableValueBasedDetection: true,\r\n strictDateDetection: false,\r\n globalTransformations: {\r\n 'DATE': {\r\n sourceType: 'DATE',\r\n targetType: 'Date',\r\n handleNull: true,\r\n validator: (value) => typeof value === 'string' && !isNaN(Date.parse(value))\r\n },\r\n 'TIMESTAMP': {\r\n sourceType: 'TIMESTAMP',\r\n targetType: 'Date',\r\n handleNull: true,\r\n validator: (value) => typeof value === 'string' && !isNaN(Date.parse(value))\r\n },\r\n 'BIGINT': {\r\n sourceType: 'BIGINT',\r\n targetType: 'bigint',\r\n handleNull: true,\r\n validator: (value) => {\r\n try {\r\n BigInt(value);\r\n return true;\r\n } catch {\r\n return false;\r\n }\r\n }\r\n }\r\n }\r\n };\r\n }\r\n\r\n /**\r\n * Create a safe configuration for handling user input\r\n * Disables value-based detection and uses strict date detection\r\n */\r\n public static createSafeConfig(columnMappings?: { [columnName: string]: TypeTransformation }): TypeTransformationConfig {\r\n return {\r\n enableValueBasedDetection: false,\r\n strictDateDetection: true,\r\n columnTransformations: columnMappings || {},\r\n globalTransformations: {\r\n 'DATE': {\r\n sourceType: 'DATE',\r\n targetType: 'Date',\r\n handleNull: true,\r\n validator: (value) => typeof value === 'string' && !isNaN(Date.parse(value))\r\n },\r\n 'TIMESTAMP': {\r\n sourceType: 'TIMESTAMP',\r\n targetType: 'Date',\r\n handleNull: true,\r\n validator: (value) => typeof value === 'string' && !isNaN(Date.parse(value))\r\n },\r\n 'BIGINT': {\r\n sourceType: 'BIGINT',\r\n targetType: 'bigint',\r\n handleNull: true,\r\n validator: (value) => {\r\n try {\r\n BigInt(value);\r\n return true;\r\n } catch {\r\n return false;\r\n }\r\n }\r\n }\r\n }\r\n };\r\n }\r\n}\r\n\r\n/**\r\n * Convenience function to create and apply transformations\r\n */\r\nexport function transformDatabaseResult<T = any>(\r\n result: any,\r\n config?: TypeTransformationConfig\r\n): T {\r\n const processor = new TypeTransformationPostProcessor(\r\n config || TypeTransformationPostProcessor.createDefaultConfig()\r\n );\r\n return processor.transformResult<T>(result);\r\n}\r\n\r\n/**\r\n * Type-safe transformation helpers\r\n */\r\nexport const TypeTransformers = {\r\n /**\r\n * Transform date string to Date object\r\n */\r\n toDate: (value: string | null): Date | null => {\r\n if (value === null || value === undefined) return null;\r\n const date = new Date(value);\r\n return isNaN(date.getTime()) ? null : date;\r\n },\r\n\r\n /**\r\n * Transform numeric string to BigInt\r\n */\r\n toBigInt: (value: string | number | null): bigint | null => {\r\n if (value === null || value === undefined) return null;\r\n try {\r\n return BigInt(value);\r\n } catch {\r\n return null;\r\n }\r\n },\r\n\r\n /**\r\n * Transform JSON string to object\r\n */\r\n toObject: <T = any>(value: string | null): T | null => {\r\n if (value === null || value === undefined) return null;\r\n try {\r\n return JSON.parse(value) as T;\r\n } catch {\r\n return null;\r\n }\r\n }\r\n};\r\n", "import { SqlComponent, SqlComponentVisitor } from '../models/SqlComponent';\r\nimport { CommonTable, SubQuerySource, TableSource } from '../models/Clause';\r\nimport { SelectClause, SelectItem } from '../models/Clause';\r\nimport { SimpleSelectQuery } from '../models/SimpleSelectQuery';\r\nimport { CTECollector } from './CTECollector';\r\nimport { SelectableColumnCollector, DuplicateDetectionMode } from './SelectableColumnCollector';\r\nimport { SelectValueCollector } from './SelectValueCollector';\r\nimport { ColumnReference } from '../models/ValueComponent';\r\nimport { BinarySelectQuery, SelectQuery } from '../models/SelectQuery';\r\nimport { SourceExpression } from '../models/Clause';\r\nimport { TableColumnResolver } from './TableColumnResolver';\r\n\r\nexport class TableSchema {\r\n public name: string;\r\n public columns: string[];\r\n\r\n constructor(name: string, columns: string[]) {\r\n this.name = name;\r\n this.columns = columns;\r\n }\r\n}\r\n\r\n/**\r\n * A visitor that collects schema information (table names and column names) from a SQL query structure.\r\n */\r\nexport class SchemaCollector implements SqlComponentVisitor<void> {\r\n private handlers: Map<symbol, (arg: any) => void>;\r\n\r\n private tableSchemas: TableSchema[] = [];\r\n private visitedNodes: Set<SqlComponent> = new Set();\r\n private commonTables: CommonTable[] = [];\r\n private running = false;\r\n\r\n constructor(private tableColumnResolver: TableColumnResolver | null = null) {\r\n this.handlers = new Map<symbol, (arg: any) => void>();\r\n\r\n // Setup handlers for query components\r\n this.handlers.set(SimpleSelectQuery.kind, (expr) => this.visitSimpleSelectQuery(expr as SimpleSelectQuery));\r\n this.handlers.set(BinarySelectQuery.kind, (expr) => this.visitBinarySelectQuery(expr as BinarySelectQuery));\r\n }\r\n\r\n /**\r\n * Collects schema information (table names and column names) from a SQL query structure.\r\n * This method ensures that the collected schema information is unique and sorted.\r\n * The resulting schemas and columns are sorted alphabetically to ensure deterministic ordering.\r\n *\r\n * @param arg The SQL query structure to analyze.\r\n */\r\n public collect(arg: SqlComponent): TableSchema[] {\r\n this.visit(arg);\r\n return this.tableSchemas;\r\n }\r\n\r\n /**\r\n * Main entry point for the visitor pattern.\r\n * Implements the shallow visit pattern to distinguish between root and recursive visits.\r\n *\r\n * This method ensures that schema information is collected uniquely and sorted.\r\n * The resulting schemas and columns are sorted alphabetically to ensure deterministic ordering.\r\n *\r\n * @param arg The SQL component to visit.\r\n */\r\n public visit(arg: SqlComponent): void {\r\n // If not a root visit, just visit the node and return\r\n if (this.running) {\r\n this.visitNode(arg);\r\n return;\r\n }\r\n\r\n // If this is a root visit, we need to reset the state\r\n this.reset();\r\n this.running = true;\r\n\r\n try {\r\n // Ensure the argument is a SelectQuery\r\n if (!(arg instanceof SimpleSelectQuery || arg instanceof BinarySelectQuery)) {\r\n throw new Error(`Unsupported SQL component type for schema collection. Received: ${arg.constructor.name}. Expected: SimpleSelectQuery or BinarySelectQuery.`);\r\n }\r\n\r\n // Collects Common Table Expressions (CTEs) using CTECollector\r\n const cteCollector = new CTECollector();\r\n this.commonTables = cteCollector.collect(arg);\r\n\r\n this.visitNode(arg);\r\n\r\n // Consolidate tableSchemas\r\n this.consolidateTableSchemas();\r\n } finally {\r\n // Regardless of success or failure, reset the root visit flag\r\n this.running = false;\r\n }\r\n }\r\n\r\n /**\r\n * Internal visit method used for all nodes.\r\n * This separates the visit flag management from the actual node visitation logic.\r\n */\r\n private visitNode(arg: SqlComponent): void {\r\n // Skip if we've already visited this node to prevent infinite recursion\r\n if (this.visitedNodes.has(arg)) {\r\n return;\r\n }\r\n\r\n // Mark as visited\r\n this.visitedNodes.add(arg);\r\n\r\n const handler = this.handlers.get(arg.getKind());\r\n if (handler) {\r\n handler(arg);\r\n return;\r\n }\r\n\r\n // If no handler found, that's ok - we only care about specific components\r\n }\r\n\r\n /**\r\n * Resets the state of the collector for a new root visit.\r\n */\r\n private reset(): void {\r\n this.tableSchemas = [];\r\n this.visitedNodes = new Set();\r\n this.commonTables = [];\r\n }\r\n\r\n /**\r\n * Consolidates table schemas by merging columns for tables with the same name.\r\n * This ensures that each table name appears only once in the final schema list,\r\n * with all its columns combined while removing duplicates.\r\n *\r\n * Note: The resulting schemas and columns are sorted alphabetically to ensure deterministic ordering.\r\n */\r\n private consolidateTableSchemas(): void {\r\n const consolidatedSchemas: Map<string, Set<string>> = new Map();\r\n\r\n for (const schema of this.tableSchemas) {\r\n if (!consolidatedSchemas.has(schema.name)) {\r\n consolidatedSchemas.set(schema.name, new Set(schema.columns));\r\n } else {\r\n const existingColumns = consolidatedSchemas.get(schema.name);\r\n schema.columns.forEach(column => existingColumns?.add(column));\r\n }\r\n }\r\n\r\n this.tableSchemas = Array.from(consolidatedSchemas.entries())\r\n .sort(([nameA], [nameB]) => nameA.localeCompare(nameB)) // Sort by table name\r\n .map(([name, columns]) => {\r\n return new TableSchema(name, Array.from(columns).sort()); // Sort columns alphabetically\r\n });\r\n }\r\n\r\n private handleTableSource(source: SourceExpression, queryColumns: { table: string, column: string }[], includeUnnamed: boolean): void {\r\n if (source.datasource instanceof TableSource) {\r\n const tableName = source.datasource.getSourceName();\r\n const cte = this.commonTables.filter((table) => table.getSourceAliasName() === tableName);\r\n if (cte.length > 0) {\r\n cte[0].query.accept(this);\r\n } else {\r\n const tableAlias = source.getAliasName() ?? tableName;\r\n this.processCollectTableSchema(tableName, tableAlias, queryColumns, includeUnnamed);\r\n }\r\n } else {\r\n throw new Error(\"Datasource is not an instance of TableSource\");\r\n }\r\n }\r\n\r\n private visitSimpleSelectQuery(query: SimpleSelectQuery): void {\r\n if (query.fromClause === null) {\r\n return;\r\n }\r\n\r\n // Collect columns used in the query\r\n const columnCollector = new SelectableColumnCollector(this.tableColumnResolver, true, DuplicateDetectionMode.FullName);\r\n const columns = columnCollector.collect(query);\r\n const queryColumns = columns.filter((column) => column.value instanceof ColumnReference)\r\n .map(column => column.value as ColumnReference)\r\n .map(columnRef => ({\r\n table: columnRef.getNamespace(),\r\n column: columnRef.column.name\r\n }));\r\n\r\n // Throw an error if there are columns without table names in queries with joins\r\n if (query.fromClause.joins !== null && query.fromClause.joins.length > 0) {\r\n const columnsWithoutTable = queryColumns.filter((columnRef) => columnRef.table === \"\").map((columnRef) => columnRef.column);\r\n if (columnsWithoutTable.length > 0) {\r\n throw new Error(`Column reference(s) without table name found in query: ${columnsWithoutTable.join(', ')}`);\r\n }\r\n }\r\n\r\n // Handle the main FROM clause table\r\n if (query.fromClause.source.datasource instanceof TableSource) {\r\n this.handleTableSource(query.fromClause.source, queryColumns, true);\r\n } else if (query.fromClause.source.datasource instanceof SubQuerySource) {\r\n query.fromClause.source.datasource.query.accept(this);\r\n }\r\n\r\n // Handle JOIN clause tables\r\n if (query.fromClause?.joins) {\r\n for (const join of query.fromClause.joins) {\r\n if (join.source.datasource instanceof TableSource) {\r\n this.handleTableSource(join.source, queryColumns, false);\r\n } else if (join.source.datasource instanceof SubQuerySource) {\r\n join.source.datasource.query.accept(this);\r\n }\r\n }\r\n }\r\n }\r\n\r\n private visitBinarySelectQuery(query: BinarySelectQuery): void {\r\n // Visit the left and right queries\r\n this.visitNode(query.left);\r\n this.visitNode(query.right);\r\n }\r\n\r\n private processCollectTableSchema(tableName: string, tableAlias: string, queryColumns: { table: string, column: string }[], includeUnnamed: boolean = false): void {\r\n // If a wildcard is present and no resolver is provided, throw an error\r\n if (this.tableColumnResolver === null) {\r\n const hasWildcard = queryColumns\r\n .filter((columnRef) => columnRef.table === tableAlias || (includeUnnamed && columnRef.table === \"\"))\r\n .filter((columnRef) => columnRef.column === \"*\")\r\n .length > 0;\r\n if (hasWildcard) {\r\n const errorMessage = tableName\r\n ? `Wildcard (*) is used. A TableColumnResolver is required to resolve wildcards. Target table: ${tableName}`\r\n : \"Wildcard (*) is used. A TableColumnResolver is required to resolve wildcards.\";\r\n throw new Error(errorMessage);\r\n }\r\n }\r\n\r\n let tableColumns = queryColumns\r\n .filter((columnRef) => columnRef.column !== \"*\")\r\n .filter((columnRef) => columnRef.table === tableAlias || (includeUnnamed && columnRef.table === \"\"))\r\n .map((columnRef) => columnRef.column);\r\n\r\n const tableSchema = new TableSchema(tableName, tableColumns);\r\n this.tableSchemas.push(tableSchema);\r\n }\r\n}\r\n", "import { SelectQuery, SimpleSelectQuery } from \"../models/SelectQuery\";\r\nimport { SelectableColumnCollector } from \"./SelectableColumnCollector\";\r\nimport { BinaryExpression, FunctionCall, ParameterExpression, ParenExpression, ValueComponent, ValueList } from \"../models/ValueComponent\";\r\nimport { UpstreamSelectQueryFinder } from \"./UpstreamSelectQueryFinder\";\r\nimport { SelectQueryParser } from \"../parsers/SelectQueryParser\";\r\n\r\n/**\r\n * Options for SqlParamInjector\r\n */\r\nexport interface SqlParamInjectorOptions {\r\n /** Whether to ignore case and underscore differences when matching column names */\r\n ignoreCaseAndUnderscore?: boolean;\r\n /** Whether to allow injection when all parameters are undefined (defaults to false for safety) */\r\n allowAllUndefined?: boolean;\r\n}\r\n\r\n/**\r\n * SqlParamInjector injects state parameters into a SelectQuery model,\r\n * creating WHERE conditions and setting parameter values.\r\n */\r\nexport class SqlParamInjector {\r\n private tableColumnResolver?: (tableName: string) => string[];\r\n private options: SqlParamInjectorOptions;\r\n\r\n constructor(optionsOrResolver?: SqlParamInjectorOptions | ((tableName: string) => string[]), options?: SqlParamInjectorOptions) {\r\n // Type-check to decide which argument was provided\r\n if (typeof optionsOrResolver === 'function') {\r\n this.tableColumnResolver = optionsOrResolver;\r\n this.options = options || {};\r\n } else {\r\n this.tableColumnResolver = undefined;\r\n this.options = optionsOrResolver || {};\r\n }\r\n }\r\n\r\n /**\r\n * Injects parameters as WHERE conditions into the given query model.\r\n * @param query The SelectQuery to modify\r\n * @param state A record of parameter names and values\r\n * @returns The modified SelectQuery\r\n * @throws Error when all parameters are undefined and allowAllUndefined is not set to true\r\n */\r\n public inject(\r\n query: SimpleSelectQuery | string,\r\n state: Record<string, number | string | boolean | Date | null | undefined | Condition>\r\n ): SelectQuery {\r\n // Convert string query to SimpleSelectQuery using SelectQueryParser if needed\r\n if (typeof query === 'string') {\r\n query = SelectQueryParser.parse(query) as SimpleSelectQuery;\r\n }\r\n\r\n // Pass tableColumnResolver to finder and collector\r\n const finder = new UpstreamSelectQueryFinder(this.tableColumnResolver, this.options);\r\n const collector = new SelectableColumnCollector(this.tableColumnResolver);\r\n // Normalization is handled locally below.\r\n const normalize = (s: string) =>\r\n this.options.ignoreCaseAndUnderscore ? s.toLowerCase().replace(/_/g, '') : s;\r\n\r\n const allowedOps = ['min', 'max', 'like', 'ilike', 'in', 'any', '=', '<', '>', '!=', '<>', '<=', '>=', 'or', 'and', 'column'];\r\n\r\n // Check if all parameters are undefined\r\n const stateValues = Object.values(state);\r\n const hasParameters = stateValues.length > 0;\r\n const allUndefined = hasParameters && stateValues.every(value => value === undefined);\r\n \r\n if (allUndefined && !this.options.allowAllUndefined) {\r\n throw new Error('All parameters are undefined. This would result in fetching all records. Use allowAllUndefined: true option to explicitly allow this behavior.');\r\n }\r\n\r\n for (const [name, stateValue] of Object.entries(state)) {\r\n // skip undefined values\r\n if (stateValue === undefined) continue;\r\n\r\n // Handle OR conditions specially - they don't need the main column to exist\r\n if (stateValue !== null && typeof stateValue === 'object' && !Array.isArray(stateValue) && 'or' in stateValue) {\r\n const orConditions = stateValue.or as SingleCondition[];\r\n if (orConditions && orConditions.length > 0) {\r\n // For OR conditions, we need to find a query that contains any of the referenced columns\r\n const referencedColumns = orConditions\r\n .map(cond => cond.column || name)\r\n .filter((col, index, arr) => arr.indexOf(col) === index); // unique columns\r\n\r\n let targetQuery: SimpleSelectQuery | null = null;\r\n for (const colName of referencedColumns) {\r\n const queries = finder.find(query, colName);\r\n if (queries.length > 0) {\r\n targetQuery = queries[0];\r\n break;\r\n }\r\n }\r\n\r\n if (!targetQuery) {\r\n throw new Error(`None of the OR condition columns [${referencedColumns.join(', ')}] found in query`);\r\n }\r\n\r\n const columns = collector.collect(targetQuery);\r\n injectOrConditions(targetQuery, name, orConditions, normalize, columns, collector);\r\n continue;\r\n }\r\n }\r\n\r\n // Handle AND conditions specially - they don't need the main column to exist\r\n if (stateValue !== null && typeof stateValue === 'object' && !Array.isArray(stateValue) && 'and' in stateValue) {\r\n const andConditions = stateValue.and as SingleCondition[];\r\n if (andConditions && andConditions.length > 0) {\r\n // For AND conditions, we need to find a query that contains any of the referenced columns\r\n const referencedColumns = andConditions\r\n .map(cond => cond.column || name)\r\n .filter((col, index, arr) => arr.indexOf(col) === index); // unique columns\r\n\r\n let targetQuery: SimpleSelectQuery | null = null;\r\n for (const colName of referencedColumns) {\r\n const queries = finder.find(query, colName);\r\n if (queries.length > 0) {\r\n targetQuery = queries[0];\r\n break;\r\n }\r\n }\r\n\r\n if (!targetQuery) {\r\n throw new Error(`None of the AND condition columns [${referencedColumns.join(', ')}] found in query`);\r\n }\r\n\r\n const columns = collector.collect(targetQuery);\r\n injectAndConditions(targetQuery, name, andConditions, normalize, columns, collector);\r\n continue;\r\n }\r\n }\r\n\r\n // Handle explicit column mapping without OR\r\n if (stateValue !== null && typeof stateValue === 'object' && !Array.isArray(stateValue) && 'column' in stateValue && !('or' in stateValue)) {\r\n const explicitColumnName = stateValue.column;\r\n if (explicitColumnName) {\r\n const queries = finder.find(query, explicitColumnName);\r\n if (queries.length === 0) {\r\n throw new Error(`Explicit column '${explicitColumnName}' not found in query`);\r\n }\r\n\r\n for (const q of queries) {\r\n const columns = collector.collect(q);\r\n const entry = columns.find(item => normalize(item.name) === normalize(explicitColumnName));\r\n if (!entry) {\r\n throw new Error(`Explicit column '${explicitColumnName}' not found in query`);\r\n }\r\n\r\n // if object, validate its keys\r\n if (stateValue !== null && typeof stateValue === 'object' && !Array.isArray(stateValue) && Object.getPrototypeOf(stateValue) === Object.prototype) {\r\n validateOperators(stateValue, allowedOps, name);\r\n }\r\n\r\n injectComplexConditions(q, entry.value, name, stateValue);\r\n }\r\n continue;\r\n }\r\n }\r\n\r\n const queries = finder.find(query, name);\r\n if (queries.length === 0) {\r\n throw new Error(`Column '${name}' not found in query`);\r\n }\r\n\r\n for (const q of queries) {\r\n const columns = collector.collect(q);\r\n const entry = columns.find(item => normalize(item.name) === normalize(name));\r\n if (!entry) {\r\n throw new Error(`Column '${name}' not found in query`);\r\n }\r\n const columnRef = entry.value; // if object, validate its keys\r\n if (stateValue !== null && typeof stateValue === 'object' && !Array.isArray(stateValue) && Object.getPrototypeOf(stateValue) === Object.prototype) {\r\n validateOperators(stateValue, allowedOps, name);\r\n }\r\n\r\n // Handle explicit column mapping\r\n let targetColumn = columnRef;\r\n let targetColumnName = name;\r\n if (stateValue !== null && typeof stateValue === 'object' && !Array.isArray(stateValue) && 'column' in stateValue) {\r\n const explicitColumnName = stateValue.column;\r\n if (explicitColumnName) {\r\n const explicitEntry = columns.find(item => normalize(item.name) === normalize(explicitColumnName));\r\n if (explicitEntry) {\r\n targetColumn = explicitEntry.value;\r\n targetColumnName = explicitColumnName;\r\n }\r\n }\r\n }\r\n\r\n if (\r\n stateValue === null ||\r\n typeof stateValue !== 'object' ||\r\n Array.isArray(stateValue) ||\r\n stateValue instanceof Date\r\n ) {\r\n injectSimpleCondition(q, targetColumn, targetColumnName, stateValue);\r\n } else {\r\n injectComplexConditions(q, targetColumn, targetColumnName, stateValue);\r\n }\r\n }\r\n } function injectAndConditions(\r\n q: SimpleSelectQuery,\r\n baseName: string,\r\n andConditions: SingleCondition[],\r\n normalize: (s: string) => string,\r\n availableColumns: { name: string; value: ValueComponent }[],\r\n collector: SelectableColumnCollector\r\n ): void {\r\n // For AND conditions, we process each condition and add them all with AND logic\r\n for (let i = 0; i < andConditions.length; i++) {\r\n const andCondition = andConditions[i];\r\n const columnName = andCondition.column || baseName;\r\n\r\n // Find the target column\r\n const entry = availableColumns.find(item => normalize(item.name) === normalize(columnName));\r\n if (!entry) {\r\n throw new Error(`Column '${columnName}' not found in query for AND condition`);\r\n }\r\n const columnRef = entry.value;\r\n\r\n // Process each operator in the AND condition\r\n if ('=' in andCondition && andCondition['='] !== undefined) {\r\n const paramName = `${baseName}_and_${i}_eq`;\r\n const paramExpr = new ParameterExpression(paramName, andCondition['=']);\r\n q.appendWhere(new BinaryExpression(columnRef, \"=\", paramExpr));\r\n }\r\n if ('min' in andCondition && andCondition.min !== undefined) {\r\n const paramName = `${baseName}_and_${i}_min`;\r\n const paramExpr = new ParameterExpression(paramName, andCondition.min);\r\n q.appendWhere(new BinaryExpression(columnRef, \">=\", paramExpr));\r\n }\r\n if ('max' in andCondition && andCondition.max !== undefined) {\r\n const paramName = `${baseName}_and_${i}_max`;\r\n const paramExpr = new ParameterExpression(paramName, andCondition.max);\r\n q.appendWhere(new BinaryExpression(columnRef, \"<=\", paramExpr));\r\n } if ('like' in andCondition && andCondition.like !== undefined) {\r\n const paramName = `${baseName}_and_${i}_like`;\r\n const paramExpr = new ParameterExpression(paramName, andCondition.like);\r\n q.appendWhere(new BinaryExpression(columnRef, \"like\", paramExpr));\r\n }\r\n if ('ilike' in andCondition && andCondition.ilike !== undefined) {\r\n const paramName = `${baseName}_and_${i}_ilike`;\r\n const paramExpr = new ParameterExpression(paramName, andCondition.ilike);\r\n q.appendWhere(new BinaryExpression(columnRef, \"ilike\", paramExpr));\r\n }\r\n if ('in' in andCondition && andCondition.in !== undefined) {\r\n const arr = andCondition.in as (number | string)[];\r\n const prms: ParameterExpression[] = arr.map((v, j) =>\r\n new ParameterExpression(`${baseName}_and_${i}_in_${j}`, v)\r\n );\r\n q.appendWhere(new BinaryExpression(columnRef, \"in\", new ParenExpression(new ValueList(prms))));\r\n }\r\n if ('any' in andCondition && andCondition.any !== undefined) {\r\n const paramName = `${baseName}_and_${i}_any`;\r\n const paramExpr = new ParameterExpression(paramName, andCondition.any);\r\n q.appendWhere(new BinaryExpression(columnRef, \"=\", new FunctionCall(null, \"any\", paramExpr, null)));\r\n }\r\n if ('<' in andCondition && andCondition['<'] !== undefined) {\r\n const paramName = `${baseName}_and_${i}_lt`;\r\n const paramExpr = new ParameterExpression(paramName, andCondition['<']);\r\n q.appendWhere(new BinaryExpression(columnRef, \"<\", paramExpr));\r\n }\r\n if ('>' in andCondition && andCondition['>'] !== undefined) {\r\n const paramName = `${baseName}_and_${i}_gt`;\r\n const paramExpr = new ParameterExpression(paramName, andCondition['>']);\r\n q.appendWhere(new BinaryExpression(columnRef, \">\", paramExpr));\r\n }\r\n if ('!=' in andCondition && andCondition['!='] !== undefined) {\r\n const paramName = `${baseName}_and_${i}_neq`;\r\n const paramExpr = new ParameterExpression(paramName, andCondition['!=']);\r\n q.appendWhere(new BinaryExpression(columnRef, \"!=\", paramExpr));\r\n }\r\n if ('<>' in andCondition && andCondition['<>'] !== undefined) {\r\n const paramName = `${baseName}_and_${i}_ne`;\r\n const paramExpr = new ParameterExpression(paramName, andCondition['<>']);\r\n q.appendWhere(new BinaryExpression(columnRef, \"<>\", paramExpr));\r\n }\r\n if ('<=' in andCondition && andCondition['<='] !== undefined) {\r\n const paramName = `${baseName}_and_${i}_le`;\r\n const paramExpr = new ParameterExpression(paramName, andCondition['<=']);\r\n q.appendWhere(new BinaryExpression(columnRef, \"<=\", paramExpr));\r\n }\r\n if ('>=' in andCondition && andCondition['>='] !== undefined) {\r\n const paramName = `${baseName}_and_${i}_ge`;\r\n const paramExpr = new ParameterExpression(paramName, andCondition['>=']);\r\n q.appendWhere(new BinaryExpression(columnRef, \">=\", paramExpr));\r\n }\r\n }\r\n }\r\n\r\n function injectOrConditions(\r\n q: SimpleSelectQuery,\r\n baseName: string,\r\n orConditions: SingleCondition[],\r\n normalize: (s: string) => string,\r\n availableColumns: { name: string; value: ValueComponent }[],\r\n collector: SelectableColumnCollector\r\n ): void {\r\n const orExpressions: ValueComponent[] = [];\r\n\r\n for (let i = 0; i < orConditions.length; i++) {\r\n const orCondition = orConditions[i];\r\n const columnName = orCondition.column || baseName;\r\n\r\n // Find the target column\r\n const entry = availableColumns.find(item => normalize(item.name) === normalize(columnName));\r\n if (!entry) {\r\n throw new Error(`Column '${columnName}' not found in query for OR condition`);\r\n }\r\n const columnRef = entry.value;\r\n\r\n // Create conditions for this OR branch\r\n const branchConditions: ValueComponent[] = [];\r\n\r\n // Process each operator in the OR condition\r\n if ('=' in orCondition && orCondition['='] !== undefined) {\r\n const paramName = `${baseName}_or_${i}_eq`;\r\n const paramExpr = new ParameterExpression(paramName, orCondition['=']);\r\n branchConditions.push(new BinaryExpression(columnRef, \"=\", paramExpr));\r\n }\r\n if ('min' in orCondition && orCondition.min !== undefined) {\r\n const paramName = `${baseName}_or_${i}_min`;\r\n const paramExpr = new ParameterExpression(paramName, orCondition.min);\r\n branchConditions.push(new BinaryExpression(columnRef, \">=\", paramExpr));\r\n }\r\n if ('max' in orCondition && orCondition.max !== undefined) {\r\n const paramName = `${baseName}_or_${i}_max`;\r\n const paramExpr = new ParameterExpression(paramName, orCondition.max);\r\n branchConditions.push(new BinaryExpression(columnRef, \"<=\", paramExpr));\r\n } if ('like' in orCondition && orCondition.like !== undefined) {\r\n const paramName = `${baseName}_or_${i}_like`;\r\n const paramExpr = new ParameterExpression(paramName, orCondition.like);\r\n branchConditions.push(new BinaryExpression(columnRef, \"like\", paramExpr));\r\n }\r\n if ('ilike' in orCondition && orCondition.ilike !== undefined) {\r\n const paramName = `${baseName}_or_${i}_ilike`;\r\n const paramExpr = new ParameterExpression(paramName, orCondition.ilike);\r\n branchConditions.push(new BinaryExpression(columnRef, \"ilike\", paramExpr));\r\n }\r\n if ('in' in orCondition && orCondition.in !== undefined) {\r\n const arr = orCondition.in as (number | string)[];\r\n const prms: ParameterExpression[] = arr.map((v, j) =>\r\n new ParameterExpression(`${baseName}_or_${i}_in_${j}`, v)\r\n );\r\n branchConditions.push(new BinaryExpression(columnRef, \"in\", new ParenExpression(new ValueList(prms))));\r\n }\r\n if ('any' in orCondition && orCondition.any !== undefined) {\r\n const paramName = `${baseName}_or_${i}_any`;\r\n const paramExpr = new ParameterExpression(paramName, orCondition.any);\r\n branchConditions.push(new BinaryExpression(columnRef, \"=\", new FunctionCall(null, \"any\", paramExpr, null)));\r\n }\r\n if ('<' in orCondition && orCondition['<'] !== undefined) {\r\n const paramName = `${baseName}_or_${i}_lt`;\r\n const paramExpr = new ParameterExpression(paramName, orCondition['<']);\r\n branchConditions.push(new BinaryExpression(columnRef, \"<\", paramExpr));\r\n }\r\n if ('>' in orCondition && orCondition['>'] !== undefined) {\r\n const paramName = `${baseName}_or_${i}_gt`;\r\n const paramExpr = new ParameterExpression(paramName, orCondition['>']);\r\n branchConditions.push(new BinaryExpression(columnRef, \">\", paramExpr));\r\n }\r\n if ('!=' in orCondition && orCondition['!='] !== undefined) {\r\n const paramName = `${baseName}_or_${i}_neq`;\r\n const paramExpr = new ParameterExpression(paramName, orCondition['!=']);\r\n branchConditions.push(new BinaryExpression(columnRef, \"!=\", paramExpr));\r\n }\r\n if ('<>' in orCondition && orCondition['<>'] !== undefined) {\r\n const paramName = `${baseName}_or_${i}_ne`;\r\n const paramExpr = new ParameterExpression(paramName, orCondition['<>']);\r\n branchConditions.push(new BinaryExpression(columnRef, \"<>\", paramExpr));\r\n }\r\n if ('<=' in orCondition && orCondition['<='] !== undefined) {\r\n const paramName = `${baseName}_or_${i}_le`;\r\n const paramExpr = new ParameterExpression(paramName, orCondition['<=']);\r\n branchConditions.push(new BinaryExpression(columnRef, \"<=\", paramExpr));\r\n }\r\n if ('>=' in orCondition && orCondition['>='] !== undefined) {\r\n const paramName = `${baseName}_or_${i}_ge`;\r\n const paramExpr = new ParameterExpression(paramName, orCondition['>=']);\r\n branchConditions.push(new BinaryExpression(columnRef, \">=\", paramExpr));\r\n }\r\n\r\n // Combine branch conditions with AND if there are multiple\r\n if (branchConditions.length > 0) {\r\n let branchExpr = branchConditions[0];\r\n for (let j = 1; j < branchConditions.length; j++) {\r\n branchExpr = new BinaryExpression(branchExpr, \"and\", branchConditions[j]);\r\n }\r\n // Wrap in parentheses if multiple conditions within the OR branch\r\n if (branchConditions.length > 1) {\r\n orExpressions.push(new ParenExpression(branchExpr));\r\n } else {\r\n orExpressions.push(branchExpr);\r\n }\r\n }\r\n }\r\n\r\n // Combine OR expressions\r\n if (orExpressions.length > 0) {\r\n let finalOrExpr = orExpressions[0];\r\n for (let i = 1; i < orExpressions.length; i++) {\r\n finalOrExpr = new BinaryExpression(finalOrExpr, \"or\", orExpressions[i]);\r\n }\r\n\r\n // Wrap in parentheses and append to WHERE clause\r\n q.appendWhere(new ParenExpression(finalOrExpr));\r\n }\r\n }\r\n\r\n function validateOperators(stateValue: object, allowedOps: string[], name: string): void {\r\n Object.keys(stateValue).forEach(op => {\r\n if (!allowedOps.includes(op)) {\r\n throw new Error(`Unsupported operator '${op}' for state key '${name}'`);\r\n }\r\n });\r\n }\r\n\r\n function injectSimpleCondition(q: SimpleSelectQuery, columnRef: ValueComponent, name: string, stateValue: any): void {\r\n const paramExpr = new ParameterExpression(name, stateValue);\r\n q.appendWhere(new BinaryExpression(columnRef, \"=\", paramExpr));\r\n } function injectComplexConditions(q: SimpleSelectQuery, columnRef: ValueComponent, name: string, stateValue: Condition): void {\r\n const conditions: ValueComponent[] = [];\r\n\r\n if ('=' in stateValue) {\r\n const paramEq = new ParameterExpression(name, stateValue['=']);\r\n conditions.push(new BinaryExpression(columnRef, \"=\", paramEq));\r\n }\r\n if ('min' in stateValue) {\r\n const paramMin = new ParameterExpression(name + \"_min\", stateValue.min);\r\n conditions.push(new BinaryExpression(columnRef, \">=\", paramMin));\r\n }\r\n if ('max' in stateValue) {\r\n const paramMax = new ParameterExpression(name + \"_max\", stateValue.max);\r\n conditions.push(new BinaryExpression(columnRef, \"<=\", paramMax));\r\n } if ('like' in stateValue) {\r\n const paramLike = new ParameterExpression(name + \"_like\", stateValue.like);\r\n conditions.push(new BinaryExpression(columnRef, \"like\", paramLike));\r\n }\r\n if ('ilike' in stateValue) {\r\n const paramIlike = new ParameterExpression(name + \"_ilike\", stateValue.ilike);\r\n conditions.push(new BinaryExpression(columnRef, \"ilike\", paramIlike));\r\n }\r\n if ('in' in stateValue) {\r\n const arr = stateValue['in'] as (number | string)[];\r\n const prms: ParameterExpression[] = arr.map((v, i) =>\r\n new ParameterExpression(`${name}_in_${i}`, v)\r\n );\r\n conditions.push(new BinaryExpression(columnRef, \"in\", new ParenExpression(new ValueList(prms))));\r\n }\r\n if ('any' in stateValue) {\r\n const paramAny = new ParameterExpression(name + \"_any\", stateValue.any);\r\n conditions.push(new BinaryExpression(columnRef, \"=\", new FunctionCall(null, \"any\", paramAny, null)));\r\n }\r\n if ('<' in stateValue) {\r\n const paramLT = new ParameterExpression(name + \"_lt\", stateValue['<']);\r\n conditions.push(new BinaryExpression(columnRef, \"<\", paramLT));\r\n }\r\n if ('>' in stateValue) {\r\n const paramGT = new ParameterExpression(name + \"_gt\", stateValue['>']);\r\n conditions.push(new BinaryExpression(columnRef, \">\", paramGT));\r\n }\r\n if ('!=' in stateValue) {\r\n const paramNEQ = new ParameterExpression(name + \"_neq\", stateValue['!=']);\r\n conditions.push(new BinaryExpression(columnRef, \"!=\", paramNEQ));\r\n }\r\n if ('<>' in stateValue) {\r\n const paramNE = new ParameterExpression(name + \"_ne\", stateValue['<>']);\r\n conditions.push(new BinaryExpression(columnRef, \"<>\", paramNE));\r\n }\r\n if ('<=' in stateValue) {\r\n const paramLE = new ParameterExpression(name + \"_le\", stateValue['<=']);\r\n conditions.push(new BinaryExpression(columnRef, \"<=\", paramLE));\r\n }\r\n if ('>=' in stateValue) {\r\n const paramGE = new ParameterExpression(name + \"_ge\", stateValue['>=']);\r\n conditions.push(new BinaryExpression(columnRef, \">=\", paramGE));\r\n }\r\n\r\n // Combine conditions with AND and wrap in parentheses if multiple conditions for clarity\r\n if (conditions.length === 1) {\r\n // Single condition - no parentheses needed\r\n q.appendWhere(conditions[0]);\r\n } else if (conditions.length > 1) {\r\n // Multiple conditions - combine with AND and wrap in parentheses for clarity\r\n let combinedExpr = conditions[0];\r\n for (let i = 1; i < conditions.length; i++) {\r\n combinedExpr = new BinaryExpression(combinedExpr, \"and\", conditions[i]);\r\n }\r\n q.appendWhere(new ParenExpression(combinedExpr));\r\n }\r\n }\r\n\r\n return query;\r\n }\r\n}\r\n\r\n// Define allowed condition keywords for state values\r\ntype BaseCondition = {\r\n '='?: number | string | boolean | Date;\r\n min?: number | string | Date;\r\n max?: number | string | Date;\r\n like?: string;\r\n ilike?: string;\r\n in?: (number | string | Date)[];\r\n any?: (number | string | Date)[];\r\n '<'?: number | string | Date;\r\n '>'?: number | string | Date;\r\n '!='?: number | string | boolean | Date;\r\n '<>'?: number | string | boolean | Date;\r\n '<='?: number | string | Date;\r\n '>='?: number | string | Date;\r\n};\r\n\r\n// Single condition with optional column mapping\r\ntype SingleCondition = BaseCondition & {\r\n column?: string;\r\n};\r\n\r\n// Logical grouping conditions\r\ntype LogicalCondition = {\r\n column?: string;\r\n and?: SingleCondition[];\r\n or?: SingleCondition[];\r\n};\r\n\r\n// Main condition type supporting all patterns\r\ntype Condition = BaseCondition | SingleCondition | LogicalCondition;", "import { SelectQuery, SimpleSelectQuery } from \"../models/SelectQuery\";\r\nimport { SelectableColumnCollector } from \"./SelectableColumnCollector\";\r\nimport { OrderByClause, OrderByItem, SortDirection, NullsSortDirection } from \"../models/Clause\";\r\nimport { ValueComponent } from \"../models/ValueComponent\";\r\nimport { SelectQueryParser } from \"../parsers/SelectQueryParser\";\r\n\r\n/**\r\n * SqlSortInjector injects sort conditions into a SelectQuery model,\r\n * creating ORDER BY clauses based on provided sort conditions.\r\n */\r\nexport class SqlSortInjector {\r\n private tableColumnResolver?: (tableName: string) => string[];\r\n\r\n constructor(tableColumnResolver?: (tableName: string) => string[]) {\r\n this.tableColumnResolver = tableColumnResolver;\r\n }\r\n\r\n /**\r\n * Removes ORDER BY clause from the given query.\r\n * @param query The SelectQuery to modify\r\n * @returns The modified SimpleSelectQuery with ORDER BY clause removed\r\n */\r\n public static removeOrderBy(query: SimpleSelectQuery | string): SimpleSelectQuery {\r\n // Convert string query to SimpleSelectQuery using SelectQueryParser if needed\r\n if (typeof query === 'string') {\r\n query = SelectQueryParser.parse(query) as SimpleSelectQuery;\r\n }\r\n\r\n // Check if query is SimpleSelectQuery\r\n if (!(query instanceof SimpleSelectQuery)) {\r\n throw new Error('Complex queries are not supported for ORDER BY removal');\r\n }\r\n\r\n // Create a new query without ORDER BY clause\r\n return new SimpleSelectQuery({\r\n withClause: query.withClause,\r\n selectClause: query.selectClause,\r\n fromClause: query.fromClause,\r\n whereClause: query.whereClause,\r\n groupByClause: query.groupByClause,\r\n havingClause: query.havingClause,\r\n orderByClause: null, // Remove ORDER BY\r\n windowClause: query.windowClause,\r\n limitClause: query.limitClause,\r\n offsetClause: query.offsetClause,\r\n fetchClause: query.fetchClause,\r\n forClause: query.forClause,\r\n });\r\n }\r\n\r\n /**\r\n * Injects sort conditions as ORDER BY clauses into the given query model.\r\n * Appends to existing ORDER BY clause if present.\r\n * @param query The SelectQuery to modify\r\n * @param sortConditions A record of column names and sort conditions\r\n * @returns The modified SimpleSelectQuery\r\n */\r\n public inject(\r\n query: SimpleSelectQuery | string,\r\n sortConditions: SortConditions\r\n ): SimpleSelectQuery {\r\n // Convert string query to SimpleSelectQuery using SelectQueryParser if needed\r\n if (typeof query === 'string') {\r\n query = SelectQueryParser.parse(query) as SimpleSelectQuery;\r\n }\r\n\r\n // Check if query is SimpleSelectQuery\r\n if (!(query instanceof SimpleSelectQuery)) {\r\n throw new Error('Complex queries are not supported for sorting');\r\n }\r\n\r\n // Collect available columns from the current query only (no upstream search)\r\n const collector = new SelectableColumnCollector(this.tableColumnResolver);\r\n const availableColumns = collector.collect(query);\r\n\r\n // Validate that all specified columns exist\r\n for (const columnName of Object.keys(sortConditions)) {\r\n const columnEntry = availableColumns.find(item => item.name === columnName);\r\n if (!columnEntry) {\r\n throw new Error(`Column or alias '${columnName}' not found in current query`);\r\n }\r\n }\r\n\r\n // Build new ORDER BY items\r\n const newOrderByItems: OrderByItem[] = [];\r\n\r\n for (const [columnName, condition] of Object.entries(sortConditions)) {\r\n const columnEntry = availableColumns.find(item => item.name === columnName);\r\n if (!columnEntry) continue; // Should not happen due to validation above\r\n\r\n const columnRef = columnEntry.value;\r\n\r\n // Validate condition\r\n this.validateSortCondition(columnName, condition);\r\n\r\n // Determine sort direction\r\n let sortDirection: SortDirection;\r\n if (condition.desc) {\r\n sortDirection = SortDirection.Descending;\r\n } else {\r\n sortDirection = SortDirection.Ascending; // Default to ASC\r\n }\r\n\r\n // Determine nulls position\r\n let nullsPosition: NullsSortDirection | null = null;\r\n if (condition.nullsFirst) {\r\n nullsPosition = NullsSortDirection.First;\r\n } else if (condition.nullsLast) {\r\n nullsPosition = NullsSortDirection.Last;\r\n }\r\n\r\n // Create OrderByItem\r\n const orderByItem = new OrderByItem(columnRef, sortDirection, nullsPosition);\r\n newOrderByItems.push(orderByItem);\r\n }\r\n\r\n // Combine with existing ORDER BY clause if present\r\n let finalOrderByItems: (OrderByItem | ValueComponent)[] = [];\r\n\r\n if (query.orderByClause) {\r\n // Append to existing ORDER BY\r\n finalOrderByItems = [...query.orderByClause.order, ...newOrderByItems];\r\n } else {\r\n // Create new ORDER BY\r\n finalOrderByItems = newOrderByItems;\r\n }\r\n\r\n // Create new OrderByClause\r\n const newOrderByClause = finalOrderByItems.length > 0\r\n ? new OrderByClause(finalOrderByItems)\r\n : null;\r\n\r\n // Create new query with updated ORDER BY clause\r\n return new SimpleSelectQuery({\r\n withClause: query.withClause,\r\n selectClause: query.selectClause,\r\n fromClause: query.fromClause,\r\n whereClause: query.whereClause,\r\n groupByClause: query.groupByClause,\r\n havingClause: query.havingClause,\r\n orderByClause: newOrderByClause,\r\n windowClause: query.windowClause,\r\n limitClause: query.limitClause,\r\n offsetClause: query.offsetClause,\r\n fetchClause: query.fetchClause,\r\n forClause: query.forClause,\r\n });\r\n }\r\n\r\n /**\r\n * Validates sort condition for a column\r\n */\r\n private validateSortCondition(columnName: string, condition: SortCondition): void {\r\n // Check for conflicting sort directions\r\n if (condition.asc && condition.desc) {\r\n throw new Error(`Conflicting sort directions for column '${columnName}': both asc and desc specified`);\r\n }\r\n\r\n // Check for conflicting nulls positions\r\n if (condition.nullsFirst && condition.nullsLast) {\r\n throw new Error(`Conflicting nulls positions for column '${columnName}': both nullsFirst and nullsLast specified`);\r\n }\r\n\r\n // Check if at least one option is specified\r\n if (!condition.asc && !condition.desc && !condition.nullsFirst && !condition.nullsLast) {\r\n throw new Error(`Empty sort condition for column '${columnName}': at least one sort option must be specified`);\r\n }\r\n }\r\n}\r\n\r\n// Type definitions\r\nexport type SortCondition = {\r\n asc?: boolean;\r\n desc?: boolean;\r\n nullsFirst?: boolean;\r\n nullsLast?: boolean;\r\n};\r\n\r\nexport type SortConditions = {\r\n [columnName: string]: SortCondition;\r\n};\r\n", "import { SelectQuery, SimpleSelectQuery } from \"../models/SelectQuery\";\r\nimport { LimitClause, OffsetClause } from \"../models/Clause\";\r\nimport { LiteralValue, ParameterExpression } from \"../models/ValueComponent\";\r\nimport { SelectQueryParser } from \"../parsers/SelectQueryParser\";\r\n\r\n/**\r\n * Options for pagination injection\r\n */\r\nexport interface PaginationOptions {\r\n /** Page number (1-based) */\r\n page: number;\r\n /** Number of items per page */\r\n pageSize: number;\r\n}\r\n\r\n/**\r\n * SqlPaginationInjector injects pagination (LIMIT/OFFSET) into a SelectQuery model,\r\n * creating LIMIT and OFFSET clauses based on provided pagination options.\r\n */\r\nexport class SqlPaginationInjector {\r\n\r\n /**\r\n * Injects pagination as LIMIT/OFFSET clauses into the given query model.\r\n * @param query The SelectQuery to modify\r\n * @param pagination Pagination options containing page number and page size\r\n * @returns The modified SimpleSelectQuery with pagination applied\r\n */\r\n public inject(\r\n query: SimpleSelectQuery | string,\r\n pagination: PaginationOptions\r\n ): SimpleSelectQuery {\r\n // Validate pagination options\r\n this.validatePaginationOptions(pagination);\r\n\r\n // Convert string query to SimpleSelectQuery using SelectQueryParser if needed\r\n if (typeof query === 'string') {\r\n query = SelectQueryParser.parse(query) as SimpleSelectQuery;\r\n }\r\n\r\n // Check if query is SimpleSelectQuery\r\n if (!(query instanceof SimpleSelectQuery)) {\r\n throw new Error('Complex queries are not supported for pagination');\r\n }\r\n\r\n // Check if query already has LIMIT or OFFSET clauses\r\n if (query.limitClause || query.offsetClause) {\r\n throw new Error('Query already contains LIMIT or OFFSET clause. Use removePagination() first if you want to override existing pagination.');\r\n }\r\n\r\n // Calculate offset\r\n const offset = (pagination.page - 1) * pagination.pageSize;\r\n\r\n // Create LIMIT clause\r\n const limitClause = new LimitClause(\r\n new ParameterExpression('paging_limit', pagination.pageSize)\r\n );\r\n\r\n // Create OFFSET clause (always include for consistent query caching)\r\n const offsetClause = new OffsetClause(\r\n new ParameterExpression('paging_offset', offset)\r\n );\r\n\r\n // Create a new query with pagination clauses\r\n return new SimpleSelectQuery({\r\n withClause: query.withClause,\r\n selectClause: query.selectClause,\r\n fromClause: query.fromClause,\r\n whereClause: query.whereClause,\r\n groupByClause: query.groupByClause,\r\n havingClause: query.havingClause,\r\n orderByClause: query.orderByClause,\r\n windowClause: query.windowClause,\r\n limitClause: limitClause,\r\n offsetClause: offsetClause,\r\n fetchClause: query.fetchClause,\r\n forClause: query.forClause,\r\n });\r\n }\r\n\r\n /**\r\n * Removes LIMIT and OFFSET clauses from the given query.\r\n * @param query The SelectQuery to modify\r\n * @returns The modified SimpleSelectQuery with pagination removed\r\n */\r\n public static removePagination(query: SimpleSelectQuery | string): SimpleSelectQuery {\r\n // Convert string query to SimpleSelectQuery using SelectQueryParser if needed\r\n if (typeof query === 'string') {\r\n query = SelectQueryParser.parse(query) as SimpleSelectQuery;\r\n }\r\n\r\n // Check if query is SimpleSelectQuery\r\n if (!(query instanceof SimpleSelectQuery)) {\r\n throw new Error('Complex queries are not supported for pagination removal');\r\n }\r\n\r\n // Create a new query without LIMIT and OFFSET clauses\r\n return new SimpleSelectQuery({\r\n withClause: query.withClause,\r\n selectClause: query.selectClause,\r\n fromClause: query.fromClause,\r\n whereClause: query.whereClause,\r\n groupByClause: query.groupByClause,\r\n havingClause: query.havingClause,\r\n orderByClause: query.orderByClause,\r\n windowClause: query.windowClause,\r\n limitClause: null, // Remove LIMIT\r\n offsetClause: null, // Remove OFFSET\r\n fetchClause: query.fetchClause,\r\n forClause: query.forClause,\r\n });\r\n }\r\n\r\n /**\r\n * Validates pagination options\r\n * @param pagination Pagination options to validate\r\n * @throws Error if validation fails\r\n */\r\n private validatePaginationOptions(pagination: PaginationOptions): void {\r\n if (!pagination) {\r\n throw new Error('Pagination options are required');\r\n }\r\n\r\n if (typeof pagination.page !== 'number' || pagination.page < 1) {\r\n throw new Error('Page number must be a positive integer (1 or greater)');\r\n }\r\n\r\n if (typeof pagination.pageSize !== 'number' || pagination.pageSize < 1) {\r\n throw new Error('Page size must be a positive integer (1 or greater)');\r\n }\r\n\r\n // Optional: Set reasonable upper limit for page size to prevent performance issues\r\n if (pagination.pageSize > 1000) {\r\n throw new Error('Page size cannot exceed 1000 items');\r\n }\r\n }\r\n}\r\n", "import { SelectQuery, SimpleSelectQuery } from \"../models/SelectQuery\";\r\nimport { SelectQueryParser } from \"../parsers/SelectQueryParser\";\r\nimport { SqlParamInjector } from \"./SqlParamInjector\";\r\nimport { SqlSortInjector, SortConditions } from \"./SqlSortInjector\";\r\nimport { SqlPaginationInjector, PaginationOptions } from \"./SqlPaginationInjector\";\r\nimport { PostgresJsonQueryBuilder, JsonMapping } from \"./PostgresJsonQueryBuilder\";\r\nimport { QueryBuilder } from \"./QueryBuilder\";\r\n\r\n/**\r\n * Options for dynamic query building\r\n */\r\nexport interface QueryBuildOptions {\r\n /** Filter conditions to inject into WHERE clause */\r\n filter?: Record<string, any>;\r\n /** Sort conditions to inject into ORDER BY clause */\r\n sort?: SortConditions;\r\n /** Pagination options to inject LIMIT/OFFSET clauses */\r\n paging?: PaginationOptions;\r\n /** JSON serialization mapping to transform results into hierarchical JSON\r\n * - JsonMapping object: explicit mapping configuration\r\n * - true: auto-load mapping from corresponding .json file\r\n * - false/undefined: no serialization\r\n */\r\n serialize?: JsonMapping | boolean;\r\n}\r\n\r\n/**\r\n * DynamicQueryBuilder provides pure JavaScript SQL query building capabilities.\r\n * It combines SQL parsing with dynamic condition injection (filtering, sorting, pagination, serialization).\r\n * \r\n * This class is framework-agnostic and does not perform any file I/O operations.\r\n * It only works with SQL content provided as strings.\r\n * \r\n * Key features:\r\n * - Pure JavaScript/TypeScript - no file system dependencies\r\n * - Framework-agnostic - can be used with any database framework\r\n * - Composable - combines multiple injectors in the correct order\r\n * - Type-safe - provides TypeScript types for all options\r\n * - Testable - easy to unit test without mocking file system\r\n */\r\nexport class DynamicQueryBuilder {\r\n private tableColumnResolver?: (tableName: string) => string[];\r\n /**\r\n * Creates a new DynamicQueryBuilder instance\r\n * @param tableColumnResolver Optional function to resolve table columns for wildcard queries\r\n */\r\n constructor(tableColumnResolver?: (tableName: string) => string[]) {\r\n this.tableColumnResolver = tableColumnResolver;\r\n }\r\n\r\n /**\r\n * Builds a SelectQuery from SQL content with dynamic conditions.\r\n * This is a pure function that does not perform any I/O operations.\r\n * * @param sqlContent Raw SQL string to parse and modify\r\n * @param options Dynamic conditions to apply (filter, sort, paging, serialize)\r\n * @returns Modified SelectQuery with all dynamic conditions applied\r\n * * @example\r\n * ```typescript\r\n * const builder = new DynamicQueryBuilder();\r\n * const query = builder.buildQuery(\r\n * 'SELECT id, name FROM users WHERE active = true',\r\n * {\r\n * filter: { status: 'premium' },\r\n * sort: { created_at: { desc: true } },\r\n * paging: { page: 2, pageSize: 10 },\r\n * serialize: { rootName: 'user', rootEntity: { id: 'user', name: 'User', columns: { id: 'id', name: 'name' } }, nestedEntities: [] }\r\n * }\r\n * );\r\n * ```\r\n */\r\n buildQuery(sqlContent: string, options: QueryBuildOptions = {}): SelectQuery {\r\n // Parse the base SQL\r\n let parsedQuery: SimpleSelectQuery;\r\n try {\r\n parsedQuery = SelectQueryParser.parse(sqlContent) as SimpleSelectQuery;\r\n } catch (error) {\r\n throw new Error(`Failed to parse SQL: ${error instanceof Error ? error.message : 'Unknown error'}`);\r\n }\r\n\r\n // Apply dynamic modifications in the correct order\r\n let modifiedQuery: SelectQuery = parsedQuery;\r\n\r\n // 1. Apply filtering first (most selective, should reduce data early)\r\n if (options.filter && Object.keys(options.filter).length > 0) {\r\n const paramInjector = new SqlParamInjector(this.tableColumnResolver);\r\n // Ensure we have a SimpleSelectQuery for the injector\r\n const simpleQuery = QueryBuilder.buildSimpleQuery(modifiedQuery);\r\n modifiedQuery = paramInjector.inject(simpleQuery, options.filter);\r\n }\r\n\r\n // 2. Apply sorting second (after filtering to sort smaller dataset)\r\n if (options.sort && Object.keys(options.sort).length > 0) {\r\n const sortInjector = new SqlSortInjector(this.tableColumnResolver);\r\n // Ensure we have a SimpleSelectQuery for the injector\r\n const simpleQuery = QueryBuilder.buildSimpleQuery(modifiedQuery);\r\n modifiedQuery = sortInjector.inject(simpleQuery, options.sort);\r\n } // 3. Apply pagination third (after filtering and sorting)\r\n if (options.paging) {\r\n const { page = 1, pageSize } = options.paging;\r\n if (pageSize !== undefined) {\r\n const paginationInjector = new SqlPaginationInjector();\r\n const paginationOptions = { page, pageSize };\r\n // Ensure we have a SimpleSelectQuery for the injector\r\n const simpleQuery = QueryBuilder.buildSimpleQuery(modifiedQuery);\r\n modifiedQuery = paginationInjector.inject(simpleQuery, paginationOptions);\r\n }\r\n }\r\n // 4. Apply serialization last (transform the final query structure to JSON)\r\n // Note: boolean values are handled at RawSqlClient level for auto-loading\r\n if (options.serialize && typeof options.serialize === 'object') {\r\n const jsonBuilder = new PostgresJsonQueryBuilder();\r\n // Ensure we have a SimpleSelectQuery for the JSON builder\r\n const simpleQuery = QueryBuilder.buildSimpleQuery(modifiedQuery);\r\n modifiedQuery = jsonBuilder.buildJsonQuery(simpleQuery, options.serialize);\r\n }\r\n\r\n return modifiedQuery;\r\n }\r\n\r\n /**\r\n * Builds a SelectQuery with only filtering applied.\r\n * Convenience method for when you only need dynamic WHERE conditions.\r\n * \r\n * @param sqlContent Raw SQL string to parse and modify\r\n * @param filter Filter conditions to apply\r\n * @returns Modified SelectQuery with filter conditions applied\r\n */\r\n buildFilteredQuery(sqlContent: string, filter: Record<string, any>): SelectQuery {\r\n return this.buildQuery(sqlContent, { filter });\r\n }\r\n\r\n /**\r\n * Builds a SelectQuery with only sorting applied.\r\n * Convenience method for when you only need dynamic ORDER BY clauses.\r\n * \r\n * @param sqlContent Raw SQL string to parse and modify\r\n * @param sort Sort conditions to apply\r\n * @returns Modified SelectQuery with sort conditions applied\r\n */\r\n buildSortedQuery(sqlContent: string, sort: SortConditions): SelectQuery {\r\n return this.buildQuery(sqlContent, { sort });\r\n } /**\r\n * Builds a SelectQuery with only pagination applied.\r\n * Convenience method for when you only need LIMIT/OFFSET clauses.\r\n * \r\n * @param sqlContent Raw SQL string to parse and modify\r\n * @param paging Pagination options to apply\r\n * @returns Modified SelectQuery with pagination applied\r\n */\r\n buildPaginatedQuery(sqlContent: string, paging: PaginationOptions): SelectQuery {\r\n return this.buildQuery(sqlContent, { paging });\r\n }\r\n\r\n /**\r\n * Builds a SelectQuery with only JSON serialization applied.\r\n * Convenience method for when you only need hierarchical JSON transformation.\r\n * \r\n * @param sqlContent Raw SQL string to parse and modify\r\n * @param serialize JSON mapping configuration to apply\r\n * @returns Modified SelectQuery with JSON serialization applied\r\n */\r\n buildSerializedQuery(sqlContent: string, serialize: JsonMapping): SelectQuery {\r\n return this.buildQuery(sqlContent, { serialize });\r\n }\r\n\r\n /**\r\n * Validates SQL content by attempting to parse it.\r\n * Useful for testing SQL validity without applying any modifications.\r\n * \r\n * @param sqlContent Raw SQL string to validate\r\n * @returns true if SQL is valid, throws error if invalid\r\n * @throws Error if SQL cannot be parsed\r\n */\r\n validateSql(sqlContent: string): boolean {\r\n try {\r\n SelectQueryParser.parse(sqlContent);\r\n return true;\r\n } catch (error) {\r\n throw new Error(`Invalid SQL: ${error instanceof Error ? error.message : 'Unknown error'}`);\r\n }\r\n }\r\n}\r\n", "import { SchemaCollector, TableSchema } from '../transformers/SchemaCollector';\r\nimport { SqlComponent } from '../models/SqlComponent';\r\nimport { TableColumnResolver } from '../transformers/TableColumnResolver';\r\nimport { SelectQueryParser } from '../parsers/SelectQueryParser';\r\n\r\nexport class SqlSchemaValidator {\r\n /**\r\n * Validates a SQL query structure against a provided TableColumnResolver or TableSchema array.\r\n * @param sql The SQL query structure to validate, can be a SQL string or a SqlComponent.\r\n * @param tableResolver The TableColumnResolver or TableSchema array to validate against.\r\n * @throws Error if the query contains undefined tables or columns.\r\n */\r\n public static validate(\r\n sql: string | SqlComponent,\r\n tableResolver: TableColumnResolver | TableSchema[]\r\n ): void {\r\n const sqlComponent = typeof sql === 'string' ? SelectQueryParser.parse(sql) : sql;\r\n\r\n // Convert TableSchema[] to a resolver function if necessary\r\n const resolver = Array.isArray(tableResolver)\r\n ? (tableName: string) => {\r\n const schema = tableResolver.find((t) => t.name === tableName);\r\n return schema ? schema.columns : [];\r\n }\r\n : tableResolver;\r\n\r\n const schemaCollector = new SchemaCollector(resolver);\r\n const tableSchemas = schemaCollector.collect(sqlComponent);\r\n const errors: string[] = [];\r\n\r\n for (const tableSchema of tableSchemas) {\r\n const resolvedColumns = resolver(tableSchema.name);\r\n if (resolvedColumns.length === 0) {\r\n errors.push(`Table '${tableSchema.name}' is not defined.`);\r\n continue;\r\n }\r\n\r\n const undefinedColumns = tableSchema.columns.filter(column => !resolvedColumns.includes(column));\r\n if (undefinedColumns.length > 0) {\r\n errors.push(\r\n `Table '${tableSchema.name}' contains undefined columns: ${undefinedColumns.join(', ')}.`\r\n );\r\n }\r\n }\r\n\r\n if (errors.length > 0) {\r\n throw new Error(errors.join('\\n'));\r\n }\r\n }\r\n}\r\n", "import { JsonMapping } from '../transformers/PostgresJsonQueryBuilder';\r\n\r\n/**\r\n * Type alias for nested entity structure from JsonMapping\r\n */\r\ntype NestedEntity = JsonMapping['nestedEntities'][0];\r\n\r\n/**\r\n * Represents the structure extracted from JsonMapping analysis\r\n */\r\nexport type ExtractedStructure =\r\n | 'primitive'\r\n | { [key: string]: ExtractedStructure }\r\n | ExtractedStructure[];\r\n\r\n/**\r\n * Represents the expected type structure for validation\r\n */\r\nexport type ExpectedTypeStructure =\r\n | 'primitive'\r\n | { [key: string]: ExpectedTypeStructure }\r\n | ExpectedTypeStructure[];\r\n\r\n/**\r\n * Result of JsonMapping validation\r\n */\r\nexport interface ValidationResult {\r\n isValid: boolean;\r\n errors: string[];\r\n missingProperties: string[];\r\n extraProperties: string[];\r\n}\r\n\r\nexport class JsonSchemaValidator {\r\n /**\r\n * Validates JsonMapping structure against an expected type structure.\r\n * Checks if the JsonMapping covers all required properties and relationships.\r\n * \r\n * @param jsonMapping The JsonMapping configuration to validate\r\n * @param expectedStructure The expected type structure to validate against\r\n * @returns ValidationResult containing validation status and detailed errors\r\n */\r\n public static validate(\r\n jsonMapping: JsonMapping,\r\n expectedStructure: ExpectedTypeStructure\r\n ): ValidationResult {\r\n const extractedStructure = this.extractStructureFromJsonMapping(jsonMapping);\r\n return this.compareStructures(extractedStructure, expectedStructure);\r\n }\r\n\r\n /**\r\n * Validates JsonMapping structure and throws an error if validation fails.\r\n * Convenience method for strict validation scenarios.\r\n * \r\n * @param jsonMapping The JsonMapping configuration to validate\r\n * @param expectedStructure The expected type structure to validate against\r\n * @throws Error if validation fails with detailed error messages\r\n */\r\n public static validateStrict(\r\n jsonMapping: JsonMapping,\r\n expectedStructure: ExpectedTypeStructure\r\n ): void {\r\n const result = this.validate(jsonMapping, expectedStructure);\r\n if (!result.isValid) {\r\n const errorMessage = [\r\n 'JsonMapping validation failed:',\r\n ...result.errors\r\n ].join('\\n');\r\n throw new Error(errorMessage);\r\n }\r\n }\r\n\r\n /**\r\n * Extracts structure information from JsonMapping configuration.\r\n * Analyzes rootEntity and nestedEntities to build complete structure map.\r\n * \r\n * @param jsonMapping The JsonMapping to analyze\r\n * @returns ExtractedStructure representing the mapping structure\r\n */\r\n private static extractStructureFromJsonMapping(jsonMapping: JsonMapping): ExtractedStructure {\r\n const structure: ExtractedStructure = {};\r\n\r\n // Extract root entity properties\r\n if (jsonMapping.rootEntity && jsonMapping.rootEntity.columns) {\r\n Object.keys(jsonMapping.rootEntity.columns).forEach(propertyName => {\r\n structure[propertyName] = 'primitive';\r\n });\r\n }\r\n // Extract nested entities\r\n if (jsonMapping.nestedEntities) {\r\n // Process direct children of root entity first\r\n jsonMapping.nestedEntities\r\n .filter((entity: NestedEntity) => entity.parentId === jsonMapping.rootEntity.id)\r\n .forEach((entity: NestedEntity) => {\r\n if (entity.propertyName && entity.columns) {\r\n if (entity.relationshipType === 'object') {\r\n // Single object relationship\r\n structure[entity.propertyName] = this.extractNestedEntityStructure(entity, jsonMapping);\r\n } else if (entity.relationshipType === 'array') {\r\n // Array relationship\r\n structure[entity.propertyName] = [this.extractNestedEntityStructure(entity, jsonMapping)];\r\n }\r\n }\r\n });\r\n }\r\n\r\n return structure;\r\n } /**\r\n * Extracts structure from a nested entity, including its children.\r\n */\r\n private static extractNestedEntityStructure(entity: NestedEntity, jsonMapping: JsonMapping): ExtractedStructure {\r\n const entityStructure: ExtractedStructure = {};\r\n\r\n // Add entity's own columns\r\n if (entity.columns) {\r\n Object.keys(entity.columns).forEach(propName => {\r\n entityStructure[propName] = 'primitive';\r\n });\r\n }\r\n\r\n // Add nested children of this entity\r\n if (jsonMapping.nestedEntities) {\r\n jsonMapping.nestedEntities\r\n .filter((childEntity: NestedEntity) => childEntity.parentId === entity.id)\r\n .forEach((childEntity: NestedEntity) => {\r\n if (childEntity.propertyName && childEntity.columns) {\r\n if (childEntity.relationshipType === 'object') {\r\n entityStructure[childEntity.propertyName] = this.extractNestedEntityStructure(childEntity, jsonMapping);\r\n } else if (childEntity.relationshipType === 'array') {\r\n entityStructure[childEntity.propertyName] = [this.extractNestedEntityStructure(childEntity, jsonMapping)];\r\n }\r\n }\r\n });\r\n }\r\n\r\n return entityStructure;\r\n } /**\r\n * Compares extracted structure with expected structure with proper type guards.\r\n */\r\n private static compareStructures(\r\n extracted: ExtractedStructure,\r\n expected: ExpectedTypeStructure,\r\n path: string = ''\r\n ): ValidationResult {\r\n const errors: string[] = [];\r\n const missingProperties: string[] = [];\r\n const extraProperties: string[] = [];\r\n\r\n // Handle primitive comparison\r\n if (extracted === 'primitive' && expected === 'primitive') {\r\n return { isValid: true, errors: [], missingProperties: [], extraProperties: [] };\r\n }\r\n\r\n // Handle array types\r\n if (Array.isArray(expected) && Array.isArray(extracted)) {\r\n if (expected.length > 0 && extracted.length > 0) {\r\n const nestedResult = this.compareStructures(extracted[0], expected[0], `${path}[]`);\r\n errors.push(...nestedResult.errors);\r\n missingProperties.push(...nestedResult.missingProperties);\r\n extraProperties.push(...nestedResult.extraProperties);\r\n }\r\n return { isValid: errors.length === 0, errors, missingProperties, extraProperties };\r\n } // Both should be objects for property comparison\r\n if (typeof extracted !== 'object' || typeof expected !== 'object' ||\r\n Array.isArray(extracted) || Array.isArray(expected) ||\r\n extracted === null || expected === null) {\r\n return { isValid: true, errors: [], missingProperties: [], extraProperties: [] };\r\n }\r\n\r\n // Now we know both are object types, safe to access properties\r\n const extractedObj = extracted as { [key: string]: ExtractedStructure };\r\n const expectedObj = expected as { [key: string]: ExpectedTypeStructure };\r\n\r\n // Check for missing properties in extracted structure\r\n Object.keys(expectedObj).forEach(key => {\r\n const currentPath = path ? `${path}.${key}` : key;\r\n\r\n if (!(key in extractedObj)) {\r\n missingProperties.push(currentPath);\r\n errors.push(`Missing property: ${currentPath}`);\r\n return;\r\n }\r\n\r\n const extractedValue = extractedObj[key];\r\n const expectedValue = expectedObj[key];\r\n\r\n // Recursively compare nested structures\r\n const nestedResult = this.compareStructures(extractedValue, expectedValue, currentPath);\r\n errors.push(...nestedResult.errors);\r\n missingProperties.push(...nestedResult.missingProperties);\r\n extraProperties.push(...nestedResult.extraProperties);\r\n });\r\n\r\n // Check for extra properties in extracted structure\r\n Object.keys(extractedObj).forEach(key => {\r\n const currentPath = path ? `${path}.${key}` : key;\r\n if (!(key in expectedObj)) {\r\n extraProperties.push(currentPath);\r\n // Note: Extra properties are not considered errors in this implementation\r\n // as JsonMapping might include additional metadata\r\n }\r\n });\r\n\r\n return {\r\n isValid: errors.length === 0,\r\n errors,\r\n missingProperties,\r\n extraProperties\r\n };\r\n }\r\n\r\n /**\r\n * Validates JsonMapping structure against a sample object that implements the expected type.\r\n * This method extracts structure from the sample object and compares it with JsonMapping.\r\n * \r\n * @param jsonMapping The JsonMapping configuration to validate\r\n * @param sampleObject A sample object that implements the expected interface/type\r\n * @returns ValidationResult containing validation status and detailed errors\r\n */\r\n public static validateAgainstSample<T>(\r\n jsonMapping: JsonMapping,\r\n sampleObject: T\r\n ): ValidationResult {\r\n const expectedStructure = this.extractStructureFromSample(sampleObject);\r\n return this.validate(jsonMapping, expectedStructure);\r\n }\r\n\r\n /**\r\n * Validates JsonMapping structure against a sample object and throws an error if validation fails.\r\n * Convenience method for strict validation scenarios with sample objects.\r\n * \r\n * @param jsonMapping The JsonMapping configuration to validate\r\n * @param sampleObject A sample object that implements the expected interface/type\r\n * @throws Error if validation fails with detailed error messages\r\n */\r\n public static validateAgainstSampleStrict<T>(\r\n jsonMapping: JsonMapping,\r\n sampleObject: T\r\n ): void {\r\n const result = this.validateAgainstSample(jsonMapping, sampleObject);\r\n if (!result.isValid) {\r\n const errorMessage = [\r\n 'JsonMapping validation against sample object failed:',\r\n ...result.errors\r\n ].join('\\n');\r\n throw new Error(errorMessage);\r\n }\r\n } /**\r\n * Extracts structure information from a sample object.\r\n * Recursively analyzes the object properties to build a structure map.\r\n * \r\n * @param sampleObject The sample object to analyze\r\n * @returns ExpectedTypeStructure representing the object structure\r\n */\r\n private static extractStructureFromSample(sampleObject: any): ExpectedTypeStructure {\r\n if (sampleObject === null || sampleObject === undefined) {\r\n return 'primitive' as ExpectedTypeStructure;\r\n }\r\n\r\n if (Array.isArray(sampleObject)) {\r\n if (sampleObject.length === 0) {\r\n return [] as ExpectedTypeStructure;\r\n }\r\n return [this.extractStructureFromSample(sampleObject[0])] as ExpectedTypeStructure;\r\n }\r\n\r\n if (typeof sampleObject === 'object') {\r\n const structure: { [key: string]: ExpectedTypeStructure } = {};\r\n Object.keys(sampleObject).forEach(key => {\r\n structure[key] = this.extractStructureFromSample(sampleObject[key]);\r\n });\r\n return structure as ExpectedTypeStructure;\r\n }\r\n\r\n // Primitive types (string, number, boolean, etc.)\r\n return 'primitive' as ExpectedTypeStructure;\r\n }\r\n}\r\n", "/**\r\n * Schema Manager for rawsql-ts\r\n * Provides unified schema definition and automatic conversion to various formats\r\n * Eliminates code duplication and provides type-safe schema management\r\n */\r\n\r\n// Import JsonMapping interface for type safety\r\nimport type { JsonMapping } from '../transformers/PostgresJsonQueryBuilder';\r\n\r\n// === Core Types for User-defined Schemas ===\r\n\r\n/**\r\n * Database column metadata for schema mapping\r\n */\r\nexport interface ColumnDefinition {\r\n /** Column name in database */\r\n name: string;\r\n /** Primary key indicator - used for UPDATE/DELETE query WHERE conditions */\r\n isPrimaryKey?: boolean;\r\n /** Foreign key reference */\r\n foreignKey?: {\r\n table: string;\r\n column: string;\r\n };\r\n /** Alias for JSON output (useful for avoiding conflicts) */\r\n jsonAlias?: string;\r\n}\r\n\r\n/**\r\n * Table relationship definition\r\n */\r\nexport interface RelationshipDefinition {\r\n /** Type of relationship */\r\n type: 'object' | 'array';\r\n /** Target table name */\r\n table: string;\r\n /** Property name in JSON output */\r\n propertyName: string;\r\n /** Optional: Override target table's primary key */\r\n targetKey?: string;\r\n}\r\n\r\n/**\r\n * Complete table schema definition that users write\r\n */\r\nexport interface TableDefinition {\r\n /** Table name in database */\r\n name: string;\r\n /** Human-readable entity name */\r\n displayName?: string;\r\n /** Column definitions */\r\n columns: Record<string, ColumnDefinition>;\r\n /** Relationships with other tables */\r\n relationships?: RelationshipDefinition[];\r\n}\r\n\r\n/**\r\n * Schema registry containing all table definitions\r\n */\r\nexport interface SchemaRegistry {\r\n [tableName: string]: TableDefinition;\r\n}\r\n\r\n// === Schema Manager Class ===\r\n\r\n/**\r\n * Central schema management utility for rawsql-ts\r\n * Converts user-defined schemas to various internal formats\r\n */\r\nexport class SchemaManager {\r\n private schemas: SchemaRegistry;\r\n\r\n constructor(schemas: SchemaRegistry) {\r\n this.schemas = schemas;\r\n this.validateSchemas();\r\n }\r\n\r\n /**\r\n * Validate schema definitions for consistency\r\n * Ensures each table has a primary key (required for UPDATE/DELETE operations)\r\n * and validates relationship references\r\n */\r\n private validateSchemas(): void {\r\n const tableNames = Object.keys(this.schemas);\r\n const errors: string[] = [];\r\n\r\n // Validate each table\r\n Object.entries(this.schemas).forEach(([tableName, table]) => {\r\n // Check primary key exists (required for UPDATE/DELETE WHERE conditions)\r\n const primaryKeys = Object.entries(table.columns)\r\n .filter(([_, col]) => col.isPrimaryKey)\r\n .map(([name, _]) => name);\r\n\r\n if (primaryKeys.length === 0) {\r\n errors.push(`Table '${tableName}' has no primary key defined`);\r\n }\r\n\r\n // Validate foreign key references\r\n table.relationships?.forEach(rel => {\r\n if (!tableNames.includes(rel.table)) {\r\n errors.push(`Table '${tableName}' references unknown table '${rel.table}' in relationship`);\r\n }\r\n });\r\n });\r\n\r\n if (errors.length > 0) {\r\n throw new Error(`Schema validation failed:\\\\n${errors.join('\\\\n')}`);\r\n }\r\n }\r\n\r\n /**\r\n * Get table column names for SqlParamInjector TableColumnResolver\r\n * @param tableName Name of the table\r\n * @returns Array of column names\r\n */\r\n public getTableColumns(tableName: string): string[] {\r\n const table = this.schemas[tableName];\r\n if (!table) {\r\n return [];\r\n }\r\n return Object.keys(table.columns);\r\n }\r\n\r\n /**\r\n * Create TableColumnResolver function for SqlParamInjector\r\n * @returns Function compatible with SqlParamInjector\r\n */\r\n public createTableColumnResolver(): (tableName: string) => string[] {\r\n return (tableName: string) => this.getTableColumns(tableName);\r\n }\r\n\r\n /**\r\n * Generate JSON mapping configuration for PostgresJsonQueryBuilder\r\n * @param rootTableName Root table for the JSON structure\r\n * @returns JSON mapping configuration\r\n */\r\n public createJsonMapping(rootTableName: string): JsonMapping {\r\n const rootTable = this.schemas[rootTableName];\r\n if (!rootTable) {\r\n throw new Error(`Table '${rootTableName}' not found in schema registry`);\r\n }\r\n\r\n // Build root entity columns mapping\r\n const rootColumns: Record<string, string> = {};\r\n Object.entries(rootTable.columns).forEach(([columnName, column]) => {\r\n rootColumns[columnName] = column.jsonAlias || column.name;\r\n });\r\n\r\n // Build nested entities from relationships\r\n const nestedEntities: JsonMapping['nestedEntities'] = [];\r\n\r\n rootTable.relationships?.forEach(rel => {\r\n const relatedTable = this.schemas[rel.table];\r\n if (!relatedTable) {\r\n throw new Error(`Related table '${rel.table}' not found in schema registry`);\r\n }\r\n\r\n // Build columns mapping for related table\r\n const relatedColumns: Record<string, string> = {};\r\n Object.entries(relatedTable.columns).forEach(([columnName, column]) => {\r\n relatedColumns[columnName] = column.jsonAlias || column.name;\r\n });\r\n\r\n // Determine relationship type for JSON builder\r\n const relationshipType = rel.type;\r\n\r\n nestedEntities.push({\r\n id: rel.propertyName,\r\n name: relatedTable.displayName || rel.table,\r\n parentId: rootTableName,\r\n propertyName: rel.propertyName,\r\n relationshipType: relationshipType as 'object' | 'array',\r\n columns: relatedColumns\r\n });\r\n });\r\n\r\n return {\r\n rootName: rootTableName,\r\n rootEntity: {\r\n id: rootTableName,\r\n name: rootTable.displayName || rootTableName,\r\n columns: rootColumns\r\n },\r\n nestedEntities,\r\n resultFormat: \"single\" as const\r\n };\r\n }\r\n\r\n /**\r\n * Get all table names in the schema\r\n * @returns Array of table names\r\n */\r\n public getTableNames(): string[] {\r\n return Object.keys(this.schemas);\r\n }\r\n\r\n /**\r\n * Get table definition by name\r\n * @param tableName Name of the table\r\n * @returns Table definition or undefined\r\n */\r\n public getTable(tableName: string): TableDefinition | undefined {\r\n return this.schemas[tableName];\r\n }\r\n\r\n /**\r\n * Get primary key column name for a table\r\n * Used by QueryBuilder.buildUpdateQuery for WHERE clause conditions\r\n * @param tableName Name of the table\r\n * @returns Primary key column name or undefined\r\n */\r\n public getPrimaryKey(tableName: string): string | undefined {\r\n const table = this.schemas[tableName];\r\n if (!table) return undefined;\r\n\r\n const primaryKeyEntry = Object.entries(table.columns)\r\n .find(([_, col]) => col.isPrimaryKey);\r\n\r\n return primaryKeyEntry ? primaryKeyEntry[0] : undefined;\r\n }\r\n\r\n /**\r\n * Get foreign key relationships for a table\r\n * @param tableName Name of the table\r\n * @returns Array of foreign key relationships\r\n */\r\n public getForeignKeys(tableName: string): Array<{ column: string; referencedTable: string; referencedColumn: string }> {\r\n const table = this.schemas[tableName];\r\n if (!table) return [];\r\n\r\n const foreignKeys: Array<{ column: string; referencedTable: string; referencedColumn: string }> = [];\r\n\r\n Object.entries(table.columns).forEach(([columnName, column]) => {\r\n if (column.foreignKey) {\r\n foreignKeys.push({\r\n column: columnName,\r\n referencedTable: column.foreignKey.table,\r\n referencedColumn: column.foreignKey.column\r\n });\r\n }\r\n });\r\n\r\n return foreignKeys;\r\n }\r\n}\r\n\r\n// === Convenience Functions ===\r\n\r\n/**\r\n * Create a SchemaManager instance from schema definitions\r\n * @param schemas Schema registry object\r\n * @returns SchemaManager instance\r\n */\r\nexport function createSchemaManager(schemas: SchemaRegistry): SchemaManager {\r\n return new SchemaManager(schemas);\r\n}\r\n\r\n/**\r\n * Create TableColumnResolver function from schema definitions\r\n * @param schemas Schema registry object\r\n * @returns TableColumnResolver function for SqlParamInjector\r\n */\r\nexport function createTableColumnResolver(schemas: SchemaRegistry): (tableName: string) => string[] {\r\n const manager = new SchemaManager(schemas);\r\n return manager.createTableColumnResolver();\r\n}\r\n\r\n/**\r\n * Create JSON mapping from schema definitions\r\n * @param schemas Schema registry object\r\n * @param rootTableName Root table name\r\n * @returns JSON mapping for PostgresJsonQueryBuilder\r\n */\r\nexport function createJsonMappingFromSchema(schemas: SchemaRegistry, rootTableName: string): JsonMapping {\r\n const manager = new SchemaManager(schemas);\r\n return manager.createJsonMapping(rootTableName);\r\n}\r\n"],
|
|
5
|
-
"mappings": "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",
|
|
6
|
-
"names": ["index_exports", "__export", "ArrayExpression", "ArrayQueryExpression", "BetweenExpression", "BinaryExpression", "BinarySelectQuery", "CTECollector", "CTENormalizer", "CaseExpression", "CaseKeyValuePair", "CastExpression", "ColumnReference", "DuplicateDetectionMode", "DynamicQueryBuilder", "Formatter", "FunctionCall", "IdentifierString", "InlineQuery", "InsertQuery", "InsertQueryParser", "JsonSchemaValidator", "LiteralValue", "ParameterExpression", "ParenExpression", "PostgresJsonQueryBuilder", "QualifiedName", "QueryBuilder", "RawString", "SchemaCollector", "SchemaManager", "SelectQueryParser", "SelectValueCollector", "SelectableColumnCollector", "SimpleSelectQuery", "SqlFormatter", "SqlPaginationInjector", "SqlParamInjector", "SqlSchemaValidator", "SqlSortInjector", "StringSpecifierExpression", "SwitchCaseArgument", "TableSchema", "TableSourceCollector", "TupleExpression", "TypeTransformationPostProcessor", "TypeTransformers", "TypeValue", "UnaryExpression", "UpstreamSelectQueryFinder", "VALID_PRESETS", "ValueList", "ValuesQuery", "WindowFrameBound", "WindowFrameBoundStatic", "WindowFrameBoundaryValue", "WindowFrameExpression", "WindowFrameSpec", "WindowFrameType", "convertModelDrivenMapping", "convertUnifiedMapping", "createJsonMappingFromSchema", "createSchemaManager", "createTableColumnResolver", "isLegacyFormat", "isModelDrivenFormat", "isUnifiedFormat", "processJsonMapping", "transformDatabaseResult", "unifyJsonMapping", "validateModelDrivenMapping", "__toCommonJS", "SqlComponent", "visitor", "formatter", "InsertQuery", "SqlComponent", "params", "InlineQuery", "SqlComponent", "selectQuery", "ValueList", "values", "ColumnReference", "IdentifierString", "namespaces", "column", "col", "QualifiedName", "toIdentifierStringArray", "namespace", "FunctionCall", "name", "argument", "over", "WindowFrameType", "WindowFrameBound", "WindowFrameBoundStatic", "bound", "WindowFrameBoundaryValue", "value", "isFollowing", "WindowFrameSpec", "frameType", "startBound", "endBound", "WindowFrameExpression", "partition", "order", "frameSpec", "UnaryExpression", "operator", "expression", "RawString", "BinaryExpression", "left", "right", "LiteralValue", "ParameterExpression", "SwitchCaseArgument", "cases", "elseValue", "CaseKeyValuePair", "key", "alias", "ParenExpression", "CastExpression", "input", "castType", "CaseExpression", "condition", "switchCase", "ArrayExpression", "ArrayQueryExpression", "query", "BetweenExpression", "lower", "upper", "negated", "StringSpecifierExpression", "specifier", "TypeValue", "nameValue", "ns", "TupleExpression", "filteredStrings", "filteredIdentifiers", "SelectItem", "SqlComponent", "value", "name", "IdentifierString", "SelectClause", "items", "distinct", "Distinct", "DistinctOn", "WhereClause", "condition", "PartitionByClause", "WindowFrameClause", "expression", "WindowsClause", "windows", "OrderByClause", "SqlComponent", "items", "OrderByItem", "expression", "sortDirection", "nullsPosition", "GroupByClause", "HavingClause", "condition", "TableSource", "IdentifierString", "namespaces", "table", "tbl", "QualifiedName", "namespace", "RawString", "FunctionSource", "name", "argument", "nameObj", "ParenSource", "source", "SubQuerySource", "query", "SourceExpression", "datasource", "aliasExpression", "JoinOnClause", "JoinUsingClause", "JoinClause", "joinType", "lateral", "FromClause", "join", "sources", "CommonTable", "materialized", "SourceAliasExpression", "WithClause", "recursive", "tables", "LimitClause", "limit", "OffsetClause", "SqlComponent", "value", "FetchClause", "expression", "FetchExpression", "type", "count", "unit", "ForClause", "SqlComponent", "lockMode", "SourceAliasExpression", "alias", "columnAlias", "IdentifierString", "ReturningClause", "columns", "col", "SetClause", "items", "item", "SetClauseItem", "column", "value", "colObj", "QualifiedName", "UpdateClause", "source", "TableSource", "InsertClause", "TokenType", "CharLookupTable", "char", "code", "StringUtils", "_StringUtils", "input", "errPosition", "start", "end", "debugInfo", "caret", "position", "length", "charCode", "comment", "lines", "oldPosition", "lineCommentResult", "blockCommentResult", "result", "CharLookupTable", "BaseTokenReader", "input", "position", "shift", "expectChar", "char", "type", "value", "comments", "errPosition", "StringUtils", "IdentifierTokenReader", "BaseTokenReader", "previous", "char", "result", "StringUtils", "KeywordParser", "trie", "input", "position", "shift", "result", "StringUtils", "matchResult", "lexeme", "previousMatchResult", "KeywordTrie", "keywords", "keyword", "node", "word", "lexeme", "keywords", "trie", "KeywordTrie", "literalKeywordParser", "KeywordParser", "LiteralTokenReader", "BaseTokenReader", "previous", "char", "keyword", "CharLookupTable", "value", "sign", "pos", "result", "start", "hasDot", "hasExponent", "prefixType", "isHex", "c", "includeSingleQuote", "closed", "ParameterTokenReader", "BaseTokenReader", "input", "previous", "start", "identifier", "char", "CharLookupTable", "SpecialSymbolTokenReader", "_SpecialSymbolTokenReader", "BaseTokenReader", "previous", "char", "TokenReaderManager", "input", "position", "reader", "readers", "previous", "lexeme", "maxPosition", "total", "ratio", "trie", "KeywordTrie", "operatorOrTypeTrie", "keywordParser", "KeywordParser", "operatorOrTypeParser", "OperatorTokenReader", "BaseTokenReader", "previous", "char", "CharLookupTable", "start", "current", "resut", "result", "operatorOrTypeParser", "keywordParser", "joinTrie", "KeywordTrie", "keywordTrie", "keywordParser", "KeywordParser", "joinkeywordParser", "CommandTokenReader", "BaseTokenReader", "previous", "keywordJoin", "keyword", "start", "STRING_SPECIFIERS", "UNICODE_STRING_SPECIFIERS", "StringSpecifierTokenReader", "BaseTokenReader", "previous", "start", "trie", "KeywordTrie", "keywordParser", "KeywordParser", "FunctionTokenReader", "BaseTokenReader", "previous", "keyword", "result", "StringUtils", "shift", "trie", "KeywordTrie", "typeParser", "KeywordParser", "TypeTokenReader", "BaseTokenReader", "previous", "keyword", "result", "StringUtils", "EscapedIdentifierTokenReader", "BaseTokenReader", "previous", "char", "identifier", "delimiter", "start", "SqlTokenizer", "input", "TokenReaderManager", "EscapedIdentifierTokenReader", "ParameterTokenReader", "StringSpecifierTokenReader", "LiteralTokenReader", "SpecialSymbolTokenReader", "CommandTokenReader", "OperatorTokenReader", "TypeTokenReader", "FunctionTokenReader", "IdentifierTokenReader", "shift", "estimatedTokens", "lexemes", "lexemeCount", "comment", "pendingComments", "previous", "lexeme", "currentComment", "lastToken", "prefixComments", "suffixComments", "StringUtils", "errPosition", "FullNameParser", "_FullNameParser", "lexemes", "index", "identifiers", "newIndex", "namespaces", "name", "lastTokenType", "IdentifierString", "str", "SqlTokenizer", "result", "idx", "IdentifierParser", "lexemes", "index", "namespaces", "name", "newIndex", "FullNameParser", "ColumnReference", "LiteralParser", "lexemes", "index", "idx", "valueText", "parsedValue", "lex", "literalKeywordParser", "value", "RawString", "LiteralValue", "ParenExpressionParser", "lexemes", "index", "idx", "result", "SelectQueryParser", "InlineQuery", "ValueParser", "ParenExpression", "UnaryExpressionParser", "lexemes", "index", "idx", "operator", "ColumnReference", "result", "ValueParser", "UnaryExpression", "ParameterExpressionParser", "lexemes", "index", "idx", "paramName", "value", "ParameterExpression", "StringSpecifierExpressionParser", "lexemes", "index", "idx", "specifer", "value", "StringSpecifierExpression", "CommandExpressionParser", "lexemes", "index", "idx", "current", "command", "result", "ValueParser", "UnaryExpression", "condition", "switchCaseResult", "CaseExpression", "casewhenResult", "caseWhenList", "initialWhenThenList", "whenThenList", "elseValue", "whenResult", "elseResult", "SwitchCaseArgument", "lexeme", "value", "CaseKeyValuePair", "OrderByClauseParser", "query", "lexemes", "SqlTokenizer", "result", "index", "idx", "items", "item", "OrderByClause", "parsedValue", "ValueParser", "value", "sortDirection", "nullsSortDirection", "OrderByItem", "PartitionByParser", "query", "lexemes", "SqlTokenizer", "result", "index", "idx", "items", "item", "ValueParser", "PartitionByClause", "ValueList", "WindowExpressionParser", "query", "lexemes", "SqlTokenizer", "result", "index", "idx", "partition", "order", "frameSpec", "partitionResult", "PartitionByParser", "orderResult", "OrderByClauseParser", "frameSpecResult", "WindowFrameExpression", "value", "lowerValue", "frameTypeStr", "frameType", "startBoundResult", "startBound", "endBoundResult", "endBound", "WindowFrameSpec", "boundaryResult", "currentValue", "frameBound", "WindowFrameBoundStatic", "valueResult", "ValueParser", "direction", "isFollowing", "WindowFrameBoundaryValue", "OverExpressionParser", "query", "lexemes", "SqlTokenizer", "result", "index", "idx", "name", "IdentifierString", "WindowExpressionParser", "FunctionExpressionParser", "lexemes", "index", "idx", "arg", "ValueParser", "ArrayExpression", "SelectQueryParser", "ArrayQueryExpression", "current", "left", "allowAndOperator", "allowOrOperator", "operator", "typeValue", "CastExpression", "rightResult", "BinaryExpression", "value", "negated", "lower", "upper", "BetweenExpression", "fullNameResult", "FullNameParser", "namespaces", "name", "over", "OverExpressionParser", "FunctionCall", "keywords", "input", "key", "required", "right", "newIndex", "TypeValue", "RawString", "ParseError", "_ParseError", "message", "index", "context", "lexemes", "messagePrefix", "start", "end", "lexeme", "idx", "marker", "typeName", "TokenType", "OperatorPrecedence", "operator", "precedence", "operator1", "operator2", "op", "lowerOp", "ValueParser", "query", "lexemes", "SqlTokenizer", "result", "ParseError", "index", "allowAndOperator", "allowOrOperator", "minPrecedence", "idx", "comment", "left", "operator", "precedence", "OperatorPrecedence", "betweenResult", "FunctionExpressionParser", "typeValue", "CastExpression", "nextMinPrecedence", "rightResult", "BinaryExpression", "current", "first", "IdentifierParser", "second", "LiteralParser", "UnaryExpression", "namespaces", "name", "newIndex", "FullNameParser", "ColumnReference", "ParenExpressionParser", "UnaryExpressionParser", "ParameterExpressionParser", "StringSpecifierExpressionParser", "CommandExpressionParser", "TypeValue", "openToken", "closeToken", "args", "ValueList", "wildcard", "argResult", "CTECollector", "SimpleSelectQuery", "expr", "BinarySelectQuery", "ValuesQuery", "WithClause", "CommonTable", "SelectItem", "IdentifierString", "RawString", "ColumnReference", "ParameterExpression", "LiteralValue", "SourceExpression", "TableSource", "FunctionSource", "ParenSource", "SubQuerySource", "InlineQuery", "FromClause", "JoinClause", "JoinOnClause", "JoinUsingClause", "WhereClause", "ParenExpression", "BinaryExpression", "UnaryExpression", "CaseExpression", "CaseKeyValuePair", "SwitchCaseArgument", "BetweenExpression", "FunctionCall", "ArrayExpression", "ArrayQueryExpression", "TupleExpression", "CastExpression", "WindowFrameExpression", "WindowFrameSpec", "TypeValue", "ValueList", "StringSpecifierExpression", "SelectClause", "GroupByClause", "HavingClause", "OrderByClause", "WindowFrameClause", "LimitClause", "ForClause", "OrderByItem", "PartitionByClause", "query", "arg", "handler", "kindSymbol", "constructor", "win", "tuple", "withClause", "i", "commonTable", "clause", "item", "fromClause", "join", "source", "subQuery", "inlineQuery", "joinClause", "joinOn", "joinUsing", "whereClause", "switchCase", "caseItem", "pair", "func", "value", "spec", "ident", "raw", "column", "param", "partitionBy", "valueList", "CTEDisabler", "SimpleSelectQuery", "expr", "BinarySelectQuery", "ValuesQuery", "SelectItem", "IdentifierString", "RawString", "ColumnReference", "ParameterExpression", "LiteralValue", "SourceExpression", "TableSource", "ParenSource", "SubQuerySource", "InlineQuery", "FromClause", "JoinClause", "JoinOnClause", "JoinUsingClause", "WhereClause", "ParenExpression", "BinaryExpression", "UnaryExpression", "CaseExpression", "CaseKeyValuePair", "SwitchCaseArgument", "BetweenExpression", "FunctionCall", "ArrayExpression", "ArrayQueryExpression", "TupleExpression", "CastExpression", "WindowFrameExpression", "WindowFrameSpec", "TypeValue", "SelectClause", "GroupByClause", "HavingClause", "OrderByClause", "WindowFrameClause", "LimitClause", "ForClause", "OrderByItem", "arg", "handler", "kindSymbol", "constructor", "table", "WindowsClause", "w", "query", "newTuples", "tuple", "clause", "newItems", "item", "newSource", "newJoins", "join", "subQuery", "newQuery", "inlineQuery", "joinClause", "newCondition", "joinOn", "joinUsing", "whereClause", "newGrouping", "newOrder", "newExpression", "newLimit", "newLeft", "newRight", "newSwitchCase", "switchCase", "newCases", "caseItem", "newElseValue", "pair", "newKey", "newValue", "newLower", "newUpper", "func", "newArgument", "newOver", "newValues", "value", "newInput", "newCastType", "typeValue", "ident", "raw", "column", "source", "newAlias", "param", "newPartition", "newFrameSpec", "spec", "TableSourceCollector", "selectableOnly", "SimpleSelectQuery", "expr", "BinarySelectQuery", "ValuesQuery", "WithClause", "CommonTable", "FromClause", "JoinClause", "JoinOnClause", "JoinUsingClause", "SourceExpression", "TableSource", "FunctionSource", "ParenSource", "SubQuerySource", "InlineQuery", "WhereClause", "GroupByClause", "HavingClause", "OrderByClause", "WindowFrameClause", "LimitClause", "OffsetClause", "FetchClause", "ForClause", "OrderByItem", "SelectClause", "SelectItem", "ParenExpression", "BinaryExpression", "UnaryExpression", "CaseExpression", "CaseKeyValuePair", "SwitchCaseArgument", "BetweenExpression", "FunctionCall", "ArrayExpression", "ArrayQueryExpression", "TupleExpression", "CastExpression", "ValueList", "StringSpecifierExpression", "source", "ns", "RawString", "query", "arg", "handler", "cteCollector", "CTECollector", "commonTables", "cte", "win", "tuple", "withClause", "table", "commonTable", "fromClause", "join", "identifier", "value", "tableName", "subQuery", "inlineQuery", "joinClause", "joinOn", "joinUsing", "whereClause", "clause", "item", "switchCase", "caseItem", "pair", "func", "valueList", "SqlPrintToken", "type", "text", "containerType", "ParameterCollector", "node", "result", "walk", "n", "ParameterExpression", "key", "v", "IdentifierDecorator", "identifierEscape", "text", "ParameterDecorator", "options", "text", "index", "paramText", "UpdateQuery", "SqlComponent", "params", "SetClause", "SelectValueCollector", "_SelectValueCollector", "tableColumnResolver", "initialCommonTables", "CTECollector", "SimpleSelectQuery", "expr", "SelectClause", "SourceExpression", "FromClause", "arg", "items", "handler", "query", "wildcards", "item", "ColumnReference", "wildSourceNames", "fromSourceName", "join", "joinSourceName", "clause", "joinCascade", "sourceName", "source", "commonTable", "innerCommonTables", "columnName", "column", "TableSource", "SubQuerySource", "ParenSource", "name", "value", "CreateTableQuery", "SqlComponent", "params", "IdentifierString", "selectItems", "SelectValueCollector", "val", "SelectItem", "RawString", "SimpleSelectQuery", "SelectClause", "FromClause", "SourceExpression", "TableSource", "FunctionCall", "ColumnReference", "PRESETS", "SqlPrintTokenParser", "_SqlPrintTokenParser", "options", "ParameterDecorator", "IdentifierDecorator", "ValueList", "expr", "ColumnReference", "QualifiedName", "FunctionCall", "UnaryExpression", "BinaryExpression", "LiteralValue", "ParameterExpression", "SwitchCaseArgument", "CaseKeyValuePair", "RawString", "IdentifierString", "ParenExpression", "CastExpression", "CaseExpression", "ArrayExpression", "ArrayQueryExpression", "BetweenExpression", "StringSpecifierExpression", "TypeValue", "TupleExpression", "InlineQuery", "WindowFrameExpression", "WindowFrameSpec", "WindowFrameBoundStatic", "WindowFrameBoundaryValue", "PartitionByClause", "OrderByClause", "OrderByItem", "SelectItem", "SelectClause", "Distinct", "DistinctOn", "TableSource", "FunctionSource", "SourceExpression", "SourceAliasExpression", "FromClause", "JoinClause", "JoinOnClause", "JoinUsingClause", "WhereClause", "GroupByClause", "HavingClause", "WindowsClause", "WindowFrameClause", "LimitClause", "OffsetClause", "FetchClause", "FetchExpression", "ForClause", "WithClause", "CommonTable", "SimpleSelectQuery", "SubQuerySource", "BinarySelectQuery", "ValuesQuery", "InsertQuery", "InsertClause", "UpdateQuery", "UpdateClause", "SetClause", "SetClauseItem", "ReturningClause", "CreateTableQuery", "SqlPrintToken", "arg", "token", "i", "paramsRaw", "ParameterCollector", "a", "b", "style", "paramsObj", "p", "key", "paramsArr", "handler", "text", "kv", "elseValue", "elseToken", "elseValueContainer", "thenValueContainer", "specifier", "value", "first", "defaultName", "fullName", "ns", "query", "subQuery", "values", "queryToken", "LinePrinter", "indentChar", "indentSize", "newline", "result", "line", "level", "current", "PrintLine", "text", "workingIndex", "workLine", "SqlPrinter", "options", "LinePrinter", "token", "level", "current", "text", "keywordToken", "innerLevel", "child", "VALID_PRESETS", "SqlFormatter", "options", "presetConfig", "PRESETS", "parserOptions", "SqlPrintTokenParser", "SqlPrinter", "sql", "token", "params", "Formatter", "SqlFormatter", "arg", "config", "result", "CTEBuilder", "TableSourceCollector", "CTECollector", "Formatter", "commonTables", "WithClause", "resolvedTables", "tableMap", "recursiveCTEs", "dependencies", "sortedTables", "ctesByName", "table", "tableName", "name", "tables", "definitions", "referencedBy", "referencedTables", "referencedTable", "referencedCTEs", "referencedCTE", "referencedName", "recursiveResult", "nonRecursiveResult", "visited", "visiting", "visit", "deps", "dep", "CTEInjector", "CTEBuilder", "CTECollector", "query", "commonTables", "resolvedWithCaluse", "SimpleSelectQuery", "BinarySelectQuery", "withClause", "CTENormalizer", "query", "allCommonTables", "CTECollector", "CTEDisabler", "CTEInjector", "DuplicateDetectionMode", "SelectableColumnCollector", "tableColumnResolver", "includeWildCard", "duplicateDetection", "options", "CTECollector", "SimpleSelectQuery", "expr", "SelectClause", "FromClause", "WhereClause", "GroupByClause", "HavingClause", "OrderByClause", "WindowFrameClause", "LimitClause", "OffsetClause", "FetchClause", "JoinOnClause", "JoinUsingClause", "ColumnReference", "BinaryExpression", "UnaryExpression", "FunctionCall", "ParenExpression", "CaseExpression", "CastExpression", "BetweenExpression", "ArrayExpression", "ArrayQueryExpression", "ValueList", "WindowFrameExpression", "PartitionByClause", "arg", "items", "name", "value", "item", "tableName", "key", "itemTable", "handler", "query", "win", "clause", "sourceValues", "SelectValueCollector", "join", "joinOnClause", "joinUsingClause", "columnRef", "func", "SourceParser", "_SourceParser", "query", "lexemes", "SqlTokenizer", "result", "index", "fullNameResult", "FullNameParser", "idx", "namespaces", "name", "newIndex", "TableSource", "argument", "ValueParser", "functionName", "FunctionSource", "keyword", "selectQuery", "SelectQueryParser", "SubQuerySource", "UpstreamSelectQueryFinder", "tableColumnResolver", "options", "SelectableColumnCollector", "query", "columnNames", "namesArray", "ctes", "CTECollector", "cteMap", "cte", "src", "nextCteMap", "result", "fromClause", "sources", "allBranchResults", "allBranchesOk", "validBranchCount", "sourceExpr", "branchResult", "TableSource", "SubQuerySource", "ValuesQuery", "SimpleSelectQuery", "columns", "col", "normalize", "s", "name", "BinarySelectQuery", "left", "right", "SourceAliasExpressionParser", "lexemes", "index", "idx", "table", "columns", "SourceAliasExpression", "SourceExpressionParser", "query", "lexemes", "SqlTokenizer", "result", "index", "SourceParser", "SourceExpression", "idx", "sourceResult", "aliasResult", "SourceAliasExpressionParser", "type", "QueryBuilder", "_QueryBuilder", "queries", "operator", "wrap", "q", "ValuesQuery", "result", "BinarySelectQuery", "CTENormalizer", "query", "SimpleSelectQuery", "subQuerySource", "SubQuerySource", "sourceExpr", "SourceExpression", "SourceAliasExpression", "fromClause", "FromClause", "selectClause", "columnCount", "selectItems", "name", "SelectItem", "ColumnReference", "SelectClause", "columnRef", "selectItem", "tableName", "isTemporary", "CreateTableQuery", "selectQuery", "cols", "count", "SelectValueCollector", "item", "SourceExpressionParser", "InsertQuery", "InsertClause", "selectSourceName", "updateTableExprRaw", "primaryKeys", "updateClause", "UpdateClause", "pkArray", "collectedCTEs", "CTECollector", "CTEDisabler", "pk", "updateSourceName", "setItems", "col", "SetClauseItem", "setClause", "SetClause", "from", "where", "cond", "BinaryExpression", "whereClause", "WhereClause", "UpdateQuery", "WithClause", "ParameterHelper", "query", "name", "value", "params", "ParameterCollector", "found", "p", "SimpleSelectQuery", "SqlComponent", "params", "rightQuery", "operator", "QueryBuilder", "rawCondition", "parsedCondition", "ValueParser", "condition", "BinaryExpression", "WhereClause", "HavingClause", "joinSourceRawText", "alias", "columns", "resolver", "sourceExpr", "joinType", "tableSource", "SourceParser", "SourceExpression", "SourceAliasExpression", "columnsArr", "valueSets", "SelectableColumnCollector", "joinCondition", "count", "sourceAlias", "valueSet", "col", "expr", "ColumnReference", "joinOnClause", "JoinOnClause", "joinClause", "JoinClause", "CTENormalizer", "SubQuerySource", "commonTable", "tables", "WithClause", "rawText", "query", "SelectQueryParser", "CommonTable", "columnName", "fn", "items", "item", "exprSql", "Formatter", "newValue", "exprBuilder", "options", "queries", "UpstreamSelectQueryFinder", "collector", "formatter", "q", "exprs", "exprStr", "name", "value", "ParameterHelper", "BinarySelectQuery", "_BinarySelectQuery", "SqlComponent", "left", "operator", "right", "RawString", "query", "CTENormalizer", "sql", "parsedQuery", "SelectQueryParser", "alias", "SourceExpression", "SubQuerySource", "SourceAliasExpression", "name", "value", "ParameterHelper", "ValuesQuery", "SqlComponent", "tuples", "columnAliases", "QueryBuilder", "name", "value", "ParameterHelper", "SelectClauseParser", "query", "lexemes", "SqlTokenizer", "result", "index", "idx", "distinct", "Distinct", "argument", "ValueParser", "DistinctOn", "items", "item", "SelectItemParser", "SelectClause", "parsedValue", "value", "alias", "SelectItem", "ColumnReference", "JoinOnClauseParser", "lexemes", "index", "idx", "condition", "ValueParser", "JoinOnClause", "JoinUsingClauseParser", "lexemes", "index", "idx", "result", "ValueParser", "usingColumns", "JoinUsingClause", "JoinClauseParser", "lexemes", "index", "idx", "joins", "joinClause", "value", "joinkeywordParser", "joinType", "lateralResult", "lateral", "sourceResult", "SourceExpressionParser", "onResult", "JoinOnClauseParser", "JoinClause", "usingResult", "JoinUsingClauseParser", "FromClauseParser", "query", "lexemes", "SqlTokenizer", "result", "index", "idx", "sourceExpression", "SourceExpressionParser", "join", "JoinClauseParser", "FromClause", "WhereClauseParser", "query", "lexemes", "SqlTokenizer", "result", "index", "idx", "item", "ValueParser", "WhereClause", "GroupByClauseParser", "query", "lexemes", "SqlTokenizer", "result", "index", "idx", "items", "item", "GroupByClause", "parsedValue", "ValueParser", "value", "HavingClauseParser", "query", "lexemes", "SqlTokenizer", "result", "index", "idx", "item", "ValueParser", "HavingClause", "WindowClauseParser", "query", "lexemes", "SqlTokenizer", "result", "index", "idx", "windows", "name", "expr", "WindowExpressionParser", "WindowFrameClause", "WindowsClause", "LimitClauseParser", "query", "lexemes", "SqlTokenizer", "result", "index", "idx", "limitItem", "ValueParser", "LimitClause", "ForClauseParser", "query", "lexemes", "SqlTokenizer", "result", "index", "idx", "lockModeValue", "lockMode", "ForClause", "CommonTableParser", "query", "lexemes", "SqlTokenizer", "result", "index", "idx", "aliasResult", "SourceAliasExpressionParser", "materialized", "currentValue", "queryResult", "SelectQueryParser", "CommonTable", "WithClauseParser", "query", "lexemes", "SqlTokenizer", "result", "index", "idx", "recursive", "tables", "firstCte", "CommonTableParser", "cteResult", "WithClause", "ValuesQueryParser", "query", "lexemes", "SqlTokenizer", "result", "index", "idx", "tuples", "firstTuple", "tuple", "ValuesQuery", "values", "TupleExpression", "firstValue", "ValueParser", "value", "FetchClauseParser", "lexemes", "index", "idx", "fetchExprResult", "FetchExpressionParser", "fetchExpr", "FetchClause", "type", "typeToken", "count", "unit", "LiteralValue", "FetchExpression", "countResult", "ValueParser", "OffsetClauseParser", "query", "lexemes", "SqlTokenizer", "result", "index", "idx", "offsetItem", "ValueParser", "OffsetClause", "SelectQueryParser", "query", "lexemes", "SqlTokenizer", "result", "index", "idx", "firstToken", "firstResult", "operator", "nextToken", "BinarySelectQuery", "withClauseResult", "WithClauseParser", "selectClauseResult", "SelectClauseParser", "fromClauseResult", "FromClauseParser", "whereClauseResult", "WhereClauseParser", "groupByClauseResult", "GroupByClauseParser", "havingClauseResult", "HavingClauseParser", "windowClauseResult", "WindowClauseParser", "orderByClauseResult", "OrderByClauseParser", "limitClauseResult", "LimitClauseParser", "offsetClauseResult", "OffsetClauseParser", "fetchClauseResult", "FetchClauseParser", "forClauseResult", "ForClauseParser", "SimpleSelectQuery", "ValuesQueryParser", "InsertQueryParser", "query", "lexemes", "SqlTokenizer", "result", "index", "idx", "withclause", "WithClauseParser", "sourceResult", "SourceExpressionParser", "columns", "selectResult", "SelectQueryParser", "SimpleSelectQuery", "InsertQuery", "InsertClause", "PostgresObjectEntityCteBuilder", "_PostgresObjectEntityCteBuilder", "initialCte", "allEntities", "mapping", "ctes", "previousCteAlias", "objectEntityInfos", "entitiesByDepth", "depths", "a", "b", "depth", "entitiesAtDepth", "cteAlias", "cte", "objectInfos", "calculateActualObjectNestingDepth", "entityIdOfObject", "initialEntity", "currentParentIdInHierarchy", "calculatedObjectDepth", "visitedInPath", "parentEntityData", "parentIsConsideredAnObjectForNesting", "parentDefinition", "ne", "nestedEntity", "entity", "info", "selectItems", "SelectItem", "ColumnReference", "IdentifierString", "jsonColumn", "cteSelect", "SimpleSelectQuery", "SelectClause", "FromClause", "SourceExpression", "TableSource", "CommonTable", "SourceAliasExpression", "jsonObjectArgs", "nullChecks", "jsonObject", "nullCondition", "caseExpr", "jsonColumnName", "jsonKey", "sqlColumn", "LiteralValue", "BinaryExpression", "childEntity", "child", "args", "jsonBuildFunction", "FunctionCall", "RawString", "ValueList", "acc", "check", "CaseExpression", "SwitchCaseArgument", "CaseKeyValuePair", "PostgresArrayEntityCteBuilder", "_PostgresArrayEntityCteBuilder", "ctesSoFar", "aliasOfCteToBuildUpon", "allEntities", "mapping", "currentCtes", "currentCteAlias", "sortedArrayInfos", "entitiesByDepth", "depths", "a", "b", "depth", "infos", "cte", "newCteAlias", "arrayEntityInfos", "getDepth", "entityId", "entity", "ne", "currentArrayEntity", "parentEntity", "parentSqlColumns", "parentIdColumnSqlName", "arrayInfos", "info", "arrayColumns", "col", "collectNestedColumns", "parentEntityId", "nestedEntity", "column", "columnName", "prevCte", "c", "prevSelects", "SelectValueCollector", "groupByItems", "selectItems", "currentLevelArrayColumns", "arrayEntityColumns", "agg", "SelectItem", "cteAlias", "cteSelect", "SimpleSelectQuery", "SelectClause", "FromClause", "SourceExpression", "TableSource", "IdentifierString", "GroupByClause", "CommonTable", "SourceAliasExpression", "nestedEntities", "jsonBuildFunction", "args", "jsonKey", "sqlColumn", "LiteralValue", "ColumnReference", "childEntity", "jsonColumnName", "jsonObject", "FunctionCall", "RawString", "ValueList", "jsonAggFunction", "primaryColumn", "currentDepth", "arrayEntitiesByDepth", "maxDepth", "d", "entityDepth", "currentEntity", "e", "targetDepth", "sv", "isJsonColumn", "shouldInclude", "columns", "entityMatch", "PostgresJsonQueryBuilder", "SelectValueCollector", "PostgresObjectEntityCteBuilder", "PostgresArrayEntityCteBuilder", "query", "mapping", "selectedValues", "availableColumns", "sv", "jsonKey", "columnDef", "sourceColumn", "entityIds", "parentToChildrenMap", "ne", "entity", "allParentIds", "parentId", "directChildren", "c", "parentName", "propertyNames", "child", "originalQuery", "simpleQuery", "SimpleSelectQuery", "QueryBuilder", "initialCte", "initialCteAlias", "ctesForProcessing", "currentAliasToBuildUpon", "allEntities", "objectEntityResult", "arrayCteBuildResult", "originCteAlias", "CommonTable", "SourceAliasExpression", "finalCtesList", "lastCteAliasForFromClause", "currentCtes", "rootObjectCteAlias", "rootEntity", "rootObjectBuilderExpression", "rootObjectSelectItem", "SelectItem", "rootObjectCte", "SelectClause", "FromClause", "SourceExpression", "TableSource", "IdentifierString", "aggregationFunc", "aggregateExpression", "FunctionCall", "RawString", "ValueList", "ColumnReference", "WithClause", "LimitClause", "LiteralValue", "sourceAlias", "nestedEntities", "jsonBuildFunction", "args", "sqlColumn", "childEntity", "jsonColumnName", "convertUnifiedMapping", "unified", "protectedStringFields", "processColumns", "columns", "result", "key", "config", "jsonMapping", "entity", "convertModelDrivenMapping", "modelMapping", "protectedStringFields", "entityIdCounter", "generateEntityId", "processStructure", "structure", "parentId", "columns", "nestedEntities", "fieldName", "config", "fieldConfig", "nestedStructure", "entityId", "processedNested", "entity", "processed", "jsonMapping", "validateModelDrivenMapping", "mapping", "errors", "detectMappingFormat", "input", "convertUnifiedFormat", "result", "entity", "convertLegacyFormat", "propertyName", "relationship", "rel", "processJsonMapping", "format", "jsonMapping", "metadata", "modelDrivenInput", "converted", "convertModelDrivenMapping", "error", "unifyJsonMapping", "isModelDrivenFormat", "isUnifiedFormat", "isLegacyFormat", "TypeTransformationPostProcessor", "config", "result", "item", "obj", "transformed", "key", "value", "columnTransform", "detectedTransform", "globalTransform", "v", "date", "transformation", "integerValue", "error", "columnMappings", "transformDatabaseResult", "TypeTransformers", "TableSchema", "name", "columns", "SchemaCollector", "tableColumnResolver", "SimpleSelectQuery", "expr", "BinarySelectQuery", "arg", "cteCollector", "CTECollector", "handler", "consolidatedSchemas", "schema", "existingColumns", "column", "nameA", "nameB", "source", "queryColumns", "includeUnnamed", "TableSource", "tableName", "cte", "table", "tableAlias", "query", "SelectableColumnCollector", "ColumnReference", "columnRef", "columnsWithoutTable", "SubQuerySource", "join", "errorMessage", "tableColumns", "tableSchema", "SqlParamInjector", "optionsOrResolver", "options", "query", "state", "SelectQueryParser", "finder", "UpstreamSelectQueryFinder", "collector", "SelectableColumnCollector", "normalize", "s", "allowedOps", "stateValues", "value", "name", "stateValue", "orConditions", "referencedColumns", "cond", "col", "index", "arr", "targetQuery", "colName", "queries", "columns", "injectOrConditions", "andConditions", "injectAndConditions", "explicitColumnName", "q", "entry", "item", "validateOperators", "injectComplexConditions", "columnRef", "targetColumn", "targetColumnName", "explicitEntry", "injectSimpleCondition", "baseName", "availableColumns", "i", "andCondition", "columnName", "paramName", "paramExpr", "ParameterExpression", "BinaryExpression", "prms", "v", "j", "ParenExpression", "ValueList", "FunctionCall", "orExpressions", "orCondition", "branchConditions", "branchExpr", "finalOrExpr", "op", "conditions", "paramEq", "paramMin", "paramMax", "paramLike", "paramIlike", "paramAny", "paramLT", "paramGT", "paramNEQ", "paramNE", "paramLE", "paramGE", "combinedExpr", "SqlSortInjector", "tableColumnResolver", "query", "SelectQueryParser", "SimpleSelectQuery", "sortConditions", "availableColumns", "SelectableColumnCollector", "columnName", "item", "newOrderByItems", "condition", "columnEntry", "columnRef", "sortDirection", "nullsPosition", "orderByItem", "OrderByItem", "finalOrderByItems", "newOrderByClause", "OrderByClause", "SqlPaginationInjector", "query", "pagination", "SelectQueryParser", "SimpleSelectQuery", "offset", "limitClause", "LimitClause", "ParameterExpression", "offsetClause", "OffsetClause", "DynamicQueryBuilder", "tableColumnResolver", "sqlContent", "options", "parsedQuery", "SelectQueryParser", "error", "modifiedQuery", "paramInjector", "SqlParamInjector", "simpleQuery", "QueryBuilder", "sortInjector", "SqlSortInjector", "page", "pageSize", "paginationInjector", "SqlPaginationInjector", "paginationOptions", "jsonBuilder", "PostgresJsonQueryBuilder", "filter", "sort", "paging", "serialize", "SqlSchemaValidator", "sql", "tableResolver", "sqlComponent", "SelectQueryParser", "resolver", "tableName", "schema", "t", "tableSchemas", "SchemaCollector", "errors", "tableSchema", "resolvedColumns", "undefinedColumns", "column", "JsonSchemaValidator", "jsonMapping", "expectedStructure", "extractedStructure", "result", "errorMessage", "structure", "propertyName", "entity", "entityStructure", "propName", "childEntity", "extracted", "expected", "path", "errors", "missingProperties", "extraProperties", "nestedResult", "extractedObj", "expectedObj", "key", "currentPath", "extractedValue", "expectedValue", "sampleObject", "SchemaManager", "schemas", "tableNames", "errors", "tableName", "table", "_", "col", "name", "rel", "rootTableName", "rootTable", "rootColumns", "columnName", "column", "nestedEntities", "relatedTable", "relatedColumns", "relationshipType", "primaryKeyEntry", "foreignKeys", "createSchemaManager", "createTableColumnResolver", "createJsonMappingFromSchema"]
|
|
3
|
+
"sources": ["../src/index.ts", "../src/models/SqlComponent.ts", "../src/models/InsertQuery.ts", "../src/models/ValueComponent.ts", "../src/models/Clause.ts", "../src/models/Lexeme.ts", "../src/utils/charLookupTable.ts", "../src/utils/stringUtils.ts", "../src/tokenReaders/BaseTokenReader.ts", "../src/tokenReaders/IdentifierTokenReader.ts", "../src/parsers/KeywordParser.ts", "../src/models/KeywordTrie.ts", "../src/tokenReaders/LiteralTokenReader.ts", "../src/tokenReaders/ParameterTokenReader.ts", "../src/tokenReaders/SymbolTokenReader.ts", "../src/tokenReaders/TokenReaderManager.ts", "../src/tokenReaders/OperatorTokenReader.ts", "../src/tokenReaders/CommandTokenReader.ts", "../src/tokenReaders/StringSpecifierTokenReader.ts", "../src/tokenReaders/FunctionTokenReader.ts", "../src/tokenReaders/TypeTokenReader.ts", "../src/tokenReaders/EscapedIdentifierTokenReader.ts", "../src/parsers/SqlTokenizer.ts", "../src/parsers/FullNameParser.ts", "../src/parsers/IdentifierParser.ts", "../src/parsers/LiteralParser.ts", "../src/parsers/ParenExpressionParser.ts", "../src/parsers/UnaryExpressionParser.ts", "../src/parsers/ParameterExpressionParser.ts", "../src/parsers/StringSpecifierExpressionParser.ts", "../src/parsers/CommandExpressionParser.ts", "../src/parsers/OrderByClauseParser.ts", "../src/parsers/PartitionByParser.ts", "../src/parsers/WindowExpressionParser.ts", "../src/parsers/OverExpressionParser.ts", "../src/parsers/FunctionExpressionParser.ts", "../src/parsers/ParseError.ts", "../src/utils/OperatorPrecedence.ts", "../src/parsers/ValueParser.ts", "../src/transformers/CTECollector.ts", "../src/transformers/CTEDisabler.ts", "../src/transformers/TableSourceCollector.ts", "../src/models/SqlPrintToken.ts", "../src/transformers/ParameterCollector.ts", "../src/parsers/IdentifierDecorator.ts", "../src/parsers/ParameterDecorator.ts", "../src/models/UpdateQuery.ts", "../src/transformers/SelectValueCollector.ts", "../src/models/CreateTableQuery.ts", "../src/parsers/SqlPrintTokenParser.ts", "../src/transformers/LinePrinter.ts", "../src/transformers/SqlPrinter.ts", "../src/transformers/SqlFormatter.ts", "../src/transformers/Formatter.ts", "../src/transformers/CTEBuilder.ts", "../src/transformers/CTEInjector.ts", "../src/transformers/CTENormalizer.ts", "../src/transformers/SelectableColumnCollector.ts", "../src/parsers/SourceParser.ts", "../src/transformers/UpstreamSelectQueryFinder.ts", "../src/parsers/SourceAliasExpressionParser.ts", "../src/parsers/SourceExpressionParser.ts", "../src/transformers/QueryBuilder.ts", "../src/utils/ParameterHelper.ts", "../src/models/SimpleSelectQuery.ts", "../src/models/BinarySelectQuery.ts", "../src/models/ValuesQuery.ts", "../src/parsers/SelectClauseParser.ts", "../src/parsers/JoinOnClauseParser.ts", "../src/parsers/JoinUsingClauseParser.ts", "../src/parsers/JoinClauseParser.ts", "../src/parsers/FromClauseParser.ts", "../src/parsers/WhereClauseParser.ts", "../src/parsers/GroupByParser.ts", "../src/parsers/HavingParser.ts", "../src/parsers/WindowClauseParser.ts", "../src/parsers/LimitClauseParser.ts", "../src/parsers/ForClauseParser.ts", "../src/parsers/CommonTableParser.ts", "../src/parsers/WithClauseParser.ts", "../src/parsers/ValuesQueryParser.ts", "../src/parsers/FetchClauseParser.ts", "../src/parsers/OffsetClauseParser.ts", "../src/parsers/SelectQueryParser.ts", "../src/parsers/InsertQueryParser.ts", "../src/transformers/PostgresObjectEntityCteBuilder.ts", "../src/transformers/PostgresArrayEntityCteBuilder.ts", "../src/transformers/PostgresJsonQueryBuilder.ts", "../src/transformers/ModelDrivenJsonMapping.ts", "../src/transformers/EnhancedJsonMapping.ts", "../src/transformers/JsonMappingConverter.ts", "../src/transformers/JsonMappingUnifier.ts", "../src/transformers/TypeTransformationPostProcessor.ts", "../src/transformers/SchemaCollector.ts", "../src/transformers/SqlParamInjector.ts", "../src/transformers/SqlSortInjector.ts", "../src/transformers/SqlPaginationInjector.ts", "../src/transformers/DynamicQueryBuilder.ts", "../src/utils/SqlSchemaValidator.ts", "../src/utils/JsonSchemaValidator.ts", "../src/utils/SchemaManager.ts"],
|
|
4
|
+
"sourcesContent": ["// Entry point for rawsql-ts package\r\nexport * from './parsers/SelectQueryParser';\r\nexport * from './parsers/InsertQueryParser';\r\n\r\nexport * from './models/BinarySelectQuery';\r\nexport * from './models/SelectQuery';\r\nexport * from './models/ValueComponent';\r\nexport * from './models/ValuesQuery';\r\n\r\nexport * from './transformers/CTECollector';\r\nexport * from './transformers/CTENormalizer';\r\nexport * from './transformers/Formatter';\r\nexport * from './transformers/SqlFormatter';\r\nexport * from './transformers/PostgresJsonQueryBuilder';\r\nexport * from './transformers/QueryBuilder'; // old name:QueryConverter\r\nexport * from './transformers/SelectValueCollector';\r\nexport * from './transformers/SelectableColumnCollector';\r\nexport * from './transformers/TableColumnResolver';\r\nexport * from './transformers/TableSourceCollector';\r\nexport * from './transformers/JsonMappingConverter';\r\nexport * from './transformers/EnhancedJsonMapping';\r\nexport {\r\n ModelDrivenJsonMapping,\r\n convertModelDrivenMapping,\r\n validateModelDrivenMapping,\r\n FieldMapping,\r\n NestedStructure,\r\n StructureFields,\r\n FieldType\r\n} from './transformers/ModelDrivenJsonMapping';\r\nexport {\r\n /** @deprecated Use JsonMappingConverter.convert() instead */\r\n processJsonMapping,\r\n isModelDrivenFormat,\r\n isUnifiedFormat,\r\n isLegacyFormat\r\n} from './transformers/JsonMappingUnifier';\r\n\r\n/** @deprecated Use JsonMappingConverter.toLegacyMapping() instead */\r\nexport { unifyJsonMapping } from './transformers/JsonMappingUnifier';\r\nexport * from './transformers/UpstreamSelectQueryFinder';\r\nexport * from './transformers/TypeTransformationPostProcessor';\r\n\r\nexport * from './transformers/SchemaCollector';\r\nexport * from './transformers/SqlParamInjector';\r\nexport * from './transformers/SqlSortInjector';\r\nexport * from './transformers/SqlPaginationInjector';\r\nexport * from './transformers/DynamicQueryBuilder';\r\n\r\nexport * from './utils/SqlSchemaValidator';\r\nexport * from './utils/JsonSchemaValidator';\r\nexport * from './utils/SchemaManager';\r\n// Add more exports here if you want to expose additional public API\r\n", "\uFEFFexport abstract class SqlComponent {\r\n // `kind` is declared abstractly and defined concretely in a subclass.\r\n static kind: symbol;\r\n\r\n getKind(): symbol {\r\n return (this.constructor as typeof SqlComponent).kind;\r\n }\r\n\r\n accept<T>(visitor: SqlComponentVisitor<T>): T {\r\n return visitor.visit(this);\r\n }\r\n\r\n toSqlString(formatter: SqlComponentVisitor<string>): string {\r\n return this.accept(formatter);\r\n }\r\n\r\n comments: string[] | null = null;\r\n}\r\n\r\nexport interface SqlComponentVisitor<T> {\r\n visit(expr: SqlComponent): T;\r\n}\r\n\r\nexport class SqlDialectConfiguration {\r\n public parameterSymbol: string = \":\";\r\n public identifierEscape = { start: '\"', end: '\"' };\r\n public exportComment: boolean = true;\r\n}\r\n", "// Represents an INSERT query in SQL.\r\n// Supports single/multi-row VALUES and INSERT ... SELECT.\r\nimport { SqlComponent } from \"./SqlComponent\";\r\nimport { SelectQuery } from \"./SelectQuery\";\r\nimport { InsertClause } from \"./Clause\";\r\n\r\nexport class InsertQuery extends SqlComponent {\r\n static kind = Symbol(\"InsertQuery\");\r\n insertClause: InsertClause;\r\n selectQuery: SelectQuery | null;\r\n\r\n /**\r\n * @param params.insertClause InsertClause instance (target table and columns)\r\n * @param params.selectQuery SELECT/VALUES query (required)\r\n */\r\n constructor(params: {\r\n insertClause: InsertClause;\r\n selectQuery?: SelectQuery | null;\r\n }) {\r\n super();\r\n this.insertClause = params.insertClause;\r\n this.selectQuery = params.selectQuery ?? null;\r\n }\r\n}", "import { PartitionByClause, OrderByClause } from \"./Clause\";\r\nimport { SelectQuery, SimpleSelectQuery } from \"./SelectQuery\";\r\nimport { SqlComponent } from \"./SqlComponent\";\r\n\r\nexport type ValueComponent = ValueList |\r\n ColumnReference |\r\n FunctionCall |\r\n UnaryExpression |\r\n BinaryExpression |\r\n LiteralValue |\r\n ParameterExpression |\r\n SwitchCaseArgument |\r\n CaseKeyValuePair |\r\n RawString |\r\n IdentifierString |\r\n ParenExpression |\r\n CastExpression |\r\n CaseExpression |\r\n ArrayExpression |\r\n ArrayQueryExpression |\r\n BetweenExpression |\r\n InlineQuery |\r\n StringSpecifierExpression |\r\n TypeValue |\r\n TupleExpression;\r\n\r\nexport class InlineQuery extends SqlComponent {\r\n static kind = Symbol(\"InlineQuery\");\r\n selectQuery: SelectQuery;\r\n constructor(selectQuery: SelectQuery) {\r\n super();\r\n this.selectQuery = selectQuery;\r\n }\r\n}\r\n\r\nexport class ValueList extends SqlComponent {\r\n static kind = Symbol(\"ValueList\");\r\n values: ValueComponent[];\r\n constructor(values: ValueComponent[]) {\r\n super();\r\n this.values = values;\r\n }\r\n}\r\n\r\nexport class ColumnReference extends SqlComponent {\r\n /**\r\n * For backward compatibility: returns the namespaces as IdentifierString[] | null (readonly)\r\n */\r\n get namespaces(): IdentifierString[] | null {\r\n return this.qualifiedName.namespaces;\r\n }\r\n /**\r\n * For backward compatibility: returns the column name as IdentifierString (readonly)\r\n */\r\n get column(): IdentifierString {\r\n // If the name is RawString, convert to IdentifierString for compatibility\r\n if (this.qualifiedName.name instanceof IdentifierString) {\r\n return this.qualifiedName.name;\r\n } else {\r\n return new IdentifierString(this.qualifiedName.name.value);\r\n }\r\n }\r\n static kind = Symbol(\"ColumnReference\");\r\n qualifiedName: QualifiedName; constructor(namespaces: string | string[] | IdentifierString[] | null, column: string | IdentifierString) {\r\n super();\r\n const col = typeof column === \"string\" ? new IdentifierString(column) : column;\r\n this.qualifiedName = new QualifiedName(toIdentifierStringArray(namespaces), col);\r\n }\r\n\r\n public toString(): string {\r\n return this.qualifiedName.toString();\r\n }\r\n public getNamespace(): string {\r\n if (this.qualifiedName.namespaces) {\r\n return this.qualifiedName.namespaces.map((namespace) => namespace.name).join(\".\");\r\n } else {\r\n return '';\r\n }\r\n }\r\n}\r\n\r\nexport class FunctionCall extends SqlComponent {\r\n static kind = Symbol(\"FunctionCall\");\r\n qualifiedName: QualifiedName;\r\n argument: ValueComponent | null;\r\n over: OverExpression | null; constructor(\r\n namespaces: string | string[] | IdentifierString[] | null,\r\n name: string | RawString | IdentifierString,\r\n argument: ValueComponent | null,\r\n over: OverExpression | null\r\n ) {\r\n super();\r\n this.qualifiedName = new QualifiedName(namespaces, name);\r\n this.argument = argument;\r\n this.over = over;\r\n }\r\n\r\n /**\r\n * For backward compatibility: returns the namespaces as IdentifierString[] | null (readonly)\r\n */\r\n get namespaces(): IdentifierString[] | null {\r\n return this.qualifiedName.namespaces;\r\n }\r\n /**\r\n * For backward compatibility: returns the function name as RawString | IdentifierString (readonly)\r\n */\r\n get name(): RawString | IdentifierString {\r\n return this.qualifiedName.name;\r\n }\r\n}\r\n\r\nexport type OverExpression = WindowFrameExpression | IdentifierString;\r\n\r\nexport enum WindowFrameType {\r\n Rows = \"rows\",\r\n Range = \"range\",\r\n Groups = \"groups\",\r\n}\r\n\r\nexport enum WindowFrameBound {\r\n UnboundedPreceding = \"unbounded preceding\",\r\n UnboundedFollowing = \"unbounded following\",\r\n CurrentRow = \"current row\",\r\n}\r\n\r\nexport type FrameBoundaryComponent = WindowFrameBoundStatic | WindowFrameBoundaryValue;\r\n\r\nexport class WindowFrameBoundStatic extends SqlComponent {\r\n static kind = Symbol(\"WindowFrameStaticBound\");\r\n bound: WindowFrameBound;\r\n constructor(bound: WindowFrameBound) {\r\n super();\r\n this.bound = bound;\r\n }\r\n}\r\n\r\nexport class WindowFrameBoundaryValue extends SqlComponent {\r\n static kind = Symbol(\"WindowFrameBoundary\");\r\n value: ValueComponent;\r\n isFollowing: boolean; // true for \"FOLLOWING\", false for \"PRECEDING\"\r\n constructor(value: ValueComponent, isFollowing: boolean) {\r\n super();\r\n this.value = value;\r\n this.isFollowing = isFollowing;\r\n }\r\n}\r\n\r\nexport class WindowFrameSpec extends SqlComponent {\r\n static kind = Symbol(\"WindowFrameSpec\");\r\n frameType: WindowFrameType;\r\n startBound: FrameBoundaryComponent;\r\n endBound: FrameBoundaryComponent | null; // null for single boundary specification\r\n constructor(frameType: WindowFrameType, startBound: FrameBoundaryComponent, endBound: FrameBoundaryComponent | null) {\r\n super();\r\n this.frameType = frameType;\r\n this.startBound = startBound;\r\n this.endBound = endBound;\r\n }\r\n}\r\n\r\nexport class WindowFrameExpression extends SqlComponent {\r\n static kind = Symbol(\"WindowFrameExpression\");\r\n partition: PartitionByClause | null;\r\n order: OrderByClause | null;\r\n frameSpec: WindowFrameSpec | null;\r\n constructor(partition: PartitionByClause | null, order: OrderByClause | null, frameSpec: WindowFrameSpec | null = null) {\r\n super();\r\n this.partition = partition;\r\n this.order = order;\r\n this.frameSpec = frameSpec;\r\n }\r\n}\r\n\r\nexport class UnaryExpression extends SqlComponent {\r\n static kind = Symbol(\"UnaryExpression\");\r\n operator: RawString;\r\n expression: ValueComponent;\r\n constructor(operator: string, expression: ValueComponent) {\r\n super();\r\n this.operator = new RawString(operator);\r\n this.expression = expression;\r\n }\r\n}\r\n\r\nexport class BinaryExpression extends SqlComponent {\r\n static kind = Symbol(\"BinaryExpression\");\r\n left: ValueComponent;\r\n operator: RawString;\r\n right: ValueComponent;\r\n constructor(left: ValueComponent, operator: string, right: ValueComponent) {\r\n super();\r\n this.left = left;\r\n this.operator = new RawString(operator);\r\n this.right = right;\r\n }\r\n}\r\n\r\nexport class LiteralValue extends SqlComponent {\r\n static kind = Symbol(\"LiteralExpression\");\r\n // Use the string type instead of the RawString type because it has its own escaping process.\r\n value: string | number | boolean | null;\r\n constructor(value: string | number | boolean | null) {\r\n super();\r\n this.value = value;\r\n }\r\n}\r\n\r\nexport class ParameterExpression extends SqlComponent {\r\n static kind = Symbol(\"ParameterExpression\");\r\n name: RawString;\r\n value: any | null; // Holds the parameter value; can be provided via second argument.\r\n /**\r\n * The index assigned by the formatter when generating parameterized queries.\r\n * Used for naming parameters like $1, $2, etc.\r\n */\r\n index: number | null;\r\n constructor(name: string, value: any | null = null) {\r\n super();\r\n this.name = new RawString(name);\r\n this.value = value; // Value is now accepted as a second argument (optional)\r\n this.index = null;\r\n }\r\n}\r\n\r\nexport class SwitchCaseArgument extends SqlComponent {\r\n static kind = Symbol(\"SwitchCaseArgument\");\r\n cases: CaseKeyValuePair[];\r\n elseValue: ValueComponent | null;\r\n constructor(cases: CaseKeyValuePair[], elseValue: ValueComponent | null = null) {\r\n super();\r\n this.cases = cases;\r\n this.elseValue = elseValue;\r\n }\r\n}\r\n\r\nexport class CaseKeyValuePair extends SqlComponent {\r\n static kind = Symbol(\"CaseKeyValuePair\");\r\n key: ValueComponent;\r\n value: ValueComponent;\r\n constructor(key: ValueComponent, value: ValueComponent) {\r\n super();\r\n this.key = key;\r\n this.value = value;\r\n }\r\n}\r\n\r\n/*\r\n * Values \u200B\u200Bthat must be hard-coded, such as type names and function names.\r\n * A simple check is performed when decoding.\r\n */\r\nexport class RawString extends SqlComponent {\r\n static kind = Symbol(\"RawString\");\r\n value: string;\r\n constructor(value: string) {\r\n super();\r\n this.value = value;\r\n }\r\n}\r\n\r\nexport class IdentifierString extends SqlComponent {\r\n static kind = Symbol(\"IdentifierString\");\r\n name: string;\r\n constructor(alias: string) {\r\n super();\r\n this.name = alias;\r\n }\r\n}\r\n\r\nexport class ParenExpression extends SqlComponent {\r\n static kind = Symbol(\"ParenExpression\");\r\n expression: ValueComponent;\r\n constructor(expression: ValueComponent) {\r\n super();\r\n this.expression = expression;\r\n }\r\n}\r\n\r\nexport class CastExpression extends SqlComponent {\r\n static kind = Symbol(\"CastExpression\");\r\n input: ValueComponent;\r\n castType: TypeValue;\r\n constructor(input: ValueComponent, castType: TypeValue) {\r\n super();\r\n this.input = input;\r\n this.castType = castType;\r\n }\r\n}\r\n\r\nexport class CaseExpression extends SqlComponent {\r\n static kind = Symbol(\"CaseExpression\");\r\n condition: ValueComponent | null;\r\n switchCase: SwitchCaseArgument;\r\n\r\n constructor(condition: ValueComponent | null, switchCase: SwitchCaseArgument) {\r\n super();\r\n this.condition = condition;\r\n this.switchCase = switchCase;\r\n }\r\n}\r\n\r\nexport class ArrayExpression extends SqlComponent {\r\n static kind = Symbol(\"ArrayExpression\");\r\n expression: ValueComponent;\r\n constructor(expression: ValueComponent) {\r\n super();\r\n this.expression = expression;\r\n }\r\n}\r\n\r\nexport class ArrayQueryExpression extends SqlComponent {\r\n static kind = Symbol(\"ArrayQueryExpression\");\r\n query: SelectQuery;\r\n constructor(query: SelectQuery) {\r\n super();\r\n this.query = query;\r\n }\r\n}\r\n\r\nexport class BetweenExpression extends SqlComponent {\r\n static kind = Symbol(\"BetweenExpression\");\r\n expression: ValueComponent;\r\n lower: ValueComponent;\r\n upper: ValueComponent;\r\n negated: boolean;\r\n constructor(expression: ValueComponent, lower: ValueComponent, upper: ValueComponent, negated: boolean) {\r\n super();\r\n this.expression = expression;\r\n this.lower = lower;\r\n this.upper = upper;\r\n this.negated = negated;\r\n }\r\n}\r\n\r\nexport class StringSpecifierExpression extends SqlComponent {\r\n static kind = Symbol(\"StringSpecifierExpression\");\r\n // e.g. 'E', 'X', 'U&'\r\n specifier: RawString;\r\n value: LiteralValue;\r\n constructor(specifier: string, value: string) {\r\n super();\r\n this.specifier = new RawString(specifier);\r\n this.value = new LiteralValue(value);\r\n }\r\n}\r\n\r\n// other\r\n\r\nexport class TypeValue extends SqlComponent {\r\n static kind = Symbol(\"TypeValue\");\r\n qualifiedName: QualifiedName;\r\n argument: ValueComponent | null;\r\n constructor(namespaces: string[] | IdentifierString[] | null, name: string | RawString | IdentifierString, argument: ValueComponent | null = null) {\r\n super();\r\n this.qualifiedName = new QualifiedName(namespaces, name);\r\n this.argument = argument;\r\n }\r\n /**\r\n * For backward compatibility: returns the namespaces as IdentifierString[] | null (readonly)\r\n */\r\n get namespaces(): IdentifierString[] | null {\r\n return this.qualifiedName.namespaces;\r\n }\r\n /**\r\n * For backward compatibility: returns the type name as RawString | IdentifierString (readonly)\r\n */\r\n get name(): RawString | IdentifierString {\r\n return this.qualifiedName.name;\r\n }\r\n public getTypeName(): string {\r\n const nameValue = this.qualifiedName.name instanceof RawString ? this.qualifiedName.name.value : this.qualifiedName.name.name;\r\n if (this.qualifiedName.namespaces && this.qualifiedName.namespaces.length > 0) {\r\n return this.qualifiedName.namespaces.map(ns => ns.name).join(\".\") + \".\" + nameValue;\r\n } else {\r\n return nameValue;\r\n }\r\n }\r\n}\r\n\r\nexport class TupleExpression extends SqlComponent {\r\n static kind = Symbol(\"TupleExpression\");\r\n values: ValueComponent[];\r\n constructor(values: ValueComponent[]) {\r\n super();\r\n this.values = values;\r\n }\r\n}\r\n\r\nfunction toIdentifierStringArray(input: string | string[] | IdentifierString[] | null): IdentifierString[] | null {\r\n if (input == null) return null;\r\n\r\n if (typeof input === \"string\") {\r\n // Empty string should be treated as null\r\n return input.trim() === \"\" ? null : [new IdentifierString(input)];\r\n }\r\n\r\n if (Array.isArray(input)) {\r\n if (input.length === 0) return null;\r\n\r\n if (typeof input[0] === \"string\") {\r\n // Filter out empty strings from string array\r\n const filteredStrings = (input as string[]).filter(ns => ns.trim() !== \"\");\r\n return filteredStrings.length === 0 ? null : filteredStrings.map(ns => new IdentifierString(ns));\r\n } else {\r\n // Filter out empty IdentifierStrings from IdentifierString array\r\n const filteredIdentifiers = (input as IdentifierString[]).filter(ns => ns.name.trim() !== \"\");\r\n return filteredIdentifiers.length === 0 ? null : filteredIdentifiers;\r\n }\r\n }\r\n\r\n return null;\r\n}\r\n\r\n/**\r\n * Represents a qualified name with optional namespaces (e.g. schema.table, db.schema.function)\r\n */\r\nexport class QualifiedName extends SqlComponent {\r\n static kind = Symbol(\"QualifiedName\");\r\n\r\n /** List of namespaces (e.g. schema, database) */\r\n namespaces: IdentifierString[] | null;\r\n /** The actual name (e.g. table, function, type, column) */\r\n name: RawString | IdentifierString;\r\n\r\n constructor(namespaces: string | string[] | IdentifierString[] | null, name: string | RawString | IdentifierString) {\r\n super();\r\n this.namespaces = toIdentifierStringArray(namespaces);\r\n if (typeof name === \"string\") {\r\n this.name = new RawString(name);\r\n } else {\r\n this.name = name;\r\n }\r\n }\r\n\r\n /** Returns the full qualified name as a string (dot-separated) */\r\n toString(): string {\r\n const nameValue = this.name instanceof RawString ? this.name.value : this.name.name;\r\n if (this.namespaces && this.namespaces.length > 0) {\r\n return this.namespaces.map(ns => ns.name).join(\".\") + \".\" + nameValue;\r\n } else {\r\n return nameValue;\r\n }\r\n }\r\n}", "import { SelectQuery, SimpleSelectQuery } from \"./SelectQuery\";\r\nimport { SqlComponent } from \"./SqlComponent\";\r\nimport { IdentifierString, RawString, TupleExpression, ValueComponent, WindowFrameExpression, QualifiedName } from \"./ValueComponent\";\r\n\r\nexport class SelectItem extends SqlComponent {\r\n static kind = Symbol(\"SelectItem\");\r\n value: ValueComponent;\r\n identifier: IdentifierString | null;\r\n constructor(value: ValueComponent, name: string | null = null) {\r\n super();\r\n this.value = value;\r\n this.identifier = name ? new IdentifierString(name) : null;\r\n }\r\n}\r\n\r\nexport class SelectClause extends SqlComponent {\r\n static kind = Symbol(\"SelectClause\");\r\n items: SelectItem[];\r\n distinct: DistinctComponent | null;\r\n constructor(items: SelectItem[], distinct: DistinctComponent | null = null) {\r\n super();\r\n this.items = items;\r\n this.distinct = distinct;\r\n }\r\n}\r\n\r\nexport type DistinctComponent = Distinct | DistinctOn;\r\n\r\nexport class Distinct extends SqlComponent {\r\n static kind = Symbol(\"Distinct\");\r\n constructor() {\r\n super();\r\n }\r\n}\r\n\r\nexport class DistinctOn extends SqlComponent {\r\n static kind = Symbol(\"DistinctOn\");\r\n value: ValueComponent;\r\n constructor(value: ValueComponent) {\r\n super();\r\n this.value = value;\r\n }\r\n}\r\n\r\n\r\nexport class WhereClause extends SqlComponent {\r\n static kind = Symbol(\"WhereClause\");\r\n condition: ValueComponent;\r\n constructor(condition: ValueComponent) {\r\n super();\r\n this.condition = condition;\r\n }\r\n}\r\n\r\nexport class PartitionByClause extends SqlComponent {\r\n static kind = Symbol(\"PartitionByClause\");\r\n value: ValueComponent;\r\n constructor(value: ValueComponent) {\r\n super();\r\n this.value = value;\r\n }\r\n}\r\n\r\nexport class WindowFrameClause extends SqlComponent {\r\n static kind = Symbol(\"WindowFrameClause\");\r\n name: IdentifierString;\r\n expression: WindowFrameExpression;\r\n constructor(name: string, expression: WindowFrameExpression) {\r\n super();\r\n this.name = new IdentifierString(name);\r\n this.expression = expression;\r\n }\r\n}\r\n\r\n/**\r\n * Represents a collection of window definitions (WINDOW clause in SQL).\r\n * @param windows Array of WindowFrameClause\r\n */\r\nexport class WindowsClause extends SqlComponent {\r\n static kind = Symbol(\"WindowsClause\");\r\n windows: WindowFrameClause[];\r\n constructor(windows: WindowFrameClause[]) {\r\n super();\r\n this.windows = windows;\r\n }\r\n}\r\n\r\nexport enum SortDirection {\r\n Ascending = \"asc\",\r\n Descending = \"desc\",\r\n}\r\nexport enum NullsSortDirection {\r\n First = \"first\",\r\n Last = \"last\",\r\n}\r\n\r\nexport type OrderByComponent = OrderByItem | ValueComponent;\r\n\r\nexport class OrderByClause extends SqlComponent {\r\n static kind = Symbol(\"OrderByClause\");\r\n order: OrderByComponent[];\r\n constructor(items: OrderByComponent[]) {\r\n super();\r\n this.order = items;\r\n }\r\n}\r\n\r\nexport class OrderByItem extends SqlComponent {\r\n static kind = Symbol(\"OrderByItem\");\r\n value: ValueComponent;\r\n sortDirection: SortDirection;\r\n nullsPosition: NullsSortDirection | null;\r\n constructor(expression: ValueComponent, sortDirection: SortDirection | null, nullsPosition: NullsSortDirection | null) {\r\n super();\r\n this.value = expression;\r\n this.sortDirection = sortDirection === null ? SortDirection.Ascending : sortDirection;\r\n this.nullsPosition = nullsPosition;\r\n }\r\n}\r\n\r\nexport class GroupByClause extends SqlComponent {\r\n static kind = Symbol(\"GroupByClause\");\r\n grouping: ValueComponent[];\r\n constructor(expression: ValueComponent[]) {\r\n super();\r\n this.grouping = expression;\r\n }\r\n}\r\n\r\nexport class HavingClause extends SqlComponent {\r\n static kind = Symbol(\"HavingClause\");\r\n condition: ValueComponent;\r\n constructor(condition: ValueComponent) {\r\n super();\r\n this.condition = condition;\r\n }\r\n}\r\n\r\nexport type SourceComponent = TableSource |\r\n FunctionSource |\r\n SubQuerySource |\r\n ParenSource;\r\n\r\nexport class TableSource extends SqlComponent {\r\n static kind = Symbol(\"TableSource\");\r\n qualifiedName: QualifiedName;\r\n /**\r\n * For backward compatibility: returns the namespaces as IdentifierString[] | null (readonly)\r\n */\r\n get namespaces(): IdentifierString[] | null {\r\n return this.qualifiedName.namespaces;\r\n }\r\n /**\r\n * For backward compatibility: returns the table name as IdentifierString (readonly)\r\n */\r\n get table(): IdentifierString {\r\n // If the name is RawString, convert to IdentifierString for compatibility\r\n if (this.qualifiedName.name instanceof IdentifierString) {\r\n return this.qualifiedName.name;\r\n } else {\r\n return new IdentifierString(this.qualifiedName.name.value);\r\n }\r\n }\r\n /**\r\n * For backward compatibility: returns the table name as IdentifierString (readonly)\r\n */\r\n get identifier(): IdentifierString {\r\n return this.table;\r\n }\r\n constructor(namespaces: string[] | IdentifierString[] | null, table: string | IdentifierString) {\r\n super();\r\n // Convert the table name to an IdentifierString if it is provided as a string.\r\n const tbl = typeof table === \"string\" ? new IdentifierString(table) : table;\r\n // Wrap the namespaces and table name in a QualifiedName object.\r\n // This design choice ensures backward compatibility by allowing the namespaces\r\n // and table name to be accessed in a way consistent with the previous implementation.\r\n this.qualifiedName = new QualifiedName(namespaces, tbl);\r\n }\r\n public getSourceName(): string {\r\n if (this.qualifiedName.namespaces && this.qualifiedName.namespaces.length > 0) {\r\n return this.qualifiedName.namespaces.map((namespace) => namespace.name).join(\".\") + \".\" + (this.qualifiedName.name instanceof RawString ? this.qualifiedName.name.value : this.qualifiedName.name.name);\r\n } else {\r\n return this.qualifiedName.name instanceof RawString ? this.qualifiedName.name.value : this.qualifiedName.name.name;\r\n }\r\n }\r\n}\r\n\r\nexport class FunctionSource extends SqlComponent {\r\n static kind = Symbol(\"FunctionSource\");\r\n qualifiedName: QualifiedName;\r\n argument: ValueComponent | null;\r\n constructor(\r\n name: string | IdentifierString | { namespaces: string[] | IdentifierString[] | null, name: string | RawString | IdentifierString },\r\n argument: ValueComponent | null\r\n ) {\r\n super();\r\n if (typeof name === \"object\" && name !== null && \"name\" in name) {\r\n // Accepts { namespaces, name }\r\n const nameObj = name as { namespaces: string[] | IdentifierString[] | null, name: string | RawString | IdentifierString };\r\n this.qualifiedName = new QualifiedName(nameObj.namespaces, nameObj.name);\r\n } else {\r\n this.qualifiedName = new QualifiedName(null, name as string | RawString | IdentifierString);\r\n }\r\n this.argument = argument;\r\n }\r\n\r\n /**\r\n * For backward compatibility: returns the namespaces as IdentifierString[] | null (readonly)\r\n */\r\n get namespaces(): IdentifierString[] | null {\r\n return this.qualifiedName.namespaces;\r\n }\r\n /**\r\n * For backward compatibility: returns the function name as RawString | IdentifierString (readonly)\r\n */\r\n get name(): RawString | IdentifierString {\r\n return this.qualifiedName.name;\r\n }\r\n}\r\n\r\nexport class ParenSource extends SqlComponent {\r\n static kind = Symbol(\"ParenSource\");\r\n source: SourceComponent;\r\n constructor(source: SourceComponent) {\r\n super();\r\n this.source = source;\r\n }\r\n}\r\n\r\nexport class SubQuerySource extends SqlComponent {\r\n static kind = Symbol(\"SubQuerySource\");\r\n query: SelectQuery;\r\n constructor(query: SelectQuery) {\r\n super();\r\n this.query = query;\r\n }\r\n}\r\n\r\nexport class SourceExpression extends SqlComponent {\r\n static kind = Symbol(\"SourceExpression\");\r\n datasource: SourceComponent;\r\n aliasExpression: SourceAliasExpression | null;\r\n constructor(datasource: SourceComponent, aliasExpression: SourceAliasExpression | null) {\r\n super();\r\n this.datasource = datasource;\r\n this.aliasExpression = aliasExpression;\r\n }\r\n public getAliasName(): string | null {\r\n if (this.aliasExpression) {\r\n return this.aliasExpression.table.name;\r\n }\r\n else if (this.datasource instanceof TableSource) {\r\n return this.datasource.getSourceName();\r\n }\r\n return null;\r\n }\r\n}\r\n\r\nexport type JoinConditionComponent = JoinOnClause | JoinUsingClause;\r\n\r\nexport class JoinOnClause extends SqlComponent {\r\n static kind = Symbol(\"JoinOnClause\");\r\n condition: ValueComponent;\r\n constructor(condition: ValueComponent) {\r\n super();\r\n this.condition = condition;\r\n }\r\n}\r\n\r\nexport class JoinUsingClause extends SqlComponent {\r\n static kind = Symbol(\"JoinUsingClause\");\r\n condition: ValueComponent;\r\n constructor(condition: ValueComponent) {\r\n super();\r\n this.condition = condition;\r\n }\r\n}\r\n\r\nexport class JoinClause extends SqlComponent {\r\n static kind = Symbol(\"JoinItem\");\r\n joinType: RawString;\r\n source: SourceExpression;\r\n condition: JoinConditionComponent | null;\r\n lateral: boolean;\r\n constructor(joinType: string, source: SourceExpression, condition: JoinConditionComponent | null, lateral: boolean) {\r\n super();\r\n this.joinType = new RawString(joinType);\r\n this.source = source;\r\n this.condition = condition;\r\n this.lateral = lateral;\r\n }\r\n public getSourceAliasName(): string | null {\r\n if (this.source.aliasExpression) {\r\n return this.source.aliasExpression.table.name;\r\n }\r\n else if (this.source instanceof TableSource) {\r\n return this.source.table.name;\r\n }\r\n return null;\r\n }\r\n}\r\n\r\nexport class FromClause extends SqlComponent {\r\n static kind = Symbol(\"FromClause\");\r\n source: SourceExpression;\r\n joins: JoinClause[] | null;\r\n constructor(source: SourceExpression, join: JoinClause[] | null) {\r\n super();\r\n this.source = source;\r\n this.joins = join;\r\n }\r\n public getSourceAliasName(): string | null {\r\n if (this.source.aliasExpression) {\r\n return this.source.aliasExpression.table.name;\r\n }\r\n else if (this.source.datasource instanceof TableSource) {\r\n return this.source.datasource.table.name;\r\n }\r\n return null;\r\n }\r\n /**\r\n * Returns all SourceExpression objects in this FROM clause, including main source and all JOIN sources.\r\n */\r\n public getSources(): SourceExpression[] {\r\n const sources: SourceExpression[] = [this.source];\r\n if (this.joins) {\r\n for (const join of this.joins) {\r\n sources.push(join.source);\r\n }\r\n }\r\n return sources;\r\n }\r\n}\r\n\r\nexport class CommonTable extends SqlComponent {\r\n static kind = Symbol(\"CommonTable\");\r\n query: SelectQuery;\r\n materialized: boolean | null;\r\n aliasExpression: SourceAliasExpression;\r\n constructor(query: SelectQuery, aliasExpression: SourceAliasExpression | string, materialized: boolean | null) {\r\n super();\r\n this.query = query;\r\n this.materialized = materialized;\r\n if (typeof aliasExpression === \"string\") {\r\n this.aliasExpression = new SourceAliasExpression(aliasExpression, null);\r\n } else {\r\n this.aliasExpression = aliasExpression;\r\n }\r\n }\r\n public getSourceAliasName(): string {\r\n return this.aliasExpression.table.name;\r\n }\r\n}\r\n\r\nexport class WithClause extends SqlComponent {\r\n static kind = Symbol(\"WithClause\");\r\n recursive: boolean;\r\n tables: CommonTable[];\r\n constructor(recursive: boolean, tables: CommonTable[]) {\r\n super();\r\n this.recursive = recursive;\r\n this.tables = tables;\r\n }\r\n}\r\n\r\nexport class LimitClause extends SqlComponent {\r\n static kind = Symbol(\"LimitClause\");\r\n value: ValueComponent;\r\n constructor(limit: ValueComponent) {\r\n super();\r\n this.value = limit;\r\n }\r\n}\r\n\r\nexport enum FetchType {\r\n Next = \"next\",\r\n First = \"first\",\r\n}\r\n\r\nexport enum FetchUnit {\r\n RowsOnly = \"rows only\",\r\n Percent = \"percent\",\r\n PercentWithTies = \"percent with ties\",\r\n}\r\n\r\n\r\nexport class OffsetClause extends SqlComponent {\r\n static kind = Symbol(\"OffsetClause\");\r\n value: ValueComponent;\r\n constructor(value: ValueComponent) {\r\n super();\r\n this.value = value;\r\n }\r\n}\r\n\r\nexport class FetchClause extends SqlComponent {\r\n static kind = Symbol(\"FetchClause\");\r\n expression: FetchExpression;\r\n constructor(expression: FetchExpression) {\r\n super();\r\n this.expression = expression;\r\n }\r\n}\r\n\r\nexport class FetchExpression extends SqlComponent {\r\n static kind = Symbol(\"FetchExpression\");\r\n // type count unit\r\n type: FetchType;\r\n count: ValueComponent;\r\n unit: FetchUnit | null;\r\n constructor(type: FetchType, count: ValueComponent, unit: FetchUnit | null) {\r\n super();\r\n this.type = type;\r\n this.count = count;\r\n this.unit = unit;\r\n }\r\n}\r\n\r\nexport enum LockMode {\r\n Update = \"update\",\r\n Share = \"share\",\r\n KeyShare = \"key share\",\r\n NokeyUpdate = \"no key update\",\r\n}\r\n\r\nexport class ForClause extends SqlComponent {\r\n static kind = Symbol(\"ForClause\");\r\n lockMode: LockMode;\r\n constructor(lockMode: LockMode) {\r\n super();\r\n this.lockMode = lockMode;\r\n }\r\n}\r\n\r\nexport class SourceAliasExpression extends SqlComponent {\r\n static kind = Symbol(\"SourceAliasExpression\");\r\n table: IdentifierString;\r\n columns: IdentifierString[] | null;\r\n constructor(alias: string, columnAlias: string[] | null) {\r\n super();\r\n this.table = new IdentifierString(alias);\r\n this.columns = columnAlias !== null ? columnAlias.map((alias) => new IdentifierString(alias)) : null;\r\n }\r\n}\r\n\r\nexport class ReturningClause extends SqlComponent {\r\n static kind = Symbol(\"ReturningClause\");\r\n columns: IdentifierString[];\r\n /**\r\n * Constructs a ReturningClause.\r\n * @param columns Array of IdentifierString or string representing column names.\r\n */\r\n constructor(columns: (IdentifierString | string)[]) {\r\n super();\r\n this.columns = columns.map(col => typeof col === \"string\" ? new IdentifierString(col) : col);\r\n }\r\n}\r\n\r\nexport class SetClause extends SqlComponent {\r\n static kind = Symbol(\"SetClause\");\r\n items: SetClauseItem[];\r\n constructor(items: (SetClauseItem | { column: string | IdentifierString, value: ValueComponent })[]) {\r\n super();\r\n this.items = items.map(item => item instanceof SetClauseItem ? item : new SetClauseItem(item.column, item.value));\r\n }\r\n}\r\n\r\n/**\r\n * Represents a single SET clause item in an UPDATE statement.\r\n */\r\n/**\r\n * Represents a single SET clause item in an UPDATE statement.\r\n * Now supports namespaces for fully qualified column names (e.g. schema.table.column).\r\n */\r\n/**\r\n * Represents a single SET clause item in an UPDATE statement.\r\n * Now supports namespaces for fully qualified column names (e.g. schema.table.column).\r\n * Refactored to use QualifiedName for unified name/namespace handling.\r\n */\r\nexport class SetClauseItem extends SqlComponent {\r\n static kind = Symbol(\"SetClauseItem\");\r\n qualifiedName: QualifiedName;\r\n value: ValueComponent;\r\n constructor(\r\n column: string | IdentifierString | { namespaces: string[] | IdentifierString[] | null, column: string | IdentifierString },\r\n value: ValueComponent\r\n ) {\r\n super();\r\n // Accepts { namespaces, column } or just column\r\n if (typeof column === \"object\" && column !== null && \"column\" in column) {\r\n const colObj = column as { namespaces: string[] | IdentifierString[] | null, column: string | IdentifierString };\r\n const col = typeof colObj.column === \"string\" ? new IdentifierString(colObj.column) : colObj.column;\r\n this.qualifiedName = new QualifiedName(colObj.namespaces, col);\r\n } else {\r\n const col = typeof column === \"string\" ? new IdentifierString(column) : column as IdentifierString;\r\n this.qualifiedName = new QualifiedName(null, col);\r\n }\r\n this.value = value;\r\n }\r\n /**\r\n * For backward compatibility: returns the namespaces as IdentifierString[] | null (readonly)\r\n */\r\n get namespaces(): IdentifierString[] | null {\r\n return this.qualifiedName.namespaces;\r\n }\r\n /**\r\n * For backward compatibility: returns the column name as IdentifierString (readonly)\r\n */\r\n get column(): IdentifierString {\r\n if (this.qualifiedName.name instanceof IdentifierString) {\r\n return this.qualifiedName.name;\r\n } else {\r\n return new IdentifierString(this.qualifiedName.name.value);\r\n }\r\n }\r\n /**\r\n * Returns the fully qualified column name as a string.\r\n */\r\n public getFullName(): string {\r\n return this.qualifiedName.toString();\r\n }\r\n}\r\n\r\nexport class UpdateClause extends SqlComponent {\r\n static kind = Symbol(\"UpdateClause\");\r\n source: SourceExpression;\r\n constructor(source: SourceExpression) {\r\n super();\r\n this.source = source;\r\n }\r\n public getSourceAliasName() {\r\n if (this.source.aliasExpression) {\r\n return this.source.aliasExpression.table.name;\r\n }\r\n else if (this.source.datasource instanceof TableSource) {\r\n return this.source.datasource.table.name;\r\n }\r\n return null;\r\n }\r\n}\r\n\r\n/**\r\n * Represents the target table (with optional alias/schema) and columns for an INSERT statement.\r\n * @param source The target table as a SourceExpression (can include schema, alias, etc.)\r\n * @param columns Array of column names (as strings)\r\n */\r\nexport class InsertClause extends SqlComponent {\r\n source: SourceExpression;\r\n columns: IdentifierString[];\r\n\r\n constructor(source: SourceExpression, columns: string[]) {\r\n super();\r\n this.source = source;\r\n this.columns = columns.map((col) => new IdentifierString(col));\r\n }\r\n}", "\uFEFFexport enum TokenType {\r\n None = 0,\r\n Literal = 1 << 0,\r\n Operator = 1 << 1,\r\n OpenParen = 1 << 2,\r\n CloseParen = 1 << 3,\r\n Comma = 1 << 4,\r\n Dot = 1 << 5,\r\n Identifier = 1 << 6,\r\n Command = 1 << 7, // select, from, where as, on, array etc\r\n Parameter = 1 << 8,\r\n OpenBracket = 1 << 9,\r\n CloseBracket = 1 << 10,\r\n Function = 1 << 11, // next token is open paren\r\n StringSpecifier = 1 << 12, // next token is string literal\r\n Type = 1 << 13,\r\n}\r\n\r\n/**\r\n * Represents a lexical token in SQL parsing\r\n */\r\nexport interface Lexeme {\r\n type: number; // Bit flags for TokenType\r\n value: string;\r\n comments: string[] | null;\r\n}\r\n", "\uFEFF/**\r\n * Fast character classification utilities for SQL tokenization\r\n */\r\nexport class CharLookupTable {\r\n public static isWhitespace(char: string): boolean {\r\n if (char.length !== 1) return false;\r\n const code = char.charCodeAt(0);\r\n // Check for space(32), tab(9), line feed(10), carriage return(13)\r\n return code === 32 || code === 9 || code === 10 || code === 13;\r\n }\r\n\r\n public static isDigit(char: string): boolean {\r\n if (char.length !== 1) return false;\r\n const code = char.charCodeAt(0);\r\n // Check if within '0'(48) to '9'(57) range\r\n return code >= 48 && code <= 57;\r\n }\r\n\r\n public static isHexChar(char: string): boolean {\r\n if (char.length !== 1) return false;\r\n const code = char.charCodeAt(0);\r\n // Check if '0'(48) to '9'(57) or 'a'(97) to 'f'(102) or 'A'(65) to 'F'(70)\r\n return (code >= 48 && code <= 57) ||\r\n (code >= 97 && code <= 102) ||\r\n (code >= 65 && code <= 70);\r\n }\r\n\r\n public static isOperatorSymbol(char: string): boolean {\r\n if (char.length !== 1) return false;\r\n const code = char.charCodeAt(0);\r\n\r\n // Check for specific operator character codes\r\n // '+'=43, '-'=45, '*'=42, '/'=47, '%'=37, '~'=126, '@'=64, '#'=35, '^'=94, \r\n // '&'=38, ':'=58, '!'=33, '<'=60, '>'=62, '='=61, '|'=124\r\n return code === 43 || code === 45 || code === 42 || code === 47 ||\r\n code === 37 || code === 126 || code === 64 || code === 35 ||\r\n code === 94 || code === 38 || code === 58 || code === 33 ||\r\n code === 60 || code === 62 || code === 61 || code === 124;\r\n }\r\n\r\n public static isDelimiter(char: string): boolean {\r\n if (char.length !== 1) return false;\r\n const code = char.charCodeAt(0);\r\n\r\n // First check delimiters: '.'=46, ','=44, '('=40, ')'=41, '['=91, ']'=93, '{'=123, '}'=125, ';'=59\r\n if (code === 46 || code === 44 || code === 40 || code === 41 ||\r\n code === 91 || code === 93 || code === 123 || code === 125 || code === 59) {\r\n return true;\r\n }\r\n\r\n // Then check for whitespace: ' '=32, '\\t'=9, '\\n'=10, '\\r'=13\r\n if (code === 32 || code === 9 || code === 10 || code === 13) {\r\n return true;\r\n }\r\n\r\n // Finally check for operator symbols\r\n // '+'=43, '-'=45, '*'=42, '/'=47, '%'=37, '~'=126, '@'=64, '#'=35, '^'=94, \r\n // '&'=38, ':'=58, '!'=33, '<'=60, '>'=62, '='=61, '|'=124\r\n return code === 43 || code === 45 || code === 42 || code === 47 ||\r\n code === 37 || code === 126 || code === 64 || code === 35 ||\r\n code === 94 || code === 38 || code === 58 || code === 33 ||\r\n code === 60 || code === 62 || code === 61 || code === 124;\r\n }\r\n\r\n public static isNamedParameterPrefix(char: string): boolean {\r\n if (char.length !== 1) return false;\r\n const code = char.charCodeAt(0);\r\n\r\n // Check for parameter prefix characters: '@'=64, ':'=58, '$'=36\r\n return code === 64 || code === 58 || code === 36;\r\n }\r\n}\r\n", "\uFEFFimport { CharLookupTable } from \"./charLookupTable\";\r\n\r\n/**\r\n * Utilities for string operations during tokenization\r\n */\r\nexport class StringUtils {\r\n /**\r\n * Creates a visual representation of an error position in text\r\n * @param input The input text\r\n * @param errPosition The error position\r\n * @returns A string with a caret pointing to the error position\r\n */\r\n public static getDebugPositionInfo(input: string, errPosition: number): string {\r\n // Get 5 characters before and after the error\r\n // If the start and end points are out of the string range, keep them within the range\r\n // Display ^ at the error position on the next line\r\n const start = Math.max(0, errPosition - 5);\r\n const end = Math.min(input.length, errPosition + 5);\r\n const debugInfo = input.slice(start, end);\r\n const caret = ' '.repeat(errPosition - start) + '^';\r\n return `${debugInfo}\\n${caret}`;\r\n }\r\n\r\n /**\r\n * Skip white space characters.\r\n */\r\n private static skipWhiteSpace(input: string, position: number): number {\r\n const length = input.length;\r\n\r\n /*\r\n * Optimization: Try to skip 4 spaces at once (for 4-space indents).\r\n * This is effective when SQL is deeply nested and uses 4-space indentation.\r\n * In typical cases, charCodeAt in a loop is fastest, but for large/indented SQL,\r\n * this can reduce the number of iterations and improve stability (lower error/deviation in benchmarks).\r\n * If indentation is not 4 spaces, this check is skipped quickly, so overhead is minimal.\r\n *\r\n * Even for 2-space indents or mixed indents (2, 4, tab),\r\n * the remaining whitespace is handled by the following loop, so there is no performance loss.\r\n *\r\n * Benchmark results show that this optimization does not slow down short queries,\r\n * and can make long/indented queries more stable and slightly faster.\r\n */\r\n while (position + 4 <= length && input.slice(position, position + 4) === ' ') {\r\n position += 4;\r\n }\r\n\r\n // Then skip remaining whitespace one by one (space, tab, newline, carriage return)\r\n while (position < length) {\r\n const charCode = input.charCodeAt(position);\r\n // ' '=32, '\\t'=9, '\\n'=10, '\\r'=13\r\n if (charCode !== 32 && charCode !== 9 && charCode !== 10 && charCode !== 13) {\r\n break;\r\n }\r\n position++;\r\n }\r\n\r\n return position;\r\n }\r\n\r\n /**\r\n * Skip line comment.\r\n */\r\n private static readLineComment(input: string, position: number): { newPosition: number, comment: string | null } {\r\n if (position + 1 >= input.length) {\r\n return { newPosition: position, comment: null };\r\n }\r\n\r\n // '-'=45\r\n if (input.charCodeAt(position) === 45 && input.charCodeAt(position + 1) === 45) {\r\n const start = position;\r\n position += 2;\r\n\r\n // '\\n'=10\r\n while (position < input.length && input.charCodeAt(position) !== 10) {\r\n position++;\r\n }\r\n\r\n // Return the trimmed comment content (excluding -- tokens)\r\n const comment = input.slice(start + 2, position).trim();\r\n return { newPosition: position, comment };\r\n }\r\n return { newPosition: position, comment: null };\r\n }\r\n\r\n /**\r\n * Skip block comment.\r\n */\r\n private static readBlockComment(input: string, position: number): { newPosition: number, comments: string[] | null } {\r\n if (position + 3 >= input.length) {\r\n return { newPosition: position, comments: null };\r\n }\r\n\r\n // '/'=47, '*'=42, '+'=43\r\n if (input.charCodeAt(position) === 47 && input.charCodeAt(position + 1) === 42 && input.charCodeAt(position + 2) !== 43) {\r\n const start = position;\r\n position += 2;\r\n\r\n while (position + 1 < input.length) {\r\n // '*'=42, '/'=47\r\n if (input.charCodeAt(position) === 42 && input.charCodeAt(position + 1) === 47) {\r\n position += 2;\r\n\r\n // Process the comment content\r\n const lines = input.slice(start + 2, position - 2).replace(/\\r/g, '').split('\\n');\r\n for (let i = 0; i < lines.length; i++) {\r\n lines[i] = lines[i].trim();\r\n }\r\n\r\n // Remove empty lines, but only at the beginning and end\r\n while (lines.length > 0 && lines[0] === '') {\r\n lines.shift();\r\n }\r\n while (lines.length > 0 && lines[lines.length - 1] === '') {\r\n lines.pop();\r\n }\r\n\r\n return { newPosition: position, comments: lines };\r\n }\r\n position++;\r\n }\r\n throw new Error(`Block comment is not closed. position: ${position}`);\r\n }\r\n return { newPosition: position, comments: null };\r\n }\r\n\r\n /**\r\n * Skip white space characters and SQL comments.\r\n * @returns Object containing the new position and an array of skipped comments\r\n */\r\n public static readWhiteSpaceAndComment(input: string, position: number): { position: number, lines: string[] } {\r\n const lines: string[] = [];\r\n const length = input.length;\r\n\r\n while (position < length) {\r\n // Store current position\r\n const oldPosition = position;\r\n\r\n // Skip whitespace first\r\n position = StringUtils.skipWhiteSpace(input, position);\r\n if (position !== oldPosition) {\r\n continue;\r\n }\r\n\r\n // Fast character code check\r\n const charCode = input.charCodeAt(position);\r\n\r\n // '-'=45 (Line comment)\r\n if (charCode === 45) {\r\n const lineCommentResult = StringUtils.readLineComment(input, position);\r\n if (lineCommentResult.newPosition !== position) {\r\n position = lineCommentResult.newPosition;\r\n if (lineCommentResult.comment) {\r\n lines.push(lineCommentResult.comment.trim());\r\n }\r\n continue;\r\n }\r\n }\r\n // '/'=47 (Block comment)\r\n else if (charCode === 47) {\r\n const blockCommentResult = StringUtils.readBlockComment(input, position);\r\n if (blockCommentResult.newPosition !== position) {\r\n position = blockCommentResult.newPosition;\r\n if (blockCommentResult.comments) {\r\n lines.push(...blockCommentResult.comments);\r\n }\r\n continue;\r\n }\r\n }\r\n\r\n // No more whitespace or comments found\r\n break;\r\n }\r\n\r\n return { position, lines: lines };\r\n }\r\n\r\n /**\r\n * Read a regular identifier.\r\n */\r\n public static readRegularIdentifier(input: string, position: number): { identifier: string, newPosition: number } {\r\n const result = this.tryReadRegularIdentifier(input, position);\r\n\r\n if (!result) {\r\n throw new Error(`Unexpected character. position: ${position}\\n${StringUtils.getDebugPositionInfo(input, position)}`);\r\n }\r\n\r\n return result;\r\n }\r\n\r\n public static tryReadRegularIdentifier(input: string, position: number): { identifier: string, newPosition: number } | null {\r\n const start = position;\r\n\r\n while (position < input.length) {\r\n if (CharLookupTable.isDelimiter(input[position])) {\r\n break;\r\n }\r\n position++;\r\n }\r\n\r\n if (start === position) {\r\n return null;\r\n }\r\n\r\n // Check index range before checking for [] (array type)\r\n while (\r\n position + 1 < input.length &&\r\n input[position] === '[' &&\r\n input[position + 1] === ']'\r\n ) {\r\n position += 2; // Skip the []\r\n }\r\n\r\n return {\r\n identifier: input.slice(start, position),\r\n newPosition: position\r\n };\r\n }\r\n}\r\n", "\uFEFFimport { Lexeme, TokenType } from '../models/Lexeme';\r\nimport { StringUtils } from '../utils/stringUtils';\r\n\r\n/**\r\n * Base class for token readers\r\n */\r\nexport abstract class BaseTokenReader {\r\n protected input: string;\r\n protected position: number;\r\n\r\n constructor(input: string, position: number = 0) {\r\n this.input = input;\r\n this.position = position;\r\n }\r\n\r\n /**\r\n * Get the current position in the input\r\n */\r\n public getPosition(): number {\r\n return this.position;\r\n }\r\n\r\n /**\r\n * Set the position in the input\r\n */\r\n public setPosition(position: number): void {\r\n this.position = position;\r\n }\r\n\r\n /**\r\n * Check if we've reached the end of input\r\n */\r\n protected isEndOfInput(shift: number = 0): boolean {\r\n return this.position + shift >= this.input.length;\r\n }\r\n\r\n /**\r\n * Check if we can read more characters\r\n */\r\n protected canRead(shift: number = 0): boolean {\r\n return !this.isEndOfInput(shift);\r\n }\r\n\r\n /**\r\n * Read an expected character\r\n */\r\n protected read(expectChar: string): string {\r\n if (this.isEndOfInput()) {\r\n throw new Error(`Unexpected character. expect: ${expectChar}, actual: EndOfInput, position: ${this.position}`);\r\n }\r\n\r\n const char = this.input[this.position];\r\n if (char !== expectChar) {\r\n throw new Error(`Unexpected character. expect: ${expectChar}, actual: ${char}, position: ${this.position}`);\r\n }\r\n\r\n this.position++;\r\n return char;\r\n }\r\n\r\n /**\r\n * Create a lexeme with the specified type and value\r\n */\r\n protected createLexeme(type: TokenType, value: string, comments: string[] | null = null): Lexeme {\r\n if (type === TokenType.Command || type === TokenType.Operator || type === TokenType.Function) {\r\n // Benchmark tests showed that directly calling toLowerCase() is ~5x faster\r\n // than first checking if the string is already lowercase.\r\n // See benchmarks/lowercase-benchmark.js for detailed performance analysis.\r\n return {\r\n type,\r\n value: value.toLowerCase(),\r\n comments: comments,\r\n };\r\n }\r\n return {\r\n type,\r\n value,\r\n comments: comments,\r\n };\r\n }\r\n\r\n /**\r\n * Get debug info for error reporting\r\n */\r\n protected getDebugPositionInfo(errPosition: number): string {\r\n return StringUtils.getDebugPositionInfo(this.input, errPosition);\r\n }\r\n\r\n /**\r\n * Try to read a token from the current position\r\n * @param previous The previous token, if available\r\n * @returns The read token or null if no token could be read\r\n */\r\n public abstract tryRead(previous: Lexeme | null): Lexeme | null;\r\n}\r\n", "\uFEFFimport { BaseTokenReader } from './BaseTokenReader';\r\nimport { Lexeme, TokenType } from '../models/Lexeme';\r\nimport { StringUtils } from '../utils/stringUtils';\r\n\r\n/**\r\n * Reads SQL identifier tokens\r\n */\r\nexport class IdentifierTokenReader extends BaseTokenReader {\r\n /**\r\n * Try to read an identifier token\r\n */\r\n public tryRead(previous: Lexeme | null): Lexeme | null {\r\n if (this.isEndOfInput()) {\r\n return null;\r\n }\r\n\r\n const char = this.input[this.position];\r\n\r\n // wildcard identifier\r\n if (char === '*') {\r\n // Assume that the OperatorTokenReader is executed before the IdentifierTokenReader.\r\n // Since we have determined that the OperatorTokenReader is not an Operator,\r\n // we treat '*' here as a wildcard identifier.\r\n this.position++;\r\n return this.createLexeme(TokenType.Identifier, char);\r\n }\r\n\r\n // Regular identifier\r\n const result = StringUtils.readRegularIdentifier(this.input, this.position);\r\n this.position = result.newPosition;\r\n return this.createLexeme(TokenType.Identifier, result.identifier);\r\n }\r\n}\r\n", "\uFEFFimport { KeywordTrie } from \"../models/KeywordTrie\";\r\nimport { StringUtils } from \"../utils/stringUtils\";\r\n\r\nexport enum KeywordMatchResult {\r\n NotAKeyword, // \"Not recognized as a keyword\"\r\n PartialOnly, // \"Partial match (this will not be the end)\"\r\n PartialOrFinal, // \"Partial or complete match (it can stop here)\"\r\n Final // \"Complete match (no longer keywords after this)\"\r\n}\r\n\r\nexport class KeywordParser {\r\n private trie: KeywordTrie;\r\n\r\n constructor(trie: KeywordTrie) {\r\n this.trie = trie;\r\n }\r\n\r\n private isEndOfInput(input: string, position: number, shift: number = 0): boolean {\r\n return position + shift >= input.length;\r\n }\r\n\r\n private canParse(input: string, position: number, shift: number = 0): boolean {\r\n return !this.isEndOfInput(input, position, shift);\r\n }\r\n\r\n public parse(input: string, position: number): { keyword: string, newPosition: number } | null {\r\n if (this.isEndOfInput(input, position)) {\r\n return null;\r\n }\r\n\r\n // reset trie node\r\n this.trie.reset();\r\n const result = StringUtils.tryReadRegularIdentifier(input, position);\r\n\r\n if (result === null) {\r\n return null;\r\n }\r\n\r\n let matchResult = this.trie.pushLexeme(result.identifier.toLowerCase());\r\n\r\n if (matchResult === KeywordMatchResult.NotAKeyword) {\r\n return null;\r\n }\r\n\r\n if (matchResult === KeywordMatchResult.Final) {\r\n return {\r\n keyword: result.identifier,\r\n newPosition: result.newPosition\r\n };\r\n }\r\n\r\n // multi-word keyword\r\n let lexeme = result.identifier;\r\n position = StringUtils.readWhiteSpaceAndComment(input, result.newPosition).position;\r\n\r\n // end of input\r\n if (this.isEndOfInput(input, position)) {\r\n if (matchResult === KeywordMatchResult.PartialOrFinal) {\r\n // if the last match was partial or final, it means that the keyword is finished\r\n return {\r\n keyword: lexeme,\r\n newPosition: position\r\n };\r\n } else {\r\n\r\n return null;\r\n }\r\n }\r\n\r\n while (this.canParse(input, position)) {\r\n const previousMatchResult = matchResult;\r\n\r\n const result = StringUtils.tryReadRegularIdentifier(input, position);\r\n\r\n if (result !== null) {\r\n matchResult = this.trie.pushLexeme(result.identifier.toLowerCase());\r\n\r\n if (matchResult === KeywordMatchResult.NotAKeyword) {\r\n if (previousMatchResult === KeywordMatchResult.PartialOrFinal) {\r\n break;\r\n } else {\r\n return null;\r\n }\r\n }\r\n\r\n lexeme += ' ' + result.identifier;\r\n position = StringUtils.readWhiteSpaceAndComment(input, result.newPosition).position;\r\n\r\n if (matchResult === KeywordMatchResult.Final) {\r\n break;\r\n }\r\n } else if (previousMatchResult === KeywordMatchResult.PartialOrFinal) {\r\n break;\r\n } else {\r\n return null;\r\n }\r\n }\r\n\r\n return {\r\n keyword: lexeme,\r\n newPosition: position\r\n };\r\n }\r\n}\r\n\r\n", "\uFEFFimport { KeywordMatchResult } from \"../parsers/KeywordParser\";\r\n\r\n// Note: An object-based trie (string-keyed object) was tested, but benchmark results showed no improvement and sometimes worse performance for long queries.\r\n// Therefore, the original Map-based implementation is retained for best stability and speed.\r\n\r\nexport class KeywordTrie {\r\n private root: Map<string, any> = new Map();\r\n private currentNode: Map<string, any>;\r\n\r\n // cache properties\r\n private hasEndProperty: boolean = false;\r\n private hasMoreProperties: boolean = false;\r\n\r\n constructor(keywords: string[][]) {\r\n // initialize root node\r\n for (const keyword of keywords) {\r\n this.addKeyword(keyword);\r\n }\r\n // set current node to root\r\n this.currentNode = this.root;\r\n }\r\n\r\n private addKeyword(keyword: string[]) {\r\n let node = this.root;\r\n for (const word of keyword) {\r\n if (!node.has(word)) {\r\n node.set(word, new Map());\r\n }\r\n node = node.get(word);\r\n }\r\n node.set(\"__end__\", true);\r\n }\r\n\r\n public reset(): void {\r\n this.currentNode = this.root;\r\n this.hasEndProperty = false;\r\n this.hasMoreProperties = false;\r\n }\r\n\r\n public pushLexeme(lexeme: string): KeywordMatchResult {\r\n if (!this.currentNode.has(lexeme)) {\r\n return KeywordMatchResult.NotAKeyword;\r\n }\r\n\r\n // move to next node\r\n this.currentNode = this.currentNode.get(lexeme);\r\n\r\n // Cache property checks to avoid repeated operations\r\n this.hasEndProperty = this.currentNode.has(\"__end__\");\r\n this.hasMoreProperties = this.currentNode.size > (this.hasEndProperty ? 1 : 0);\r\n\r\n if (this.hasEndProperty && !this.hasMoreProperties) {\r\n return KeywordMatchResult.Final;\r\n }\r\n if (this.hasEndProperty && this.hasMoreProperties) {\r\n return KeywordMatchResult.PartialOrFinal;\r\n }\r\n\r\n return KeywordMatchResult.PartialOnly;\r\n }\r\n}\r\n", "\uFEFFimport { BaseTokenReader } from './BaseTokenReader';\r\nimport { Lexeme, TokenType } from '../models/Lexeme';\r\nimport { CharLookupTable } from '../utils/charLookupTable';\r\nimport { KeywordParser } from '../parsers/KeywordParser';\r\nimport { KeywordTrie } from '../models/KeywordTrie';\r\n\r\n/**\r\n * Reads SQL literal tokens (numbers, strings)\r\n */\r\n\r\nconst keywords = [\r\n [\"null\"],\r\n [\"true\"],\r\n [\"false\"],\r\n [\"current_date\"],\r\n [\"current_time\"],\r\n [\"current_timestamp\"],\r\n [\"localtime\"],\r\n [\"localtimestamp\"],\r\n [\"unbounded\"],\r\n [\"normalized\"],\r\n [\"nfc\", \"normalized\"],\r\n [\"nfd\", \"normalized\"],\r\n [\"nfkc\", \"normalized\"],\r\n [\"nfkd\", \"normalized\"],\r\n [\"nfc\"],\r\n [\"nfd\"],\r\n [\"nfkc\"],\r\n [\"nfkd\"],\r\n];\r\nconst trie = new KeywordTrie(keywords);\r\nexport const literalKeywordParser = new KeywordParser(trie);\r\n\r\nexport class LiteralTokenReader extends BaseTokenReader {\r\n /**\r\n * Try to read a literal token\r\n */\r\n public tryRead(previous: Lexeme | null): Lexeme | null {\r\n if (this.isEndOfInput()) {\r\n return null;\r\n }\r\n\r\n const char = this.input[this.position];\r\n\r\n // Check for keyword literals \r\n const keyword = this.tryReadKeyword();\r\n if (keyword) {\r\n return keyword;\r\n }\r\n\r\n // Decimal token starting with a dot\r\n if (char === '.' && this.canRead(1) && CharLookupTable.isDigit(this.input[this.position + 1])) {\r\n return this.createLexeme(TokenType.Literal, this.readDigit());\r\n }\r\n\r\n // String literal\r\n if (char === '\\'') {\r\n const value = this.readSingleQuotedString(false);\r\n return this.createLexeme(TokenType.Literal, value);\r\n }\r\n\r\n // Digit tokens\r\n if (CharLookupTable.isDigit(char)) {\r\n return this.createLexeme(TokenType.Literal, this.readDigit());\r\n }\r\n\r\n // Signed number\r\n if ((char === '+' || char === '-') && this.determineSignOrOperator(previous) === \"sign\") {\r\n const sign = char;\r\n this.position++;\r\n\r\n // Skip whitespace after sign\r\n const pos = this.position;\r\n while (this.canRead() && CharLookupTable.isWhitespace(this.input[this.position])) {\r\n this.position++;\r\n }\r\n\r\n if (this.canRead() && (\r\n CharLookupTable.isDigit(this.input[this.position]) ||\r\n (this.input[this.position] === '.' &&\r\n this.canRead(1) &&\r\n CharLookupTable.isDigit(this.input[this.position + 1]))\r\n )) {\r\n return this.createLexeme(\r\n TokenType.Literal,\r\n sign === '-' ? sign + this.readDigit() : this.readDigit()\r\n );\r\n }\r\n\r\n // Not a number, restore position\r\n this.position = pos - 1; // Adjust for the increment at the beginning\r\n }\r\n\r\n return null;\r\n }\r\n\r\n private tryReadKeyword(): Lexeme | null {\r\n // Check for keyword literals\r\n const result = literalKeywordParser.parse(this.input, this.position);\r\n if (result) {\r\n this.position = result.newPosition;\r\n return this.createLexeme(TokenType.Literal, result.keyword);\r\n }\r\n return null;\r\n }\r\n\r\n /**\r\n * Determines if the current context treats '+' or '-' as a numeric sign or an operator.\r\n * This method is used to differentiate between operators and numeric signs (e.g., '+' or '-').\r\n *\r\n * For example:\r\n * - In `1-1`, the '-' is treated as an operator, so the expression is split into `1`, `-`, and `1`.\r\n * - In `-1`, the '-' is treated as a sign, making `-1` a single, indivisible literal.\r\n *\r\n * The logic for determining whether '+' or '-' is a sign or an operator is as follows:\r\n * - If there is no previous lexeme, it is considered the start of the input, so the sign is valid.\r\n * - If the previous lexeme is a literal, identifier, parameter, or closing parenthesis, the sign is treated as an operator.\r\n *\r\n * @param previous The previous lexeme in the input stream.\r\n * @returns \"sign\" if the context allows for a numeric sign, otherwise \"operator\".\r\n */\r\n private determineSignOrOperator(previous: Lexeme | null): \"sign\" | \"operator\" {\r\n // If there is no previous lexeme, treat as a sign\r\n if (previous === null) {\r\n return \"sign\";\r\n }\r\n\r\n // If the previous lexeme is a literal, identifier, parameter, or closing parenthesis, treat as an operator\r\n const isOperatorContext = (previous.type & TokenType.Literal) || \r\n (previous.type & TokenType.Identifier) || \r\n (previous.type & TokenType.Parameter) || \r\n (previous.type & TokenType.CloseParen);\r\n return isOperatorContext ? \"operator\" : \"sign\";\r\n }\r\n\r\n /**\r\n * Read a numeric value\r\n */\r\n private readDigit(): string {\r\n const start = this.position;\r\n let hasDot = false;\r\n let hasExponent = false;\r\n\r\n // Consider 0x, 0b, 0o\r\n if (this.canRead(1) &&\r\n this.input[this.position] === '0' &&\r\n \"xbo\".includes(this.input[this.position + 1].toLowerCase())) {\r\n\r\n const prefixType = this.input[this.position + 1].toLowerCase();\r\n this.position += 2;\r\n\r\n // Continue to get numeric and hexadecimal notation strings\r\n const isHex = prefixType === 'x';\r\n while (this.canRead()) {\r\n const c = this.input[this.position];\r\n if (CharLookupTable.isDigit(c) || (isHex && CharLookupTable.isHexChar(c))) {\r\n this.position++;\r\n } else {\r\n break;\r\n }\r\n }\r\n\r\n return this.input.slice(start, this.position);\r\n }\r\n\r\n // If starting with dot, note it\r\n if (this.input[start] === '.') {\r\n hasDot = true;\r\n this.position++;\r\n }\r\n\r\n // Consider decimal point and exponential notation\r\n while (this.canRead()) {\r\n const char = this.input[this.position];\r\n\r\n if (char === '.' && !hasDot) {\r\n hasDot = true;\r\n } else if ((char === 'e' || char === 'E') && !hasExponent) {\r\n hasExponent = true;\r\n if (this.canRead(1) && (this.input[this.position + 1] === '+' || this.input[this.position + 1] === '-')) {\r\n this.position++;\r\n }\r\n } else if (!CharLookupTable.isDigit(char)) {\r\n break;\r\n }\r\n\r\n this.position++;\r\n }\r\n\r\n if (start === this.position) {\r\n throw new Error(`Unexpected character. position: ${start}\\n${this.getDebugPositionInfo(start)}`);\r\n }\r\n\r\n if (this.input[start] === '.') {\r\n // If the number starts with a dot, add 0 to the front\r\n return '0' + this.input.slice(start, this.position);\r\n }\r\n\r\n return this.input.slice(start, this.position);\r\n }\r\n\r\n /**\r\n * Read a string literal\r\n */\r\n private readSingleQuotedString(includeSingleQuote: boolean): string {\r\n const start = this.position;\r\n let closed = false;\r\n this.read(\"'\");\r\n\r\n while (this.canRead()) {\r\n const char = this.input[this.position];\r\n this.position++;\r\n\r\n // escape character check\r\n if (char === \"\\\\\" && this.canRead(1)) {\r\n this.position++;\r\n continue;\r\n }\r\n else if (char === '\\'') {\r\n closed = true;\r\n break;\r\n }\r\n }\r\n\r\n if (closed === false) {\r\n throw new Error(`Single quote is not closed. position: ${start}\\n${this.getDebugPositionInfo(start)}`);\r\n }\r\n\r\n if (includeSingleQuote) {\r\n const value = this.input.slice(start, this.position);\r\n return value;\r\n } else {\r\n const value = this.input.slice(start + 1, this.position - 1);\r\n return value;\r\n }\r\n }\r\n}\r\n", "\uFEFFimport { BaseTokenReader } from './BaseTokenReader';\r\nimport { Lexeme, TokenType } from '../models/Lexeme';\r\nimport { CharLookupTable } from '../utils/charLookupTable';\r\n\r\n/**\r\n * Reads SQL parameter tokens (@param, :param, $param, ?, ${param})\r\n */\r\nexport class ParameterTokenReader extends BaseTokenReader {\r\n constructor(input: string) {\r\n super(input);\r\n }\r\n\r\n /**\r\n * Try to read a parameter token\r\n */\r\n public tryRead(previous: Lexeme | null): Lexeme | null {\r\n if (this.isEndOfInput()) {\r\n return null;\r\n }\r\n\r\n // parameter with suffix (${param}) - check this first\r\n if (this.canRead(1) && this.input[this.position] === '$' && this.input[this.position + 1] === '{') {\r\n this.position += 2; // Skip ${\r\n const start = this.position;\r\n while (this.canRead() && this.input[this.position] !== '}') {\r\n this.position++;\r\n }\r\n if (this.isEndOfInput()) {\r\n throw new Error(`Unexpected end of input. Expected closing '}' for parameter at position ${start}`);\r\n }\r\n\r\n const identifier = this.input.slice(start, this.position);\r\n if (identifier.length === 0) {\r\n throw new Error('Empty parameter name is not allowed: found ${} at position ' + (start - 2));\r\n }\r\n\r\n this.position++; // Skip }\r\n return this.createLexeme(TokenType.Parameter, '${' + identifier + '}');\r\n }\r\n\r\n const char = this.input[this.position];\r\n\r\n // named parameter (@param, :param, $param)\r\n if (CharLookupTable.isNamedParameterPrefix(char)) {\r\n\r\n // However, do not recognize as a parameter if the next character is an operator symbol\r\n // To avoid postgres `::`\r\n if (this.canRead(1) && CharLookupTable.isOperatorSymbol(this.input[this.position + 1])) {\r\n return null;\r\n }\r\n\r\n this.position++;\r\n\r\n // Read the identifier part after the prefix\r\n const start = this.position;\r\n while (this.canRead() && !CharLookupTable.isDelimiter(this.input[this.position])) {\r\n this.position++;\r\n }\r\n\r\n const identifier = this.input.slice(start, this.position);\r\n return this.createLexeme(TokenType.Parameter, char + identifier);\r\n }\r\n\r\n // nameless parameter (?)\r\n if (char === '?') {\r\n this.position++;\r\n return this.createLexeme(TokenType.Parameter, char);\r\n }\r\n\r\n return null;\r\n }\r\n}\r\n", "\uFEFFimport { BaseTokenReader } from './BaseTokenReader';\r\nimport { Lexeme, TokenType } from '../models/Lexeme';\r\n\r\n/**\r\n * Reads SQL symbol tokens (., ,, (, ))\r\n */\r\nexport class SpecialSymbolTokenReader extends BaseTokenReader {\r\n private static readonly SPECIAL_SYMBOL_TOKENS: Record<string, TokenType> = {\r\n '.': TokenType.Dot,\r\n ',': TokenType.Comma,\r\n '(': TokenType.OpenParen,\r\n ')': TokenType.CloseParen,\r\n '[': TokenType.OpenBracket,\r\n ']': TokenType.CloseBracket,\r\n };\r\n\r\n /**\r\n * Try to read a symbol token\r\n */\r\n public tryRead(previous: Lexeme | null): Lexeme | null {\r\n if (this.isEndOfInput()) {\r\n return null;\r\n }\r\n\r\n const char = this.input[this.position];\r\n\r\n // symbol tokens\r\n if (char in SpecialSymbolTokenReader.SPECIAL_SYMBOL_TOKENS) {\r\n this.position++;\r\n return this.createLexeme(\r\n SpecialSymbolTokenReader.SPECIAL_SYMBOL_TOKENS[char],\r\n char\r\n );\r\n }\r\n return null;\r\n }\r\n}\r\n", "\uFEFFimport { BaseTokenReader } from './BaseTokenReader';\r\nimport { Lexeme, TokenType } from '../models/Lexeme';\r\n\r\n/**\r\n * Manages and coordinates multiple token readers\r\n */\r\nexport class TokenReaderManager {\r\n private readers: BaseTokenReader[];\r\n private input: string;\r\n private position: number;\r\n private tokenCache: Map<number, Lexeme | null>;\r\n private cacheHits: number = 0;\r\n private cacheMisses: number = 0;\r\n\r\n constructor(input: string, position: number = 0) {\r\n this.input = input;\r\n this.position = position;\r\n this.readers = [];\r\n this.tokenCache = new Map();\r\n }\r\n\r\n /**\r\n * Register a token reader\r\n * @param reader The reader to register\r\n * @returns This manager instance for chaining\r\n */\r\n public register(reader: BaseTokenReader): TokenReaderManager {\r\n this.readers.push(reader);\r\n return this;\r\n }\r\n\r\n /**\r\n * Register multiple token readers\r\n * @param readers The readers to register\r\n * @returns This manager instance for chaining\r\n */\r\n public registerAll(readers: BaseTokenReader[]): TokenReaderManager {\r\n readers.forEach(reader => this.register(reader));\r\n return this;\r\n }\r\n\r\n /**\r\n * Update the position for all readers\r\n */\r\n private setPosition(position: number): void {\r\n this.position = position;\r\n for (const reader of this.readers) {\r\n reader.setPosition(position);\r\n }\r\n }\r\n\r\n /**\r\n * Try to read a token using all registered readers\r\n * @param position The position to read from\r\n * @param previous The previous token, if any\r\n * @returns The lexeme if a reader could read it, null otherwise\r\n */\r\n public tryRead(position: number, previous: Lexeme | null): Lexeme | null {\r\n // Check cache - using position as the key\r\n if (this.tokenCache.has(position)) {\r\n // Cache hit\r\n this.cacheHits++;\r\n const lexeme = this.tokenCache.get(position) || null;\r\n return lexeme;\r\n }\r\n\r\n // Cache miss - create new entry\r\n this.cacheMisses++;\r\n this.setPosition(position);\r\n\r\n // Try to read with each reader\r\n let lexeme: Lexeme | null = null;\r\n for (const reader of this.readers) {\r\n lexeme = reader.tryRead(previous);\r\n if (lexeme) {\r\n this.position = reader.getPosition();\r\n break;\r\n }\r\n }\r\n\r\n // Update all readers' positions\r\n for (const reader of this.readers) {\r\n reader.setPosition(this.position);\r\n }\r\n\r\n // Save to cache (even if null)\r\n this.tokenCache.set(position, lexeme);\r\n return lexeme;\r\n }\r\n\r\n /**\r\n * Get the maximum position among all readers\r\n */\r\n public getMaxPosition(): number {\r\n let maxPosition = this.position;\r\n for (const reader of this.readers) {\r\n const position = reader.getPosition();\r\n if (position > maxPosition) {\r\n maxPosition = position;\r\n }\r\n }\r\n return maxPosition;\r\n }\r\n\r\n /**\r\n * Get the input string\r\n */\r\n public getInput(): string {\r\n return this.input;\r\n }\r\n\r\n /**\r\n * Get cache statistics\r\n */\r\n public getCacheStats(): { hits: number, misses: number, ratio: number } {\r\n const total = this.cacheHits + this.cacheMisses;\r\n const ratio = total > 0 ? this.cacheHits / total : 0;\r\n return {\r\n hits: this.cacheHits,\r\n misses: this.cacheMisses,\r\n ratio: ratio\r\n };\r\n }\r\n}\r\n", "\uFEFFimport { BaseTokenReader } from './BaseTokenReader';\r\nimport { Lexeme, TokenType } from '../models/Lexeme';\r\nimport { CharLookupTable } from '../utils/charLookupTable';\r\nimport { KeywordParser } from '../parsers/KeywordParser';\r\nimport { KeywordTrie } from '../models/KeywordTrie';\r\n\r\nconst trie = new KeywordTrie([\r\n // binary\r\n [\"and\"],\r\n [\"or\"],\r\n [\"is\"],\r\n [\"is\", \"not\"],\r\n [\"is\", \"distinct\", \"from\"],\r\n [\"is\", \"not\", \"distinct\", \"from\"],\r\n [\"like\"],\r\n [\"ilike\"],\r\n [\"in\"],\r\n [\"exists\"],\r\n [\"between\"],\r\n [\"not\", \"like\"],\r\n [\"not\", \"ilike\"],\r\n [\"not\", \"in\"],\r\n [\"not\", \"exists\"],\r\n [\"not\", \"between\"],\r\n [\"escape\"], // e.g. '10% OFF on all items' like '10\\%%' escape '\\'\r\n [\"uescape\"], // e.g. U&'d!0061t!+000061' uescape '!'\r\n [\"similar\", \"to\"], // e.g. name similar to 'J(ohn|ane)%'\r\n [\"not\", \"similar\", \"to\"], // e.g. name not similar to 'J(ohn|ane)%'\r\n [\"similar\"], // e.g. substring('abcdef' similar '%#\"cd#\"%' escape '#')\r\n [\"placing\"], // e.g. overlay('abcdef' placing 'cd' from 3 for 2)\r\n // unary\r\n [\"not\"],\r\n // unary - trim\r\n [\"both\"],\r\n [\"leading\"],\r\n [\"trailing\"],\r\n [\"both\", \"from\"], // Postgres\r\n [\"leading\", \"from\"], // Postgres\r\n [\"trailing\", \"from\"], // Postgres\r\n // unary - extract\r\n [\"year\", \"from\"],\r\n [\"month\", \"from\"],\r\n [\"day\", \"from\"],\r\n [\"hour\", \"from\"],\r\n [\"minute\", \"from\"],\r\n [\"second\", \"from\"],\r\n [\"dow\", \"from\"],\r\n [\"doy\", \"from\"],\r\n [\"isodow\", \"from\"],\r\n [\"quarter\", \"from\"],\r\n [\"week\", \"from\"],\r\n [\"epoch\", \"from\"],\r\n [\"at\", \"time\", \"zone\"],\r\n // The following are not considered operators.\r\n // [\"from\"], can be used as an operator only within the substring function, but it cannot be distinguished from the Form Clause. This will be resolved with a dedicated substring parser.\r\n // [\"for\"], can be used as an operator only within the substring function, but it cannot be distinguished from the For Clause. This will be resolved with a dedicated substring parser.\r\n]);\r\n\r\n// Typed literal format\r\nconst operatorOrTypeTrie = new KeywordTrie([\r\n [\"date\"],\r\n [\"time\"],\r\n [\"timestamp\"],\r\n [\"timestamptz\"],// timestamp with time zone\r\n [\"timetz\"], // time with time zone\r\n [\"interval\"],\r\n [\"boolean\"],\r\n [\"integer\"],\r\n [\"bigint\"],\r\n [\"smallint\"],\r\n [\"numeric\"],\r\n [\"decimal\"],\r\n [\"real\"],\r\n [\"double\", \"precision\"],\r\n [\"double\", \"precision\"],\r\n [\"character\", \"varying\"],\r\n [\"time\", \"without\", \"time\", \"zone\"],\r\n [\"time\", \"with\", \"time\", \"zone\"],\r\n [\"timestamp\", \"without\", \"time\", \"zone\"],\r\n [\"timestamp\", \"with\", \"time\", \"zone\"],\r\n]);\r\n\r\nconst keywordParser = new KeywordParser(trie);\r\nconst operatorOrTypeParser = new KeywordParser(operatorOrTypeTrie);\r\n\r\n// Indicates the token may also represent a type (e.g., 'interval')\r\nconst MAYBE_TYPE = true;\r\n\r\nexport class OperatorTokenReader extends BaseTokenReader {\r\n public tryRead(previous: Lexeme | null): Lexeme | null {\r\n if (this.isEndOfInput()) {\r\n return null;\r\n }\r\n\r\n /*\r\n NOTE:\r\n Asterisks could potentially be wildcard identifiers,\r\n but since they're indistinguishable at this stage, they're treated as Operators at the token level.\r\n The Parser needs to determine whether they are appropriate Operators or Identifiers.\r\n */\r\n\r\n const char = this.input[this.position];\r\n\r\n if (CharLookupTable.isOperatorSymbol(char)) {\r\n const start = this.position;\r\n\r\n while (this.canRead() && CharLookupTable.isOperatorSymbol(this.input[this.position])) {\r\n // check for `--` and `/*` comments\r\n if (this.canRead(1)) {\r\n const current = this.input[this.position];\r\n if (current === '-' && this.input[this.position + 1] === '-') {\r\n break;\r\n } else if (current === '/' && this.input[this.position + 1] === '*') {\r\n break; // end of operator\r\n }\r\n }\r\n\r\n this.position++;\r\n }\r\n const resut = this.input.slice(start, this.position);\r\n return this.createLexeme(TokenType.Operator, resut);\r\n }\r\n\r\n // Logical operators\r\n let result = operatorOrTypeParser.parse(this.input, this.position);\r\n if (result !== null) {\r\n // Special handling for typed literal format.\r\n // Treated as an operator in cases like `interval '2 days'`,\r\n // but can also be used as a type in expressions like `'1 month'::interval`,\r\n // so we return it as both Operator and Type.\r\n this.position = result.newPosition;\r\n return this.createLexeme(TokenType.Operator | TokenType.Type | TokenType.Identifier, result.keyword);\r\n }\r\n\r\n result = keywordParser.parse(this.input, this.position);\r\n if (result !== null) {\r\n this.position = result.newPosition;\r\n return this.createLexeme(TokenType.Operator, result.keyword);\r\n }\r\n\r\n return null;\r\n }\r\n}\r\n", "\uFEFFimport { BaseTokenReader } from \"./BaseTokenReader\";\r\nimport { Lexeme, TokenType } from '../models/Lexeme';\r\nimport { KeywordTrie } from \"../models/KeywordTrie\";\r\nimport { KeywordParser } from \"../parsers/KeywordParser\";\r\n\r\n// Commands are those that require a dedicated parser.\r\n// Keywords composed of multiple words are also considered commands.\r\n// The exception is \"type\". Since types can be user-defined and cannot be accurately identified, they are treated as Identifiers.\r\n\r\nconst joinTrie = new KeywordTrie([\r\n [\"join\"],\r\n [\"inner\", \"join\"],\r\n [\"cross\", \"join\"],\r\n [\"left\", \"join\"],\r\n [\"left\", \"outer\", \"join\"],\r\n [\"right\", \"join\"],\r\n [\"right\", \"outer\", \"join\"],\r\n [\"full\", \"join\"],\r\n [\"full\", \"outer\", \"join\"],\r\n\r\n [\"natural\", \"join\"],\r\n [\"natural\", \"inner\", \"join\"],\r\n [\"natural\", \"left\", \"join\"],\r\n [\"natural\", \"left\", \"outer\", \"join\"],\r\n [\"natural\", \"right\", \"join\"],\r\n [\"natural\", \"right\", \"outer\", \"join\"],\r\n [\"natural\", \"full\", \"join\"],\r\n [\"natural\", \"full\", \"outer\", \"join\"],\r\n]);\r\nconst keywordTrie = new KeywordTrie([\r\n [\"with\"],\r\n [\"recursive\"],\r\n [\"materialized\"],\r\n [\"not\", \"materialized\"],\r\n [\"select\"],\r\n [\"from\"],\r\n [\"distinct\"],\r\n [\"distinct\", \"on\"],\r\n [\"where\"],\r\n [\"group\", \"by\"],\r\n [\"having\"],\r\n [\"order\", \"by\"],\r\n [\"limit\"],\r\n [\"offset\"],\r\n [\"fetch\"],\r\n [\"first\"],\r\n [\"next\"],\r\n [\"row\"],\r\n [\"row\", \"only\"],\r\n [\"rows\", \"only\"],\r\n [\"percent\"],\r\n [\"percent\", \"with\", \"ties\"],\r\n // for\r\n [\"for\"],\r\n [\"update\"],\r\n [\"share\"],\r\n [\"key\", \"share\"],\r\n [\"no\", \"key\", \"update\"],\r\n // set operations\r\n [\"union\"],\r\n [\"union\", \"all\"],\r\n [\"intersect\"],\r\n [\"intersect\", \"all\"],\r\n [\"except\"],\r\n [\"except\", \"all\"],\r\n // between and\r\n [\"beteen\"],\r\n // window functions\r\n [\"window\"],\r\n [\"over\"],\r\n [\"partition\", \"by\"],\r\n [\"range\"],\r\n [\"rows\"],\r\n [\"groups\"],\r\n // window frame\r\n [\"current\", \"row\"],\r\n [\"unbounded\", \"preceding\"],\r\n [\"unbounded\", \"following\"],\r\n [\"preceding\"],\r\n [\"following\"],\r\n // table join commands\r\n [\"on\"],\r\n [\"using\"],\r\n [\"lateral\"],\r\n // case \r\n [\"case\"],\r\n [\"case\", \"when\"],\r\n [\"when\"],\r\n [\"then\"],\r\n [\"else\"],\r\n [\"end\"],\r\n // others\r\n [\"insert\", \"into\"],\r\n [\"update\"],\r\n [\"delete\", \"from\"],\r\n [\"merge\", \"into\"],\r\n [\"matched\"],\r\n [\"not\", \"matched\"],\r\n [\"update\", \"set\"],\r\n [\"do\", \"nothing\"],\r\n [\"values\"],\r\n [\"set\"],\r\n [\"returning\"],\r\n [\"create\", \"table\"],\r\n [\"create\", \"temporary\", \"table\"],\r\n [\"tablesample\"],\r\n // cast\r\n [\"as\"],\r\n // odrder\r\n [\"asc\"],\r\n [\"desc\"],\r\n [\"nulls\", \"first\"],\r\n [\"nulls\", \"last\"],\r\n]);\r\nconst keywordParser = new KeywordParser(keywordTrie);\r\nexport const joinkeywordParser = new KeywordParser(joinTrie);\r\n\r\nexport class CommandTokenReader extends BaseTokenReader {\r\n public tryRead(previous: Lexeme | null): Lexeme | null {\r\n if (this.isEndOfInput()) {\r\n return null;\r\n }\r\n\r\n const keywordJoin = joinkeywordParser.parse(this.input, this.position);\r\n if (keywordJoin !== null) {\r\n this.position = keywordJoin.newPosition;\r\n return this.createLexeme(TokenType.Command, keywordJoin.keyword);\r\n }\r\n\r\n // Check for keyword identifiers\r\n const keyword = keywordParser.parse(this.input, this.position);\r\n if (keyword !== null) {\r\n this.position = keyword.newPosition;\r\n return this.createLexeme(TokenType.Command, keyword.keyword);\r\n }\r\n\r\n // check hint clause\r\n if (this.canRead(2) && this.input[this.position] === '/' && this.input[this.position + 1] === '*' && this.input[this.position + 2] === '+') {\r\n this.position += 3;\r\n const start = this.position;\r\n while (this.position + 1 < this.input.length) {\r\n if (this.input[this.position] === '*' && this.input[this.position + 1] === '/') {\r\n this.position += 2;\r\n return this.createLexeme(TokenType.Command, '/*+ ' + this.input.slice(start, this.position - 2).trim() + ' */');\r\n }\r\n this.position++;\r\n }\r\n throw new Error(`Block comment is not closed. position: ${this.position}`);\r\n }\r\n\r\n return null;\r\n }\r\n}\r\n", "import { Lexeme, TokenType } from '../models/Lexeme';\r\nimport { BaseTokenReader } from './BaseTokenReader';\r\n\r\n// Prefix sets for quick checks\r\nconst STRING_SPECIFIERS = new Set(['e\\'', 'E\\'', 'x\\'', 'X\\'', 'b\\'', 'B\\'']);\r\nconst UNICODE_STRING_SPECIFIERS = new Set(['u&\\'', 'U&\\'']);\r\n\r\nexport class StringSpecifierTokenReader extends BaseTokenReader {\r\n\r\n /**\r\n * Try to read an escaped literal like e'...', x'...', etc.\r\n */\r\n public tryRead(previous: Lexeme | null): Lexeme | null {\r\n const start = this.position;\r\n\r\n // Check for prefixed literals: e', x', b'\r\n if (this.canRead(1) && STRING_SPECIFIERS.has(this.input.slice(start, start + 2))) {\r\n this.position += 1;\r\n const result = this.createLexeme(TokenType.StringSpecifier, this.input.slice(start, this.position));\r\n return result;\r\n }\r\n\r\n // Check for unicode literal: u&'\r\n if (this.canRead(2) && UNICODE_STRING_SPECIFIERS.has(this.input.slice(start, start + 3))) {\r\n this.position += 2;\r\n const result = this.createLexeme(TokenType.StringSpecifier, this.input.slice(start, this.position));\r\n return result;\r\n }\r\n\r\n return null;\r\n }\r\n}\r\n", "\uFEFFimport { BaseTokenReader } from './BaseTokenReader';\r\nimport { Lexeme, TokenType } from '../models/Lexeme';\r\nimport { StringUtils } from '../utils/stringUtils';\r\nimport { KeywordTrie } from '../models/KeywordTrie';\r\nimport { KeywordParser } from '../parsers/KeywordParser';\r\n\r\nconst trie = new KeywordTrie([\r\n [\"grouping\", \"sets\"],\r\n // ARRAY has special syntax with [] arguments, so it is forcibly treated as a function\r\n [\"array\"],\r\n]);\r\nconst keywordParser = new KeywordParser(trie);\r\n\r\n/**\r\n * Reads SQL identifier tokens\r\n */\r\nexport class FunctionTokenReader extends BaseTokenReader {\r\n /**\r\n * Try to read an identifier token\r\n */\r\n public tryRead(previous: Lexeme | null): Lexeme | null {\r\n if (this.isEndOfInput()) {\r\n return null;\r\n }\r\n\r\n // Check for keyword identifiers\r\n const keyword = keywordParser.parse(this.input, this.position);\r\n if (keyword !== null) {\r\n this.position = keyword.newPosition;\r\n return this.createLexeme(TokenType.Function, keyword.keyword);\r\n }\r\n\r\n // Regular identifier\r\n const result = StringUtils.tryReadRegularIdentifier(this.input, this.position);\r\n if (!result) {\r\n return null;\r\n }\r\n this.position = result.newPosition;\r\n\r\n // peek next token \r\n var shift = StringUtils.readWhiteSpaceAndComment(this.input, this.position).position - this.position;\r\n\r\n if (this.canRead(shift) && this.input[this.position + shift] === '(') {\r\n return this.createLexeme(TokenType.Function, result.identifier);\r\n }\r\n return null;\r\n }\r\n}\r\n", "\uFEFFimport { BaseTokenReader } from './BaseTokenReader';\r\nimport { Lexeme, TokenType } from '../models/Lexeme';\r\nimport { StringUtils } from '../utils/stringUtils';\r\nimport { KeywordTrie } from '../models/KeywordTrie';\r\nimport { KeywordParser } from '../parsers/KeywordParser';\r\n\r\n// Use KeywordTrie to identify type names composed of multiple words.\r\nconst trie = new KeywordTrie([\r\n // type\r\n [\"double\", \"precision\"],\r\n [\"character\", \"varying\"],\r\n [\"time\", \"without\", \"time\", \"zone\"],\r\n [\"time\", \"with\", \"time\", \"zone\"],\r\n [\"timestamp\", \"without\", \"time\", \"zone\"],\r\n [\"timestamp\", \"with\", \"time\", \"zone\"],\r\n]);\r\nconst typeParser = new KeywordParser(trie);\r\n\r\n/**\r\n * Reads SQL identifier tokens\r\n */\r\nexport class TypeTokenReader extends BaseTokenReader {\r\n /**\r\n * Try to read an identifier token\r\n */\r\n public tryRead(previous: Lexeme | null): Lexeme | null {\r\n if (this.isEndOfInput()) {\r\n return null;\r\n }\r\n\r\n // Check for keyword identifiers\r\n const keyword = typeParser.parse(this.input, this.position);\r\n if (keyword !== null) {\r\n this.position = keyword.newPosition;\r\n return this.createLexeme(TokenType.Type, keyword.keyword);\r\n }\r\n\r\n // check pervious token\r\n if (previous === null) {\r\n return null;\r\n }\r\n\r\n const result = StringUtils.tryReadRegularIdentifier(this.input, this.position);\r\n if (!result) {\r\n return null;\r\n }\r\n this.position = result.newPosition;\r\n\r\n // type cast command\r\n if (previous.type & TokenType.Command && previous.value === \"as\") {\r\n // If the previous token is the `as` keyword, it could be a type cast or an identifier\r\n return this.createLexeme(TokenType.Identifier | TokenType.Type, result.identifier);\r\n }\r\n\r\n // postgres type conversion\r\n if (previous.type & TokenType.Operator && previous.value === \"::\") {\r\n return this.createLexeme(TokenType.Type, result.identifier);\r\n }\r\n\r\n return null;\r\n }\r\n}\r\n", "import { BaseTokenReader } from './BaseTokenReader';\r\nimport { Lexeme, TokenType } from '../models/Lexeme';\r\nimport { StringUtils } from '../utils/stringUtils';\r\n\r\n/**\r\n * Reads SQL identifier tokens\r\n */\r\nexport class EscapedIdentifierTokenReader extends BaseTokenReader {\r\n /**\r\n * Try to read an identifier token\r\n */\r\n public tryRead(previous: Lexeme | null): Lexeme | null {\r\n if (this.isEndOfInput()) {\r\n return null;\r\n }\r\n\r\n const char = this.input[this.position];\r\n\r\n // MySQL escaped identifier (escape character is backtick)\r\n if (char === '`') {\r\n const identifier = this.readEscapedIdentifier('`');\r\n return this.createLexeme(TokenType.Identifier, identifier);\r\n }\r\n\r\n // Postgres escaped identifier (escape character is double quote)\r\n if (char === '\"') {\r\n const identifier = this.readEscapedIdentifier('\"');\r\n return this.createLexeme(TokenType.Identifier, identifier);\r\n }\r\n\r\n // SQLServer escaped identifier (escape character is square bracket)\r\n if (char === '[' && (previous === null || previous.value !== \"array\")) {\r\n const identifier = this.readEscapedIdentifier(']');\r\n return this.createLexeme(TokenType.Identifier, identifier);\r\n }\r\n\r\n return null;\r\n }\r\n\r\n /**\r\n * Read an escaped identifier (surrounded by delimiters)\r\n */\r\n private readEscapedIdentifier(delimiter: string): string {\r\n const start = this.position;\r\n\r\n // Skip the opening delimiter\r\n this.position++;\r\n\r\n while (this.canRead()) {\r\n if (this.input[this.position] === delimiter) {\r\n break;\r\n }\r\n this.position++;\r\n }\r\n\r\n if (start === this.position) {\r\n throw new Error(`Closing delimiter is not found. position: ${start}, delimiter: ${delimiter}\\n${this.getDebugPositionInfo(start)}`);\r\n }\r\n\r\n // Skip the closing delimiter\r\n this.position++;\r\n\r\n // exclude the delimiter\r\n return this.input.slice(start + 1, this.position - 1);\r\n }\r\n}\r\n", "\uFEFFimport { Lexeme, TokenType } from '../models/Lexeme';\r\nimport { IdentifierTokenReader } from '../tokenReaders/IdentifierTokenReader';\r\nimport { LiteralTokenReader } from '../tokenReaders/LiteralTokenReader';\r\nimport { ParameterTokenReader } from '../tokenReaders/ParameterTokenReader';\r\nimport { SpecialSymbolTokenReader } from '../tokenReaders/SymbolTokenReader';\r\nimport { TokenReaderManager } from '../tokenReaders/TokenReaderManager';\r\nimport { OperatorTokenReader } from '../tokenReaders/OperatorTokenReader';\r\nimport { StringUtils } from '../utils/stringUtils';\r\nimport { CommandTokenReader } from '../tokenReaders/CommandTokenReader';\r\nimport { StringSpecifierTokenReader } from '../tokenReaders/StringSpecifierTokenReader';\r\nimport { FunctionTokenReader } from '../tokenReaders/FunctionTokenReader';\r\nimport { TypeTokenReader } from '../tokenReaders/TypeTokenReader';\r\nimport { EscapedIdentifierTokenReader } from '../tokenReaders/EscapedIdentifierTokenReader';\r\n\r\n/**\r\n * Class responsible for tokenizing SQL input.\r\n */\r\nexport class SqlTokenizer {\r\n /**\r\n * The input SQL string to be tokenized.\r\n */\r\n private input: string;\r\n\r\n /**\r\n * Current position within the input string.\r\n */\r\n private position: number;\r\n\r\n /**\r\n * Manager responsible for handling token readers.\r\n */\r\n private readerManager: TokenReaderManager;\r\n\r\n /**\r\n * Initializes a new instance of the SqlTokenizer.\r\n */\r\n constructor(input: string) {\r\n this.input = input;\r\n this.position = 0;\r\n\r\n // Initialize the token reader manager and register all readers\r\n this.readerManager = new TokenReaderManager(input)\r\n .register(new EscapedIdentifierTokenReader(input))\r\n .register(new ParameterTokenReader(input))\r\n .register(new StringSpecifierTokenReader(input))\r\n // LiteralTokenReader should be registered before SpecialSymbolTokenReader and OperatorTokenReader\r\n // Reason: To prevent numeric literals starting with a dot or sign from being misrecognized as operators\r\n // e.g. `1.0` is a literal, not an operator\r\n .register(new LiteralTokenReader(input))\r\n .register(new SpecialSymbolTokenReader(input))\r\n .register(new CommandTokenReader(input))\r\n .register(new OperatorTokenReader(input))\r\n // TypeTokenReader should be registered before FunctionTokenReader\r\n // Reason: To prevent types containing parentheses from being misrecognized as functions\r\n // e.g. `numeric(10, 2)` is a type, not a function\r\n .register(new TypeTokenReader(input))\r\n .register(new FunctionTokenReader(input))\r\n .register(new IdentifierTokenReader(input)) // IdentifierTokenReader should be registered last\r\n ;\r\n }\r\n\r\n /**\r\n * Checks if the end of input is reached.\r\n * \r\n * @param shift - The shift to consider beyond the current position.\r\n * @returns True if the end of input is reached; otherwise, false.\r\n */\r\n private isEndOfInput(shift: number = 0): boolean {\r\n return this.position + shift >= this.input.length;\r\n }\r\n\r\n /**\r\n * Checks if more input can be read.\r\n * \r\n * @param shift - The shift to consider beyond the current position.\r\n * @returns True if more input can be read; otherwise, false.\r\n */\r\n private canRead(shift: number = 0): boolean {\r\n return !this.isEndOfInput(shift);\r\n }\r\n\r\n /**\r\n * Reads the lexemes from the input string.\r\n * \r\n * @returns An array of lexemes extracted from the input string.\r\n * @throws Error if an unexpected character is encountered.\r\n */\r\n public readLexmes(): Lexeme[] {\r\n // Pre-allocate array with estimated capacity for better performance\r\n const estimatedTokens = Math.ceil(this.input.length / 8); // Assuming average token length of 8 chars\r\n const lexemes: Lexeme[] = new Array(estimatedTokens);\r\n let lexemeCount = 0;\r\n\r\n // Read initial prefix comments\r\n const comment = this.readComment();\r\n let pendingComments = comment.lines;\r\n this.position = comment.position;\r\n\r\n // Track the previous token\r\n let previous: Lexeme | null = null;\r\n\r\n // Read tokens until the end of input is reached\r\n while (this.canRead()) {\r\n // Semicolon is a delimiter, so stop reading\r\n if (this.input[this.position] === ';') {\r\n break;\r\n }\r\n\r\n // Read using the token reader manager\r\n const lexeme = this.readerManager.tryRead(this.position, previous);\r\n\r\n if (lexeme === null) {\r\n throw new Error(`Unexpected character. actual: ${this.input[this.position]}, position: ${this.position}\\n${this.getDebugPositionInfo(this.position)}`);\r\n }\r\n\r\n // Update position\r\n this.position = this.readerManager.getMaxPosition();\r\n\r\n // Read suffix comments\r\n const currentComment = this.readComment();\r\n this.position = currentComment.position;\r\n\r\n if ((lexeme.type & TokenType.Comma) || (lexeme.type & TokenType.Operator)) {\r\n // Carry over comments after commas or operators\r\n if (currentComment.lines.length > 0) {\r\n pendingComments.push(...currentComment.lines);\r\n }\r\n } else {\r\n // Add comments to the current token if any\r\n const hasComments = pendingComments.length > 0 || currentComment.lines.length > 0;\r\n if (hasComments) {\r\n this.addCommentsToToken(lexeme, pendingComments, currentComment.lines);\r\n }\r\n pendingComments = []; // Clear as they are processed\r\n }\r\n\r\n lexemes[lexemeCount++] = lexeme;\r\n previous = lexeme;\r\n }\r\n\r\n // Add any pending comments to the last token\r\n if (pendingComments.length > 0 && lexemeCount > 0) {\r\n const lastToken = lexemes[lexemeCount - 1];\r\n if (lastToken.comments === null) {\r\n lastToken.comments = [];\r\n }\r\n lastToken.comments.push(...pendingComments);\r\n }\r\n\r\n // Trim the array to actual size used\r\n return lexemeCount === estimatedTokens ? lexemes : lexemes.slice(0, lexemeCount);\r\n }\r\n\r\n /**\r\n * Adds pending comments to the last token.\r\n */\r\n private addPendingCommentsToLastToken(lexemes: Lexeme[], pendingComments: string[]): void {\r\n if (pendingComments.length > 0 && lexemes.length > 0) {\r\n const lastToken = lexemes[lexemes.length - 1];\r\n if (lastToken.comments === null) {\r\n lastToken.comments = [];\r\n }\r\n lastToken.comments.push(...pendingComments);\r\n }\r\n }\r\n\r\n /**\r\n * Adds comments to the token.\r\n */\r\n private addCommentsToToken(lexeme: Lexeme, prefixComments: string[], suffixComments: string[]): void {\r\n const hasComments = prefixComments.length > 0 || suffixComments.length > 0;\r\n\r\n if (hasComments) {\r\n if (lexeme.comments === null) {\r\n lexeme.comments = [];\r\n }\r\n\r\n // Add prefix comments to the beginning.\r\n if (prefixComments.length > 0) {\r\n lexeme.comments.unshift(...prefixComments);\r\n }\r\n\r\n // Add suffix comments to the end.\r\n if (suffixComments.length > 0) {\r\n lexeme.comments.push(...suffixComments);\r\n }\r\n }\r\n }\r\n\r\n /**\r\n * Skips whitespace characters and SQL comments in the input.\r\n * \r\n * @remarks This method updates the position pointer.\r\n */\r\n private readComment(): { position: number, lines: string[] } {\r\n return StringUtils.readWhiteSpaceAndComment(this.input, this.position);\r\n }\r\n\r\n /**\r\n * Gets debug information for error reporting.\r\n * \r\n * @param errPosition - The position where the error occurred.\r\n * @returns A string containing the debug position information.\r\n */\r\n private getDebugPositionInfo(errPosition: number): string {\r\n return StringUtils.getDebugPositionInfo(this.input, errPosition);\r\n }\r\n}\r\n", "import { Lexeme, TokenType } from \"../models/Lexeme\";\r\nimport { IdentifierString } from \"../models/ValueComponent\";\r\nimport { SqlTokenizer } from \"./SqlTokenizer\";\r\n\r\n/**\r\n * Utility class for parsing fully qualified names (e.g. db.schema.table or db.schema.table.column_name)\r\n * This can be used for both table and column references.\r\n */\r\nexport class FullNameParser {\r\n /**\r\n * Parses a fully qualified name from lexemes, returning namespaces, table, and new index.\r\n */\r\n public static parseFromLexeme(lexemes: Lexeme[], index: number): { namespaces: string[] | null, name: IdentifierString, newIndex: number, lastTokenType: number } {\r\n const { identifiers, newIndex } = FullNameParser.parseEscapedOrDotSeparatedIdentifiers(lexemes, index);\r\n const { namespaces, name } = FullNameParser.extractNamespacesAndName(identifiers);\r\n // Returns the type of the last token in the identifier sequence\r\n let lastTokenType = 0;\r\n if (newIndex > index) {\r\n lastTokenType = lexemes[newIndex - 1].type;\r\n }\r\n return { namespaces, name: new IdentifierString(name), newIndex, lastTokenType };\r\n }\r\n\r\n /**\r\n * Parses a fully qualified name from a string (e.g. 'db.schema.table')\r\n * Returns { namespaces, name }\r\n */\r\n public static parse(str: string): { namespaces: string[] | null, name: IdentifierString } {\r\n const tokenizer = new SqlTokenizer(str);\r\n const lexemes = tokenizer.readLexmes();\r\n const result = this.parseFromLexeme(lexemes, 0);\r\n if (result.newIndex < lexemes.length) {\r\n // Use a context-agnostic error message since FullNameParser is used in multiple query types\r\n throw new Error(`Syntax error: Unexpected token \"${lexemes[result.newIndex].value}\" at position ${result.newIndex}. The name is complete but additional tokens were found.`);\r\n }\r\n return { namespaces: result.namespaces, name: result.name };\r\n }\r\n\r\n // Parses SQL Server-style escaped identifiers ([table]) and dot-separated identifiers, including namespaced wildcards (e.g., db.schema.*, [db].[schema].*)\r\n private static parseEscapedOrDotSeparatedIdentifiers(lexemes: Lexeme[], index: number): { identifiers: string[]; newIndex: number } {\r\n let idx = index;\r\n const identifiers: string[] = [];\r\n while (idx < lexemes.length) {\r\n if (lexemes[idx].type & TokenType.OpenBracket) {\r\n idx++; // skip [\r\n if (idx >= lexemes.length || !((lexemes[idx].type & TokenType.Identifier) || (lexemes[idx].type & TokenType.Command))) {\r\n throw new Error(`Expected identifier after '[' at position ${idx}`);\r\n }\r\n identifiers.push(lexemes[idx].value);\r\n idx++;\r\n if (idx >= lexemes.length || lexemes[idx].value !== \"]\") {\r\n throw new Error(`Expected closing ']' after identifier at position ${idx}`);\r\n }\r\n idx++; // skip ]\r\n } else if (lexemes[idx].type & TokenType.Identifier) {\r\n identifiers.push(lexemes[idx].value);\r\n idx++;\r\n } else if (lexemes[idx].type & TokenType.Function) {\r\n identifiers.push(lexemes[idx].value);\r\n idx++;\r\n } else if (lexemes[idx].type & TokenType.Type) {\r\n identifiers.push(lexemes[idx].value);\r\n idx++;\r\n } else if (lexemes[idx].value === \"*\") {\r\n // The wildcard '*' is always treated as the terminal part of a qualified name in SQL (e.g., db.schema.* or [db].[schema].*).\r\n // No valid SQL syntax allows a wildcard in the middle of a multi-part name.\r\n identifiers.push(lexemes[idx].value);\r\n idx++;\r\n break;\r\n }\r\n // Handle dot for schema.table or db.schema.table\r\n if (idx < lexemes.length && (lexemes[idx].type & TokenType.Dot)) {\r\n idx++; // skip dot\r\n } else {\r\n break;\r\n }\r\n }\r\n return { identifiers, newIndex: idx };\r\n }\r\n\r\n // Utility to extract namespaces and the final name from an array of identifiers\r\n // Example: [\"db\", \"schema\", \"users\"] => { namespaces: [\"db\", \"schema\"], name: \"users\" }\r\n private static extractNamespacesAndName(identifiers: string[]): { namespaces: string[] | null, name: string } {\r\n if (!identifiers || identifiers.length === 0) {\r\n throw new Error(\"Identifier list is empty\");\r\n }\r\n if (identifiers.length === 1) {\r\n return { namespaces: null, name: identifiers[0] };\r\n }\r\n return { namespaces: identifiers.slice(0, -1), name: identifiers[identifiers.length - 1] };\r\n }\r\n}\r\n", "import { FullNameParser } from \"./FullNameParser\";\r\nimport { Lexeme } from \"../models/Lexeme\";\r\nimport { ColumnReference, ValueComponent } from \"../models/ValueComponent\";\r\n\r\nexport class IdentifierParser {\r\n public static parseFromLexeme(lexemes: Lexeme[], index: number): { value: ValueComponent; newIndex: number } {\r\n // Use FullNameParser to robustly parse qualified identifiers, including wildcards and escaped names.\r\n const { namespaces, name, newIndex } = FullNameParser.parseFromLexeme(lexemes, index);\r\n const value = new ColumnReference(namespaces, name);\r\n return { value, newIndex };\r\n }\r\n}", "import { Lexeme } from \"../models/Lexeme\";\r\nimport { LiteralValue, RawString, ValueComponent } from \"../models/ValueComponent\";\r\nimport { literalKeywordParser } from \"../tokenReaders/LiteralTokenReader\";\r\n\r\nexport class LiteralParser {\r\n public static parseFromLexeme(lexemes: Lexeme[], index: number): { value: ValueComponent; newIndex: number } {\r\n // Process literal value\r\n let idx = index;\r\n const valueText = lexemes[idx].value;\r\n let parsedValue: string | number | boolean | null;\r\n\r\n const lex = literalKeywordParser.parse(valueText.toLowerCase(), 0);\r\n if (lex) {\r\n const value = new RawString(lex.keyword);\r\n idx++\r\n return { value, newIndex: idx };\r\n }\r\n\r\n // Check if it is a number\r\n if (/^[+-]?\\d+(\\.\\d+)?([eE][+-]?\\d+)?$/.test(valueText)) {\r\n parsedValue = Number(valueText);\r\n }\r\n // Otherwise, treat it as a string\r\n else {\r\n // Remove single quotes if enclosed\r\n if (valueText.startsWith(\"'\") && valueText.endsWith(\"'\")) {\r\n parsedValue = valueText.slice(1, -1);\r\n } else {\r\n parsedValue = valueText;\r\n }\r\n }\r\n idx++\r\n const value = new LiteralValue(parsedValue);\r\n return { value, newIndex: idx };\r\n }\r\n}", "import { Lexeme, TokenType } from \"../models/Lexeme\";\r\nimport { InlineQuery, ParenExpression, ValueComponent } from \"../models/ValueComponent\";\r\nimport { SelectQueryParser } from \"./SelectQueryParser\";\r\nimport { ValueParser } from \"./ValueParser\";\r\n\r\nexport class ParenExpressionParser {\r\n public static parseFromLexeme(lexemes: Lexeme[], index: number): { value: ValueComponent; newIndex: number } {\r\n let idx = index;\r\n\r\n // check inline query\r\n if (idx + 1 < lexemes.length && lexemes[idx].type & TokenType.OpenParen && (\r\n lexemes[idx + 1].value === \"select\" || lexemes[idx + 1].value === \"values\" || lexemes[idx + 1].value === \"with\"\r\n )) {\r\n idx += 1; // Skip the '(' token\r\n const result = SelectQueryParser.parseFromLexeme(lexemes, idx);\r\n idx = result.newIndex;\r\n\r\n // Check for closing parenthesis\r\n if (idx >= lexemes.length || lexemes[idx].type !== TokenType.CloseParen) {\r\n throw new Error(`Expected ')' at index ${idx}, but found ${lexemes[idx].value}`);\r\n }\r\n idx++; // Skip the ')' token\r\n\r\n const value = new InlineQuery(result.value);\r\n return { value, newIndex: idx };\r\n } else {\r\n const result = ValueParser.parseArgument(TokenType.OpenParen, TokenType.CloseParen, lexemes, index);\r\n idx = result.newIndex;\r\n\r\n const value = new ParenExpression(result.value);\r\n return { value, newIndex: idx };\r\n }\r\n }\r\n}", "import { Lexeme, TokenType } from \"../models/Lexeme\";\r\nimport { ColumnReference, IdentifierString, UnaryExpression, ValueComponent } from \"../models/ValueComponent\";\r\nimport { ValueParser } from \"./ValueParser\";\r\n\r\nexport class UnaryExpressionParser {\r\n public static parseFromLexeme(lexemes: Lexeme[], index: number): { value: ValueComponent; newIndex: number } {\r\n let idx = index;\r\n\r\n // Process unary operator\r\n if (idx < lexemes.length && (lexemes[idx].type & TokenType.Operator)) {\r\n const operator = lexemes[idx].value;\r\n idx++;\r\n\r\n // Treat the asterisk as an Identifier, not as a unary operator\r\n if (operator === '*') {\r\n const v = new ColumnReference(null, '*');\r\n return { value: v, newIndex: idx };\r\n }\r\n\r\n // Get the right-hand side value of the unary operator\r\n const result = ValueParser.parseFromLexeme(lexemes, idx);\r\n idx = result.newIndex;\r\n\r\n // Create unary expression\r\n const value = new UnaryExpression(operator, result.value);\r\n return { value, newIndex: idx };\r\n }\r\n\r\n throw new Error(`Invalid unary expression at index ${index}: ${lexemes[index].value}`);\r\n }\r\n}", "import { Lexeme } from \"../models/Lexeme\";\r\nimport { ParameterExpression, ValueComponent } from \"../models/ValueComponent\";\r\n\r\nexport class ParameterExpressionParser {\r\n public static parseFromLexeme(lexemes: Lexeme[], index: number): { value: ValueComponent; newIndex: number } {\r\n let idx = index;\r\n let paramName = lexemes[idx].value;\r\n\r\n // Normalize parameter: Remove the parameter symbol and extract the parameter name.\r\n if (paramName.startsWith('${') && paramName.endsWith('}')) {\r\n // ${name} \u2192 name\r\n paramName = paramName.slice(2, -1);\r\n } else {\r\n // :name \u2192 name\r\n paramName = paramName.slice(1);\r\n }\r\n\r\n const value = new ParameterExpression(paramName);\r\n idx++;\r\n return { value, newIndex: idx };\r\n }\r\n}", "import { Lexeme, TokenType } from \"../models/Lexeme\";\r\nimport { StringSpecifierExpression, ValueComponent } from \"../models/ValueComponent\";\r\n\r\nexport class StringSpecifierExpressionParser {\r\n public static parseFromLexeme(lexemes: Lexeme[], index: number): { value: ValueComponent; newIndex: number } {\r\n let idx = index;\r\n const specifer = lexemes[idx].value;\r\n idx++;\r\n if (idx >= lexemes.length || lexemes[idx].type !== TokenType.Literal) {\r\n throw new Error(`Expected string literal after string specifier at index ${idx}`);\r\n }\r\n const value = lexemes[idx].value;\r\n idx++;\r\n // Create StringSpecifierExpression\r\n const result = new StringSpecifierExpression(specifer, value);\r\n\r\n return { value: result, newIndex: idx };\r\n }\r\n}", "import { Lexeme, TokenType } from \"../models/Lexeme\";\r\nimport { ArrayExpression, CaseExpression, CaseKeyValuePair, SwitchCaseArgument, UnaryExpression, ValueComponent } from \"../models/ValueComponent\";\r\nimport { ValueParser } from \"./ValueParser\";\r\n\r\nexport class CommandExpressionParser {\r\n public static parseFromLexeme(lexemes: Lexeme[], index: number): { value: ValueComponent; newIndex: number } {\r\n let idx = index;\r\n const current = lexemes[idx];\r\n if (current.value === \"case\") {\r\n idx++;\r\n return this.parseCaseExpression(lexemes, idx);\r\n } else if (current.value === \"case when\") {\r\n idx++;\r\n return this.parseCaseWhenExpression(lexemes, idx);\r\n }\r\n\r\n return this.parseModifierUnaryExpression(lexemes, idx);\r\n }\r\n\r\n private static parseModifierUnaryExpression(lexemes: Lexeme[], index: number): { value: ValueComponent; newIndex: number; } {\r\n let idx = index;\r\n // Check for modifier unary expression\r\n if (idx < lexemes.length && (lexemes[idx].type & TokenType.Command)) {\r\n const command = lexemes[idx].value;\r\n idx++;\r\n const result = ValueParser.parseFromLexeme(lexemes, idx);\r\n return { value: new UnaryExpression(command!, result.value), newIndex: result.newIndex };\r\n }\r\n throw new Error(`Invalid modifier unary expression at index ${idx}, Lexeme: ${lexemes[idx].value}`);\r\n }\r\n\r\n private static parseCaseExpression(lexemes: Lexeme[], index: number): { value: ValueComponent; newIndex: number; } {\r\n let idx = index;\r\n const condition = ValueParser.parseFromLexeme(lexemes, idx);\r\n idx = condition.newIndex;\r\n\r\n const switchCaseResult = this.parseSwitchCaseArgument(lexemes, idx, []);\r\n idx = switchCaseResult.newIndex;\r\n\r\n // Create CASE expression\r\n const result = new CaseExpression(condition.value, switchCaseResult.value);\r\n return { value: result, newIndex: idx };\r\n }\r\n\r\n private static parseCaseWhenExpression(lexemes: Lexeme[], index: number): { value: ValueComponent; newIndex: number; } {\r\n let idx = index;\r\n\r\n // Parse the first WHEN clause\r\n const casewhenResult = this.parseCaseConditionValuePair(lexemes, idx);\r\n idx = casewhenResult.newIndex;\r\n\r\n // Add the initial WHEN-THEN pair to the list\r\n const caseWhenList = [casewhenResult.value];\r\n\r\n // Process remaining WHEN-ELSE-END parts\r\n const switchCaseResult = this.parseSwitchCaseArgument(lexemes, idx, caseWhenList);\r\n idx = switchCaseResult.newIndex;\r\n\r\n // Create CASE expression with condition null (uses WHEN conditions instead of a simple CASE)\r\n const result = new CaseExpression(null, switchCaseResult.value);\r\n return { value: result, newIndex: idx };\r\n }\r\n\r\n // parseSwitchCaseArgument method processes the WHEN, ELSE, and END clauses of a CASE expression.\r\n private static parseSwitchCaseArgument(\r\n lexemes: Lexeme[],\r\n index: number,\r\n initialWhenThenList: CaseKeyValuePair[]\r\n ): { value: SwitchCaseArgument; newIndex: number; } {\r\n let idx = index;\r\n const whenThenList = [...initialWhenThenList];\r\n let elseValue = null;\r\n\r\n // Process WHEN clauses\r\n while (idx < lexemes.length && this.isCommandWithValue(lexemes[idx], \"when\")) {\r\n idx++;\r\n const whenResult = this.parseCaseConditionValuePair(lexemes, idx);\r\n idx = whenResult.newIndex;\r\n whenThenList.push(whenResult.value);\r\n }\r\n\r\n // Process ELSE\r\n if (idx < lexemes.length && this.isCommandWithValue(lexemes[idx], \"else\")) {\r\n idx++;\r\n const elseResult = ValueParser.parseFromLexeme(lexemes, idx);\r\n elseValue = elseResult.value;\r\n idx = elseResult.newIndex;\r\n }\r\n\r\n // Process END\r\n if (idx < lexemes.length && this.isCommandWithValue(lexemes[idx], \"end\")) {\r\n idx++;\r\n } else {\r\n throw new Error(`The CASE expression requires 'end' keyword at the end (index ${idx})`);\r\n }\r\n\r\n if (whenThenList.length === 0) {\r\n throw new Error(`The CASE expression requires at least one WHEN clause (index ${idx})`);\r\n }\r\n\r\n // Create SwitchCaseArgument\r\n const value = new SwitchCaseArgument(whenThenList, elseValue);\r\n return { value, newIndex: idx };\r\n }\r\n\r\n // Helper method: Check if a lexeme is a Command token with the specified value\r\n private static isCommandWithValue(lexeme: Lexeme, value: string): boolean {\r\n return ((lexeme.type & TokenType.Command) !== 0) && lexeme.value === value;\r\n }\r\n\r\n private static parseCaseConditionValuePair(lexemes: Lexeme[], index: number): { value: CaseKeyValuePair; newIndex: number; } {\r\n let idx = index;\r\n const condition = ValueParser.parseFromLexeme(lexemes, idx);\r\n idx = condition.newIndex;\r\n\r\n // Check for the existence of the THEN keyword\r\n if (idx >= lexemes.length || !(lexemes[idx].type & TokenType.Command) || lexemes[idx].value !== \"then\") {\r\n throw new Error(`Expected 'then' after WHEN condition at index ${idx}`);\r\n }\r\n idx++; // Skip the THEN keyword\r\n\r\n // Parse the value after THEN\r\n const value = ValueParser.parseFromLexeme(lexemes, idx);\r\n idx = value.newIndex;\r\n\r\n return { value: new CaseKeyValuePair(condition.value, value.value), newIndex: idx };\r\n }\r\n}", "import { NullsSortDirection, OrderByClause, OrderByComponent, OrderByItem, SortDirection } from \"../models/Clause\";\r\nimport { Lexeme, TokenType } from \"../models/Lexeme\";\r\nimport { SqlTokenizer } from \"./SqlTokenizer\";\r\nimport { ValueParser } from \"./ValueParser\";\r\n\r\nexport class OrderByClauseParser {\r\n // Parse SQL string to AST (was: parse)\r\n public static parse(query: string): OrderByClause {\r\n const tokenizer = new SqlTokenizer(query); // Initialize tokenizer\r\n const lexemes = tokenizer.readLexmes(); // Get tokens\r\n\r\n // Parse\r\n const result = this.parseFromLexeme(lexemes, 0);\r\n\r\n // Error if there are remaining tokens\r\n if (result.newIndex < lexemes.length) {\r\n throw new Error(`Syntax error: Unexpected token \"${lexemes[result.newIndex].value}\" at position ${result.newIndex}. The ORDER BY clause is complete but there are additional tokens.`);\r\n }\r\n\r\n return result.value;\r\n }\r\n\r\n // Parse from lexeme array (was: parse)\r\n public static parseFromLexeme(lexemes: Lexeme[], index: number): { value: OrderByClause; newIndex: number } {\r\n let idx = index;\r\n\r\n if (lexemes[idx].value !== 'order by') {\r\n throw new Error(`Syntax error at position ${idx}: Expected 'ORDER BY' keyword but found \"${lexemes[idx].value}\". ORDER BY clauses must start with the ORDER BY keywords.`);\r\n }\r\n idx++;\r\n\r\n const items: OrderByComponent[] = [];\r\n const item = this.parseItem(lexemes, idx);\r\n items.push(item.value);\r\n idx = item.newIndex;\r\n\r\n while (idx < lexemes.length && (lexemes[idx].type & TokenType.Comma)) {\r\n idx++;\r\n const item = this.parseItem(lexemes, idx);\r\n items.push(item.value);\r\n idx = item.newIndex;\r\n }\r\n\r\n if (items.length === 0) {\r\n throw new Error(`Syntax error at position ${index}: No ordering expressions found. The ORDER BY clause requires at least one expression to order by.`);\r\n } else {\r\n const clause = new OrderByClause(items);\r\n return { value: clause, newIndex: idx };\r\n }\r\n }\r\n\r\n private static parseItem(lexemes: Lexeme[], index: number): { value: OrderByComponent; newIndex: number } {\r\n let idx = index;\r\n const parsedValue = ValueParser.parseFromLexeme(lexemes, idx);\r\n const value = parsedValue.value;\r\n idx = parsedValue.newIndex;\r\n if (idx >= lexemes.length) {\r\n return { value: value, newIndex: idx };\r\n }\r\n\r\n // asc, desc\r\n const sortDirection = idx >= lexemes.length\r\n ? null\r\n : lexemes[idx].value === 'asc'\r\n ? (idx++, SortDirection.Ascending)\r\n : lexemes[idx].value === 'desc'\r\n ? (idx++, SortDirection.Descending)\r\n : null;\r\n\r\n // nulls first, nulls last\r\n const nullsSortDirection = idx >= lexemes.length\r\n ? null\r\n : lexemes[idx].value === 'nulls first'\r\n ? (idx++, NullsSortDirection.First)\r\n : lexemes[idx].value === 'nulls last'\r\n ? (idx++, NullsSortDirection.Last)\r\n : null;\r\n\r\n if (sortDirection === null && nullsSortDirection === null) {\r\n return { value: value, newIndex: idx };\r\n }\r\n\r\n return { value: new OrderByItem(value, sortDirection, nullsSortDirection), newIndex: idx };\r\n }\r\n}\r\n", "import { PartitionByClause } from \"../models/Clause\";\r\nimport { Lexeme, TokenType } from \"../models/Lexeme\";\r\nimport { ValueComponent, ValueList } from \"../models/ValueComponent\";\r\nimport { SqlTokenizer } from \"./SqlTokenizer\";\r\nimport { ValueParser } from \"./ValueParser\";\r\n\r\nexport class PartitionByParser {\r\n // Parse SQL string to AST (was: parse)\r\n public static parse(query: string): PartitionByClause {\r\n const tokenizer = new SqlTokenizer(query); // Initialize tokenizer\r\n const lexemes = tokenizer.readLexmes(); // Get tokens\r\n\r\n // Parse\r\n const result = this.parseFromLexeme(lexemes, 0);\r\n\r\n // Error if there are remaining tokens\r\n if (result.newIndex < lexemes.length) {\r\n throw new Error(`Syntax error: Unexpected token \"${lexemes[result.newIndex].value}\" at position ${result.newIndex}. The PARTITION BY clause is complete but there are additional tokens.`);\r\n }\r\n\r\n return result.value;\r\n }\r\n\r\n // Parse from lexeme array (was: parse)\r\n public static parseFromLexeme(lexemes: Lexeme[], index: number): { value: PartitionByClause; newIndex: number } {\r\n let idx = index;\r\n if (lexemes[idx].value !== 'partition by') {\r\n throw new Error(`Syntax error at position ${idx}: Expected 'PARTITION BY' keyword but found \"${lexemes[idx].value}\". PARTITION BY clauses must start with the PARTITION BY keywords.`);\r\n }\r\n idx++;\r\n const items: ValueComponent[] = [];\r\n const item = ValueParser.parseFromLexeme(lexemes, idx);\r\n items.push(item.value);\r\n idx = item.newIndex;\r\n while (idx < lexemes.length && (lexemes[idx].type & TokenType.Comma)) {\r\n idx++;\r\n const item = ValueParser.parseFromLexeme(lexemes, idx);\r\n items.push(item.value);\r\n idx = item.newIndex;\r\n }\r\n if (items.length === 0) {\r\n throw new Error(`Syntax error at position ${index}: No partition expressions found. The PARTITION BY clause requires at least one expression to partition by.`);\r\n } else if (items.length === 1) {\r\n const clause = new PartitionByClause(items[0]);\r\n return { value: clause, newIndex: idx };\r\n } else {\r\n const clause = new PartitionByClause(new ValueList(items));\r\n return { value: clause, newIndex: idx };\r\n }\r\n }\r\n}\r\n", "import { OrderByClause, PartitionByClause } from \"../models/Clause\";\r\nimport { Lexeme, TokenType } from \"../models/Lexeme\";\r\nimport { WindowFrameBound, WindowFrameBoundaryValue, FrameBoundaryComponent, WindowFrameExpression, WindowFrameSpec, WindowFrameType, WindowFrameBoundStatic } from \"../models/ValueComponent\";\r\nimport { OrderByClauseParser } from \"./OrderByClauseParser\";\r\nimport { PartitionByParser } from \"./PartitionByParser\";\r\nimport { SqlTokenizer } from \"./SqlTokenizer\";\r\nimport { ValueParser } from \"./ValueParser\";\r\n\r\nexport class WindowExpressionParser {\r\n // Parse SQL string to AST (was: parse)\r\n public static parse(query: string): WindowFrameExpression {\r\n const tokenizer = new SqlTokenizer(query); // Initialize tokenizer\r\n const lexemes = tokenizer.readLexmes(); // Get tokens\r\n\r\n // Parse\r\n const result = this.parseFromLexeme(lexemes, 0);\r\n\r\n // Error if there are remaining tokens\r\n if (result.newIndex < lexemes.length) {\r\n throw new Error(`Syntax error: Unexpected token \"${lexemes[result.newIndex].value}\" at position ${result.newIndex}. The window frame expression is complete but there are additional tokens.`);\r\n }\r\n\r\n return result.value;\r\n }\r\n\r\n // Parse from lexeme array (was: parse)\r\n public static parseFromLexeme(lexemes: Lexeme[], index: number): { value: WindowFrameExpression; newIndex: number } {\r\n let idx = index;\r\n if (lexemes[idx].type !== TokenType.OpenParen) {\r\n throw new Error(`Syntax error at position ${idx}: Expected opening parenthesis '(' but found \"${lexemes[idx].value}\".`);\r\n }\r\n idx++;\r\n let partition: PartitionByClause | null = null;\r\n let order: OrderByClause | null = null;\r\n let frameSpec: WindowFrameSpec | null = null;\r\n if (idx < lexemes.length && lexemes[idx].value === 'partition by') {\r\n const partitionResult = PartitionByParser.parseFromLexeme(lexemes, idx);\r\n partition = partitionResult.value;\r\n idx = partitionResult.newIndex;\r\n }\r\n if (idx < lexemes.length && lexemes[idx].value === 'order by') {\r\n const orderResult = OrderByClauseParser.parseFromLexeme(lexemes, idx);\r\n order = orderResult.value;\r\n idx = orderResult.newIndex;\r\n }\r\n // Parse frame clause (ROWS/RANGE/GROUPS)\r\n if (idx < lexemes.length && this.isFrameTypeKeyword(lexemes[idx].value)) {\r\n const frameSpecResult = this.parseFrameSpec(lexemes, idx);\r\n frameSpec = frameSpecResult.value;\r\n idx = frameSpecResult.newIndex;\r\n }\r\n if (idx >= lexemes.length || lexemes[idx].type !== TokenType.CloseParen) {\r\n throw new Error(`Syntax error at position ${idx}: Missing closing parenthesis ')' for window frame. Each opening parenthesis must have a matching closing parenthesis.`);\r\n }\r\n // Read close paren\r\n idx++;\r\n\r\n return { value: new WindowFrameExpression(partition, order, frameSpec), newIndex: idx };\r\n }\r\n\r\n private static isFrameTypeKeyword(value: string): boolean {\r\n const lowerValue = value;\r\n return lowerValue === 'rows' || lowerValue === 'range' || lowerValue === 'groups';\r\n }\r\n\r\n private static parseFrameSpec(lexemes: Lexeme[], index: number): { value: WindowFrameSpec; newIndex: number } {\r\n let idx = index;\r\n\r\n // Determine frame type (ROWS/RANGE/GROUPS)\r\n const frameTypeStr = lexemes[idx].value;\r\n let frameType: WindowFrameType;\r\n\r\n switch (frameTypeStr) {\r\n case 'rows':\r\n frameType = WindowFrameType.Rows;\r\n break;\r\n case 'range':\r\n frameType = WindowFrameType.Range;\r\n break;\r\n case 'groups':\r\n frameType = WindowFrameType.Groups;\r\n break;\r\n default:\r\n throw new Error(`Syntax error at position ${idx}: Invalid frame type \"${lexemes[idx].value}\". Expected one of: ROWS, RANGE, GROUPS.`);\r\n }\r\n idx++;\r\n\r\n // Check for BETWEEN ... AND ... syntax\r\n if (idx < lexemes.length && lexemes[idx].value === 'between') {\r\n // BETWEEN ... AND ... syntax\r\n idx++;\r\n\r\n // Parse start boundary\r\n const startBoundResult = this.parseFrameBoundary(lexemes, idx);\r\n const startBound = startBoundResult.value;\r\n idx = startBoundResult.newIndex;\r\n\r\n // Check for AND keyword - may be recognized as a separate token or part of a compound token\r\n if (idx >= lexemes.length || (lexemes[idx].value !== 'and')) {\r\n throw new Error(`Syntax error at position ${idx}: Expected 'AND' keyword in BETWEEN clause.`);\r\n }\r\n idx++; // Skip AND\r\n\r\n // Parse end boundary\r\n const endBoundResult = this.parseFrameBoundary(lexemes, idx);\r\n const endBound = endBoundResult.value;\r\n idx = endBoundResult.newIndex;\r\n\r\n return {\r\n value: new WindowFrameSpec(frameType, startBound, endBound),\r\n newIndex: idx\r\n };\r\n } else {\r\n // Single boundary specification\r\n const boundaryResult = this.parseFrameBoundary(lexemes, idx);\r\n const startBound = boundaryResult.value;\r\n idx = boundaryResult.newIndex;\r\n\r\n return {\r\n value: new WindowFrameSpec(frameType, startBound, null),\r\n newIndex: idx\r\n };\r\n }\r\n }\r\n\r\n private static parseFrameBoundary(lexemes: Lexeme[], index: number): { value: FrameBoundaryComponent, newIndex: number } {\r\n let idx = index;\r\n // Check for predefined boundaries\r\n if (idx < lexemes.length && (lexemes[idx].type & TokenType.Command)) {\r\n const currentValue = lexemes[idx].value;\r\n let frameBound: WindowFrameBound;\r\n switch (currentValue) {\r\n case 'current row':\r\n frameBound = WindowFrameBound.CurrentRow;\r\n break;\r\n case 'unbounded preceding':\r\n frameBound = WindowFrameBound.UnboundedPreceding;\r\n break;\r\n case 'unbounded following':\r\n frameBound = WindowFrameBound.UnboundedFollowing;\r\n break;\r\n default:\r\n throw new Error(`Syntax error at position ${idx}: Invalid frame type \"${lexemes[idx].value}\". Expected one of: ROWS, RANGE, GROUPS.`);\r\n }\r\n const bound = new WindowFrameBoundStatic(frameBound);\r\n return { value: bound, newIndex: idx + 1 };\r\n } else if (idx < lexemes.length && (lexemes[idx].type & TokenType.Literal)) {\r\n // Parse the numeric/literal value\r\n const valueResult = ValueParser.parseFromLexeme(lexemes, idx);\r\n idx = valueResult.newIndex;\r\n // Next token must be 'preceding' or 'following'\r\n if (idx < lexemes.length && (lexemes[idx].type & TokenType.Command)) {\r\n const direction = lexemes[idx].value;\r\n let isFollowing: boolean;\r\n if (direction === 'preceding') {\r\n isFollowing = false;\r\n } else if (direction === 'following') {\r\n isFollowing = true;\r\n } else {\r\n throw new Error(`Syntax error at position ${idx}: Expected 'preceding' or 'following' after numeric value in window frame boundary.`);\r\n }\r\n idx++;\r\n const bound = new WindowFrameBoundaryValue(valueResult.value, isFollowing);\r\n return { value: bound, newIndex: idx };\r\n } else {\r\n throw new Error(`Syntax error at position ${idx}: Expected 'preceding' or 'following' after numeric value in window frame boundary.`);\r\n }\r\n }\r\n throw new Error(`Syntax error at position ${idx}: Expected a valid frame boundary component.`);\r\n }\r\n}", "import { Lexeme, TokenType } from \"../models/Lexeme\";\r\nimport { IdentifierString, OverExpression } from \"../models/ValueComponent\";\r\nimport { SqlTokenizer } from \"./SqlTokenizer\";\r\nimport { WindowExpressionParser } from \"./WindowExpressionParser\";\r\n\r\nexport class OverExpressionParser {\r\n public static parse(query: string): OverExpression {\r\n const tokenizer = new SqlTokenizer(query); // Initialize tokenizer\r\n const lexemes = tokenizer.readLexmes(); // Get tokens\r\n\r\n // Parse\r\n const result = this.parseFromLexeme(lexemes, 0);\r\n\r\n // Error if there are remaining tokens\r\n if (result.newIndex < lexemes.length) {\r\n throw new Error(`Syntax error: Unexpected token \"${lexemes[result.newIndex].value}\" at position ${result.newIndex}. The OVER expression is complete but there are additional tokens.`);\r\n }\r\n\r\n return result.value;\r\n }\r\n\r\n public static parseFromLexeme(lexemes: Lexeme[], index: number): { value: OverExpression; newIndex: number } {\r\n let idx = index;\r\n\r\n if (lexemes[idx].value !== 'over') {\r\n throw new Error(`Syntax error at position ${idx}: Expected 'OVER' keyword but found \"${lexemes[idx].value}\". OVER expressions must start with the OVER keyword.`);\r\n }\r\n idx++;\r\n\r\n if (idx >= lexemes.length) {\r\n throw new Error(`Syntax error: Unexpected end of input after 'OVER' keyword. Expected either a window name or an opening parenthesis '('.`);\r\n }\r\n\r\n if (lexemes[idx].type & TokenType.Identifier) {\r\n // named window frame\r\n const name = lexemes[idx].value;\r\n idx++;\r\n return { value: new IdentifierString(name), newIndex: idx };\r\n }\r\n\r\n if (lexemes[idx].type & TokenType.OpenParen) {\r\n // Delegate processing to WindowFrameExpressionParser\r\n const result = WindowExpressionParser.parseFromLexeme(lexemes, idx);\r\n return result;\r\n }\r\n\r\n throw new Error(`Syntax error at position ${idx}: Expected a window name or opening parenthesis '(' after OVER keyword, but found \"${lexemes[idx].value}\".`);\r\n }\r\n}\r\n", "import { Lexeme, TokenType } from \"../models/Lexeme\";\r\nimport { FunctionCall, ValueComponent, BinaryExpression, TypeValue, CastExpression, BetweenExpression, RawString, ArrayExpression, ArrayQueryExpression } from \"../models/ValueComponent\";\r\nimport { SelectQuery } from \"../models/SelectQuery\";\r\nimport { OverExpressionParser } from \"./OverExpressionParser\";\r\nimport { ValueParser } from \"./ValueParser\";\r\nimport { FullNameParser } from \"./FullNameParser\";\r\nimport { SelectQueryParser } from \"./SelectQueryParser\";\r\n\r\nexport class FunctionExpressionParser {\r\n /**\r\n * Parse ARRAY expressions - handles both ARRAY[...] (literal) and ARRAY(...) (query) syntax\r\n * @param lexemes Array of lexemes to parse\r\n * @param index Current parsing index\r\n * @returns Parsed array expression and new index\r\n */\r\n private static parseArrayExpression(lexemes: Lexeme[], index: number): { value: ValueComponent; newIndex: number } {\r\n let idx = index;\r\n\r\n // Check if this is array literal (ARRAY[...]) or function call (ARRAY(...))\r\n if (idx + 1 < lexemes.length && (lexemes[idx + 1].type & TokenType.OpenBracket)) {\r\n idx++;\r\n const arg = ValueParser.parseArgument(TokenType.OpenBracket, TokenType.CloseBracket, lexemes, idx);\r\n idx = arg.newIndex;\r\n const value = new ArrayExpression(arg.value);\r\n return { value, newIndex: idx };\r\n } else if (idx + 1 < lexemes.length && (lexemes[idx + 1].type & TokenType.OpenParen)) {\r\n idx++;\r\n idx++; // Skip the opening parenthesis\r\n const arg = SelectQueryParser.parseFromLexeme(lexemes, idx);\r\n idx = arg.newIndex;\r\n idx++; // Skip the closing parenthesis\r\n const value = new ArrayQueryExpression(arg.value);\r\n return { value, newIndex: idx };\r\n }\r\n\r\n throw new Error(`Invalid ARRAY syntax at index ${idx}, expected ARRAY[... or ARRAY(...)`);\r\n }\r\n\r\n public static parseFromLexeme(lexemes: Lexeme[], index: number): { value: ValueComponent; newIndex: number } {\r\n let idx = index;\r\n const current = lexemes[idx];\r\n\r\n if (current.value === \"array\") {\r\n return this.parseArrayExpression(lexemes, idx);\r\n } else if (current.value === \"substring\" || current.value === \"overlay\") {\r\n return this.parseKeywordFunction(lexemes, idx, [\r\n { key: \"from\", required: false },\r\n { key: \"for\", required: false }\r\n ]);\r\n } else if (current.value === \"cast\") {\r\n return this.parseKeywordFunction(lexemes, idx, [\r\n { key: \"as\", required: true }\r\n ]);\r\n } else if (current.value === \"trim\") {\r\n return this.parseKeywordFunction(lexemes, idx, [\r\n { key: \"from\", required: false }\r\n ]);\r\n }\r\n\r\n return this.parseFunctionCall(lexemes, idx);\r\n }\r\n\r\n public static tryParseBinaryExpression(lexemes: Lexeme[], index: number, left: ValueComponent, allowAndOperator: boolean = true, allowOrOperator: boolean = true): { value: ValueComponent; newIndex: number } | null {\r\n let idx = index;\r\n\r\n // If the next element is an operator, process it as a binary expression\r\n if (idx < lexemes.length && (lexemes[idx].type & TokenType.Operator)) {\r\n const operator = lexemes[idx].value.toLowerCase();\r\n\r\n if (!allowAndOperator && operator === \"and\") {\r\n // Handle special case for \"and\" operator\r\n return null;\r\n }\r\n\r\n if (!allowOrOperator && operator === \"or\") {\r\n // Handle special case for \"or\" operator\r\n return null;\r\n }\r\n\r\n idx++;\r\n\r\n // between\r\n if (operator === \"between\") {\r\n return this.parseBetweenExpression(lexemes, idx, left, false);\r\n } else if (operator === \"not between\") {\r\n return this.parseBetweenExpression(lexemes, idx, left, true);\r\n }\r\n\r\n // ::\r\n if (operator === \"::\") {\r\n const typeValue = this.parseTypeValue(lexemes, idx);\r\n idx = typeValue.newIndex;\r\n const exp = new CastExpression(left, typeValue.value);\r\n return { value: exp, newIndex: idx };\r\n }\r\n\r\n // Get the right-hand side value\r\n const rightResult = ValueParser.parseFromLexeme(lexemes, idx);\r\n idx = rightResult.newIndex;\r\n\r\n // Create binary expression\r\n const value = new BinaryExpression(left, operator, rightResult.value);\r\n return { value, newIndex: idx };\r\n }\r\n\r\n return null;\r\n }\r\n\r\n public static parseBetweenExpression(lexemes: Lexeme[], index: number, value: ValueComponent, negated: boolean): { value: ValueComponent; newIndex: number; } {\r\n let idx = index;\r\n const lower = ValueParser.parseFromLexeme(lexemes, idx, false);\r\n idx = lower.newIndex;\r\n\r\n if (idx < lexemes.length && (lexemes[idx].type & TokenType.Operator) && lexemes[idx].value !== \"and\") {\r\n throw new Error(`Expected 'and' after 'between' at index ${idx}`);\r\n }\r\n idx++;\r\n\r\n // Parse upper bound with restricted scope - stop at logical operators\r\n const upper = this.parseBetweenUpperBound(lexemes, idx);\r\n idx = upper.newIndex;\r\n const result = new BetweenExpression(value, lower.value, upper.value, negated);\r\n return { value: result, newIndex: idx };\r\n }\r\n\r\n /**\r\n * Parse the upper bound of a BETWEEN expression with logical operator precedence\r\n * This stops parsing when it encounters AND/OR operators at the same level\r\n */\r\n private static parseBetweenUpperBound(lexemes: Lexeme[], index: number): { value: ValueComponent; newIndex: number } {\r\n // Parse with higher precedence than AND/OR to ensure BETWEEN binds tighter\r\n // Use precedence 3 (higher than AND=2, OR=1) as minimum to stop at logical operators\r\n return ValueParser.parseFromLexeme(lexemes, index, false, false);\r\n }\r\n\r\n private static parseFunctionCall(lexemes: Lexeme[], index: number): { value: ValueComponent; newIndex: number } {\r\n let idx = index;\r\n // Parse namespaced function name (e.g., myschema.myfunc, dbo.util.myfunc)\r\n // Use FullNameParser to get namespaces and function name\r\n const fullNameResult = FullNameParser.parseFromLexeme(lexemes, idx);\r\n const namespaces = fullNameResult.namespaces;\r\n const name = fullNameResult.name;\r\n idx = fullNameResult.newIndex;\r\n\r\n if (idx < lexemes.length && (lexemes[idx].type & TokenType.OpenParen)) {\r\n // General argument parsing\r\n const arg = ValueParser.parseArgument(TokenType.OpenParen, TokenType.CloseParen, lexemes, idx);\r\n idx = arg.newIndex;\r\n\r\n if (idx < lexemes.length && lexemes[idx].value === \"over\") {\r\n const over = OverExpressionParser.parseFromLexeme(lexemes, idx);\r\n idx = over.newIndex;\r\n const value = new FunctionCall(namespaces, name.name, arg.value, over.value);\r\n return { value, newIndex: idx };\r\n } else {\r\n const value = new FunctionCall(namespaces, name.name, arg.value, null);\r\n return { value, newIndex: idx };\r\n }\r\n } else {\r\n throw new Error(`Expected opening parenthesis after function name '${name.name}' at index ${idx}`);\r\n }\r\n }\r\n\r\n private static parseKeywordFunction(\r\n lexemes: Lexeme[],\r\n index: number,\r\n keywords: { key: string, required: boolean }[]\r\n ): { value: ValueComponent; newIndex: number; } {\r\n let idx = index;\r\n // Parse function name and namespaces at the beginning for consistent usage\r\n const fullNameResult = FullNameParser.parseFromLexeme(lexemes, idx);\r\n const namespaces = fullNameResult.namespaces;\r\n const name = fullNameResult.name;\r\n idx = fullNameResult.newIndex;\r\n\r\n if (idx < lexemes.length && (lexemes[idx].type & TokenType.OpenParen)) {\r\n idx++;\r\n\r\n const input = ValueParser.parseFromLexeme(lexemes, idx);\r\n let arg = input.value;\r\n idx = input.newIndex;\r\n\r\n // Delegate to the standard function parser if parsing by comma\r\n if (idx < lexemes.length && (lexemes[idx].type & TokenType.Comma)) {\r\n return this.parseFunctionCall(lexemes, index);\r\n }\r\n\r\n // Check for required/optional keywords in function arguments\r\n for (const { key, required } of keywords) {\r\n if (idx < lexemes.length && (lexemes[idx].type & TokenType.Command) && lexemes[idx].value === key) {\r\n idx++;\r\n\r\n if (idx < lexemes.length && (lexemes[idx].type & TokenType.Type)) {\r\n const typeValue = this.parseTypeValue(lexemes, idx);\r\n arg = new BinaryExpression(arg, key, typeValue.value);\r\n idx = typeValue.newIndex;\r\n } else {\r\n const right = ValueParser.parseFromLexeme(lexemes, idx);\r\n arg = new BinaryExpression(arg, key, right.value);\r\n idx = right.newIndex;\r\n }\r\n\r\n } else if (required) {\r\n throw new Error(`Keyword '${key}' is required at index ${idx}`);\r\n }\r\n }\r\n\r\n if (idx < lexemes.length && (lexemes[idx].type & TokenType.CloseParen)) {\r\n idx++;\r\n // Use the previously parsed namespaces and function name for consistency\r\n if (idx < lexemes.length && lexemes[idx].value === \"over\") {\r\n idx++;\r\n const over = OverExpressionParser.parseFromLexeme(lexemes, idx);\r\n idx = over.newIndex;\r\n const value = new FunctionCall(namespaces, name.name, arg, over.value);\r\n return { value, newIndex: idx };\r\n } else {\r\n const value = new FunctionCall(namespaces, name.name, arg, null);\r\n return { value, newIndex: idx };\r\n }\r\n } else {\r\n throw new Error(`Missing closing parenthesis for function '${name.name}' at index ${idx}`);\r\n }\r\n } else {\r\n throw new Error(`Missing opening parenthesis for function '${name.name}' at index ${idx}`);\r\n }\r\n }\r\n\r\n public static parseTypeValue(lexemes: Lexeme[], index: number): { value: TypeValue; newIndex: number; } {\r\n let idx = index;\r\n\r\n const { namespaces, name, newIndex } = FullNameParser.parseFromLexeme(lexemes, idx);\r\n idx = newIndex;\r\n\r\n if (idx < lexemes.length && (lexemes[idx].type & TokenType.OpenParen)) {\r\n const arg = ValueParser.parseArgument(TokenType.OpenParen, TokenType.CloseParen, lexemes, idx);\r\n idx = arg.newIndex;\r\n const value = new TypeValue(namespaces, new RawString(name.name), arg.value);\r\n return { value, newIndex: idx };\r\n } else {\r\n const value = new TypeValue(namespaces, new RawString(name.name));\r\n return { value, newIndex: idx };\r\n }\r\n }\r\n}", "import { Lexeme, TokenType } from \"../models/Lexeme\";\r\n\r\nexport class ParseError extends Error {\r\n constructor(message: string, public index: number, public context: string) {\r\n super(message);\r\n this.name = \"ParseError\";\r\n }\r\n\r\n public static fromUnparsedLexemes(lexemes: Lexeme[], index: number, messagePrefix: string): ParseError {\r\n const start = Math.max(0, index - 2);\r\n const end = Math.min(lexemes.length, index + 3);\r\n const context = lexemes.slice(start, end).map((lexeme, idx) => {\r\n const marker = idx + start === index ? '>' : ' ';\r\n const typeName = TokenType[lexeme.type] || lexeme.type; // Convert type to name if possible\r\n return `${marker} ${idx + start}:${lexeme.value} [${typeName}]`;\r\n }).join('\\n');\r\n\r\n const message = `${messagePrefix} Unparsed lexeme remains at index ${index}: ${lexemes[index].value}\\nContext:\\n${context}`;\r\n return new ParseError(message, index, context);\r\n }\r\n}\r\n", "/**\r\n * SQL operator precedence definitions\r\n * Higher numbers indicate higher precedence (tighter binding)\r\n */\r\nexport class OperatorPrecedence {\r\n private static readonly precedenceMap: Record<string, number> = {\r\n // Logical operators (lowest precedence)\r\n 'or': 1,\r\n 'and': 2,\r\n\r\n // Comparison operators\r\n '=': 10,\r\n '!=': 10,\r\n '<>': 10,\r\n '<': 10,\r\n '<=': 10,\r\n '>': 10,\r\n '>=': 10,\r\n 'like': 10,\r\n 'ilike': 10,\r\n 'not like': 10,\r\n 'not ilike': 10,\r\n 'similar to': 10,\r\n 'not similar to': 10,\r\n 'in': 10,\r\n 'not in': 10,\r\n 'is': 10,\r\n 'is not': 10,\r\n 'between': 15, // BETWEEN has higher precedence than logical operators\r\n 'not between': 15,\r\n\r\n // Arithmetic operators\r\n '+': 20,\r\n '-': 20,\r\n '*': 30,\r\n '/': 30,\r\n '%': 30,\r\n '^': 40,\r\n\r\n // Type casting\r\n '::': 50,\r\n\r\n // Highest precedence operators\r\n 'unary+': 100,\r\n 'unary-': 100,\r\n 'not': 100\r\n };\r\n\r\n /**\r\n * Get the precedence of an operator\r\n * @param operator The operator string\r\n * @returns The precedence number (higher = tighter binding)\r\n */\r\n public static getPrecedence(operator: string): number {\r\n const precedence = this.precedenceMap[operator.toLowerCase()];\r\n return precedence !== undefined ? precedence : 0;\r\n }\r\n\r\n /**\r\n * Check if operator1 has higher or equal precedence than operator2\r\n */\r\n public static hasHigherOrEqualPrecedence(operator1: string, operator2: string): boolean {\r\n return this.getPrecedence(operator1) >= this.getPrecedence(operator2);\r\n }\r\n\r\n /**\r\n * Check if an operator is a logical operator (AND/OR)\r\n */\r\n public static isLogicalOperator(operator: string): boolean {\r\n const op = operator.toLowerCase();\r\n return op === 'and' || op === 'or';\r\n }\r\n\r\n /**\r\n * Check if an operator is a BETWEEN operator\r\n */\r\n public static isBetweenOperator(operator: string): boolean {\r\n const op = operator.toLowerCase();\r\n return op === 'between' || op === 'not between';\r\n }\r\n\r\n /**\r\n * Check if a string is a comparison operator\r\n */\r\n public static isComparisonOperator(operator: string): boolean {\r\n const lowerOp = operator.toLowerCase();\r\n return ['=', '!=', '<>', '<', '>', '<=', '>=', 'like', 'ilike', 'similar to', 'in', 'not in'].includes(lowerOp);\r\n }\r\n}\r\n", "import { Lexeme, TokenType } from \"../models/Lexeme\";\r\nimport { ColumnReference, TypeValue, UnaryExpression, ValueComponent, ValueList, BinaryExpression, CastExpression } from \"../models/ValueComponent\";\r\nimport { SqlTokenizer } from \"./SqlTokenizer\";\r\nimport { IdentifierParser } from \"./IdentifierParser\";\r\nimport { LiteralParser } from \"./LiteralParser\";\r\nimport { ParenExpressionParser } from \"./ParenExpressionParser\";\r\nimport { UnaryExpressionParser } from \"./UnaryExpressionParser\";\r\nimport { ParameterExpressionParser } from \"./ParameterExpressionParser\";\r\nimport { StringSpecifierExpressionParser } from \"./StringSpecifierExpressionParser\";\r\nimport { CommandExpressionParser } from \"./CommandExpressionParser\";\r\nimport { FunctionExpressionParser } from \"./FunctionExpressionParser\";\r\nimport { FullNameParser } from \"./FullNameParser\";\r\nimport { ParseError } from \"./ParseError\";\r\nimport { OperatorPrecedence } from \"../utils/OperatorPrecedence\";\r\n\r\nexport class ValueParser {\r\n // Parse SQL string to AST (was: parse)\r\n public static parse(query: string): ValueComponent {\r\n const tokenizer = new SqlTokenizer(query); // Initialize tokenizer\r\n const lexemes = tokenizer.readLexmes(); // Get tokens\r\n\r\n // Parse\r\n const result = this.parseFromLexeme(lexemes, 0);\r\n\r\n // Error if there are remaining tokens\r\n if (result.newIndex < lexemes.length) {\r\n throw ParseError.fromUnparsedLexemes(\r\n lexemes,\r\n result.newIndex,\r\n `[ValueParser]`\r\n );\r\n }\r\n\r\n return result.value;\r\n }\r\n\r\n /**\r\n * Parse from lexeme array with logical operator controls\r\n */\r\n public static parseFromLexeme(lexemes: Lexeme[], index: number, allowAndOperator: boolean = true, allowOrOperator: boolean = true): { value: ValueComponent; newIndex: number } {\r\n return this.parseExpressionWithPrecedence(lexemes, index, 0, allowAndOperator, allowOrOperator);\r\n }\r\n\r\n /**\r\n * Parse expressions with operator precedence handling\r\n * Uses precedence climbing algorithm\r\n */\r\n private static parseExpressionWithPrecedence(\r\n lexemes: Lexeme[],\r\n index: number,\r\n minPrecedence: number,\r\n allowAndOperator: boolean = true,\r\n allowOrOperator: boolean = true\r\n ): { value: ValueComponent; newIndex: number } {\r\n let idx = index;\r\n\r\n // Parse the primary expression (left side)\r\n const comment = lexemes[idx].comments;\r\n const left = this.parseItem(lexemes, idx);\r\n left.value.comments = comment;\r\n idx = left.newIndex;\r\n\r\n let result = left.value;\r\n\r\n // Process operators with precedence\r\n while (idx < lexemes.length && (lexemes[idx].type & TokenType.Operator)) {\r\n const operatorToken = lexemes[idx];\r\n const operator = operatorToken.value;\r\n\r\n // Check if this operator is allowed\r\n if (!allowAndOperator && operator.toLowerCase() === \"and\") {\r\n break;\r\n }\r\n if (!allowOrOperator && operator.toLowerCase() === \"or\") {\r\n break;\r\n }\r\n\r\n // Get operator precedence\r\n const precedence = OperatorPrecedence.getPrecedence(operator);\r\n\r\n // If this operator has lower precedence than minimum, stop\r\n if (precedence < minPrecedence) {\r\n break;\r\n }\r\n\r\n idx++; // consume operator // Handle BETWEEN specially as it has different syntax\r\n if (OperatorPrecedence.isBetweenOperator(operator)) {\r\n const betweenResult = FunctionExpressionParser.parseBetweenExpression(\r\n lexemes, idx, result, operator.toLowerCase().includes('not')\r\n );\r\n result = betweenResult.value;\r\n idx = betweenResult.newIndex;\r\n continue;\r\n }\r\n\r\n // Handle :: (cast) operator specially\r\n if (operator === \"::\") {\r\n const typeValue = FunctionExpressionParser.parseTypeValue(lexemes, idx);\r\n result = new CastExpression(result, typeValue.value);\r\n idx = typeValue.newIndex;\r\n continue;\r\n }\r\n\r\n // For left-associative operators, use precedence + 1\r\n const nextMinPrecedence = precedence + 1;\r\n\r\n // Parse the right-hand side with higher precedence\r\n const rightResult = this.parseExpressionWithPrecedence(\r\n lexemes, idx, nextMinPrecedence, allowAndOperator, allowOrOperator\r\n );\r\n idx = rightResult.newIndex;\r\n\r\n // Create binary expression directly\r\n result = new BinaryExpression(result, operator, rightResult.value);\r\n }\r\n\r\n return { value: result, newIndex: idx };\r\n }\r\n\r\n private static parseItem(lexemes: Lexeme[], index: number): { value: ValueComponent; newIndex: number } {\r\n let idx = index;\r\n\r\n // Range check\r\n if (idx >= lexemes.length) {\r\n throw new Error(`Unexpected end of lexemes at index ${index}`);\r\n }\r\n\r\n const current = lexemes[idx];\r\n\r\n if (current.type & TokenType.Identifier && current.type & TokenType.Operator && current.type & TokenType.Type) {\r\n // Check if this is followed by parentheses (function call)\r\n if (idx + 1 < lexemes.length && (lexemes[idx + 1].type & TokenType.OpenParen)) {\r\n // Determine if this is a type constructor or function call\r\n if (this.isTypeConstructor(lexemes, idx + 1, current.value)) {\r\n // Type constructor\r\n const typeValue = FunctionExpressionParser.parseTypeValue(lexemes, idx);\r\n return { value: typeValue.value, newIndex: typeValue.newIndex };\r\n } else {\r\n // Function call\r\n return FunctionExpressionParser.parseFromLexeme(lexemes, idx);\r\n }\r\n }\r\n // Typed literal format pattern\r\n // e.g., `interval '2 days'`\r\n const first = IdentifierParser.parseFromLexeme(lexemes, idx);\r\n if (first.newIndex >= lexemes.length) {\r\n return first;\r\n }\r\n const next = lexemes[first.newIndex];\r\n if (next.type & TokenType.Literal) {\r\n // Typed literal format\r\n const second = LiteralParser.parseFromLexeme(lexemes, first.newIndex);\r\n const result = new UnaryExpression(lexemes[idx].value, second.value);\r\n return { value: result, newIndex: second.newIndex };\r\n }\r\n return first;\r\n } else if (current.type & TokenType.Identifier) {\r\n const { namespaces, name, newIndex } = FullNameParser.parseFromLexeme(lexemes, idx);\r\n // Namespace is also recognized as Identifier.\r\n // Since functions and types, as well as columns (tables), can have namespaces,\r\n // it is necessary to determine by the last element of the identifier.\r\n if (lexemes[newIndex - 1].type & TokenType.Function) {\r\n return FunctionExpressionParser.parseFromLexeme(lexemes, idx);\r\n } else if (lexemes[newIndex - 1].type & TokenType.Type) {\r\n // Handle Type tokens that also have Identifier flag\r\n if (newIndex < lexemes.length && (lexemes[newIndex].type & TokenType.OpenParen)) {\r\n // Determine if this is a type constructor or function call\r\n if (this.isTypeConstructor(lexemes, newIndex, name.name)) {\r\n // Type constructor (NUMERIC(10,2), VARCHAR(50), etc.)\r\n const typeValue = FunctionExpressionParser.parseTypeValue(lexemes, idx);\r\n return { value: typeValue.value, newIndex: typeValue.newIndex };\r\n } else {\r\n // Function call (DATE('2025-01-01'), etc.)\r\n return FunctionExpressionParser.parseFromLexeme(lexemes, idx);\r\n }\r\n } else {\r\n // Handle standalone type tokens\r\n const value = new TypeValue(namespaces, name);\r\n return { value, newIndex };\r\n }\r\n }\r\n const value = new ColumnReference(namespaces, name);\r\n return { value, newIndex };\r\n } else if (current.type & TokenType.Literal) {\r\n return LiteralParser.parseFromLexeme(lexemes, idx);\r\n } else if (current.type & TokenType.OpenParen) {\r\n return ParenExpressionParser.parseFromLexeme(lexemes, idx);\r\n } else if (current.type & TokenType.Function) {\r\n return FunctionExpressionParser.parseFromLexeme(lexemes, idx);\r\n } else if (current.type & TokenType.Operator) {\r\n return UnaryExpressionParser.parseFromLexeme(lexemes, idx);\r\n } else if (current.type & TokenType.Parameter) {\r\n return ParameterExpressionParser.parseFromLexeme(lexemes, idx);\r\n } else if (current.type & TokenType.StringSpecifier) {\r\n return StringSpecifierExpressionParser.parseFromLexeme(lexemes, idx);\r\n } else if (current.type & TokenType.Command) {\r\n return CommandExpressionParser.parseFromLexeme(lexemes, idx);\r\n } else if (current.type & TokenType.OpenBracket) {\r\n // SQLServer escape identifier format. e.g. [dbo] or [dbo].[table]\r\n const { namespaces, name, newIndex } = FullNameParser.parseFromLexeme(lexemes, idx);\r\n const value = new ColumnReference(namespaces, name);\r\n return { value, newIndex };\r\n } else if (current.type & TokenType.Type) {\r\n // Check if this type token is followed by an opening parenthesis\r\n const { namespaces, name, newIndex } = FullNameParser.parseFromLexeme(lexemes, idx);\r\n if (newIndex < lexemes.length && (lexemes[newIndex].type & TokenType.OpenParen)) {\r\n // Determine if this is a type constructor or function call\r\n if (this.isTypeConstructor(lexemes, newIndex, name.name)) {\r\n // Type constructor (NUMERIC(10,2), VARCHAR(50), etc.)\r\n const typeValue = FunctionExpressionParser.parseTypeValue(lexemes, idx);\r\n return { value: typeValue.value, newIndex: typeValue.newIndex };\r\n } else {\r\n // Function call (DATE('2025-01-01'), etc.)\r\n return FunctionExpressionParser.parseFromLexeme(lexemes, idx);\r\n }\r\n } else {\r\n // Handle standalone type tokens\r\n const value = new TypeValue(namespaces, name);\r\n return { value, newIndex };\r\n }\r\n }\r\n\r\n throw new Error(`[ValueParser] Invalid lexeme. index: ${idx}, type: ${lexemes[idx].type}, value: ${lexemes[idx].value}`);\r\n }\r\n\r\n public static parseArgument(openToken: TokenType, closeToken: TokenType, lexemes: Lexeme[], index: number): { value: ValueComponent; newIndex: number } {\r\n let idx = index;\r\n const args: ValueComponent[] = [];\r\n\r\n // Check for opening parenthesis\r\n if (idx < lexemes.length && lexemes[idx].type === openToken) {\r\n idx++;\r\n\r\n if (idx < lexemes.length && lexemes[idx].type === closeToken) {\r\n // If there are no arguments, return an empty ValueList\r\n idx++;\r\n return { value: new ValueList([]), newIndex: idx };\r\n }\r\n\r\n // If the next element is `*`, treat `*` as an Identifier\r\n if (idx < lexemes.length && lexemes[idx].value === \"*\") {\r\n const wildcard = new ColumnReference(null, \"*\");\r\n idx++;\r\n // The next element must be closeToken\r\n if (idx < lexemes.length && lexemes[idx].type === closeToken) {\r\n idx++;\r\n return { value: wildcard, newIndex: idx };\r\n } else {\r\n throw new Error(`Expected closing parenthesis at index ${idx}`);\r\n }\r\n }\r\n\r\n // Parse the value inside\r\n const result = this.parseFromLexeme(lexemes, idx);\r\n idx = result.newIndex;\r\n args.push(result.value);\r\n\r\n // Continue reading if the next element is a comma\r\n while (idx < lexemes.length && (lexemes[idx].type & TokenType.Comma)) {\r\n idx++;\r\n const argResult = this.parseFromLexeme(lexemes, idx);\r\n idx = argResult.newIndex;\r\n args.push(argResult.value);\r\n }\r\n\r\n // Check for closing parenthesis\r\n if (idx < lexemes.length && lexemes[idx].type === closeToken) {\r\n idx++;\r\n if (args.length === 1) {\r\n // Return as is if there is only one argument\r\n return { value: args[0], newIndex: idx };\r\n }\r\n // Create ValueCollection if there are multiple arguments\r\n const value = new ValueList(args);\r\n return { value, newIndex: idx };\r\n } else {\r\n throw new Error(`Missing closing parenthesis at index ${idx}`);\r\n }\r\n }\r\n\r\n throw new Error(`Expected opening parenthesis at index ${index}`);\r\n }\r\n\r\n /**\r\n * Determines if a type token followed by parentheses is a type constructor or function call\r\n * @param lexemes Array of lexemes\r\n * @param openParenIndex Index of the opening parenthesis\r\n * @param typeName Name of the type/function\r\n * @returns True if this is a type constructor, false if it's a function call\r\n */\r\n private static isTypeConstructor(lexemes: Lexeme[], openParenIndex: number, typeName: string): boolean {\r\n // These are always type constructors regardless of content\r\n const alwaysTypeConstructors = [\r\n 'NUMERIC', 'DECIMAL', 'VARCHAR', 'CHAR', 'CHARACTER',\r\n 'TIMESTAMP', 'TIME', 'INTERVAL'\r\n ];\r\n \r\n const upperTypeName = typeName.toUpperCase();\r\n if (alwaysTypeConstructors.includes(upperTypeName)) {\r\n return true;\r\n }\r\n \r\n // For DATE, check if the first argument is a string literal (function) or not (type)\r\n if (upperTypeName === 'DATE') {\r\n const firstArgIndex = openParenIndex + 1;\r\n if (firstArgIndex < lexemes.length) {\r\n const firstArg = lexemes[firstArgIndex];\r\n const isStringLiteral = (firstArg.type & TokenType.Literal) && \r\n typeof firstArg.value === 'string' &&\r\n isNaN(Number(firstArg.value));\r\n // If first argument is a string literal, it's a function call\r\n // DATE('2025-01-01') -> function\r\n // DATE(6) -> type constructor\r\n return !isStringLiteral;\r\n }\r\n }\r\n \r\n // Default: assume it's a function call for ambiguous cases\r\n return false;\r\n }\r\n}\r\n", "import { CommonTable, ForClause, FromClause, FunctionSource, GroupByClause, HavingClause, JoinClause, JoinOnClause, JoinUsingClause, LimitClause, OrderByClause, OrderByItem, ParenSource, PartitionByClause, SelectClause, SelectItem, SourceExpression, SubQuerySource, TableSource, WhereClause, WindowFrameClause, WindowsClause, WithClause } from \"../models/Clause\";\r\nimport { BinarySelectQuery, SimpleSelectQuery, SelectQuery, ValuesQuery } from \"../models/SelectQuery\";\r\nimport { SqlComponent, SqlComponentVisitor } from \"../models/SqlComponent\";\r\nimport {\r\n ArrayExpression, ArrayQueryExpression, BetweenExpression, BinaryExpression, CaseExpression, CaseKeyValuePair,\r\n CastExpression, ColumnReference, FunctionCall, InlineQuery, ParenExpression,\r\n ParameterExpression, SwitchCaseArgument, TupleExpression, UnaryExpression, ValueComponent,\r\n OverExpression, WindowFrameExpression, IdentifierString, RawString,\r\n WindowFrameSpec,\r\n LiteralValue,\r\n TypeValue,\r\n ValueList,\r\n StringSpecifierExpression\r\n} from \"../models/ValueComponent\";\r\n\r\n/**\r\n * A visitor that collects all CommonTable instances from a SQL query structure.\r\n * This includes tables from:\r\n * - WITH clauses\r\n * - Subqueries\r\n * - Inline queries\r\n * - UNION queries\r\n * - Value components that may contain queries\r\n */\r\nexport class CTECollector implements SqlComponentVisitor<void> {\r\n private handlers: Map<symbol, (arg: any) => void>;\r\n private commonTables: CommonTable[] = [];\r\n private visitedNodes: Set<SqlComponent> = new Set();\r\n private isRootVisit: boolean = true;\r\n\r\n constructor() {\r\n this.handlers = new Map<symbol, (arg: any) => void>();\r\n\r\n // Setup handlers for all component types that might contain CommonTables\r\n\r\n // SelectQuery types\r\n this.handlers.set(SimpleSelectQuery.kind, (expr) => this.visitSimpleSelectQuery(expr as SimpleSelectQuery));\r\n this.handlers.set(BinarySelectQuery.kind, (expr) => this.visitBinarySelectQuery(expr as BinarySelectQuery));\r\n this.handlers.set(ValuesQuery.kind, (expr) => this.visitValuesQuery(expr as ValuesQuery));\r\n\r\n // WITH clause that directly contains CommonTables\r\n this.handlers.set(WithClause.kind, (expr) => this.visitWithClause(expr as WithClause));\r\n this.handlers.set(CommonTable.kind, (expr) => this.visitCommonTable(expr as CommonTable));\r\n\r\n // SelectComponent types\r\n this.handlers.set(SelectItem.kind, (expr) => this.visitSelectItem(expr as SelectItem));\r\n\r\n // Identifiers and raw strings (leaf nodes that don't need traversal)\r\n this.handlers.set(IdentifierString.kind, (expr) => this.visitIdentifierString(expr as IdentifierString));\r\n this.handlers.set(RawString.kind, (expr) => this.visitRawString(expr as RawString));\r\n this.handlers.set(ColumnReference.kind, (expr) => this.visitColumnReference(expr as ColumnReference));\r\n this.handlers.set(ParameterExpression.kind, (expr) => this.visitParameterExpression(expr as ParameterExpression));\r\n this.handlers.set(LiteralValue.kind, (expr) => this.visitLiteralValue(expr as LiteralValue));\r\n\r\n // Source components\r\n this.handlers.set(SourceExpression.kind, (expr) => this.visitSourceExpression(expr as SourceExpression));\r\n this.handlers.set(TableSource.kind, (expr) => this.visitTableSource(expr as TableSource));\r\n this.handlers.set(FunctionSource.kind, (expr) => this.visitFunctionSource(expr as FunctionSource));\r\n this.handlers.set(ParenSource.kind, (expr) => this.visitParenSource(expr as ParenSource));\r\n\r\n // Subqueries and inline queries\r\n this.handlers.set(SubQuerySource.kind, (expr) => this.visitSubQuerySource(expr as SubQuerySource));\r\n this.handlers.set(InlineQuery.kind, (expr) => this.visitInlineQuery(expr as InlineQuery));\r\n\r\n // FROM and JOIN clauses\r\n this.handlers.set(FromClause.kind, (expr) => this.visitFromClause(expr as FromClause));\r\n this.handlers.set(JoinClause.kind, (expr) => this.visitJoinClause(expr as JoinClause));\r\n this.handlers.set(JoinOnClause.kind, (expr) => this.visitJoinOnClause(expr as JoinOnClause));\r\n this.handlers.set(JoinUsingClause.kind, (expr) => this.visitJoinUsingClause(expr as JoinUsingClause));\r\n\r\n // WHERE clause\r\n this.handlers.set(WhereClause.kind, (expr) => this.visitWhereClause(expr as WhereClause));\r\n\r\n // Value components that might contain subqueries\r\n this.handlers.set(ParenExpression.kind, (expr) => this.visitParenExpression(expr as ParenExpression));\r\n this.handlers.set(BinaryExpression.kind, (expr) => this.visitBinaryExpression(expr as BinaryExpression));\r\n this.handlers.set(UnaryExpression.kind, (expr) => this.visitUnaryExpression(expr as UnaryExpression));\r\n this.handlers.set(CaseExpression.kind, (expr) => this.visitCaseExpression(expr as CaseExpression));\r\n this.handlers.set(CaseKeyValuePair.kind, (expr) => this.visitCaseKeyValuePair(expr as CaseKeyValuePair));\r\n this.handlers.set(SwitchCaseArgument.kind, (expr) => this.visitSwitchCaseArgument(expr as SwitchCaseArgument));\r\n this.handlers.set(BetweenExpression.kind, (expr) => this.visitBetweenExpression(expr as BetweenExpression));\r\n this.handlers.set(FunctionCall.kind, (expr) => this.visitFunctionCall(expr as FunctionCall));\r\n this.handlers.set(ArrayExpression.kind, (expr) => this.visitArrayExpression(expr as ArrayExpression));\r\n this.handlers.set(ArrayQueryExpression.kind, (expr) => this.visitArrayQueryExpression(expr as ArrayQueryExpression));\r\n this.handlers.set(TupleExpression.kind, (expr) => this.visitTupleExpression(expr as TupleExpression));\r\n this.handlers.set(CastExpression.kind, (expr) => this.visitCastExpression(expr as CastExpression));\r\n this.handlers.set(WindowFrameExpression.kind, (expr) => this.visitWindowFrameExpression(expr as WindowFrameExpression));\r\n this.handlers.set(WindowFrameSpec.kind, (expr) => this.visitWindowFrameSpec(expr as WindowFrameSpec));\r\n this.handlers.set(TypeValue.kind, (expr) => this.visitTypeValue(expr as TypeValue));\r\n this.handlers.set(ValueList.kind, (expr) => this.visitValueList(expr as ValueList));\r\n this.handlers.set(StringSpecifierExpression.kind, (expr) => this.visitStringSpecifierExpression(expr as StringSpecifierExpression));\r\n\r\n // Add handlers for other clause types\r\n this.handlers.set(SelectClause.kind, (expr) => this.visitSelectClause(expr as SelectClause));\r\n this.handlers.set(GroupByClause.kind, (expr) => this.visitGroupByClause(expr as GroupByClause));\r\n this.handlers.set(HavingClause.kind, (expr) => this.visitHavingClause(expr as HavingClause));\r\n this.handlers.set(OrderByClause.kind, (expr) => this.visitOrderByClause(expr as OrderByClause));\r\n this.handlers.set(WindowFrameClause.kind, (expr) => this.visitWindowFrameClause(expr as WindowFrameClause));\r\n this.handlers.set(LimitClause.kind, (expr) => this.visitLimitClause(expr as LimitClause));\r\n this.handlers.set(ForClause.kind, (expr) => this.visitForClause(expr as ForClause));\r\n this.handlers.set(OrderByItem.kind, (expr) => this.visitOrderByItem(expr as OrderByItem));\r\n this.handlers.set(PartitionByClause.kind, (expr) => this.visitPartitionByClause(expr as PartitionByClause));\r\n }\r\n\r\n /**\r\n * Get all collected CommonTables\r\n */\r\n public getCommonTables(): CommonTable[] {\r\n return this.commonTables;\r\n }\r\n\r\n /**\r\n * Reset the collection of CommonTables\r\n */\r\n private reset(): void {\r\n this.commonTables = [];\r\n this.visitedNodes.clear();\r\n }\r\n\r\n public collect(query: SelectQuery): CommonTable[] {\r\n // Visit the query to collect all CommonTables\r\n this.visit(query);\r\n return this.getCommonTables();\r\n }\r\n\r\n /**\r\n * Main entry point for the visitor pattern.\r\n * Implements the shallow visit pattern to distinguish between root and recursive visits.\r\n */\r\n public visit(arg: SqlComponent): void {\r\n // If not a root visit, just visit the node and return\r\n if (!this.isRootVisit) {\r\n this.visitNode(arg);\r\n return;\r\n }\r\n\r\n // If this is a root visit, we need to reset the state\r\n this.reset();\r\n this.isRootVisit = false;\r\n\r\n try {\r\n this.visitNode(arg);\r\n } finally {\r\n // Regardless of success or failure, reset the root visit flag\r\n this.isRootVisit = true;\r\n }\r\n }\r\n\r\n /**\r\n * Internal visit method used for all nodes.\r\n * This separates the visit flag management from the actual node visitation logic.\r\n */\r\n private visitNode(arg: SqlComponent): void {\r\n // Skip if we've already visited this node to prevent infinite recursion\r\n if (this.visitedNodes.has(arg)) {\r\n return;\r\n }\r\n\r\n // Mark as visited\r\n this.visitedNodes.add(arg);\r\n\r\n const handler = this.handlers.get(arg.getKind());\r\n if (handler) {\r\n handler(arg);\r\n return;\r\n }\r\n\r\n // Provide more detailed error message\r\n const kindSymbol = arg.getKind()?.toString() || 'unknown';\r\n const constructor = arg.constructor?.name || 'unknown';\r\n throw new Error(`[CTECollector] No handler for ${constructor} with kind ${kindSymbol}.`);\r\n }\r\n\r\n private visitSimpleSelectQuery(query: SimpleSelectQuery): void {\r\n // The order matters here!\r\n // First, visit all clauses that might contain nested CTEs\r\n // to ensure inner CTEs are collected before outer CTEs\r\n\r\n // Check FROM clause first (can contain subqueries with nested CTEs)\r\n if (query.fromClause) {\r\n query.fromClause.accept(this);\r\n }\r\n\r\n // Check WHERE clause (can contain subqueries with WITH clauses)\r\n if (query.whereClause) {\r\n query.whereClause.accept(this);\r\n }\r\n\r\n // Check other clauses that might contain CTEs\r\n if (query.groupByClause) {\r\n query.groupByClause.accept(this);\r\n }\r\n\r\n if (query.havingClause) {\r\n query.havingClause.accept(this);\r\n }\r\n\r\n if (query.orderByClause) {\r\n query.orderByClause.accept(this);\r\n }\r\n\r\n if (query.windowClause) {\r\n for (const win of query.windowClause.windows) {\r\n win.accept(this);\r\n }\r\n }\r\n\r\n if (query.limitClause) {\r\n query.limitClause.accept(this);\r\n }\r\n\r\n if (query.forClause) {\r\n query.forClause.accept(this);\r\n }\r\n\r\n // Check SELECT clause\r\n query.selectClause.accept(this);\r\n\r\n // Finally check the WITH clause after all nested CTEs have been collected\r\n // This ensures inner CTEs are collected before outer CTEs\r\n if (query.withClause) {\r\n query.withClause.accept(this);\r\n }\r\n\r\n }\r\n\r\n private visitBinarySelectQuery(query: BinarySelectQuery): void {\r\n // Visit both sides of the binary query (UNION, EXCEPT, etc.)\r\n query.left.accept(this);\r\n query.right.accept(this);\r\n }\r\n\r\n private visitValuesQuery(query: ValuesQuery): void {\r\n // VALUES queries might contain subqueries in tuple expressions\r\n for (const tuple of query.tuples) {\r\n tuple.accept(this);\r\n }\r\n }\r\n\r\n private visitWithClause(withClause: WithClause): void {\r\n // Visit each CommonTable\r\n // Simply process tables in sequence\r\n // Note: visitCommonTable already handles nested CTEs\r\n for (let i = 0; i < withClause.tables.length; i++) {\r\n const commonTable = withClause.tables[i];\r\n commonTable.accept(this);\r\n }\r\n }\r\n\r\n private visitCommonTable(commonTable: CommonTable): void {\r\n // Process CommonTable directly within the query\r\n // Use the same instance to process the query instead of creating another Collector\r\n commonTable.query.accept(this);\r\n\r\n // Add current CTE after all nested CTEs have been added\r\n this.commonTables.push(commonTable);\r\n }\r\n\r\n private visitSelectClause(clause: SelectClause): void {\r\n // Check each item in the select clause\r\n for (const item of clause.items) {\r\n item.accept(this);\r\n }\r\n }\r\n\r\n private visitSelectItem(item: SelectItem): void {\r\n // Select items might contain subqueries\r\n item.value.accept(this);\r\n }\r\n\r\n private visitFromClause(fromClause: FromClause): void {\r\n // Check the source\r\n fromClause.source.accept(this);\r\n\r\n // Check joins\r\n if (fromClause.joins) {\r\n for (const join of fromClause.joins) {\r\n join.accept(this);\r\n }\r\n }\r\n }\r\n\r\n private visitSourceExpression(source: SourceExpression): void {\r\n source.datasource.accept(this);\r\n // The alias part doesn't contain subqueries so we skip it\r\n }\r\n\r\n private visitTableSource(source: TableSource): void {\r\n // Table sources don't contain subqueries, nothing to do\r\n }\r\n\r\n private visitFunctionSource(source: FunctionSource): void {\r\n // Function sources may have arguments that could contain subqueries\r\n if (source.argument) {\r\n source.argument.accept(this);\r\n }\r\n }\r\n\r\n private visitParenSource(source: ParenSource): void {\r\n source.source.accept(this);\r\n }\r\n\r\n private visitSubQuerySource(subQuery: SubQuerySource): void {\r\n subQuery.query.accept(this);\r\n }\r\n\r\n private visitInlineQuery(inlineQuery: InlineQuery): void {\r\n inlineQuery.selectQuery.accept(this);\r\n }\r\n\r\n private visitJoinClause(joinClause: JoinClause): void {\r\n // Check join source\r\n joinClause.source.accept(this);\r\n\r\n // Check join condition\r\n if (joinClause.condition) {\r\n joinClause.condition.accept(this);\r\n }\r\n }\r\n\r\n private visitJoinOnClause(joinOn: JoinOnClause): void {\r\n joinOn.condition.accept(this);\r\n }\r\n\r\n private visitJoinUsingClause(joinUsing: JoinUsingClause): void {\r\n joinUsing.condition.accept(this);\r\n }\r\n\r\n private visitWhereClause(whereClause: WhereClause): void {\r\n whereClause.condition.accept(this);\r\n }\r\n\r\n private visitGroupByClause(clause: GroupByClause): void {\r\n for (const item of clause.grouping) {\r\n item.accept(this);\r\n }\r\n }\r\n\r\n private visitHavingClause(clause: HavingClause): void {\r\n clause.condition.accept(this);\r\n }\r\n\r\n private visitOrderByClause(clause: OrderByClause): void {\r\n for (const item of clause.order) {\r\n item.accept(this);\r\n }\r\n }\r\n\r\n private visitWindowFrameClause(clause: WindowFrameClause): void {\r\n clause.expression.accept(this);\r\n }\r\n\r\n private visitLimitClause(clause: LimitClause): void {\r\n clause.value.accept(this);\r\n }\r\n\r\n private visitForClause(clause: ForClause): void {\r\n // FOR clause doesn't contain subqueries\r\n }\r\n\r\n private visitOrderByItem(item: OrderByItem): void {\r\n item.value.accept(this);\r\n }\r\n\r\n private visitParenExpression(expr: ParenExpression): void {\r\n expr.expression.accept(this);\r\n }\r\n\r\n private visitBinaryExpression(expr: BinaryExpression): void {\r\n expr.left.accept(this);\r\n expr.right.accept(this);\r\n }\r\n\r\n private visitUnaryExpression(expr: UnaryExpression): void {\r\n expr.expression.accept(this);\r\n }\r\n\r\n private visitCaseExpression(expr: CaseExpression): void {\r\n if (expr.condition) {\r\n expr.condition.accept(this);\r\n }\r\n expr.switchCase.accept(this);\r\n }\r\n\r\n private visitSwitchCaseArgument(switchCase: SwitchCaseArgument): void {\r\n // Check all case expressions\r\n for (const caseItem of switchCase.cases) {\r\n caseItem.accept(this);\r\n }\r\n\r\n // Check ELSE expression\r\n if (switchCase.elseValue) {\r\n switchCase.elseValue.accept(this);\r\n }\r\n }\r\n\r\n private visitCaseKeyValuePair(pair: CaseKeyValuePair): void {\r\n // Check the WHEN condition\r\n pair.key.accept(this);\r\n // Check the THEN value\r\n pair.value.accept(this);\r\n }\r\n\r\n private visitBetweenExpression(expr: BetweenExpression): void {\r\n expr.expression.accept(this);\r\n expr.lower.accept(this);\r\n expr.upper.accept(this);\r\n }\r\n\r\n private visitFunctionCall(func: FunctionCall): void {\r\n if (func.argument) {\r\n func.argument.accept(this);\r\n }\r\n\r\n // Check OVER clause if present\r\n if (func.over) {\r\n func.over.accept(this);\r\n }\r\n }\r\n\r\n private visitArrayExpression(expr: ArrayExpression): void {\r\n expr.expression.accept(this);\r\n }\r\n\r\n private visitArrayQueryExpression(expr: ArrayQueryExpression): void {\r\n expr.query.accept(this);\r\n }\r\n\r\n private visitTupleExpression(expr: TupleExpression): void {\r\n // Check each value in the tuple for possible subqueries\r\n for (const value of expr.values) {\r\n value.accept(this);\r\n }\r\n }\r\n\r\n private visitCastExpression(expr: CastExpression): void {\r\n // Check the input expression\r\n expr.input.accept(this);\r\n // Check the type expression\r\n expr.castType.accept(this);\r\n }\r\n\r\n private visitTypeValue(expr: TypeValue): void {\r\n // Visit the argument if present\r\n if (expr.argument) {\r\n expr.argument.accept(this);\r\n }\r\n // The type itself doesn't contain subqueries\r\n }\r\n\r\n private visitWindowFrameExpression(expr: WindowFrameExpression): void {\r\n if (expr.partition) {\r\n expr.partition.accept(this);\r\n }\r\n if (expr.order) {\r\n expr.order.accept(this);\r\n }\r\n if (expr.frameSpec) {\r\n expr.frameSpec.accept(this);\r\n }\r\n }\r\n\r\n private visitWindowFrameSpec(spec: WindowFrameSpec): void {\r\n // WindowFrameSpec is a simple value object, nothing to traverse\r\n }\r\n\r\n private visitIdentifierString(ident: IdentifierString): void {\r\n // Leaf node, nothing to traverse\r\n }\r\n\r\n private visitRawString(raw: RawString): void {\r\n // Leaf node, nothing to traverse\r\n }\r\n\r\n private visitColumnReference(column: ColumnReference): void {\r\n // Column references don't have subqueries\r\n }\r\n\r\n private visitParameterExpression(param: ParameterExpression): void {\r\n // Parameter expressions don't have child components\r\n }\r\n\r\n private visitLiteralValue(value: LiteralValue): void {\r\n // Literal values are leaf nodes\r\n }\r\n\r\n public visitPartitionByClause(partitionBy: PartitionByClause): void {\r\n // don't have subqueries\r\n }\r\n\r\n public visitValueList(valueList: ValueList): void {\r\n for (const value of valueList.values) {\r\n value.accept(this);\r\n }\r\n }\r\n\r\n private visitStringSpecifierExpression(expr: StringSpecifierExpression): void {\r\n // StringSpecifierExpression contains RawString and LiteralValue which are leaf nodes\r\n // No need to visit children as they don't contain subqueries\r\n }\r\n}", "import { CommonTable, ForClause, FromClause, GroupByClause, HavingClause, JoinClause, JoinConditionComponent, JoinOnClause, JoinUsingClause, LimitClause, OrderByClause, OrderByComponent, OrderByItem, ParenSource, PartitionByClause, SelectClause, SelectItem, SourceAliasExpression, SourceComponent, SourceExpression, SubQuerySource, TableSource, WhereClause, WindowFrameClause, WindowsClause, WithClause } from \"../models/Clause\";\r\nimport { BinarySelectQuery, SimpleSelectQuery, SelectQuery, ValuesQuery } from \"../models/SelectQuery\";\r\nimport { SqlComponent, SqlComponentVisitor } from \"../models/SqlComponent\";\r\nimport {\r\n ArrayExpression, ArrayQueryExpression, BetweenExpression, BinaryExpression, CaseExpression, CaseKeyValuePair,\r\n CastExpression, ColumnReference, FunctionCall, InlineQuery, ParenExpression,\r\n ParameterExpression, SwitchCaseArgument, TupleExpression, UnaryExpression, ValueComponent,\r\n OverExpression, WindowFrameExpression, IdentifierString, RawString,\r\n WindowFrameSpec,\r\n LiteralValue,\r\n TypeValue\r\n} from \"../models/ValueComponent\";\r\n\r\n/**\r\n * A visitor that disables all WITH clauses in a SQL query structure.\r\n * This processes and removes WITH clauses from:\r\n * - Simple SELECT queries\r\n * - Binary queries (UNION, EXCEPT, etc.)\r\n * - Subqueries\r\n * - Inline queries\r\n * \r\n * It maintains the CTE queries themselves but restructures the query to not use\r\n * the WITH clause syntactical construct.\r\n */\r\nexport class CTEDisabler implements SqlComponentVisitor<SqlComponent> {\r\n private handlers: Map<symbol, (arg: any) => SqlComponent>;\r\n private visitedNodes: Set<SqlComponent> = new Set();\r\n private isRootVisit: boolean = true;\r\n\r\n constructor() {\r\n this.handlers = new Map<symbol, (arg: any) => SqlComponent>();\r\n\r\n // Setup handlers for all component types that might contain WITH clauses\r\n\r\n // SelectQuery types\r\n this.handlers.set(SimpleSelectQuery.kind, (expr) => this.visitSimpleSelectQuery(expr as SimpleSelectQuery));\r\n this.handlers.set(BinarySelectQuery.kind, (expr) => this.visitBinarySelectQuery(expr as BinarySelectQuery));\r\n this.handlers.set(ValuesQuery.kind, (expr) => this.visitValuesQuery(expr as ValuesQuery));\r\n\r\n // SelectComponent types\r\n this.handlers.set(SelectItem.kind, (expr) => this.visitSelectItem(expr as SelectItem));\r\n\r\n // Identifiers and raw strings\r\n this.handlers.set(IdentifierString.kind, (expr) => this.visitIdentifierString(expr as IdentifierString));\r\n this.handlers.set(RawString.kind, (expr) => this.visitRawString(expr as RawString));\r\n this.handlers.set(ColumnReference.kind, (expr) => this.visitColumnReference(expr as ColumnReference));\r\n this.handlers.set(ParameterExpression.kind, (expr) => this.visitParameterExpression(expr as ParameterExpression));\r\n this.handlers.set(LiteralValue.kind, (expr) => this.visitLiteralValue(expr as LiteralValue));\r\n\r\n // Source components\r\n this.handlers.set(SourceExpression.kind, (expr) => this.visitSourceExpression(expr as SourceExpression));\r\n this.handlers.set(TableSource.kind, (expr) => this.visitTableSource(expr as TableSource));\r\n this.handlers.set(ParenSource.kind, (expr) => this.visitParenSource(expr as ParenSource));\r\n\r\n // Subqueries and inline queries\r\n this.handlers.set(SubQuerySource.kind, (expr) => this.visitSubQuerySource(expr as SubQuerySource));\r\n this.handlers.set(InlineQuery.kind, (expr) => this.visitInlineQuery(expr as InlineQuery));\r\n\r\n // FROM and JOIN clauses\r\n this.handlers.set(FromClause.kind, (expr) => this.visitFromClause(expr as FromClause));\r\n this.handlers.set(JoinClause.kind, (expr) => this.visitJoinClause(expr as JoinClause));\r\n this.handlers.set(JoinOnClause.kind, (expr) => this.visitJoinOnClause(expr as JoinOnClause));\r\n this.handlers.set(JoinUsingClause.kind, (expr) => this.visitJoinUsingClause(expr as JoinUsingClause));\r\n\r\n // WHERE clause\r\n this.handlers.set(WhereClause.kind, (expr) => this.visitWhereClause(expr as WhereClause));\r\n\r\n // Value components that might contain subqueries\r\n this.handlers.set(ParenExpression.kind, (expr) => this.visitParenExpression(expr as ParenExpression));\r\n this.handlers.set(BinaryExpression.kind, (expr) => this.visitBinaryExpression(expr as BinaryExpression));\r\n this.handlers.set(UnaryExpression.kind, (expr) => this.visitUnaryExpression(expr as UnaryExpression));\r\n this.handlers.set(CaseExpression.kind, (expr) => this.visitCaseExpression(expr as CaseExpression));\r\n this.handlers.set(CaseKeyValuePair.kind, (expr) => this.visitCaseKeyValuePair(expr as CaseKeyValuePair));\r\n this.handlers.set(SwitchCaseArgument.kind, (expr) => this.visitSwitchCaseArgument(expr as SwitchCaseArgument));\r\n this.handlers.set(BetweenExpression.kind, (expr) => this.visitBetweenExpression(expr as BetweenExpression));\r\n this.handlers.set(FunctionCall.kind, (expr) => this.visitFunctionCall(expr as FunctionCall));\r\n this.handlers.set(ArrayExpression.kind, (expr) => this.visitArrayExpression(expr as ArrayExpression));\r\n this.handlers.set(ArrayQueryExpression.kind, (expr) => this.visitArrayQueryExpression(expr as ArrayQueryExpression));\r\n this.handlers.set(TupleExpression.kind, (expr) => this.visitTupleExpression(expr as TupleExpression));\r\n this.handlers.set(CastExpression.kind, (expr) => this.visitCastExpression(expr as CastExpression));\r\n this.handlers.set(WindowFrameExpression.kind, (expr) => this.visitWindowFrameExpression(expr as WindowFrameExpression));\r\n this.handlers.set(WindowFrameSpec.kind, (expr) => this.visitWindowFrameSpec(expr as WindowFrameSpec));\r\n this.handlers.set(TypeValue.kind, (expr) => this.visitTypeValue(expr as TypeValue));\r\n\r\n // Add handlers for other clause types\r\n this.handlers.set(SelectClause.kind, (expr) => this.visitSelectClause(expr as SelectClause));\r\n this.handlers.set(GroupByClause.kind, (expr) => this.visitGroupByClause(expr as GroupByClause));\r\n this.handlers.set(HavingClause.kind, (expr) => this.visitHavingClause(expr as HavingClause));\r\n this.handlers.set(OrderByClause.kind, (expr) => this.visitOrderByClause(expr as OrderByClause));\r\n this.handlers.set(WindowFrameClause.kind, (expr) => this.visitWindowFrameClause(expr as WindowFrameClause));\r\n this.handlers.set(LimitClause.kind, (expr) => this.visitLimitClause(expr as LimitClause));\r\n this.handlers.set(ForClause.kind, (expr) => this.visitForClause(expr as ForClause));\r\n this.handlers.set(OrderByItem.kind, (expr) => this.visitOrderByItem(expr as OrderByItem));\r\n }\r\n\r\n /**\r\n * Reset the visited nodes tracking\r\n */\r\n private reset(): void {\r\n this.visitedNodes.clear();\r\n }\r\n\r\n public execute(arg: SqlComponent): SelectQuery {\r\n // Reset the visited nodes before starting the visit\r\n this.reset();\r\n return this.visit(arg) as SelectQuery;\r\n }\r\n\r\n /**\r\n * Main entry point for the visitor pattern.\r\n * Implements the shallow visit pattern to distinguish between root and recursive visits.\r\n */\r\n public visit(arg: SqlComponent): SqlComponent {\r\n // If not a root visit, just visit the node and return\r\n if (!this.isRootVisit) {\r\n return this.visitNode(arg);\r\n }\r\n\r\n // If this is a root visit, we need to reset the state\r\n this.reset();\r\n this.isRootVisit = false;\r\n\r\n try {\r\n return this.visitNode(arg);\r\n } finally {\r\n // Regardless of success or failure, reset the root visit flag\r\n this.isRootVisit = true;\r\n }\r\n }\r\n\r\n /**\r\n * Internal visit method used for all nodes.\r\n * This separates the visit flag management from the actual node visitation logic.\r\n */\r\n private visitNode(arg: SqlComponent): SqlComponent {\r\n // Check for circular references - if node already visited, return as is\r\n if (this.visitedNodes.has(arg)) {\r\n return arg;\r\n }\r\n\r\n // Mark as visited node\r\n this.visitedNodes.add(arg);\r\n\r\n const handler = this.handlers.get(arg.getKind());\r\n if (handler) {\r\n return handler(arg);\r\n }\r\n\r\n // Provide more detailed error message\r\n const kindSymbol = arg.getKind()?.toString() || 'unknown';\r\n const constructor = arg.constructor?.name || 'unknown';\r\n throw new Error(`[CTEDisabler] No handler for ${constructor} with kind ${kindSymbol}.`);\r\n }\r\n\r\n visitSimpleSelectQuery(arg: SimpleSelectQuery): SqlComponent {\r\n if (arg.withClause) {\r\n arg.withClause.tables.forEach(table => {\r\n this.visit(table.query);\r\n });\r\n }\r\n\r\n arg.withClause = null; // Explicitly remove WITH clause\r\n\r\n // Visit the components of the SimpleSelectQuery\r\n arg.selectClause = this.visit(arg.selectClause) as SelectClause;\r\n arg.fromClause = arg.fromClause ? this.visit(arg.fromClause) as FromClause : null;\r\n arg.whereClause = arg.whereClause ? this.visit(arg.whereClause) as WhereClause : null;\r\n arg.groupByClause = arg.groupByClause ? this.visit(arg.groupByClause) as GroupByClause : null;\r\n arg.havingClause = arg.havingClause ? this.visit(arg.havingClause) as HavingClause : null;\r\n arg.orderByClause = arg.orderByClause ? this.visit(arg.orderByClause) as OrderByClause : null;\r\n if (arg.windowClause) {\r\n arg.windowClause = new WindowsClause(arg.windowClause.windows.map(w => this.visit(w) as WindowFrameClause));\r\n }\r\n arg.limitClause = arg.limitClause ? this.visit(arg.limitClause) as LimitClause : null;\r\n arg.forClause = arg.forClause ? this.visit(arg.forClause) as ForClause : null;\r\n return arg;\r\n }\r\n\r\n visitBinarySelectQuery(query: BinarySelectQuery): SqlComponent {\r\n query.left = this.visit(query.left) as SelectQuery;\r\n query.right = this.visit(query.right) as SelectQuery;\r\n return query;\r\n }\r\n\r\n visitValuesQuery(query: ValuesQuery): SqlComponent {\r\n const newTuples = query.tuples.map(tuple => this.visit(tuple) as TupleExpression);\r\n return new ValuesQuery(newTuples);\r\n }\r\n\r\n visitSelectClause(clause: SelectClause): SqlComponent {\r\n const newItems = clause.items.map(item => {\r\n return this.visit(item) as SelectItem;\r\n });\r\n\r\n return new SelectClause(\r\n newItems,\r\n clause.distinct,\r\n );\r\n }\r\n\r\n visitFromClause(clause: FromClause): SqlComponent {\r\n const newSource = this.visit(clause.source) as SourceExpression;\r\n const newJoins = clause.joins ? clause.joins.map(join => this.visit(join) as JoinClause) : null;\r\n\r\n return new FromClause(newSource, newJoins);\r\n }\r\n\r\n visitSubQuerySource(subQuery: SubQuerySource): SqlComponent {\r\n const newQuery = this.visit(subQuery.query) as SelectQuery;\r\n return new SubQuerySource(newQuery);\r\n }\r\n\r\n visitInlineQuery(inlineQuery: InlineQuery): SqlComponent {\r\n const newQuery = this.visit(inlineQuery.selectQuery) as SelectQuery;\r\n return new InlineQuery(newQuery);\r\n }\r\n\r\n visitJoinClause(joinClause: JoinClause): SqlComponent {\r\n const newSource = this.visit(joinClause.source) as SourceExpression;\r\n const newCondition = joinClause.condition ? this.visit(joinClause.condition) as JoinConditionComponent : null;\r\n\r\n return new JoinClause(\r\n joinClause.joinType.value,\r\n newSource,\r\n newCondition,\r\n joinClause.lateral,\r\n );\r\n }\r\n\r\n visitJoinOnClause(joinOn: JoinOnClause): SqlComponent {\r\n const newCondition = this.visit(joinOn.condition) as ValueComponent;\r\n return new JoinOnClause(newCondition);\r\n }\r\n\r\n visitJoinUsingClause(joinUsing: JoinUsingClause): SqlComponent {\r\n const newCondition = this.visit(joinUsing.condition) as ValueComponent;\r\n return new JoinUsingClause(newCondition);\r\n }\r\n\r\n visitWhereClause(whereClause: WhereClause): SqlComponent {\r\n const newCondition = this.visit(whereClause.condition) as ValueComponent;\r\n return new WhereClause(newCondition);\r\n }\r\n\r\n visitGroupByClause(clause: GroupByClause): SqlComponent {\r\n const newGrouping = clause.grouping.map(item => this.visit(item) as ValueComponent);\r\n return new GroupByClause(newGrouping);\r\n }\r\n\r\n visitHavingClause(clause: HavingClause): SqlComponent {\r\n const newCondition = this.visit(clause.condition) as ValueComponent;\r\n return new HavingClause(newCondition);\r\n }\r\n\r\n visitOrderByClause(clause: OrderByClause): SqlComponent {\r\n const newOrder = clause.order.map(item => this.visit(item) as OrderByComponent);\r\n return new OrderByClause(newOrder);\r\n }\r\n\r\n visitWindowFrameClause(clause: WindowFrameClause): SqlComponent {\r\n const newExpression = this.visit(clause.expression) as WindowFrameExpression;\r\n return new WindowFrameClause(clause.name.name, newExpression);\r\n }\r\n\r\n visitLimitClause(clause: LimitClause): SqlComponent {\r\n const newLimit = this.visit(clause.value) as ValueComponent;\r\n return new LimitClause(newLimit);\r\n }\r\n\r\n visitForClause(clause: ForClause): SqlComponent {\r\n return new ForClause(clause.lockMode);\r\n }\r\n\r\n visitParenExpression(expr: ParenExpression): SqlComponent {\r\n const newExpression = this.visit(expr.expression) as ValueComponent;\r\n return new ParenExpression(newExpression);\r\n }\r\n\r\n visitBinaryExpression(expr: BinaryExpression): SqlComponent {\r\n const newLeft = this.visit(expr.left) as ValueComponent;\r\n const newRight = this.visit(expr.right) as ValueComponent;\r\n return new BinaryExpression(newLeft, expr.operator.value, newRight);\r\n }\r\n\r\n visitUnaryExpression(expr: UnaryExpression): SqlComponent {\r\n const newExpression = this.visit(expr.expression) as ValueComponent;\r\n return new UnaryExpression(expr.operator.value, newExpression);\r\n }\r\n\r\n visitCaseExpression(expr: CaseExpression): SqlComponent {\r\n const newCondition = expr.condition ? this.visit(expr.condition) as ValueComponent : null;\r\n const newSwitchCase = this.visit(expr.switchCase) as SwitchCaseArgument;\r\n return new CaseExpression(newCondition, newSwitchCase);\r\n }\r\n\r\n visitSwitchCaseArgument(switchCase: SwitchCaseArgument): SqlComponent {\r\n const newCases = switchCase.cases.map(caseItem => this.visit(caseItem) as CaseKeyValuePair);\r\n const newElseValue = switchCase.elseValue ? this.visit(switchCase.elseValue) as ValueComponent : null;\r\n return new SwitchCaseArgument(newCases, newElseValue);\r\n }\r\n\r\n visitCaseKeyValuePair(pair: CaseKeyValuePair): SqlComponent {\r\n const newKey = this.visit(pair.key) as ValueComponent;\r\n const newValue = this.visit(pair.value) as ValueComponent;\r\n return new CaseKeyValuePair(newKey, newValue);\r\n }\r\n\r\n visitBetweenExpression(expr: BetweenExpression): SqlComponent {\r\n const newExpression = this.visit(expr.expression) as ValueComponent;\r\n const newLower = this.visit(expr.lower) as ValueComponent;\r\n const newUpper = this.visit(expr.upper) as ValueComponent;\r\n return new BetweenExpression(newExpression, newLower, newUpper, expr.negated);\r\n }\r\n\r\n visitFunctionCall(func: FunctionCall): SqlComponent {\r\n const newArgument = func.argument ? this.visit(func.argument) as ValueComponent : null;\r\n const newOver = func.over ? this.visit(func.over) as OverExpression : null;\r\n return new FunctionCall(func.namespaces, func.name, newArgument, newOver);\r\n }\r\n\r\n visitArrayExpression(expr: ArrayExpression): SqlComponent {\r\n const newExpression = this.visit(expr.expression) as ValueComponent;\r\n return new ArrayExpression(newExpression);\r\n }\r\n\r\n visitArrayQueryExpression(expr: ArrayQueryExpression): SqlComponent {\r\n const newQuery = this.visit(expr.query) as SelectQuery;\r\n return new ArrayQueryExpression(newQuery);\r\n }\r\n\r\n visitTupleExpression(expr: TupleExpression): SqlComponent {\r\n const newValues = expr.values.map(value => this.visit(value) as ValueComponent);\r\n return new TupleExpression(newValues);\r\n }\r\n\r\n visitCastExpression(expr: CastExpression): SqlComponent {\r\n const newInput = this.visit(expr.input) as ValueComponent;\r\n const newCastType = this.visit(expr.castType) as TypeValue;\r\n return new CastExpression(newInput, newCastType);\r\n }\r\n\r\n visitTypeValue(typeValue: TypeValue): SqlComponent {\r\n const newArgument = typeValue.argument ? this.visit(typeValue.argument) as ValueComponent : null;\r\n return new TypeValue(typeValue.namespaces, typeValue.name, newArgument);\r\n }\r\n\r\n visitSelectItem(item: SelectItem): SqlComponent {\r\n const newValue = this.visit(item.value) as ValueComponent;\r\n return new SelectItem(newValue, item.identifier?.name);\r\n }\r\n\r\n visitIdentifierString(ident: IdentifierString): SqlComponent {\r\n // Identifiers don't have child components, so just return as-is\r\n return ident;\r\n }\r\n\r\n visitRawString(raw: RawString): SqlComponent {\r\n // Raw strings don't have child components, so just return as-is\r\n return raw;\r\n }\r\n\r\n visitColumnReference(column: ColumnReference): SqlComponent {\r\n // Column references don't have subqueries, so just return as-is\r\n return column;\r\n }\r\n\r\n visitSourceExpression(source: SourceExpression): SqlComponent {\r\n const newSource = this.visit(source.datasource) as SourceComponent;\r\n // SourceAliasEpression don't contain subqueries, so just return as-is\r\n const newAlias = source.aliasExpression;\r\n return new SourceExpression(newSource, newAlias);\r\n }\r\n\r\n visitTableSource(source: TableSource): SqlComponent {\r\n // Table sources don't contain subqueries, so just return as-is\r\n return source;\r\n }\r\n\r\n visitParenSource(source: ParenSource): SqlComponent {\r\n const newSource = this.visit(source.source) as SourceComponent;\r\n return new ParenSource(newSource);\r\n }\r\n\r\n visitParameterExpression(param: ParameterExpression): SqlComponent {\r\n // Parameter expressions don't have child components, so just return as-is\r\n return param;\r\n }\r\n\r\n visitWindowFrameExpression(expr: WindowFrameExpression): SqlComponent {\r\n const newPartition = expr.partition ? this.visit(expr.partition) as PartitionByClause : null;\r\n const newOrder = expr.order ? this.visit(expr.order) as OrderByClause : null;\r\n const newFrameSpec = expr.frameSpec ? this.visit(expr.frameSpec) as WindowFrameSpec : null;\r\n\r\n return new WindowFrameExpression(\r\n newPartition,\r\n newOrder,\r\n newFrameSpec\r\n );\r\n }\r\n\r\n visitWindowFrameSpec(spec: WindowFrameSpec): SqlComponent {\r\n // WindowFrameSpec is a simple value object, so return as-is\r\n return spec;\r\n }\r\n\r\n visitLiteralValue(value: ValueComponent): SqlComponent {\r\n // Literal values are returned as-is\r\n return value;\r\n }\r\n\r\n visitOrderByItem(item: OrderByItem): SqlComponent {\r\n const newValue = this.visit(item.value) as ValueComponent;\r\n return new OrderByItem(newValue, item.sortDirection, item.nullsPosition);\r\n }\r\n}", "import { CommonTable, FetchClause, ForClause, FromClause, FunctionSource, GroupByClause, HavingClause, JoinClause, JoinOnClause, JoinUsingClause, LimitClause, OffsetClause, OrderByClause, OrderByItem, ParenSource, PartitionByClause, SelectClause, SelectItem, SourceExpression, SubQuerySource, TableSource, WhereClause, WindowFrameClause, WindowsClause, WithClause } from \"../models/Clause\";\r\nimport { BinarySelectQuery, SelectQuery, SimpleSelectQuery, ValuesQuery } from \"../models/SelectQuery\";\r\nimport { SqlComponent, SqlComponentVisitor } from \"../models/SqlComponent\";\r\nimport {\r\n ArrayExpression, ArrayQueryExpression, BetweenExpression, BinaryExpression, CaseExpression, CaseKeyValuePair,\r\n CastExpression, ColumnReference, FunctionCall, InlineQuery, ParenExpression,\r\n ParameterExpression, SwitchCaseArgument, TupleExpression, UnaryExpression, ValueComponent, ValueList,\r\n OverExpression, WindowFrameExpression, IdentifierString, RawString,\r\n WindowFrameSpec,\r\n LiteralValue,\r\n TypeValue,\r\n StringSpecifierExpression\r\n} from \"../models/ValueComponent\";\r\nimport { CTECollector } from \"./CTECollector\";\r\n\r\n/**\r\n * A visitor that collects all table source names from a SQL query structure.\r\n * \r\n * When selectableOnly is true (default behavior):\r\n * - Includes only table sources from FROM and JOIN clauses\r\n * - Excludes inline queries, subqueries, and CTEs\r\n * \r\n * When selectableOnly is false:\r\n * - Scans all parts of the query including WITH clauses, subqueries, etc.\r\n * - Collects all table sources from the entire query\r\n * - Excludes tables that are managed by CTEs\r\n * \r\n * For UNION-like queries, it scans both the left and right parts.\r\n */\r\nexport class TableSourceCollector implements SqlComponentVisitor<void> {\r\n private handlers: Map<symbol, (arg: any) => void>;\r\n private tableSources: TableSource[] = [];\r\n private visitedNodes: Set<SqlComponent> = new Set();\r\n private tableNameMap: Map<string, boolean> = new Map<string, boolean>();\r\n private selectableOnly: boolean;\r\n private cteNames: Set<string> = new Set<string>();\r\n private isRootVisit: boolean = true;\r\n\r\n constructor(selectableOnly: boolean = true) {\r\n this.selectableOnly = selectableOnly;\r\n this.handlers = new Map<symbol, (arg: any) => void>();\r\n\r\n // Setup handlers for query components\r\n this.handlers.set(SimpleSelectQuery.kind, (expr) => this.visitSimpleSelectQuery(expr as SimpleSelectQuery));\r\n this.handlers.set(BinarySelectQuery.kind, (expr) => this.visitBinarySelectQuery(expr as BinarySelectQuery));\r\n this.handlers.set(ValuesQuery.kind, (expr) => this.visitValuesQuery(expr as ValuesQuery));\r\n\r\n // WITH clause and common tables\r\n this.handlers.set(WithClause.kind, (expr) => this.visitWithClause(expr as WithClause));\r\n this.handlers.set(CommonTable.kind, (expr) => this.visitCommonTable(expr as CommonTable));\r\n\r\n // Handlers for FROM and JOIN components\r\n this.handlers.set(FromClause.kind, (expr) => this.visitFromClause(expr as FromClause));\r\n this.handlers.set(JoinClause.kind, (expr) => this.visitJoinClause(expr as JoinClause));\r\n this.handlers.set(JoinOnClause.kind, (expr) => this.visitJoinOnClause(expr as JoinOnClause));\r\n this.handlers.set(JoinUsingClause.kind, (expr) => this.visitJoinUsingClause(expr as JoinUsingClause));\r\n\r\n // Source components\r\n this.handlers.set(SourceExpression.kind, (expr) => this.visitSourceExpression(expr as SourceExpression));\r\n this.handlers.set(TableSource.kind, (expr) => this.visitTableSource(expr as TableSource));\r\n this.handlers.set(FunctionSource.kind, (expr) => this.visitFunctionSource(expr as FunctionSource));\r\n this.handlers.set(ParenSource.kind, (expr) => this.visitParenSource(expr as ParenSource));\r\n this.handlers.set(SubQuerySource.kind, (expr) => this.visitSubQuerySource(expr as SubQuerySource));\r\n this.handlers.set(InlineQuery.kind, (expr) => this.visitInlineQuery(expr as InlineQuery));\r\n\r\n // Only register these handlers when not in selectableOnly mode\r\n if (!selectableOnly) {\r\n // Additional clause handlers for full scanning\r\n this.handlers.set(WhereClause.kind, (expr) => this.visitWhereClause(expr as WhereClause));\r\n this.handlers.set(GroupByClause.kind, (expr) => this.visitGroupByClause(expr as GroupByClause));\r\n this.handlers.set(HavingClause.kind, (expr) => this.visitHavingClause(expr as HavingClause));\r\n this.handlers.set(OrderByClause.kind, (expr) => this.visitOrderByClause(expr as OrderByClause));\r\n this.handlers.set(WindowFrameClause.kind, (expr) => this.visitWindowFrameClause(expr as WindowFrameClause));\r\n this.handlers.set(LimitClause.kind, (expr) => this.visitLimitClause(expr as LimitClause));\r\n this.handlers.set(OffsetClause.kind, (expr) => this.visitOffsetClause(expr as OffsetClause));\r\n this.handlers.set(FetchClause.kind, (expr) => this.visitFetchClause(expr as FetchClause));\r\n this.handlers.set(ForClause.kind, (expr) => this.visitForClause(expr as ForClause));\r\n this.handlers.set(OrderByItem.kind, (expr) => this.visitOrderByItem(expr as OrderByItem));\r\n this.handlers.set(SelectClause.kind, (expr) => this.visitSelectClause(expr as SelectClause));\r\n this.handlers.set(SelectItem.kind, (expr) => this.visitSelectItem(expr as SelectItem));\r\n\r\n // Value components that might contain table references\r\n this.handlers.set(ParenExpression.kind, (expr) => this.visitParenExpression(expr as ParenExpression));\r\n this.handlers.set(BinaryExpression.kind, (expr) => this.visitBinaryExpression(expr as BinaryExpression));\r\n this.handlers.set(UnaryExpression.kind, (expr) => this.visitUnaryExpression(expr as UnaryExpression));\r\n this.handlers.set(CaseExpression.kind, (expr) => this.visitCaseExpression(expr as CaseExpression));\r\n this.handlers.set(CaseKeyValuePair.kind, (expr) => this.visitCaseKeyValuePair(expr as CaseKeyValuePair));\r\n this.handlers.set(SwitchCaseArgument.kind, (expr) => this.visitSwitchCaseArgument(expr as SwitchCaseArgument));\r\n this.handlers.set(BetweenExpression.kind, (expr) => this.visitBetweenExpression(expr as BetweenExpression));\r\n this.handlers.set(FunctionCall.kind, (expr) => this.visitFunctionCall(expr as FunctionCall));\r\n this.handlers.set(ArrayExpression.kind, (expr) => this.visitArrayExpression(expr as ArrayExpression));\r\n this.handlers.set(ArrayQueryExpression.kind, (expr) => this.visitArrayQueryExpression(expr as ArrayQueryExpression));\r\n this.handlers.set(TupleExpression.kind, (expr) => this.visitTupleExpression(expr as TupleExpression));\r\n this.handlers.set(CastExpression.kind, (expr) => this.visitCastExpression(expr as CastExpression));\r\n this.handlers.set(ValueList.kind, (expr) => this.visitValueList(expr as ValueList));\r\n this.handlers.set(StringSpecifierExpression.kind, (expr) => this.visitStringSpecifierExpression(expr as StringSpecifierExpression));\r\n }\r\n }\r\n\r\n /**\r\n * Gets all collected table sources\r\n */\r\n public getTableSources(): TableSource[] {\r\n return this.tableSources;\r\n }\r\n\r\n /**\r\n * Reset the collection of table sources\r\n */\r\n private reset(): void {\r\n this.tableSources = [];\r\n this.tableNameMap.clear();\r\n this.visitedNodes.clear();\r\n this.cteNames.clear();\r\n }\r\n\r\n /**\r\n * Gets a unique identifier for a table source\r\n */\r\n private getTableIdentifier(source: TableSource): string {\r\n // Use QualifiedName for identifier (dot-joined string)\r\n if (source.qualifiedName.namespaces && source.qualifiedName.namespaces.length > 0) {\r\n return source.qualifiedName.namespaces.map(ns => ns.name).join('.') + '.' + (source.qualifiedName.name instanceof RawString ? source.qualifiedName.name.value : source.qualifiedName.name.name);\r\n } else {\r\n return source.qualifiedName.name instanceof RawString ? source.qualifiedName.name.value : source.qualifiedName.name.name;\r\n }\r\n }\r\n\r\n public collect(query: SqlComponent): TableSource[] {\r\n // Visit the SQL component to collect table sources\r\n this.visit(query);\r\n return this.getTableSources();\r\n }\r\n\r\n /**\r\n * Main entry point for the visitor pattern.\r\n * Implements the shallow visit pattern to distinguish between root and recursive visits.\r\n */\r\n public visit(arg: SqlComponent): void {\r\n // If not a root visit, just visit the node and return\r\n if (!this.isRootVisit) {\r\n this.visitNode(arg);\r\n return;\r\n }\r\n\r\n // If this is a root visit, we need to reset the state\r\n this.reset();\r\n this.isRootVisit = false;\r\n\r\n try {\r\n // When in full scan mode, collect CTEs first to exclude them from table sources\r\n if (!this.selectableOnly) {\r\n this.collectCTEs(arg);\r\n }\r\n this.visitNode(arg);\r\n } finally {\r\n // Regardless of success or failure, reset the root visit flag\r\n this.isRootVisit = true;\r\n }\r\n }\r\n\r\n /**\r\n * Internal visit method used for all nodes.\r\n * This separates the visit flag management from the actual node visitation logic.\r\n */\r\n private visitNode(arg: SqlComponent): void {\r\n // Skip if we've already visited this node to prevent infinite recursion\r\n if (this.visitedNodes.has(arg)) {\r\n return;\r\n }\r\n\r\n // Mark as visited\r\n this.visitedNodes.add(arg);\r\n\r\n const handler = this.handlers.get(arg.getKind());\r\n if (handler) {\r\n handler(arg);\r\n return;\r\n }\r\n\r\n // If no handler found, that's ok - we only care about specific components\r\n }\r\n\r\n /**\r\n * Collects all CTE names to exclude them from real table sources\r\n */\r\n private collectCTEs(query: SqlComponent): void {\r\n // Use CommonTableCollector to get all CTEs\r\n const cteCollector = new CTECollector();\r\n cteCollector.visit(query);\r\n const commonTables = cteCollector.getCommonTables();\r\n\r\n // Add CTE names to the set\r\n for (const cte of commonTables) {\r\n // aliasExpression.table is TableSource, so use .table getter (IdentifierString)\r\n this.cteNames.add(cte.aliasExpression.table.name);\r\n }\r\n }\r\n\r\n private visitSimpleSelectQuery(query: SimpleSelectQuery): void {\r\n // Process the FROM and JOIN clauses\r\n if (query.fromClause) {\r\n query.fromClause.accept(this);\r\n }\r\n\r\n // If in full scan mode, visit all other clauses too\r\n if (!this.selectableOnly) {\r\n if (query.withClause) {\r\n query.withClause.accept(this);\r\n }\r\n\r\n if (query.whereClause) {\r\n query.whereClause.accept(this);\r\n }\r\n\r\n if (query.groupByClause) {\r\n query.groupByClause.accept(this);\r\n }\r\n\r\n if (query.havingClause) {\r\n query.havingClause.accept(this);\r\n }\r\n\r\n if (query.orderByClause) {\r\n query.orderByClause.accept(this);\r\n }\r\n\r\n if (query.windowClause) {\r\n for (const win of query.windowClause.windows) {\r\n win.accept(this);\r\n }\r\n }\r\n\r\n if (query.limitClause) {\r\n query.limitClause.accept(this);\r\n }\r\n\r\n if (query.offsetClause) {\r\n query.offsetClause.accept(this);\r\n }\r\n\r\n if (query.fetchClause) {\r\n query.fetchClause.accept(this);\r\n }\r\n\r\n if (query.forClause) {\r\n query.forClause.accept(this);\r\n }\r\n\r\n query.selectClause.accept(this);\r\n }\r\n }\r\n\r\n private visitBinarySelectQuery(query: BinarySelectQuery): void {\r\n // For UNION-like queries, visit both sides\r\n query.left.accept(this);\r\n query.right.accept(this);\r\n }\r\n\r\n private visitValuesQuery(query: ValuesQuery): void {\r\n if (!this.selectableOnly) {\r\n // VALUES queries might contain subqueries in tuple expressions\r\n for (const tuple of query.tuples) {\r\n tuple.accept(this);\r\n }\r\n }\r\n }\r\n\r\n private visitWithClause(withClause: WithClause): void {\r\n if (!this.selectableOnly) {\r\n // Visit each CommonTable\r\n for (const table of withClause.tables) {\r\n table.accept(this);\r\n }\r\n }\r\n }\r\n\r\n private visitCommonTable(commonTable: CommonTable): void {\r\n if (!this.selectableOnly) {\r\n // Process the query within the common table\r\n commonTable.query.accept(this);\r\n }\r\n }\r\n\r\n private visitFromClause(fromClause: FromClause): void {\r\n // Check the main source in FROM clause\r\n fromClause.source.accept(this);\r\n\r\n // Check all JOIN clauses\r\n if (fromClause.joins) {\r\n for (const join of fromClause.joins) {\r\n join.accept(this);\r\n }\r\n }\r\n }\r\n\r\n private visitSourceExpression(source: SourceExpression): void {\r\n // Process the actual data source, ignoring aliases\r\n source.datasource.accept(this);\r\n }\r\n\r\n private visitTableSource(source: TableSource): void {\r\n // Get the table identifier for uniqueness check\r\n const identifier = this.getTableIdentifier(source);\r\n\r\n // Check if this is a table managed by a CTE\r\n if (!this.tableNameMap.has(identifier) && !this.isCTETable(source.table.name)) {\r\n this.tableNameMap.set(identifier, true);\r\n this.tableSources.push(source);\r\n }\r\n }\r\n\r\n private visitFunctionSource(source: FunctionSource): void {\r\n // Function sources are not regular table sources, but may contain subqueries in their arguments\r\n if (source.argument) {\r\n // Special handling for function arguments to ensure we traverse nested structures\r\n this.visitValueComponent(source.argument);\r\n }\r\n // Function sources themselves are not collected as table sources\r\n }\r\n\r\n /**\r\n * Helper method to visit value components, handling special cases like TupleExpression, ParenExpression, InlineQuery, and ArrayQueryExpression\r\n * even in selectableOnly mode when they appear in function arguments\r\n */\r\n private visitValueComponent(value: ValueComponent): void {\r\n // Always use the normal accept pattern - let handlers deal with the logic\r\n value.accept(this);\r\n }\r\n\r\n /**\r\n * Checks if a table name is a CTE name\r\n */\r\n private isCTETable(tableName: string): boolean {\r\n return this.cteNames.has(tableName);\r\n }\r\n\r\n private visitParenSource(source: ParenSource): void {\r\n // For parenthesized sources, visit the inner source\r\n source.source.accept(this);\r\n }\r\n\r\n private visitSubQuerySource(subQuery: SubQuerySource): void {\r\n if (!this.selectableOnly) {\r\n // In full scan mode, we also check subqueries\r\n subQuery.query.accept(this);\r\n }\r\n // In selectableOnly mode, we don't collect sources from subqueries\r\n }\r\n\r\n private visitInlineQuery(inlineQuery: InlineQuery): void {\r\n if (!this.selectableOnly) {\r\n // In full scan mode, visit inline queries too\r\n inlineQuery.selectQuery.accept(this);\r\n }\r\n }\r\n\r\n private visitJoinClause(joinClause: JoinClause): void {\r\n // Visit the source being joined\r\n joinClause.source.accept(this);\r\n\r\n // If full scanning, also visit the join condition\r\n if (!this.selectableOnly && joinClause.condition) {\r\n joinClause.condition.accept(this);\r\n }\r\n }\r\n\r\n private visitJoinOnClause(joinOn: JoinOnClause): void {\r\n if (!this.selectableOnly) {\r\n // In full scan mode, check ON condition for table references\r\n joinOn.condition.accept(this);\r\n }\r\n }\r\n\r\n private visitJoinUsingClause(joinUsing: JoinUsingClause): void {\r\n if (!this.selectableOnly) {\r\n // In full scan mode, check USING condition for table references\r\n joinUsing.condition.accept(this);\r\n }\r\n }\r\n\r\n // Additional visitor methods only used in full scan mode\r\n\r\n private visitWhereClause(whereClause: WhereClause): void {\r\n whereClause.condition.accept(this);\r\n }\r\n\r\n private visitGroupByClause(clause: GroupByClause): void {\r\n for (const item of clause.grouping) {\r\n item.accept(this);\r\n }\r\n }\r\n\r\n private visitHavingClause(clause: HavingClause): void {\r\n clause.condition.accept(this);\r\n }\r\n\r\n private visitOrderByClause(clause: OrderByClause): void {\r\n for (const item of clause.order) {\r\n item.accept(this);\r\n }\r\n }\r\n\r\n private visitWindowFrameClause(clause: WindowFrameClause): void {\r\n clause.expression.accept(this);\r\n }\r\n\r\n private visitLimitClause(clause: LimitClause): void {\r\n clause.value.accept(this);\r\n }\r\n\r\n private visitOffsetClause(clause: OffsetClause): void {\r\n clause.value.accept(this);\r\n }\r\n\r\n private visitFetchClause(clause: FetchClause): void {\r\n clause.expression.accept(this);\r\n }\r\n\r\n private visitForClause(clause: ForClause): void {\r\n // FOR clause doesn't contain table sources\r\n }\r\n\r\n private visitOrderByItem(item: OrderByItem): void {\r\n item.value.accept(this);\r\n }\r\n\r\n private visitSelectClause(clause: SelectClause): void {\r\n for (const item of clause.items) {\r\n item.accept(this);\r\n }\r\n }\r\n\r\n private visitSelectItem(item: SelectItem): void {\r\n item.value.accept(this);\r\n }\r\n\r\n private visitParenExpression(expr: ParenExpression): void {\r\n expr.expression.accept(this);\r\n }\r\n\r\n private visitBinaryExpression(expr: BinaryExpression): void {\r\n expr.left.accept(this);\r\n expr.right.accept(this);\r\n }\r\n\r\n private visitUnaryExpression(expr: UnaryExpression): void {\r\n expr.expression.accept(this);\r\n }\r\n\r\n private visitCaseExpression(expr: CaseExpression): void {\r\n if (expr.condition) {\r\n expr.condition.accept(this);\r\n }\r\n expr.switchCase.accept(this);\r\n }\r\n\r\n private visitSwitchCaseArgument(switchCase: SwitchCaseArgument): void {\r\n for (const caseItem of switchCase.cases) {\r\n caseItem.accept(this);\r\n }\r\n\r\n if (switchCase.elseValue) {\r\n switchCase.elseValue.accept(this);\r\n }\r\n }\r\n\r\n private visitCaseKeyValuePair(pair: CaseKeyValuePair): void {\r\n pair.key.accept(this);\r\n pair.value.accept(this);\r\n }\r\n\r\n private visitBetweenExpression(expr: BetweenExpression): void {\r\n expr.expression.accept(this);\r\n expr.lower.accept(this);\r\n expr.upper.accept(this);\r\n }\r\n\r\n private visitFunctionCall(func: FunctionCall): void {\r\n if (func.argument) {\r\n func.argument.accept(this);\r\n }\r\n\r\n if (func.over) {\r\n func.over.accept(this);\r\n }\r\n }\r\n\r\n private visitArrayExpression(expr: ArrayExpression): void {\r\n expr.expression.accept(this);\r\n }\r\n\r\n private visitArrayQueryExpression(expr: ArrayQueryExpression): void {\r\n expr.query.accept(this);\r\n }\r\n\r\n private visitTupleExpression(expr: TupleExpression): void {\r\n for (const value of expr.values) {\r\n value.accept(this);\r\n }\r\n }\r\n\r\n private visitCastExpression(expr: CastExpression): void {\r\n expr.input.accept(this);\r\n expr.castType.accept(this);\r\n }\r\n\r\n private visitValueList(valueList: ValueList): void {\r\n // Process all values in the list, this may include InlineQuery and other table-referencing components\r\n for (const value of valueList.values) {\r\n value.accept(this);\r\n }\r\n }\r\n\r\n // Handle StringSpecifierExpression (PostgreSQL E-strings)\r\n private visitStringSpecifierExpression(expr: StringSpecifierExpression): void {\r\n // StringSpecifierExpression is just a literal string with an escape specifier\r\n // It doesn't contain table references, so we don't need to visit any children\r\n // This is a no-op method to prevent \"No handler\" errors\r\n }\r\n}", "export enum SqlPrintTokenType {\r\n container = 0,\r\n keyword,\r\n value, // Represents non-keyword elements such as table names\r\n comma, // Represents comma ','\r\n parenthesis, // Represents parentheses: ( ) { } [ ]\r\n operator, // Represents operators such as +, -, *, /\r\n comment,\r\n parameter,\r\n dot,\r\n type,\r\n space,\r\n argumentSplitter,\r\n}\r\n\r\n// Enum for container type, used for formatting and context\r\nexport enum SqlPrintTokenContainerType {\r\n ColumnReference = 'ColumnReference',\r\n LiteralValue = 'LiteralValue',\r\n IdentifierString = 'IdentifierString',\r\n InlineQuery = 'InlineQuery',\r\n StringSpecifierExpression = 'StringSpecifierExpression',\r\n None = '',\r\n ValueList = 'ValueList',\r\n OrderByItem = 'OrderByItem',\r\n FunctionCall = 'FunctionCall',\r\n UnaryExpression = 'UnaryExpression',\r\n BinaryExpression = 'BinaryExpression',\r\n SwitchCaseArgument = 'SwitchCaseArgument',\r\n ElseClause = 'ElseClause',\r\n CaseKeyValuePair = 'CaseKeyValuePair',\r\n CaseThenValue = 'CaseThenValue',\r\n CaseElseValue = 'CaseElseValue',\r\n ParenExpression = 'ParenExpression',\r\n CastExpression = 'CastExpression',\r\n CaseExpression = 'CaseExpression',\r\n ArrayExpression = 'ArrayExpression',\r\n BetweenExpression = 'BetweenExpression',\r\n TypeValue = 'TypeValue',\r\n TupleExpression = 'TupleExpression',\r\n WindowFrameExpression = 'WindowFrameExpression',\r\n SelectItem = 'SelectItem',\r\n SelectClause = 'SelectClause',\r\n DistinctOn = 'DistinctOn',\r\n SourceExpression = 'SourceExpression',\r\n FromClause = 'FromClause',\r\n JoinClause = 'JoinClause',\r\n JoinOnClause = 'JoinOnClause',\r\n JoinUsingClause = 'JoinUsingClause',\r\n FunctionSource = 'FunctionSource',\r\n SourceAliasExpression = 'SourceAliasExpression',\r\n RawString = 'RawString',\r\n QualifiedName = \"QualifiedName\",\r\n WhereClause = \"WhereClause\",\r\n SimpleSelectQuery = \"SimpleSelectQuery\",\r\n OrderByClause = \"OrderByClause\",\r\n GroupByClause = \"GroupByClause\",\r\n HavingClause = \"HavingClause\",\r\n SubQuerySource = \"SubQuerySource\",\r\n PartitionByClause = \"PartitionByClause\",\r\n WindowFrameClause = \"WindowFrameClause\",\r\n LimitClause = \"LimitClause\",\r\n OffsetClause = \"OffsetClause\",\r\n ForClause = \"ForClause\",\r\n WindowClause = \"WindowClause\",\r\n BinarySelectQueryOperator = \"BinarySelectQueryOperator\",\r\n Values = \"Values\",\r\n ValuesQuery = \"ValuesQuery\",\r\n WithClause = \"WithClause\",\r\n CommonTable = \"CommonTable\",\r\n WindowFrameSpec = \"WindowFrameSpec\",\r\n WindowFrameBoundStatic = \"WindowFrameBoundStatic\",\r\n WindowFrameBoundaryValue = \"WindowFrameBoundaryValue\",\r\n FetchClause = \"FetchClause\",\r\n FetchExpression = \"FetchExpression\",\r\n InsertQuery = \"InsertQuery\",\r\n UpdateQuery = \"UpdateQuery\",\r\n UpdateClause = \"UpdateClause\",\r\n ReturningClause = \"ReturningClause\",\r\n SetClauseItem = \"SetClauseItem\",\r\n CreateTableQuery = \"CreateTableQuery\",\r\n // Add more as needed\r\n}\r\n\r\nexport class SqlPrintToken {\r\n /**\r\n * The type of this token, representing the general category (e.g. keyword, value, operator).\r\n */\r\n type: SqlPrintTokenType;\r\n /**\r\n * The actual text content of this token, following SQL syntax.\r\n */\r\n text: string;\r\n /**\r\n * The type of the container this token belongs to. Used for clauses, functions, or other groupings.\r\n */\r\n containerType: SqlPrintTokenContainerType;\r\n\r\n /**\r\n * Optional. Keywords that are part of this token, like DISTINCT in a SELECT clause.\r\n * These should typically be processed before innerTokens.\r\n */\r\n keywordTokens?: SqlPrintToken[];\r\n\r\n /**\r\n * Child tokens that belong to this container.\r\n */\r\n innerTokens: SqlPrintToken[] = [];\r\n\r\n constructor(type: SqlPrintTokenType, text: string = '', containerType: SqlPrintTokenContainerType = SqlPrintTokenContainerType.None) {\r\n this.type = type;\r\n this.text = text;\r\n this.containerType = containerType;\r\n }\r\n}\r\n", "import { ParameterExpression } from \"../models/ValueComponent\";\r\n\r\n/**\r\n * Utility class to collect all ParameterExpression nodes from an AST.\r\n */\r\nexport class ParameterCollector {\r\n /**\r\n * Recursively collect all ParameterExpression nodes from AST.\r\n * @param node AST root\r\n * @returns ParameterExpression[]\r\n */\r\n static collect(node: any): ParameterExpression[] {\r\n const result: ParameterExpression[] = [];\r\n function walk(n: any) {\r\n if (!n || typeof n !== 'object') return;\r\n if (n.constructor && n.constructor.kind === ParameterExpression.kind) {\r\n result.push(n);\r\n }\r\n for (const key of Object.keys(n)) {\r\n const v = n[key];\r\n if (Array.isArray(v)) {\r\n v.forEach(walk);\r\n } else if (v && typeof v === 'object' && v.constructor && v.constructor.kind) {\r\n walk(v);\r\n }\r\n }\r\n }\r\n walk(node);\r\n return result;\r\n }\r\n}\r\n", "export class IdentifierDecorator {\r\n start: string;\r\n end: string;\r\n\r\n constructor(identifierEscape?: { start?: string; end?: string }) {\r\n this.start = identifierEscape?.start ?? '\"';\r\n this.end = identifierEscape?.end ?? '\"';\r\n }\r\n\r\n decorate(text: string): string {\r\n // override\r\n text = this.start + text + this.end;\r\n return text;\r\n }\r\n}\r\n", "/**\r\n * This decorator formats parameter tokens according to DBMS-specific rules.\r\n * It supports prefix/suffix, and parameter style (named, indexed, anonymous).\r\n */\r\nexport class ParameterDecorator {\r\n prefix: string;\r\n suffix: string;\r\n style: 'named' | 'indexed' | 'anonymous';\r\n\r\n constructor(options?: { prefix?: string; suffix?: string; style?: 'named' | 'indexed' | 'anonymous' }) {\r\n this.prefix = options?.prefix ?? ':';\r\n this.suffix = options?.suffix ?? '';\r\n this.style = options?.style ?? 'named';\r\n }\r\n\r\n /**\r\n * Decorate a parameter token with DBMS-specific format.\r\n * @param token The parameter token\r\n * @param index The parameter index (for indexed/anonymous)\r\n */\r\n decorate(text: string, index: number): string {\r\n let paramText = '';\r\n if (this.style === 'anonymous') {\r\n // e.g. ?\r\n paramText = this.prefix;\r\n } else if (this.style === 'indexed') {\r\n // e.g. $1, ?1, :1\r\n paramText = this.prefix + index;\r\n } else if (this.style === 'named') {\r\n // e.g. :name, @name, ${name}\r\n paramText = this.prefix + text + this.suffix;\r\n }\r\n\r\n // override \r\n text = paramText;\r\n return text;\r\n }\r\n}\r\n", "// Represents an UPDATE query in SQL.\r\n// Supports SET, WHERE, and optional FROM/RETURNING clauses.\r\nimport { SqlComponent } from \"./SqlComponent\";\r\nimport { IdentifierString, ValueComponent } from \"./ValueComponent\";\r\nimport { FromClause, ReturningClause, SetClause, WhereClause, SourceExpression, UpdateClause } from \"./Clause\";\r\nimport { WithClause } from \"./Clause\";\r\n\r\nexport class UpdateQuery extends SqlComponent {\r\n static kind = Symbol(\"UpdateQuery\");\r\n withClause: WithClause | null;\r\n updateClause: UpdateClause;\r\n setClause: SetClause;\r\n whereClause: WhereClause | null;\r\n fromClause: FromClause | null;\r\n returningClause: ReturningClause | null;\r\n\r\n /**\r\n * @param params.source SourceExpression (table or subquery with optional alias)\r\n * @param params.setClause SetClause instance or array of {column, value} pairs\r\n * @param params.where WHERE clause (optional)\r\n * @param params.from FROM clause (optional)\r\n * @param params.returning RETURNING clause (optional)\r\n */\r\n\r\n constructor(params: {\r\n withClause?: WithClause | null;\r\n updateClause: UpdateClause;\r\n setClause: SetClause | { column: string | IdentifierString, value: ValueComponent }[];\r\n whereClause?: WhereClause | null;\r\n fromClause?: FromClause | null;\r\n returning?: ReturningClause | null;\r\n }) {\r\n super();\r\n this.withClause = params.withClause ?? null;\r\n this.updateClause = params.updateClause;\r\n this.setClause = params.setClause instanceof SetClause ? params.setClause : new SetClause(params.setClause);\r\n this.whereClause = params.whereClause ?? null;\r\n this.fromClause = params.fromClause ?? null;\r\n this.returningClause = params.returning ?? null;\r\n }\r\n}\r\n", "import { CommonTable, FromClause, JoinClause, ParenSource, SelectClause, SelectItem, SourceExpression, SubQuerySource, TableSource } from \"../models/Clause\";\r\nimport { BinarySelectQuery, SimpleSelectQuery, SelectQuery, ValuesQuery } from \"../models/SelectQuery\";\r\nimport { SqlComponent, SqlComponentVisitor } from \"../models/SqlComponent\";\r\nimport { ColumnReference, InlineQuery, LiteralValue, ValueComponent } from \"../models/ValueComponent\";\r\nimport { CTECollector } from \"./CTECollector\";\r\nimport { TableColumnResolver } from \"./TableColumnResolver\";\r\n\r\n/**\r\n * A visitor that collects all SelectItem instances from a SQL query structure.\r\n * This visitor scans through select clauses and collects all the SelectItem objects.\r\n * It can also resolve wildcard selectors (table.* or *) using a provided table column resolver.\r\n */\r\nexport class SelectValueCollector implements SqlComponentVisitor<void> {\r\n private handlers: Map<symbol, (arg: any) => void>;\r\n private selectValues: { name: string, value: ValueComponent }[] = [];\r\n private visitedNodes: Set<SqlComponent> = new Set();\r\n private isRootVisit: boolean = true;\r\n private tableColumnResolver: TableColumnResolver | null;\r\n private commonTableCollector: CTECollector;\r\n private commonTables: CommonTable[];\r\n public initialCommonTables: CommonTable[] | null;\r\n\r\n constructor(tableColumnResolver: TableColumnResolver | null = null, initialCommonTables: CommonTable[] | null = null) {\r\n this.tableColumnResolver = tableColumnResolver ?? null;\r\n this.commonTableCollector = new CTECollector();\r\n this.commonTables = [];\r\n this.initialCommonTables = initialCommonTables;\r\n\r\n this.handlers = new Map<symbol, (arg: any) => void>();\r\n\r\n this.handlers.set(SimpleSelectQuery.kind, (expr) => this.visitSimpleSelectQuery(expr as SimpleSelectQuery));\r\n this.handlers.set(SelectClause.kind, (expr) => this.visitSelectClause(expr as SelectClause));\r\n this.handlers.set(SourceExpression.kind, (expr) => this.visitSourceExpression(expr as SourceExpression));\r\n this.handlers.set(FromClause.kind, (expr) => this.visitFromClause(expr as FromClause));\r\n }\r\n\r\n /**\r\n * Get all collected SelectItems as an array of objects with name and value properties\r\n * @returns An array of objects with name (string) and value (ValueComponent) properties\r\n */\r\n public getValues(): { name: string, value: ValueComponent }[] {\r\n return this.selectValues;\r\n }\r\n\r\n /**\r\n * Reset the collection of SelectItems\r\n */\r\n private reset(): void {\r\n this.selectValues = [];\r\n this.visitedNodes.clear();\r\n if (this.initialCommonTables) {\r\n this.commonTables = this.initialCommonTables;\r\n } else {\r\n this.commonTables = [];\r\n }\r\n }\r\n\r\n public collect(arg: SqlComponent): { name: string, value: ValueComponent }[] {\r\n // Visit the component and return the collected select items\r\n this.visit(arg);\r\n const items = this.getValues();\r\n this.reset(); // Reset after collection\r\n return items;\r\n }\r\n\r\n /**\r\n * Main entry point for the visitor pattern.\r\n * Implements the shallow visit pattern to distinguish between root and recursive visits.\r\n */\r\n public visit(arg: SqlComponent): void {\r\n // If not a root visit, just visit the node and return\r\n if (!this.isRootVisit) {\r\n this.visitNode(arg);\r\n return;\r\n }\r\n\r\n // If this is a root visit, we need to reset the state\r\n this.reset();\r\n this.isRootVisit = false;\r\n\r\n try {\r\n this.visitNode(arg);\r\n } finally {\r\n // Regardless of success or failure, reset the root visit flag\r\n this.isRootVisit = true;\r\n }\r\n }\r\n\r\n /**\r\n * Internal visit method used for all nodes.\r\n * This separates the visit flag management from the actual node visitation logic.\r\n */\r\n private visitNode(arg: SqlComponent): void {\r\n // Skip if we've already visited this node to prevent infinite recursion\r\n if (this.visitedNodes.has(arg)) {\r\n return;\r\n }\r\n\r\n // Mark as visited\r\n this.visitedNodes.add(arg);\r\n\r\n const handler = this.handlers.get(arg.getKind());\r\n if (handler) {\r\n handler(arg);\r\n return;\r\n }\r\n }\r\n\r\n /**\r\n * Process a SimpleSelectQuery to collect data and store the current context\r\n */\r\n private visitSimpleSelectQuery(query: SimpleSelectQuery): void {\r\n if (this.commonTables.length === 0 && this.initialCommonTables === null) {\r\n this.commonTables = this.commonTableCollector.collect(query);\r\n }\r\n\r\n if (query.selectClause) {\r\n query.selectClause.accept(this);\r\n }\r\n\r\n // no wildcard \r\n const wildcards = this.selectValues.filter(item => item.name === '*');\r\n if (wildcards.length === 0) {\r\n return;\r\n }\r\n\r\n // full wildcard\r\n if (this.selectValues.some(item => item.value instanceof ColumnReference && item.value.namespaces === null)) {\r\n if (query.fromClause) {\r\n this.processFromClause(query.fromClause, true);\r\n }\r\n // remove wildcard\r\n this.selectValues = this.selectValues.filter(item => item.name !== '*');\r\n return;\r\n };\r\n\r\n // table wildcard\r\n const wildSourceNames = wildcards.filter(item => item.value instanceof ColumnReference && item.value.namespaces)\r\n .map(item => (item.value as ColumnReference).getNamespace());\r\n\r\n if (query.fromClause) {\r\n const fromSourceName = query.fromClause.getSourceAliasName();\r\n if (fromSourceName && wildSourceNames.includes(fromSourceName)) {\r\n this.processFromClause(query.fromClause, false);\r\n }\r\n if (query.fromClause.joins) {\r\n for (const join of query.fromClause.joins) {\r\n const joinSourceName = join.getSourceAliasName();\r\n if (joinSourceName && wildSourceNames.includes(joinSourceName)) {\r\n this.processJoinClause(join);\r\n }\r\n }\r\n }\r\n }\r\n // remove wildcard\r\n this.selectValues = this.selectValues.filter(item => item.name !== '*');\r\n return;\r\n }\r\n\r\n private processFromClause(clause: FromClause, joinCascade: boolean): void {\r\n if (clause) {\r\n const fromSourceName = clause.getSourceAliasName();\r\n this.processSourceExpression(fromSourceName, clause.source);\r\n\r\n if (clause.joins && joinCascade) {\r\n for (const join of clause.joins) {\r\n this.processJoinClause(join);\r\n }\r\n }\r\n }\r\n return;\r\n }\r\n\r\n private processJoinClause(clause: JoinClause): void {\r\n const sourceName = clause.getSourceAliasName();\r\n this.processSourceExpression(sourceName, clause.source);\r\n }\r\n\r\n private processSourceExpression(sourceName: string | null, source: SourceExpression) {\r\n // check common table\r\n const commonTable = this.commonTables.find(item => item.aliasExpression.table.name === sourceName);\r\n if (commonTable) {\r\n // Exclude this CTE from consideration to prevent self-reference\r\n const innerCommonTables = this.commonTables.filter(item => item.aliasExpression.table.name !== sourceName);\r\n\r\n const innerCollector = new SelectValueCollector(this.tableColumnResolver, innerCommonTables);\r\n const innerSelected = innerCollector.collect(commonTable.query);\r\n innerSelected.forEach(item => {\r\n this.addSelectValueAsUnique(item.name, new ColumnReference(sourceName ? [sourceName] : null, item.name));\r\n });\r\n } else {\r\n const innerCollector = new SelectValueCollector(this.tableColumnResolver, this.commonTables);\r\n const innerSelected = innerCollector.collect(source);\r\n innerSelected.forEach(item => {\r\n this.addSelectValueAsUnique(item.name, new ColumnReference(sourceName ? [sourceName] : null, item.name));\r\n });\r\n }\r\n }\r\n\r\n private visitSelectClause(clause: SelectClause): void {\r\n for (const item of clause.items) {\r\n this.processSelectItem(item);\r\n }\r\n }\r\n\r\n private processSelectItem(item: SelectItem): void {\r\n if (item.identifier) {\r\n this.addSelectValueAsUnique(item.identifier.name, item.value);\r\n }\r\n else if (item.value instanceof ColumnReference) { // Handle column reference\r\n // columnName can be '*'\r\n const columnName = item.value.column.name;\r\n if (columnName === '*') {\r\n // Force add without checking duplicates\r\n this.selectValues.push({ name: columnName, value: item.value });\r\n }\r\n else {\r\n // Add with duplicate checking\r\n this.addSelectValueAsUnique(columnName, item.value);\r\n }\r\n }\r\n }\r\n\r\n private visitSourceExpression(source: SourceExpression): void {\r\n // Column aliases have the highest priority if present\r\n // For physical tables, use external function to get column names\r\n // For subqueries, instantiate a new collector and get column names from the subquery\r\n // For parenthesized expressions, treat them the same as subqueries\r\n\r\n if (source.aliasExpression && source.aliasExpression.columns) {\r\n const sourceName = source.getAliasName();\r\n source.aliasExpression.columns.forEach(column => {\r\n this.addSelectValueAsUnique(column.name, new ColumnReference(sourceName ? [sourceName] : null, column.name));\r\n });\r\n return;\r\n } else if (source.datasource instanceof TableSource) {\r\n if (this.tableColumnResolver) {\r\n const sourceName = source.datasource.getSourceName();\r\n this.tableColumnResolver(sourceName).forEach(column => {\r\n this.addSelectValueAsUnique(column, new ColumnReference([sourceName], column));\r\n });\r\n }\r\n return;\r\n } else if (source.datasource instanceof SubQuerySource) {\r\n const sourceName = source.getAliasName();\r\n const innerCollector = new SelectValueCollector(this.tableColumnResolver, this.commonTables);\r\n const innerSelected = innerCollector.collect(source.datasource.query);\r\n innerSelected.forEach(item => {\r\n this.addSelectValueAsUnique(item.name, new ColumnReference(sourceName ? [sourceName] : null, item.name));\r\n });\r\n return;\r\n } else if (source.datasource instanceof ParenSource) {\r\n return this.visit(source.datasource.source);\r\n }\r\n }\r\n\r\n private visitFromClause(clause: FromClause): void {\r\n if (clause) {\r\n this.processFromClause(clause, true);\r\n }\r\n }\r\n\r\n private addSelectValueAsUnique(name: string, value: ValueComponent): void {\r\n // Check if a select value with the same name already exists before adding\r\n if (!this.selectValues.some(item => item.name === name)) {\r\n this.selectValues.push({ name, value });\r\n }\r\n }\r\n}\r\n", "import { SqlComponent } from \"./SqlComponent\";\r\nimport type { SelectQuery } from \"./SelectQuery\";\r\nimport { ColumnReference, FunctionCall, IdentifierString, RawString } from \"./ValueComponent\";\r\nimport { SimpleSelectQuery } from \"./SimpleSelectQuery\";\r\nimport { SelectClause, SelectItem, FromClause, TableSource, SourceExpression } from \"./Clause\";\r\nimport { SelectValueCollector } from \"../transformers/SelectValueCollector\";\r\n\r\n// Represents a CREATE TABLE query model\r\n// Supports temporary tables and AS SELECT ...\r\nexport class CreateTableQuery extends SqlComponent {\r\n /** SqlComponent kind symbol for visitor pattern */\r\n static kind = Symbol(\"CreateTableQuery\");\r\n /** Table name (with optional schema) */\r\n tableName: IdentifierString;\r\n /** If true, this is a temporary table */\r\n isTemporary: boolean;\r\n /** Optional: SELECT query for AS SELECT ... */\r\n asSelectQuery?: SelectQuery;\r\n\r\n constructor(params: {\r\n tableName: string;\r\n isTemporary?: boolean;\r\n asSelectQuery?: SelectQuery;\r\n }) {\r\n super();\r\n this.tableName = new IdentifierString(params.tableName);\r\n this.isTemporary = params.isTemporary ?? false;\r\n this.asSelectQuery = params.asSelectQuery;\r\n }\r\n\r\n /**\r\n * Returns a SelectQuery that selects all columns from this table.\r\n */\r\n getSelectQuery(): SimpleSelectQuery {\r\n let selectItems: SelectItem[];\r\n if (this.asSelectQuery) {\r\n // Use SelectValueCollector to get columns from asSelectQuery\r\n const collector = new SelectValueCollector();\r\n const values = collector.collect(this.asSelectQuery);\r\n selectItems = values.map(val => new SelectItem(val.value, val.name));\r\n } else {\r\n // fallback: wildcard\r\n selectItems = [new SelectItem(new RawString(\"*\"))];\r\n }\r\n return new SimpleSelectQuery({\r\n selectClause: new SelectClause(selectItems),\r\n fromClause: new FromClause(\r\n new SourceExpression(\r\n new TableSource(null, this.tableName.name),\r\n null\r\n ),\r\n null // joins\r\n ),\r\n });\r\n }\r\n\r\n /**\r\n * Returns a SelectQuery that counts all rows in this table.\r\n */\r\n getCountQuery(): SimpleSelectQuery {\r\n return new SimpleSelectQuery({\r\n selectClause: new SelectClause([\r\n new SelectItem(new FunctionCall(null, \"count\", new ColumnReference(null, \"*\"), null))\r\n ]),\r\n fromClause: new FromClause(\r\n new SourceExpression(\r\n new TableSource(null, this.tableName.name),\r\n null\r\n ),\r\n null // joins\r\n ),\r\n });\r\n }\r\n}\r\n", "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\";\r\nimport { BinarySelectQuery, SimpleSelectQuery, ValuesQuery } from \"../models/SelectQuery\";\r\nimport { SqlComponent, SqlComponentVisitor } from \"../models/SqlComponent\";\r\nimport { SqlPrintToken, SqlPrintTokenType, SqlPrintTokenContainerType } from \"../models/SqlPrintToken\";\r\nimport {\r\n ValueList,\r\n ColumnReference,\r\n FunctionCall,\r\n UnaryExpression,\r\n BinaryExpression,\r\n LiteralValue,\r\n ParameterExpression,\r\n SwitchCaseArgument,\r\n CaseKeyValuePair,\r\n RawString,\r\n IdentifierString,\r\n ParenExpression,\r\n CastExpression,\r\n CaseExpression,\r\n ArrayExpression,\r\n ArrayQueryExpression,\r\n BetweenExpression,\r\n StringSpecifierExpression,\r\n TypeValue,\r\n TupleExpression,\r\n WindowFrameExpression,\r\n QualifiedName,\r\n InlineQuery,\r\n WindowFrameSpec,\r\n WindowFrameBoundStatic,\r\n WindowFrameBoundaryValue\r\n} from \"../models/ValueComponent\";\r\nimport { ParameterCollector } from \"../transformers/ParameterCollector\";\r\nimport { IdentifierDecorator } from \"./IdentifierDecorator\";\r\nimport { ParameterDecorator } from \"./ParameterDecorator\";\r\nimport { InsertQuery } from \"../models/InsertQuery\";\r\nimport { UpdateQuery } from \"../models/UpdateQuery\";\r\nimport { CreateTableQuery } from \"../models/CreateTableQuery\";\r\n\r\nexport enum ParameterStyle {\r\n Anonymous = 'anonymous',\r\n Indexed = 'indexed',\r\n Named = 'named'\r\n}\r\n\r\nexport interface FormatterConfig {\r\n identifierEscape?: {\r\n start: string;\r\n end: string;\r\n };\r\n parameterSymbol?: string | { start: string; end: string };\r\n /**\r\n * Parameter style: anonymous (?), indexed ($1), or named (:name)\r\n */\r\n parameterStyle?: ParameterStyle;\r\n}\r\n\r\nexport const PRESETS: Record<string, FormatterConfig> = {\r\n mysql: {\r\n identifierEscape: { start: '`', end: '`' },\r\n parameterSymbol: '?',\r\n parameterStyle: ParameterStyle.Anonymous,\r\n },\r\n postgres: {\r\n identifierEscape: { start: '\"', end: '\"' },\r\n parameterSymbol: '$',\r\n parameterStyle: ParameterStyle.Indexed,\r\n },\r\n postgresWithNamedParams: {\r\n identifierEscape: { start: '\"', end: '\"' },\r\n parameterSymbol: ':',\r\n parameterStyle: ParameterStyle.Named,\r\n },\r\n sqlserver: {\r\n identifierEscape: { start: '[', end: ']' },\r\n parameterSymbol: '@',\r\n parameterStyle: ParameterStyle.Named,\r\n },\r\n sqlite: {\r\n identifierEscape: { start: '\"', end: '\"' },\r\n parameterSymbol: ':',\r\n parameterStyle: ParameterStyle.Named,\r\n },\r\n oracle: {\r\n identifierEscape: { start: '\"', end: '\"' },\r\n parameterSymbol: ':',\r\n parameterStyle: ParameterStyle.Named,\r\n },\r\n clickhouse: {\r\n identifierEscape: { start: '`', end: '`' },\r\n parameterSymbol: '?',\r\n parameterStyle: ParameterStyle.Anonymous,\r\n },\r\n firebird: {\r\n identifierEscape: { start: '\"', end: '\"' },\r\n parameterSymbol: '?',\r\n parameterStyle: ParameterStyle.Anonymous,\r\n },\r\n db2: {\r\n identifierEscape: { start: '\"', end: '\"' },\r\n parameterSymbol: '?',\r\n parameterStyle: ParameterStyle.Anonymous,\r\n },\r\n snowflake: {\r\n identifierEscape: { start: '\"', end: '\"' },\r\n parameterSymbol: '?',\r\n parameterStyle: ParameterStyle.Anonymous,\r\n },\r\n cloudspanner: {\r\n identifierEscape: { start: '`', end: '`' },\r\n parameterSymbol: '@',\r\n parameterStyle: ParameterStyle.Named,\r\n },\r\n duckdb: {\r\n identifierEscape: { start: '\"', end: '\"' },\r\n parameterSymbol: '?',\r\n parameterStyle: ParameterStyle.Anonymous,\r\n },\r\n cockroachdb: {\r\n identifierEscape: { start: '\"', end: '\"' },\r\n parameterSymbol: '$',\r\n parameterStyle: ParameterStyle.Indexed,\r\n },\r\n athena: {\r\n identifierEscape: { start: '\"', end: '\"' },\r\n parameterSymbol: '?',\r\n parameterStyle: ParameterStyle.Anonymous,\r\n },\r\n bigquery: {\r\n identifierEscape: { start: '`', end: '`' },\r\n parameterSymbol: '@',\r\n parameterStyle: ParameterStyle.Named,\r\n },\r\n hive: {\r\n identifierEscape: { start: '`', end: '`' },\r\n parameterSymbol: '?',\r\n parameterStyle: ParameterStyle.Anonymous,\r\n },\r\n mariadb: {\r\n identifierEscape: { start: '`', end: '`' },\r\n parameterSymbol: '?',\r\n parameterStyle: ParameterStyle.Anonymous,\r\n },\r\n redshift: {\r\n identifierEscape: { start: '\"', end: '\"' },\r\n parameterSymbol: '$',\r\n parameterStyle: ParameterStyle.Indexed,\r\n },\r\n flinksql: {\r\n identifierEscape: { start: '`', end: '`' },\r\n parameterSymbol: '?',\r\n parameterStyle: ParameterStyle.Anonymous,\r\n },\r\n mongodb: {\r\n identifierEscape: { start: '\"', end: '\"' },\r\n parameterSymbol: '?',\r\n parameterStyle: ParameterStyle.Anonymous,\r\n },\r\n};\r\n\r\nexport class SqlPrintTokenParser implements SqlComponentVisitor<SqlPrintToken> {\r\n // Static tokens for common symbols\r\n private static readonly SPACE_TOKEN = new SqlPrintToken(SqlPrintTokenType.space, ' ');\r\n private static readonly COMMA_TOKEN = new SqlPrintToken(SqlPrintTokenType.comma, ',');\r\n private static readonly ARGUMENT_SPLIT_COMMA_TOKEN = new SqlPrintToken(SqlPrintTokenType.argumentSplitter, ',');\r\n private static readonly PAREN_OPEN_TOKEN = new SqlPrintToken(SqlPrintTokenType.parenthesis, '(');\r\n private static readonly PAREN_CLOSE_TOKEN = new SqlPrintToken(SqlPrintTokenType.parenthesis, ')');\r\n private static readonly DOT_TOKEN = new SqlPrintToken(SqlPrintTokenType.dot, '.');\r\n\r\n private handlers: Map<symbol, (arg: any) => SqlPrintToken> = new Map();\r\n parameterDecorator: ParameterDecorator;\r\n identifierDecorator: IdentifierDecorator;\r\n index: number = 1;\r\n\r\n constructor(options?: {\r\n preset?: FormatterConfig,\r\n identifierEscape?: { start: string; end: string },\r\n parameterSymbol?: string | { start: string; end: string },\r\n parameterStyle?: 'anonymous' | 'indexed' | 'named'\r\n }) {\r\n if (options?.preset) {\r\n const preset = options.preset\r\n options = { ...preset, ...options };\r\n }\r\n\r\n this.parameterDecorator = new ParameterDecorator({\r\n prefix: typeof options?.parameterSymbol === 'string' ? options.parameterSymbol : options?.parameterSymbol?.start ?? ':',\r\n suffix: typeof options?.parameterSymbol === 'object' ? options.parameterSymbol.end : '',\r\n style: options?.parameterStyle ?? 'named'\r\n });\r\n\r\n this.identifierDecorator = new IdentifierDecorator({\r\n start: options?.identifierEscape?.start ?? '\"',\r\n end: options?.identifierEscape?.end ?? '\"'\r\n });\r\n\r\n this.handlers.set(ValueList.kind, (expr) => this.visitValueList(expr as ValueList));\r\n this.handlers.set(ColumnReference.kind, (expr) => this.visitColumnReference(expr as ColumnReference));\r\n this.handlers.set(QualifiedName.kind, (expr) => this.visitQualifiedName(expr as QualifiedName));\r\n this.handlers.set(FunctionCall.kind, (expr) => this.visitFunctionCall(expr as FunctionCall));\r\n this.handlers.set(UnaryExpression.kind, (expr) => this.visitUnaryExpression(expr as UnaryExpression));\r\n this.handlers.set(BinaryExpression.kind, (expr) => this.visitBinaryExpression(expr as BinaryExpression));\r\n this.handlers.set(LiteralValue.kind, (expr) => this.visitLiteralValue(expr as LiteralValue));\r\n this.handlers.set(ParameterExpression.kind, (expr) => this.visitParameterExpression(expr as ParameterExpression));\r\n this.handlers.set(SwitchCaseArgument.kind, (expr) => this.visitSwitchCaseArgument(expr as SwitchCaseArgument));\r\n this.handlers.set(CaseKeyValuePair.kind, (expr) => this.visitCaseKeyValuePair(expr as CaseKeyValuePair));\r\n this.handlers.set(RawString.kind, (expr) => this.visitRawString(expr as RawString));\r\n this.handlers.set(IdentifierString.kind, (expr) => this.visitIdentifierString(expr as IdentifierString));\r\n this.handlers.set(ParenExpression.kind, (expr) => this.visitParenExpression(expr as ParenExpression));\r\n this.handlers.set(CastExpression.kind, (expr) => this.visitCastExpression(expr as CastExpression));\r\n this.handlers.set(CaseExpression.kind, (expr) => this.visitCaseExpression(expr as CaseExpression));\r\n this.handlers.set(ArrayExpression.kind, (expr) => this.visitArrayExpression(expr as ArrayExpression));\r\n this.handlers.set(ArrayQueryExpression.kind, (expr) => this.visitArrayQueryExpression(expr as ArrayQueryExpression));\r\n this.handlers.set(BetweenExpression.kind, (expr) => this.visitBetweenExpression(expr as BetweenExpression));\r\n this.handlers.set(StringSpecifierExpression.kind, (expr) => this.visitStringSpecifierExpression(expr as StringSpecifierExpression));\r\n this.handlers.set(TypeValue.kind, (expr) => this.visitTypeValue(expr as TypeValue));\r\n this.handlers.set(TupleExpression.kind, (expr) => this.visitTupleExpression(expr as TupleExpression));\r\n this.handlers.set(InlineQuery.kind, (expr) => this.visitInlineQuery(expr as InlineQuery));\r\n\r\n this.handlers.set(WindowFrameExpression.kind, (expr) => this.visitWindowFrameExpression(expr as WindowFrameExpression));\r\n this.handlers.set(WindowFrameSpec.kind, (expr) => this.visitWindowFrameSpec(expr as WindowFrameSpec));\r\n this.handlers.set(WindowFrameBoundStatic.kind, (expr) => this.visitWindowFrameBoundStatic(expr as WindowFrameBoundStatic));\r\n this.handlers.set(WindowFrameBoundaryValue.kind, (expr) => this.visitWindowFrameBoundaryValue(expr as WindowFrameBoundaryValue));\r\n this.handlers.set(PartitionByClause.kind, (expr) => this.visitPartitionByClause(expr as PartitionByClause));\r\n this.handlers.set(OrderByClause.kind, (expr) => this.visitOrderByClause(expr as OrderByClause));\r\n this.handlers.set(OrderByItem.kind, (expr) => this.visitOrderByItem(expr));\r\n\r\n // select\r\n this.handlers.set(SelectItem.kind, (expr) => this.visitSelectItem(expr as SelectItem));\r\n this.handlers.set(SelectClause.kind, (expr) => this.visitSelectClause(expr as SelectClause));\r\n this.handlers.set(Distinct.kind, (expr) => this.visitDistinct(expr as Distinct));\r\n this.handlers.set(DistinctOn.kind, (expr) => this.visitDistinctOn(expr as DistinctOn));\r\n\r\n // from\r\n this.handlers.set(TableSource.kind, (expr) => this.visitTableSource(expr as TableSource));\r\n this.handlers.set(FunctionSource.kind, (expr) => this.visitFunctionSource(expr as FunctionSource));\r\n this.handlers.set(SourceExpression.kind, (expr) => this.visitSourceExpression(expr as SourceExpression));\r\n this.handlers.set(SourceAliasExpression.kind, (expr) => this.visitSourceAliasExpression(expr as SourceAliasExpression));\r\n this.handlers.set(FromClause.kind, (expr) => this.visitFromClause(expr as FromClause));\r\n this.handlers.set(JoinClause.kind, (expr) => this.visitJoinClause(expr as JoinClause));\r\n this.handlers.set(JoinOnClause.kind, (expr) => this.visitJoinOnClause(expr as JoinOnClause));\r\n this.handlers.set(JoinUsingClause.kind, (expr) => this.visitJoinUsingClause(expr as JoinUsingClause));\r\n\r\n // where\r\n this.handlers.set(WhereClause.kind, (expr) => this.visitWhereClause(expr as WhereClause));\r\n\r\n // group\r\n this.handlers.set(GroupByClause.kind, (expr) => this.visitGroupByClause(expr as GroupByClause));\r\n this.handlers.set(HavingClause.kind, (expr) => this.visitHavingClause(expr as HavingClause));\r\n\r\n this.handlers.set(WindowClause.kind, (expr) => this.visitWindowClause(expr as WindowClause));\r\n this.handlers.set(WindowFrameClause.kind, (expr) => this.visitWindowFrameClause(expr as WindowFrameClause));\r\n this.handlers.set(LimitClause.kind, (expr) => this.visitLimitClause(expr as LimitClause));\r\n this.handlers.set(OffsetClause.kind, (expr) => this.visitOffsetClause(expr as OffsetClause));\r\n this.handlers.set(FetchClause.kind, (expr) => this.visitFetchClause(expr as FetchClause));\r\n this.handlers.set(FetchExpression.kind, (expr) => this.visitFetchExpression(expr as FetchExpression));\r\n this.handlers.set(ForClause.kind, (expr) => this.visitForClause(expr as ForClause));\r\n\r\n // With\r\n this.handlers.set(WithClause.kind, (expr) => this.visitWithClause(expr as WithClause));\r\n this.handlers.set(CommonTable.kind, (expr) => this.visitCommonTable(expr as CommonTable));\r\n\r\n // Query\r\n this.handlers.set(SimpleSelectQuery.kind, (expr) => this.visitSimpleQuery(expr as SimpleSelectQuery));\r\n this.handlers.set(SubQuerySource.kind, (expr) => this.visitSubQuerySource(expr as SubQuerySource));\r\n this.handlers.set(BinarySelectQuery.kind, (expr) => this.visitBinarySelectQuery(expr));\r\n this.handlers.set(ValuesQuery.kind, (expr) => this.visitValuesQuery(expr as ValuesQuery));\r\n this.handlers.set(TupleExpression.kind, (expr) => this.visitTupleExpression(expr as TupleExpression));\r\n\r\n this.handlers.set(InsertQuery.kind, (expr) => this.visitInsertQuery(expr as InsertQuery));\r\n this.handlers.set(InsertClause.kind, (expr) => this.visitInsertClause(expr as InsertClause));\r\n this.handlers.set(UpdateQuery.kind, (expr) => this.visitUpdateQuery(expr as UpdateQuery));\r\n this.handlers.set(UpdateClause.kind, (expr) => this.visitUpdateClause(expr as UpdateClause));\r\n this.handlers.set(SetClause.kind, (expr) => this.visitSetClause(expr as SetClause));\r\n this.handlers.set(SetClauseItem.kind, (expr) => this.visitSetClauseItem(expr as SetClauseItem));\r\n this.handlers.set(ReturningClause.kind, (expr) => this.visitReturningClause(expr as ReturningClause));\r\n this.handlers.set(CreateTableQuery.kind, (expr) => this.visitCreateTableQuery(expr as CreateTableQuery));\r\n }\r\n\r\n /**\r\n * Pretty-prints a BinarySelectQuery (e.g., UNION, INTERSECT, EXCEPT).\r\n * This will recursively print left and right queries, separated by the operator.\r\n * @param arg BinarySelectQuery\r\n */\r\n private visitBinarySelectQuery(arg: BinarySelectQuery): SqlPrintToken {\r\n const token = new SqlPrintToken(SqlPrintTokenType.container, '');\r\n\r\n token.innerTokens.push(this.visit(arg.left));\r\n token.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN);\r\n\r\n token.innerTokens.push(new SqlPrintToken(SqlPrintTokenType.keyword, arg.operator.value, SqlPrintTokenContainerType.BinarySelectQueryOperator));\r\n\r\n token.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN);\r\n token.innerTokens.push(this.visit(arg.right));\r\n\r\n return token;\r\n }\r\n\r\n /**\r\n * Returns an array of tokens representing a comma followed by a space.\r\n * This is a common pattern in SQL pretty-printing.\r\n */\r\n private static commaSpaceTokens(): SqlPrintToken[] {\r\n return [SqlPrintTokenParser.COMMA_TOKEN, SqlPrintTokenParser.SPACE_TOKEN];\r\n }\r\n\r\n private static argumentCommaSpaceTokens(): SqlPrintToken[] {\r\n return [SqlPrintTokenParser.ARGUMENT_SPLIT_COMMA_TOKEN, SqlPrintTokenParser.SPACE_TOKEN];\r\n }\r\n\r\n\r\n private visitQualifiedName(arg: QualifiedName): SqlPrintToken {\r\n const token = new SqlPrintToken(SqlPrintTokenType.container, '', SqlPrintTokenContainerType.QualifiedName);\r\n\r\n if (arg.namespaces) {\r\n for (let i = 0; i < arg.namespaces.length; i++) {\r\n token.innerTokens.push(arg.namespaces[i].accept(this));\r\n token.innerTokens.push(SqlPrintTokenParser.DOT_TOKEN);\r\n }\r\n }\r\n token.innerTokens.push(arg.name.accept(this));\r\n\r\n return token;\r\n }\r\n\r\n private visitPartitionByClause(arg: PartitionByClause): SqlPrintToken {\r\n // Print as: partition by ...\r\n const token = new SqlPrintToken(SqlPrintTokenType.keyword, 'partition by', SqlPrintTokenContainerType.PartitionByClause);\r\n token.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN);\r\n token.innerTokens.push(this.visit(arg.value));\r\n return token;\r\n }\r\n\r\n private visitOrderByClause(arg: OrderByClause): SqlPrintToken {\r\n // Print as: order by ...\r\n const token = new SqlPrintToken(SqlPrintTokenType.keyword, 'order by', SqlPrintTokenContainerType.OrderByClause);\r\n token.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN);\r\n for (let i = 0; i < arg.order.length; i++) {\r\n if (i > 0) token.innerTokens.push(...SqlPrintTokenParser.commaSpaceTokens());\r\n token.innerTokens.push(this.visit(arg.order[i]));\r\n }\r\n return token;\r\n }\r\n\r\n /**\r\n * Print an OrderByItem (expression [asc|desc] [nulls first|last])\r\n */\r\n private visitOrderByItem(arg: OrderByItem): SqlPrintToken {\r\n // arg: OrderByItem\r\n const token = new SqlPrintToken(SqlPrintTokenType.container, '', SqlPrintTokenContainerType.OrderByItem);\r\n token.innerTokens.push(this.visit(arg.value));\r\n\r\n if (arg.sortDirection && arg.sortDirection !== SortDirection.Ascending) {\r\n token.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN);\r\n token.innerTokens.push(new SqlPrintToken(SqlPrintTokenType.keyword, 'desc'));\r\n }\r\n\r\n if (arg.nullsPosition) {\r\n if (arg.nullsPosition === NullsSortDirection.First) {\r\n token.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN);\r\n token.innerTokens.push(new SqlPrintToken(SqlPrintTokenType.keyword, 'nulls first'));\r\n } else if (arg.nullsPosition === NullsSortDirection.Last) {\r\n token.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN);\r\n token.innerTokens.push(new SqlPrintToken(SqlPrintTokenType.keyword, 'nulls last'));\r\n }\r\n }\r\n return token;\r\n }\r\n\r\n public parse(arg: SqlComponent): { token: SqlPrintToken, params: any[] | Record<string, any>[] | Record<string, any> } {\r\n // reset parameter index before parsing\r\n this.index = 1;\r\n\r\n const token = this.visit(arg);\r\n const paramsRaw = ParameterCollector.collect(arg).sort((a, b) => (a.index ?? 0) - (b.index ?? 0));\r\n\r\n const style = this.parameterDecorator.style;\r\n if (style === ParameterStyle.Named) {\r\n // Named: { name: value, ... }\r\n const paramsObj: Record<string, any> = {};\r\n for (const p of paramsRaw) {\r\n const key = p.name.value;\r\n if (paramsObj.hasOwnProperty(key)) {\r\n if (paramsObj[key] !== p.value) {\r\n throw new Error(`Duplicate parameter name '${key}' with different values detected during query composition.`);\r\n }\r\n // If value is the same, skip (already set)\r\n continue;\r\n }\r\n paramsObj[key] = p.value;\r\n }\r\n return { token, params: paramsObj };\r\n } else if (style === ParameterStyle.Indexed) {\r\n // Indexed: [value1, value2, ...] (sorted by index)\r\n const paramsArr = paramsRaw.map(p => p.value);\r\n return { token, params: paramsArr };\r\n } else if (style === ParameterStyle.Anonymous) {\r\n // Anonymous: [value1, value2, ...] (sorted by index, name is empty)\r\n const paramsArr = paramsRaw.map(p => p.value);\r\n return { token, params: paramsArr };\r\n }\r\n\r\n // Fallback (just in case)\r\n return { token, params: [] };\r\n }\r\n\r\n public visit(arg: SqlComponent): SqlPrintToken {\r\n const handler = this.handlers.get(arg.getKind());\r\n if (handler) {\r\n return handler(arg);\r\n }\r\n throw new Error(`[SqlPrintTokenParser] No handler for kind: ${arg.getKind().toString()}`);\r\n }\r\n\r\n private visitValueList(arg: ValueList): SqlPrintToken {\r\n const token = new SqlPrintToken(SqlPrintTokenType.container, '', SqlPrintTokenContainerType.ValueList);\r\n for (let i = 0; i < arg.values.length; i++) {\r\n if (i > 0) {\r\n token.innerTokens.push(...SqlPrintTokenParser.argumentCommaSpaceTokens());\r\n }\r\n token.innerTokens.push(this.visit(arg.values[i]));\r\n }\r\n return token;\r\n }\r\n\r\n private visitColumnReference(arg: ColumnReference): SqlPrintToken {\r\n const token = new SqlPrintToken(SqlPrintTokenType.container, '', SqlPrintTokenContainerType.ColumnReference);\r\n token.innerTokens.push(arg.qualifiedName.accept(this));\r\n return token;\r\n }\r\n\r\n private visitFunctionCall(arg: FunctionCall): SqlPrintToken {\r\n const token = new SqlPrintToken(SqlPrintTokenType.container, '', SqlPrintTokenContainerType.FunctionCall);\r\n\r\n token.innerTokens.push(arg.qualifiedName.accept(this));\r\n token.innerTokens.push(SqlPrintTokenParser.PAREN_OPEN_TOKEN);\r\n if (arg.argument) {\r\n token.innerTokens.push(this.visit(arg.argument));\r\n }\r\n token.innerTokens.push(SqlPrintTokenParser.PAREN_CLOSE_TOKEN);\r\n if (arg.over) {\r\n token.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN);\r\n token.innerTokens.push(new SqlPrintToken(SqlPrintTokenType.keyword, 'over'));\r\n\r\n if (arg.over instanceof IdentifierString) {\r\n token.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN);\r\n token.innerTokens.push(arg.over.accept(this));\r\n }\r\n else {\r\n token.innerTokens.push(SqlPrintTokenParser.PAREN_OPEN_TOKEN);\r\n token.innerTokens.push(this.visit(arg.over));\r\n token.innerTokens.push(SqlPrintTokenParser.PAREN_CLOSE_TOKEN);\r\n }\r\n }\r\n\r\n return token;\r\n }\r\n\r\n private visitUnaryExpression(arg: UnaryExpression): SqlPrintToken {\r\n const token = new SqlPrintToken(SqlPrintTokenType.container, '', SqlPrintTokenContainerType.UnaryExpression);\r\n\r\n token.innerTokens.push(this.visit(arg.operator));\r\n token.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN);\r\n token.innerTokens.push(this.visit(arg.expression));\r\n\r\n return token;\r\n }\r\n\r\n private visitBinaryExpression(arg: BinaryExpression): SqlPrintToken {\r\n const token = new SqlPrintToken(SqlPrintTokenType.container, '', SqlPrintTokenContainerType.BinaryExpression);\r\n\r\n token.innerTokens.push(this.visit(arg.left));\r\n token.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN);\r\n token.innerTokens.push(new SqlPrintToken(SqlPrintTokenType.operator, arg.operator.value));\r\n token.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN);\r\n token.innerTokens.push(this.visit(arg.right));\r\n\r\n return token;\r\n }\r\n\r\n private visitLiteralValue(arg: LiteralValue): SqlPrintToken {\r\n let text;\r\n if (typeof arg.value === \"string\") {\r\n text = `'${arg.value.replace(/'/g, \"''\")}'`;\r\n } else if (arg.value === null) {\r\n text = \"null\";\r\n } else {\r\n text = arg.value.toString();\r\n }\r\n return new SqlPrintToken(\r\n SqlPrintTokenType.value,\r\n text,\r\n SqlPrintTokenContainerType.LiteralValue\r\n );\r\n }\r\n\r\n private visitParameterExpression(arg: ParameterExpression): SqlPrintToken {\r\n // Create a parameter token and decorate it using the parameterDecorator\r\n arg.index = this.index;\r\n const text = this.parameterDecorator.decorate(arg.name.value, arg.index)\r\n const token = new SqlPrintToken(SqlPrintTokenType.parameter, text);\r\n\r\n this.index++;\r\n return token;\r\n }\r\n\r\n private visitSwitchCaseArgument(arg: SwitchCaseArgument): SqlPrintToken {\r\n const token = new SqlPrintToken(SqlPrintTokenType.container, '', SqlPrintTokenContainerType.SwitchCaseArgument);\r\n\r\n // Add each WHEN/THEN clause\r\n for (const kv of arg.cases) {\r\n // Create a new line for each WHEN clause\r\n token.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN);\r\n token.innerTokens.push(kv.accept(this));\r\n }\r\n\r\n // Add ELSE clause if present\r\n if (arg.elseValue) {\r\n token.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN);\r\n token.innerTokens.push(this.createElseToken(arg.elseValue));\r\n }\r\n return token;\r\n }\r\n\r\n private createElseToken(elseValue: SqlComponent): SqlPrintToken {\r\n // Creates a token for the ELSE clause in a CASE expression.\r\n const elseToken = new SqlPrintToken(SqlPrintTokenType.container, '', SqlPrintTokenContainerType.ElseClause); // Add the ELSE keyword\r\n elseToken.innerTokens.push(new SqlPrintToken(SqlPrintTokenType.keyword, 'else'));\r\n\r\n // Create a container for the ELSE value to enable proper indentation\r\n elseToken.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN);\r\n const elseValueContainer = new SqlPrintToken(SqlPrintTokenType.container, '', SqlPrintTokenContainerType.CaseElseValue);\r\n elseValueContainer.innerTokens.push(this.visit(elseValue));\r\n elseToken.innerTokens.push(elseValueContainer);\r\n\r\n return elseToken;\r\n }\r\n\r\n private visitCaseKeyValuePair(arg: CaseKeyValuePair): SqlPrintToken {\r\n const token = new SqlPrintToken(SqlPrintTokenType.container, '', SqlPrintTokenContainerType.CaseKeyValuePair);\r\n\r\n // Create WHEN clause\r\n token.innerTokens.push(new SqlPrintToken(SqlPrintTokenType.keyword, 'when'));\r\n token.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN);\r\n token.innerTokens.push(this.visit(arg.key)); // Create THEN clause\r\n token.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN);\r\n token.innerTokens.push(new SqlPrintToken(SqlPrintTokenType.keyword, 'then'));\r\n\r\n // Create a container for the THEN value to enable proper indentation\r\n token.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN);\r\n const thenValueContainer = new SqlPrintToken(SqlPrintTokenType.container, '', SqlPrintTokenContainerType.CaseThenValue);\r\n thenValueContainer.innerTokens.push(this.visit(arg.value));\r\n token.innerTokens.push(thenValueContainer);\r\n\r\n return token;\r\n }\r\n\r\n private visitRawString(arg: RawString): SqlPrintToken {\r\n // Even for non-container tokens, set the container type for context\r\n return new SqlPrintToken(\r\n SqlPrintTokenType.value,\r\n arg.value,\r\n SqlPrintTokenContainerType.RawString\r\n );\r\n }\r\n\r\n private visitIdentifierString(arg: IdentifierString): SqlPrintToken {\r\n // Create an identifier token and decorate it using the identifierDecorator\r\n const text = arg.name === \"*\" ? arg.name : this.identifierDecorator.decorate(arg.name)\r\n const token = new SqlPrintToken(\r\n SqlPrintTokenType.value,\r\n text,\r\n SqlPrintTokenContainerType.IdentifierString\r\n );\r\n return token;\r\n }\r\n\r\n private visitParenExpression(arg: ParenExpression): SqlPrintToken {\r\n const token = new SqlPrintToken(SqlPrintTokenType.container, '', SqlPrintTokenContainerType.ParenExpression);\r\n\r\n token.innerTokens.push(SqlPrintTokenParser.PAREN_OPEN_TOKEN);\r\n token.innerTokens.push(this.visit(arg.expression));\r\n token.innerTokens.push(SqlPrintTokenParser.PAREN_CLOSE_TOKEN);\r\n\r\n return token;\r\n }\r\n\r\n private visitCastExpression(arg: CastExpression): SqlPrintToken {\r\n const token = new SqlPrintToken(SqlPrintTokenType.container, '', SqlPrintTokenContainerType.CastExpression);\r\n\r\n token.innerTokens.push(this.visit(arg.input));\r\n token.innerTokens.push(new SqlPrintToken(SqlPrintTokenType.operator, '::'));\r\n token.innerTokens.push(this.visit(arg.castType));\r\n\r\n return token;\r\n }\r\n\r\n private visitCaseExpression(arg: CaseExpression): SqlPrintToken {\r\n const token = new SqlPrintToken(SqlPrintTokenType.container, '', SqlPrintTokenContainerType.CaseExpression);\r\n\r\n // Add the CASE keyword\r\n token.innerTokens.push(new SqlPrintToken(SqlPrintTokenType.keyword, 'case'));\r\n\r\n // Add the condition if exists\r\n if (arg.condition) {\r\n token.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN);\r\n token.innerTokens.push(this.visit(arg.condition));\r\n }\r\n\r\n // Add the WHEN/THEN pairs and ELSE\r\n token.innerTokens.push(this.visit(arg.switchCase));\r\n\r\n // Add the END keyword\r\n token.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN);\r\n token.innerTokens.push(new SqlPrintToken(SqlPrintTokenType.keyword, 'end'));\r\n\r\n return token;\r\n }\r\n\r\n private visitArrayExpression(arg: ArrayExpression): SqlPrintToken {\r\n const token = new SqlPrintToken(SqlPrintTokenType.container, '', SqlPrintTokenContainerType.ArrayExpression);\r\n\r\n token.innerTokens.push(new SqlPrintToken(SqlPrintTokenType.keyword, 'array'));\r\n token.innerTokens.push(new SqlPrintToken(SqlPrintTokenType.parenthesis, '['));\r\n token.innerTokens.push(this.visit(arg.expression));\r\n token.innerTokens.push(new SqlPrintToken(SqlPrintTokenType.parenthesis, ']'));\r\n\r\n return token;\r\n }\r\n\r\n private visitArrayQueryExpression(arg: ArrayQueryExpression): SqlPrintToken {\r\n const token = new SqlPrintToken(SqlPrintTokenType.container, '', SqlPrintTokenContainerType.ArrayExpression);\r\n\r\n token.innerTokens.push(new SqlPrintToken(SqlPrintTokenType.keyword, 'array'));\r\n // ARRAY(SELECT ...)\r\n token.innerTokens.push(new SqlPrintToken(SqlPrintTokenType.parenthesis, '('));\r\n token.innerTokens.push(this.visit(arg.query));\r\n token.innerTokens.push(new SqlPrintToken(SqlPrintTokenType.parenthesis, ')'));\r\n\r\n return token;\r\n }\r\n\r\n private visitBetweenExpression(arg: BetweenExpression): SqlPrintToken {\r\n const token = new SqlPrintToken(SqlPrintTokenType.container, '', SqlPrintTokenContainerType.BetweenExpression);\r\n\r\n token.innerTokens.push(this.visit(arg.expression));\r\n token.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN);\r\n if (arg.negated) {\r\n token.innerTokens.push(new SqlPrintToken(SqlPrintTokenType.keyword, 'not'));\r\n token.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN);\r\n }\r\n token.innerTokens.push(new SqlPrintToken(SqlPrintTokenType.keyword, 'between'));\r\n token.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN);\r\n token.innerTokens.push(this.visit(arg.lower));\r\n token.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN);\r\n token.innerTokens.push(new SqlPrintToken(SqlPrintTokenType.keyword, 'and'));\r\n token.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN);\r\n token.innerTokens.push(this.visit(arg.upper));\r\n\r\n return token;\r\n }\r\n\r\n private visitStringSpecifierExpression(arg: StringSpecifierExpression): SqlPrintToken {\r\n // Combine specifier and value into a single token\r\n const specifier = arg.specifier.accept(this).text;\r\n const value = arg.value.accept(this).text;\r\n return new SqlPrintToken(\r\n SqlPrintTokenType.value,\r\n specifier + value,\r\n SqlPrintTokenContainerType.StringSpecifierExpression\r\n );\r\n }\r\n\r\n private visitTypeValue(arg: TypeValue): SqlPrintToken {\r\n const token = new SqlPrintToken(SqlPrintTokenType.container, '', SqlPrintTokenContainerType.TypeValue);\r\n\r\n token.innerTokens.push(arg.qualifiedName.accept(this));\r\n if (arg.argument) {\r\n token.innerTokens.push(SqlPrintTokenParser.PAREN_OPEN_TOKEN);\r\n token.innerTokens.push(this.visit(arg.argument));\r\n token.innerTokens.push(SqlPrintTokenParser.PAREN_CLOSE_TOKEN);\r\n }\r\n\r\n return token;\r\n }\r\n\r\n private visitTupleExpression(arg: TupleExpression): SqlPrintToken {\r\n const token = new SqlPrintToken(SqlPrintTokenType.container, '', SqlPrintTokenContainerType.TupleExpression);\r\n\r\n token.innerTokens.push(SqlPrintTokenParser.PAREN_OPEN_TOKEN);\r\n for (let i = 0; i < arg.values.length; i++) {\r\n if (i > 0) {\r\n token.innerTokens.push(...SqlPrintTokenParser.argumentCommaSpaceTokens());\r\n }\r\n token.innerTokens.push(this.visit(arg.values[i]));\r\n }\r\n token.innerTokens.push(SqlPrintTokenParser.PAREN_CLOSE_TOKEN);\r\n\r\n return token;\r\n }\r\n\r\n private visitWindowFrameExpression(arg: WindowFrameExpression): SqlPrintToken {\r\n // Compose window frame expression: over(partition by ... order by ... rows ...)\r\n const token = new SqlPrintToken(SqlPrintTokenType.container, '', SqlPrintTokenContainerType.WindowFrameExpression);\r\n\r\n let first = true;\r\n if (arg.partition) {\r\n token.innerTokens.push(this.visit(arg.partition));\r\n first = false;\r\n }\r\n if (arg.order) {\r\n if (!first) {\r\n token.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN);\r\n } else {\r\n first = false;\r\n }\r\n token.innerTokens.push(this.visit(arg.order));\r\n }\r\n if (arg.frameSpec) {\r\n if (!first) {\r\n token.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN);\r\n } else {\r\n first = false;\r\n }\r\n token.innerTokens.push(this.visit(arg.frameSpec));\r\n }\r\n\r\n return token;\r\n }\r\n\r\n private visitWindowFrameSpec(arg: WindowFrameSpec): SqlPrintToken {\r\n // This method prints a window frame specification, such as \"rows between ... and ...\" or \"range ...\".\r\n const token = new SqlPrintToken(SqlPrintTokenType.container, '', SqlPrintTokenContainerType.WindowFrameSpec);\r\n\r\n // Add frame type (e.g., \"rows\", \"range\", \"groups\")\r\n token.innerTokens.push(new SqlPrintToken(SqlPrintTokenType.keyword, arg.frameType));\r\n\r\n if (arg.endBound === null) {\r\n // Only start bound: e.g., \"rows unbounded preceding\"\r\n token.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN);\r\n token.innerTokens.push(arg.startBound.accept(this));\r\n } else {\r\n // Between: e.g., \"rows between unbounded preceding and current row\"\r\n token.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN);\r\n token.innerTokens.push(new SqlPrintToken(SqlPrintTokenType.keyword, 'between'));\r\n token.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN);\r\n token.innerTokens.push(arg.startBound.accept(this));\r\n token.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN);\r\n token.innerTokens.push(new SqlPrintToken(SqlPrintTokenType.keyword, 'and'));\r\n token.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN);\r\n token.innerTokens.push(arg.endBound.accept(this));\r\n }\r\n\r\n return token;\r\n }\r\n\r\n /**\r\n * Prints a window frame boundary value, such as \"5 preceding\" or \"3 following\".\r\n * @param arg WindowFrameBoundaryValue\r\n */\r\n private visitWindowFrameBoundaryValue(arg: WindowFrameBoundaryValue): SqlPrintToken {\r\n const token = new SqlPrintToken(SqlPrintTokenType.container, '', SqlPrintTokenContainerType.WindowFrameBoundaryValue);\r\n\r\n token.innerTokens.push(arg.value.accept(this));\r\n token.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN);\r\n // true for \"FOLLOWING\", false for \"PRECEDING\"\r\n token.innerTokens.push(new SqlPrintToken(SqlPrintTokenType.keyword, arg.isFollowing ? 'following' : 'preceding'));\r\n\r\n return token;\r\n }\r\n\r\n /**\r\n * Prints a static window frame bound, such as \"unbounded preceding\", \"current row\", or \"unbounded following\".\r\n * @param arg WindowFrameBoundStatic\r\n */\r\n private visitWindowFrameBoundStatic(arg: WindowFrameBoundStatic): SqlPrintToken {\r\n const token = new SqlPrintToken(SqlPrintTokenType.keyword, arg.bound);\r\n return token;\r\n }\r\n\r\n private visitSelectItem(arg: SelectItem): SqlPrintToken {\r\n const token = new SqlPrintToken(SqlPrintTokenType.container, '', SqlPrintTokenContainerType.SelectItem);\r\n\r\n token.innerTokens.push(this.visit(arg.value));\r\n\r\n if (!arg.identifier) {\r\n return token;\r\n }\r\n\r\n // No alias needed if it matches the default name\r\n if (arg.value instanceof ColumnReference) {\r\n const defaultName = arg.value.column.name;\r\n if (arg.identifier.name === defaultName) {\r\n return token;\r\n }\r\n }\r\n\r\n // Add alias if it is different from the default name\r\n token.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN);\r\n token.innerTokens.push(new SqlPrintToken(SqlPrintTokenType.keyword, 'as'));\r\n token.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN);\r\n token.innerTokens.push(this.visit(arg.identifier));\r\n return token;\r\n }\r\n\r\n private visitSelectClause(arg: SelectClause): SqlPrintToken {\r\n const token = new SqlPrintToken(SqlPrintTokenType.keyword, 'select', SqlPrintTokenContainerType.SelectClause);\r\n\r\n token.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN);\r\n\r\n if (arg.distinct) {\r\n token.keywordTokens = [];\r\n token.keywordTokens.push(SqlPrintTokenParser.SPACE_TOKEN);\r\n token.keywordTokens.push(arg.distinct.accept(this));\r\n }\r\n\r\n for (let i = 0; i < arg.items.length; i++) {\r\n if (i > 0) {\r\n token.innerTokens.push(...SqlPrintTokenParser.commaSpaceTokens());\r\n }\r\n token.innerTokens.push(this.visit(arg.items[i]));\r\n }\r\n\r\n return token;\r\n }\r\n\r\n private visitDistinct(arg: Distinct): SqlPrintToken {\r\n const token = new SqlPrintToken(SqlPrintTokenType.keyword, 'distinct');\r\n return token;\r\n }\r\n\r\n private visitDistinctOn(arg: DistinctOn): SqlPrintToken {\r\n const token = new SqlPrintToken(SqlPrintTokenType.container, '', SqlPrintTokenContainerType.DistinctOn);\r\n\r\n token.innerTokens.push(new SqlPrintToken(SqlPrintTokenType.keyword, 'distinct on'));\r\n token.innerTokens.push(SqlPrintTokenParser.PAREN_OPEN_TOKEN);\r\n token.innerTokens.push(arg.value.accept(this));\r\n token.innerTokens.push(SqlPrintTokenParser.PAREN_CLOSE_TOKEN);\r\n\r\n return token;\r\n }\r\n\r\n private visitTableSource(arg: TableSource): SqlPrintToken {\r\n // Print table name with optional namespaces and alias\r\n let fullName = '';\r\n if (Array.isArray(arg.namespaces) && arg.namespaces.length > 0) {\r\n fullName = arg.namespaces.map(ns => ns.accept(this).text).join('.') + '.';\r\n }\r\n fullName += arg.table.accept(this).text;\r\n const token = new SqlPrintToken(SqlPrintTokenType.value, fullName);\r\n // alias (if present and different from table name)\r\n if (arg.identifier && arg.identifier.name !== arg.table.name) {\r\n\r\n }\r\n return token;\r\n }\r\n\r\n private visitSourceExpression(arg: SourceExpression): SqlPrintToken {\r\n // Print source expression (e.g. \"table\", \"table as t\", \"schema.table t\")\r\n const token = new SqlPrintToken(SqlPrintTokenType.container, '', SqlPrintTokenContainerType.SourceExpression);\r\n token.innerTokens.push(arg.datasource.accept(this));\r\n\r\n if (!arg.aliasExpression) {\r\n return token;\r\n }\r\n\r\n if (arg.datasource instanceof TableSource) {\r\n // No alias needed if it matches the default name\r\n const defaultName = arg.datasource.table.name;\r\n if (arg.aliasExpression.table.name === defaultName) {\r\n return token;\r\n }\r\n token.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN);\r\n token.innerTokens.push(new SqlPrintToken(SqlPrintTokenType.keyword, 'as'));\r\n token.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN);\r\n // exclude column aliases\r\n token.innerTokens.push(arg.aliasExpression.accept(this));\r\n return token;\r\n } else {\r\n // For other source types, just print the alias\r\n token.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN);\r\n token.innerTokens.push(new SqlPrintToken(SqlPrintTokenType.keyword, 'as'));\r\n token.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN);\r\n // included column aliases\r\n token.innerTokens.push(arg.aliasExpression.accept(this));\r\n return token;\r\n }\r\n }\r\n\r\n public visitFromClause(arg: FromClause): SqlPrintToken {\r\n const token = new SqlPrintToken(SqlPrintTokenType.keyword, 'from', SqlPrintTokenContainerType.FromClause);\r\n\r\n token.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN);\r\n token.innerTokens.push(this.visit(arg.source));\r\n\r\n if (arg.joins) {\r\n for (let i = 0; i < arg.joins.length; i++) {\r\n token.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN);\r\n token.innerTokens.push(this.visit(arg.joins[i]));\r\n }\r\n }\r\n\r\n return token;\r\n }\r\n\r\n public visitJoinClause(arg: JoinClause): SqlPrintToken {\r\n // Print join clause: [joinType] [lateral] [source] [on/using ...]\r\n const token = new SqlPrintToken(SqlPrintTokenType.container, '', SqlPrintTokenContainerType.JoinClause);\r\n\r\n // join type (e.g. inner join, left join, etc)\r\n token.innerTokens.push(new SqlPrintToken(SqlPrintTokenType.keyword, arg.joinType.value));\r\n if (arg.lateral) {\r\n token.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN);\r\n token.innerTokens.push(new SqlPrintToken(SqlPrintTokenType.keyword, 'lateral'));\r\n }\r\n token.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN);\r\n token.innerTokens.push(this.visit(arg.source));\r\n\r\n if (arg.condition) {\r\n token.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN);\r\n token.innerTokens.push(this.visit(arg.condition));\r\n }\r\n\r\n return token;\r\n }\r\n\r\n public visitJoinOnClause(arg: JoinOnClause): SqlPrintToken {\r\n const token = new SqlPrintToken(SqlPrintTokenType.container, '', SqlPrintTokenContainerType.JoinOnClause);\r\n\r\n token.innerTokens.push(new SqlPrintToken(SqlPrintTokenType.keyword, 'on'));\r\n token.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN);\r\n token.innerTokens.push(this.visit(arg.condition));\r\n\r\n return token;\r\n }\r\n\r\n public visitJoinUsingClause(arg: JoinUsingClause): SqlPrintToken {\r\n const token = new SqlPrintToken(SqlPrintTokenType.container, '', SqlPrintTokenContainerType.JoinUsingClause);\r\n\r\n token.innerTokens.push(new SqlPrintToken(SqlPrintTokenType.keyword, 'using'));\r\n token.innerTokens.push(SqlPrintTokenParser.PAREN_OPEN_TOKEN);\r\n token.innerTokens.push(this.visit(arg.condition));\r\n token.innerTokens.push(SqlPrintTokenParser.PAREN_CLOSE_TOKEN);\r\n\r\n return token;\r\n }\r\n\r\n public visitFunctionSource(arg: FunctionSource): SqlPrintToken {\r\n // Print function source: [functionName]([args])\r\n const token = new SqlPrintToken(SqlPrintTokenType.container, '', SqlPrintTokenContainerType.FunctionSource);\r\n\r\n token.innerTokens.push(arg.qualifiedName.accept(this));\r\n token.innerTokens.push(SqlPrintTokenParser.PAREN_OPEN_TOKEN);\r\n if (arg.argument) {\r\n token.innerTokens.push(this.visit(arg.argument));\r\n }\r\n token.innerTokens.push(SqlPrintTokenParser.PAREN_CLOSE_TOKEN);\r\n return token;\r\n }\r\n\r\n public visitSourceAliasExpression(arg: SourceAliasExpression): SqlPrintToken {\r\n // Print source alias expression: [source] as [alias]\r\n const token = new SqlPrintToken(\r\n SqlPrintTokenType.container,\r\n '',\r\n SqlPrintTokenContainerType.SourceAliasExpression\r\n );\r\n\r\n token.innerTokens.push(this.visit(arg.table));\r\n\r\n if (arg.columns) {\r\n token.innerTokens.push(SqlPrintTokenParser.PAREN_OPEN_TOKEN);\r\n for (let i = 0; i < arg.columns.length; i++) {\r\n if (i > 0) {\r\n token.innerTokens.push(...SqlPrintTokenParser.argumentCommaSpaceTokens());\r\n }\r\n token.innerTokens.push(this.visit(arg.columns[i]));\r\n }\r\n token.innerTokens.push(SqlPrintTokenParser.PAREN_CLOSE_TOKEN);\r\n }\r\n\r\n return token;\r\n }\r\n\r\n public visitWhereClause(arg: WhereClause): SqlPrintToken {\r\n const token = new SqlPrintToken(SqlPrintTokenType.keyword, 'where', SqlPrintTokenContainerType.WhereClause);\r\n\r\n token.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN);\r\n token.innerTokens.push(this.visit(arg.condition));\r\n\r\n return token;\r\n }\r\n\r\n public visitGroupByClause(arg: GroupByClause): SqlPrintToken {\r\n const token = new SqlPrintToken(SqlPrintTokenType.keyword, 'group by', SqlPrintTokenContainerType.GroupByClause);\r\n\r\n token.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN);\r\n for (let i = 0; i < arg.grouping.length; i++) {\r\n if (i > 0) {\r\n token.innerTokens.push(...SqlPrintTokenParser.commaSpaceTokens());\r\n }\r\n token.innerTokens.push(this.visit(arg.grouping[i]));\r\n }\r\n\r\n return token;\r\n }\r\n\r\n public visitHavingClause(arg: HavingClause): SqlPrintToken {\r\n const token = new SqlPrintToken(SqlPrintTokenType.keyword, 'having', SqlPrintTokenContainerType.HavingClause);\r\n\r\n token.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN);\r\n token.innerTokens.push(this.visit(arg.condition));\r\n\r\n return token;\r\n }\r\n\r\n public visitWindowClause(arg: WindowClause): SqlPrintToken {\r\n const token = new SqlPrintToken(SqlPrintTokenType.keyword, 'window', SqlPrintTokenContainerType.WindowClause);\r\n\r\n token.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN);\r\n for (let i = 0; i < arg.windows.length; i++) {\r\n if (i > 0) {\r\n token.innerTokens.push(...SqlPrintTokenParser.commaSpaceTokens());\r\n }\r\n token.innerTokens.push(this.visit(arg.windows[i]));\r\n }\r\n\r\n return token;\r\n }\r\n\r\n public visitWindowFrameClause(arg: WindowFrameClause): SqlPrintToken {\r\n const token = new SqlPrintToken(SqlPrintTokenType.container, '', SqlPrintTokenContainerType.WindowFrameClause);\r\n\r\n token.innerTokens.push(arg.name.accept(this));\r\n token.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN);\r\n token.innerTokens.push(new SqlPrintToken(SqlPrintTokenType.keyword, 'as'));\r\n token.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN);\r\n token.innerTokens.push(SqlPrintTokenParser.PAREN_OPEN_TOKEN);\r\n token.innerTokens.push(this.visit(arg.expression));\r\n token.innerTokens.push(SqlPrintTokenParser.PAREN_CLOSE_TOKEN);\r\n\r\n return token;\r\n }\r\n\r\n public visitLimitClause(arg: LimitClause): SqlPrintToken {\r\n const token = new SqlPrintToken(SqlPrintTokenType.keyword, 'limit', SqlPrintTokenContainerType.LimitClause);\r\n\r\n token.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN);\r\n token.innerTokens.push(this.visit(arg.value));\r\n\r\n return token;\r\n }\r\n\r\n public visitOffsetClause(arg: OffsetClause): SqlPrintToken {\r\n const token = new SqlPrintToken(SqlPrintTokenType.keyword, 'offset', SqlPrintTokenContainerType.OffsetClause);\r\n\r\n token.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN);\r\n token.innerTokens.push(this.visit(arg.value));\r\n\r\n return token;\r\n }\r\n\r\n public visitFetchClause(arg: FetchClause): SqlPrintToken {\r\n const token = new SqlPrintToken(SqlPrintTokenType.keyword, 'fetch', SqlPrintTokenContainerType.FetchClause);\r\n\r\n token.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN);\r\n token.innerTokens.push(this.visit(arg.expression));\r\n\r\n return token;\r\n }\r\n\r\n public visitFetchExpression(arg: FetchExpression): SqlPrintToken {\r\n const token = new SqlPrintToken(SqlPrintTokenType.container, '', SqlPrintTokenContainerType.FetchExpression);\r\n\r\n token.innerTokens.push(new SqlPrintToken(SqlPrintTokenType.keyword, arg.type));\r\n token.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN);\r\n token.innerTokens.push(arg.count.accept(this));\r\n\r\n if (arg.unit) {\r\n token.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN);\r\n token.innerTokens.push(new SqlPrintToken(SqlPrintTokenType.keyword, arg.unit));\r\n }\r\n\r\n return token;\r\n }\r\n\r\n public visitForClause(arg: ForClause): SqlPrintToken {\r\n const token = new SqlPrintToken(SqlPrintTokenType.keyword, 'for', SqlPrintTokenContainerType.ForClause);\r\n\r\n token.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN);\r\n token.innerTokens.push(new SqlPrintToken(SqlPrintTokenType.keyword, arg.lockMode));\r\n\r\n return token;\r\n }\r\n\r\n public visitWithClause(arg: WithClause): SqlPrintToken {\r\n const token = new SqlPrintToken(SqlPrintTokenType.keyword, 'with', SqlPrintTokenContainerType.WithClause);\r\n\r\n token.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN);\r\n if (arg.recursive) {\r\n token.innerTokens.push(new SqlPrintToken(SqlPrintTokenType.keyword, 'recursive'));\r\n token.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN);\r\n }\r\n\r\n for (let i = 0; i < arg.tables.length; i++) {\r\n if (i > 0) {\r\n token.innerTokens.push(...SqlPrintTokenParser.commaSpaceTokens());\r\n }\r\n token.innerTokens.push(arg.tables[i].accept(this));\r\n }\r\n\r\n token.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN);\r\n return token;\r\n }\r\n\r\n public visitCommonTable(arg: CommonTable): SqlPrintToken {\r\n const token = new SqlPrintToken(SqlPrintTokenType.container, '', SqlPrintTokenContainerType.CommonTable);\r\n\r\n token.innerTokens.push(arg.aliasExpression.accept(this));\r\n token.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN);\r\n token.innerTokens.push(new SqlPrintToken(SqlPrintTokenType.keyword, 'as'));\r\n token.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN);\r\n\r\n if (arg.materialized !== null) {\r\n if (arg.materialized) {\r\n token.innerTokens.push(new SqlPrintToken(SqlPrintTokenType.keyword, 'materialized'));\r\n } else {\r\n token.innerTokens.push(new SqlPrintToken(SqlPrintTokenType.keyword, 'not materialized'));\r\n }\r\n token.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN);\r\n }\r\n\r\n token.innerTokens.push(SqlPrintTokenParser.PAREN_OPEN_TOKEN);\r\n\r\n const query = new SqlPrintToken(SqlPrintTokenType.container, '', SqlPrintTokenContainerType.SubQuerySource);\r\n query.innerTokens.push(arg.query.accept(this));\r\n\r\n token.innerTokens.push(query);\r\n token.innerTokens.push(SqlPrintTokenParser.PAREN_CLOSE_TOKEN);\r\n\r\n return token;\r\n }\r\n\r\n // query\r\n public visitSimpleQuery(arg: SimpleSelectQuery): SqlPrintToken {\r\n const token = new SqlPrintToken(SqlPrintTokenType.container, '', SqlPrintTokenContainerType.SimpleSelectQuery);\r\n\r\n if (arg.withClause) {\r\n token.innerTokens.push(arg.withClause.accept(this));\r\n }\r\n\r\n token.innerTokens.push(arg.selectClause.accept(this));\r\n\r\n if (!arg.fromClause) {\r\n return token;\r\n }\r\n\r\n token.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN);\r\n token.innerTokens.push(arg.fromClause.accept(this));\r\n\r\n if (arg.whereClause) {\r\n token.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN);\r\n token.innerTokens.push(arg.whereClause.accept(this));\r\n }\r\n\r\n if (arg.groupByClause) {\r\n token.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN);\r\n token.innerTokens.push(arg.groupByClause.accept(this));\r\n }\r\n\r\n if (arg.havingClause) {\r\n token.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN);\r\n token.innerTokens.push(arg.havingClause.accept(this));\r\n }\r\n\r\n if (arg.orderByClause) {\r\n token.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN);\r\n token.innerTokens.push(arg.orderByClause.accept(this));\r\n }\r\n\r\n if (arg.windowClause) {\r\n token.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN);\r\n token.innerTokens.push(arg.windowClause.accept(this));\r\n }\r\n\r\n if (arg.limitClause) {\r\n token.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN);\r\n token.innerTokens.push(arg.limitClause.accept(this));\r\n }\r\n\r\n if (arg.offsetClause) {\r\n token.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN);\r\n token.innerTokens.push(arg.offsetClause.accept(this));\r\n }\r\n\r\n if (arg.fetchClause) {\r\n token.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN);\r\n token.innerTokens.push(arg.fetchClause.accept(this));\r\n }\r\n\r\n if (arg.forClause) {\r\n token.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN);\r\n token.innerTokens.push(arg.forClause.accept(this));\r\n }\r\n\r\n return token;\r\n }\r\n\r\n public visitSubQuerySource(arg: SubQuerySource): SqlPrintToken {\r\n const token = new SqlPrintToken(SqlPrintTokenType.container, '');\r\n\r\n token.innerTokens.push(SqlPrintTokenParser.PAREN_OPEN_TOKEN);\r\n\r\n const subQuery = new SqlPrintToken(SqlPrintTokenType.container, '', SqlPrintTokenContainerType.SubQuerySource);\r\n subQuery.innerTokens.push(arg.query.accept(this));\r\n\r\n token.innerTokens.push(subQuery);\r\n token.innerTokens.push(SqlPrintTokenParser.PAREN_CLOSE_TOKEN);\r\n\r\n return token;\r\n }\r\n\r\n public visitValuesQuery(arg: ValuesQuery): SqlPrintToken {\r\n const token = new SqlPrintToken(SqlPrintTokenType.keyword, 'values', SqlPrintTokenContainerType.ValuesQuery);\r\n token.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN);\r\n\r\n const values = new SqlPrintToken(SqlPrintTokenType.container, '', SqlPrintTokenContainerType.Values);\r\n for (let i = 0; i < arg.tuples.length; i++) {\r\n if (i > 0) {\r\n values.innerTokens.push(...SqlPrintTokenParser.commaSpaceTokens());\r\n }\r\n values.innerTokens.push(arg.tuples[i].accept(this));\r\n }\r\n\r\n token.innerTokens.push(values);\r\n return token;\r\n }\r\n\r\n public visitInlineQuery(arg: InlineQuery): SqlPrintToken {\r\n const token = new SqlPrintToken(SqlPrintTokenType.container, '');\r\n\r\n token.innerTokens.push(SqlPrintTokenParser.PAREN_OPEN_TOKEN);\r\n\r\n const queryToken = new SqlPrintToken(SqlPrintTokenType.container, '', SqlPrintTokenContainerType.InlineQuery);\r\n queryToken.innerTokens.push(arg.selectQuery.accept(this));\r\n\r\n token.innerTokens.push(queryToken);\r\n token.innerTokens.push(SqlPrintTokenParser.PAREN_CLOSE_TOKEN);\r\n\r\n return token;\r\n }\r\n\r\n private visitInsertQuery(arg: InsertQuery): SqlPrintToken {\r\n const token = new SqlPrintToken(SqlPrintTokenType.container, '', SqlPrintTokenContainerType.InsertQuery);\r\n\r\n // Process the insert clause\r\n token.innerTokens.push(this.visit(arg.insertClause));\r\n\r\n // Process the select query if present\r\n if (arg.selectQuery) {\r\n token.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN);\r\n token.innerTokens.push(this.visit(arg.selectQuery));\r\n }\r\n\r\n return token;\r\n }\r\n\r\n private visitInsertClause(arg: InsertClause): SqlPrintToken {\r\n const token = new SqlPrintToken(SqlPrintTokenType.container, '');\r\n\r\n token.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN);\r\n token.innerTokens.push(new SqlPrintToken(SqlPrintTokenType.keyword, 'insert into'));\r\n token.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN);\r\n token.innerTokens.push(arg.source.accept(this));\r\n\r\n if (arg.columns.length > 0) {\r\n token.innerTokens.push(SqlPrintTokenParser.PAREN_OPEN_TOKEN);\r\n for (let i = 0; i < arg.columns.length; i++) {\r\n if (i > 0) {\r\n token.innerTokens.push(...SqlPrintTokenParser.commaSpaceTokens());\r\n }\r\n token.innerTokens.push(arg.columns[i].accept(this));\r\n }\r\n token.innerTokens.push(SqlPrintTokenParser.PAREN_CLOSE_TOKEN);\r\n }\r\n\r\n return token;\r\n }\r\n\r\n private visitUpdateQuery(arg: UpdateQuery): SqlPrintToken {\r\n const token = new SqlPrintToken(SqlPrintTokenType.container, '', SqlPrintTokenContainerType.UpdateQuery);\r\n\r\n if (arg.withClause) {\r\n token.innerTokens.push(arg.withClause.accept(this));\r\n }\r\n\r\n token.innerTokens.push(arg.updateClause.accept(this));\r\n token.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN);\r\n token.innerTokens.push(arg.setClause.accept(this));\r\n\r\n if (arg.fromClause) {\r\n token.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN);\r\n token.innerTokens.push(arg.fromClause.accept(this));\r\n }\r\n\r\n if (arg.whereClause) {\r\n token.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN);\r\n token.innerTokens.push(arg.whereClause.accept(this));\r\n }\r\n\r\n if (arg.returningClause) {\r\n token.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN);\r\n token.innerTokens.push(arg.returningClause.accept(this));\r\n }\r\n\r\n return token;\r\n }\r\n\r\n public visitUpdateClause(arg: UpdateClause): SqlPrintToken {\r\n const token = new SqlPrintToken(SqlPrintTokenType.keyword, 'update', SqlPrintTokenContainerType.UpdateClause);\r\n\r\n token.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN);\r\n token.innerTokens.push(arg.source.accept(this));\r\n\r\n return token;\r\n }\r\n\r\n public visitSetClause(arg: SetClause): SqlPrintToken {\r\n const token = new SqlPrintToken(SqlPrintTokenType.keyword, 'set', SqlPrintTokenContainerType.SelectClause);\r\n\r\n token.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN);\r\n for (let i = 0; i < arg.items.length; i++) {\r\n if (i > 0) {\r\n token.innerTokens.push(...SqlPrintTokenParser.commaSpaceTokens());\r\n }\r\n token.innerTokens.push(this.visit(arg.items[i]));\r\n }\r\n\r\n return token;\r\n }\r\n\r\n public visitSetClauseItem(arg: SetClauseItem): SqlPrintToken {\r\n const token = new SqlPrintToken(SqlPrintTokenType.container, '', SqlPrintTokenContainerType.SetClauseItem);\r\n\r\n token.innerTokens.push(arg.column.accept(this));\r\n token.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN);\r\n token.innerTokens.push(new SqlPrintToken(SqlPrintTokenType.operator, '='));\r\n token.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN);\r\n token.innerTokens.push(arg.value.accept(this));\r\n\r\n return token;\r\n }\r\n\r\n public visitReturningClause(arg: ReturningClause): SqlPrintToken {\r\n const token = new SqlPrintToken(SqlPrintTokenType.keyword, 'returning', SqlPrintTokenContainerType.ReturningClause);\r\n\r\n token.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN);\r\n for (let i = 0; i < arg.columns.length; i++) {\r\n if (i > 0) {\r\n token.innerTokens.push(...SqlPrintTokenParser.commaSpaceTokens());\r\n }\r\n token.innerTokens.push(this.visit(arg.columns[i]));\r\n }\r\n\r\n return token;\r\n }\r\n\r\n public visitCreateTableQuery(arg: CreateTableQuery): SqlPrintToken {\r\n const token = new SqlPrintToken(SqlPrintTokenType.keyword, arg.isTemporary ? 'create temporary table' : 'create table', SqlPrintTokenContainerType.CreateTableQuery);\r\n\r\n token.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN);\r\n token.innerTokens.push(arg.tableName.accept(this));\r\n\r\n if (arg.asSelectQuery) {\r\n token.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN);\r\n token.innerTokens.push(new SqlPrintToken(SqlPrintTokenType.keyword, 'as'));\r\n token.innerTokens.push(SqlPrintTokenParser.SPACE_TOKEN);\r\n token.innerTokens.push(arg.asSelectQuery.accept(this));\r\n }\r\n\r\n return token;\r\n }\r\n}\r\n", "// Define the allowed newline options\r\nexport type NewlineOption = ' ' | '\\n' | '\\r\\n';\r\n\r\n// Define the allowed indent character options\r\nexport type IndentCharOption = '' | ' ' | '\\t';\r\n\r\n/**\r\n * SqlPrintHelper provides utility methods for SQL pretty printing.\r\n */\r\nexport class LinePrinter {\r\n indentChar: IndentCharOption; // Changed type to IndentCharOption\r\n indentSize: number;\r\n newline: NewlineOption; // Changed type to NewlineOption\r\n lines: PrintLine[];\r\n /**\r\n * @param indentChar Character used for indentation (default: ' ') // Updated comment to reflect options\r\n * @param indentSize Number of indentChar per level (default: 0)\r\n * @param newline Newline string (default: '\\r\\n') // Changed type and default value\r\n */\r\n constructor(indentChar: IndentCharOption = ' ', indentSize: number = 0, newline: NewlineOption = '\\r\\n') { // Changed type for indentChar\r\n this.indentChar = indentChar;\r\n this.indentSize = indentSize;\r\n this.newline = newline;\r\n this.lines = [];\r\n this.appendNewline(0);\r\n }\r\n\r\n public print(): string {\r\n let result = '';\r\n for (const line of this.lines) {\r\n if (line.text !== '') {\r\n // append indent and text\r\n result += this.indent(line.level) + line.text;\r\n }\r\n }\r\n return result.trimEnd();\r\n }\r\n\r\n /**\r\n * Returns the indent string for a given level.\r\n * @param level Indentation level\r\n */\r\n private indent(level: number): string {\r\n return this.indentChar.repeat(this.indentSize * level);\r\n }\r\n\r\n /**\r\n * Appends a newline token to the given tokens array if newline is set, or adds an empty line if tokens is empty.\r\n * @param tokens Array of token objects with 'level' and 'text' property\r\n * @param level Indentation level\r\n */\r\n appendNewline(level: number): void {\r\n if (this.lines.length > 0) {\r\n const current = this.lines[this.lines.length - 1];\r\n if (current.text !== '') {\r\n current.text = current.text.trimEnd() + this.newline;\r\n }\r\n }\r\n this.lines.push(new PrintLine(level, ''));\r\n }\r\n\r\n /**\r\n * Appends text to the last element of tokens array.\r\n * @param tokens Array of token objects with 'text' property\r\n * @param text Text to append\r\n */\r\n appendText(text: string): void {\r\n if (this.lines.length > 0) {\r\n const workingIndex = this.lines.length - 1;\r\n const workLine = this.lines[workingIndex]\r\n // Leading space is not needed\r\n if (!(text === ' ' && workLine.text === '')) {\r\n workLine.text += text;\r\n }\r\n } else {\r\n throw new Error('No tokens to append to.');\r\n }\r\n }\r\n\r\n getCurrentLine(): PrintLine {\r\n if (this.lines.length > 0) {\r\n return this.lines[this.lines.length - 1];\r\n } else {\r\n throw new Error('No tokens to get current line from.');\r\n }\r\n }\r\n}\r\n\r\nexport class PrintLine {\r\n level: number;\r\n text: string;\r\n\r\n constructor(level: number, text: string) {\r\n this.level = level;\r\n this.text = text;\r\n }\r\n}", "import { SqlPrintToken, SqlPrintTokenType, SqlPrintTokenContainerType } from \"../models/SqlPrintToken\";\r\nimport { IndentCharOption, LinePrinter, NewlineOption } from \"./LinePrinter\";\r\n\r\n/**\r\n * CommaBreakStyle determines how commas are placed in formatted SQL output.\r\n * - 'none': No line break for commas\r\n * - 'before': Line break before comma\r\n * - 'after': Line break after comma\r\n */\r\nexport type CommaBreakStyle = 'none' | 'before' | 'after';\r\n\r\n/**\r\n * AndBreakStyle determines how AND operators are placed in formatted SQL output.\r\n * - 'none': No line break for AND\r\n * - 'before': Line break before AND\r\n * - 'after': Line break after AND\r\n */\r\nexport type AndBreakStyle = 'none' | 'before' | 'after';\r\n\r\n/**\r\n * SqlPrinter formats a SqlPrintToken tree into a SQL string with flexible style options.\r\n */\r\nexport class SqlPrinter {\r\n /** Indent character (e.g., ' ' or '\\\\t') */\r\n indentChar: IndentCharOption; // Changed type from string\r\n /** Indent size (number of indentChar repetitions per level) */\r\n indentSize: number;\r\n /** Newline character (e.g., '\\\\n' or '\\\\r\\\\n') */\r\n newline: NewlineOption; // Changed type from string\r\n /** Comma break style: 'none', 'before', or 'after' */\r\n commaBreak: CommaBreakStyle;\r\n /** AND break style: 'none', 'before', or 'after' */\r\n andBreak: AndBreakStyle;\r\n\r\n /** Keyword case style: 'none', 'upper' | 'lower' */\r\n keywordCase: 'none' | 'upper' | 'lower';\r\n\r\n private linePrinter: LinePrinter;\r\n private indentIncrementContainers: Set<SqlPrintTokenContainerType>;\r\n\r\n /**\r\n * @param options Optional style settings for pretty printing\r\n */\r\n constructor(options?: {\r\n indentChar?: IndentCharOption;\r\n indentSize?: number;\r\n newline?: NewlineOption;\r\n commaBreak?: CommaBreakStyle;\r\n andBreak?: AndBreakStyle;\r\n keywordCase?: 'none' | 'upper' | 'lower';\r\n indentIncrementContainerTypes?: string[]; // Option to customize\r\n }) {\r\n this.indentChar = options?.indentChar ?? '';\r\n this.indentSize = options?.indentSize ?? 0;\r\n\r\n // The default newline character is set to a blank space (' ') to enable one-liner formatting.\r\n // This is intentional and differs from the LinePrinter default of '\\r\\n'.\r\n this.newline = options?.newline ?? ' ';\r\n\r\n this.commaBreak = options?.commaBreak ?? 'none';\r\n this.andBreak = options?.andBreak ?? 'none';\r\n this.keywordCase = options?.keywordCase ?? 'none';\r\n this.linePrinter = new LinePrinter(this.indentChar, this.indentSize, this.newline);\r\n\r\n // Initialize\r\n this.indentIncrementContainers = new Set(\r\n (options?.indentIncrementContainerTypes as SqlPrintTokenContainerType[] | undefined) ?? [\r\n SqlPrintTokenContainerType.SelectClause,\r\n SqlPrintTokenContainerType.FromClause,\r\n SqlPrintTokenContainerType.WhereClause,\r\n SqlPrintTokenContainerType.GroupByClause,\r\n SqlPrintTokenContainerType.HavingClause,\r\n SqlPrintTokenContainerType.WindowFrameExpression,\r\n SqlPrintTokenContainerType.PartitionByClause,\r\n SqlPrintTokenContainerType.OrderByClause,\r\n SqlPrintTokenContainerType.WindowClause,\r\n SqlPrintTokenContainerType.LimitClause,\r\n SqlPrintTokenContainerType.OffsetClause,\r\n SqlPrintTokenContainerType.SubQuerySource,\r\n SqlPrintTokenContainerType.BinarySelectQueryOperator, SqlPrintTokenContainerType.Values,\r\n SqlPrintTokenContainerType.WithClause,\r\n SqlPrintTokenContainerType.SwitchCaseArgument,\r\n SqlPrintTokenContainerType.CaseKeyValuePair,\r\n SqlPrintTokenContainerType.CaseThenValue,\r\n SqlPrintTokenContainerType.ElseClause,\r\n SqlPrintTokenContainerType.CaseElseValue\r\n // CaseExpression, SwitchCaseArgument, CaseKeyValuePair, and ElseClause\r\n // are not included by default to maintain backward compatibility with tests\r\n //SqlPrintTokenContainerType.CommonTable\r\n ]\r\n );\r\n }\r\n\r\n /**\r\n * Converts a SqlPrintToken tree to a formatted SQL string.\r\n * @param token The root SqlPrintToken\r\n * @param level Indentation level (default: 0)\r\n */\r\n print(token: SqlPrintToken, level: number = 0): string {\r\n // initialize\r\n this.linePrinter = new LinePrinter(this.indentChar, this.indentSize, this.newline);\r\n if (this.linePrinter.lines.length > 0 && level !== this.linePrinter.lines[0].level) {\r\n this.linePrinter.lines[0].level = level;\r\n }\r\n\r\n this.appendToken(token, level);\r\n\r\n return this.linePrinter.print();\r\n }\r\n\r\n private appendToken(token: SqlPrintToken, level: number) {\r\n if (!token.innerTokens || token.innerTokens.length === 0) {\r\n if (token.text === '') {\r\n return;\r\n }\r\n }\r\n\r\n const current = this.linePrinter.getCurrentLine();\r\n\r\n if (token.type === SqlPrintTokenType.keyword) {\r\n let text = token.text;\r\n if (this.keywordCase === 'upper') {\r\n text = text.toUpperCase();\r\n } else if (this.keywordCase === 'lower') {\r\n text = text.toLowerCase();\r\n }\r\n this.linePrinter.appendText(text);\r\n } else if (token.type === SqlPrintTokenType.comma) {\r\n let text = token.text;\r\n if (this.commaBreak === 'before') {\r\n this.linePrinter.appendNewline(level);\r\n this.linePrinter.appendText(text);\r\n } else if (this.commaBreak === 'after') {\r\n this.linePrinter.appendText(text);\r\n this.linePrinter.appendNewline(level);\r\n } else {\r\n this.linePrinter.appendText(text);\r\n }\r\n } else if (token.type === SqlPrintTokenType.operator && token.text.toLowerCase() === 'and') {\r\n let text = token.text;\r\n if (this.keywordCase === 'upper') {\r\n text = text.toUpperCase();\r\n } else if (this.keywordCase === 'lower') {\r\n text = text.toLowerCase();\r\n }\r\n\r\n if (this.andBreak === 'before') {\r\n this.linePrinter.appendNewline(level);\r\n this.linePrinter.appendText(text);\r\n } else if (this.andBreak === 'after') {\r\n this.linePrinter.appendText(text);\r\n this.linePrinter.appendNewline(level);\r\n } else {\r\n this.linePrinter.appendText(text);\r\n }\r\n } else if (token.containerType === \"JoinClause\") {\r\n let text = token.text;\r\n if (this.keywordCase === 'upper') {\r\n text = text.toUpperCase();\r\n } else if (this.keywordCase === 'lower') {\r\n text = text.toLowerCase();\r\n }\r\n // before join clause, add newline\r\n this.linePrinter.appendNewline(level);\r\n this.linePrinter.appendText(text);\r\n } else {\r\n this.linePrinter.appendText(token.text);\r\n }\r\n\r\n // append keyword tokens(not indented)\r\n if (token.keywordTokens && token.keywordTokens.length > 0) {\r\n for (let i = 0; i < token.keywordTokens.length; i++) {\r\n const keywordToken = token.keywordTokens[i];\r\n this.appendToken(keywordToken, level);\r\n }\r\n }\r\n\r\n let innerLevel = level;\r\n\r\n // indent level up\r\n if (this.newline !== ' ' && current.text !== '' && this.indentIncrementContainers.has(token.containerType)) { // Changed condition\r\n innerLevel++;\r\n this.linePrinter.appendNewline(innerLevel);\r\n }\r\n\r\n for (let i = 0; i < token.innerTokens.length; i++) {\r\n const child = token.innerTokens[i];\r\n this.appendToken(child, innerLevel);\r\n }\r\n\r\n // indent level down\r\n if (innerLevel !== level) {\r\n this.linePrinter.appendNewline(level);\r\n }\r\n }\r\n}", "import { SqlPrintTokenParser, FormatterConfig, PRESETS } from '../parsers/SqlPrintTokenParser';\r\nimport { SqlPrinter, CommaBreakStyle, AndBreakStyle } from './SqlPrinter';\r\nimport { IndentCharOption, NewlineOption } from './LinePrinter'; // Import types for compatibility\r\nimport { SelectQuery } from '../models/SelectQuery';\r\nimport { SqlComponent } from '../models/SqlComponent';\r\n\r\n// Define valid preset names as a union type\r\nexport const VALID_PRESETS = ['mysql', 'postgres', 'sqlserver', 'sqlite'] as const;\r\nexport type PresetName = (typeof VALID_PRESETS)[number];\r\n\r\n/**\r\n * SqlFormatter class combines parsing and printing of SQL queries into a single interface.\r\n */\r\nexport class SqlFormatter {\r\n private parser: SqlPrintTokenParser;\r\n private printer: SqlPrinter;\r\n\r\n constructor(options: {\r\n preset?: PresetName; // Restrict preset to specific strings\r\n identifierEscape?: { start: string; end: string }; // Allow custom identifier escape\r\n parameterSymbol?: string | { start: string; end: string }; // Allow custom parameter symbol\r\n parameterStyle?: 'anonymous' | 'indexed' | 'named'; // Allow custom parameter style\r\n indentSize?: number;\r\n indentChar?: IndentCharOption; // Updated type\r\n newline?: NewlineOption; // Updated type\r\n keywordCase?: 'none' | 'upper' | 'lower'; // Updated type\r\n commaBreak?: CommaBreakStyle; // Updated type\r\n andBreak?: AndBreakStyle; // Updated type\r\n } = {}) { // Default to 'sqlserver' if options is empty\r\n\r\n const presetConfig = options.preset ? PRESETS[options.preset] : undefined;\r\n\r\n if (options.preset && !presetConfig) {\r\n throw new Error(`Invalid preset: ${options.preset}`); // Throw error for invalid preset\r\n }\r\n\r\n const parserOptions = {\r\n ...presetConfig, // Apply preset configuration\r\n identifierEscape: options.identifierEscape ?? presetConfig?.identifierEscape,\r\n parameterSymbol: options.parameterSymbol ?? presetConfig?.parameterSymbol,\r\n parameterStyle: options.parameterStyle ?? presetConfig?.parameterStyle,\r\n };\r\n\r\n this.parser = new SqlPrintTokenParser(parserOptions);\r\n this.printer = new SqlPrinter(options);\r\n } /**\r\n * Formats a SQL query string with the given parameters.\r\n * @param sqlText The SQL query string to format.\r\n * @param parameters A dictionary of parameters to replace in the query.\r\n * @returns An object containing the formatted SQL string and the parameters.\r\n */\r\n format(sql: SqlComponent): { formattedSql: string; params: any[] | Record<string, any> } {\r\n const { token, params } = this.parser.parse(sql);\r\n const formattedSql = this.printer.print(token);\r\n\r\n return { formattedSql, params };\r\n }\r\n}\r\n", "import { SqlFormatter } from './SqlFormatter';\r\nimport { SelectQuery } from '../models/SelectQuery';\r\nimport { SqlComponent, SqlComponentVisitor } from '../models/SqlComponent';\r\nimport { FormatterConfig } from '../parsers/SqlPrintTokenParser';\r\n\r\n/**\r\n * @deprecated The Formatter class is deprecated. Use SqlFormatter instead.\r\n */\r\nexport class Formatter implements SqlComponentVisitor<string> {\r\n private sqlFormatter: SqlFormatter;\r\n\r\n constructor() {\r\n this.sqlFormatter = new SqlFormatter({\r\n identifierEscape: { start: '\"', end: '\"' },\r\n parameterSymbol: ':',\r\n parameterStyle: 'named' // Default to 'named' for backward compatibility\r\n });\r\n }\r\n\r\n public format(arg: SqlComponent, config: FormatterConfig | null = null): string {\r\n // Use the sqlFormatter instance to format the SQL component\r\n if (config) {\r\n this.sqlFormatter = new SqlFormatter(config);\r\n }\r\n const result = this.sqlFormatter.format(arg);\r\n return result.formattedSql;\r\n }\r\n\r\n public formatWithParameters(arg: SqlComponent, config: FormatterConfig | null = null): { sql: string, params: any[] | Record<string, any>[] | Record<string, any> } {\r\n // Use the sqlFormatter instance to format the SQL component with parameters\r\n if (config) {\r\n this.sqlFormatter = new SqlFormatter(config);\r\n }\r\n const result = this.sqlFormatter.format(arg);\r\n return { sql: result.formattedSql, params: result.params };\r\n }\r\n\r\n public visit(arg: SqlComponent): string {\r\n return this.format(arg);\r\n }\r\n}\r\n\r\nexport { SqlFormatter };", "import { CommonTable, WithClause } from \"../models/Clause\";\r\nimport { CTECollector } from \"./CTECollector\";\r\nimport { TableSourceCollector } from \"./TableSourceCollector\";\r\nimport { Formatter } from \"./Formatter\";\r\n\r\n/**\r\n * CTENameConflictResolver is responsible for resolving name conflicts among Common Table Expressions (CTEs).\r\n * It also sorts the tables in the proper order based on dependencies and recursiveness.\r\n */\r\nexport class CTEBuilder {\r\n private sourceCollector: TableSourceCollector;\r\n private cteCollector: CTECollector;\r\n private formatter: Formatter;\r\n\r\n constructor() {\r\n this.sourceCollector = new TableSourceCollector(true);\r\n this.cteCollector = new CTECollector();\r\n this.formatter = new Formatter();\r\n }\r\n\r\n /**\r\n * Resolves name conflicts among CommonTables.\r\n * If there are duplicate CTE names, they must have identical definitions.\r\n * Also sorts the tables so that:\r\n * 1. Recursive CTEs come first (CTEs that reference themselves)\r\n * 2. Then remaining tables are sorted so inner (deeper) CTEs come before outer CTEs\r\n * \r\n * @param commonTables The list of CommonTables to check for name conflicts\r\n * @returns An object containing:\r\n * - needRecursive: boolean indicating if any recursive CTEs are present\r\n * - commonTables: A new list of CommonTables with resolved name conflicts and proper order\r\n * @throws Error if there are duplicate CTE names with different definitions\r\n */\r\n public build(commonTables: CommonTable[]): WithClause {\r\n // Early return for empty CTEs\r\n // Note:\r\n // Although it may seem reasonable to return early when there is only one element,\r\n // the 'recursive' property is determined dynamically. Therefore, if there is at least one element,\r\n // the CTEs must be rebuilt to ensure correct recursive detection.\r\n if (commonTables.length === 0) {\r\n return new WithClause(\r\n false,\r\n commonTables\r\n );\r\n }\r\n\r\n // Step 1: Resolve name conflicts\r\n const resolvedTables = this.resolveDuplicateNames(commonTables);\r\n\r\n // Step 2: Identify recursive CTEs and build dependency graph\r\n const { tableMap, recursiveCTEs, dependencies } = this.buildDependencyGraph(resolvedTables);\r\n\r\n // Step 3: Sort tables according to dependencies and recursiveness\r\n const sortedTables = this.sortCommonTables(resolvedTables, tableMap, recursiveCTEs, dependencies);\r\n\r\n return new WithClause(\r\n recursiveCTEs.size > 0,\r\n sortedTables\r\n );\r\n }\r\n\r\n /**\r\n * Resolves duplicate CTE names by checking if they have identical definitions.\r\n * If definitions differ, throws an error.\r\n * \r\n * @param commonTables The list of CTEs to check for duplicates\r\n * @returns A list of CTEs with duplicates removed\r\n * @throws Error if there are duplicate CTE names with different definitions\r\n */\r\n private resolveDuplicateNames(commonTables: CommonTable[]): CommonTable[] {\r\n // Group CTEs by their names\r\n const ctesByName = new Map<string, CommonTable[]>();\r\n for (const table of commonTables) {\r\n const tableName = table.aliasExpression.table.name;\r\n if (!ctesByName.has(tableName)) {\r\n ctesByName.set(tableName, []);\r\n }\r\n ctesByName.get(tableName)!.push(table);\r\n }\r\n\r\n // Resolve name duplications\r\n const resolvedTables: CommonTable[] = [];\r\n for (const [name, tables] of ctesByName.entries()) {\r\n if (tables.length === 1) {\r\n // No duplication\r\n resolvedTables.push(tables[0]);\r\n continue;\r\n }\r\n\r\n // For duplicate names, check if definitions are identical\r\n const definitions = tables.map(table => this.formatter.format(table.query));\r\n const uniqueDefinitions = new Set(definitions);\r\n\r\n if (uniqueDefinitions.size === 1) {\r\n // If all definitions are identical, use only the first one\r\n resolvedTables.push(tables[0]);\r\n } else {\r\n // Error if definitions differ\r\n throw new Error(`CTE name conflict detected: '${name}' has multiple different definitions`);\r\n }\r\n }\r\n\r\n return resolvedTables;\r\n }\r\n\r\n /**\r\n * Builds a dependency graph of CTEs and identifies recursive CTEs.\r\n * \r\n * @param tables The list of CTEs to analyze\r\n * @returns Object containing the table map, set of recursive CTEs, and dependency map\r\n */\r\n private buildDependencyGraph(tables: CommonTable[]): {\r\n tableMap: Map<string, CommonTable>,\r\n recursiveCTEs: Set<string>,\r\n dependencies: Map<string, Set<string>>\r\n } {\r\n // Create a map of table names for quick lookup\r\n const tableMap = new Map<string, CommonTable>();\r\n for (const table of tables) {\r\n tableMap.set(table.aliasExpression.table.name, table);\r\n }\r\n\r\n // Identify recursive CTEs (those that reference themselves)\r\n const recursiveCTEs = new Set<string>();\r\n\r\n // Build dependency graph: which tables reference which other tables\r\n const dependencies = new Map<string, Set<string>>();\r\n const referencedBy = new Map<string, Set<string>>();\r\n\r\n for (const table of tables) {\r\n const tableName = table.aliasExpression.table.name;\r\n\r\n // Check for self-references (recursive CTEs)\r\n const referencedTables = this.sourceCollector.collect(table.query);\r\n\r\n // Check if this CTE references itself\r\n for (const referencedTable of referencedTables) {\r\n if (referencedTable.table.name === tableName) {\r\n recursiveCTEs.add(tableName);\r\n break;\r\n }\r\n }\r\n\r\n // Setup dependencies\r\n if (!dependencies.has(tableName)) {\r\n dependencies.set(tableName, new Set<string>());\r\n }\r\n\r\n // Find any references to other CTEs in this table's query\r\n const referencedCTEs = this.cteCollector.collect(table.query);\r\n\r\n for (const referencedCTE of referencedCTEs) {\r\n const referencedName = referencedCTE.aliasExpression.table.name;\r\n\r\n // Only consider references to tables in our collection\r\n if (tableMap.has(referencedName)) {\r\n dependencies.get(tableName)!.add(referencedName);\r\n\r\n // Add the reverse relationship\r\n if (!referencedBy.has(referencedName)) {\r\n referencedBy.set(referencedName, new Set<string>());\r\n }\r\n referencedBy.get(referencedName)!.add(tableName);\r\n }\r\n }\r\n }\r\n\r\n return { tableMap, recursiveCTEs, dependencies };\r\n }\r\n\r\n /**\r\n * Sorts the CTEs using topological sort, with recursive CTEs coming first.\r\n * \r\n * @param tables The list of CTEs to sort\r\n * @param tableMap Map of table names to their CommonTable objects\r\n * @param recursiveCTEs Set of table names that are recursive (self-referential)\r\n * @param dependencies Map of table dependencies\r\n * @returns Sorted list of CTEs\r\n * @throws Error if a circular reference is detected\r\n */\r\n private sortCommonTables(\r\n tables: CommonTable[],\r\n tableMap: Map<string, CommonTable>,\r\n recursiveCTEs: Set<string>,\r\n dependencies: Map<string, Set<string>>\r\n ): CommonTable[] {\r\n const recursiveResult: CommonTable[] = [];\r\n const nonRecursiveResult: CommonTable[] = [];\r\n const visited = new Set<string>();\r\n const visiting = new Set<string>();\r\n\r\n // Topological sort function\r\n const visit = (tableName: string) => {\r\n if (visited.has(tableName)) return;\r\n if (visiting.has(tableName)) {\r\n throw new Error(`Circular reference detected in CTE: ${tableName}`);\r\n }\r\n\r\n visiting.add(tableName);\r\n\r\n // Process dependencies first (inner CTEs)\r\n const deps = dependencies.get(tableName) || new Set<string>();\r\n for (const dep of deps) {\r\n visit(dep);\r\n }\r\n\r\n visiting.delete(tableName);\r\n visited.add(tableName);\r\n\r\n // Add this table after its dependencies\r\n // Recursive CTEs go to recursiveResult, others to nonRecursiveResult\r\n if (recursiveCTEs.has(tableName)) {\r\n recursiveResult.push(tableMap.get(tableName)!);\r\n } else {\r\n nonRecursiveResult.push(tableMap.get(tableName)!);\r\n }\r\n };\r\n\r\n // Process all tables\r\n for (const table of tables) {\r\n const tableName = table.aliasExpression.table.name;\r\n if (!visited.has(tableName)) {\r\n visit(tableName);\r\n }\r\n }\r\n\r\n // Combine the results: recursive CTEs first, then non-recursive CTEs\r\n return [...recursiveResult, ...nonRecursiveResult];\r\n }\r\n}\r\n", "import { CommonTable, WithClause } from \"../models/Clause\";\r\nimport { BinarySelectQuery, SelectQuery, SimpleSelectQuery, ValuesQuery } from \"../models/SelectQuery\";\r\nimport { CTECollector } from \"./CTECollector\";\r\nimport { CTEBuilder } from \"./CTEBuilder\";\r\n\r\n/**\r\n * CTEInjector accepts a SelectQuery object and an array of CommonTables,\r\n * and inserts Common Table Expressions into the query.\r\n * For BinarySelectQuery, CTEs are inserted into the left query.\r\n * \r\n * Uses CTENameConflictResolver to resolve naming conflicts between CTEs.\r\n */\r\nexport class CTEInjector {\r\n private nameConflictResolver: CTEBuilder;\r\n private cteCollector: CTECollector;\r\n\r\n constructor() {\r\n this.nameConflictResolver = new CTEBuilder();\r\n this.cteCollector = new CTECollector();\r\n }\r\n\r\n /**\r\n * Inserts Common Table Expressions into a SelectQuery object.\r\n * \r\n * @param query The query to inject CTEs into\r\n * @param commonTables Array of CommonTables to be inserted\r\n * @returns A new query with the injected CTEs\r\n */\r\n public inject(query: SelectQuery, commonTables: CommonTable[]): SelectQuery {\r\n // If the array is empty, return the query as is\r\n if (commonTables.length === 0) {\r\n return query;\r\n }\r\n\r\n // Collect CTEs from the query\r\n commonTables.push(...this.cteCollector.collect(query));\r\n\r\n // Use CTENameConflictResolver to resolve duplicates and sort in appropriate order\r\n const resolvedWithCaluse = this.nameConflictResolver.build(commonTables);\r\n\r\n // Process based on query type\r\n if (query instanceof SimpleSelectQuery) {\r\n return this.injectIntoSimpleQuery(query, resolvedWithCaluse);\r\n } else if (query instanceof BinarySelectQuery) {\r\n return this.injectIntoBinaryQuery(query, resolvedWithCaluse);\r\n }\r\n\r\n // Unsupported query type\r\n throw new Error(\"Unsupported query type\");\r\n }\r\n\r\n /**\r\n * Inserts Common Table Expressions into a SimpleSelectQuery.\r\n * \r\n * @param query The SimpleSelectQuery to inject CTEs into\r\n * @param commonTables Array of CommonTables to be inserted\r\n * @param needRecursive Boolean indicating if recursive WITH clause is needed\r\n * @returns A new SimpleSelectQuery with the injected CTEs\r\n */\r\n private injectIntoSimpleQuery(query: SimpleSelectQuery, withClause: WithClause): SimpleSelectQuery {\r\n if (query.withClause) {\r\n throw new Error(\"The query already has a WITH clause. Please remove it before injecting new CTEs.\");\r\n }\r\n // If the query doesn't have a WITH clause, set the new one\r\n query.withClause = withClause;\r\n return query;\r\n }\r\n\r\n /**\r\n * Inserts Common Table Expressions into the left query of a BinarySelectQuery.\r\n * \r\n * @param query The BinarySelectQuery to inject CTEs into\r\n * @param commonTables Array of CommonTables to be inserted\r\n * @param needRecursive Boolean indicating if recursive WITH clause is needed\r\n * @returns A new BinarySelectQuery with the injected CTEs\r\n */\r\n private injectIntoBinaryQuery(query: BinarySelectQuery, withClause: WithClause): BinarySelectQuery {\r\n // Insert CTEs into the left query\r\n if (query.left instanceof SimpleSelectQuery) {\r\n this.injectIntoSimpleQuery(query.left, withClause);\r\n return query;\r\n } else if (query.left instanceof BinarySelectQuery) {\r\n this.injectIntoBinaryQuery(query.left, withClause);\r\n return query;\r\n }\r\n throw new Error(\"Unsupported query type for BinarySelectQuery left side\");\r\n }\r\n}\r\n", "import { CommonTable, WithClause } from \"../models/Clause\";\r\nimport { BinarySelectQuery, SelectQuery, SimpleSelectQuery, ValuesQuery } from \"../models/SelectQuery\";\r\nimport { CTECollector } from \"./CTECollector\";\r\nimport { TableSourceCollector } from \"./TableSourceCollector\";\r\nimport { CTEDisabler } from \"./CTEDisabler\";\r\nimport { Formatter } from \"./Formatter\";\r\nimport { CTEBuilder } from \"./CTEBuilder\";\r\nimport { CTEInjector } from \"./CTEInjector\";\r\n\r\n/**\r\n * CTENormalizer is responsible for normalizing Common Table Expressions (CTEs) within SQL queries.\r\n * It collects all CTEs from various parts of the query and consolidates them into a single WITH clause\r\n * at the root level of the query.\r\n * \r\n * This implementation uses:\r\n * 1. CommonTableCollector - to gather all CTEs from the query structure\r\n * 2. WithClauseDisabler - to remove all original WITH clauses from the query\r\n * 3. CTENameConflictResolver - to resolve name conflicts among CTEs and sort them properly\r\n */\r\nexport class CTENormalizer {\r\n /**\r\n * Private constructor to prevent instantiation of this utility class.\r\n */\r\n private constructor() {\r\n // This class is not meant to be instantiated.\r\n }\r\n /**\r\n * Normalizes a SQL query by consolidating all CTEs into a single WITH clause\r\n * at the root level of the query.\r\n * \r\n * @param query The query to normalize\r\n * @returns A new normalized query with all CTEs at the root level\r\n */\r\n public static normalize(query: SelectQuery): SelectQuery {\r\n // No need to normalize if the query doesn't have any CTEs\r\n const cteCollector = new CTECollector();\r\n const allCommonTables = cteCollector.collect(query);\r\n\r\n if (allCommonTables.length === 0) {\r\n return query;\r\n }\r\n\r\n // Remove all WITH clauses from the original query\r\n const cteDisabler = new CTEDisabler();\r\n cteDisabler.execute(query);\r\n\r\n const injector = new CTEInjector();\r\n return injector.inject(query, allCommonTables);\r\n }\r\n}", "/**\r\n * Enum for duplicate detection modes in SelectableColumnCollector.\r\n * Determines how duplicates are identified during column collection.\r\n */\r\nexport enum DuplicateDetectionMode {\r\n /**\r\n * Detect duplicates based only on column names.\r\n * This mode ignores the table name, so columns with the same name\r\n * from different tables are considered duplicates.\r\n */\r\n ColumnNameOnly = 'columnNameOnly',\r\n /**\r\n * Detect duplicates based on both table and column names.\r\n * This mode ensures that columns with the same name from different\r\n * tables are treated as distinct.\r\n */\r\n FullName = 'fullName',\r\n}\r\nimport { CommonTable, ForClause, FromClause, GroupByClause, HavingClause, LimitClause, OrderByClause, SelectClause, WhereClause, WindowFrameClause, WindowsClause, JoinClause, JoinOnClause, JoinUsingClause, TableSource, SubQuerySource, SourceExpression, SelectItem, PartitionByClause, FetchClause, OffsetClause } from \"../models/Clause\";\r\nimport { SimpleSelectQuery, BinarySelectQuery } from \"../models/SelectQuery\";\r\nimport { SqlComponent, SqlComponentVisitor } from \"../models/SqlComponent\";\r\nimport { ArrayExpression, ArrayQueryExpression, BetweenExpression, BinaryExpression, CaseExpression, CastExpression, ColumnReference, FunctionCall, InlineQuery, ParenExpression, UnaryExpression, ValueComponent, ValueList, WindowFrameExpression } from \"../models/ValueComponent\";\r\nimport { CTECollector } from \"./CTECollector\";\r\nimport { SelectValueCollector } from \"./SelectValueCollector\";\r\nimport { TableColumnResolver } from \"./TableColumnResolver\";\r\n\r\n/**\r\n * A visitor that collects all ColumnReference instances from SimpleSelectQuery structures.\r\n * This visitor scans through all clauses and collects all unique ColumnReference objects.\r\n * It does not scan Common Table Expressions (CTEs) or subqueries.\r\n * \r\n * IMPORTANT: This collector only supports SimpleSelectQuery. BinarySelectQuery \r\n * (UNION/INTERSECT/EXCEPT) will throw an error and should be decomposed into \r\n * individual SimpleSelectQuery branches before using this collector.\r\n * \r\n * Behavioral notes:\r\n * - Only collects column references to tables defined in the root FROM/JOIN clauses\r\n * - For aliased columns (e.g., 'title as name'), collects both the original column \r\n * reference ('title') AND the alias ('name') to enable complete dependency tracking\r\n * \r\n * Use cases:\r\n * - Dependency analysis and schema migration tools\r\n * - Column usage tracking within individual SELECT branches\r\n * - Security analysis for column-level access control\r\n */\r\nexport class SelectableColumnCollector implements SqlComponentVisitor<void> {\r\n private handlers: Map<symbol, (arg: any) => void>;\r\n private selectValues: { name: string, value: ValueComponent }[] = [];\r\n private visitedNodes: Set<SqlComponent> = new Set();\r\n private isRootVisit: boolean = true;\r\n private tableColumnResolver: TableColumnResolver | null = null;\r\n private commonTableCollector: CTECollector;\r\n private commonTables: CommonTable[] = [];\r\n private includeWildCard: boolean; // This option controls whether wildcard columns are included in the collection.\r\n private duplicateDetection: DuplicateDetectionMode;\r\n private options: { ignoreCaseAndUnderscore?: boolean };\r\n\r\n /**\r\n * Creates a new instance of SelectableColumnCollector.\r\n *\r\n * @param {TableColumnResolver | null} [tableColumnResolver=null] - The resolver used to resolve column references to their respective tables.\r\n * @param {boolean} [includeWildCard=false] - If true, wildcard columns (e.g., `*`) are included in the collection.\r\n * @param {DuplicateDetectionMode} [duplicateDetection=DuplicateDetectionMode.ColumnNameOnly] - Specifies the duplicate detection mode: 'columnNameOnly' (default, only column name is used), or 'fullName' (table name + column name).\r\n * @param {Object} [options={}] - Additional options for the collector.\r\n * @param {boolean} [options.ignoreCaseAndUnderscore=false] - If true, column names are compared without considering case and underscores.\r\n */\r\n constructor(\r\n tableColumnResolver?: TableColumnResolver | null,\r\n includeWildCard: boolean = false,\r\n duplicateDetection: DuplicateDetectionMode = DuplicateDetectionMode.ColumnNameOnly,\r\n options?: { ignoreCaseAndUnderscore?: boolean }\r\n ) {\r\n this.tableColumnResolver = tableColumnResolver ?? null;\r\n this.includeWildCard = includeWildCard;\r\n this.commonTableCollector = new CTECollector();\r\n this.commonTables = [];\r\n this.duplicateDetection = duplicateDetection;\r\n this.options = options || {};\r\n this.handlers = new Map<symbol, (arg: any) => void>();\r\n\r\n // Main entry point for SimpleSelectQuery only\r\n this.handlers.set(SimpleSelectQuery.kind, (expr) => this.visitSimpleSelectQuery(expr as SimpleSelectQuery));\r\n // NOTE: BinarySelectQuery is NOT supported - it should be decomposed before using this collector\r\n\r\n // Handlers for each clause type that might contain column references\r\n this.handlers.set(SelectClause.kind, (expr) => this.visitSelectClause(expr as SelectClause));\r\n this.handlers.set(FromClause.kind, (expr) => this.visitFromClause(expr as FromClause));\r\n this.handlers.set(WhereClause.kind, (expr) => this.visitWhereClause(expr as WhereClause));\r\n this.handlers.set(GroupByClause.kind, (expr) => this.visitGroupByClause(expr as GroupByClause));\r\n this.handlers.set(HavingClause.kind, (expr) => this.visitHavingClause(expr as HavingClause));\r\n this.handlers.set(OrderByClause.kind, (expr) => this.visitOrderByClause(expr as OrderByClause));\r\n this.handlers.set(WindowFrameClause.kind, (expr) => this.visitWindowFrameClause(expr as WindowFrameClause));\r\n this.handlers.set(LimitClause.kind, (expr) => this.visitLimitClause(expr as LimitClause));\r\n this.handlers.set(OffsetClause.kind, (expr) => this.offsetClause(expr as OffsetClause));\r\n this.handlers.set(FetchClause.kind, (expr) => this.visitFetchClause(expr as FetchClause));\r\n\r\n // Add handlers for JOIN conditions\r\n this.handlers.set(JoinOnClause.kind, (expr) => this.visitJoinOnClause(expr as JoinOnClause));\r\n this.handlers.set(JoinUsingClause.kind, (expr) => this.visitJoinUsingClause(expr as JoinUsingClause));\r\n\r\n // For value components that might contain column references\r\n this.handlers.set(ColumnReference.kind, (expr) => this.visitColumnReference(expr as ColumnReference));\r\n this.handlers.set(BinaryExpression.kind, (expr) => this.visitBinaryExpression(expr as BinaryExpression));\r\n this.handlers.set(UnaryExpression.kind, (expr) => this.visitUnaryExpression(expr as UnaryExpression));\r\n this.handlers.set(FunctionCall.kind, (expr) => this.visitFunctionCall(expr as FunctionCall));\r\n this.handlers.set(ParenExpression.kind, (expr) => this.visitParenExpression(expr as ParenExpression));\r\n this.handlers.set(CaseExpression.kind, (expr) => this.visitCaseExpression(expr as CaseExpression));\r\n this.handlers.set(CastExpression.kind, (expr) => this.visitCastExpression(expr as CastExpression));\r\n this.handlers.set(BetweenExpression.kind, (expr) => this.visitBetweenExpression(expr as BetweenExpression));\r\n this.handlers.set(ArrayExpression.kind, (expr) => this.visitArrayExpression(expr as ArrayExpression));\r\n this.handlers.set(ArrayQueryExpression.kind, (expr) => this.visitArrayQueryExpression(expr as ArrayQueryExpression));\r\n this.handlers.set(ValueList.kind, (expr) => this.visitValueList(expr as ValueList));\r\n this.handlers.set(WindowFrameClause.kind, (expr) => this.visitWindowFrameClause(expr as WindowFrameClause));\r\n this.handlers.set(WindowFrameExpression.kind, (expr) => this.visitWindowFrameExpression(expr as WindowFrameExpression));\r\n this.handlers.set(PartitionByClause.kind, (expr) => this.visitPartitionByClause(expr as PartitionByClause));\r\n }\r\n\r\n public getValues(): { name: string, value: ValueComponent }[] {\r\n return this.selectValues;\r\n }\r\n\r\n public collect(arg: SqlComponent): { name: string, value: ValueComponent }[] {\r\n // Visit the component and return the collected select items\r\n this.visit(arg);\r\n const items = this.getValues();\r\n this.reset(); // Reset after collection\r\n return items;\r\n }\r\n\r\n /**\r\n * Reset the collection of ColumnReferences\r\n */\r\n private reset(): void {\r\n this.selectValues = []\r\n this.visitedNodes.clear();\r\n this.commonTables = [];\r\n }\r\n\r\n /**\r\n * Add a select value as unique, according to the duplicate detection option.\r\n * If duplicateDetection is 'columnNameOnly', only column name is checked.\r\n * If duplicateDetection is 'fullName', both table and column name are checked.\r\n */\r\n private addSelectValueAsUnique(name: string, value: ValueComponent): void {\r\n if (this.duplicateDetection === DuplicateDetectionMode.ColumnNameOnly) {\r\n if (!this.selectValues.some(item => item.name === name)) {\r\n this.selectValues.push({ name, value });\r\n }\r\n } else if (this.duplicateDetection === DuplicateDetectionMode.FullName) {\r\n // Try to get table name from ValueComponent if possible\r\n let tableName = '';\r\n if (value && typeof (value as any).getNamespace === 'function') {\r\n tableName = (value as any).getNamespace() || '';\r\n }\r\n const key = tableName ? tableName + '.' + name : name;\r\n if (!this.selectValues.some(item => {\r\n let itemTable = '';\r\n if (item.value && typeof (item.value as any).getNamespace === 'function') {\r\n itemTable = (item.value as any).getNamespace() || '';\r\n }\r\n const itemKey = itemTable ? itemTable + '.' + item.name : item.name;\r\n return itemKey === key;\r\n })) {\r\n this.selectValues.push({ name, value });\r\n }\r\n }\r\n }\r\n\r\n /**\r\n * Main entry point for the visitor pattern.\r\n * Implements the shallow visit pattern to distinguish between root and recursive visits.\r\n */\r\n public visit(arg: SqlComponent): void {\r\n // If not a root visit, just visit the node and return\r\n if (!this.isRootVisit) {\r\n this.visitNode(arg);\r\n return;\r\n }\r\n\r\n if (!(arg instanceof SimpleSelectQuery)) {\r\n throw new Error(\"Root visit requires a SimpleSelectQuery. Decompose compound queries before collecting columns.\");\r\n }\r\n\r\n // If this is a root visit, we need to reset the state\r\n this.reset();\r\n this.isRootVisit = false;\r\n this.commonTables = this.commonTableCollector.collect(arg);\r\n\r\n try {\r\n this.visitNode(arg);\r\n } finally {\r\n // Regardless of success or failure, reset the root visit flag\r\n this.isRootVisit = true;\r\n }\r\n }\r\n\r\n /**\r\n * Internal visit method used for all nodes.\r\n * This separates the visit flag management from the actual node visitation logic.\r\n */\r\n private visitNode(arg: SqlComponent): void {\r\n // Skip if we've already visited this node to prevent infinite recursion\r\n if (this.visitedNodes.has(arg)) {\r\n return;\r\n }\r\n\r\n // Mark as visited\r\n this.visitedNodes.add(arg);\r\n\r\n const handler = this.handlers.get(arg.getKind());\r\n if (handler) {\r\n handler(arg);\r\n return;\r\n }\r\n\r\n // For any other component types, we don't need to do anything\r\n }\r\n\r\n /**\r\n * Process a SimpleSelectQuery to collect ColumnReferences from all its clauses\r\n */\r\n private visitSimpleSelectQuery(query: SimpleSelectQuery): void {\r\n // Visit all clauses that might contain column references\r\n if (query.selectClause) {\r\n query.selectClause.accept(this);\r\n }\r\n\r\n if (query.fromClause) {\r\n query.fromClause.accept(this);\r\n }\r\n\r\n if (query.whereClause) {\r\n query.whereClause.accept(this);\r\n }\r\n\r\n if (query.groupByClause) {\r\n query.groupByClause.accept(this);\r\n }\r\n\r\n if (query.havingClause) {\r\n query.havingClause.accept(this);\r\n }\r\n\r\n if (query.windowClause) {\r\n for (const win of query.windowClause.windows) {\r\n win.accept(this);\r\n }\r\n }\r\n\r\n if (query.orderByClause) {\r\n query.orderByClause.accept(this);\r\n }\r\n\r\n if (query.limitClause) {\r\n query.limitClause.accept(this);\r\n }\r\n\r\n if (query.offsetClause) {\r\n query.offsetClause.accept(this);\r\n }\r\n\r\n if (query.fetchClause) {\r\n query.fetchClause.accept(this);\r\n }\r\n if (query.forClause) {\r\n query.forClause.accept(this);\r\n }\r\n // Explicitly NOT processing query.WithClause to avoid scanning CTEs\r\n }\r\n\r\n // Clause handlers\r\n private visitSelectClause(clause: SelectClause): void {\r\n for (const item of clause.items) {\r\n if (item.identifier) {\r\n this.addSelectValueAsUnique(item.identifier.name, item.value);\r\n }\r\n item.value.accept(this);\r\n }\r\n }\r\n\r\n private visitFromClause(clause: FromClause): void {\r\n // import source values\r\n const collector = new SelectValueCollector(this.tableColumnResolver, this.commonTables);\r\n const sourceValues = collector.collect(clause);\r\n for (const item of sourceValues) {\r\n // Add the select value as unique to avoid duplicates\r\n this.addSelectValueAsUnique(item.name, item.value);\r\n }\r\n\r\n if (clause.joins) {\r\n for (const join of clause.joins) {\r\n if (join.condition) {\r\n join.condition.accept(this);\r\n }\r\n }\r\n }\r\n }\r\n\r\n private visitWhereClause(clause: WhereClause): void {\r\n if (clause.condition) {\r\n clause.condition.accept(this);\r\n }\r\n }\r\n\r\n private visitGroupByClause(clause: GroupByClause): void {\r\n if (clause.grouping) {\r\n for (const item of clause.grouping) {\r\n item.accept(this);\r\n }\r\n }\r\n }\r\n\r\n private visitHavingClause(clause: HavingClause): void {\r\n if (clause.condition) {\r\n clause.condition.accept(this);\r\n }\r\n }\r\n\r\n private visitOrderByClause(clause: OrderByClause): void {\r\n if (clause.order) {\r\n for (const item of clause.order) {\r\n item.accept(this);\r\n }\r\n }\r\n }\r\n\r\n private visitWindowFrameClause(clause: WindowFrameClause): void {\r\n clause.expression.accept(this);\r\n }\r\n\r\n private visitWindowFrameExpression(expr: WindowFrameExpression): void {\r\n if (expr.partition) {\r\n expr.partition.accept(this);\r\n }\r\n if (expr.order) {\r\n expr.order.accept(this);\r\n }\r\n if (expr.frameSpec) {\r\n expr.frameSpec.accept(this);\r\n }\r\n }\r\n\r\n private visitLimitClause(clause: LimitClause): void {\r\n if (clause.value) {\r\n clause.value.accept(this);\r\n }\r\n }\r\n\r\n private offsetClause(clause: OffsetClause): void {\r\n if (clause.value) {\r\n clause.value.accept(this);\r\n }\r\n }\r\n\r\n private visitFetchClause(clause: FetchClause): void {\r\n if (clause.expression) {\r\n clause.expression.accept(this);\r\n }\r\n }\r\n\r\n private visitJoinOnClause(joinOnClause: JoinOnClause): void {\r\n // Visit the join condition\r\n if (joinOnClause.condition) {\r\n joinOnClause.condition.accept(this);\r\n }\r\n }\r\n\r\n private visitJoinUsingClause(joinUsingClause: JoinUsingClause): void {\r\n // Visit the columns in the USING clause\r\n if (joinUsingClause.condition) {\r\n joinUsingClause.condition.accept(this);\r\n }\r\n }\r\n\r\n // Value component handlers\r\n private visitColumnReference(columnRef: ColumnReference): void {\r\n if (columnRef.column.name !== \"*\") {\r\n this.addSelectValueAsUnique(columnRef.column.name, columnRef);\r\n } else if (!this.includeWildCard) {\r\n return;\r\n } else {\r\n this.addSelectValueAsUnique(columnRef.column.name, columnRef);\r\n }\r\n }\r\n\r\n private visitBinaryExpression(expr: BinaryExpression): void {\r\n // Visit both sides of the expression\r\n if (expr.left) {\r\n expr.left.accept(this);\r\n }\r\n if (expr.right) {\r\n expr.right.accept(this);\r\n }\r\n }\r\n\r\n private visitUnaryExpression(expr: UnaryExpression): void {\r\n if (expr.expression) {\r\n expr.expression.accept(this);\r\n }\r\n }\r\n\r\n private visitFunctionCall(func: FunctionCall): void {\r\n if (func.argument) {\r\n func.argument.accept(this);\r\n }\r\n if (func.over) {\r\n func.over.accept(this);\r\n }\r\n }\r\n\r\n private visitParenExpression(expr: ParenExpression): void {\r\n if (expr.expression) {\r\n expr.expression.accept(this);\r\n }\r\n }\r\n\r\n private visitCaseExpression(expr: CaseExpression): void {\r\n if (expr.condition) {\r\n expr.condition.accept(this);\r\n }\r\n\r\n if (expr.switchCase) {\r\n expr.switchCase.accept(this);\r\n }\r\n }\r\n\r\n private visitCastExpression(expr: CastExpression): void {\r\n if (expr.input) {\r\n expr.input.accept(this);\r\n }\r\n }\r\n\r\n private visitBetweenExpression(expr: BetweenExpression): void {\r\n if (expr.expression) {\r\n expr.expression.accept(this);\r\n }\r\n\r\n if (expr.lower) {\r\n expr.lower.accept(this);\r\n }\r\n\r\n if (expr.upper) {\r\n expr.upper.accept(this);\r\n }\r\n }\r\n\r\n private visitArrayExpression(expr: ArrayExpression): void {\r\n if (expr.expression) {\r\n expr.expression.accept(this);\r\n }\r\n }\r\n\r\n private visitArrayQueryExpression(expr: ArrayQueryExpression): void {\r\n expr.query.accept(this);\r\n }\r\n\r\n private visitValueList(expr: ValueList): void {\r\n if (expr.values) {\r\n for (const value of expr.values) {\r\n value.accept(this);\r\n }\r\n }\r\n }\r\n\r\n private visitPartitionByClause(clause: PartitionByClause): void {\r\n clause.value.accept(this);\r\n }\r\n}", "import { FullNameParser } from \"./FullNameParser\";\r\nimport { FunctionSource, SourceComponent, SubQuerySource, TableSource } from \"../models/Clause\";\r\nimport { Lexeme, TokenType } from \"../models/Lexeme\";\r\nimport { SelectQueryParser } from \"./SelectQueryParser\";\r\nimport { SqlTokenizer } from \"./SqlTokenizer\";\r\nimport { ValueParser } from \"./ValueParser\";\r\n\r\nexport class SourceParser {\r\n // Parse SQL string to AST (was: parse)\r\n public static parse(query: string): SourceComponent {\r\n const tokenizer = new SqlTokenizer(query); // Initialize tokenizer\r\n const lexemes = tokenizer.readLexmes(); // Get tokens\r\n\r\n // Parse\r\n const result = this.parseFromLexeme(lexemes, 0);\r\n\r\n // Error if there are remaining tokens\r\n if (result.newIndex < lexemes.length) {\r\n throw new Error(`Syntax error: Unexpected token \"${lexemes[result.newIndex].value}\" at position ${result.newIndex}. The source component is complete but there are additional tokens.`);\r\n }\r\n\r\n return result.value;\r\n }\r\n\r\n /**\r\n * Parses only a TableSource from the given lexemes, regardless of the presence of parentheses after the identifier.\r\n * This method is specifically used for cases like INSERT queries (e.g., \"insert into table_name (col1, col2)\")\r\n * where a parenthesis immediately following the table name could otherwise be misinterpreted as a function call.\r\n * By using this method, the parser forcibly treats the source as a TableSource.\r\n *\r\n * @param lexemes The array of lexemes to parse.\r\n * @param index The starting index in the lexeme array.\r\n * @returns An object containing the parsed TableSource and the new index.\r\n */\r\n public static parseTableSourceFromLexemes(lexemes: Lexeme[], index: number): { value: SourceComponent; newIndex: number } {\r\n const fullNameResult = FullNameParser.parseFromLexeme(lexemes, index);\r\n return this.parseTableSource(fullNameResult);\r\n }\r\n\r\n // Parse from lexeme array (was: parse)\r\n public static parseFromLexeme(lexemes: Lexeme[], index: number): { value: SourceComponent; newIndex: number } {\r\n let idx = index;\r\n\r\n // Handle subquery\r\n if (idx < lexemes.length && (lexemes[idx].type & TokenType.OpenParen)) {\r\n return this.parseParenSource(lexemes, idx);\r\n }\r\n\r\n // Retrieve the full name only once and reuse the result\r\n const fullNameResult = FullNameParser.parseFromLexeme(lexemes, idx);\r\n\r\n // Handle function-based source (determine by lastTokenType)\r\n if (fullNameResult.lastTokenType & TokenType.Function) {\r\n // Also use fullNameResult as argument for parseFunctionSource\r\n return SourceParser.parseFunctionSource(lexemes, fullNameResult);\r\n }\r\n\r\n // Handle table source (regular table, potentially schema-qualified)\r\n return SourceParser.parseTableSource(fullNameResult);\r\n }\r\n\r\n private static parseTableSource(fullNameResult: { namespaces: string[] | null, name: any, newIndex: number }): { value: TableSource; newIndex: number } {\r\n const { namespaces, name, newIndex } = fullNameResult;\r\n const value = new TableSource(namespaces, name.name);\r\n return { value, newIndex };\r\n }\r\n\r\n private static parseFunctionSource(\r\n lexemes: Lexeme[],\r\n fullNameResult: { namespaces: string[] | null, name: any, newIndex: number }\r\n ): { value: FunctionSource; newIndex: number } {\r\n let idx = fullNameResult.newIndex;\r\n const { namespaces, name } = fullNameResult;\r\n\r\n const argument = ValueParser.parseArgument(TokenType.OpenParen, TokenType.CloseParen, lexemes, idx);\r\n idx = argument.newIndex;\r\n\r\n const functionName = name.name;\r\n const result = new FunctionSource({ namespaces: namespaces, name: functionName }, argument.value);\r\n return { value: result, newIndex: idx };\r\n }\r\n\r\n private static parseParenSource(lexemes: Lexeme[], index: number): { value: SourceComponent; newIndex: number } {\r\n let idx = index;\r\n // skip the open parenthesis\r\n idx++;\r\n if (idx >= lexemes.length) {\r\n throw new Error(`Syntax error: Unexpected end of input at position ${idx}. Expected a subquery or nested expression after opening parenthesis.`);\r\n }\r\n\r\n // Support both SELECT and VALUES in subqueries\r\n const keyword = lexemes[idx].value;\r\n if (keyword === \"select\" || keyword === \"values\" || keyword === \"with\") {\r\n const result = this.parseSubQuerySource(lexemes, idx);\r\n idx = result.newIndex;\r\n if (idx < lexemes.length && lexemes[idx].type == TokenType.CloseParen) {\r\n // skip the closing parenthesis\r\n idx++;\r\n } else {\r\n throw new Error(`Syntax error at position ${idx}: Missing closing parenthesis. Each opening parenthesis must have a matching closing parenthesis.`);\r\n }\r\n return { value: result.value, newIndex: idx };\r\n } else if (lexemes[idx].type == TokenType.OpenParen) {\r\n const result = this.parseParenSource(lexemes, idx);\r\n idx = result.newIndex;\r\n if (idx < lexemes.length && lexemes[idx].type == TokenType.CloseParen) {\r\n // skip the closing parenthesis\r\n idx++;\r\n } else {\r\n throw new Error(`Syntax error at position ${idx}: Missing closing parenthesis. Each opening parenthesis must have a matching closing parenthesis.`);\r\n }\r\n return { value: result.value, newIndex: idx };\r\n }\r\n\r\n throw new Error(`Syntax error at position ${idx}: Expected 'SELECT' keyword, 'VALUES' keyword, or opening parenthesis '(' but found \"${lexemes[idx].value}\".`);\r\n }\r\n\r\n private static parseSubQuerySource(lexemes: Lexeme[], index: number): { value: SubQuerySource; newIndex: number } {\r\n let idx = index;\r\n\r\n // Use the new parseFromLexeme method and destructure the result\r\n const { value: selectQuery, newIndex } = SelectQueryParser.parseFromLexeme(lexemes, idx);\r\n idx = newIndex;\r\n\r\n const subQuerySource = new SubQuerySource(selectQuery);\r\n return { value: subQuerySource, newIndex: idx };\r\n }\r\n}\r\n", "import { SelectQuery, SimpleSelectQuery, BinarySelectQuery, ValuesQuery } from \"../models/SelectQuery\";\r\nimport { CommonTable, SubQuerySource, TableSource, WithClause } from \"../models/Clause\";\r\nimport { SelectableColumnCollector } from \"./SelectableColumnCollector\";\r\nimport { CTECollector } from \"./CTECollector\";\r\n\r\n/**\r\n * UpstreamSelectQueryFinder searches upstream queries for the specified columns.\r\n * If a query (including its upstream CTEs or subqueries) contains all columns,\r\n * it returns the highest such SelectQuery. Otherwise, it searches downstream.\r\n * \r\n * For BinarySelectQuery (UNION/INTERSECT/EXCEPT), this finder processes each branch\r\n * independently, as SelectableColumnCollector is designed for SimpleSelectQuery only.\r\n * This approach ensures accurate column detection within individual SELECT branches\r\n * while maintaining compatibility with compound query structures.\r\n */\r\nexport class UpstreamSelectQueryFinder {\r\n private options: { ignoreCaseAndUnderscore?: boolean };\r\n private tableColumnResolver?: (tableName: string) => string[];\r\n private columnCollector: SelectableColumnCollector;\r\n\r\n constructor(tableColumnResolver?: (tableName: string) => string[], options?: { ignoreCaseAndUnderscore?: boolean }) {\r\n this.options = options || {};\r\n this.tableColumnResolver = tableColumnResolver;\r\n // Pass the tableColumnResolver instead of options to fix type mismatch.\r\n this.columnCollector = new SelectableColumnCollector(this.tableColumnResolver);\r\n }\r\n\r\n /**\r\n * Finds the highest SelectQuery containing all specified columns.\r\n * @param query The root SelectQuery to search.\r\n * @param columnNames A column name or array of column names to check for.\r\n * @returns An array of SelectQuery objects, or an empty array if not found.\r\n */\r\n public find(query: SelectQuery, columnNames: string | string[]): SimpleSelectQuery[] {\r\n // Normalize columnNames to array\r\n const namesArray = typeof columnNames === 'string' ? [columnNames] : columnNames;\r\n // Use CTECollector to collect CTEs from the root query only once and reuse\r\n const cteCollector = new CTECollector();\r\n const ctes = cteCollector.collect(query);\r\n const cteMap: Map<string, CommonTable> = new Map();\r\n for (const cte of ctes) {\r\n cteMap.set(cte.getSourceAliasName(), cte);\r\n }\r\n return this.findUpstream(query, namesArray, cteMap);\r\n }\r\n\r\n private handleTableSource(src: TableSource, columnNames: string[], cteMap: Map<string, CommonTable>): SimpleSelectQuery[] | null {\r\n // Handles the logic for TableSource in findUpstream\r\n const cte = cteMap.get(src.table.name);\r\n if (cte) {\r\n // Remove the current CTE name from the map to prevent infinite recursion\r\n const nextCteMap = new Map(cteMap);\r\n nextCteMap.delete(src.table.name);\r\n const result = this.findUpstream(cte.query, columnNames, nextCteMap);\r\n if (result.length === 0) {\r\n return null;\r\n }\r\n return result;\r\n }\r\n return null;\r\n }\r\n\r\n private handleSubQuerySource(src: SubQuerySource, columnNames: string[], cteMap: Map<string, CommonTable>): SimpleSelectQuery[] | null {\r\n // Handles the logic for SubQuerySource in findUpstream\r\n const result = this.findUpstream(src.query, columnNames, cteMap);\r\n if (result.length === 0) {\r\n return null;\r\n }\r\n return result;\r\n }\r\n\r\n /**\r\n * Processes all source branches in a FROM clause and checks if all upstream queries contain the specified columns.\r\n * Returns a flat array of SelectQuery if all branches are valid, otherwise null.\r\n */\r\n private processFromClauseBranches(\r\n fromClause: any,\r\n columnNames: string[],\r\n cteMap: Map<string, CommonTable>\r\n ): SimpleSelectQuery[] | null {\r\n const sources = fromClause.getSources();\r\n if (sources.length === 0) return null;\r\n\r\n let allBranchResults: SimpleSelectQuery[][] = [];\r\n let allBranchesOk = true;\r\n let validBranchCount = 0; // Count only filterable branches\r\n\r\n for (const sourceExpr of sources) {\r\n const src = sourceExpr.datasource;\r\n let branchResult: SimpleSelectQuery[] | null = null;\r\n if (src instanceof TableSource) {\r\n branchResult = this.handleTableSource(src, columnNames, cteMap);\r\n validBranchCount++;\r\n } else if (src instanceof SubQuerySource) {\r\n branchResult = this.handleSubQuerySource(src, columnNames, cteMap);\r\n validBranchCount++;\r\n } else if (src instanceof ValuesQuery) {\r\n // Skip ValuesQuery: not filterable, do not count as a valid branch\r\n continue;\r\n } else {\r\n allBranchesOk = false;\r\n break;\r\n }\r\n\r\n // If the branch result is null, \r\n // it means it didn't find the required columns in this branch\r\n if (branchResult === null) {\r\n allBranchesOk = false;\r\n break;\r\n }\r\n allBranchResults.push(branchResult);\r\n }\r\n\r\n // Check if all valid (filterable) branches are valid and contain the required columns\r\n if (allBranchesOk && allBranchResults.length === validBranchCount) {\r\n return allBranchResults.flat();\r\n }\r\n return null;\r\n }\r\n\r\n private findUpstream(query: SelectQuery, columnNames: string[], cteMap: Map<string, CommonTable>): SimpleSelectQuery[] {\r\n if (query instanceof SimpleSelectQuery) {\r\n // First, try to find upstream queries from FROM clause\r\n const fromClause = query.fromClause;\r\n if (fromClause) {\r\n const branchResult = this.processFromClauseBranches(fromClause, columnNames, cteMap);\r\n if (branchResult && branchResult.length > 0) {\r\n return branchResult;\r\n }\r\n }\r\n\r\n // If no upstream queries found, check if current query contains all columns\r\n const columns = this.columnCollector.collect(query).map(col => col.name);\r\n // Collect columns defined in CTEs as well\r\n const cteColumns = this.collectCTEColumns(query, cteMap);\r\n const allColumns = [...columns, ...cteColumns];\r\n \r\n const normalize = (s: string) =>\r\n this.options.ignoreCaseAndUnderscore ? s.toLowerCase().replace(/_/g, '') : s;\r\n // Normalize both the columns and the required names for comparison.\r\n const hasAll = columnNames.every(name => allColumns.some(col => normalize(col) === normalize(name)));\r\n \r\n if (hasAll) {\r\n return [query];\r\n }\r\n \r\n return [];\r\n } else if (query instanceof BinarySelectQuery) {\r\n // Process BinarySelectQuery by decomposing into individual branches.\r\n // SelectableColumnCollector is designed for SimpleSelectQuery only,\r\n // so we handle UNION/INTERSECT/EXCEPT by processing left and right branches separately.\r\n const left = this.findUpstream(query.left, columnNames, cteMap);\r\n const right = this.findUpstream(query.right, columnNames, cteMap);\r\n return [...left, ...right];\r\n }\r\n return [];\r\n }\r\n\r\n /**\r\n * Collects columns defined in CTEs\r\n */\r\n private collectCTEColumns(query: SimpleSelectQuery, cteMap: Map<string, CommonTable>): string[] {\r\n const cteColumns: string[] = [];\r\n \r\n // If WITH clause exists, collect columns defined in CTEs\r\n if (query.withClause) {\r\n for (const cte of query.withClause.tables) {\r\n // Collect columns from CTE query\r\n const columns = this.collectColumnsFromSelectQuery(cte.query);\r\n cteColumns.push(...columns);\r\n }\r\n }\r\n \r\n return cteColumns;\r\n }\r\n\r\n /**\r\n * Recursively collects columns from SelectQuery\r\n */\r\n private collectColumnsFromSelectQuery(query: SelectQuery): string[] {\r\n if (query instanceof SimpleSelectQuery) {\r\n try {\r\n return this.columnCollector.collect(query).map(col => col.name);\r\n } catch (error) {\r\n // Return empty array if SelectableColumnCollector fails\r\n console.warn('Failed to collect columns from SimpleSelectQuery:', error);\r\n return [];\r\n }\r\n } else if (query instanceof BinarySelectQuery) {\r\n // For BinarySelectQuery (UNION etc.), get column names from the left query\r\n // In UNION statements, left and right must have matching column count/types, so left side is sufficient\r\n return this.collectColumnsFromSelectQuery(query.left);\r\n }\r\n return [];\r\n }\r\n}\r\n", "import { SourceAliasExpression } from \"../models/Clause\";\r\nimport { Lexeme, TokenType } from \"../models/Lexeme\";\r\n\r\n\r\nexport class SourceAliasExpressionParser {\r\n // Parse from lexeme array (was: parse)\r\n public static parseFromLexeme(lexemes: Lexeme[], index: number): { value: SourceAliasExpression; newIndex: number; } {\r\n let idx = index;\r\n\r\n // If there is a column alias, it may be detected as a function, so functions are also processed.\r\n if (idx < lexemes.length && ((lexemes[idx].type & TokenType.Identifier) || (lexemes[idx].type & TokenType.Function))) {\r\n // Check for alias\r\n const table = lexemes[idx].value;\r\n idx++;\r\n\r\n if (idx < lexemes.length && (lexemes[idx].type & TokenType.OpenParen)) {\r\n // Check for column alias\r\n const columns: string[] = [];\r\n\r\n // Skip the open parenthesis\r\n idx++;\r\n\r\n while (idx < lexemes.length && (lexemes[idx].type & TokenType.Identifier)) {\r\n columns.push(lexemes[idx].value);\r\n idx++;\r\n if (idx < lexemes.length && (lexemes[idx].type & TokenType.Comma)) {\r\n idx++;\r\n } else {\r\n break; // Exit loop if not a comma\r\n }\r\n }\r\n\r\n if (lexemes[idx].type & TokenType.CloseParen) {\r\n // Skip the closing parenthesis\r\n idx++;\r\n } else {\r\n throw new Error(`Syntax error at position ${idx}: Missing closing parenthesis ')' for column alias list. Each opening parenthesis must have a matching closing parenthesis.`);\r\n }\r\n if (columns.length === 0) {\r\n throw new Error(`Syntax error at position ${index}: No column aliases found. Column alias declarations must contain at least one column name.`);\r\n }\r\n\r\n return { value: new SourceAliasExpression(table, columns), newIndex: idx };\r\n }\r\n\r\n return { value: new SourceAliasExpression(table, null), newIndex: idx };\r\n }\r\n\r\n throw new Error(`Syntax error at position ${index}: Expected an identifier for table alias but found \"${lexemes[index]?.value || 'end of input'}\".`);\r\n }\r\n}\r\n", "import { SourceAliasExpression, SourceExpression, TableSource } from \"../models/Clause\";\r\nimport { SqlTokenizer } from \"./SqlTokenizer\";\r\nimport { Lexeme, TokenType } from \"../models/Lexeme\";\r\nimport { SourceParser } from \"./SourceParser\";\r\nimport { SourceAliasExpressionParser } from \"./SourceAliasExpressionParser\";\r\n\r\nexport class SourceExpressionParser {\r\n /**\r\n * Parse SQL string to SourceExpression (e.g. \"table\", \"table as t\", \"schema.table t\")\r\n */\r\n public static parse(query: string): SourceExpression {\r\n const tokenizer = new SqlTokenizer(query);\r\n const lexemes = tokenizer.readLexmes();\r\n const result = this.parseFromLexeme(lexemes, 0);\r\n if (result.newIndex < lexemes.length) {\r\n throw new Error(`Syntax error: Unexpected token \"${lexemes[result.newIndex].value}\" at position ${result.newIndex}. The source expression is complete but there are additional tokens.`);\r\n }\r\n return result.value;\r\n }\r\n\r\n public static parseTableSourceFromLexemes(lexemes: Lexeme[], index: number): { value: SourceExpression; newIndex: number } {\r\n const result = SourceParser.parseTableSourceFromLexemes(lexemes, index);\r\n // No alias for table source\r\n const sourceExpr = new SourceExpression(result.value, null);\r\n return { value: sourceExpr, newIndex: result.newIndex };\r\n }\r\n\r\n // Parse from lexeme array (was: parse)\r\n public static parseFromLexeme(lexemes: Lexeme[], index: number): { value: SourceExpression; newIndex: number; } {\r\n let idx = index;\r\n\r\n const sourceResult = SourceParser.parseFromLexeme(lexemes, idx);\r\n idx = sourceResult.newIndex;\r\n\r\n if (idx < lexemes.length) {\r\n if (lexemes[idx].value === \"as\") {\r\n idx++;\r\n const aliasResult = SourceAliasExpressionParser.parseFromLexeme(lexemes, idx);\r\n idx = aliasResult.newIndex;\r\n const sourceExpr = new SourceExpression(sourceResult.value, aliasResult.value);\r\n return { value: sourceExpr, newIndex: idx };\r\n }\r\n\r\n /**\r\n * Explanation:\r\n * Source aliases are typically identified as TokenType.Identifier.\r\n * However, when the 'AS' keyword is omitted and column alias names are specified,\r\n * they may sometimes be classified as TokenType.Function.\r\n * Since the TokenReader's responsibility is to perform coarse-grained classification,\r\n * the parser must interpret subsequent 'Function' tokens as source alias expressions\r\n * when they follow a source definition.\r\n * Example:\r\n * SQL: select t.* from (values(1)) t(id)\r\n * Explanation: The alias 't' and its column alias 'id' are parsed as a source alias expression.\r\n */\r\n if (idx < lexemes.length && this.isTokenTypeAliasCandidate(lexemes[idx].type)) {\r\n const aliasResult = SourceAliasExpressionParser.parseFromLexeme(lexemes, idx);\r\n idx = aliasResult.newIndex;\r\n const sourceExpr = new SourceExpression(sourceResult.value, aliasResult.value);\r\n return { value: sourceExpr, newIndex: idx };\r\n }\r\n }\r\n\r\n // no alias\r\n const expr = new SourceExpression(sourceResult.value, null);\r\n return { value: expr, newIndex: idx };\r\n }\r\n\r\n private static isTokenTypeAliasCandidate(type: number): boolean {\r\n return (type & TokenType.Identifier) !== 0 || (type & TokenType.Function) !== 0;\r\n }\r\n}\r\n", "import { SetClause, SetClauseItem, FromClause, WhereClause, SelectClause, SelectItem, SourceAliasExpression, SourceExpression, SubQuerySource, WithClause, TableSource, UpdateClause, InsertClause } from '../models/Clause';\r\nimport { UpdateQuery } from '../models/UpdateQuery';\r\nimport { BinaryExpression, ColumnReference } from '../models/ValueComponent';\r\nimport { SelectValueCollector } from './SelectValueCollector';\r\nimport { BinarySelectQuery, SelectQuery, SimpleSelectQuery, ValuesQuery } from \"../models/SelectQuery\";\r\nimport { CTECollector } from \"./CTECollector\";\r\nimport { CTENormalizer } from \"./CTENormalizer\";\r\nimport { CreateTableQuery } from \"../models/CreateTableQuery\";\r\nimport { InsertQuery } from \"../models/InsertQuery\";\r\nimport { CTEDisabler } from './CTEDisabler';\r\nimport { SourceExpressionParser } from '../parsers/SourceExpressionParser';\r\n\r\n/**\r\n * QueryBuilder provides static methods to build or convert various SQL query objects.\r\n */\r\nexport class QueryBuilder {\r\n /**\r\n * Builds a BinarySelectQuery by combining an array of SelectQuery using the specified operator.\r\n * Throws if less than two queries are provided.\r\n * @param queries Array of SelectQuery to combine\r\n * @param operator SQL operator to use (e.g. 'union', 'union all', 'intersect', 'except')\r\n * @returns BinarySelectQuery\r\n */\r\n public static buildBinaryQuery(queries: SelectQuery[], operator: string): BinarySelectQuery {\r\n if (!queries || queries.length === 0) {\r\n throw new Error(\"No queries provided to combine.\");\r\n }\r\n if (queries.length === 1) {\r\n throw new Error(\"At least two queries are required to create a BinarySelectQuery.\");\r\n }\r\n\r\n // Always create a new BinarySelectQuery instance (never mutate input)\r\n const wrap = (q: SelectQuery) => q instanceof ValuesQuery ? QueryBuilder.buildSimpleQuery(q) : q;\r\n let result: BinarySelectQuery = new BinarySelectQuery(wrap(queries[0]), operator, wrap(queries[1]));\r\n CTENormalizer.normalize(result);\r\n\r\n for (let i = 2; i < queries.length; i++) {\r\n result.appendSelectQuery(operator, wrap(queries[i]));\r\n }\r\n\r\n return result;\r\n }\r\n\r\n private constructor() {\r\n // This class is not meant to be instantiated.\r\n }\r\n\r\n /**\r\n * Converts a SELECT query to a standard SimpleSelectQuery form.\r\n * @param query The query to convert\r\n * @returns A SimpleSelectQuery\r\n */\r\n public static buildSimpleQuery(query: SelectQuery): SimpleSelectQuery {\r\n if (query instanceof SimpleSelectQuery) {\r\n return query;\r\n }\r\n else if (query instanceof BinarySelectQuery) {\r\n return QueryBuilder.buildSimpleBinaryQuery(query);\r\n }\r\n else if (query instanceof ValuesQuery) {\r\n return QueryBuilder.buildSimpleValuesQuery(query);\r\n }\r\n throw new Error(\"Unsupported query type for buildSimpleQuery\");\r\n }\r\n\r\n private static buildSimpleBinaryQuery(query: BinarySelectQuery): SimpleSelectQuery {\r\n // Create a subquery source from the binary query\r\n const subQuerySource = new SubQuerySource(query);\r\n\r\n // Create a source expression with alias\r\n const sourceExpr = new SourceExpression(\r\n subQuerySource,\r\n new SourceAliasExpression(\"bq\", null)\r\n );\r\n\r\n // Create FROM clause with the source expression\r\n const fromClause = new FromClause(sourceExpr, null);\r\n\r\n // Create SELECT clause with * (all columns)\r\n const selectClause = QueryBuilder.createSelectAllClause();\r\n\r\n // Create the final simple select query\r\n const q = new SimpleSelectQuery(\r\n {\r\n selectClause,\r\n fromClause\r\n }\r\n );\r\n\r\n return CTENormalizer.normalize(q) as SimpleSelectQuery;\r\n }\r\n\r\n /**\r\n * Converts a ValuesQuery to a SimpleSelectQuery with sequentially numbered columns or user-specified columns\r\n * \r\n * @param query The VALUES query to convert\r\n * @param columns Optional: column names\r\n * @returns A SimpleSelectQuery\r\n */\r\n private static buildSimpleValuesQuery(query: ValuesQuery): SimpleSelectQuery {\r\n // Figure out how many columns are in the VALUES clause\r\n const columnCount = query.tuples.length > 0 ? query.tuples[0].values.length : 0;\r\n if (query.tuples.length === 0) {\r\n throw new Error(\"Empty VALUES clause cannot be converted to a SimpleSelectQuery\");\r\n }\r\n if (!query.columnAliases) {\r\n throw new Error(\"Column aliases are required to convert a VALUES clause to SimpleSelectQuery. Please specify column aliases.\");\r\n }\r\n if (query.columnAliases.length !== columnCount) {\r\n throw new Error(`The number of column aliases (${query.columnAliases.length}) does not match the number of columns in the first tuple (${columnCount}).`);\r\n }\r\n\r\n // Create a subquery source from the VALUES query\r\n const subQuerySource = new SubQuerySource(query);\r\n const sourceExpr = new SourceExpression(\r\n subQuerySource,\r\n new SourceAliasExpression(\"vq\", query.columnAliases)\r\n );\r\n\r\n // Create FROM clause with the source expression\r\n const fromClause = new FromClause(sourceExpr, null);\r\n\r\n // Create SELECT clause with all columns\r\n const selectItems = query.columnAliases.map(name => new SelectItem(new ColumnReference(\"vq\", name), name));\r\n const selectClause = new SelectClause(selectItems, null);\r\n\r\n // Create the final simple select query\r\n return new SimpleSelectQuery(\r\n {\r\n selectClause,\r\n fromClause\r\n }\r\n );\r\n }\r\n\r\n /**\r\n * Creates a SELECT clause with a single * (all columns) item\r\n * \r\n * @returns A SELECT clause with *\r\n */\r\n private static createSelectAllClause(): SelectClause {\r\n // Create a column reference for *\r\n const columnRef = new ColumnReference(null, \"*\");\r\n\r\n // Create a SelectItem with the column reference\r\n const selectItem = new SelectItem(columnRef, \"*\");\r\n\r\n // Create and return a SelectClause with the item\r\n return new SelectClause([selectItem], null);\r\n }\r\n\r\n /**\r\n * Converts a SELECT query to a CREATE TABLE query (CREATE [TEMPORARY] TABLE ... AS SELECT ...)\r\n * @param query The SELECT query to use as the source\r\n * @param tableName The name of the table to create\r\n * @param isTemporary If true, creates a temporary table\r\n * @returns A CreateTableQuery instance\r\n */\r\n public static buildCreateTableQuery(query: SelectQuery, tableName: string, isTemporary: boolean = false): CreateTableQuery {\r\n return new CreateTableQuery({\r\n tableName,\r\n isTemporary,\r\n asSelectQuery: query\r\n });\r\n }\r\n\r\n /**\r\n * Converts a SELECT query to an INSERT query (INSERT INTO ... SELECT ...)\r\n * @param selectQuery The SELECT query to use as the source\r\n * @param tableName The name of the table to insert into\r\n * @param columns Optional: array of column names. If omitted, columns are inferred from the selectQuery\r\n * @returns An InsertQuery instance\r\n */\r\n public static buildInsertQuery(selectQuery: SimpleSelectQuery, tableName: string): InsertQuery {\r\n let cols: string[];\r\n\r\n const count = selectQuery.selectClause.items.length;\r\n\r\n // Try to infer columns from the selectQuery\r\n const collector = new SelectValueCollector();\r\n const items = collector.collect(selectQuery);\r\n cols = items.map(item => item.name);\r\n if (!cols.length || count !== cols.length) {\r\n throw new Error(\r\n `Columns cannot be inferred from the selectQuery. ` +\r\n `Make sure you are not using wildcards or unnamed columns.\\n` +\r\n `Select clause column count: ${count}, ` +\r\n `Columns with valid names: ${cols.length}\\n` +\r\n `Detected column names: [${cols.join(\", \")}]`\r\n );\r\n }\r\n\r\n // Generate SourceExpression (supports only table name, does not support alias or schema)\r\n const sourceExpr = SourceExpressionParser.parse(tableName);\r\n return new InsertQuery({\r\n insertClause: new InsertClause(sourceExpr, cols),\r\n selectQuery: selectQuery\r\n });\r\n }\r\n\r\n /**\r\n * Builds an UPDATE query from a SELECT query, table name, and primary key(s).\r\n * @param selectQuery The SELECT query providing new values (must select all columns to update and PKs)\r\n * @param updateTableExprRaw The table name to update\r\n * @param primaryKeys The primary key column name(s)\r\n * @returns UpdateQuery instance\r\n */\r\n public static buildUpdateQuery(selectQuery: SimpleSelectQuery, selectSourceName: string, updateTableExprRaw: string, primaryKeys: string | string[]) {\r\n const updateClause = new UpdateClause(SourceExpressionParser.parse(updateTableExprRaw));\r\n\r\n const pkArray = Array.isArray(primaryKeys) ? primaryKeys : [primaryKeys];\r\n const selectCollector = new SelectValueCollector();\r\n const selectItems = selectCollector.collect(selectQuery);\r\n\r\n const cteCollector = new CTECollector();\r\n const collectedCTEs = cteCollector.collect(selectQuery);\r\n const cteDisabler = new CTEDisabler();\r\n cteDisabler.execute(selectQuery);\r\n\r\n for (const pk of pkArray) {\r\n if (!selectItems.some(item => item.name === pk)) {\r\n throw new Error(`Primary key column '${pk}' is not present in selectQuery select list.`);\r\n }\r\n }\r\n\r\n const updateSourceName = updateClause.getSourceAliasName();\r\n if (!updateSourceName) {\r\n throw new Error(`Source expression does not have an alias. Please provide an alias for the source expression.`);\r\n }\r\n\r\n const setColumns = selectItems.filter(item => !pkArray.includes(item.name));\r\n const setItems = setColumns.map(col => new SetClauseItem(col.name, new ColumnReference(updateSourceName, col.name)));\r\n const setClause = new SetClause(setItems);\r\n\r\n const from = new FromClause(selectQuery.toSource(selectSourceName), null);\r\n\r\n let where: BinaryExpression | null = null;\r\n for (const pk of pkArray) {\r\n const cond = new BinaryExpression(\r\n new ColumnReference(updateSourceName, pk),\r\n '=',\r\n new ColumnReference(selectSourceName, pk)\r\n );\r\n where = where ? new BinaryExpression(where, 'and', cond) : cond;\r\n }\r\n const whereClause = new WhereClause(where!);\r\n\r\n const updateQuery = new UpdateQuery({\r\n updateClause: updateClause,\r\n setClause: setClause,\r\n fromClause: from,\r\n whereClause: whereClause,\r\n withClause: collectedCTEs.length > 0 ? new WithClause(false, collectedCTEs) : undefined,\r\n });\r\n return updateQuery;\r\n }\r\n}\r\n", "import { ParameterCollector } from \"../transformers/ParameterCollector\";\r\nimport { SqlComponent } from \"../models/SqlComponent\";\r\n\r\n/**\r\n * Utility class for parameter operations on SQL queries.\r\n */\r\nexport class ParameterHelper {\r\n /**\r\n * Sets the value of a parameter by name in the given query.\r\n * Throws an error if the parameter is not found.\r\n * @param query The query object (must be a SqlComponent)\r\n * @param name Parameter name\r\n * @param value Value to set\r\n */\r\n public static set(query: SqlComponent, name: string, value: any): void {\r\n const params = ParameterCollector.collect(query);\r\n\r\n let found = false;\r\n for (const p of params) {\r\n if (p.name.value === name) {\r\n p.value = value;\r\n found = true;\r\n }\r\n }\r\n\r\n if (!found) {\r\n throw new Error(`Parameter '${name}' not found in query.`);\r\n }\r\n }\r\n}\r\n", "import { SqlComponent } from \"./SqlComponent\";\r\nimport { ForClause, FromClause, GroupByClause, HavingClause, JoinClause, JoinOnClause, LimitClause, OrderByClause, SelectClause, SourceExpression, SubQuerySource, SourceAliasExpression, WhereClause, WindowsClause as WindowClause, WithClause, CommonTable, OffsetClause, FetchClause } from \"./Clause\";\r\nimport { BinaryExpression, ColumnReference, ValueComponent } from \"./ValueComponent\";\r\nimport { ValueParser } from \"../parsers/ValueParser\";\r\nimport { CTENormalizer } from \"../transformers/CTENormalizer\";\r\nimport { SelectableColumnCollector } from \"../transformers/SelectableColumnCollector\";\r\nimport { SourceParser } from \"../parsers/SourceParser\";\r\nimport { BinarySelectQuery } from \"./BinarySelectQuery\";\r\nimport type { SelectQuery } from \"./SelectQuery\";\r\nimport { SelectQueryParser } from \"../parsers/SelectQueryParser\";\r\nimport { Formatter } from \"../transformers/Formatter\";\r\nimport { TableColumnResolver } from \"../transformers/TableColumnResolver\";\r\nimport { UpstreamSelectQueryFinder } from \"../transformers/UpstreamSelectQueryFinder\";\r\nimport { QueryBuilder } from \"../transformers/QueryBuilder\";\r\nimport { ParameterHelper } from \"../utils/ParameterHelper\";\r\n\r\n/**\r\n * Represents a simple SELECT query in SQL.\r\n */\r\nexport class SimpleSelectQuery extends SqlComponent implements SelectQuery {\r\n static kind = Symbol(\"SelectQuery\");\r\n withClause: WithClause | null;\r\n selectClause: SelectClause;\r\n fromClause: FromClause | null;\r\n whereClause: WhereClause | null;\r\n groupByClause: GroupByClause | null;\r\n havingClause: HavingClause | null;\r\n orderByClause: OrderByClause | null;\r\n windowClause: WindowClause | null;\r\n limitClause: LimitClause | null;\r\n offsetClause: OffsetClause | null;\r\n fetchClause: FetchClause | null;\r\n forClause: ForClause | null;\r\n\r\n constructor(params: {\r\n selectClause: SelectClause,\r\n fromClause?: FromClause | null,\r\n whereClause?: WhereClause | null,\r\n groupByClause?: GroupByClause | null,\r\n havingClause?: HavingClause | null,\r\n orderByClause?: OrderByClause | null,\r\n windowClause?: WindowClause | null,\r\n limitClause?: LimitClause | null,\r\n offsetClause?: OffsetClause | null,\r\n fetchClause?: FetchClause | null,\r\n forClause?: ForClause | null,\r\n withClause?: WithClause | null,\r\n }) {\r\n super();\r\n this.withClause = params.withClause ?? null;\r\n this.selectClause = params.selectClause;\r\n this.fromClause = params.fromClause ?? null;\r\n this.whereClause = params.whereClause ?? null;\r\n this.groupByClause = params.groupByClause ?? null;\r\n this.havingClause = params.havingClause ?? null;\r\n this.orderByClause = params.orderByClause ?? null;\r\n this.windowClause = params.windowClause ?? null;\r\n this.limitClause = params.limitClause ?? null;\r\n this.offsetClause = params.offsetClause ?? null;\r\n this.fetchClause = params.fetchClause ?? null;\r\n this.forClause = params.forClause ?? null;\r\n }\r\n\r\n /**\r\n * Creates a new BinarySelectQuery with this query as the left side and the provided query as the right side,\r\n * using UNION as the operator.\r\n * \r\n * @param rightQuery The right side of the UNION\r\n * @returns A new BinarySelectQuery representing \"this UNION rightQuery\"\r\n */\r\n public toUnion(rightQuery: SelectQuery): BinarySelectQuery {\r\n return this.toBinaryQuery('union', rightQuery);\r\n }\r\n\r\n /**\r\n * Creates a new BinarySelectQuery with this query as the left side and the provided query as the right side,\r\n * using UNION ALL as the operator.\r\n * \r\n * @param rightQuery The right side of the UNION ALL\r\n * @returns A new BinarySelectQuery representing \"this UNION ALL rightQuery\"\r\n */\r\n public toUnionAll(rightQuery: SelectQuery): BinarySelectQuery {\r\n return this.toBinaryQuery('union all', rightQuery);\r\n }\r\n\r\n /**\r\n * Creates a new BinarySelectQuery with this query as the left side and the provided query as the right side,\r\n * using INTERSECT as the operator.\r\n * \r\n * @param rightQuery The right side of the INTERSECT\r\n * @returns A new BinarySelectQuery representing \"this INTERSECT rightQuery\"\r\n */\r\n public toIntersect(rightQuery: SelectQuery): BinarySelectQuery {\r\n return this.toBinaryQuery('intersect', rightQuery);\r\n }\r\n\r\n /**\r\n * Creates a new BinarySelectQuery with this query as the left side and the provided query as the right side,\r\n * using INTERSECT ALL as the operator.\r\n * \r\n * @param rightQuery The right side of the INTERSECT ALL\r\n * @returns A new BinarySelectQuery representing \"this INTERSECT ALL rightQuery\"\r\n */\r\n public toIntersectAll(rightQuery: SelectQuery): BinarySelectQuery {\r\n return this.toBinaryQuery('intersect all', rightQuery);\r\n }\r\n\r\n /**\r\n * Creates a new BinarySelectQuery with this query as the left side and the provided query as the right side,\r\n * using EXCEPT as the operator.\r\n * \r\n * @param rightQuery The right side of the EXCEPT\r\n * @returns A new BinarySelectQuery representing \"this EXCEPT rightQuery\"\r\n */\r\n public toExcept(rightQuery: SelectQuery): BinarySelectQuery {\r\n return this.toBinaryQuery('except', rightQuery);\r\n }\r\n\r\n /**\r\n * Creates a new BinarySelectQuery with this query as the left side and the provided query as the right side,\r\n * using EXCEPT ALL as the operator.\r\n * \r\n * @param rightQuery The right side of the EXCEPT ALL\r\n * @returns A new BinarySelectQuery representing \"this EXCEPT ALL rightQuery\"\r\n */\r\n public toExceptAll(rightQuery: SelectQuery): BinarySelectQuery {\r\n return this.toBinaryQuery('except all', rightQuery);\r\n }\r\n\r\n /**\r\n * Creates a new BinarySelectQuery with this query as the left side and the provided query as the right side,\r\n * using the specified operator.\r\n * \r\n * @param operator SQL operator to use (e.g. 'union', 'union all', 'intersect', 'except')\r\n * @param rightQuery The right side of the binary operation\r\n * @returns A new BinarySelectQuery representing \"this [operator] rightQuery\"\r\n */\r\n public toBinaryQuery(operator: string, rightQuery: SelectQuery): BinarySelectQuery {\r\n return QueryBuilder.buildBinaryQuery([this, rightQuery], operator);\r\n }\r\n\r\n /**\r\n * Appends a new condition to the query's WHERE clause using AND logic.\r\n * The condition is provided as a raw SQL string which is parsed internally.\r\n * \r\n * @param rawCondition Raw SQL string representing the condition (e.g. \"status = 'active'\")\r\n */\r\n public appendWhereRaw(rawCondition: string): void {\r\n const parsedCondition = ValueParser.parse(rawCondition);\r\n this.appendWhere(parsedCondition);\r\n }\r\n\r\n /**\r\n * Appends a new condition to the query's WHERE clause using AND logic.\r\n * The condition is provided as a ValueComponent object.\r\n * \r\n * @param condition ValueComponent representing the condition\r\n */\r\n public appendWhere(condition: ValueComponent): void {\r\n if (!this.whereClause) {\r\n this.whereClause = new WhereClause(condition);\r\n } else {\r\n this.whereClause.condition = new BinaryExpression(\r\n this.whereClause.condition,\r\n 'and',\r\n condition\r\n );\r\n }\r\n }\r\n\r\n /**\r\n * Appends a new condition to the query's HAVING clause using AND logic.\r\n * The condition is provided as a raw SQL string which is parsed internally.\r\n * \r\n * @param rawCondition Raw SQL string representing the condition (e.g. \"count(*) > 5\")\r\n */\r\n public appendHavingRaw(rawCondition: string): void {\r\n const parsedCondition = ValueParser.parse(rawCondition);\r\n this.appendHaving(parsedCondition);\r\n }\r\n\r\n /**\r\n * Appends a new condition to the query's HAVING clause using AND logic.\r\n * The condition is provided as a ValueComponent object.\r\n * \r\n * @param condition ValueComponent representing the condition\r\n */\r\n public appendHaving(condition: ValueComponent): void {\r\n if (!this.havingClause) {\r\n this.havingClause = new HavingClause(condition);\r\n } else {\r\n this.havingClause.condition = new BinaryExpression(\r\n this.havingClause.condition,\r\n 'and',\r\n condition\r\n );\r\n }\r\n }\r\n\r\n /**\r\n * Appends an INNER JOIN clause to the query.\r\n * @param joinSourceRawText The table source text to join (e.g., \"my_table\", \"schema.my_table\")\r\n * @param alias The alias for the joined table\r\n * @param columns The columns to use for the join condition (e.g. [\"user_id\"] or \"user_id\")\r\n */\r\n public innerJoinRaw(joinSourceRawText: string, alias: string, columns: string | string[], resolver: TableColumnResolver | null = null): void {\r\n this.joinSourceRaw('inner join', joinSourceRawText, alias, columns, resolver);\r\n }\r\n\r\n /**\r\n * Appends a LEFT JOIN clause to the query.\r\n * @param joinSourceRawText The table source text to join\r\n * @param alias The alias for the joined table\r\n * @param columns The columns to use for the join condition\r\n */\r\n public leftJoinRaw(joinSourceRawText: string, alias: string, columns: string | string[], resolver: TableColumnResolver | null = null): void {\r\n this.joinSourceRaw('left join', joinSourceRawText, alias, columns, resolver);\r\n }\r\n\r\n /**\r\n * Appends a RIGHT JOIN clause to the query.\r\n * @param joinSourceRawText The table source text to join\r\n * @param alias The alias for the joined table\r\n * @param columns The columns to use for the join condition\r\n */\r\n public rightJoinRaw(joinSourceRawText: string, alias: string, columns: string | string[], resolver: TableColumnResolver | null = null): void {\r\n this.joinSourceRaw('right join', joinSourceRawText, alias, columns, resolver);\r\n }\r\n\r\n /**\r\n * Appends an INNER JOIN clause to the query using a SourceExpression.\r\n * @param sourceExpr The source expression to join\r\n * @param columns The columns to use for the join condition\r\n */\r\n public innerJoin(sourceExpr: SourceExpression, columns: string | string[], resolver: TableColumnResolver | null = null): void {\r\n this.joinSource('inner join', sourceExpr, columns, resolver);\r\n }\r\n\r\n /**\r\n * Appends a LEFT JOIN clause to the query using a SourceExpression.\r\n * @param sourceExpr The source expression to join\r\n * @param columns The columns to use for the join condition\r\n */\r\n public leftJoin(sourceExpr: SourceExpression, columns: string | string[], resolver: TableColumnResolver | null = null): void {\r\n this.joinSource('left join', sourceExpr, columns, resolver);\r\n }\r\n\r\n /**\r\n * Appends a RIGHT JOIN clause to the query using a SourceExpression.\r\n * @param sourceExpr The source expression to join\r\n * @param columns The columns to use for the join condition\r\n */\r\n public rightJoin(sourceExpr: SourceExpression, columns: string | string[], resolver: TableColumnResolver | null = null): void {\r\n this.joinSource('right join', sourceExpr, columns, resolver);\r\n }\r\n\r\n /**\r\n * Internal helper to append a JOIN clause.\r\n * Parses the table source, finds the corresponding columns in the existing query context,\r\n * and builds the JOIN condition.\r\n * @param joinType Type of join (e.g., 'inner join', 'left join')\r\n * @param joinSourceRawText Raw text for the table/source to join (e.g., \"my_table\", \"schema.another_table\")\r\n * @param alias Alias for the table/source being joined\r\n * @param columns Array or string of column names to join on\r\n */\r\n private joinSourceRaw(joinType: string, joinSourceRawText: string, alias: string, columns: string | string[], resolver: TableColumnResolver | null = null): void {\r\n const tableSource = SourceParser.parse(joinSourceRawText);\r\n const sourceExpr = new SourceExpression(tableSource, new SourceAliasExpression(alias, null));\r\n this.joinSource(joinType, sourceExpr, columns, resolver);\r\n }\r\n\r\n /**\r\n * Internal helper to append a JOIN clause using a SourceExpression.\r\n * @param joinType Type of join (e.g., 'inner join', 'left join')\r\n * @param sourceExpr The source expression to join\r\n * @param columns Array or string of column names to join on\r\n */\r\n private joinSource(joinType: string, sourceExpr: SourceExpression, columns: string | string[], resolver: TableColumnResolver | null = null): void {\r\n if (!this.fromClause) {\r\n throw new Error('A FROM clause is required to add a JOIN condition.');\r\n }\r\n\r\n // Always treat columns as array\r\n const columnsArr = Array.isArray(columns) ? columns : [columns];\r\n\r\n const collector = new SelectableColumnCollector(resolver);\r\n const valueSets = collector.collect(this);\r\n let joinCondition: ValueComponent | null = null;\r\n let count = 0;\r\n\r\n const sourceAlias = sourceExpr.getAliasName();\r\n if (!sourceAlias) {\r\n throw new Error('An alias is required for the source expression to add a JOIN condition.');\r\n }\r\n\r\n for (const valueSet of valueSets) {\r\n if (columnsArr.some(col => col == valueSet.name)) {\r\n const expr = new BinaryExpression(\r\n valueSet.value,\r\n '=',\r\n new ColumnReference([sourceAlias], valueSet.name)\r\n );\r\n if (joinCondition) {\r\n joinCondition = new BinaryExpression(\r\n joinCondition,\r\n 'and',\r\n expr\r\n );\r\n } else {\r\n joinCondition = expr;\r\n }\r\n count++;\r\n }\r\n }\r\n\r\n if (!joinCondition || count !== columnsArr.length) {\r\n throw new Error(`Invalid JOIN condition. The specified columns were not found: ${columnsArr.join(', ')}`);\r\n }\r\n\r\n const joinOnClause = new JoinOnClause(joinCondition);\r\n const joinClause = new JoinClause(joinType, sourceExpr, joinOnClause, false);\r\n\r\n if (this.fromClause) {\r\n if (this.fromClause.joins) {\r\n this.fromClause.joins.push(joinClause);\r\n } else {\r\n this.fromClause.joins = [joinClause];\r\n }\r\n }\r\n\r\n CTENormalizer.normalize(this);\r\n }\r\n\r\n // Returns a SourceExpression wrapping this query as a subquery source.\r\n // Alias is required for correct SQL generation and join logic.\r\n public toSource(alias: string): SourceExpression {\r\n if (!alias || alias.trim() === \"\") {\r\n throw new Error(\"Alias is required for toSource(). Please specify a non-empty alias name.\");\r\n }\r\n return new SourceExpression(\r\n new SubQuerySource(this),\r\n new SourceAliasExpression(alias, null)\r\n );\r\n }\r\n\r\n public appendWith(commonTable: CommonTable | CommonTable[]): void {\r\n // Always treat as array for simplicity\r\n const tables = Array.isArray(commonTable) ? commonTable : [commonTable];\r\n if (!this.withClause) {\r\n this.withClause = new WithClause(false, tables);\r\n } else {\r\n this.withClause.tables.push(...tables);\r\n }\r\n\r\n CTENormalizer.normalize(this);\r\n }\r\n\r\n /**\r\n * Appends a CommonTable (CTE) to the WITH clause from raw SQL text and alias.\r\n * If alias is provided, it will be used as the CTE name.\r\n *\r\n * @param rawText Raw SQL string representing the CTE body (e.g. '(SELECT ...)')\r\n * @param alias Optional alias for the CTE (e.g. 'cte_name')\r\n */\r\n public appendWithRaw(rawText: string, alias: string): void {\r\n const query = SelectQueryParser.parse(rawText);\r\n const commonTable = new CommonTable(query, alias, null);\r\n this.appendWith(commonTable);\r\n }\r\n\r\n /**\r\n * Overrides a select item using a template literal function.\r\n * The callback receives the SQL string of the original expression and must return a new SQL string.\r\n * The result is parsed and set as the new select item value.\r\n *\r\n * Example usage:\r\n * query.overrideSelectItemRaw(\"journal_date\", expr => `greatest(${expr}, DATE '2025-01-01')`)\r\n *\r\n * @param columnName The name of the column to override\r\n * @param fn Callback that receives the SQL string of the original expression and returns a new SQL string\r\n */\r\n public overrideSelectItemExpr(columnName: string, fn: (expr: string) => string): void {\r\n const items = this.selectClause.items.filter(item => item.identifier?.name === columnName);\r\n if (items.length === 0) {\r\n throw new Error(`Column ${columnName} not found in the query`);\r\n }\r\n if (items.length > 1) {\r\n throw new Error(`Duplicate column name ${columnName} found in the query`);\r\n }\r\n const item = items[0];\r\n const formatter = new Formatter();\r\n const exprSql = formatter.visit(item.value);\r\n const newValue = fn(exprSql);\r\n item.value = ValueParser.parse(newValue);\r\n }\r\n\r\n /**\r\n * Appends a WHERE clause using the expression for the specified column.\r\n * If `options.upstream` is true, applies to all upstream queries containing the column.\r\n * If false or omitted, applies only to the current query.\r\n *\r\n * @param columnName The name of the column to target.\r\n * @param exprBuilder Function that receives the column expression as a string and returns the WHERE condition string.\r\n * @param options Optional settings. If `upstream` is true, applies to upstream queries.\r\n */\r\n public appendWhereExpr(\r\n columnName: string,\r\n exprBuilder: (expr: string) => string,\r\n options?: { upstream?: boolean }\r\n ): void {\r\n // If upstream option is true, find all upstream queries containing the column\r\n if (options && options.upstream) {\r\n // Use UpstreamSelectQueryFinder to find all relevant queries\r\n // (Assume UpstreamSelectQueryFinder is imported)\r\n const finder = new UpstreamSelectQueryFinder();\r\n const queries = finder.find(this, [columnName]);\r\n const collector = new SelectableColumnCollector();\r\n const formatter = new Formatter();\r\n for (const q of queries) {\r\n const exprs = collector.collect(q).filter(item => item.name === columnName).map(item => item.value);\r\n if (exprs.length !== 1) {\r\n throw new Error(`Expected exactly one expression for column '${columnName}'`);\r\n }\r\n const exprStr = formatter.format(exprs[0]);\r\n q.appendWhereRaw(exprBuilder(exprStr));\r\n }\r\n } else {\r\n // Only apply to the current query\r\n const collector = new SelectableColumnCollector();\r\n const formatter = new Formatter();\r\n const exprs = collector.collect(this).filter(item => item.name === columnName).map(item => item.value);\r\n if (exprs.length !== 1) {\r\n throw new Error(`Expected exactly one expression for column '${columnName}'`);\r\n }\r\n const exprStr = formatter.format(exprs[0]);\r\n this.appendWhereRaw(exprBuilder(exprStr));\r\n }\r\n }\r\n\r\n /**\r\n * Sets the value of a parameter by name in this query.\r\n * @param name Parameter name\r\n * @param value Value to set\r\n */\r\n public setParameter(name: string, value: any): this {\r\n ParameterHelper.set(this, name, value);\r\n return this;\r\n }\r\n}\r\n", "import { SourceExpression, SubQuerySource, SourceAliasExpression } from \"./Clause\";\r\nimport type { SelectQuery } from \"./SelectQuery\";\r\nimport { SqlComponent } from \"./SqlComponent\";\r\nimport { RawString } from \"./ValueComponent\";\r\nimport { CTENormalizer } from \"../transformers/CTENormalizer\";\r\nimport { SelectQueryParser } from \"../parsers/SelectQueryParser\";\r\nimport { ParameterCollector } from \"../transformers/ParameterCollector\";\r\nimport { ParameterHelper } from \"../utils/ParameterHelper\";\r\n\r\n/**\r\n * Represents a binary SELECT query (e.g., UNION, INTERSECT, EXCEPT).\r\n */\r\nexport class BinarySelectQuery extends SqlComponent implements SelectQuery {\r\n static kind = Symbol(\"BinarySelectQuery\");\r\n left: SelectQuery;\r\n operator: RawString;\r\n right: SelectQuery;\r\n\r\n constructor(left: SelectQuery, operator: string, right: SelectQuery) {\r\n super();\r\n this.left = left;\r\n this.operator = new RawString(operator);\r\n this.right = right;\r\n }\r\n\r\n /**\r\n * Appends another query to this binary query using UNION as the operator.\r\n * This creates a new BinarySelectQuery where the left side is this binary query\r\n * and the right side is the provided query.\r\n * \r\n * @param query The query to append with UNION\r\n * @returns A new BinarySelectQuery representing \"(this) UNION query\"\r\n */\r\n public union(query: SelectQuery): BinarySelectQuery {\r\n return this.appendSelectQuery('union', query);\r\n }\r\n\r\n /**\r\n * Appends another query to this binary query using UNION ALL as the operator.\r\n * This creates a new BinarySelectQuery where the left side is this binary query\r\n * and the right side is the provided query.\r\n * \r\n * @param query The query to append with UNION ALL\r\n * @returns A new BinarySelectQuery representing \"(this) UNION ALL query\"\r\n */\r\n public unionAll(query: SelectQuery): BinarySelectQuery {\r\n return this.appendSelectQuery('union all', query);\r\n }\r\n\r\n /**\r\n * Appends another query to this binary query using INTERSECT as the operator.\r\n * This creates a new BinarySelectQuery where the left side is this binary query\r\n * and the right side is the provided query.\r\n * \r\n * @param query The query to append with INTERSECT\r\n * @returns A new BinarySelectQuery representing \"(this) INTERSECT query\"\r\n */\r\n public intersect(query: SelectQuery): BinarySelectQuery {\r\n return this.appendSelectQuery('intersect', query);\r\n }\r\n\r\n /**\r\n * Appends another query to this binary query using INTERSECT ALL as the operator.\r\n * This creates a new BinarySelectQuery where the left side is this binary query\r\n * and the right side is the provided query.\r\n * \r\n * @param query The query to append with INTERSECT ALL\r\n * @returns A new BinarySelectQuery representing \"(this) INTERSECT ALL query\"\r\n */\r\n public intersectAll(query: SelectQuery): BinarySelectQuery {\r\n return this.appendSelectQuery('intersect all', query);\r\n }\r\n\r\n /**\r\n * Appends another query to this binary query using EXCEPT as the operator.\r\n * This creates a new BinarySelectQuery where the left side is this binary query\r\n * and the right side is the provided query.\r\n * \r\n * @param query The query to append with EXCEPT\r\n * @returns A new BinarySelectQuery representing \"(this) EXCEPT query\"\r\n */\r\n public except(query: SelectQuery): BinarySelectQuery {\r\n return this.appendSelectQuery('except', query);\r\n }\r\n\r\n /**\r\n * Appends another query to this binary query using EXCEPT ALL as the operator.\r\n * This creates a new BinarySelectQuery where the left side is this binary query\r\n * and the right side is the provided query.\r\n * \r\n * @param query The query to append with EXCEPT ALL\r\n * @returns A new BinarySelectQuery representing \"(this) EXCEPT ALL query\"\r\n */\r\n public exceptAll(query: SelectQuery): BinarySelectQuery {\r\n return this.appendSelectQuery('except all', query);\r\n }\r\n\r\n /**\r\n * Appends another query to this binary query using the specified operator.\r\n * This creates a new BinarySelectQuery where the left side is this binary query\r\n * and the right side is the provided query.\r\n * \r\n * @param operator SQL operator to use (e.g. 'union', 'union all', 'intersect', 'except')\r\n * @param query The query to append with the specified operator\r\n * @returns A new BinarySelectQuery representing \"(this) [operator] query\"\r\n */\r\n public appendSelectQuery(operator: string, query: SelectQuery): BinarySelectQuery {\r\n this.left = new BinarySelectQuery(this.left, this.operator.value, this.right);\r\n this.operator = new RawString(operator);\r\n this.right = query;\r\n\r\n CTENormalizer.normalize(this);\r\n\r\n return this;\r\n }\r\n\r\n /**\r\n * Appends another query to this binary query using UNION as the operator, accepting a raw SQL string.\r\n * This method parses the SQL string and appends the resulting query using UNION.\r\n * @param sql The SQL string to parse and union\r\n * @returns A new BinarySelectQuery representing \"(this) UNION (parsed query)\"\r\n */\r\n public unionRaw(sql: string): BinarySelectQuery {\r\n const parsedQuery = SelectQueryParser.parse(sql);\r\n return this.union(parsedQuery);\r\n }\r\n public unionAllRaw(sql: string): BinarySelectQuery {\r\n const parsedQuery = SelectQueryParser.parse(sql);\r\n return this.unionAll(parsedQuery);\r\n }\r\n public intersectRaw(sql: string): BinarySelectQuery {\r\n const parsedQuery = SelectQueryParser.parse(sql);\r\n return this.intersect(parsedQuery);\r\n }\r\n public intersectAllRaw(sql: string): BinarySelectQuery {\r\n const parsedQuery = SelectQueryParser.parse(sql);\r\n return this.intersectAll(parsedQuery);\r\n }\r\n public exceptRaw(sql: string): BinarySelectQuery {\r\n const parsedQuery = SelectQueryParser.parse(sql);\r\n return this.except(parsedQuery);\r\n }\r\n public exceptAllRaw(sql: string): BinarySelectQuery {\r\n const parsedQuery = SelectQueryParser.parse(sql);\r\n return this.exceptAll(parsedQuery);\r\n }\r\n\r\n // Returns a SourceExpression wrapping this query as a subquery source.\r\n // Optionally takes an alias name (default: \"subq\")\r\n public toSource(alias: string = \"subq\"): SourceExpression {\r\n return new SourceExpression(\r\n new SubQuerySource(this),\r\n new SourceAliasExpression(alias, null)\r\n );\r\n }\r\n\r\n /**\r\n * Sets the value of a parameter by name in this query.\r\n * @param name Parameter name\r\n * @param value Value to set\r\n */\r\n public setParameter(name: string, value: any): this {\r\n ParameterHelper.set(this, name, value);\r\n return this;\r\n }\r\n}\r\n", "import { ParameterHelper } from \"../utils/ParameterHelper\";\r\nimport { ParameterCollector } from \"../transformers/ParameterCollector\";\r\nimport { QueryBuilder } from \"../transformers/QueryBuilder\";\r\nimport { SelectQuery } from \"./SelectQuery\";\r\nimport { SimpleSelectQuery } from \"./SimpleSelectQuery\";\r\nimport { SqlComponent } from \"./SqlComponent\";\r\nimport { TupleExpression } from \"./ValueComponent\";\r\n\r\n/**\r\n * Represents a VALUES query in SQL.\r\n */\r\nexport class ValuesQuery extends SqlComponent implements SelectQuery {\r\n static kind = Symbol(\"ValuesQuery\");\r\n tuples: TupleExpression[];\r\n /**\r\n * Column aliases for the VALUES query.\r\n * These represent the logical column names for each value tuple.\r\n * Note: This property is optional and is not referenced during SQL output, but is used when converting to a SimpleSelectQuery.\r\n */\r\n columnAliases: string[] | null;\r\n\r\n constructor(tuples: TupleExpression[], columnAliases: string[] | null = null) {\r\n super();\r\n this.tuples = tuples;\r\n this.columnAliases = columnAliases;\r\n }\r\n\r\n public toSimpleSelectQuery(): SimpleSelectQuery {\r\n return QueryBuilder.buildSimpleQuery(this);\r\n }\r\n\r\n /**\r\n * Sets the value of a parameter by name in this query.\r\n * @param name Parameter name\r\n * @param value Value to set\r\n */\r\n public setParameter(name: string, value: any): this {\r\n ParameterHelper.set(this, name, value);\r\n return this;\r\n }\r\n}\r\n", "import { Distinct, DistinctComponent, DistinctOn, SelectClause, SelectItem } from \"../models/Clause\";\r\nimport { Lexeme, TokenType } from \"../models/Lexeme\";\r\nimport { ColumnReference } from \"../models/ValueComponent\";\r\nimport { SqlTokenizer } from \"./SqlTokenizer\";\r\nimport { ValueParser } from \"./ValueParser\";\r\n\r\nexport class SelectClauseParser {\r\n // Parse SQL string to AST (was: parse)\r\n public static parse(query: string): SelectClause {\r\n const tokenizer = new SqlTokenizer(query); // Initialize tokenizer\r\n const lexemes = tokenizer.readLexmes(); // Get tokens\r\n\r\n // Parse\r\n const result = this.parseFromLexeme(lexemes, 0);\r\n\r\n // Error if there are remaining tokens\r\n if (result.newIndex < lexemes.length) {\r\n throw new Error(`Syntax error: Unexpected token \"${lexemes[result.newIndex].value}\" at position ${result.newIndex}. The SELECT clause is complete but there are additional tokens.`);\r\n }\r\n\r\n return result.value;\r\n }\r\n\r\n // Parse from lexeme array (was: parse)\r\n public static parseFromLexeme(lexemes: Lexeme[], index: number): { value: SelectClause; newIndex: number } {\r\n let idx = index;\r\n let distinct: DistinctComponent | null = null;\r\n\r\n if (lexemes[idx].value !== 'select') {\r\n throw new Error(`Syntax error at position ${idx}: Expected 'SELECT' keyword but found \"${lexemes[idx].value}\". SELECT clauses must start with the SELECT keyword.`);\r\n }\r\n idx++;\r\n\r\n if (idx < lexemes.length && lexemes[idx].value === 'distinct') {\r\n idx++;\r\n distinct = new Distinct();\r\n } else if (idx < lexemes.length && lexemes[idx].value === 'distinct on') {\r\n idx++;\r\n const argument = ValueParser.parseArgument(TokenType.OpenParen, TokenType.CloseParen, lexemes, idx);\r\n distinct = new DistinctOn(argument.value);\r\n idx = argument.newIndex;\r\n }\r\n\r\n const items: SelectItem[] = [];\r\n const item = SelectItemParser.parseItem(lexemes, idx);\r\n items.push(item.value);\r\n idx = item.newIndex;\r\n\r\n while (idx < lexemes.length && (lexemes[idx].type & TokenType.Comma)) {\r\n idx++;\r\n const item = SelectItemParser.parseItem(lexemes, idx);\r\n items.push(item.value);\r\n idx = item.newIndex;\r\n }\r\n\r\n if (items.length === 0) {\r\n throw new Error(`Syntax error at position ${index}: No select items found. The SELECT clause requires at least one expression to select.`);\r\n } else {\r\n const clause = new SelectClause(items, distinct);\r\n return { value: clause, newIndex: idx };\r\n }\r\n }\r\n\r\n}\r\n\r\n// Extracted SelectItemParser for parsing individual select items\r\nexport class SelectItemParser {\r\n /**\r\n * Parses a single select item from a SQL string.\r\n * @param query The SQL string representing a select item (e.g. 'id as user_id').\r\n * @returns The parsed SelectItem instance.\r\n */\r\n public static parse(query: string): SelectItem {\r\n const tokenizer = new SqlTokenizer(query);\r\n const lexemes = tokenizer.readLexmes();\r\n const result = this.parseItem(lexemes, 0);\r\n if (result.newIndex < lexemes.length) {\r\n throw new Error(`Syntax error: Unexpected token \"${lexemes[result.newIndex].value}\" at position ${result.newIndex}. The select item is complete but there are additional tokens.`);\r\n }\r\n return result.value;\r\n }\r\n\r\n /**\r\n * Parses a single select item from lexemes.\r\n * @param lexemes The array of lexemes.\r\n * @param index The starting index.\r\n * @returns An object containing the SelectItem and the new index.\r\n */\r\n public static parseItem(lexemes: Lexeme[], index: number): { value: SelectItem; newIndex: number } {\r\n let idx = index;\r\n const parsedValue = ValueParser.parseFromLexeme(lexemes, idx);\r\n const value = parsedValue.value;\r\n idx = parsedValue.newIndex;\r\n\r\n if (idx < lexemes.length && lexemes[idx].value === 'as') {\r\n // Skip 'AS' keyword\r\n idx++;\r\n }\r\n\r\n if (idx < lexemes.length && (lexemes[idx].type & TokenType.Identifier)) {\r\n const alias = lexemes[idx].value;\r\n idx++;\r\n return {\r\n value: new SelectItem(value, alias),\r\n newIndex: idx,\r\n };\r\n } else if (value instanceof ColumnReference && value.column.name !== \"*\") {\r\n // nameless select item\r\n return {\r\n value: new SelectItem(value, value.column.name),\r\n newIndex: idx,\r\n };\r\n }\r\n // nameless select item\r\n return {\r\n value: new SelectItem(value),\r\n newIndex: idx,\r\n };\r\n }\r\n}", "import { JoinOnClause } from \"../models/Clause\";\r\nimport { Lexeme } from \"../models/Lexeme\";\r\nimport { ValueParser } from \"./ValueParser\";\r\n\r\nexport class JoinOnClauseParser {\r\n public static tryParse(lexemes: Lexeme[], index: number): { value: JoinOnClause; newIndex: number } | null {\r\n let idx = index;\r\n if (idx < lexemes.length && lexemes[idx].value === 'on') {\r\n idx++; // Skip 'on' keyword\r\n // Parse the condition expression\r\n const condition = ValueParser.parseFromLexeme(lexemes, idx);\r\n idx = condition.newIndex;\r\n const joinOn = new JoinOnClause(condition.value);\r\n return { value: joinOn, newIndex: idx };\r\n }\r\n return null;\r\n }\r\n}\r\n", "import { JoinUsingClause } from \"../models/Clause\";\r\nimport { Lexeme, TokenType } from \"../models/Lexeme\";\r\nimport { ValueParser } from \"./ValueParser\";\r\n\r\nexport class JoinUsingClauseParser {\r\n public static tryParse(lexemes: Lexeme[], index: number): { value: JoinUsingClause; newIndex: number } | null {\r\n let idx = index;\r\n if (idx < lexemes.length && lexemes[idx].value === 'using') {\r\n idx++; // Skip 'using' keyword\r\n // Parse the columns in parentheses\r\n const result = ValueParser.parseArgument(TokenType.OpenParen, TokenType.CloseParen, lexemes, idx);\r\n const usingColumns = result.value;\r\n idx = result.newIndex;\r\n const joinUsing = new JoinUsingClause(usingColumns);\r\n return { value: joinUsing, newIndex: idx };\r\n }\r\n return null;\r\n }\r\n}\r\n", "import { JoinClause, SourceExpression } from \"../models/Clause\";\r\nimport { Lexeme, TokenType } from \"../models/Lexeme\";\r\nimport { joinkeywordParser } from \"../tokenReaders/CommandTokenReader\";\r\nimport { SourceExpressionParser } from \"./SourceExpressionParser\";\r\nimport { JoinOnClauseParser } from \"./JoinOnClauseParser\";\r\nimport { JoinUsingClauseParser } from \"./JoinUsingClauseParser\";\r\n\r\nexport class JoinClauseParser {\r\n public static tryParse(lexemes: Lexeme[], index: number): { value: JoinClause[]; newIndex: number } | null {\r\n let idx = index;\r\n const joins: JoinClause[] = [];\r\n\r\n while (this.isJoinCommand(lexemes, idx)) {\r\n const joinClause = this.parseJoinClause(lexemes, idx);\r\n joins.push(joinClause.value);\r\n idx = joinClause.newIndex;\r\n }\r\n\r\n if (joins.length > 0) {\r\n return { value: joins, newIndex: idx };\r\n }\r\n return null;\r\n }\r\n\r\n private static isJoinKeyword(value: string): boolean {\r\n // Although performance is not ideal,\r\n // we use keyword token reader to centralize keyword management\r\n const result = joinkeywordParser.parse(value, 0);\r\n if (result) {\r\n return true;\r\n }\r\n return false;\r\n }\r\n\r\n private static parseLateral(lexemes: Lexeme[], index: number): { value: boolean; newIndex: number } {\r\n let idx = index;\r\n\r\n if (idx < lexemes.length && lexemes[idx].value === 'lateral') {\r\n // Skip 'lateral' keyword\r\n idx++;\r\n return { value: true, newIndex: idx };\r\n }\r\n\r\n return { value: false, newIndex: idx };\r\n }\r\n\r\n private static isJoinCommand(lexemes: Lexeme[], index: number): boolean {\r\n if (index >= lexemes.length) {\r\n return false;\r\n }\r\n\r\n if (lexemes[index].type & TokenType.Comma || this.isJoinKeyword(lexemes[index].value) === true) {\r\n return true;\r\n }\r\n return false;\r\n }\r\n\r\n private static parseJoinClause(lexemes: Lexeme[], index: number): { value: JoinClause; newIndex: number } {\r\n let idx = index;\r\n\r\n // Get the join type\r\n const joinType = lexemes[idx].value === \",\" ? \"cross join\" : lexemes[idx].value;\r\n idx++;\r\n\r\n // Check for lateral join\r\n const lateralResult = this.parseLateral(lexemes, idx);\r\n const lateral = lateralResult.value;\r\n idx = lateralResult.newIndex;\r\n\r\n // Parse the source expression to join with\r\n const sourceResult = SourceExpressionParser.parseFromLexeme(lexemes, idx);\r\n idx = sourceResult.newIndex;\r\n\r\n\r\n if (idx < lexemes.length) {\r\n // JoinOnClauseParser\r\n const onResult = JoinOnClauseParser.tryParse(lexemes, idx);\r\n if (onResult) {\r\n const joinClause = new JoinClause(joinType, sourceResult.value, onResult.value, lateral);\r\n return { value: joinClause, newIndex: onResult.newIndex };\r\n }\r\n // JoinUsingClauseParser\r\n const usingResult = JoinUsingClauseParser.tryParse(lexemes, idx);\r\n if (usingResult) {\r\n const joinClause = new JoinClause(joinType, sourceResult.value, usingResult.value, lateral);\r\n return { value: joinClause, newIndex: usingResult.newIndex };\r\n }\r\n }\r\n\r\n // If we reach the end of the input, we can treat it as a natural join\r\n const joinClause = new JoinClause(joinType, sourceResult.value, null, lateral);\r\n return { value: joinClause, newIndex: idx };\r\n }\r\n}", "import { FromClause } from \"../models/Clause\";\r\nimport { Lexeme } from \"../models/Lexeme\";\r\nimport { SqlTokenizer } from \"./SqlTokenizer\";\r\nimport { JoinClauseParser } from \"./JoinClauseParser\";\r\nimport { SourceExpressionParser } from \"./SourceExpressionParser\";\r\n\r\nexport class FromClauseParser {\r\n // Parse SQL string to AST (was: parse)\r\n public static parse(query: string): FromClause {\r\n const tokenizer = new SqlTokenizer(query); // Initialize tokenizer\r\n const lexemes = tokenizer.readLexmes(); // Get tokens\r\n\r\n // Parse\r\n const result = this.parseFromLexeme(lexemes, 0);\r\n\r\n // Error if there are remaining tokens\r\n if (result.newIndex < lexemes.length) {\r\n throw new Error(`Syntax error: Unexpected token \"${lexemes[result.newIndex].value}\" at position ${result.newIndex}. The FROM clause is complete but there are additional tokens.`);\r\n }\r\n\r\n return result.value;\r\n }\r\n\r\n // Parse from lexeme array (was: parse)\r\n public static parseFromLexeme(lexemes: Lexeme[], index: number): { value: FromClause; newIndex: number } {\r\n let idx = index;\r\n\r\n if (lexemes[idx].value !== 'from') {\r\n throw new Error(`Syntax error at position ${idx}: Expected 'FROM' keyword but found \"${lexemes[idx].value}\". FROM clauses must start with the FROM keyword.`);\r\n }\r\n idx++;\r\n\r\n if (idx >= lexemes.length) {\r\n throw new Error(`Syntax error: Unexpected end of input after 'FROM' keyword. The FROM clause requires a table reference.`);\r\n }\r\n\r\n // Parse the main source expression\r\n const sourceExpression = SourceExpressionParser.parseFromLexeme(lexemes, idx);\r\n idx = sourceExpression.newIndex;\r\n\r\n const join = JoinClauseParser.tryParse(lexemes, idx);\r\n idx = join?.newIndex || idx;\r\n\r\n if (join !== null) {\r\n const clause = new FromClause(sourceExpression.value, join.value);\r\n return { value: clause, newIndex: idx };\r\n } else {\r\n const clause = new FromClause(sourceExpression.value, null);\r\n return { value: clause, newIndex: idx };\r\n }\r\n }\r\n}", "import { WhereClause } from \"../models/Clause\";\r\nimport { Lexeme } from \"../models/Lexeme\";\r\nimport { SqlTokenizer } from \"./SqlTokenizer\";\r\nimport { ValueParser } from \"./ValueParser\";\r\n\r\nexport class WhereClauseParser {\r\n // Parse SQL string to AST (was: parse)\r\n public static parse(query: string): WhereClause {\r\n const tokenizer = new SqlTokenizer(query); // Initialize tokenizer\r\n const lexemes = tokenizer.readLexmes(); // Get tokens\r\n\r\n // Parse\r\n const result = this.parseFromLexeme(lexemes, 0);\r\n\r\n // Error if there are remaining tokens\r\n if (result.newIndex < lexemes.length) {\r\n throw new Error(`Syntax error: Unexpected token \"${lexemes[result.newIndex].value}\" at position ${result.newIndex}. The WHERE clause is complete but there are additional tokens.`);\r\n }\r\n\r\n return result.value;\r\n }\r\n\r\n // Parse from lexeme array (was: parse)\r\n public static parseFromLexeme(lexemes: Lexeme[], index: number): { value: WhereClause; newIndex: number } {\r\n let idx = index;\r\n\r\n if (lexemes[idx].value !== 'where') {\r\n throw new Error(`Syntax error at position ${idx}: Expected 'WHERE' keyword but found \"${lexemes[idx].value}\". WHERE clauses must start with the WHERE keyword.`);\r\n }\r\n idx++;\r\n\r\n if (idx >= lexemes.length) {\r\n throw new Error(`Syntax error: Unexpected end of input after 'WHERE' keyword. The WHERE clause requires a condition expression.`);\r\n }\r\n\r\n const item = ValueParser.parseFromLexeme(lexemes, idx);\r\n const clause = new WhereClause(item.value);\r\n\r\n return { value: clause, newIndex: item.newIndex };\r\n }\r\n}", "import { GroupByClause } from \"../models/Clause\";\r\nimport { Lexeme, TokenType } from \"../models/Lexeme\";\r\nimport { ValueComponent } from \"../models/ValueComponent\";\r\nimport { SqlTokenizer } from \"./SqlTokenizer\";\r\nimport { ValueParser } from \"./ValueParser\";\r\n\r\nexport class GroupByClauseParser {\r\n // Parse SQL string to AST (was: parse)\r\n public static parse(query: string): GroupByClause {\r\n const tokenizer = new SqlTokenizer(query); // Initialize tokenizer\r\n const lexemes = tokenizer.readLexmes(); // Get tokens\r\n\r\n // Parse\r\n const result = this.parseFromLexeme(lexemes, 0);\r\n\r\n // Error if there are remaining tokens\r\n if (result.newIndex < lexemes.length) {\r\n throw new Error(`Syntax error: Unexpected token \"${lexemes[result.newIndex].value}\" at position ${result.newIndex}. The GROUP BY clause is complete but there are additional tokens.`);\r\n }\r\n\r\n return result.value;\r\n }\r\n\r\n // Parse from lexeme array (was: parse)\r\n public static parseFromLexeme(lexemes: Lexeme[], index: number): { value: GroupByClause; newIndex: number } {\r\n let idx = index;\r\n\r\n if (lexemes[idx].value !== 'group by') {\r\n throw new Error(`Syntax error at position ${idx}: Expected 'GROUP BY' keyword but found \"${lexemes[idx].value}\". GROUP BY clauses must start with the GROUP BY keywords.`);\r\n }\r\n idx++;\r\n\r\n if (idx >= lexemes.length) {\r\n throw new Error(`Syntax error: Unexpected end of input after 'GROUP BY' keyword. The GROUP BY clause requires at least one expression to group by.`);\r\n }\r\n\r\n const items: ValueComponent[] = [];\r\n const item = this.parseItem(lexemes, idx);\r\n items.push(item.value);\r\n idx = item.newIndex;\r\n\r\n while (idx < lexemes.length && (lexemes[idx].type & TokenType.Comma)) {\r\n idx++;\r\n const item = this.parseItem(lexemes, idx);\r\n items.push(item.value);\r\n idx = item.newIndex;\r\n }\r\n\r\n if (items.length === 0) {\r\n throw new Error(`Syntax error at position ${index}: No grouping expressions found. The GROUP BY clause requires at least one expression to group by.`);\r\n } else {\r\n const clause = new GroupByClause(items);\r\n return { value: clause, newIndex: idx };\r\n }\r\n }\r\n\r\n private static parseItem(lexemes: Lexeme[], index: number): { value: ValueComponent; newIndex: number } {\r\n let idx = index;\r\n const parsedValue = ValueParser.parseFromLexeme(lexemes, idx);\r\n const value = parsedValue.value;\r\n idx = parsedValue.newIndex;\r\n return { value, newIndex: idx };\r\n }\r\n}", "import { HavingClause } from \"../models/Clause\";\r\nimport { Lexeme } from \"../models/Lexeme\";\r\nimport { SqlTokenizer } from \"./SqlTokenizer\";\r\nimport { ValueParser } from \"./ValueParser\";\r\n\r\nexport class HavingClauseParser {\r\n // Parse SQL string to AST (was: parse)\r\n public static parse(query: string): HavingClause {\r\n const tokenizer = new SqlTokenizer(query); // Initialize tokenizer\r\n const lexemes = tokenizer.readLexmes(); // Get tokens\r\n\r\n // Parse\r\n const result = this.parseFromLexeme(lexemes, 0);\r\n\r\n // Error if there are remaining tokens\r\n if (result.newIndex < lexemes.length) {\r\n throw new Error(`Syntax error: Unexpected token \"${lexemes[result.newIndex].value}\" at position ${result.newIndex}. The HAVING clause is complete but there are additional tokens.`);\r\n }\r\n\r\n return result.value;\r\n }\r\n\r\n // Parse from lexeme array (was: parse)\r\n public static parseFromLexeme(lexemes: Lexeme[], index: number): { value: HavingClause; newIndex: number } {\r\n let idx = index;\r\n\r\n if (lexemes[idx].value !== 'having') {\r\n throw new Error(`Syntax error at position ${idx}: Expected 'HAVING' keyword but found \"${lexemes[idx].value}\". HAVING clauses must start with the HAVING keyword.`);\r\n }\r\n idx++;\r\n\r\n if (idx >= lexemes.length) {\r\n throw new Error(`Syntax error: Unexpected end of input after 'HAVING' keyword. The HAVING clause requires a condition expression.`);\r\n }\r\n\r\n const item = ValueParser.parseFromLexeme(lexemes, idx);\r\n const clause = new HavingClause(item.value);\r\n\r\n return { value: clause, newIndex: item.newIndex };\r\n }\r\n}", "import { WindowFrameClause, WindowsClause } from \"../models/Clause\";\r\nimport { Lexeme, TokenType } from \"../models/Lexeme\";\r\nimport { SqlTokenizer } from \"./SqlTokenizer\";\r\nimport { WindowExpressionParser } from \"./WindowExpressionParser\";\r\n\r\nexport class WindowClauseParser {\r\n // Parse SQL string to AST (was: parse)\r\n public static parse(query: string): WindowsClause {\r\n const tokenizer = new SqlTokenizer(query);\r\n const lexemes = tokenizer.readLexmes();\r\n const result = this.parseFromLexeme(lexemes, 0);\r\n if (result.newIndex < lexemes.length) {\r\n throw new Error(`Syntax error: Unexpected token \"${lexemes[result.newIndex].value}\" at position ${result.newIndex}. The WINDOW clause is complete but there are additional tokens.`);\r\n }\r\n return result.value;\r\n }\r\n\r\n // Parse from lexeme array (was: parse)\r\n public static parseFromLexeme(lexemes: Lexeme[], index: number): { value: WindowsClause; newIndex: number } {\r\n let idx = index;\r\n\r\n if (lexemes[idx].value !== 'window') {\r\n throw new Error(`Syntax error at position ${idx}: Expected 'WINDOW' keyword but found \"${lexemes[idx].value}\". WINDOW clauses must start with the WINDOW keyword.`);\r\n }\r\n idx++;\r\n\r\n if (idx >= lexemes.length) {\r\n throw new Error(`Syntax error: Unexpected end of input after 'WINDOW' keyword. The WINDOW clause requires at least one window definition.`);\r\n }\r\n\r\n const windows: WindowFrameClause[] = [];\r\n while (idx < lexemes.length) {\r\n\r\n if (idx >= lexemes.length || lexemes[idx].type !== TokenType.Identifier) {\r\n throw new Error(`Syntax error: Expected window name after 'WINDOW' keyword.`);\r\n }\r\n const name = lexemes[idx].value;\r\n idx++;\r\n if (idx >= lexemes.length || lexemes[idx].value !== 'as') {\r\n throw new Error(`Syntax error at position ${idx}: Expected 'AS' keyword after window name.`);\r\n }\r\n idx++;\r\n const expr = WindowExpressionParser.parseFromLexeme(lexemes, idx);\r\n idx = expr.newIndex;\r\n windows.push(new WindowFrameClause(name, expr.value));\r\n\r\n if (idx < lexemes.length && lexemes[idx].type & TokenType.Comma) {\r\n idx++;\r\n } else {\r\n break;\r\n }\r\n }\r\n\r\n if (windows.length === 0) {\r\n throw new Error('At least one WINDOW clause is required after WINDOW keyword.');\r\n }\r\n return { value: new WindowsClause(windows), newIndex: idx };\r\n }\r\n}", "import { LimitClause as LimitClause } from \"../models/Clause\";\r\nimport { Lexeme } from \"../models/Lexeme\";\r\nimport { SqlTokenizer } from \"./SqlTokenizer\";\r\nimport { ValueParser } from \"./ValueParser\";\r\n\r\nexport class LimitClauseParser {\r\n // Parse SQL string to AST (was: parse)\r\n public static parse(query: string): LimitClause {\r\n const tokenizer = new SqlTokenizer(query); // Initialize tokenizer\r\n const lexemes = tokenizer.readLexmes(); // Get tokens\r\n\r\n // Parse\r\n const result = this.parseFromLexeme(lexemes, 0);\r\n\r\n // Error if there are remaining tokens\r\n if (result.newIndex < lexemes.length) {\r\n throw new Error(`Syntax error: Unexpected token \"${lexemes[result.newIndex].value}\" at position ${result.newIndex}. The LIMIT clause is complete but there are additional tokens.`);\r\n }\r\n\r\n return result.value;\r\n }\r\n\r\n // Parse from lexeme array (was: parse)\r\n public static parseFromLexeme(lexemes: Lexeme[], index: number): { value: LimitClause; newIndex: number } {\r\n let idx = index;\r\n\r\n if (lexemes[idx].value !== 'limit') {\r\n throw new Error(`Syntax error at position ${idx}: Expected 'LIMIT' keyword but found \"${lexemes[idx].value}\". LIMIT clauses must start with the LIMIT keyword.`);\r\n }\r\n idx++;\r\n\r\n if (idx >= lexemes.length) {\r\n throw new Error(`Syntax error: Unexpected end of input after 'LIMIT' keyword. The LIMIT clause requires a numeric expression.`);\r\n }\r\n\r\n // Parse LIMIT value\r\n const limitItem = ValueParser.parseFromLexeme(lexemes, idx);\r\n idx = limitItem.newIndex;\r\n\r\n const clause = new LimitClause(limitItem.value);\r\n\r\n return { value: clause, newIndex: idx };\r\n }\r\n}", "import { ForClause, LockMode } from \"../models/Clause\";\r\nimport { Lexeme } from \"../models/Lexeme\";\r\nimport { SqlTokenizer } from \"./SqlTokenizer\";\r\n\r\nexport class ForClauseParser {\r\n // Parse SQL string to AST (was: parse)\r\n public static parse(query: string): ForClause {\r\n const tokenizer = new SqlTokenizer(query);\r\n const lexemes = tokenizer.readLexmes();\r\n\r\n // Parse\r\n const result = this.parseFromLexeme(lexemes, 0);\r\n\r\n // Error if there are remaining tokens\r\n if (result.newIndex < lexemes.length) {\r\n throw new Error(`Syntax error: Unexpected token \"${lexemes[result.newIndex].value}\" at position ${result.newIndex}. The FOR clause is complete but there are additional tokens.`);\r\n }\r\n\r\n return result.value;\r\n }\r\n\r\n // Parse from lexeme array (was: parse)\r\n public static parseFromLexeme(lexemes: Lexeme[], index: number): { value: ForClause; newIndex: number } {\r\n let idx = index;\r\n\r\n // Check for FOR keyword\r\n if (lexemes[idx].value.toLowerCase() !== 'for') {\r\n throw new Error(`Syntax error at position ${idx}: Expected 'FOR' keyword but found \"${lexemes[idx].value}\". FOR clauses must start with the FOR keyword.`);\r\n }\r\n idx++;\r\n\r\n if (idx >= lexemes.length) {\r\n throw new Error(`Syntax error: Unexpected end of input after 'FOR' keyword. The FOR clause requires a lock mode specification.`);\r\n }\r\n\r\n // Parse lock mode\r\n const lockModeValue = lexemes[idx].value;\r\n let lockMode: LockMode;\r\n\r\n switch (lockModeValue) {\r\n case 'update':\r\n lockMode = LockMode.Update;\r\n idx++;\r\n break;\r\n case 'share':\r\n lockMode = LockMode.Share;\r\n idx++;\r\n break;\r\n case 'key share':\r\n lockMode = LockMode.KeyShare;\r\n idx++;\r\n break;\r\n case 'no key update':\r\n lockMode = LockMode.NokeyUpdate;\r\n idx++;\r\n break;\r\n default:\r\n throw new Error(`Syntax error at position ${idx}: Invalid lock mode \"${lockModeValue}\". Valid lock modes are: UPDATE, SHARE, KEY SHARE, NO KEY UPDATE.`);\r\n }\r\n\r\n const clause = new ForClause(lockMode);\r\n return { value: clause, newIndex: idx };\r\n }\r\n}", "import { CommonTable } from \"../models/Clause\";\r\nimport { Lexeme, TokenType } from \"../models/Lexeme\";\r\nimport { SqlTokenizer } from \"./SqlTokenizer\";\r\nimport { SelectQueryParser } from \"./SelectQueryParser\";\r\nimport { SourceAliasExpressionParser } from \"./SourceAliasExpressionParser\";\r\n\r\nexport class CommonTableParser {\r\n // Parse SQL string to AST (was: parse)\r\n public static parse(query: string): CommonTable {\r\n const tokenizer = new SqlTokenizer(query); // Initialize tokenizer\r\n const lexemes = tokenizer.readLexmes(); // Get tokens\r\n\r\n // Parse\r\n const result = this.parseFromLexeme(lexemes, 0);\r\n\r\n // Error if there are remaining tokens\r\n if (result.newIndex < lexemes.length) {\r\n throw new Error(`Syntax error: Unexpected token \"${lexemes[result.newIndex].value}\" at position ${result.newIndex}. The CommonTable definition is complete but there are additional tokens.`);\r\n }\r\n\r\n return result.value;\r\n }\r\n\r\n // Parse from lexeme array (was: parse)\r\n public static parseFromLexeme(lexemes: Lexeme[], index: number): { value: CommonTable; newIndex: number } {\r\n let idx = index;\r\n\r\n // Parse alias and optional column aliases\r\n // SourceAliasExpressionParser already handles column aliases if present\r\n const aliasResult = SourceAliasExpressionParser.parseFromLexeme(lexemes, idx);\r\n idx = aliasResult.newIndex;\r\n\r\n if (idx < lexemes.length && lexemes[idx].value !== \"as\") {\r\n throw new Error(`Syntax error at position ${idx}: Expected 'AS' keyword after CTE name but found \"${lexemes[idx].value}\".`);\r\n }\r\n idx++; // Skip 'AS' keyword\r\n\r\n // Materialized flag\r\n let materialized: boolean | null = null;\r\n\r\n // Parse optional MATERIALIZED or NOT MATERIALIZED keywords\r\n if (idx < lexemes.length) {\r\n const currentValue = lexemes[idx].value;\r\n if (currentValue === \"materialized\") {\r\n materialized = true;\r\n idx++;\r\n } else if (currentValue === \"not materialized\") {\r\n materialized = false;\r\n idx++;\r\n }\r\n }\r\n\r\n if (idx < lexemes.length && lexemes[idx].type !== TokenType.OpenParen) {\r\n throw new Error(`Syntax error at position ${idx}: Expected '(' after CTE name but found \"${lexemes[idx].value}\".`);\r\n }\r\n idx++; // Skip opening parenthesis\r\n\r\n const queryResult = SelectQueryParser.parseFromLexeme(lexemes, idx);\r\n idx = queryResult.newIndex;\r\n\r\n if (idx < lexemes.length && lexemes[idx].type !== TokenType.CloseParen) {\r\n throw new Error(`Syntax error at position ${idx}: Expected ')' after CTE query but found \"${lexemes[idx].value}\".`);\r\n }\r\n idx++; // Skip closing parenthesis\r\n\r\n const value = new CommonTable(queryResult.value, aliasResult.value, materialized);\r\n return { value, newIndex: idx };\r\n }\r\n}", "import { CommonTable, WithClause } from \"../models/Clause\";\r\nimport { Lexeme, TokenType } from \"../models/Lexeme\";\r\nimport { SqlTokenizer } from \"./SqlTokenizer\";\r\nimport { CommonTableParser } from \"./CommonTableParser\";\r\n\r\nexport class WithClauseParser {\r\n // Parse SQL string to AST (was: parse)\r\n public static parse(query: string): WithClause {\r\n const tokenizer = new SqlTokenizer(query); // Initialize tokenizer\r\n const lexemes = tokenizer.readLexmes(); // Get tokens\r\n\r\n // Parse\r\n const result = this.parseFromLexeme(lexemes, 0);\r\n\r\n // Error if there are remaining tokens\r\n if (result.newIndex < lexemes.length) {\r\n throw new Error(`Syntax error: Unexpected token \"${lexemes[result.newIndex].value}\" at position ${result.newIndex}. The WITH clause is complete but there are additional tokens.`);\r\n }\r\n\r\n return result.value;\r\n }\r\n\r\n // Parse from lexeme array (was: parse)\r\n public static parseFromLexeme(lexemes: Lexeme[], index: number): { value: WithClause; newIndex: number } {\r\n let idx = index;\r\n\r\n // Expect WITH keyword\r\n if (idx < lexemes.length && lexemes[idx].value.toLowerCase() === \"with\") {\r\n idx++;\r\n } else {\r\n throw new Error(`Syntax error at position ${idx}: Expected WITH keyword.`);\r\n }\r\n\r\n // Check for RECURSIVE keyword\r\n const recursive = idx < lexemes.length && lexemes[idx].value.toLowerCase() === \"recursive\";\r\n if (recursive) {\r\n idx++;\r\n }\r\n\r\n // Parse CTEs\r\n const tables: CommonTable[] = [];\r\n\r\n // Parse first CTE (required)\r\n const firstCte = CommonTableParser.parseFromLexeme(lexemes, idx);\r\n tables.push(firstCte.value);\r\n idx = firstCte.newIndex;\r\n\r\n // Parse additional CTEs (optional)\r\n while (idx < lexemes.length && (lexemes[idx].type & TokenType.Comma)) {\r\n idx++; // Skip comma\r\n const cteResult = CommonTableParser.parseFromLexeme(lexemes, idx);\r\n tables.push(cteResult.value);\r\n idx = cteResult.newIndex;\r\n }\r\n\r\n // Create WITH clause\r\n return {\r\n value: new WithClause(recursive, tables),\r\n newIndex: idx\r\n };\r\n }\r\n}", "import { Lexeme, TokenType } from \"../models/Lexeme\";\r\nimport { ValuesQuery } from \"../models/SelectQuery\";\r\nimport { TupleExpression, ValueComponent } from \"../models/ValueComponent\";\r\nimport { SqlTokenizer } from \"./SqlTokenizer\";\r\nimport { ValueParser } from \"./ValueParser\";\r\n\r\nexport class ValuesQueryParser {\r\n public static parse(query: string): ValuesQuery {\r\n const tokenizer = new SqlTokenizer(query); // Initialize tokenizer\r\n const lexemes = tokenizer.readLexmes(); // Get tokens\r\n\r\n // Parse\r\n const result = this.parseFromLexeme(lexemes, 0);\r\n\r\n // Error if there are remaining tokens\r\n if (result.newIndex < lexemes.length) {\r\n throw new Error(`Syntax error: Unexpected token \"${lexemes[result.newIndex].value}\" at position ${result.newIndex}. The VALUES clause is complete but there are additional tokens.`);\r\n }\r\n\r\n return result.value;\r\n }\r\n\r\n public static parseFromLexeme(lexemes: Lexeme[], index: number): { value: ValuesQuery; newIndex: number } {\r\n let idx = index;\r\n\r\n if (lexemes[idx].value.toLowerCase() !== 'values') {\r\n throw new Error(`Syntax error at position ${idx}: Expected 'VALUES' keyword but found \"${lexemes[idx].value}\". VALUES clauses must start with the VALUES keyword.`);\r\n }\r\n idx++;\r\n\r\n if (idx >= lexemes.length) {\r\n throw new Error(`Syntax error: Unexpected end of input after 'VALUES' keyword. The VALUES clause requires at least one tuple expression.`);\r\n }\r\n\r\n const tuples: TupleExpression[] = [];\r\n\r\n // Parse the first tuple\r\n const firstTuple = this.parseTuple(lexemes, idx);\r\n tuples.push(firstTuple.value);\r\n idx = firstTuple.newIndex;\r\n\r\n // Parse additional tuples if they exist\r\n while (idx < lexemes.length && (lexemes[idx].type & TokenType.Comma)) {\r\n idx++; // Skip comma\r\n const tuple = this.parseTuple(lexemes, idx);\r\n tuples.push(tuple.value);\r\n idx = tuple.newIndex;\r\n }\r\n\r\n const query = new ValuesQuery(tuples);\r\n return { value: query, newIndex: idx };\r\n }\r\n\r\n private static parseTuple(lexemes: Lexeme[], index: number): { value: TupleExpression; newIndex: number } {\r\n let idx = index;\r\n\r\n // Check for opening parenthesis\r\n if (idx >= lexemes.length || lexemes[idx].type !== TokenType.OpenParen) {\r\n throw new Error(`Syntax error at position ${idx}: Expected opening parenthesis but found \"${idx < lexemes.length ? lexemes[idx].value : \"end of input\"}\". Tuple expressions in VALUES clause must be enclosed in parentheses.`);\r\n }\r\n idx++;\r\n\r\n // Parse values inside the tuple\r\n const values: ValueComponent[] = [];\r\n\r\n // Parse first value\r\n if (idx >= lexemes.length) {\r\n throw new Error(`Syntax error: Unexpected end of input after opening parenthesis in tuple expression.`);\r\n }\r\n\r\n // Check for empty tuple case\r\n if (lexemes[idx].type & TokenType.CloseParen) {\r\n idx++; // Skip closing parenthesis\r\n return { value: new TupleExpression([]), newIndex: idx };\r\n }\r\n\r\n // Parse the first value\r\n const firstValue = ValueParser.parseFromLexeme(lexemes, idx);\r\n values.push(firstValue.value);\r\n idx = firstValue.newIndex;\r\n\r\n // Parse additional values\r\n while (idx < lexemes.length && (lexemes[idx].type & TokenType.Comma)) {\r\n idx++; // Skip comma\r\n\r\n if (idx >= lexemes.length) {\r\n throw new Error(`Syntax error: Unexpected end of input after comma in tuple expression.`);\r\n }\r\n\r\n const value = ValueParser.parseFromLexeme(lexemes, idx);\r\n values.push(value.value);\r\n idx = value.newIndex;\r\n }\r\n\r\n // Check for closing parenthesis\r\n if (idx >= lexemes.length || lexemes[idx].type !== TokenType.CloseParen) {\r\n throw new Error(`Syntax error at position ${idx}: Expected closing parenthesis but found \"${idx < lexemes.length ? lexemes[idx].value : \"end of input\"}\". Tuple expressions in VALUES clause must be enclosed in parentheses.`);\r\n }\r\n idx++; // Skip closing parenthesis\r\n\r\n return { value: new TupleExpression(values), newIndex: idx };\r\n }\r\n}", "import { FetchClause, FetchType, FetchUnit, FetchExpression } from \"../models/Clause\";\r\nimport { Lexeme } from \"../models/Lexeme\";\r\nimport { LiteralValue, ValueComponent } from \"../models/ValueComponent\";\r\nimport { ValueParser } from \"./ValueParser\";\r\n\r\nexport class FetchClauseParser {\r\n /**\r\n * Parses a FETCH clause from a lexeme array starting at the given index.\r\n * Supports syntax like: FETCH [FIRST|NEXT] <count> ROWS ONLY\r\n * @param lexemes The array of lexemes\r\n * @param index The starting index\r\n * @returns { value: FetchSpecification, newIndex: number }\r\n */\r\n public static parseFromLexeme(lexemes: Lexeme[], index: number): { value: FetchClause; newIndex: number } {\r\n let idx = index;\r\n if (lexemes[idx].value !== 'fetch') {\r\n throw new Error(`Syntax error at position ${idx}: Expected 'FETCH' keyword but found \"${lexemes[idx].value}\".`);\r\n }\r\n idx++;\r\n if (idx >= lexemes.length) {\r\n throw new Error(`Syntax error: Unexpected end of input after 'FETCH' keyword.`);\r\n }\r\n\r\n const fetchExprResult = FetchExpressionParser.parseFromLexeme(lexemes, idx);\r\n const fetchExpr = fetchExprResult.value;\r\n idx = fetchExprResult.newIndex;\r\n\r\n return { value: new FetchClause(fetchExpr), newIndex: idx };\r\n }\r\n}\r\n\r\n// FetchExpressionParser: parses FETCH [FIRST|NEXT] <count> ROWS ONLY ...\r\nexport class FetchExpressionParser {\r\n /**\r\n * Parses a FETCH expression (not the whole clause, just the fetch part)\r\n */\r\n public static parseFromLexeme(lexemes: Lexeme[], index: number): { value: FetchExpression; newIndex: number } {\r\n let idx = index;\r\n let type: FetchType;\r\n const typeToken = lexemes[idx].value;\r\n if (typeToken === 'first') {\r\n type = FetchType.First;\r\n } else if (typeToken === 'next') {\r\n type = FetchType.Next;\r\n } else {\r\n throw new Error(`Syntax error at position ${idx}: Expected 'FIRST' or 'NEXT' after 'FETCH' but found \"${lexemes[idx].value}\".`);\r\n }\r\n idx++;\r\n if (idx >= lexemes.length) {\r\n throw new Error(`Syntax error: Unexpected end of input after 'FETCH FIRST|NEXT'.`);\r\n }\r\n\r\n let count: ValueComponent | null = null;\r\n let unit: FetchUnit | null = null;\r\n\r\n // Omitted count notation\r\n if (lexemes[idx].value === 'row only' || lexemes[idx].value === 'rows only') {\r\n count = new LiteralValue(1);\r\n unit = FetchUnit.RowsOnly;\r\n idx++;\r\n return { value: new FetchExpression(type, count, unit), newIndex: idx };\r\n }\r\n\r\n // <count>\r\n const countResult = ValueParser.parseFromLexeme(lexemes, idx);\r\n count = countResult.value;\r\n idx = countResult.newIndex;\r\n if (idx >= lexemes.length) {\r\n throw new Error(`Syntax error: Unexpected end of input after 'FETCH FIRST|NEXT <count>'.`);\r\n }\r\n // ROWS ONLY (or other unit)\r\n\r\n if (lexemes[idx].value === 'rows only') {\r\n unit = FetchUnit.RowsOnly;\r\n idx++;\r\n } else if (lexemes[idx].value === 'percent') {\r\n unit = FetchUnit.Percent;\r\n idx++;\r\n } else if (lexemes[idx].value === 'percent with ties') {\r\n unit = FetchUnit.PercentWithTies;\r\n idx++;\r\n }\r\n if (!unit) {\r\n throw new Error(`Syntax error: Expected 'ROWS ONLY', 'PERCENT', or 'PERCENT WITH TIES' after 'FETCH FIRST|NEXT <count>'.`);\r\n }\r\n return { value: new FetchExpression(type, count, unit), newIndex: idx };\r\n }\r\n}\r\n", "import { OffsetClause } from \"../models/Clause\";\r\nimport { Lexeme } from \"../models/Lexeme\";\r\nimport { SqlTokenizer } from \"./SqlTokenizer\";\r\nimport { ValueParser } from \"./ValueParser\";\r\n\r\nexport class OffsetClauseParser {\r\n // Parse SQL string to AST (was: parse)\r\n public static parse(query: string): OffsetClause {\r\n const tokenizer = new SqlTokenizer(query); // Initialize tokenizer\r\n const lexemes = tokenizer.readLexmes(); // Get tokens\r\n\r\n // Parse\r\n const result = this.parseFromLexeme(lexemes, 0);\r\n\r\n // Error if there are remaining tokens\r\n if (result.newIndex < lexemes.length) {\r\n throw new Error(`Syntax error: Unexpected token \"${lexemes[result.newIndex].value}\" at position ${result.newIndex}. The OFFSET clause is complete but there are additional tokens.`);\r\n }\r\n\r\n return result.value;\r\n }\r\n\r\n // Parse from lexeme array (was: parse)\r\n public static parseFromLexeme(lexemes: Lexeme[], index: number): { value: OffsetClause; newIndex: number } {\r\n let idx = index;\r\n\r\n if (lexemes[idx].value !== 'offset') {\r\n throw new Error(`Syntax error at position ${idx}: Expected 'OFFSET' keyword but found \"${lexemes[idx].value}\". OFFSET clauses must start with the OFFSET keyword.`);\r\n }\r\n idx++;\r\n\r\n if (idx >= lexemes.length) {\r\n throw new Error(`Syntax error: Unexpected end of input after 'OFFSET' keyword. The OFFSET clause requires a numeric expression.`);\r\n }\r\n\r\n // Parse OFFSET value\r\n const offsetItem = ValueParser.parseFromLexeme(lexemes, idx);\r\n idx = offsetItem.newIndex;\r\n\r\n // If there is a \"row\" or \"rows\" command, skip it\r\n if (idx < lexemes.length && (lexemes[idx].value === 'row' || lexemes[idx].value === 'rows')) {\r\n idx++;\r\n }\r\n\r\n const clause = new OffsetClause(offsetItem.value);\r\n\r\n return { value: clause, newIndex: idx };\r\n }\r\n}\r\n", "import { Lexeme } from \"../models/Lexeme\";\r\nimport { BinarySelectQuery, SelectQuery, SimpleSelectQuery } from \"../models/SelectQuery\";\r\nimport { SelectClauseParser } from \"./SelectClauseParser\";\r\nimport { FromClauseParser } from \"./FromClauseParser\";\r\nimport { WhereClauseParser } from \"./WhereClauseParser\";\r\nimport { GroupByClauseParser } from \"./GroupByParser\";\r\nimport { HavingClauseParser } from \"./HavingParser\";\r\nimport { OrderByClauseParser } from \"./OrderByClauseParser\";\r\nimport { WindowClauseParser } from \"./WindowClauseParser\";\r\nimport { LimitClauseParser } from \"./LimitClauseParser\";\r\nimport { ForClauseParser } from \"./ForClauseParser\";\r\nimport { SqlTokenizer } from \"./SqlTokenizer\";\r\nimport { WithClauseParser } from \"./WithClauseParser\";\r\nimport { ValuesQueryParser } from \"./ValuesQueryParser\";\r\nimport { FetchClauseParser } from \"./FetchClauseParser\";\r\nimport { OffsetClauseParser } from \"./OffsetClauseParser\";\r\n\r\nexport class SelectQueryParser {\r\n // Parse SQL string to AST (was: parse)\r\n public static parse(query: string): SelectQuery {\r\n const tokenizer = new SqlTokenizer(query);\r\n const lexemes = tokenizer.readLexmes();\r\n\r\n // Parse\r\n const result = this.parseFromLexeme(lexemes, 0);\r\n\r\n // Error if there are remaining tokens\r\n if (result.newIndex < lexemes.length) {\r\n throw new Error(`[SelectQueryParser] Syntax error: Unexpected token \"${lexemes[result.newIndex].value}\" at position ${result.newIndex}. The SELECT query is complete but there are additional tokens.`);\r\n }\r\n\r\n return result.value;\r\n }\r\n\r\n /**\r\n * Asynchronously parse SQL string to AST.\r\n * This method wraps the synchronous parse logic in a Promise for future extensibility.\r\n * @param query SQL string to parse\r\n * @returns Promise<SelectQuery>\r\n */\r\n public static async parseAsync(query: string): Promise<SelectQuery> {\r\n // For now, just wrap the sync parse in a resolved Promise\r\n return Promise.resolve(this.parse(query));\r\n }\r\n\r\n private static unionCommandSet = new Set<string>([\r\n \"union\",\r\n \"union all\",\r\n \"intersect\",\r\n \"intersect all\",\r\n \"except\",\r\n \"except all\",\r\n ]);\r\n private static selectCommandSet = new Set<string>([\"with\", \"select\"]);\r\n\r\n // Parse from lexeme array (was: parse)\r\n public static parseFromLexeme(lexemes: Lexeme[], index: number): { value: SelectQuery; newIndex: number } {\r\n let idx = index;\r\n\r\n if (idx >= lexemes.length) {\r\n throw new Error(`Syntax error: Unexpected end of input at position ${index}.`);\r\n }\r\n\r\n // Check if the first token is a SELECT keyword or VALUES\r\n const firstToken = lexemes[idx].value;\r\n if (!this.selectCommandSet.has(firstToken) && firstToken !== 'values') {\r\n throw new Error(`Syntax error at position ${idx}: Expected 'SELECT' or 'VALUES' keyword but found \"${lexemes[idx].value}\".`);\r\n }\r\n\r\n let firstResult = this.selectCommandSet.has(firstToken)\r\n ? this.parseSimpleSelectQuery(lexemes, idx)\r\n : this.parseValuesQuery(lexemes, idx);\r\n\r\n let query: SelectQuery = firstResult.value;\r\n idx = firstResult.newIndex;\r\n\r\n // check 'union'\r\n while (idx < lexemes.length && this.unionCommandSet.has(lexemes[idx].value.toLowerCase())) {\r\n const operator = lexemes[idx].value.toLowerCase();\r\n idx++;\r\n if (idx >= lexemes.length) {\r\n throw new Error(`Syntax error at position ${idx}: Expected a query after '${operator.toUpperCase()}' but found end of input.`);\r\n }\r\n\r\n const nextToken = lexemes[idx].value.toLowerCase();\r\n if (this.selectCommandSet.has(nextToken)) {\r\n const result = this.parseSimpleSelectQuery(lexemes, idx);\r\n query = new BinarySelectQuery(query, operator, result.value);\r\n idx = result.newIndex;\r\n } else if (nextToken === 'values') {\r\n const result = this.parseValuesQuery(lexemes, idx);\r\n query = new BinarySelectQuery(query, operator, result.value);\r\n idx = result.newIndex;\r\n } else {\r\n throw new Error(`Syntax error at position ${idx}: Expected 'SELECT' or 'VALUES' after '${operator.toUpperCase()}' but found \"${lexemes[idx].value}\".`);\r\n }\r\n }\r\n\r\n return { value: query, newIndex: idx };\r\n }\r\n\r\n private static parseSimpleSelectQuery(lexemes: Lexeme[], index: number): { value: SimpleSelectQuery; newIndex: number } {\r\n let idx = index;\r\n let withClauseResult = null;\r\n\r\n // Parse optional WITH clause\r\n if (idx < lexemes.length && lexemes[idx].value === 'with') {\r\n withClauseResult = WithClauseParser.parseFromLexeme(lexemes, idx);\r\n idx = withClauseResult.newIndex;\r\n }\r\n\r\n // Parse SELECT clause (required)\r\n if (idx >= lexemes.length || lexemes[idx].value !== 'select') {\r\n throw new Error(`Syntax error at position ${idx}: Expected 'SELECT' keyword but found \"${idx < lexemes.length ? lexemes[idx].value : 'end of input'}\". SELECT queries must start with the SELECT keyword.`);\r\n }\r\n\r\n const selectClauseResult = SelectClauseParser.parseFromLexeme(lexemes, idx);\r\n idx = selectClauseResult.newIndex;\r\n\r\n // Parse FROM clause (optional)\r\n let fromClauseResult = null;\r\n if (idx < lexemes.length && lexemes[idx].value === 'from') {\r\n fromClauseResult = FromClauseParser.parseFromLexeme(lexemes, idx);\r\n idx = fromClauseResult.newIndex;\r\n }\r\n\r\n // Parse WHERE clause (optional)\r\n let whereClauseResult = null;\r\n if (idx < lexemes.length && lexemes[idx].value === 'where') {\r\n whereClauseResult = WhereClauseParser.parseFromLexeme(lexemes, idx);\r\n idx = whereClauseResult.newIndex;\r\n }\r\n\r\n // Parse GROUP BY clause (optional)\r\n let groupByClauseResult = null;\r\n if (idx < lexemes.length && lexemes[idx].value === 'group by') {\r\n groupByClauseResult = GroupByClauseParser.parseFromLexeme(lexemes, idx);\r\n idx = groupByClauseResult.newIndex;\r\n }\r\n\r\n // Parse HAVING clause (optional)\r\n let havingClauseResult = null;\r\n if (idx < lexemes.length && lexemes[idx].value === 'having') {\r\n havingClauseResult = HavingClauseParser.parseFromLexeme(lexemes, idx);\r\n idx = havingClauseResult.newIndex;\r\n }\r\n\r\n // Parse WINDOW clause (optional)\r\n let windowClauseResult = null;\r\n if (idx < lexemes.length && lexemes[idx].value === 'window') {\r\n windowClauseResult = WindowClauseParser.parseFromLexeme(lexemes, idx);\r\n idx = windowClauseResult.newIndex;\r\n }\r\n\r\n // Parse ORDER BY clause (optional)\r\n let orderByClauseResult = null;\r\n if (idx < lexemes.length && lexemes[idx].value === 'order by') {\r\n orderByClauseResult = OrderByClauseParser.parseFromLexeme(lexemes, idx);\r\n idx = orderByClauseResult.newIndex;\r\n }\r\n\r\n // Parse LIMIT clause (optional)\r\n let limitClauseResult = null;\r\n if (idx < lexemes.length && lexemes[idx].value === 'limit') {\r\n limitClauseResult = LimitClauseParser.parseFromLexeme(lexemes, idx);\r\n idx = limitClauseResult.newIndex;\r\n }\r\n\r\n // Parse OFFSET clause (optional)\r\n let offsetClauseResult = null;\r\n if (idx < lexemes.length && lexemes[idx].value === 'offset') {\r\n offsetClauseResult = OffsetClauseParser.parseFromLexeme(lexemes, idx);\r\n idx = offsetClauseResult.newIndex;\r\n }\r\n\r\n // Parse FETCH clause (optional)\r\n let fetchClauseResult = null;\r\n if (idx < lexemes.length && lexemes[idx].value === 'fetch') {\r\n fetchClauseResult = FetchClauseParser.parseFromLexeme(lexemes, idx);\r\n idx = fetchClauseResult.newIndex;\r\n }\r\n\r\n // Parse FOR clause (optional)\r\n let forClauseResult = null;\r\n if (idx < lexemes.length && lexemes[idx].value.toLowerCase() === 'for') {\r\n forClauseResult = ForClauseParser.parseFromLexeme(lexemes, idx);\r\n idx = forClauseResult.newIndex;\r\n }\r\n\r\n // Create and return the SelectQuery object\r\n const selectQuery = new SimpleSelectQuery({\r\n withClause: withClauseResult ? withClauseResult.value : null,\r\n selectClause: selectClauseResult.value,\r\n fromClause: fromClauseResult ? fromClauseResult.value : null,\r\n whereClause: whereClauseResult ? whereClauseResult.value : null,\r\n groupByClause: groupByClauseResult ? groupByClauseResult.value : null,\r\n havingClause: havingClauseResult ? havingClauseResult.value : null,\r\n orderByClause: orderByClauseResult ? orderByClauseResult.value : null,\r\n windowClause: windowClauseResult ? windowClauseResult.value : null,\r\n limitClause: limitClauseResult ? limitClauseResult.value : null,\r\n offsetClause: offsetClauseResult ? offsetClauseResult.value : null,\r\n fetchClause: fetchClauseResult ? fetchClauseResult.value : null,\r\n forClause: forClauseResult ? forClauseResult.value : null\r\n });\r\n\r\n return { value: selectQuery, newIndex: idx };\r\n }\r\n\r\n private static parseValuesQuery(lexemes: Lexeme[], index: number): { value: SelectQuery; newIndex: number } {\r\n // Use ValuesQueryParser to parse VALUES clause\r\n const result = ValuesQueryParser.parseFromLexeme(lexemes, index);\r\n\r\n // Return the result from ValuesQueryParser directly\r\n return { value: result.value, newIndex: result.newIndex };\r\n }\r\n}", "// filepath: src/parsers/InsertQueryParser.ts\r\n// Provides parsing for INSERT queries, supporting optional columns and WITH/SELECT/VALUES structure.\r\nimport { InsertQuery } from \"../models/InsertQuery\";\r\nimport { Lexeme, TokenType } from \"../models/Lexeme\";\r\nimport { SqlTokenizer } from \"./SqlTokenizer\";\r\nimport { SelectQueryParser } from \"./SelectQueryParser\";\r\nimport { WithClause } from \"../models/Clause\";\r\nimport { WithClauseParser } from \"./WithClauseParser\";\r\nimport { SimpleSelectQuery } from \"../models/SimpleSelectQuery\";\r\nimport { SourceExpressionParser } from \"./SourceExpressionParser\";\r\nimport { InsertClause } from \"../models/Clause\";\r\n\r\nexport class InsertQueryParser {\r\n /**\r\n * Parse SQL string to InsertQuery AST.\r\n * @param query SQL string\r\n */\r\n public static parse(query: string): InsertQuery {\r\n const tokenizer = new SqlTokenizer(query);\r\n const lexemes = tokenizer.readLexmes();\r\n const result = this.parseFromLexeme(lexemes, 0);\r\n if (result.newIndex < lexemes.length) {\r\n throw new Error(`Syntax error: Unexpected token \"${lexemes[result.newIndex].value}\" at position ${result.newIndex}. The INSERT query is complete but there are additional tokens.`);\r\n }\r\n return result.value;\r\n }\r\n\r\n /**\r\n * Parse from lexeme array (for internal use and tests)\r\n */\r\n public static parseFromLexeme(lexemes: Lexeme[], index: number): { value: InsertQuery; newIndex: number } {\r\n let idx = index;\r\n\r\n let withclause: WithClause | null = null;\r\n if (lexemes[idx].value === \"with\") {\r\n const result = WithClauseParser.parseFromLexeme(lexemes, idx);\r\n withclause = result.value;\r\n idx = result.newIndex;\r\n }\r\n\r\n // Expect INSERT INTO\r\n if (lexemes[idx].value !== \"insert into\") {\r\n throw new Error(`Syntax error at position ${idx}: Expected 'INSERT INTO' but found '${lexemes[idx].value}'.`);\r\n }\r\n idx++;\r\n\r\n // Parse table and optional alias/schema using SourceExpressionParser\r\n const sourceResult = SourceExpressionParser.parseTableSourceFromLexemes(lexemes, idx);\r\n idx = sourceResult.newIndex;\r\n\r\n // Optional columns\r\n let columns: string[] = [];\r\n if (lexemes[idx]?.type === TokenType.OpenParen) {\r\n idx++;\r\n while (idx < lexemes.length && lexemes[idx].type === TokenType.Identifier) {\r\n columns.push(lexemes[idx].value);\r\n idx++;\r\n if (lexemes[idx]?.type === TokenType.Comma) {\r\n idx++;\r\n } else {\r\n break;\r\n }\r\n }\r\n if (lexemes[idx]?.type !== TokenType.CloseParen) {\r\n throw new Error(`Syntax error at position ${idx}: Expected ')' after column list.`);\r\n }\r\n idx++;\r\n }\r\n\r\n const selectResult = SelectQueryParser.parseFromLexeme(lexemes, idx);\r\n if (withclause) {\r\n if (selectResult.value instanceof SimpleSelectQuery) {\r\n selectResult.value.withClause = withclause;\r\n } else {\r\n throw new Error(`WITH clause is not supported in this context.`);\r\n }\r\n }\r\n\r\n idx = selectResult.newIndex;\r\n return {\r\n value: new InsertQuery({\r\n insertClause: new InsertClause(sourceResult.value, columns),\r\n selectQuery: selectResult.value\r\n }),\r\n newIndex: idx\r\n };\r\n }\r\n}\r\n", "import { CommonTable, SourceAliasExpression, SelectItem, SelectClause, FromClause, SourceExpression, TableSource } from '../models/Clause';\r\nimport { SimpleSelectQuery } from '../models/SimpleSelectQuery';\r\nimport { IdentifierString, ValueComponent, ColumnReference, FunctionCall, ValueList, LiteralValue, BinaryExpression, CaseExpression, SwitchCaseArgument, CaseKeyValuePair, RawString } from '../models/ValueComponent';\r\nimport { JsonMapping } from './PostgresJsonQueryBuilder';\r\n\r\n/**\r\n * Entity with processing metadata\r\n */\r\nexport interface ProcessableEntity {\r\n id: string;\r\n name: string;\r\n columns: { [jsonKey: string]: string };\r\n isRoot: boolean;\r\n propertyName: string;\r\n // For nested entities\r\n parentId?: string;\r\n relationshipType?: \"object\" | \"array\";\r\n}\r\n\r\n/**\r\n * JSON column mapping information\r\n */\r\nexport interface JsonColumnMapping {\r\n entityId: string;\r\n entityName: string;\r\n generatedColumnName: string; // \"customer_json_1\", \"address_json_2\" \u306A\u3069\r\n depth: number;\r\n}\r\n\r\n/**\r\n * Result from CTE builder including column mappings\r\n */\r\nexport interface CteBuilderResult {\r\n ctes: CommonTable[];\r\n lastCteAlias: string;\r\n columnMappings: JsonColumnMapping[];\r\n}\r\n\r\n/**\r\n * Information for object entity processing\r\n */\r\ninterface ObjectEntityProcessingInfo {\r\n entity: ProcessableEntity;\r\n depth: number;\r\n}\r\n\r\n/**\r\n * PostgreSQL-specific builder for creating CTEs for object entities (object relationships).\r\n * This class handles the creation of CTEs that build JSON/JSONB objects for object entities,\r\n * processing them from the deepest level up to ensure proper dependency ordering.\r\n * \r\n * Features:\r\n * - Depth-based CTE naming (cte_object_depth_N)\r\n * - NULL handling for entity columns\r\n * - JSONB/JSON object construction\r\n * - Hierarchical processing of nested objects\r\n * \r\n * Why depth calculation is critical:\r\n * 1. Object entities can be nested at multiple levels. We must process the deepest\r\n * (most distant) objects first to ensure their JSON representations are available\r\n * when building their parent entities.\r\n * 2. Object entity processing is essentially a column compression operation. Entities\r\n * at the same depth level can be processed simultaneously since they don't depend\r\n * on each other.\r\n * \r\n * Example hierarchy:\r\n * Order (root, depth 0)\r\n * \u2514\u2500 Customer (depth 1)\r\n * \u2514\u2500 Address (depth 2)\r\n * \u2514\u2500 Shipping (depth 1)\r\n * \u2514\u2500 Carrier (depth 2)\r\n * \r\n * Processing order: depth 2 \u2192 depth 1 \u2192 depth 0\r\n */\r\nexport class PostgresObjectEntityCteBuilder { // Constants for consistent naming conventions\r\n private static readonly CTE_OBJECT_PREFIX = 'cte_object_depth_';\r\n private static readonly WILDCARD_COLUMN = '*';\r\n \r\n // Simple counter for unique JSON column names\r\n private jsonColumnCounter = 0;\r\n // Map entity ID to generated JSON column name\r\n private entityToJsonColumnMap = new Map<string, string>();\r\n // Column mappings for external use\r\n private columnMappings: JsonColumnMapping[] = []; \r\n \r\n /**\r\n * Build CTEs for all object entities in the correct dependency order\r\n * @param initialCte The starting CTE containing all raw data\r\n * @param allEntities Map of all entities in the mapping\r\n * @param mapping The JSON mapping configuration\r\n * @returns Array of CTEs and the alias of the last CTE created\r\n */\r\n public buildObjectEntityCtes(\r\n initialCte: CommonTable,\r\n allEntities: Map<string, ProcessableEntity>,\r\n mapping: JsonMapping\r\n ): CteBuilderResult {\r\n \r\n // Reset counter and mapping for each query\r\n this.jsonColumnCounter = 0;\r\n this.entityToJsonColumnMap.clear();\r\n this.columnMappings = [];\r\n \r\n const ctes: CommonTable[] = [initialCte];\r\n let previousCteAlias = initialCte.aliasExpression.table.name; // Collect and sort object entities by depth\r\n const objectEntityInfos = this.collectAndSortObjectEntities(mapping, allEntities);\r\n\r\n // Group entities by depth\r\n const entitiesByDepth = this.groupEntitiesByDepth(objectEntityInfos);\r\n\r\n // Process each depth level, starting from the deepest\r\n const depths = Array.from(entitiesByDepth.keys()).sort((a, b) => b - a);\r\n\r\n for (const depth of depths) {\r\n const entitiesAtDepth = entitiesByDepth.get(depth)!;\r\n const cteAlias = `${PostgresObjectEntityCteBuilder.CTE_OBJECT_PREFIX}${depth}`;\r\n\r\n // Build CTE for all entities at this depth\r\n const cte = this.buildDepthCte(\r\n entitiesAtDepth,\r\n previousCteAlias,\r\n cteAlias,\r\n mapping,\r\n allEntities\r\n );\r\n\r\n ctes.push(cte);\r\n previousCteAlias = cteAlias;\r\n }\r\n\r\n return { \r\n ctes, \r\n lastCteAlias: previousCteAlias,\r\n columnMappings: this.columnMappings\r\n };\r\n }\r\n \r\n /**\r\n * Generate unique JSON column name with entity name and counter\r\n */\r\n private generateUniqueJsonColumnName(entityName: string, entityId: string, depth: number): string {\r\n this.jsonColumnCounter++;\r\n const columnName = `${entityName.toLowerCase()}_json_${this.jsonColumnCounter}`;\r\n \r\n \r\n // Record mapping information for external use\r\n this.columnMappings.push({\r\n entityId,\r\n entityName,\r\n generatedColumnName: columnName,\r\n depth\r\n });\r\n \r\n return columnName;\r\n } /**\r\n * Collect all object entities and calculate their depth from root.\r\n * \r\n * Depth calculation is crucial because:\r\n * - It determines the processing order (deepest first)\r\n * - It ensures dependencies are resolved before an entity is processed\r\n * - It allows parallel processing of entities at the same depth level\r\n * \r\n * @param mapping The JSON mapping configuration\r\n * @param allEntities Map of all entities in the mapping\r\n * @returns Array of object entity information with calculated depths\r\n */\r\n private collectAndSortObjectEntities(\r\n mapping: JsonMapping,\r\n allEntities: Map<string, ProcessableEntity>): ObjectEntityProcessingInfo[] {\r\n const objectInfos: ObjectEntityProcessingInfo[] = [];\r\n\r\n // Helper function to calculate actual object nesting depth for a given OBJECT entity\r\n const calculateActualObjectNestingDepth = (entityIdOfObject: string): number => {\r\n const initialEntity = allEntities.get(entityIdOfObject);\r\n if (!initialEntity) {\r\n throw new Error(`Entity ${entityIdOfObject} not found for depth calculation.`);\r\n }\r\n // If the object itself is root, its depth is 0. (This function should ideally be called for nested entities, not the root itself as a \"parent CTE\" subject)\r\n if (initialEntity.isRoot) return 0;\r\n\r\n // If the object is not root and has no parentId, it's considered a top-level object, depth 1.\r\n if (!initialEntity.parentId) {\r\n return 1;\r\n }\r\n\r\n let currentParentIdInHierarchy: string | undefined = initialEntity.parentId;\r\n let calculatedObjectDepth = 0;\r\n const visitedInPath = new Set<string>();\r\n visitedInPath.add(entityIdOfObject); // Add the starting object itself to detect cycles\r\n\r\n while (currentParentIdInHierarchy) {\r\n if (visitedInPath.has(currentParentIdInHierarchy)) {\r\n throw new Error(`Circular dependency detected: ${currentParentIdInHierarchy} already visited in path for ${entityIdOfObject}`);\r\n }\r\n visitedInPath.add(currentParentIdInHierarchy);\r\n\r\n const parentEntityData = allEntities.get(currentParentIdInHierarchy);\r\n if (!parentEntityData) {\r\n throw new Error(`Parent entity ${currentParentIdInHierarchy} not found during depth calculation for ${entityIdOfObject}`);\r\n }\r\n\r\n let parentIsConsideredAnObjectForNesting = false;\r\n if (parentEntityData.isRoot) {\r\n parentIsConsideredAnObjectForNesting = true; // Root counts as an object ancestor\r\n } else {\r\n // For non-root parents, find their definition in nestedEntities to check their type\r\n const parentDefinition = mapping.nestedEntities.find(ne => ne.id === currentParentIdInHierarchy);\r\n if (parentDefinition) {\r\n if (parentDefinition.relationshipType === \"object\") {\r\n parentIsConsideredAnObjectForNesting = true;\r\n }\r\n // If parentDefinition.relationshipType === \"array\", it's not an object ancestor for depth counting\r\n } else {\r\n // This implies currentParentIdInHierarchy refers to an entity not defined as root or in nestedEntities\r\n // This should ideally not happen with a consistent mapping.\r\n throw new Error(`Parent entity ${currentParentIdInHierarchy} (ancestor of ${entityIdOfObject}) has no definition in mapping.nestedEntities and is not root.`);\r\n }\r\n }\r\n\r\n if (parentIsConsideredAnObjectForNesting) {\r\n calculatedObjectDepth++;\r\n }\r\n\r\n if (parentEntityData.isRoot) {\r\n break; // Stop when the root is processed as the highest object ancestor\r\n }\r\n currentParentIdInHierarchy = parentEntityData.parentId; // Move to the next ancestor\r\n }\r\n return calculatedObjectDepth;\r\n };\r\n\r\n mapping.nestedEntities.forEach(nestedEntity => {\r\n if (nestedEntity.relationshipType === \"object\") {\r\n const entity = allEntities.get(nestedEntity.id);\r\n // Ensure we don't process the root entity itself as a \"parent\" CTE,\r\n // and that the entity actually exists.\r\n if (entity && !entity.isRoot) {\r\n objectInfos.push({\r\n entity,\r\n depth: calculateActualObjectNestingDepth(nestedEntity.id)\r\n });\r\n }\r\n }\r\n });\r\n\r\n // The existing grouping and sorting by depth (b - a for descending) should still work correctly\r\n // as it processes deepest levels first, regardless of the absolute depth numbers.\r\n return objectInfos;\r\n }\r\n\r\n /**\r\n * Group entities by their depth level.\r\n * \r\n * Grouping by depth allows us to:\r\n * - Process all entities at the same level in a single CTE\r\n * - Optimize query performance by reducing the number of CTEs\r\n * - Maintain clear dependency ordering\r\n * \r\n * @param parentInfos Array of parent entity information with depths\r\n * @returns Map of depth level to entities at that depth\r\n */ private groupEntitiesByDepth(\r\n objectInfos: ObjectEntityProcessingInfo[]\r\n ): Map<number, ObjectEntityProcessingInfo[]> {\r\n const entitiesByDepth = new Map<number, ObjectEntityProcessingInfo[]>();\r\n\r\n objectInfos.forEach(info => {\r\n const depth = info.depth;\r\n if (!entitiesByDepth.has(depth)) {\r\n entitiesByDepth.set(depth, []);\r\n }\r\n entitiesByDepth.get(depth)!.push(info);\r\n });\r\n\r\n return entitiesByDepth;\r\n }\r\n\r\n /**\r\n * Build a CTE that processes all entities at a specific depth level\r\n */\r\n private buildDepthCte(\r\n entitiesAtDepth: ObjectEntityProcessingInfo[],\r\n previousCteAlias: string,\r\n cteAlias: string,\r\n mapping: JsonMapping,\r\n allEntities: Map<string, ProcessableEntity>\r\n ): CommonTable {\r\n // Build SELECT items: * and JSON objects for all entities at this depth\r\n const selectItems: SelectItem[] = [\r\n // Select all columns from previous CTE\r\n new SelectItem(new ColumnReference(null, new IdentifierString(PostgresObjectEntityCteBuilder.WILDCARD_COLUMN)))\r\n ];\r\n\r\n // Process each entity at this depth\r\n for (const { entity } of entitiesAtDepth) {\r\n const jsonColumn = this.buildEntityJsonColumn(entity, mapping, allEntities);\r\n selectItems.push(jsonColumn);\r\n }\r\n\r\n // Create CTE that selects from previous CTE\r\n const cteSelect = new SimpleSelectQuery({\r\n selectClause: new SelectClause(selectItems),\r\n fromClause: new FromClause(\r\n new SourceExpression(\r\n new TableSource(null, new IdentifierString(previousCteAlias)),\r\n null\r\n ),\r\n null\r\n )\r\n });\r\n\r\n return new CommonTable(cteSelect, new SourceAliasExpression(cteAlias, null), null);\r\n }\r\n\r\n /**\r\n * Build JSON column for a single entity with NULL handling\r\n */\r\n private buildEntityJsonColumn(\r\n entity: ProcessableEntity,\r\n mapping: JsonMapping,\r\n allEntities: Map<string, ProcessableEntity>\r\n ): SelectItem {\r\n \r\n // Build JSON object arguments and NULL checks\r\n const { jsonObjectArgs, nullChecks } = this.prepareEntityColumns(entity);\r\n\r\n // Add child object relationships\r\n this.addChildObjectRelationships(entity, jsonObjectArgs, mapping, allEntities);\r\n // Create JSON object\r\n const jsonObject = this.createJsonObject(jsonObjectArgs);\r\n\r\n // Build NULL condition and CASE expression\r\n const nullCondition = this.buildNullCondition(nullChecks);\r\n const caseExpr = this.createCaseExpression(nullCondition, jsonObject);\r\n\r\n // Add JSON object as named column with unique name to avoid conflicts\r\n // Calculate depth for this entity (approximate - for mapping purposes)\r\n const depth = this.calculateApproximateDepth(entity, mapping);\r\n const jsonColumnName = this.generateUniqueJsonColumnName(entity.name, entity.id, depth);\r\n // Store mapping for child entity references\r\n this.entityToJsonColumnMap.set(entity.id, jsonColumnName);\r\n return new SelectItem(caseExpr, jsonColumnName);\r\n }\r\n\r\n /**\r\n * Calculate approximate depth for an entity (for mapping purposes)\r\n */\r\n private calculateApproximateDepth(entity: ProcessableEntity, mapping: JsonMapping): number {\r\n if (entity.isRoot) return 0;\r\n if (!entity.parentId) return 1;\r\n \r\n // Simple depth calculation\r\n let depth = 1;\r\n let currentParentId = entity.parentId;\r\n \r\n while (currentParentId && currentParentId !== mapping.rootEntity.id) {\r\n const parentEntity = mapping.nestedEntities.find(e => e.id === currentParentId);\r\n if (!parentEntity) break;\r\n depth++;\r\n currentParentId = parentEntity.parentId;\r\n }\r\n \r\n return depth;\r\n }\r\n\r\n /**\r\n * Prepare entity columns and NULL checks.\r\n * \r\n * This method extracts column data and creates NULL checks for each column.\r\n * The NULL checking is essential for handling outer joins correctly.\r\n * \r\n * In outer join scenarios, when there's no matching row in the joined table,\r\n * all columns from that table will be NULL. Instead of creating an empty object\r\n * with all NULL properties (e.g., {id: null, name: null, email: null}),\r\n * we want to represent the absence of the entity as NULL itself.\r\n * \r\n * This ensures cleaner JSON output where missing relationships are represented\r\n * as NULL rather than objects with all NULL fields.\r\n * \r\n * @param entity The entity whose columns are being processed\r\n * @returns Object containing arrays of JSON object arguments and NULL check conditions\r\n */\r\n private prepareEntityColumns(entity: ProcessableEntity): {\r\n jsonObjectArgs: ValueComponent[],\r\n nullChecks: ValueComponent[]\r\n } {\r\n const jsonObjectArgs: ValueComponent[] = [];\r\n const nullChecks: ValueComponent[] = [];\r\n\r\n Object.entries(entity.columns).forEach(([jsonKey, sqlColumn]) => {\r\n jsonObjectArgs.push(new LiteralValue(jsonKey));\r\n jsonObjectArgs.push(new ColumnReference(null, new IdentifierString(sqlColumn)));\r\n\r\n // Collect NULL checks for each column\r\n nullChecks.push(\r\n new BinaryExpression(\r\n new ColumnReference(null, new IdentifierString(sqlColumn)),\r\n \"is\",\r\n new LiteralValue(null)\r\n )\r\n );\r\n });\r\n\r\n return { jsonObjectArgs, nullChecks };\r\n }\r\n\r\n /**\r\n * Add child object relationships to JSON object arguments.\r\n * \r\n * This method processes nested object-type entities that are direct children of the current entity.\r\n * For each child entity, it adds the property name and corresponding JSON column reference\r\n * to the arguments array that will be used to build the parent's JSON object.\r\n * \r\n * The child JSON columns are expected to already exist in the data source (created by deeper\r\n * level CTEs), as we process from the deepest level up to the root.\r\n * \r\n * Note: In this context, \"child\" refers to entities that have an object relationship (0..1)\r\n * with their parent. From a data perspective, these are typically entities referenced via\r\n * foreign keys, representing \"parent\" entities in traditional database terminology.\r\n * \r\n * @param entity The current entity being processed\r\n * @param jsonObjectArgs Array to which JSON object arguments will be added\r\n * @param mapping The JSON mapping configuration\r\n * @param allEntities Map of all entities in the mapping\r\n */\r\n private addChildObjectRelationships(\r\n entity: ProcessableEntity,\r\n jsonObjectArgs: ValueComponent[],\r\n mapping: JsonMapping,\r\n allEntities: Map<string, ProcessableEntity>\r\n ): void {\r\n const childEntities = mapping.nestedEntities.filter(ne =>\r\n ne.parentId === entity.id && ne.relationshipType === \"object\"\r\n );\r\n\r\n childEntities.forEach(childEntity => {\r\n const child = allEntities.get(childEntity.id);\r\n if (child) {\r\n jsonObjectArgs.push(new LiteralValue(childEntity.propertyName));\r\n // Use mapped JSON column name to avoid conflicts\r\n const jsonColumnName = this.entityToJsonColumnMap.get(child.id);\r\n if (!jsonColumnName) {\r\n throw new Error(`JSON column name not found for child entity: ${child.id}`);\r\n }\r\n jsonObjectArgs.push(new ColumnReference(null, new IdentifierString(jsonColumnName)));\r\n }\r\n });\r\n }\r\n\r\n /**\r\n * Create JSON object function call\r\n */\r\n private createJsonObject(args: ValueComponent[]): FunctionCall {\r\n const jsonBuildFunction = \"jsonb_build_object\";\r\n // Always use JSONB\r\n return new FunctionCall(\r\n null,\r\n new RawString(jsonBuildFunction),\r\n new ValueList(args),\r\n null\r\n );\r\n }\r\n\r\n /**\r\n * Build NULL condition from NULL checks\r\n */\r\n private buildNullCondition(nullChecks: ValueComponent[]): ValueComponent {\r\n return nullChecks.reduce((acc, check) =>\r\n acc ? new BinaryExpression(acc, \"and\", check) : check\r\n );\r\n }\r\n\r\n /**\r\n * Create CASE expression with NULL handling\r\n */\r\n private createCaseExpression(nullCondition: ValueComponent, jsonObject: ValueComponent): CaseExpression {\r\n return new CaseExpression(\r\n null,\r\n new SwitchCaseArgument(\r\n [new CaseKeyValuePair(nullCondition, new LiteralValue(null))],\r\n jsonObject // ELSE return the JSON object\r\n )\r\n );\r\n }\r\n}\r\n", "import { CommonTable, SourceAliasExpression, SelectItem, SelectClause, FromClause, SourceExpression, TableSource, GroupByClause } from '../models/Clause';\r\nimport { SimpleSelectQuery } from '../models/SimpleSelectQuery';\r\nimport { IdentifierString, ValueComponent, ColumnReference, FunctionCall, ValueList, LiteralValue, RawString, CastExpression, TypeValue } from '../models/ValueComponent';\r\nimport { JsonMapping } from './PostgresJsonQueryBuilder';\r\nimport { ProcessableEntity, JsonColumnMapping } from './PostgresObjectEntityCteBuilder';\r\nimport { SelectValueCollector } from './SelectValueCollector';\r\n\r\n/**\r\n * Information for array entity processing\r\n */\r\ninterface ArrayEntityProcessingInfo {\r\n entity: ProcessableEntity;\r\n parentEntity: ProcessableEntity;\r\n parentIdColumnSqlName: string;\r\n depth: number;\r\n}\r\n\r\n/**\r\n * Builds CTEs for array entities using depth-first processing and row compression.\r\n * \r\n * Core concepts:\r\n * - Column Compression: OBJECT relationships (user_id, user_name \u2192 user_json)\r\n * - Row Compression: ARRAY relationships (multiple rows \u2192 JSON array via GROUP BY)\r\n * - Depth-First: Process deepest arrays first for dependency ordering\r\n * - GROUP BY Exclusion: Exclude array-internal columns to prevent over-grouping\r\n */\r\nexport class PostgresArrayEntityCteBuilder {\r\n // Constants for consistent naming conventions\r\n private static readonly CTE_ARRAY_PREFIX = 'cte_array_depth_';\r\n \r\n // JSON function names for PostgreSQL aggregation\r\n private static readonly JSON_FUNCTIONS = {\r\n BUILD_OBJECT: 'jsonb_build_object',\r\n AGGREGATE: 'jsonb_agg'\r\n } as const;\r\n\r\n /**\r\n * Builds CTEs for all array entities using depth-first processing.\r\n * Collects arrays by depth, processes deepest first, chains CTEs.\r\n * \r\n * @param ctesSoFar Array of CTEs built so far\r\n * @param aliasOfCteToBuildUpon Alias of the CTE to build upon\r\n * @param allEntities Map of all entities in the mapping\r\n * @param mapping The JSON mapping configuration\r\n * @param columnMappings Optional mappings from object entity IDs to generated JSON column names\r\n * @returns Object containing updated CTEs and last CTE alias\r\n */\r\n public buildArrayEntityCtes(\r\n ctesSoFar: CommonTable[],\r\n aliasOfCteToBuildUpon: string,\r\n allEntities: Map<string, ProcessableEntity>,\r\n mapping: JsonMapping,\r\n columnMappings?: JsonColumnMapping[]\r\n ): { updatedCtes: CommonTable[], lastCteAlias: string } {\r\n let currentCtes = [...ctesSoFar];\r\n let currentCteAlias = aliasOfCteToBuildUpon;\r\n\r\n // Collect and sort array entities by depth\r\n const sortedArrayInfos = this.collectAndSortArrayEntities(mapping, allEntities);\r\n\r\n if (sortedArrayInfos.length === 0) {\r\n return { updatedCtes: currentCtes, lastCteAlias: currentCteAlias };\r\n }\r\n\r\n // Group array entities by depth level for batch processing\r\n const entitiesByDepth = this.groupEntitiesByDepth(sortedArrayInfos);\r\n\r\n // Process from deepest to shallowest (depth-first)\r\n const depths = Array.from(entitiesByDepth.keys()).sort((a, b) => b - a);\r\n\r\n for (const depth of depths) {\r\n const infos = entitiesByDepth.get(depth)!;\r\n\r\n // Build CTE for all entities at this depth\r\n const { cte, newCteAlias } = this.buildDepthCte(\r\n infos,\r\n currentCteAlias,\r\n currentCtes,\r\n depth,\r\n mapping,\r\n columnMappings\r\n );\r\n\r\n currentCtes.push(cte);\r\n currentCteAlias = newCteAlias;\r\n }\r\n\r\n return { updatedCtes: currentCtes, lastCteAlias: currentCteAlias };\r\n }\r\n\r\n /**\r\n * Collects array entities and calculates depth for dependency ordering.\r\n * Depth = distance from root. Deeper arrays processed first.\r\n * \r\n * @param mapping The JSON mapping configuration\r\n * @param allEntities Map of all entities in the mapping\r\n * @returns Array of array entity information with depths, sorted deepest first\r\n */\r\n private collectAndSortArrayEntities(\r\n mapping: JsonMapping,\r\n allEntities: Map<string, ProcessableEntity>\r\n ): ArrayEntityProcessingInfo[] {\r\n const arrayEntityInfos: ArrayEntityProcessingInfo[] = [];\r\n\r\n // Helper function to calculate depth for an entity\r\n const getDepth = (entityId: string): number => {\r\n const entity = allEntities.get(entityId);\r\n if (!entity || entity.isRoot) return 0;\r\n if (!entity.parentId) return 1;\r\n return 1 + getDepth(entity.parentId);\r\n };\r\n\r\n // Collect all array-type nested entities\r\n mapping.nestedEntities.forEach(ne => {\r\n if (ne.relationshipType === \"array\") {\r\n const currentArrayEntity = allEntities.get(ne.id);\r\n const parentEntity = allEntities.get(ne.parentId!);\r\n\r\n if (!currentArrayEntity || !parentEntity) {\r\n throw new Error(`Configuration error: Array entity '${ne.id}' or its parent '${ne.parentId}' not found.`);\r\n }\r\n\r\n // Determine the linking column from parent entity\r\n // This assumes the first column of the parent is a suitable key for linking.\r\n // More robust linking might require explicit configuration in the mapping.\r\n const parentSqlColumns = Object.values(parentEntity.columns);\r\n if (parentSqlColumns.length === 0) {\r\n throw new Error(`Configuration error: Parent entity '${parentEntity.name}' (ID: ${parentEntity.id}) must have at least one column defined to serve as a linking key for child array '${ne.name}'.`);\r\n }\r\n const parentIdColumnSqlName = parentSqlColumns[0];\r\n\r\n arrayEntityInfos.push({\r\n entity: currentArrayEntity,\r\n parentEntity: parentEntity,\r\n parentIdColumnSqlName: parentIdColumnSqlName,\r\n depth: getDepth(ne.id)\r\n });\r\n }\r\n });\r\n\r\n // Sort by depth, deepest arrays (higher depth number) processed first (bottom-up for arrays)\r\n arrayEntityInfos.sort((a, b) => b.depth - a.depth);\r\n return arrayEntityInfos;\r\n }\r\n\r\n /**\r\n * Groups array entities by depth level for batch processing.\r\n * \r\n * @param arrayInfos Array of array entity information with depths\r\n * @returns Map of depth level to entities at that depth\r\n */\r\n private groupEntitiesByDepth(\r\n arrayInfos: ArrayEntityProcessingInfo[]\r\n ): Map<number, ArrayEntityProcessingInfo[]> {\r\n const entitiesByDepth = new Map<number, ArrayEntityProcessingInfo[]>();\r\n\r\n arrayInfos.forEach(info => {\r\n const depth = info.depth;\r\n if (!entitiesByDepth.has(depth)) {\r\n entitiesByDepth.set(depth, []);\r\n }\r\n entitiesByDepth.get(depth)!.push(info);\r\n });\r\n\r\n return entitiesByDepth;\r\n }\r\n\r\n /**\r\n * Builds CTE for specific depth level using row compression.\r\n * Uses GROUP BY to aggregate multiple rows into JSON arrays.\r\n * Excludes array-internal columns from GROUP BY to prevent over-grouping.\r\n * \r\n * @param infos Array entities at this depth level\r\n * @param currentCteAlias Alias of the CTE to build upon\r\n * @param currentCtes All CTEs built so far\r\n * @param depth Current depth level being processed\r\n * @param mapping JSON mapping configuration\r\n * @param columnMappings Optional mappings from object entity IDs to generated JSON column names\r\n * @returns The new CTE and its alias\r\n */\r\n private buildDepthCte(\r\n infos: ArrayEntityProcessingInfo[],\r\n currentCteAlias: string,\r\n currentCtes: CommonTable[],\r\n depth: number,\r\n mapping: JsonMapping,\r\n columnMappings?: JsonColumnMapping[]\r\n ): { cte: CommonTable, newCteAlias: string } {\r\n // Collect columns that will be compressed into arrays\r\n // This includes both direct columns and columns from nested entities within the array\r\n const arrayColumns = new Set<string>();\r\n infos.forEach(info => {\r\n // Add direct columns from the array entity\r\n Object.values(info.entity.columns).forEach(col => arrayColumns.add(col));\r\n\r\n // Also add columns from all nested entities within this array entity\r\n const collectNestedColumns = (parentEntityId: string) => {\r\n mapping.nestedEntities\r\n .filter(nestedEntity => nestedEntity.parentId === parentEntityId)\r\n .forEach(nestedEntity => {\r\n Object.values(nestedEntity.columns).forEach(column => {\r\n const columnName = typeof column === 'string' ? column : (column as any).column;\r\n arrayColumns.add(columnName);\r\n });\r\n // Recursively collect from deeper nested entities\r\n collectNestedColumns(nestedEntity.id);\r\n });\r\n };\r\n\r\n collectNestedColumns(info.entity.id);\r\n });\r\n\r\n // Get columns from previous CTE\r\n const prevCte = currentCtes.find(c => c.aliasExpression.table.name === currentCteAlias)?.query;\r\n if (!prevCte) {\r\n throw new Error(`CTE not found: ${currentCteAlias}`);\r\n }\r\n const prevSelects = new SelectValueCollector(null, currentCtes).collect(prevCte); // Build SELECT items: columns that are NOT being compressed (for GROUP BY)\r\n const groupByItems: ValueComponent[] = [];\r\n const selectItems: SelectItem[] = [];\r\n\r\n // Get columns from the current level's array entities that will be aggregated\r\n // These should be included in GROUP BY since they're being processed at this level\r\n const currentLevelArrayColumns = new Set<string>();\r\n infos.forEach(info => {\r\n Object.values(info.entity.columns).forEach(col => currentLevelArrayColumns.add(col));\r\n });\r\n\r\n // Collect array entity columns organized by depth for GROUP BY exclusion strategy\r\n const arrayEntityColumns = this.collectArrayEntityColumnsByDepth(mapping, depth);\r\n\r\n // Identify JSON columns from objects within the arrays being processed at this depth\r\n const arrayInternalObjectColumns = new Set<string>();\r\n if (columnMappings) {\r\n infos.forEach(info => {\r\n // Find all object-type nested entities within this array entity\r\n mapping.nestedEntities\r\n .filter(ne => ne.parentId === info.entity.id && ne.relationshipType === \"object\")\r\n .forEach(objectEntity => {\r\n // Find the corresponding JSON column mapping for this object entity\r\n const columnMapping = columnMappings.find(cm => cm.entityId === objectEntity.id);\r\n if (columnMapping) {\r\n arrayInternalObjectColumns.add(columnMapping.generatedColumnName);\r\n }\r\n });\r\n });\r\n }\r\n\r\n // Process existing SELECT variables to determine which should be included in GROUP BY\r\n this.processSelectVariablesForGroupBy(\r\n prevSelects,\r\n arrayColumns,\r\n arrayEntityColumns,\r\n depth,\r\n selectItems,\r\n groupByItems,\r\n arrayInternalObjectColumns\r\n );\r\n\r\n // Add JSON aggregation columns for each array entity at this depth\r\n for (const info of infos) {\r\n const agg = this.buildAggregationDetailsForArrayEntity(\r\n info.entity,\r\n mapping.nestedEntities,\r\n new Map(), // allEntities - not needed for array aggregation\r\n columnMappings\r\n );\r\n selectItems.push(new SelectItem(agg.jsonAgg, info.entity.propertyName));\r\n }\r\n\r\n // Create the new CTE\r\n const cteAlias = `${PostgresArrayEntityCteBuilder.CTE_ARRAY_PREFIX}${depth}`;\r\n const cteSelect = new SimpleSelectQuery({\r\n selectClause: new SelectClause(selectItems),\r\n fromClause: new FromClause(\r\n new SourceExpression(\r\n new TableSource(null, new IdentifierString(currentCteAlias)),\r\n null\r\n ),\r\n null\r\n ),\r\n groupByClause: groupByItems.length > 0 ? new GroupByClause(groupByItems) : null,\r\n });\r\n\r\n const cte = new CommonTable(cteSelect, new SourceAliasExpression(cteAlias, null), null);\r\n\r\n return { cte, newCteAlias: cteAlias };\r\n }\r\n\r\n /**\r\n * Creates jsonb_agg function for array entity.\r\n * Handles entity columns and nested child relationships.\r\n * Uses originalPropertyName to avoid sequential numbering.\r\n * \r\n * @param entity The array entity being processed\r\n * @param nestedEntities All nested entities from the mapping\r\n * @param allEntities Map of all entities (not used in current implementation)\r\n * @param columnMappings Mappings from object entity IDs to generated JSON column names\r\n * @returns Object containing the JSON aggregation function\r\n */\r\n private buildAggregationDetailsForArrayEntity(\r\n entity: ProcessableEntity,\r\n nestedEntities: any[],\r\n allEntities: Map<string, ProcessableEntity>,\r\n columnMappings?: JsonColumnMapping[]\r\n ): { jsonAgg: ValueComponent } {\r\n // Build JSON object for array elements using JSONB functions\r\n const jsonBuildFunction = PostgresArrayEntityCteBuilder.JSON_FUNCTIONS.BUILD_OBJECT;\r\n const args: ValueComponent[] = [];\r\n\r\n // Add the entity's own columns\r\n Object.entries(entity.columns).forEach(([jsonKey, sqlColumn]) => {\r\n args.push(new LiteralValue(jsonKey));\r\n args.push(new ColumnReference(null, new IdentifierString(sqlColumn)));\r\n });\r\n\r\n // Find and process child entities (both object and array types)\r\n const childEntities = nestedEntities.filter((ne) => ne.parentId === entity.id); childEntities.forEach((childEntity) => {\r\n // Use originalPropertyName if available to avoid sequential numbering in final JSON\r\n const propertyNameForJson = (childEntity as any).originalPropertyName || childEntity.propertyName;\r\n args.push(new LiteralValue(propertyNameForJson));\r\n\r\n if (childEntity.relationshipType === \"object\") {\r\n // For object relationships, use pre-computed JSON column from column mappings\r\n if (!columnMappings) {\r\n throw new Error(\r\n `\u274C PostgresArrayEntityCteBuilder Error: Column mappings not provided\\n` +\r\n `\\n` +\r\n `\uD83D\uDD0D Details:\\n` +\r\n ` - Entity ID: ${childEntity.id}\\n` +\r\n ` - Entity Name: ${childEntity.name || 'unknown'}\\n` +\r\n ` - Property Name: ${childEntity.propertyName}\\n` +\r\n ` - Relationship Type: ${childEntity.relationshipType}\\n` +\r\n `\\n` +\r\n `\uD83D\uDCA1 Solution:\\n` +\r\n ` Column mappings are required for hybrid JSON column naming.\\n` +\r\n ` This error indicates that PostgresObjectEntityCteBuilder did not\\n` +\r\n ` pass column mappings to PostgresArrayEntityCteBuilder.\\n` +\r\n `\\n` +\r\n `\uD83D\uDD27 Check:\\n` +\r\n ` 1. Ensure PostgresJsonQueryBuilder.buildJsonWithCteStrategy() passes columnMappings\\n` +\r\n ` 2. Verify PostgresObjectEntityCteBuilder.buildObjectEntityCtes() returns columnMappings\\n` +\r\n ` 3. Check that Model-driven mapping conversion generates unique entity IDs`\r\n );\r\n }\r\n\r\n const mapping = columnMappings.find(m => m.entityId === childEntity.id);\r\n if (!mapping) {\r\n const availableMappings = columnMappings.map(m => `${m.entityId} \u2192 ${m.generatedColumnName}`).join(', ');\r\n throw new Error(\r\n `\u274C PostgresArrayEntityCteBuilder Error: Column mapping not found\\n` +\r\n `\\n` +\r\n `\uD83D\uDD0D Details:\\n` +\r\n ` - Looking for Entity ID: ${childEntity.id}\\n` +\r\n ` - Entity Name: ${childEntity.name || 'unknown'}\\n` +\r\n ` - Property Name: ${childEntity.propertyName}\\n` +\r\n ` - Relationship Type: ${childEntity.relationshipType}\\n` +\r\n `\\n` +\r\n `\uD83D\uDCCB Available Mappings:\\n` +\r\n ` ${availableMappings || 'None'}\\n` +\r\n `\\n` +\r\n `\uD83D\uDCA1 Solution:\\n` +\r\n ` Entity IDs must match between mapping generation and usage.\\n` +\r\n ` This suggests a mismatch in entity ID generation or processing.\\n` +\r\n `\\n` +\r\n `\uD83D\uDD27 Check:\\n` +\r\n ` 1. Model-driven mapping conversion generates consistent entity IDs\\n` +\r\n ` 2. PostgresObjectEntityCteBuilder processes all entities correctly\\n` +\r\n ` 3. Entity hierarchy and parentId relationships are correct`\r\n );\r\n }\r\n args.push(new ColumnReference(null, new IdentifierString(mapping.generatedColumnName)));\r\n } else if (childEntity.relationshipType === \"array\") {\r\n // For array relationships, use the column directly\r\n args.push(new ColumnReference(null, new IdentifierString(childEntity.propertyName)));\r\n }\r\n });\r\n\r\n // Create JSON object\r\n const jsonObject = new FunctionCall(null, new RawString(jsonBuildFunction), new ValueList(args), null);\r\n\r\n // Create JSON aggregation using JSONB with NULL filtering\r\n // Use FILTER clause to exclude rows where primary key is NULL (no actual data)\r\n const jsonAggFunction = PostgresArrayEntityCteBuilder.JSON_FUNCTIONS.AGGREGATE;\r\n\r\n // Find the primary column (typically the first column) to use for NULL filtering\r\n const primaryColumn = Object.values(entity.columns)[0];\r\n\r\n // For now, create standard jsonb_agg and handle NULL filtering in post-processing\r\n // TODO: Implement proper FILTER clause support in SQL AST\r\n const jsonAgg = new FunctionCall(\r\n null,\r\n new RawString(jsonAggFunction),\r\n new ValueList([jsonObject]),\r\n null\r\n );\r\n\r\n return { jsonAgg };\r\n }\r\n\r\n /**\r\n * Collects array entity columns by depth for GROUP BY exclusion strategy.\r\n * \r\n * @param mapping The JSON mapping configuration containing all entities\r\n * @param currentDepth The current aggregation depth being processed\r\n * @returns A map where keys are depth levels and values are sets of column names\r\n */\r\n private collectArrayEntityColumnsByDepth(\r\n mapping: JsonMapping,\r\n currentDepth: number\r\n ): Map<number, Set<string>> {\r\n const arrayEntitiesByDepth = new Map<number, Set<string>>(); // Initialize depth maps for current and deeper levels\r\n // Use a reasonable maximum depth limit to avoid infinite loops\r\n const maxDepth = Math.max(currentDepth + 3, 5);\r\n for (let d = currentDepth; d <= maxDepth; d++) {\r\n arrayEntitiesByDepth.set(d, new Set());\r\n }\r\n\r\n // Process all array entities to collect their columns by depth\r\n mapping.nestedEntities\r\n .filter(entity => entity.relationshipType === 'array')\r\n .forEach(entity => {\r\n // Calculate entity depth in the hierarchy\r\n const entityDepth = this.calculateEntityDepth(entity, mapping);\r\n\r\n if (!arrayEntitiesByDepth.has(entityDepth)) {\r\n arrayEntitiesByDepth.set(entityDepth, new Set());\r\n }\r\n\r\n // Add direct columns from the array entity\r\n this.addEntityColumnsToDepthSet(entity, entityDepth, arrayEntitiesByDepth);\r\n\r\n // Collect columns from all descendant entities recursively\r\n this.collectDescendantColumns(entity.id, entityDepth, mapping, arrayEntitiesByDepth);\r\n });\r\n\r\n return arrayEntitiesByDepth;\r\n }\r\n\r\n /**\r\n * Calculates entity depth by traversing up to root.\r\n * \r\n * @param entity The entity to calculate depth for\r\n * @param mapping The JSON mapping containing all entities\r\n * @returns The depth level (0 for root level, 1 for first level, etc.)\r\n */\r\n private calculateEntityDepth(entity: any, mapping: JsonMapping): number {\r\n let entityDepth = 0;\r\n let currentEntity = entity;\r\n\r\n while (currentEntity.parentId && currentEntity.parentId !== mapping.rootEntity.id) {\r\n entityDepth++;\r\n currentEntity = mapping.nestedEntities.find(e => e.id === currentEntity.parentId) || currentEntity;\r\n }\r\n\r\n return entityDepth;\r\n }\r\n\r\n /**\r\n * Adds entity columns to depth set.\r\n * \r\n * @param entity The entity whose columns should be added\r\n * @param depth The depth level to add columns to\r\n * @param arrayEntitiesByDepth The map to update\r\n */\r\n private addEntityColumnsToDepthSet(\r\n entity: any,\r\n depth: number,\r\n arrayEntitiesByDepth: Map<number, Set<string>>\r\n ): void {\r\n Object.values(entity.columns).forEach(column => {\r\n const columnName = typeof column === 'string' ? column : (column as any).column;\r\n arrayEntitiesByDepth.get(depth)!.add(columnName);\r\n });\r\n }\r\n\r\n /**\r\n * Recursively collects columns from descendant entities.\r\n * \r\n * @param parentEntityId The ID of the parent entity\r\n * @param targetDepth The depth level to assign collected columns to\r\n * @param mapping The JSON mapping containing all entities\r\n * @param arrayEntitiesByDepth The map to update with collected columns\r\n */\r\n private collectDescendantColumns(\r\n parentEntityId: string,\r\n targetDepth: number,\r\n mapping: JsonMapping,\r\n arrayEntitiesByDepth: Map<number, Set<string>>\r\n ): void {\r\n mapping.nestedEntities\r\n .filter(nestedEntity => nestedEntity.parentId === parentEntityId)\r\n .forEach(nestedEntity => {\r\n // Add all columns from this descendant to the target depth\r\n this.addEntityColumnsToDepthSet(nestedEntity, targetDepth, arrayEntitiesByDepth);\r\n\r\n // Recursively collect from deeper nested entities\r\n this.collectDescendantColumns(nestedEntity.id, targetDepth, mapping, arrayEntitiesByDepth);\r\n });\r\n }\r\n\r\n /**\r\n * Implements GROUP BY exclusion strategy for array aggregation.\r\n * Excludes current array columns and array-internal object JSON columns.\r\n * \r\n * @param prevSelects SELECT variables from the previous CTE\r\n * @param arrayColumns Columns that are being aggregated (should be excluded from GROUP BY)\r\n * @param arrayEntitiesByDepth Map of depth levels to their column sets\r\n * @param currentDepth The current aggregation depth being processed\r\n * @param selectItems Output array for SELECT items\r\n * @param groupByItems Output array for GROUP BY items\r\n * @param arrayInternalObjectColumns JSON columns from objects within arrays being processed\r\n */\r\n private processSelectVariablesForGroupBy(\r\n prevSelects: any[],\r\n arrayColumns: Set<string>,\r\n arrayEntitiesByDepth: Map<number, Set<string>>,\r\n currentDepth: number,\r\n selectItems: SelectItem[],\r\n groupByItems: ValueComponent[],\r\n arrayInternalObjectColumns?: Set<string>\r\n ): void {\r\n prevSelects.forEach(sv => {\r\n if (!arrayColumns.has(sv.name)) {\r\n // Exclude JSON columns from objects within arrays being processed\r\n if (arrayInternalObjectColumns && arrayInternalObjectColumns.has(sv.name)) {\r\n // Skip this column - it's an object within the array being aggregated\r\n return;\r\n }\r\n\r\n const shouldInclude = this.shouldIncludeColumnInGroupBy(\r\n sv.name,\r\n arrayEntitiesByDepth,\r\n currentDepth\r\n );\r\n\r\n if (shouldInclude) {\r\n selectItems.push(new SelectItem(\r\n new ColumnReference(null, new IdentifierString(sv.name)),\r\n sv.name\r\n ));\r\n // Exclude JSON columns from GROUP BY as PostgreSQL doesn't support equality operators for JSON type\r\n if (!sv.name.endsWith('_json')) {\r\n groupByItems.push(new ColumnReference(null, new IdentifierString(sv.name)));\r\n }\r\n }\r\n }\r\n });\r\n }\r\n\r\n /**\r\n * Determines if column should be included in GROUP BY clause.\r\n * Applies depth-based filtering and special handling for JSON columns.\r\n * \r\n * @param columnName The name of the column to evaluate\r\n * @param arrayEntitiesByDepth Map of depth levels to their column sets\r\n * @param currentDepth The current aggregation depth\r\n * @returns True if the column should be included in GROUP BY, false otherwise\r\n */\r\n private shouldIncludeColumnInGroupBy(\r\n columnName: string,\r\n arrayEntitiesByDepth: Map<number, Set<string>>,\r\n currentDepth: number\r\n ): boolean {\r\n const isJsonColumn = columnName.endsWith('_json');\r\n let shouldInclude = true;\r\n\r\n // Check if this column belongs to array entities at current depth or deeper\r\n // These columns are being aggregated and should not be in GROUP BY\r\n for (const [entityDepth, columns] of arrayEntitiesByDepth.entries()) {\r\n if (entityDepth >= currentDepth && columns.has(columnName)) {\r\n shouldInclude = false;\r\n break;\r\n }\r\n }\r\n\r\n // Critical: JSON columns from objects within arrays being processed \r\n // must be excluded from GROUP BY as they are aggregated within the array\r\n if (isJsonColumn) {\r\n // Legacy handling for entity_ prefixed JSON columns\r\n if (columnName.startsWith('entity_')) {\r\n shouldInclude = this.shouldIncludeJsonColumn(columnName, currentDepth);\r\n }\r\n }\r\n\r\n return shouldInclude;\r\n }\r\n\r\n /**\r\n * Applies heuristics for entity JSON column inclusion in GROUP BY.\r\n * Uses entity numbering patterns to identify deeply nested entities.\r\n * \r\n * @param columnName The JSON column name (expected format: entity_N_json)\r\n * @param currentDepth The current aggregation depth\r\n * @returns True if the JSON column should be included, false otherwise\r\n */\r\n private shouldIncludeJsonColumn(columnName: string, currentDepth: number): boolean {\r\n const entityMatch = columnName.match(/entity_(\\d+)_json/);\r\n if (!entityMatch) {\r\n return true;\r\n }\r\n\r\n // For depth > 0, exclude JSON columns from highly nested entities\r\n // This heuristic assumes entities with higher numbers are more deeply nested\r\n if (currentDepth > 0) {\r\n const entityNumber = parseInt(entityMatch[1]);\r\n // Entities with numbers > 2 are typically nested within arrays and should be excluded\r\n return entityNumber <= 2;\r\n }\r\n\r\n return true;\r\n }\r\n}\r\n", "import { CommonTable, SourceAliasExpression, SelectItem, SelectClause, FromClause, SourceExpression, TableSource, GroupByClause, WithClause, SubQuerySource, LimitClause } from '../models/Clause';\r\nimport { SimpleSelectQuery } from '../models/SimpleSelectQuery';\r\nimport { SelectQuery } from '../models/SelectQuery';\r\nimport { IdentifierString, ValueComponent, ColumnReference, FunctionCall, ValueList, LiteralValue, BinaryExpression, CaseExpression, SwitchCaseArgument, CaseKeyValuePair, RawString, UnaryExpression } from '../models/ValueComponent';\r\nimport { SelectValueCollector } from \"./SelectValueCollector\";\r\nimport { PostgresObjectEntityCteBuilder, ProcessableEntity, JsonColumnMapping, CteBuilderResult } from './PostgresObjectEntityCteBuilder';\r\nimport { PostgresArrayEntityCteBuilder } from './PostgresArrayEntityCteBuilder';\r\nimport { QueryBuilder } from './QueryBuilder';\r\nimport { QueryBuildOptions } from './DynamicQueryBuilder';\r\n\r\n/**\r\n * Universal JSON mapping definition for creating any level of JSON structures.\r\n * Supports flat arrays, nested objects, and unlimited hierarchical structures.\r\n */\r\nexport interface JsonMapping {\r\n rootName: string;\r\n rootEntity: {\r\n id: string;\r\n name: string;\r\n columns: { [jsonKey: string]: string };\r\n };\r\n nestedEntities: Array<{\r\n id: string;\r\n name: string;\r\n parentId: string;\r\n propertyName: string;\r\n relationshipType?: \"object\" | \"array\";\r\n columns: { [jsonKey: string]: string };\r\n }>;\r\n resultFormat?: \"array\" | \"single\";\r\n emptyResult?: string;\r\n}\r\n\r\n/**\r\n * PostgreSQL JSON query builder that transforms SimpleSelectQuery into queries\r\n * that return JSON arrays or single JSON objects using PostgreSQL JSON functions.\r\n */\r\nexport class PostgresJsonQueryBuilder {\r\n private selectValueCollector: SelectValueCollector;\r\n private objectEntityCteBuilder: PostgresObjectEntityCteBuilder;\r\n private arrayEntityCteBuilder: PostgresArrayEntityCteBuilder;\r\n\r\n constructor() {\r\n this.selectValueCollector = new SelectValueCollector(null);\r\n this.objectEntityCteBuilder = new PostgresObjectEntityCteBuilder();\r\n this.arrayEntityCteBuilder = new PostgresArrayEntityCteBuilder();\r\n }\r\n\r\n /**\r\n * Validates the JSON mapping and the original query.\r\n * @param query Original query to transform\r\n * @param mapping JSON mapping configuration\r\n */\r\n private validateMapping(query: SimpleSelectQuery, mapping: JsonMapping): void {\r\n const collector = new SelectValueCollector();\r\n const selectedValues = collector.collect(query);\r\n\r\n // sv.name is the alias or derived name\r\n const availableColumns = new Set(selectedValues.map(sv => sv.name)); // Check root entity columns\r\n for (const jsonKey in mapping.rootEntity.columns) {\r\n const columnDef = mapping.rootEntity.columns[jsonKey];\r\n // Handle both string and object formats\r\n const sourceColumn = typeof columnDef === 'string' ? columnDef : (columnDef as any).column;\r\n if (!availableColumns.has(sourceColumn)) {\r\n throw new Error(`Validation Error: Column \"${sourceColumn}\" for JSON key \"${jsonKey}\" in root entity \"${mapping.rootEntity.name}\" not found in the query's select list.`);\r\n }\r\n }\r\n\r\n // Check nested entity columns and parent-child relationships\r\n const entityIds = new Set<string>([mapping.rootEntity.id]);\r\n const parentToChildrenMap = new Map<string, string[]>();\r\n\r\n mapping.nestedEntities.forEach(ne => {\r\n entityIds.add(ne.id);\r\n if (!parentToChildrenMap.has(ne.parentId)) {\r\n parentToChildrenMap.set(ne.parentId, []);\r\n }\r\n parentToChildrenMap.get(ne.parentId)!.push(ne.id);\r\n });\r\n\r\n for (const entity of mapping.nestedEntities) {\r\n if (!entityIds.has(entity.parentId)) {\r\n throw new Error(`Validation Error: Parent entity with ID \"${entity.parentId}\" for nested entity \"${entity.name}\" (ID: ${entity.id}) not found.`);\r\n }\r\n\r\n for (const jsonKey in entity.columns) {\r\n const columnDef = entity.columns[jsonKey];\r\n // Handle both string and object formats\r\n const sourceColumn = typeof columnDef === 'string' ? columnDef : (columnDef as any).column;\r\n if (!availableColumns.has(sourceColumn)) {\r\n throw new Error(`Validation Error: Column \"${sourceColumn}\" for JSON key \"${jsonKey}\" in nested entity \"${entity.name}\" (ID: ${entity.id}) not found in the query's select list.`);\r\n }\r\n }\r\n }\r\n\r\n // Validate: An entity should not have multiple direct array children.\r\n // Validate: Child propertyNames under a single parent must be unique.\r\n const allParentIds = new Set([mapping.rootEntity.id, ...mapping.nestedEntities.map(ne => ne.parentId)]);\r\n for (const parentId of allParentIds) {\r\n const directChildren = mapping.nestedEntities.filter(ne => ne.parentId === parentId);\r\n const directArrayChildrenCount = directChildren.filter(c => c.relationshipType === 'array').length;\r\n if (directArrayChildrenCount > 1) {\r\n const parentName = parentId === mapping.rootEntity.id ? mapping.rootEntity.name : mapping.nestedEntities.find(ne => ne.id === parentId)?.name;\r\n throw new Error(`Validation Error: Parent entity \"${parentName}\" (ID: ${parentId}) has multiple direct array children. This is not supported.`);\r\n }\r\n\r\n const propertyNames = new Set<string>();\r\n for (const child of directChildren) {\r\n if (propertyNames.has(child.propertyName)) {\r\n const parentName = parentId === mapping.rootEntity.id ? mapping.rootEntity.name : mapping.nestedEntities.find(ne => ne.id === parentId)?.name;\r\n throw new Error(`Validation Error: Parent entity \"${parentName}\" (ID: ${parentId}) has duplicate property name \"${child.propertyName}\" for its children.`);\r\n }\r\n propertyNames.add(child.propertyName);\r\n }\r\n }\r\n }\r\n\r\n /**\r\n * Build JSON query from original query and mapping configuration.\r\n * @param originalQuery Original query to transform (can be any SelectQuery type)\r\n * @param mapping JSON mapping configuration\r\n * @returns Transformed query with JSON aggregation\r\n */\r\n public buildJsonQuery(originalQuery: SelectQuery, mapping: JsonMapping, options?: QueryBuildOptions): SimpleSelectQuery;\r\n public buildJsonQuery(originalQuery: SimpleSelectQuery, mapping: JsonMapping, options?: QueryBuildOptions): SimpleSelectQuery;\r\n public buildJsonQuery(originalQuery: SelectQuery | SimpleSelectQuery, mapping: JsonMapping, options?: QueryBuildOptions): SimpleSelectQuery {\r\n // Check jsonb option - must be true (or undefined/default) for GROUP BY compatibility\r\n if (options?.jsonb === false) {\r\n throw new Error(\r\n 'JSONB must be enabled for PostgreSQL GROUP BY compatibility. ' +\r\n 'JSON type cannot be used in GROUP BY clauses. ' +\r\n 'Please set jsonb: true or omit the jsonb option (defaults to true).'\r\n );\r\n }\r\n\r\n // Convert any SelectQuery to SimpleSelectQuery using QueryBuilder\r\n const simpleQuery = originalQuery instanceof SimpleSelectQuery\r\n ? originalQuery\r\n : QueryBuilder.buildSimpleQuery(originalQuery);\r\n\r\n return this.buildJsonWithCteStrategy(simpleQuery, mapping);\r\n }\r\n\r\n /**\r\n * Build JSON query from original query and mapping configuration.\r\n * @deprecated Use buildJsonQuery instead. This method will be removed in a future version.\r\n * @param originalQuery Original query to transform\r\n * @param mapping JSON mapping configuration\r\n * @returns Transformed query with JSON aggregation\r\n */\r\n public buildJson(originalQuery: SimpleSelectQuery, mapping: JsonMapping): SimpleSelectQuery {\r\n console.warn('buildJson is deprecated. Use buildJsonQuery instead.');\r\n return this.buildJsonQuery(originalQuery, mapping);\r\n }\r\n\r\n /**\r\n * Builds the JSON structure using a unified CTE-based strategy.\r\n * @param originalQuery Original query\r\n * @param mapping JSON mapping configuration\r\n * @returns Query with CTE-based JSON aggregation\r\n */\r\n private buildJsonWithCteStrategy(\r\n originalQuery: SimpleSelectQuery,\r\n mapping: JsonMapping,\r\n ): SimpleSelectQuery {\r\n this.validateMapping(originalQuery, mapping);\r\n\r\n // Step 1: Create the initial CTE from the original query\r\n const { initialCte, initialCteAlias } = this.createInitialCte(originalQuery);\r\n\r\n let ctesForProcessing: CommonTable[] = [initialCte];\r\n let currentAliasToBuildUpon = initialCteAlias;\r\n\r\n // Step 2: Prepare entity information\r\n const allEntities = new Map<string, ProcessableEntity>();\r\n allEntities.set(mapping.rootEntity.id, { ...mapping.rootEntity, isRoot: true, propertyName: mapping.rootName });\r\n mapping.nestedEntities.forEach(ne => allEntities.set(ne.id, { ...ne, isRoot: false, propertyName: ne.propertyName })); // Step 2.5: Build CTEs for object entities using dedicated builder\r\n const objectEntityResult = this.objectEntityCteBuilder.buildObjectEntityCtes(\r\n initialCte,\r\n allEntities,\r\n mapping\r\n );\r\n // Important: Replace the entire CTE list with the result from object entity builder\r\n // The object entity builder returns all CTEs including the initial one\r\n ctesForProcessing = objectEntityResult.ctes;\r\n currentAliasToBuildUpon = objectEntityResult.lastCteAlias;\r\n // Store column mappings for later use\r\n const columnMappings = objectEntityResult.columnMappings;\r\n\r\n // Step 3: Build CTEs for array entities using dedicated builder\r\n const arrayCteBuildResult = this.arrayEntityCteBuilder.buildArrayEntityCtes(\r\n ctesForProcessing,\r\n currentAliasToBuildUpon,\r\n allEntities,\r\n mapping,\r\n columnMappings\r\n );\r\n ctesForProcessing = arrayCteBuildResult.updatedCtes;\r\n currentAliasToBuildUpon = arrayCteBuildResult.lastCteAlias;\r\n\r\n // Step 4: Build the final SELECT query using all generated CTEs\r\n return this.buildFinalSelectQuery(\r\n ctesForProcessing,\r\n currentAliasToBuildUpon,\r\n allEntities,\r\n mapping,\r\n columnMappings\r\n );\r\n }\r\n\r\n /**\r\n * Creates the initial Common Table Expression (CTE) from the original query.\r\n * @param originalQuery The base SimpleSelectQuery.\r\n * @returns An object containing the initial CTE and its alias.\r\n */\r\n private createInitialCte(originalQuery: SimpleSelectQuery): { initialCte: CommonTable, initialCteAlias: string } {\r\n const originCteAlias = \"origin_query\";\r\n const originCte = new CommonTable(\r\n originalQuery,\r\n new SourceAliasExpression(originCteAlias, null),\r\n null\r\n );\r\n return { initialCte: originCte, initialCteAlias: originCteAlias };\r\n }\r\n\r\n /**\r\n * Builds the final SELECT query that constructs the root JSON object (or array of objects).\r\n * This query uses all previously generated CTEs.\r\n * @param finalCtesList The complete list of all CTEs (initial and array CTEs).\r\n * @param lastCteAliasForFromClause Alias of the final CTE from which the root object will be built.\r\n * @param allEntities Map of all processable entities.\r\n * @param mapping JSON mapping configuration.\r\n * @returns The final SimpleSelectQuery.\r\n */\r\n private buildFinalSelectQuery(\r\n finalCtesList: CommonTable[],\r\n lastCteAliasForFromClause: string,\r\n allEntities: Map<string, ProcessableEntity>,\r\n mapping: JsonMapping,\r\n columnMappings: JsonColumnMapping[]\r\n ): SimpleSelectQuery {\r\n const currentCtes = [...finalCtesList];\r\n\r\n // Define rootObjectCteAlias outside of if block\r\n const rootObjectCteAlias = `cte_root_${mapping.rootName.toLowerCase().replace(/[^a-z0-9_]/g, '_')}`;\r\n const rootEntity = allEntities.get(mapping.rootEntity.id);\r\n if (!rootEntity) {\r\n throw new Error(`Root entity ${mapping.rootEntity.id} not found`);\r\n }\r\n if (mapping.resultFormat === \"array\" || !mapping.resultFormat) {\r\n // Step 4.1a: Create a CTE that wraps the final result as the root object // No alias needed for single table SELECT\r\n const rootObjectBuilderExpression = this.buildEntityJsonObject(\r\n rootEntity,\r\n null, // No source alias for single table\r\n mapping.nestedEntities,\r\n allEntities,\r\n columnMappings\r\n );\r\n\r\n const rootObjectSelectItem = new SelectItem(rootObjectBuilderExpression, mapping.rootName);\r\n const rootObjectCte = new CommonTable(\r\n new SimpleSelectQuery({\r\n selectClause: new SelectClause([rootObjectSelectItem]),\r\n fromClause: new FromClause(\r\n new SourceExpression(\r\n new TableSource(null, new IdentifierString(lastCteAliasForFromClause)),\r\n null // No alias\r\n ),\r\n null\r\n ),\r\n }),\r\n new SourceAliasExpression(rootObjectCteAlias, null),\r\n null\r\n );\r\n currentCtes.push(rootObjectCte);\r\n\r\n // Step 4.1b: Aggregate all the root objects\r\n const aggregationFunc = \"jsonb_agg\"; // Always use JSONB\r\n const aggregateExpression = new FunctionCall(\r\n null,\r\n new RawString(aggregationFunc),\r\n new ValueList([new ColumnReference(null, new IdentifierString(mapping.rootName))]),\r\n null\r\n );\r\n\r\n return new SimpleSelectQuery({\r\n withClause: new WithClause(false, currentCtes),\r\n selectClause: new SelectClause([\r\n new SelectItem(aggregateExpression, `${mapping.rootName}_array`)\r\n ]),\r\n fromClause: new FromClause(\r\n new SourceExpression(new TableSource(null, new IdentifierString(rootObjectCteAlias)), null),\r\n null\r\n ),\r\n });\r\n } else {\r\n // For a single object result, create root object CTE without alias\r\n const rootObjectBuilderExpression = this.buildEntityJsonObject(\r\n rootEntity,\r\n null, // No source alias for single table\r\n mapping.nestedEntities,\r\n allEntities,\r\n columnMappings\r\n );\r\n\r\n const rootObjectSelectItem = new SelectItem(rootObjectBuilderExpression, mapping.rootName);\r\n const rootObjectCte = new CommonTable(\r\n new SimpleSelectQuery({\r\n selectClause: new SelectClause([rootObjectSelectItem]),\r\n fromClause: new FromClause(\r\n new SourceExpression(\r\n new TableSource(null, new IdentifierString(lastCteAliasForFromClause)),\r\n null // No alias\r\n ),\r\n null\r\n ),\r\n }),\r\n new SourceAliasExpression(rootObjectCteAlias, null),\r\n null\r\n );\r\n currentCtes.push(rootObjectCte);\r\n\r\n // Select directly from the root_object_cte with LIMIT 1\r\n return new SimpleSelectQuery({\r\n withClause: new WithClause(false, currentCtes),\r\n selectClause: new SelectClause([\r\n new SelectItem(new ColumnReference(null, new IdentifierString(mapping.rootName)), mapping.rootName)\r\n ]),\r\n fromClause: new FromClause(\r\n new SourceExpression(new TableSource(null, new IdentifierString(rootObjectCteAlias)), null),\r\n null\r\n ),\r\n limitClause: new LimitClause(new LiteralValue(1)) // Correctly use LimitClause\r\n });\r\n }\r\n }\r\n\r\n /**\r\n * Build JSON object for entity, using parent JSON columns when available\r\n */\r\n private buildEntityJsonObject(\r\n entity: ProcessableEntity,\r\n sourceAlias: string | null,\r\n nestedEntities: JsonMapping['nestedEntities'],\r\n allEntities: Map<string, ProcessableEntity>,\r\n columnMappings: JsonColumnMapping[]\r\n ): ValueComponent {\r\n const jsonBuildFunction = \"jsonb_build_object\";\r\n const args: ValueComponent[] = [];\r\n\r\n // Add the entity's own columns\r\n Object.entries(entity.columns).forEach(([jsonKey, columnDef]) => {\r\n // Handle both string and object formats\r\n const sqlColumn = typeof columnDef === 'string' ? columnDef : (columnDef as any).column;\r\n args.push(new LiteralValue(jsonKey));\r\n args.push(new ColumnReference(null, new IdentifierString(sqlColumn)));\r\n });\r\n\r\n // Find and process child entities (both object and array types)\r\n const childEntities = nestedEntities.filter((ne) => ne.parentId === entity.id);\r\n\r\n childEntities.forEach((childEntity) => {\r\n const child = allEntities.get(childEntity.id);\r\n if (!child) return;\r\n\r\n args.push(new LiteralValue(childEntity.propertyName)); if (childEntity.relationshipType === \"object\") {\r\n // For object relationships, use pre-computed JSON column from column mappings\r\n const mapping = columnMappings.find(m => m.entityId === child.id);\r\n if (!mapping) {\r\n throw new Error(`Column mapping not found for entity: ${child.id}`);\r\n }\r\n args.push(new ColumnReference(null, new IdentifierString(mapping.generatedColumnName)));\r\n } else if (childEntity.relationshipType === \"array\") {\r\n // For array relationships, use the column directly\r\n args.push(new ColumnReference(null, new IdentifierString(childEntity.propertyName)));\r\n }\r\n });\r\n\r\n return new FunctionCall(null, new RawString(jsonBuildFunction), new ValueList(args), null);\r\n }\r\n}", "/**\r\n * Model-driven JSON mapping structure that mirrors TypeScript model definitions.\r\n * This approach provides intuitive, hierarchical mapping that closely resembles the target data structure.\r\n */\r\n\r\nimport { JsonMapping } from './PostgresJsonQueryBuilder';\r\n\r\n/**\r\n * Supported field types for database column mapping.\r\n */\r\nexport type FieldType = 'string' | 'number' | 'boolean' | 'object' | 'array' | 'auto';\r\n\r\n/**\r\n * Field mapping configuration that can be either a simple column name or enhanced mapping with type control.\r\n */\r\nexport type FieldMapping = string | {\r\n column: string;\r\n type?: FieldType;\r\n} | {\r\n from: string; // Legacy support\r\n type?: FieldType;\r\n};\r\n\r\n/**\r\n * Nested object or array structure definition.\r\n */\r\nexport interface NestedStructure {\r\n type: 'object' | 'array';\r\n from: string; // SQL table alias\r\n structure: StructureFields;\r\n}\r\n\r\n/**\r\n * Structure fields can contain either field mappings or nested structures.\r\n */\r\nexport type StructureFields = {\r\n [key: string]: FieldMapping | NestedStructure;\r\n};\r\n\r\n/**\r\n * Model-driven JSON mapping that mirrors TypeScript interface structure.\r\n * This design makes it easy to understand the relationship between models and database columns.\r\n */\r\nexport interface ModelDrivenJsonMapping {\r\n typeInfo: {\r\n interface: string;\r\n importPath: string;\r\n };\r\n structure: StructureFields;\r\n}\r\n\r\n/**\r\n * Type protection configuration extracted from the model-driven mapping.\r\n */\r\nexport interface TypeProtectionConfig {\r\n protectedStringFields: string[];\r\n}\r\n\r\n/**\r\n * Convert a model-driven JSON mapping to the traditional JsonMapping format.\r\n * This enables backward compatibility with existing PostgresJsonQueryBuilder.\r\n */\r\nexport function convertModelDrivenMapping(modelMapping: ModelDrivenJsonMapping): {\r\n jsonMapping: JsonMapping;\r\n typeProtection: TypeProtectionConfig;\r\n} {\r\n const protectedStringFields: string[] = [];\r\n let entityIdCounter = 0;\r\n const propertyNameCounters: Record<string, number> = {};\r\n\r\n // Generate unique entity IDs\r\n const generateEntityId = () => `entity_${++entityIdCounter}`;\r\n \r\n // Generate unique property names to avoid JSON key conflicts\r\n const generateUniquePropertyName = (baseName: string): string => {\r\n if (!propertyNameCounters[baseName]) {\r\n propertyNameCounters[baseName] = 0;\r\n }\r\n propertyNameCounters[baseName]++;\r\n return propertyNameCounters[baseName] === 1 ? baseName : `${baseName}_${propertyNameCounters[baseName]}`;\r\n };\r\n // Helper function to process structure fields and extract entities\r\n const processStructure = (\r\n structure: StructureFields,\r\n parentId: string | null = null\r\n ): {\r\n columns: Record<string, string>;\r\n nestedEntities: any[];\r\n } => {\r\n const columns: Record<string, string> = {};\r\n const nestedEntities: any[] = []; for (const [fieldName, config] of Object.entries(structure)) {\r\n if (typeof config === 'string') {\r\n // Simple field mapping: \"fieldName\": \"column_name\"\r\n columns[fieldName] = config;\r\n } else if ('column' in config && typeof config.column === 'string' && !('type' in config && (config.type === 'object' || config.type === 'array'))) {\r\n // Enhanced field mapping: \"fieldName\": { \"column\": \"column_name\", \"type\": \"string\" }\r\n const fieldConfig = config as FieldMapping;\r\n if (typeof fieldConfig === 'object' && 'column' in fieldConfig) {\r\n columns[fieldName] = fieldConfig.column;\r\n if (fieldConfig.type === 'string') {\r\n protectedStringFields.push(fieldConfig.column);\r\n }\r\n }\r\n } else if ('from' in config && typeof config.from === 'string' && !('type' in config && (config.type === 'object' || config.type === 'array'))) {\r\n // Legacy field mapping: \"fieldName\": { \"from\": \"column_name\", \"type\": \"string\" }\r\n const fieldConfig = config as FieldMapping;\r\n if (typeof fieldConfig === 'object' && 'from' in fieldConfig) {\r\n columns[fieldName] = fieldConfig.from;\r\n if (fieldConfig.type === 'string') {\r\n protectedStringFields.push(fieldConfig.from);\r\n }\r\n }\r\n } else if ('type' in config && (config.type === 'object' || config.type === 'array')) {\r\n // Nested structure: object or array\r\n const nestedStructure = config as NestedStructure;\r\n const uniquePropertyName = generateUniquePropertyName(fieldName);\r\n // Generate globally unique entity ID to ensure unique JSON column names\r\n const entityId = generateEntityId();\r\n\r\n const processedNested = processStructure(nestedStructure.structure, entityId);\r\n nestedEntities.push({\r\n id: entityId, // Use unique ID to avoid column conflicts\r\n name: fieldName.charAt(0).toUpperCase() + fieldName.slice(1), // Capitalize first letter\r\n parentId: parentId || 'root',\r\n propertyName: uniquePropertyName,\r\n originalPropertyName: fieldName, // Store original name for final mapping\r\n relationshipType: nestedStructure.type,\r\n columns: processedNested.columns\r\n });\r\n\r\n // Add nested entities from deeper levels\r\n nestedEntities.push(...processedNested.nestedEntities.map(entity => ({\r\n ...entity,\r\n parentId: entity.parentId === 'root' ? entityId : entity.parentId\r\n })));\r\n }\r\n }\r\n\r\n return { columns, nestedEntities };\r\n };\r\n\r\n // Process the root structure\r\n const processed = processStructure(modelMapping.structure); // Build the traditional JsonMapping\r\n const jsonMapping: JsonMapping = {\r\n rootName: 'root', // Default root name\r\n rootEntity: {\r\n id: 'root',\r\n name: 'Root',\r\n columns: processed.columns\r\n },\r\n nestedEntities: processed.nestedEntities\r\n };\r\n\r\n // Add typeInfo for backward compatibility\r\n (jsonMapping as any).typeInfo = modelMapping.typeInfo;\r\n\r\n return {\r\n jsonMapping,\r\n typeProtection: { protectedStringFields }\r\n };\r\n}\r\n\r\n/**\r\n * Validate that a model-driven mapping structure is well-formed.\r\n */\r\nexport function validateModelDrivenMapping(mapping: ModelDrivenJsonMapping): string[] {\r\n const errors: string[] = [];\r\n\r\n // Validate typeInfo\r\n if (!mapping.typeInfo) {\r\n errors.push('typeInfo is required');\r\n } else {\r\n if (!mapping.typeInfo.interface) {\r\n errors.push('typeInfo.interface is required');\r\n }\r\n if (!mapping.typeInfo.importPath) {\r\n errors.push('typeInfo.importPath is required');\r\n }\r\n }\r\n\r\n // Validate structure\r\n if (!mapping.structure || typeof mapping.structure !== 'object') {\r\n errors.push('structure is required and must be an object');\r\n }\r\n\r\n return errors;\r\n}\r\n", "/**\r\n * Enhanced JSON mapping structure that extends the base JsonMapping interface\r\n * with additional metadata and type safety features.\r\n */\r\n\r\n/**\r\n * Supported column types for enhanced mapping.\r\n */\r\nexport type ColumnType = 'string' | 'number' | 'boolean' | 'date' | 'auto';\r\n\r\n/**\r\n * Enhanced column configuration that supports both simple and complex mappings.\r\n */\r\nexport interface ColumnConfig {\r\n /** Source column name */\r\n column: string;\r\n /** Type enforcement for this column */\r\n type?: ColumnType;\r\n /** Whether this field is nullable */\r\n nullable?: boolean;\r\n /** Custom transformation function */\r\n transform?: string;\r\n}\r\n\r\n/**\r\n * Column mapping can be either a simple string or enhanced configuration.\r\n */\r\nexport type ColumnMapping = string | ColumnConfig;\r\n\r\n/**\r\n * Enhanced entity definition with additional metadata.\r\n */\r\nexport interface EnhancedEntity {\r\n id: string;\r\n name: string;\r\n columns: Record<string, ColumnMapping>;\r\n /** Entity description for documentation */\r\n description?: string;\r\n}\r\n\r\n/**\r\n * Enhanced nested entity with relationship metadata.\r\n */\r\nexport interface EnhancedNestedEntity extends EnhancedEntity {\r\n parentId: string;\r\n propertyName: string;\r\n relationshipType: 'object' | 'array';\r\n /** Join condition for complex relationships */\r\n joinCondition?: string;\r\n}\r\n\r\n/**\r\n * Type protection configuration.\r\n */\r\nexport interface TypeProtectionConfig {\r\n /** Columns that should be treated as strings */\r\n protectedStringFields: string[];\r\n /** Columns that should be parsed as dates */\r\n dateFields?: string[];\r\n /** Columns that should be parsed as numbers */\r\n numberFields?: string[];\r\n /** Custom type transformations */\r\n customTransforms?: Record<string, string>;\r\n}\r\n\r\n/**\r\n * Enhanced JSON mapping with type safety and metadata support.\r\n */\r\nexport interface EnhancedJsonMapping {\r\n /** Root entity name */\r\n rootName: string;\r\n /** Root entity definition */\r\n rootEntity: EnhancedEntity;\r\n /** Nested entities */\r\n nestedEntities: EnhancedNestedEntity[];\r\n /** Result format */\r\n resultFormat?: 'array' | 'single';\r\n /** Empty result fallback */\r\n emptyResult?: string;\r\n /** Type information */\r\n typeInfo?: {\r\n interface: string;\r\n importPath: string;\r\n generics?: string[];\r\n };\r\n /** Type protection configuration */\r\n typeProtection?: TypeProtectionConfig;\r\n /** Mapping metadata */\r\n metadata?: {\r\n version: string;\r\n description?: string;\r\n author?: string;\r\n createdAt?: string;\r\n updatedAt?: string;\r\n };\r\n}\r\n\r\n/**\r\n * Legacy JSON mapping interface (from PostgresJsonQueryBuilder).\r\n */\r\nexport interface LegacyJsonMapping {\r\n rootName: string;\r\n rootEntity: {\r\n id: string;\r\n name: string;\r\n columns: { [jsonKey: string]: string };\r\n };\r\n nestedEntities: Array<{\r\n id: string;\r\n name: string;\r\n parentId: string;\r\n propertyName: string;\r\n relationshipType?: \"object\" | \"array\";\r\n columns: { [jsonKey: string]: string };\r\n }>;\r\n resultFormat?: \"array\" | \"single\";\r\n emptyResult?: string;\r\n}\r\n\r\n/**\r\n * Converts enhanced column configurations to simple string mappings for legacy compatibility.\r\n * \r\n * This function transforms complex column configurations (with type info, nullable flags, etc.)\r\n * into simple string mappings that can be used with PostgresJsonQueryBuilder.\r\n * \r\n * **Supported Input Formats:**\r\n * - Simple strings: `\"user_name\"` \u2192 `\"user_name\"`\r\n * - Column config: `{ column: \"u.name\", type: \"string\" }` \u2192 `\"u.name\"`\r\n * - From config: `{ from: \"user_name\", nullable: true }` \u2192 `\"user_name\"`\r\n * \r\n * @param columns - Record of field names to column configurations\r\n * @returns Record of field names to column source strings\r\n * \r\n * @example\r\n * ```typescript\r\n * const enhanced = {\r\n * id: { column: \"u.user_id\", type: \"number\" },\r\n * name: { from: \"user_name\", type: \"string\" },\r\n * email: \"email_address\"\r\n * };\r\n * \r\n * const legacy = convertColumnsToLegacy(enhanced);\r\n * // Result: { id: \"u.user_id\", name: \"user_name\", email: \"email_address\" }\r\n * ```\r\n */\r\nexport function convertColumnsToLegacy(columns: Record<string, any>): Record<string, string> {\r\n const result: Record<string, string> = {};\r\n for (const [key, config] of Object.entries(columns)) {\r\n if (typeof config === 'string') {\r\n result[key] = config;\r\n } else if (config && typeof config === 'object') {\r\n if ('column' in config) {\r\n result[key] = config.column;\r\n } else if ('from' in config) {\r\n result[key] = config.from;\r\n } else {\r\n result[key] = key; // fallback\r\n }\r\n } else {\r\n result[key] = key; // fallback\r\n }\r\n }\r\n return result;\r\n}\r\n\r\n/**\r\n * Converts any unified JSON mapping format to legacy JsonMapping format.\r\n * \r\n * This universal converter handles Enhanced, Unified, and Legacy formats, providing\r\n * a single interface for converting complex mapping configurations to the simple\r\n * format expected by PostgresJsonQueryBuilder.\r\n * \r\n * **Supported Input Formats:**\r\n * - **Enhanced**: With metadata, type protection, and advanced column configs\r\n * - **Unified**: Standard format with rootName and rootEntity\r\n * - **Legacy**: Already compatible format (returned as-is)\r\n * \r\n * **Features:**\r\n * - Automatic format detection\r\n * - Column configuration simplification\r\n * - Nested entity handling\r\n * - Type protection extraction\r\n * \r\n * @param input - JSON mapping in any supported format\r\n * @returns Legacy JsonMapping compatible with PostgresJsonQueryBuilder\r\n * \r\n * @throws {Error} When input is null, undefined, or malformed\r\n * \r\n * @example\r\n * ```typescript\r\n * // Enhanced format input\r\n * const enhanced = {\r\n * rootName: \"User\",\r\n * rootEntity: {\r\n * columns: {\r\n * id: { column: \"u.user_id\", type: \"number\" },\r\n * name: { column: \"u.user_name\", type: \"string\" }\r\n * }\r\n * },\r\n * metadata: { version: \"2.0\" }\r\n * };\r\n * \r\n * const legacy = convertToLegacyJsonMapping(enhanced);\r\n * // Result: Compatible with PostgresJsonQueryBuilder\r\n * ```\r\n * \r\n * @see {@link convertColumnsToLegacy} For column-specific conversion\r\n * @see {@link extractTypeProtection} For type safety features\r\n */\r\nexport function convertToLegacyJsonMapping(input: any): LegacyJsonMapping {\r\n if (!input) {\r\n throw new Error('Input mapping is required');\r\n }\r\n\r\n // If it's already in legacy format, return as-is\r\n if (input.rootName && input.rootEntity && \r\n typeof input.rootEntity.columns === 'object' &&\r\n !input.typeInfo && !input.typeProtection && !input.metadata) {\r\n \r\n // Check if columns are already in string format\r\n const allColumnsAreStrings = Object.values(input.rootEntity.columns).every(\r\n col => typeof col === 'string'\r\n );\r\n \r\n if (allColumnsAreStrings) {\r\n return input as LegacyJsonMapping;\r\n }\r\n }\r\n\r\n // Enhanced format conversion\r\n if (input.rootName && input.rootEntity) {\r\n return {\r\n rootName: input.rootName,\r\n rootEntity: {\r\n id: input.rootEntity.id || 'root',\r\n name: input.rootEntity.name || input.rootName,\r\n columns: convertColumnsToLegacy(input.rootEntity.columns || {})\r\n },\r\n nestedEntities: (input.nestedEntities || []).map((entity: any) => ({\r\n id: entity.id,\r\n name: entity.name,\r\n parentId: entity.parentId,\r\n propertyName: entity.propertyName,\r\n relationshipType: entity.relationshipType,\r\n columns: convertColumnsToLegacy(entity.columns || {})\r\n })),\r\n resultFormat: input.resultFormat,\r\n emptyResult: input.emptyResult\r\n };\r\n }\r\n\r\n throw new Error('Unsupported mapping format');\r\n}\r\n\r\n/**\r\n * Converts enhanced mapping to legacy format for backward compatibility.\r\n */\r\nexport function toLegacyMapping(enhanced: EnhancedJsonMapping): LegacyJsonMapping {\r\n\r\n return {\r\n rootName: enhanced.rootName,\r\n rootEntity: {\r\n id: enhanced.rootEntity.id,\r\n name: enhanced.rootEntity.name,\r\n columns: convertColumnsToLegacy(enhanced.rootEntity.columns)\r\n },\r\n nestedEntities: enhanced.nestedEntities.map(entity => ({\r\n id: entity.id,\r\n name: entity.name,\r\n parentId: entity.parentId,\r\n propertyName: entity.propertyName,\r\n relationshipType: entity.relationshipType,\r\n columns: convertColumnsToLegacy(entity.columns)\r\n })),\r\n resultFormat: enhanced.resultFormat,\r\n emptyResult: enhanced.emptyResult\r\n };\r\n}\r\n\r\n/**\r\n * Extracts type protection configuration from enhanced mapping.\r\n */\r\nexport function extractTypeProtection(enhanced: EnhancedJsonMapping): TypeProtectionConfig {\r\n const protectedStringFields: string[] = [];\r\n const dateFields: string[] = [];\r\n const numberFields: string[] = [];\r\n\r\n // Use existing type protection if available\r\n if (enhanced.typeProtection) {\r\n return {\r\n protectedStringFields: enhanced.typeProtection.protectedStringFields || [],\r\n dateFields: enhanced.typeProtection.dateFields,\r\n numberFields: enhanced.typeProtection.numberFields,\r\n customTransforms: enhanced.typeProtection.customTransforms\r\n };\r\n }\r\n\r\n // Process root entity\r\n for (const [key, config] of Object.entries(enhanced.rootEntity.columns)) {\r\n if (typeof config === 'object' && config.type) {\r\n const columnName = config.column;\r\n switch (config.type) {\r\n case 'string':\r\n protectedStringFields.push(columnName);\r\n break;\r\n case 'date':\r\n dateFields.push(columnName);\r\n break;\r\n case 'number':\r\n numberFields.push(columnName);\r\n break;\r\n }\r\n }\r\n }\r\n\r\n // Process nested entities\r\n for (const entity of enhanced.nestedEntities) {\r\n for (const [key, config] of Object.entries(entity.columns)) {\r\n if (typeof config === 'object' && config.type) {\r\n const columnName = config.column;\r\n switch (config.type) {\r\n case 'string':\r\n protectedStringFields.push(columnName);\r\n break;\r\n case 'date':\r\n dateFields.push(columnName);\r\n break;\r\n case 'number':\r\n numberFields.push(columnName);\r\n break;\r\n }\r\n }\r\n }\r\n }\r\n\r\n return {\r\n protectedStringFields,\r\n dateFields: dateFields.length > 0 ? dateFields : undefined,\r\n numberFields: numberFields.length > 0 ? numberFields : undefined,\r\n customTransforms: undefined\r\n };\r\n}", "/**\r\n * Unified JSON mapping converter that handles all supported formats\r\n * and provides a single interface for mapping transformations.\r\n */\r\n\r\nimport { JsonMapping } from './PostgresJsonQueryBuilder';\r\nimport { ModelDrivenJsonMapping, convertModelDrivenMapping } from './ModelDrivenJsonMapping';\r\nimport { EnhancedJsonMapping, LegacyJsonMapping, TypeProtectionConfig, toLegacyMapping, extractTypeProtection } from './EnhancedJsonMapping';\r\n\r\n/**\r\n * Input format types that the converter can handle.\r\n */\r\nexport type JsonMappingInput = \r\n | EnhancedJsonMapping \r\n | ModelDrivenJsonMapping \r\n | LegacyJsonMapping;\r\n\r\n/**\r\n * Format detection result.\r\n */\r\nexport type MappingFormat = 'enhanced' | 'model-driven' | 'legacy';\r\n\r\n/**\r\n * Conversion result with metadata.\r\n */\r\nexport interface ConversionResult {\r\n /** Detected input format */\r\n format: MappingFormat;\r\n /** Converted legacy mapping for PostgresJsonQueryBuilder */\r\n mapping: JsonMapping;\r\n /** Type protection configuration */\r\n typeProtection: TypeProtectionConfig;\r\n /** Original input for reference */\r\n originalInput: JsonMappingInput;\r\n /** Additional metadata */\r\n metadata?: {\r\n typeInfo?: {\r\n interface: string;\r\n importPath: string;\r\n generics?: string[];\r\n };\r\n version?: string;\r\n description?: string;\r\n };\r\n}\r\n\r\n/**\r\n * Strategy interface for format-specific conversion logic.\r\n */\r\ninterface ConversionStrategy<T = JsonMappingInput> {\r\n detect(input: unknown): input is T;\r\n convert(input: T): ConversionResult;\r\n}\r\n\r\n/**\r\n * Type guard to check if input is valid JSON mapping input\r\n */\r\nfunction isValidMappingInput(input: unknown): input is JsonMappingInput {\r\n return input !== null && \r\n input !== undefined && \r\n typeof input === 'object';\r\n}\r\n\r\n/**\r\n * Enhanced format conversion strategy.\r\n */\r\nclass EnhancedFormatStrategy implements ConversionStrategy<EnhancedJsonMapping> {\r\n detect(input: unknown): input is EnhancedJsonMapping {\r\n if (!isValidMappingInput(input)) {\r\n return false;\r\n }\r\n\r\n const candidate = input as any;\r\n if (!candidate || \r\n typeof candidate.rootName !== 'string' ||\r\n !candidate.rootEntity ||\r\n !Array.isArray(candidate.nestedEntities)) {\r\n return false;\r\n }\r\n\r\n // Check if it has enhanced features\r\n if (candidate.typeInfo || candidate.typeProtection || candidate.metadata) {\r\n return true;\r\n }\r\n\r\n // Check if any column uses enhanced format (object with 'column' property)\r\n const hasEnhancedColumns = (columns: unknown): boolean => {\r\n if (!columns || typeof columns !== 'object') return false;\r\n return Object.values(columns as Record<string, unknown>).some(col => \r\n typeof col === 'object' && col !== null && 'column' in col\r\n );\r\n };\r\n\r\n if (hasEnhancedColumns(candidate.rootEntity.columns)) {\r\n return true;\r\n }\r\n\r\n return candidate.nestedEntities.some((entity: unknown) => \r\n entity && typeof entity === 'object' && \r\n hasEnhancedColumns((entity as any).columns)\r\n );\r\n }\r\n\r\n convert(input: EnhancedJsonMapping): ConversionResult {\r\n return {\r\n format: 'enhanced',\r\n mapping: toLegacyMapping(input),\r\n typeProtection: extractTypeProtection(input),\r\n originalInput: input,\r\n metadata: {\r\n typeInfo: input.typeInfo,\r\n version: input.metadata?.version,\r\n description: input.metadata?.description\r\n }\r\n };\r\n }\r\n}\r\n\r\n/**\r\n * Model-driven format conversion strategy.\r\n */\r\nclass ModelDrivenFormatStrategy implements ConversionStrategy<ModelDrivenJsonMapping> {\r\n detect(input: unknown): input is ModelDrivenJsonMapping {\r\n if (!isValidMappingInput(input)) {\r\n return false;\r\n }\r\n \r\n const candidate = input as any;\r\n return candidate && \r\n candidate.typeInfo && \r\n candidate.structure && \r\n typeof candidate.typeInfo.interface === 'string';\r\n }\r\n\r\n convert(input: ModelDrivenJsonMapping): ConversionResult {\r\n // Use the existing convertModelDrivenMapping function to avoid code duplication\r\n const converted = convertModelDrivenMapping(input);\r\n \r\n return {\r\n format: 'model-driven',\r\n mapping: converted.jsonMapping,\r\n typeProtection: converted.typeProtection,\r\n originalInput: input,\r\n metadata: {\r\n typeInfo: input.typeInfo\r\n }\r\n };\r\n }\r\n\r\n}\r\n\r\n/**\r\n * Legacy format conversion strategy.\r\n */\r\nclass LegacyFormatStrategy implements ConversionStrategy<LegacyJsonMapping> {\r\n detect(input: unknown): input is LegacyJsonMapping {\r\n if (!isValidMappingInput(input)) {\r\n return false;\r\n }\r\n \r\n const candidate = input as any;\r\n if (!candidate || \r\n typeof candidate.rootName !== 'string' ||\r\n !candidate.rootEntity ||\r\n typeof candidate.rootEntity.columns !== 'object' ||\r\n candidate.typeInfo || candidate.typeProtection || candidate.metadata) {\r\n return false;\r\n }\r\n\r\n // Check if any column uses enhanced format (object with 'column' property)\r\n const hasEnhancedColumns = (columns: unknown): boolean => {\r\n if (!columns || typeof columns !== 'object') return false;\r\n return Object.values(columns as Record<string, unknown>).some(col => \r\n typeof col === 'object' && col !== null && 'column' in col\r\n );\r\n };\r\n\r\n // If it has enhanced columns, it's not legacy format\r\n if (hasEnhancedColumns(candidate.rootEntity.columns)) {\r\n return false;\r\n }\r\n\r\n if (candidate.nestedEntities && Array.isArray(candidate.nestedEntities)) {\r\n const hasEnhancedNested = candidate.nestedEntities.some((entity: unknown) => \r\n entity && typeof entity === 'object' && hasEnhancedColumns((entity as any).columns)\r\n );\r\n if (hasEnhancedNested) {\r\n return false;\r\n }\r\n }\r\n\r\n return true;\r\n }\r\n\r\n convert(input: LegacyJsonMapping): ConversionResult {\r\n return {\r\n format: 'legacy',\r\n mapping: input as JsonMapping,\r\n typeProtection: { protectedStringFields: [] },\r\n originalInput: input\r\n };\r\n }\r\n}\r\n\r\n/**\r\n * Unified JSON mapping converter that handles all supported formats using the Strategy pattern.\r\n * \r\n * This converter automatically detects the input format and applies the appropriate conversion\r\n * strategy to transform any supported JSON mapping format into a standardized result.\r\n * \r\n * **Supported Formats:**\r\n * - **Enhanced**: Rich format with metadata, type protection, and advanced column configurations\r\n * - **Model-Driven**: TypeScript interface-based mapping with structured field definitions\r\n * - **Legacy**: Simple format compatible with PostgresJsonQueryBuilder\r\n * \r\n * **Usage:**\r\n * ```typescript\r\n * const converter = new JsonMappingConverter();\r\n * const result = converter.convert(someMapping);\r\n * const legacyMapping = converter.toLegacyMapping(someMapping);\r\n * ```\r\n * \r\n * @public\r\n */\r\nexport class JsonMappingConverter {\r\n /** Ordered list of conversion strategies, checked in priority order */\r\n private strategies: ConversionStrategy[];\r\n\r\n /**\r\n * Creates a new JsonMappingConverter with all supported strategies.\r\n * \r\n * Strategies are checked in order of specificity:\r\n * 1. Enhanced format (most feature-rich)\r\n * 2. Model-driven format (TypeScript-based)\r\n * 3. Legacy format (fallback)\r\n */\r\n constructor() {\r\n this.strategies = [\r\n new EnhancedFormatStrategy(),\r\n new ModelDrivenFormatStrategy(),\r\n new LegacyFormatStrategy()\r\n ];\r\n }\r\n\r\n /**\r\n * Detects the format of the input mapping without performing conversion.\r\n * \r\n * This method uses the same strategy pattern as conversion but only returns\r\n * the detected format type for inspection purposes.\r\n * \r\n * @param input - The JSON mapping to analyze\r\n * @returns The detected mapping format type\r\n * \r\n * @throws {Error} When input format is not supported by any strategy\r\n * \r\n * @example\r\n * ```typescript\r\n * const format = converter.detectFormat(myMapping);\r\n * console.log(`Detected format: ${format}`); // \"enhanced\", \"model-driven\", or \"legacy\"\r\n * ```\r\n */\r\n detectFormat(input: JsonMappingInput): MappingFormat {\r\n for (const strategy of this.strategies) {\r\n if (strategy.detect(input)) {\r\n const result = strategy.convert(input);\r\n return result.format;\r\n }\r\n }\r\n throw new Error('Unsupported JSON mapping format');\r\n }\r\n\r\n /**\r\n * Converts any supported JSON mapping format to a comprehensive result with metadata.\r\n * \r\n * This is the primary conversion method that performs format detection and transformation\r\n * in a single operation. The result includes the legacy mapping, type protection configuration,\r\n * and metadata about the conversion process.\r\n * \r\n * @param input - The JSON mapping in any supported format (Enhanced, Model-Driven, or Legacy)\r\n * @returns Complete conversion result with mapping, metadata, and type protection\r\n * \r\n * @throws {Error} When the input format is not recognized by any strategy\r\n * \r\n * @example\r\n * ```typescript\r\n * const result = converter.convert(enhancedMapping);\r\n * console.log(`Format: ${result.format}`);\r\n * console.log(`Type protection: ${result.typeProtection.protectedStringFields.length} fields`);\r\n * \r\n * // Use the converted mapping\r\n * const queryBuilder = new PostgresJsonQueryBuilder(result.mapping);\r\n * ```\r\n * \r\n * @see {@link toLegacyMapping} For simple mapping extraction\r\n * @see {@link getTypeProtection} For type protection only\r\n */\r\n convert(input: JsonMappingInput): ConversionResult {\r\n for (const strategy of this.strategies) {\r\n if (strategy.detect(input)) {\r\n return strategy.convert(input);\r\n }\r\n }\r\n throw new Error('Unsupported JSON mapping format: Unable to detect a compatible strategy for the provided input');\r\n }\r\n\r\n /**\r\n * Extracts only the legacy JsonMapping for direct use with PostgresJsonQueryBuilder.\r\n * \r\n * This convenience method performs the full conversion but returns only the mapping portion,\r\n * discarding metadata and type protection information. Use this when you only need\r\n * the mapping for query building and don't require additional metadata.\r\n * \r\n * @param input - The JSON mapping in any supported format\r\n * @returns Legacy-format JsonMapping ready for PostgresJsonQueryBuilder\r\n * \r\n * @throws {Error} When the input format is not supported\r\n * \r\n * @example\r\n * ```typescript\r\n * const legacyMapping = converter.toLegacyMapping(modelDrivenMapping);\r\n * const queryBuilder = new PostgresJsonQueryBuilder(legacyMapping);\r\n * const query = queryBuilder.build(selectQuery);\r\n * ```\r\n * \r\n * @see {@link convert} For full conversion with metadata\r\n */\r\n toLegacyMapping(input: JsonMappingInput): JsonMapping {\r\n return this.convert(input).mapping;\r\n }\r\n\r\n /**\r\n * Extracts type protection configuration for runtime type checking.\r\n * \r\n * Type protection helps identify fields that should be treated as strings\r\n * to prevent injection attacks or type coercion issues. This is particularly\r\n * useful when working with user input or external data sources.\r\n * \r\n * @param input - The JSON mapping in any supported format\r\n * @returns Type protection configuration with protected field definitions\r\n * \r\n * @throws {Error} When the input format is not supported\r\n * \r\n * @example\r\n * ```typescript\r\n * const typeProtection = converter.getTypeProtection(enhancedMapping);\r\n * \r\n * // Apply type protection during data processing\r\n * for (const field of typeProtection.protectedStringFields) {\r\n * if (typeof data[field] !== 'string') {\r\n * data[field] = String(data[field]);\r\n * }\r\n * }\r\n * ```\r\n */\r\n getTypeProtection(input: JsonMappingInput): TypeProtectionConfig {\r\n return this.convert(input).typeProtection;\r\n }\r\n\r\n /**\r\n * Validates that the input mapping is well-formed and can be successfully converted.\r\n * \r\n * This method performs comprehensive validation without attempting conversion,\r\n * returning an array of error messages for any issues found. An empty array\r\n * indicates the mapping is valid and ready for conversion.\r\n * \r\n * **Validation Checks:**\r\n * - Basic structure validation (object type, required fields)\r\n * - Format-specific validation (Enhanced, Model-Driven, Legacy)\r\n * - Column configuration validation\r\n * - Type protection configuration validation\r\n * \r\n * @param input - The JSON mapping to validate\r\n * @returns Array of validation error messages (empty if valid)\r\n * \r\n * @example\r\n * ```typescript\r\n * const errors = converter.validate(suspiciousMapping);\r\n * if (errors.length > 0) {\r\n * console.error('Validation failed:', errors);\r\n * throw new Error(`Invalid mapping: ${errors.join(', ')}`);\r\n * }\r\n * \r\n * // Safe to convert\r\n * const result = converter.convert(suspiciousMapping);\r\n * ```\r\n * \r\n * @see {@link convert} Performs conversion after implicit validation\r\n */\r\n validate(input: JsonMappingInput): string[] {\r\n const errors: string[] = [];\r\n\r\n // Pre-validation checks\r\n if (!input || typeof input !== 'object') {\r\n errors.push('Input must be an object');\r\n return errors;\r\n }\r\n\r\n // Check for rootName before attempting conversion\r\n if (!('rootName' in input) || !input.rootName) {\r\n errors.push('rootName is required');\r\n }\r\n\r\n try {\r\n const result = this.convert(input);\r\n \r\n // Basic validation\r\n if (!result.mapping.rootName) {\r\n errors.push('rootName is required');\r\n }\r\n \r\n if (!result.mapping.rootEntity) {\r\n errors.push('rootEntity is required');\r\n } else {\r\n if (!result.mapping.rootEntity.id) {\r\n errors.push('rootEntity.id is required');\r\n }\r\n if (!result.mapping.rootEntity.columns) {\r\n errors.push('rootEntity.columns is required');\r\n }\r\n }\r\n\r\n // Validate nested entities\r\n if (result.mapping.nestedEntities) {\r\n for (const entity of result.mapping.nestedEntities) {\r\n if (!entity.id) {\r\n errors.push(`Nested entity missing id: ${entity.propertyName}`);\r\n }\r\n if (!entity.parentId) {\r\n errors.push(`Nested entity missing parentId: ${entity.id}`);\r\n }\r\n if (!entity.propertyName) {\r\n errors.push(`Nested entity missing propertyName: ${entity.id}`);\r\n }\r\n }\r\n }\r\n\r\n } catch (error) {\r\n // Only add conversion error if we haven't already found specific errors\r\n if (errors.length === 0) {\r\n errors.push(`Conversion failed: ${error instanceof Error ? error.message : String(error)}`);\r\n }\r\n }\r\n\r\n return errors;\r\n }\r\n\r\n /**\r\n * Creates a new enhanced mapping from legacy mapping.\r\n */\r\n upgradeToEnhanced(legacy: LegacyJsonMapping, typeInfo?: { interface: string; importPath: string }): EnhancedJsonMapping {\r\n return {\r\n rootName: legacy.rootName,\r\n rootEntity: {\r\n id: legacy.rootEntity.id,\r\n name: legacy.rootEntity.name,\r\n columns: legacy.rootEntity.columns\r\n },\r\n nestedEntities: legacy.nestedEntities.map(entity => ({\r\n id: entity.id,\r\n name: entity.name,\r\n parentId: entity.parentId,\r\n propertyName: entity.propertyName,\r\n relationshipType: entity.relationshipType || 'object',\r\n columns: entity.columns\r\n })),\r\n resultFormat: legacy.resultFormat,\r\n emptyResult: legacy.emptyResult,\r\n typeInfo,\r\n metadata: {\r\n version: '1.0',\r\n description: 'Upgraded from legacy format'\r\n }\r\n };\r\n }\r\n}", "/**\r\n * Unified JSON Mapping processor that supports both legacy and model-driven formats.\r\n * \r\n * @deprecated Use JsonMappingConverter instead. This module is kept for backward compatibility.\r\n * This module provides backward compatibility while encouraging migration to the model-driven format.\r\n * It automatically detects the input format and normalizes to a consistent internal representation.\r\n */\r\n\r\nimport { JsonMapping } from './PostgresJsonQueryBuilder';\r\nimport { ModelDrivenJsonMapping, convertModelDrivenMapping } from './ModelDrivenJsonMapping';\r\nimport { JsonMappingConverter, JsonMappingInput } from './JsonMappingConverter';\r\n\r\n/**\r\n * Unified mapping format that can handle both legacy and model-driven inputs.\r\n */\r\nexport interface UnifiedMappingInput {\r\n // Model-driven format\r\n typeInfo?: {\r\n interface: string;\r\n importPath: string;\r\n };\r\n structure?: any;\r\n protectedStringFields?: string[];\r\n\r\n // Legacy format detection fields\r\n rootName?: string;\r\n rootEntity?: any;\r\n nestedEntities?: any[];\r\n\r\n // Direct JsonMapping fields (for backward compatibility)\r\n columns?: any;\r\n relationships?: any;\r\n}\r\n\r\n/**\r\n * Result of mapping format detection and conversion.\r\n */\r\nexport interface MappingProcessResult {\r\n format: 'model-driven' | 'unified' | 'legacy';\r\n jsonMapping: JsonMapping;\r\n originalInput: UnifiedMappingInput;\r\n metadata?: {\r\n typeInfo?: {\r\n interface: string;\r\n importPath: string;\r\n };\r\n protectedStringFields?: string[];\r\n typeProtection?: any; // From model-driven conversion\r\n };\r\n}\r\n\r\n/**\r\n * Detects the format of a JSON mapping configuration.\r\n * \r\n * @param input - The mapping configuration to analyze\r\n * @returns The detected format type\r\n */\r\nexport function detectMappingFormat(input: UnifiedMappingInput): 'model-driven' | 'unified' | 'legacy' {\r\n // Model-driven format: has typeInfo and structure\r\n if (input.typeInfo && input.structure) {\r\n return 'model-driven';\r\n }\r\n\r\n // Unified format: has rootName and rootEntity\r\n if (input.rootName && input.rootEntity) {\r\n return 'unified';\r\n }\r\n\r\n // Legacy format: direct JsonMapping structure\r\n if (input.columns || input.relationships) {\r\n return 'legacy';\r\n }\r\n\r\n // Default fallback\r\n return 'legacy';\r\n}\r\n\r\n/**\r\n * Converts legacy unified format to JsonMapping.\r\n * \r\n * @param input - Unified format mapping configuration\r\n * @returns Converted JsonMapping\r\n */\r\nfunction convertUnifiedFormat(input: UnifiedMappingInput): JsonMapping {\r\n if (!input.rootEntity) {\r\n throw new Error('Unified format requires rootEntity');\r\n }\r\n\r\n const result: JsonMapping = {\r\n rootName: input.rootName || 'root',\r\n rootEntity: {\r\n id: input.rootEntity.id || 'root',\r\n name: input.rootEntity.name || 'Root',\r\n columns: input.rootEntity.columns || {}\r\n },\r\n nestedEntities: []\r\n };\r\n\r\n // Convert nestedEntities\r\n if (input.nestedEntities && Array.isArray(input.nestedEntities)) {\r\n result.nestedEntities = input.nestedEntities.map(entity => ({\r\n id: entity.id || entity.propertyName || 'nested',\r\n name: entity.name || entity.propertyName || 'Nested',\r\n parentId: entity.parentId || result.rootEntity.id,\r\n propertyName: entity.propertyName || 'nested',\r\n relationshipType: entity.relationshipType || 'object',\r\n columns: entity.columns || {}\r\n }));\r\n }\r\n\r\n return result;\r\n}\r\n\r\n/**\r\n * Converts legacy format directly to JsonMapping.\r\n * \r\n * @param input - Legacy format mapping configuration\r\n * @returns JsonMapping\r\n */\r\nfunction convertLegacyFormat(input: UnifiedMappingInput): JsonMapping {\r\n const result: JsonMapping = {\r\n rootName: input.rootName || 'root',\r\n rootEntity: {\r\n id: 'root',\r\n name: input.rootName || 'Root',\r\n columns: input.columns || {}\r\n },\r\n nestedEntities: []\r\n };\r\n // Convert relationships to nestedEntities\r\n if (input.relationships && typeof input.relationships === 'object') {\r\n for (const [propertyName, relationship] of Object.entries(input.relationships)) {\r\n // Type assertion for legacy relationship format\r\n const rel = relationship as any;\r\n result.nestedEntities.push({\r\n id: propertyName,\r\n name: propertyName.charAt(0).toUpperCase() + propertyName.slice(1),\r\n parentId: 'root',\r\n propertyName,\r\n relationshipType: rel.type === 'hasMany' ? 'array' : 'object',\r\n columns: rel.columns || {}\r\n });\r\n }\r\n }\r\n\r\n return result;\r\n}\r\n\r\n/**\r\n * Main processor that unifies all JSON mapping formats into a consistent JsonMapping.\r\n * \r\n * @deprecated Use JsonMappingConverter.convert() instead.\r\n * \r\n * Features:\r\n * - Automatic format detection\r\n * - Backward compatibility with all existing formats\r\n * - Metadata preservation for advanced features\r\n * - Zero external dependencies\r\n * \r\n * @param input - Any supported JSON mapping format\r\n * @returns Unified processing result with JsonMapping and metadata\r\n */\r\nexport function processJsonMapping(input: UnifiedMappingInput): MappingProcessResult {\r\n // Runtime deprecation warning\r\n console.warn('\u26A0\uFE0F DEPRECATED: processJsonMapping() is deprecated. Use JsonMappingConverter.convert() instead.');\r\n console.warn('Migration guide: https://github.com/mk3008/rawsql-ts/blob/main/docs/migration-guide.md');\r\n \r\n // Check for legacy format with columns and relationships\r\n if ((input.columns || input.relationships) && !input.rootName && !input.rootEntity) {\r\n const jsonMapping = convertLegacyFormat(input);\r\n return {\r\n format: 'legacy',\r\n jsonMapping,\r\n originalInput: input,\r\n metadata: {}\r\n };\r\n }\r\n \r\n const converter = new JsonMappingConverter();\r\n const result = converter.convert(input as JsonMappingInput);\r\n \r\n // Map converter formats to unifier formats for backward compatibility\r\n let format: 'model-driven' | 'unified' | 'legacy' = result.format as any;\r\n \r\n // If it's detected as 'legacy' by converter but has rootName and rootEntity, it's 'unified' format\r\n if (result.format === 'legacy' && input.rootName && input.rootEntity) {\r\n format = 'unified';\r\n }\r\n \r\n return {\r\n format,\r\n jsonMapping: result.mapping,\r\n originalInput: input,\r\n metadata: {\r\n typeInfo: result.metadata?.typeInfo,\r\n typeProtection: result.typeProtection\r\n }\r\n };\r\n}\r\n\r\n/**\r\n * Convenience function for direct JsonMapping extraction.\r\n * \r\n * @deprecated Use JsonMappingConverter.toLegacyMapping() instead.\r\n * \r\n * @param input - Any supported JSON mapping format\r\n * @returns JsonMapping ready for use with PostgresJsonQueryBuilder\r\n */\r\nexport function unifyJsonMapping(input: UnifiedMappingInput): JsonMapping {\r\n // Runtime deprecation warning\r\n console.warn('\u26A0\uFE0F DEPRECATED: unifyJsonMapping() is deprecated. Use JsonMappingConverter.toLegacyMapping() instead.');\r\n console.warn('Migration guide: https://github.com/mk3008/rawsql-ts/blob/main/docs/migration-guide.md');\r\n \r\n const converter = new JsonMappingConverter();\r\n return converter.toLegacyMapping(input as JsonMappingInput);\r\n}\r\n\r\n/**\r\n * Type guard to check if input uses model-driven format.\r\n * \r\n * @param input - Mapping input to check\r\n * @returns True if input is model-driven format\r\n */\r\nexport function isModelDrivenFormat(input: UnifiedMappingInput): input is ModelDrivenJsonMapping {\r\n return detectMappingFormat(input) === 'model-driven';\r\n}\r\n\r\n/**\r\n * Type guard to check if input uses unified format.\r\n * \r\n * @param input - Mapping input to check\r\n * @returns True if input is unified format\r\n */\r\nexport function isUnifiedFormat(input: UnifiedMappingInput): boolean {\r\n return detectMappingFormat(input) === 'unified';\r\n}\r\n\r\n/**\r\n * Type guard to check if input uses legacy format.\r\n * \r\n * @param input - Mapping input to check\r\n * @returns True if input is legacy format\r\n */\r\nexport function isLegacyFormat(input: UnifiedMappingInput): boolean {\r\n return detectMappingFormat(input) === 'legacy';\r\n}\r\n\r\n/**\r\n * Migration helper that suggests upgrading to model-driven format.\r\n * \r\n * @param input - Current mapping configuration\r\n * @returns Suggestions for migration (if applicable)\r\n */\r\nexport function suggestModelDrivenMigration(input: UnifiedMappingInput): string[] {\r\n const format = detectMappingFormat(input);\r\n const suggestions: string[] = [];\r\n\r\n if (format !== 'model-driven') {\r\n suggestions.push('Consider migrating to model-driven JSON mapping format');\r\n suggestions.push('Benefits: Better type safety, IDE support, and future-proof design');\r\n suggestions.push('See: Model-Driven JSON Mapping Guide for migration instructions');\r\n\r\n if (format === 'unified') {\r\n suggestions.push('Your current unified format can be automatically converted');\r\n }\r\n\r\n if (format === 'legacy') {\r\n suggestions.push('Legacy format support will be maintained but new features target model-driven format');\r\n }\r\n }\r\n\r\n return suggestions;\r\n}\r\n", "/**\r\n * Post-processor for transforming database values to appropriate TypeScript types\r\n * after JSON serialization from PostgreSQL\r\n */\r\n\r\nexport interface TypeTransformationConfig {\r\n /** Column transformations mapping - takes precedence over value-based detection */\r\n columnTransformations?: {\r\n [columnName: string]: TypeTransformation;\r\n };\r\n /** Global transformation rules by SQL data type */\r\n globalTransformations?: {\r\n [sqlType: string]: TypeTransformation;\r\n };\r\n /** Custom transformation functions */\r\n customTransformers?: {\r\n [transformerName: string]: (value: any) => any;\r\n };\r\n /** Enable value-based type detection when column mapping is not provided (default: true) */\r\n enableValueBasedDetection?: boolean;\r\n /** Strict date detection - only convert ISO 8601 with 'T' separator (default: false) */\r\n strictDateDetection?: boolean;\r\n}\r\n\r\nexport interface TypeTransformation {\r\n /** Source SQL data type */\r\n sourceType: 'DATE' | 'TIMESTAMP' | 'BIGINT' | 'NUMERIC' | 'JSONB' | 'custom';\r\n /** Target TypeScript type representation */\r\n targetType: 'Date' | 'bigint' | 'string' | 'number' | 'object' | 'custom';\r\n /** Custom transformer function name (for custom type) */\r\n customTransformer?: string;\r\n /** Whether to handle null values (default: true) */\r\n handleNull?: boolean;\r\n /** Validation function for the value */\r\n validator?: (value: any) => boolean;\r\n}\r\n\r\n/**\r\n * Applies type transformations to JSON results from PostgreSQL\r\n */\r\nexport class TypeTransformationPostProcessor {\r\n private config: TypeTransformationConfig; constructor(config: TypeTransformationConfig = {}) {\r\n this.config = {\r\n enableValueBasedDetection: true,\r\n strictDateDetection: false,\r\n ...config\r\n };\r\n }\r\n\r\n /**\r\n * Transform a single result object\r\n * @param result The result object from PostgreSQL JSON query\r\n * @returns Transformed result with proper TypeScript types\r\n */\r\n public transformResult<T = any>(result: any): T {\r\n if (result === null || result === undefined) {\r\n return result;\r\n }\r\n\r\n if (Array.isArray(result)) {\r\n return result.map(item => this.transformSingleObject(item)) as T;\r\n }\r\n\r\n return this.transformSingleObject(result) as T;\r\n }\r\n\r\n /**\r\n * Transform a single object recursively\r\n */\r\n private transformSingleObject(obj: any): any {\r\n if (obj === null || obj === undefined || typeof obj !== 'object') {\r\n return obj;\r\n }\r\n\r\n if (Array.isArray(obj)) {\r\n return obj.map(item => this.transformSingleObject(item));\r\n }\r\n\r\n const transformed: any = {};\r\n\r\n for (const [key, value] of Object.entries(obj)) {\r\n if (value === null || value === undefined) {\r\n transformed[key] = value;\r\n continue;\r\n } // Check for column-specific transformation first (takes precedence)\r\n const columnTransform = this.config.columnTransformations?.[key];\r\n if (columnTransform) {\r\n transformed[key] = this.applyTransformation(value, columnTransform);\r\n continue;\r\n }\r\n\r\n // Only apply value-based detection if enabled and no column mapping exists\r\n if (this.config.enableValueBasedDetection) {\r\n const detectedTransform = this.detectValueBasedTransformation(value);\r\n if (detectedTransform) {\r\n transformed[key] = this.applyTransformation(value, detectedTransform);\r\n continue;\r\n }\r\n }\r\n\r\n // Apply global transformations based on SQL type (if available)\r\n const globalTransform = this.config.globalTransformations &&\r\n this.getGlobalTransformationForValue(value);\r\n if (globalTransform) {\r\n transformed[key] = this.applyTransformation(value, globalTransform);\r\n continue;\r\n }\r\n\r\n // Recursively transform nested objects\r\n if (typeof value === 'object' && !Array.isArray(value)) {\r\n transformed[key] = this.transformSingleObject(value);\r\n continue;\r\n }\r\n\r\n if (Array.isArray(value)) {\r\n transformed[key] = value.map(item =>\r\n typeof item === 'object' ? this.transformSingleObject(item) : item\r\n );\r\n continue;\r\n }\r\n\r\n // No transformation needed\r\n transformed[key] = value;\r\n }\r\n\r\n return transformed;\r\n }\r\n\r\n /**\r\n * Detect value type and create appropriate transformation based on value characteristics\r\n * This is the core value-based detection logic\r\n */\r\n private detectValueBasedTransformation(value: any): TypeTransformation | null {\r\n // Date string detection\r\n if (typeof value === 'string' && this.isDateString(value)) {\r\n return {\r\n sourceType: 'TIMESTAMP',\r\n targetType: 'Date',\r\n handleNull: true,\r\n validator: (v) => typeof v === 'string' && !isNaN(Date.parse(v))\r\n };\r\n }\r\n\r\n // BigInt detection (number > MAX_SAFE_INTEGER)\r\n if (typeof value === 'number' && !Number.isSafeInteger(value)) {\r\n return {\r\n sourceType: 'BIGINT',\r\n targetType: 'bigint',\r\n handleNull: true,\r\n validator: (v) => {\r\n try {\r\n BigInt(v);\r\n return true;\r\n } catch {\r\n return false;\r\n }\r\n }\r\n };\r\n }\r\n\r\n // Large string number detection (potential BIGINT)\r\n if (typeof value === 'string' && /^\\d{16,}$/.test(value)) {\r\n return {\r\n sourceType: 'BIGINT',\r\n targetType: 'bigint',\r\n handleNull: true,\r\n validator: (v) => {\r\n try {\r\n BigInt(v);\r\n return true;\r\n } catch {\r\n return false;\r\n }\r\n }\r\n };\r\n }\r\n\r\n return null;\r\n }\r\n\r\n /**\r\n * Get global transformation for a specific value (if any match)\r\n * This is separate from value-based detection and relies on configured global rules\r\n */\r\n private getGlobalTransformationForValue(value: any): TypeTransformation | null {\r\n if (!this.config.globalTransformations) {\r\n return null;\r\n }\r\n\r\n // This could be extended to match values against configured global rules\r\n // For now, it's a placeholder for future SQL-type-based global transformations\r\n return null;\r\n }\r\n\r\n /**\r\n * @deprecated Use detectValueBasedTransformation instead\r\n * Detect value type and get appropriate global transformation\r\n */\r\n private detectAndGetGlobalTransformation(value: any): TypeTransformation | null {\r\n return this.detectValueBasedTransformation(value);\r\n }\r\n\r\n /**\r\n * Check if string is a valid date string\r\n * Supports both strict (ISO 8601 with T separator) and loose detection\r\n */\r\n private isDateString(value: string): boolean {\r\n if (this.config.strictDateDetection) {\r\n // Strict: Only ISO 8601 with T separator (safer for user input)\r\n const strictIsoPattern = /^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}(?:\\.\\d{3})?(?:Z|[+-]\\d{2}:\\d{2})?$/;\r\n if (!strictIsoPattern.test(value)) {\r\n return false;\r\n }\r\n } else {\r\n // Loose: ISO 8601 date pattern (includes date-only strings)\r\n const isoDatePattern = /^\\d{4}-\\d{2}-\\d{2}(?:T\\d{2}:\\d{2}:\\d{2}(?:\\.\\d{3})?(?:Z|[+-]\\d{2}:\\d{2})?)?$/;\r\n if (!isoDatePattern.test(value)) {\r\n return false;\r\n }\r\n }\r\n\r\n const date = new Date(value);\r\n return !isNaN(date.getTime());\r\n }\r\n\r\n /**\r\n * Apply a specific transformation to a value\r\n */\r\n private applyTransformation(value: any, transformation: TypeTransformation): any {\r\n // Handle null values\r\n if (value === null || value === undefined) {\r\n return transformation.handleNull !== false ? value : null;\r\n }\r\n\r\n // Validate value if validator is provided\r\n if (transformation.validator && !transformation.validator(value)) {\r\n console.warn(`TypeTransformationPostProcessor: Value validation failed for ${value}`);\r\n return value;\r\n }\r\n\r\n try {\r\n switch (transformation.targetType) {\r\n case 'Date':\r\n return new Date(value); case 'bigint':\r\n // Handle both string and number inputs for BIGINT\r\n // For scientific notation numbers, convert to integer first\r\n if (typeof value === 'number') {\r\n // Convert scientific notation to integer string\r\n const integerValue = Math.trunc(value);\r\n return BigInt(integerValue.toString());\r\n }\r\n return BigInt(value);\r\n\r\n case 'string':\r\n return value.toString();\r\n\r\n case 'number':\r\n return typeof value === 'string' ? parseFloat(value) : Number(value);\r\n\r\n case 'object':\r\n return typeof value === 'string' ? JSON.parse(value) : value;\r\n\r\n case 'custom':\r\n if (transformation.customTransformer &&\r\n this.config.customTransformers?.[transformation.customTransformer]) {\r\n return this.config.customTransformers[transformation.customTransformer](value);\r\n }\r\n break;\r\n\r\n default:\r\n return value;\r\n }\r\n } catch (error) {\r\n console.warn(`TypeTransformationPostProcessor: Transformation failed for ${value}:`, error);\r\n return value;\r\n }\r\n\r\n return value;\r\n }\r\n\r\n /**\r\n * Create a default configuration for common PostgreSQL types\r\n * Enables value-based detection with loose date detection by default\r\n */\r\n public static createDefaultConfig(): TypeTransformationConfig {\r\n return {\r\n enableValueBasedDetection: true,\r\n strictDateDetection: false,\r\n globalTransformations: {\r\n 'DATE': {\r\n sourceType: 'DATE',\r\n targetType: 'Date',\r\n handleNull: true,\r\n validator: (value) => typeof value === 'string' && !isNaN(Date.parse(value))\r\n },\r\n 'TIMESTAMP': {\r\n sourceType: 'TIMESTAMP',\r\n targetType: 'Date',\r\n handleNull: true,\r\n validator: (value) => typeof value === 'string' && !isNaN(Date.parse(value))\r\n },\r\n 'BIGINT': {\r\n sourceType: 'BIGINT',\r\n targetType: 'bigint',\r\n handleNull: true,\r\n validator: (value) => {\r\n try {\r\n BigInt(value);\r\n return true;\r\n } catch {\r\n return false;\r\n }\r\n }\r\n }\r\n }\r\n };\r\n }\r\n\r\n /**\r\n * Create a safe configuration for handling user input\r\n * Disables value-based detection and uses strict date detection\r\n */\r\n public static createSafeConfig(columnMappings?: { [columnName: string]: TypeTransformation }): TypeTransformationConfig {\r\n return {\r\n enableValueBasedDetection: false,\r\n strictDateDetection: true,\r\n columnTransformations: columnMappings || {},\r\n globalTransformations: {\r\n 'DATE': {\r\n sourceType: 'DATE',\r\n targetType: 'Date',\r\n handleNull: true,\r\n validator: (value) => typeof value === 'string' && !isNaN(Date.parse(value))\r\n },\r\n 'TIMESTAMP': {\r\n sourceType: 'TIMESTAMP',\r\n targetType: 'Date',\r\n handleNull: true,\r\n validator: (value) => typeof value === 'string' && !isNaN(Date.parse(value))\r\n },\r\n 'BIGINT': {\r\n sourceType: 'BIGINT',\r\n targetType: 'bigint',\r\n handleNull: true,\r\n validator: (value) => {\r\n try {\r\n BigInt(value);\r\n return true;\r\n } catch {\r\n return false;\r\n }\r\n }\r\n }\r\n }\r\n };\r\n }\r\n}\r\n\r\n/**\r\n * Convenience function to create and apply transformations\r\n */\r\nexport function transformDatabaseResult<T = any>(\r\n result: any,\r\n config?: TypeTransformationConfig\r\n): T {\r\n const processor = new TypeTransformationPostProcessor(\r\n config || TypeTransformationPostProcessor.createDefaultConfig()\r\n );\r\n return processor.transformResult<T>(result);\r\n}\r\n\r\n/**\r\n * Type-safe transformation helpers\r\n */\r\nexport const TypeTransformers = {\r\n /**\r\n * Transform date string to Date object\r\n */\r\n toDate: (value: string | null): Date | null => {\r\n if (value === null || value === undefined) return null;\r\n const date = new Date(value);\r\n return isNaN(date.getTime()) ? null : date;\r\n },\r\n\r\n /**\r\n * Transform numeric string to BigInt\r\n */\r\n toBigInt: (value: string | number | null): bigint | null => {\r\n if (value === null || value === undefined) return null;\r\n try {\r\n return BigInt(value);\r\n } catch {\r\n return null;\r\n }\r\n },\r\n\r\n /**\r\n * Transform JSON string to object\r\n */\r\n toObject: <T = any>(value: string | null): T | null => {\r\n if (value === null || value === undefined) return null;\r\n try {\r\n return JSON.parse(value) as T;\r\n } catch {\r\n return null;\r\n }\r\n }\r\n};\r\n", "import { SqlComponent, SqlComponentVisitor } from '../models/SqlComponent';\r\nimport { CommonTable, SubQuerySource, TableSource } from '../models/Clause';\r\nimport { SelectClause, SelectItem } from '../models/Clause';\r\nimport { SimpleSelectQuery } from '../models/SimpleSelectQuery';\r\nimport { CTECollector } from './CTECollector';\r\nimport { SelectableColumnCollector, DuplicateDetectionMode } from './SelectableColumnCollector';\r\nimport { SelectValueCollector } from './SelectValueCollector';\r\nimport { ColumnReference } from '../models/ValueComponent';\r\nimport { BinarySelectQuery, SelectQuery } from '../models/SelectQuery';\r\nimport { SourceExpression } from '../models/Clause';\r\nimport { TableColumnResolver } from './TableColumnResolver';\r\n\r\nexport class TableSchema {\r\n public name: string;\r\n public columns: string[];\r\n\r\n constructor(name: string, columns: string[]) {\r\n this.name = name;\r\n this.columns = columns;\r\n }\r\n}\r\n\r\n/**\r\n * A visitor that collects schema information (table names and column names) from a SQL query structure.\r\n */\r\nexport class SchemaCollector implements SqlComponentVisitor<void> {\r\n private handlers: Map<symbol, (arg: any) => void>;\r\n\r\n private tableSchemas: TableSchema[] = [];\r\n private visitedNodes: Set<SqlComponent> = new Set();\r\n private commonTables: CommonTable[] = [];\r\n private running = false;\r\n\r\n constructor(private tableColumnResolver: TableColumnResolver | null = null) {\r\n this.handlers = new Map<symbol, (arg: any) => void>();\r\n\r\n // Setup handlers for query components\r\n this.handlers.set(SimpleSelectQuery.kind, (expr) => this.visitSimpleSelectQuery(expr as SimpleSelectQuery));\r\n this.handlers.set(BinarySelectQuery.kind, (expr) => this.visitBinarySelectQuery(expr as BinarySelectQuery));\r\n }\r\n\r\n /**\r\n * Collects schema information (table names and column names) from a SQL query structure.\r\n * This method ensures that the collected schema information is unique and sorted.\r\n * The resulting schemas and columns are sorted alphabetically to ensure deterministic ordering.\r\n *\r\n * @param arg The SQL query structure to analyze.\r\n */\r\n public collect(arg: SqlComponent): TableSchema[] {\r\n this.visit(arg);\r\n return this.tableSchemas;\r\n }\r\n\r\n /**\r\n * Main entry point for the visitor pattern.\r\n * Implements the shallow visit pattern to distinguish between root and recursive visits.\r\n *\r\n * This method ensures that schema information is collected uniquely and sorted.\r\n * The resulting schemas and columns are sorted alphabetically to ensure deterministic ordering.\r\n *\r\n * @param arg The SQL component to visit.\r\n */\r\n public visit(arg: SqlComponent): void {\r\n // If not a root visit, just visit the node and return\r\n if (this.running) {\r\n this.visitNode(arg);\r\n return;\r\n }\r\n\r\n // If this is a root visit, we need to reset the state\r\n this.reset();\r\n this.running = true;\r\n\r\n try {\r\n // Ensure the argument is a SelectQuery\r\n if (!(arg instanceof SimpleSelectQuery || arg instanceof BinarySelectQuery)) {\r\n throw new Error(`Unsupported SQL component type for schema collection. Received: ${arg.constructor.name}. Expected: SimpleSelectQuery or BinarySelectQuery.`);\r\n }\r\n\r\n // Collects Common Table Expressions (CTEs) using CTECollector\r\n const cteCollector = new CTECollector();\r\n this.commonTables = cteCollector.collect(arg);\r\n\r\n this.visitNode(arg);\r\n\r\n // Consolidate tableSchemas\r\n this.consolidateTableSchemas();\r\n } finally {\r\n // Regardless of success or failure, reset the root visit flag\r\n this.running = false;\r\n }\r\n }\r\n\r\n /**\r\n * Internal visit method used for all nodes.\r\n * This separates the visit flag management from the actual node visitation logic.\r\n */\r\n private visitNode(arg: SqlComponent): void {\r\n // Skip if we've already visited this node to prevent infinite recursion\r\n if (this.visitedNodes.has(arg)) {\r\n return;\r\n }\r\n\r\n // Mark as visited\r\n this.visitedNodes.add(arg);\r\n\r\n const handler = this.handlers.get(arg.getKind());\r\n if (handler) {\r\n handler(arg);\r\n return;\r\n }\r\n\r\n // If no handler found, that's ok - we only care about specific components\r\n }\r\n\r\n /**\r\n * Resets the state of the collector for a new root visit.\r\n */\r\n private reset(): void {\r\n this.tableSchemas = [];\r\n this.visitedNodes = new Set();\r\n this.commonTables = [];\r\n }\r\n\r\n /**\r\n * Consolidates table schemas by merging columns for tables with the same name.\r\n * This ensures that each table name appears only once in the final schema list,\r\n * with all its columns combined while removing duplicates.\r\n *\r\n * Note: The resulting schemas and columns are sorted alphabetically to ensure deterministic ordering.\r\n */\r\n private consolidateTableSchemas(): void {\r\n const consolidatedSchemas: Map<string, Set<string>> = new Map();\r\n\r\n for (const schema of this.tableSchemas) {\r\n if (!consolidatedSchemas.has(schema.name)) {\r\n consolidatedSchemas.set(schema.name, new Set(schema.columns));\r\n } else {\r\n const existingColumns = consolidatedSchemas.get(schema.name);\r\n schema.columns.forEach(column => existingColumns?.add(column));\r\n }\r\n }\r\n\r\n this.tableSchemas = Array.from(consolidatedSchemas.entries())\r\n .sort(([nameA], [nameB]) => nameA.localeCompare(nameB)) // Sort by table name\r\n .map(([name, columns]) => {\r\n return new TableSchema(name, Array.from(columns).sort()); // Sort columns alphabetically\r\n });\r\n }\r\n\r\n private handleTableSource(source: SourceExpression, queryColumns: { table: string, column: string }[], includeUnnamed: boolean): void {\r\n if (source.datasource instanceof TableSource) {\r\n const tableName = source.datasource.getSourceName();\r\n const cte = this.commonTables.filter((table) => table.getSourceAliasName() === tableName);\r\n if (cte.length > 0) {\r\n cte[0].query.accept(this);\r\n } else {\r\n const tableAlias = source.getAliasName() ?? tableName;\r\n this.processCollectTableSchema(tableName, tableAlias, queryColumns, includeUnnamed);\r\n }\r\n } else {\r\n throw new Error(\"Datasource is not an instance of TableSource\");\r\n }\r\n }\r\n\r\n private visitSimpleSelectQuery(query: SimpleSelectQuery): void {\r\n if (query.fromClause === null) {\r\n return;\r\n }\r\n\r\n // Collect columns used in the query\r\n const columnCollector = new SelectableColumnCollector(this.tableColumnResolver, true, DuplicateDetectionMode.FullName);\r\n const columns = columnCollector.collect(query);\r\n const queryColumns = columns.filter((column) => column.value instanceof ColumnReference)\r\n .map(column => column.value as ColumnReference)\r\n .map(columnRef => ({\r\n table: columnRef.getNamespace(),\r\n column: columnRef.column.name\r\n }));\r\n\r\n // Throw an error if there are columns without table names in queries with joins\r\n if (query.fromClause.joins !== null && query.fromClause.joins.length > 0) {\r\n const columnsWithoutTable = queryColumns.filter((columnRef) => columnRef.table === \"\").map((columnRef) => columnRef.column);\r\n if (columnsWithoutTable.length > 0) {\r\n throw new Error(`Column reference(s) without table name found in query: ${columnsWithoutTable.join(', ')}`);\r\n }\r\n }\r\n\r\n // Handle the main FROM clause table\r\n if (query.fromClause.source.datasource instanceof TableSource) {\r\n this.handleTableSource(query.fromClause.source, queryColumns, true);\r\n } else if (query.fromClause.source.datasource instanceof SubQuerySource) {\r\n query.fromClause.source.datasource.query.accept(this);\r\n }\r\n\r\n // Handle JOIN clause tables\r\n if (query.fromClause?.joins) {\r\n for (const join of query.fromClause.joins) {\r\n if (join.source.datasource instanceof TableSource) {\r\n this.handleTableSource(join.source, queryColumns, false);\r\n } else if (join.source.datasource instanceof SubQuerySource) {\r\n join.source.datasource.query.accept(this);\r\n }\r\n }\r\n }\r\n }\r\n\r\n private visitBinarySelectQuery(query: BinarySelectQuery): void {\r\n // Visit the left and right queries\r\n this.visitNode(query.left);\r\n this.visitNode(query.right);\r\n }\r\n\r\n private processCollectTableSchema(tableName: string, tableAlias: string, queryColumns: { table: string, column: string }[], includeUnnamed: boolean = false): void {\r\n // If a wildcard is present and no resolver is provided, throw an error\r\n if (this.tableColumnResolver === null) {\r\n const hasWildcard = queryColumns\r\n .filter((columnRef) => columnRef.table === tableAlias || (includeUnnamed && columnRef.table === \"\"))\r\n .filter((columnRef) => columnRef.column === \"*\")\r\n .length > 0;\r\n if (hasWildcard) {\r\n const errorMessage = tableName\r\n ? `Wildcard (*) is used. A TableColumnResolver is required to resolve wildcards. Target table: ${tableName}`\r\n : \"Wildcard (*) is used. A TableColumnResolver is required to resolve wildcards.\";\r\n throw new Error(errorMessage);\r\n }\r\n }\r\n\r\n let tableColumns = queryColumns\r\n .filter((columnRef) => columnRef.column !== \"*\")\r\n .filter((columnRef) => columnRef.table === tableAlias || (includeUnnamed && columnRef.table === \"\"))\r\n .map((columnRef) => columnRef.column);\r\n\r\n const tableSchema = new TableSchema(tableName, tableColumns);\r\n this.tableSchemas.push(tableSchema);\r\n }\r\n}\r\n", "import { SelectQuery, SimpleSelectQuery } from \"../models/SelectQuery\";\r\nimport { BinarySelectQuery } from \"../models/BinarySelectQuery\";\r\nimport { SelectableColumnCollector } from \"./SelectableColumnCollector\";\r\nimport { BinaryExpression, FunctionCall, ParameterExpression, ParenExpression, ValueComponent, ValueList } from \"../models/ValueComponent\";\r\nimport { UpstreamSelectQueryFinder } from \"./UpstreamSelectQueryFinder\";\r\nimport { SelectQueryParser } from \"../parsers/SelectQueryParser\";\r\n\r\n/**\r\n * Options for SqlParamInjector\r\n */\r\nexport interface SqlParamInjectorOptions {\r\n /** Whether to ignore case and underscore differences when matching column names */\r\n ignoreCaseAndUnderscore?: boolean;\r\n /** Whether to allow injection when all parameters are undefined (defaults to false for safety) */\r\n allowAllUndefined?: boolean;\r\n}\r\n\r\n/**\r\n * SqlParamInjector injects state parameters into a SelectQuery model,\r\n * creating WHERE conditions and setting parameter values.\r\n */\r\nexport class SqlParamInjector {\r\n private tableColumnResolver?: (tableName: string) => string[];\r\n private options: SqlParamInjectorOptions;\r\n\r\n constructor(optionsOrResolver?: SqlParamInjectorOptions | ((tableName: string) => string[]), options?: SqlParamInjectorOptions) {\r\n // Type-check to decide which argument was provided\r\n if (typeof optionsOrResolver === 'function') {\r\n this.tableColumnResolver = optionsOrResolver;\r\n this.options = options || {};\r\n } else {\r\n this.tableColumnResolver = undefined;\r\n this.options = optionsOrResolver || {};\r\n }\r\n }\r\n\r\n /**\r\n * Injects parameters as WHERE conditions into the given query model.\r\n * @param query The SelectQuery to modify\r\n * @param state A record of parameter names and values\r\n * @returns The modified SelectQuery\r\n * @throws Error when all parameters are undefined and allowAllUndefined is not set to true\r\n */\r\n public inject(\r\n query: SimpleSelectQuery | string,\r\n state: Record<string, number | string | boolean | Date | null | undefined | Condition>\r\n ): SelectQuery {\r\n // Convert string query to SimpleSelectQuery using SelectQueryParser if needed\r\n if (typeof query === 'string') {\r\n query = SelectQueryParser.parse(query) as SimpleSelectQuery;\r\n }\r\n\r\n // Pass tableColumnResolver to finder and collector\r\n const finder = new UpstreamSelectQueryFinder(this.tableColumnResolver, this.options);\r\n const collector = new SelectableColumnCollector(this.tableColumnResolver);\r\n // Normalization is handled locally below.\r\n const normalize = (s: string) =>\r\n this.options.ignoreCaseAndUnderscore ? s.toLowerCase().replace(/_/g, '') : s;\r\n\r\n const allowedOps = ['min', 'max', 'like', 'ilike', 'in', 'any', '=', '<', '>', '!=', '<>', '<=', '>=', 'or', 'and', 'column'];\r\n\r\n // Check if all parameters are undefined\r\n const stateValues = Object.values(state);\r\n const hasParameters = stateValues.length > 0;\r\n const allUndefined = hasParameters && stateValues.every(value => value === undefined);\r\n \r\n if (allUndefined && !this.options.allowAllUndefined) {\r\n throw new Error('All parameters are undefined. This would result in fetching all records. Use allowAllUndefined: true option to explicitly allow this behavior.');\r\n }\r\n\r\n for (const [name, stateValue] of Object.entries(state)) {\r\n // skip undefined values\r\n if (stateValue === undefined) continue;\r\n\r\n this.processStateParameter(\r\n name, stateValue, query, finder, collector, normalize, allowedOps,\r\n injectOrConditions, injectAndConditions, injectSimpleCondition, injectComplexConditions, validateOperators\r\n );\r\n } function injectAndConditions(\r\n q: SimpleSelectQuery,\r\n baseName: string,\r\n andConditions: SingleCondition[],\r\n normalize: (s: string) => string,\r\n availableColumns: { name: string; value: ValueComponent }[],\r\n collector: SelectableColumnCollector\r\n ): void {\r\n // For AND conditions, we process each condition and add them all with AND logic\r\n for (let i = 0; i < andConditions.length; i++) {\r\n const andCondition = andConditions[i];\r\n const columnName = andCondition.column || baseName;\r\n\r\n // Find the target column\r\n const entry = availableColumns.find(item => normalize(item.name) === normalize(columnName));\r\n if (!entry) {\r\n throw new Error(`Column '${columnName}' not found in query for AND condition`);\r\n }\r\n const columnRef = entry.value;\r\n\r\n // Process each operator in the AND condition\r\n if ('=' in andCondition && andCondition['='] !== undefined) {\r\n const paramName = `${baseName}_and_${i}_eq`;\r\n const paramExpr = new ParameterExpression(paramName, andCondition['=']);\r\n q.appendWhere(new BinaryExpression(columnRef, \"=\", paramExpr));\r\n }\r\n if ('min' in andCondition && andCondition.min !== undefined) {\r\n const paramName = `${baseName}_and_${i}_min`;\r\n const paramExpr = new ParameterExpression(paramName, andCondition.min);\r\n q.appendWhere(new BinaryExpression(columnRef, \">=\", paramExpr));\r\n }\r\n if ('max' in andCondition && andCondition.max !== undefined) {\r\n const paramName = `${baseName}_and_${i}_max`;\r\n const paramExpr = new ParameterExpression(paramName, andCondition.max);\r\n q.appendWhere(new BinaryExpression(columnRef, \"<=\", paramExpr));\r\n } if ('like' in andCondition && andCondition.like !== undefined) {\r\n const paramName = `${baseName}_and_${i}_like`;\r\n const paramExpr = new ParameterExpression(paramName, andCondition.like);\r\n q.appendWhere(new BinaryExpression(columnRef, \"like\", paramExpr));\r\n }\r\n if ('ilike' in andCondition && andCondition.ilike !== undefined) {\r\n const paramName = `${baseName}_and_${i}_ilike`;\r\n const paramExpr = new ParameterExpression(paramName, andCondition.ilike);\r\n q.appendWhere(new BinaryExpression(columnRef, \"ilike\", paramExpr));\r\n }\r\n if ('in' in andCondition && andCondition.in !== undefined) {\r\n const arr = andCondition.in as (number | string)[];\r\n const prms: ParameterExpression[] = arr.map((v, j) =>\r\n new ParameterExpression(`${baseName}_and_${i}_in_${j}`, v)\r\n );\r\n q.appendWhere(new BinaryExpression(columnRef, \"in\", new ParenExpression(new ValueList(prms))));\r\n }\r\n if ('any' in andCondition && andCondition.any !== undefined) {\r\n const paramName = `${baseName}_and_${i}_any`;\r\n const paramExpr = new ParameterExpression(paramName, andCondition.any);\r\n q.appendWhere(new BinaryExpression(columnRef, \"=\", new FunctionCall(null, \"any\", paramExpr, null)));\r\n }\r\n if ('<' in andCondition && andCondition['<'] !== undefined) {\r\n const paramName = `${baseName}_and_${i}_lt`;\r\n const paramExpr = new ParameterExpression(paramName, andCondition['<']);\r\n q.appendWhere(new BinaryExpression(columnRef, \"<\", paramExpr));\r\n }\r\n if ('>' in andCondition && andCondition['>'] !== undefined) {\r\n const paramName = `${baseName}_and_${i}_gt`;\r\n const paramExpr = new ParameterExpression(paramName, andCondition['>']);\r\n q.appendWhere(new BinaryExpression(columnRef, \">\", paramExpr));\r\n }\r\n if ('!=' in andCondition && andCondition['!='] !== undefined) {\r\n const paramName = `${baseName}_and_${i}_neq`;\r\n const paramExpr = new ParameterExpression(paramName, andCondition['!=']);\r\n q.appendWhere(new BinaryExpression(columnRef, \"!=\", paramExpr));\r\n }\r\n if ('<>' in andCondition && andCondition['<>'] !== undefined) {\r\n const paramName = `${baseName}_and_${i}_ne`;\r\n const paramExpr = new ParameterExpression(paramName, andCondition['<>']);\r\n q.appendWhere(new BinaryExpression(columnRef, \"<>\", paramExpr));\r\n }\r\n if ('<=' in andCondition && andCondition['<='] !== undefined) {\r\n const paramName = `${baseName}_and_${i}_le`;\r\n const paramExpr = new ParameterExpression(paramName, andCondition['<=']);\r\n q.appendWhere(new BinaryExpression(columnRef, \"<=\", paramExpr));\r\n }\r\n if ('>=' in andCondition && andCondition['>='] !== undefined) {\r\n const paramName = `${baseName}_and_${i}_ge`;\r\n const paramExpr = new ParameterExpression(paramName, andCondition['>=']);\r\n q.appendWhere(new BinaryExpression(columnRef, \">=\", paramExpr));\r\n }\r\n }\r\n }\r\n\r\n function injectOrConditions(\r\n q: SimpleSelectQuery,\r\n baseName: string,\r\n orConditions: SingleCondition[],\r\n normalize: (s: string) => string,\r\n availableColumns: { name: string; value: ValueComponent }[],\r\n collector: SelectableColumnCollector\r\n ): void {\r\n const orExpressions: ValueComponent[] = [];\r\n\r\n for (let i = 0; i < orConditions.length; i++) {\r\n const orCondition = orConditions[i];\r\n const columnName = orCondition.column || baseName;\r\n\r\n // Find the target column\r\n const entry = availableColumns.find(item => normalize(item.name) === normalize(columnName));\r\n if (!entry) {\r\n throw new Error(`Column '${columnName}' not found in query for OR condition`);\r\n }\r\n const columnRef = entry.value;\r\n\r\n // Create conditions for this OR branch\r\n const branchConditions: ValueComponent[] = [];\r\n\r\n // Process each operator in the OR condition\r\n if ('=' in orCondition && orCondition['='] !== undefined) {\r\n const paramName = `${baseName}_or_${i}_eq`;\r\n const paramExpr = new ParameterExpression(paramName, orCondition['=']);\r\n branchConditions.push(new BinaryExpression(columnRef, \"=\", paramExpr));\r\n }\r\n if ('min' in orCondition && orCondition.min !== undefined) {\r\n const paramName = `${baseName}_or_${i}_min`;\r\n const paramExpr = new ParameterExpression(paramName, orCondition.min);\r\n branchConditions.push(new BinaryExpression(columnRef, \">=\", paramExpr));\r\n }\r\n if ('max' in orCondition && orCondition.max !== undefined) {\r\n const paramName = `${baseName}_or_${i}_max`;\r\n const paramExpr = new ParameterExpression(paramName, orCondition.max);\r\n branchConditions.push(new BinaryExpression(columnRef, \"<=\", paramExpr));\r\n } if ('like' in orCondition && orCondition.like !== undefined) {\r\n const paramName = `${baseName}_or_${i}_like`;\r\n const paramExpr = new ParameterExpression(paramName, orCondition.like);\r\n branchConditions.push(new BinaryExpression(columnRef, \"like\", paramExpr));\r\n }\r\n if ('ilike' in orCondition && orCondition.ilike !== undefined) {\r\n const paramName = `${baseName}_or_${i}_ilike`;\r\n const paramExpr = new ParameterExpression(paramName, orCondition.ilike);\r\n branchConditions.push(new BinaryExpression(columnRef, \"ilike\", paramExpr));\r\n }\r\n if ('in' in orCondition && orCondition.in !== undefined) {\r\n const arr = orCondition.in as (number | string)[];\r\n const prms: ParameterExpression[] = arr.map((v, j) =>\r\n new ParameterExpression(`${baseName}_or_${i}_in_${j}`, v)\r\n );\r\n branchConditions.push(new BinaryExpression(columnRef, \"in\", new ParenExpression(new ValueList(prms))));\r\n }\r\n if ('any' in orCondition && orCondition.any !== undefined) {\r\n const paramName = `${baseName}_or_${i}_any`;\r\n const paramExpr = new ParameterExpression(paramName, orCondition.any);\r\n branchConditions.push(new BinaryExpression(columnRef, \"=\", new FunctionCall(null, \"any\", paramExpr, null)));\r\n }\r\n if ('<' in orCondition && orCondition['<'] !== undefined) {\r\n const paramName = `${baseName}_or_${i}_lt`;\r\n const paramExpr = new ParameterExpression(paramName, orCondition['<']);\r\n branchConditions.push(new BinaryExpression(columnRef, \"<\", paramExpr));\r\n }\r\n if ('>' in orCondition && orCondition['>'] !== undefined) {\r\n const paramName = `${baseName}_or_${i}_gt`;\r\n const paramExpr = new ParameterExpression(paramName, orCondition['>']);\r\n branchConditions.push(new BinaryExpression(columnRef, \">\", paramExpr));\r\n }\r\n if ('!=' in orCondition && orCondition['!='] !== undefined) {\r\n const paramName = `${baseName}_or_${i}_neq`;\r\n const paramExpr = new ParameterExpression(paramName, orCondition['!=']);\r\n branchConditions.push(new BinaryExpression(columnRef, \"!=\", paramExpr));\r\n }\r\n if ('<>' in orCondition && orCondition['<>'] !== undefined) {\r\n const paramName = `${baseName}_or_${i}_ne`;\r\n const paramExpr = new ParameterExpression(paramName, orCondition['<>']);\r\n branchConditions.push(new BinaryExpression(columnRef, \"<>\", paramExpr));\r\n }\r\n if ('<=' in orCondition && orCondition['<='] !== undefined) {\r\n const paramName = `${baseName}_or_${i}_le`;\r\n const paramExpr = new ParameterExpression(paramName, orCondition['<=']);\r\n branchConditions.push(new BinaryExpression(columnRef, \"<=\", paramExpr));\r\n }\r\n if ('>=' in orCondition && orCondition['>='] !== undefined) {\r\n const paramName = `${baseName}_or_${i}_ge`;\r\n const paramExpr = new ParameterExpression(paramName, orCondition['>=']);\r\n branchConditions.push(new BinaryExpression(columnRef, \">=\", paramExpr));\r\n }\r\n\r\n // Combine branch conditions with AND if there are multiple\r\n if (branchConditions.length > 0) {\r\n let branchExpr = branchConditions[0];\r\n for (let j = 1; j < branchConditions.length; j++) {\r\n branchExpr = new BinaryExpression(branchExpr, \"and\", branchConditions[j]);\r\n }\r\n // Wrap in parentheses if multiple conditions within the OR branch\r\n if (branchConditions.length > 1) {\r\n orExpressions.push(new ParenExpression(branchExpr));\r\n } else {\r\n orExpressions.push(branchExpr);\r\n }\r\n }\r\n }\r\n\r\n // Combine OR expressions\r\n if (orExpressions.length > 0) {\r\n let finalOrExpr = orExpressions[0];\r\n for (let i = 1; i < orExpressions.length; i++) {\r\n finalOrExpr = new BinaryExpression(finalOrExpr, \"or\", orExpressions[i]);\r\n }\r\n\r\n // Wrap in parentheses and append to WHERE clause\r\n q.appendWhere(new ParenExpression(finalOrExpr));\r\n }\r\n }\r\n\r\n function validateOperators(stateValue: object, allowedOps: string[], name: string): void {\r\n Object.keys(stateValue).forEach(op => {\r\n if (!allowedOps.includes(op)) {\r\n throw new Error(`Unsupported operator '${op}' for state key '${name}'`);\r\n }\r\n });\r\n }\r\n\r\n function injectSimpleCondition(q: SimpleSelectQuery, columnRef: ValueComponent, name: string, stateValue: any): void {\r\n const paramExpr = new ParameterExpression(name, stateValue);\r\n q.appendWhere(new BinaryExpression(columnRef, \"=\", paramExpr));\r\n } function injectComplexConditions(q: SimpleSelectQuery, columnRef: ValueComponent, name: string, stateValue: Condition): void {\r\n const conditions: ValueComponent[] = [];\r\n\r\n if ('=' in stateValue) {\r\n const paramEq = new ParameterExpression(name, stateValue['=']);\r\n conditions.push(new BinaryExpression(columnRef, \"=\", paramEq));\r\n }\r\n if ('min' in stateValue) {\r\n const paramMin = new ParameterExpression(name + \"_min\", stateValue.min);\r\n conditions.push(new BinaryExpression(columnRef, \">=\", paramMin));\r\n }\r\n if ('max' in stateValue) {\r\n const paramMax = new ParameterExpression(name + \"_max\", stateValue.max);\r\n conditions.push(new BinaryExpression(columnRef, \"<=\", paramMax));\r\n } if ('like' in stateValue) {\r\n const paramLike = new ParameterExpression(name + \"_like\", stateValue.like);\r\n conditions.push(new BinaryExpression(columnRef, \"like\", paramLike));\r\n }\r\n if ('ilike' in stateValue) {\r\n const paramIlike = new ParameterExpression(name + \"_ilike\", stateValue.ilike);\r\n conditions.push(new BinaryExpression(columnRef, \"ilike\", paramIlike));\r\n }\r\n if ('in' in stateValue) {\r\n const arr = stateValue['in'] as (number | string)[];\r\n const prms: ParameterExpression[] = arr.map((v, i) =>\r\n new ParameterExpression(`${name}_in_${i}`, v)\r\n );\r\n conditions.push(new BinaryExpression(columnRef, \"in\", new ParenExpression(new ValueList(prms))));\r\n }\r\n if ('any' in stateValue) {\r\n const paramAny = new ParameterExpression(name + \"_any\", stateValue.any);\r\n conditions.push(new BinaryExpression(columnRef, \"=\", new FunctionCall(null, \"any\", paramAny, null)));\r\n }\r\n if ('<' in stateValue) {\r\n const paramLT = new ParameterExpression(name + \"_lt\", stateValue['<']);\r\n conditions.push(new BinaryExpression(columnRef, \"<\", paramLT));\r\n }\r\n if ('>' in stateValue) {\r\n const paramGT = new ParameterExpression(name + \"_gt\", stateValue['>']);\r\n conditions.push(new BinaryExpression(columnRef, \">\", paramGT));\r\n }\r\n if ('!=' in stateValue) {\r\n const paramNEQ = new ParameterExpression(name + \"_neq\", stateValue['!=']);\r\n conditions.push(new BinaryExpression(columnRef, \"!=\", paramNEQ));\r\n }\r\n if ('<>' in stateValue) {\r\n const paramNE = new ParameterExpression(name + \"_ne\", stateValue['<>']);\r\n conditions.push(new BinaryExpression(columnRef, \"<>\", paramNE));\r\n }\r\n if ('<=' in stateValue) {\r\n const paramLE = new ParameterExpression(name + \"_le\", stateValue['<=']);\r\n conditions.push(new BinaryExpression(columnRef, \"<=\", paramLE));\r\n }\r\n if ('>=' in stateValue) {\r\n const paramGE = new ParameterExpression(name + \"_ge\", stateValue['>=']);\r\n conditions.push(new BinaryExpression(columnRef, \">=\", paramGE));\r\n }\r\n\r\n // Combine conditions with AND and wrap in parentheses if multiple conditions for clarity\r\n if (conditions.length === 1) {\r\n // Single condition - no parentheses needed\r\n q.appendWhere(conditions[0]);\r\n } else if (conditions.length > 1) {\r\n // Multiple conditions - combine with AND and wrap in parentheses for clarity\r\n let combinedExpr = conditions[0];\r\n for (let i = 1; i < conditions.length; i++) {\r\n combinedExpr = new BinaryExpression(combinedExpr, \"and\", conditions[i]);\r\n }\r\n q.appendWhere(new ParenExpression(combinedExpr));\r\n }\r\n }\r\n\r\n return query;\r\n }\r\n\r\n /**\r\n * Type guard for OR conditions\r\n */\r\n private isOrCondition(value: any): value is { or: SingleCondition[] } {\r\n return value !== null && typeof value === 'object' && !Array.isArray(value) && 'or' in value;\r\n }\r\n\r\n /**\r\n * Type guard for AND conditions\r\n */\r\n private isAndCondition(value: any): value is { and: SingleCondition[] } {\r\n return value !== null && typeof value === 'object' && !Array.isArray(value) && 'and' in value;\r\n }\r\n\r\n /**\r\n * Type guard for explicit column mapping without OR\r\n */\r\n private isExplicitColumnMapping(value: any): value is { column: string } {\r\n return value !== null && typeof value === 'object' && !Array.isArray(value) && \r\n 'column' in value && !('or' in value);\r\n }\r\n\r\n /**\r\n * Type guard for objects that need operator validation\r\n */\r\n private isValidatableObject(value: any): value is object {\r\n return value !== null && typeof value === 'object' && !Array.isArray(value) && \r\n Object.getPrototypeOf(value) === Object.prototype;\r\n }\r\n\r\n /**\r\n * Type guard for column mapping presence\r\n */\r\n private hasColumnMapping(value: any): value is { column?: string } {\r\n return value !== null && typeof value === 'object' && !Array.isArray(value) && 'column' in value;\r\n }\r\n\r\n /**\r\n * Type guard for simple values (non-object conditions)\r\n */\r\n private isSimpleValue(value: any): boolean {\r\n return value === null || typeof value !== 'object' || Array.isArray(value) || value instanceof Date;\r\n }\r\n\r\n /**\r\n * Processes a single state parameter\r\n */\r\n private processStateParameter(\r\n name: string,\r\n stateValue: any,\r\n query: SimpleSelectQuery,\r\n finder: UpstreamSelectQueryFinder,\r\n collector: SelectableColumnCollector,\r\n normalize: (s: string) => string,\r\n allowedOps: string[],\r\n injectOrConditions: Function,\r\n injectAndConditions: Function,\r\n injectSimpleCondition: Function,\r\n injectComplexConditions: Function,\r\n validateOperators: Function\r\n ): void {\r\n // Handle OR conditions specially - they don't need the main column to exist\r\n if (this.isOrCondition(stateValue)) {\r\n const orConditions = stateValue.or as SingleCondition[];\r\n if (orConditions && orConditions.length > 0) {\r\n const targetQuery = this.findTargetQueryForLogicalCondition(\r\n finder, query, name, orConditions\r\n );\r\n const allColumns = this.getAllAvailableColumns(targetQuery, collector);\r\n injectOrConditions(targetQuery, name, orConditions, normalize, allColumns, collector);\r\n return;\r\n }\r\n }\r\n\r\n // Handle AND conditions specially - they don't need the main column to exist\r\n if (this.isAndCondition(stateValue)) {\r\n const andConditions = stateValue.and as SingleCondition[];\r\n if (andConditions && andConditions.length > 0) {\r\n const targetQuery = this.findTargetQueryForLogicalCondition(\r\n finder, query, name, andConditions\r\n );\r\n const allColumns = this.getAllAvailableColumns(targetQuery, collector);\r\n injectAndConditions(targetQuery, name, andConditions, normalize, allColumns, collector);\r\n return;\r\n }\r\n }\r\n\r\n // Handle explicit column mapping without OR\r\n if (this.isExplicitColumnMapping(stateValue)) {\r\n const explicitColumnName = stateValue.column;\r\n if (explicitColumnName) {\r\n const queries = finder.find(query, explicitColumnName);\r\n if (queries.length === 0) {\r\n throw new Error(`Explicit column '${explicitColumnName}' not found in query`);\r\n }\r\n\r\n for (const q of queries) {\r\n const allColumns = this.getAllAvailableColumns(q, collector);\r\n const entry = allColumns.find(item => normalize(item.name) === normalize(explicitColumnName));\r\n if (!entry) {\r\n throw new Error(`Explicit column '${explicitColumnName}' not found in query`);\r\n }\r\n\r\n // if object, validate its keys\r\n if (this.isValidatableObject(stateValue)) {\r\n validateOperators(stateValue, allowedOps, name);\r\n }\r\n\r\n injectComplexConditions(q, entry.value, name, stateValue);\r\n }\r\n return;\r\n }\r\n }\r\n\r\n // Handle regular column conditions\r\n this.processRegularColumnCondition(\r\n name, stateValue, query, finder, collector, normalize, allowedOps,\r\n injectSimpleCondition, injectComplexConditions, validateOperators\r\n );\r\n }\r\n\r\n /**\r\n * Processes regular column conditions (non-logical, non-explicit)\r\n */\r\n private processRegularColumnCondition(\r\n name: string,\r\n stateValue: any,\r\n query: SimpleSelectQuery,\r\n finder: UpstreamSelectQueryFinder,\r\n collector: SelectableColumnCollector,\r\n normalize: (s: string) => string,\r\n allowedOps: string[],\r\n injectSimpleCondition: Function,\r\n injectComplexConditions: Function,\r\n validateOperators: Function\r\n ): void {\r\n const queries = finder.find(query, name);\r\n if (queries.length === 0) {\r\n throw new Error(`Column '${name}' not found in query`);\r\n }\r\n\r\n for (const q of queries) {\r\n const allColumns = this.getAllAvailableColumns(q, collector);\r\n const entry = allColumns.find(item => normalize(item.name) === normalize(name));\r\n if (!entry) {\r\n throw new Error(`Column '${name}' not found in query`);\r\n }\r\n const columnRef = entry.value;\r\n \r\n // if object, validate its keys\r\n if (this.isValidatableObject(stateValue)) {\r\n validateOperators(stateValue, allowedOps, name);\r\n }\r\n\r\n // Handle explicit column mapping\r\n let targetColumn = columnRef;\r\n let targetColumnName = name;\r\n if (this.hasColumnMapping(stateValue)) {\r\n const explicitColumnName = stateValue.column;\r\n if (explicitColumnName) {\r\n const explicitEntry = allColumns.find(item => normalize(item.name) === normalize(explicitColumnName));\r\n if (explicitEntry) {\r\n targetColumn = explicitEntry.value;\r\n targetColumnName = explicitColumnName;\r\n }\r\n }\r\n }\r\n\r\n if (this.isSimpleValue(stateValue)) {\r\n injectSimpleCondition(q, targetColumn, targetColumnName, stateValue);\r\n } else {\r\n injectComplexConditions(q, targetColumn, targetColumnName, stateValue);\r\n }\r\n }\r\n }\r\n\r\n /**\r\n * Finds target query for logical conditions (AND/OR)\r\n */\r\n private findTargetQueryForLogicalCondition(\r\n finder: UpstreamSelectQueryFinder,\r\n query: SimpleSelectQuery,\r\n baseName: string,\r\n conditions: SingleCondition[]\r\n ): SimpleSelectQuery {\r\n const referencedColumns = conditions\r\n .map(cond => cond.column || baseName)\r\n .filter((col, index, arr) => arr.indexOf(col) === index); // unique columns\r\n\r\n for (const colName of referencedColumns) {\r\n const queries = finder.find(query, colName);\r\n if (queries.length > 0) {\r\n return queries[0];\r\n }\r\n }\r\n\r\n const conditionType = conditions === (conditions as any).or ? 'OR' : 'AND';\r\n throw new Error(`None of the ${conditionType} condition columns [${referencedColumns.join(', ')}] found in query`);\r\n }\r\n\r\n /**\r\n * Collects all available columns from a query including CTE columns\r\n */\r\n private getAllAvailableColumns(\r\n query: SimpleSelectQuery, \r\n collector: SelectableColumnCollector\r\n ): { name: string; value: ValueComponent }[] {\r\n const columns = collector.collect(query);\r\n const cteColumns = this.collectCTEColumns(query);\r\n return [...columns, ...cteColumns];\r\n }\r\n\r\n /**\r\n * Collects column names and references from CTE definitions\r\n */\r\n private collectCTEColumns(query: SimpleSelectQuery): { name: string; value: ValueComponent }[] {\r\n const cteColumns: { name: string; value: ValueComponent }[] = [];\r\n \r\n if (query.withClause) {\r\n for (const cte of query.withClause.tables) {\r\n try {\r\n const columns = this.collectColumnsFromSelectQuery(cte.query);\r\n cteColumns.push(...columns);\r\n } catch (error) {\r\n // Log error but continue processing other CTEs\r\n console.warn(`Failed to collect columns from CTE '${cte.getSourceAliasName()}':`, error);\r\n }\r\n }\r\n }\r\n \r\n return cteColumns;\r\n }\r\n\r\n /**\r\n * Recursively collects columns from any SelectQuery type\r\n */\r\n private collectColumnsFromSelectQuery(query: SelectQuery): { name: string; value: ValueComponent }[] {\r\n if (query instanceof SimpleSelectQuery) {\r\n const collector = new SelectableColumnCollector(this.tableColumnResolver);\r\n return collector.collect(query);\r\n } else if (query instanceof BinarySelectQuery) {\r\n // For UNION/INTERSECT/EXCEPT, columns from left side are representative\r\n // since both sides must have matching column structure\r\n return this.collectColumnsFromSelectQuery(query.left);\r\n }\r\n return [];\r\n }\r\n}\r\n\r\n// Define allowed condition keywords for state values\r\ntype BaseCondition = {\r\n '='?: number | string | boolean | Date;\r\n min?: number | string | Date;\r\n max?: number | string | Date;\r\n like?: string;\r\n ilike?: string;\r\n in?: (number | string | Date)[];\r\n any?: (number | string | Date)[];\r\n '<'?: number | string | Date;\r\n '>'?: number | string | Date;\r\n '!='?: number | string | boolean | Date;\r\n '<>'?: number | string | boolean | Date;\r\n '<='?: number | string | Date;\r\n '>='?: number | string | Date;\r\n};\r\n\r\n// Single condition with optional column mapping\r\ntype SingleCondition = BaseCondition & {\r\n column?: string;\r\n};\r\n\r\n// Logical grouping conditions\r\ntype LogicalCondition = {\r\n column?: string;\r\n and?: SingleCondition[];\r\n or?: SingleCondition[];\r\n};\r\n\r\n// Main condition type supporting all patterns\r\ntype Condition = BaseCondition | SingleCondition | LogicalCondition;", "import { SelectQuery, SimpleSelectQuery } from \"../models/SelectQuery\";\r\nimport { SelectableColumnCollector } from \"./SelectableColumnCollector\";\r\nimport { OrderByClause, OrderByItem, SortDirection, NullsSortDirection } from \"../models/Clause\";\r\nimport { ValueComponent } from \"../models/ValueComponent\";\r\nimport { SelectQueryParser } from \"../parsers/SelectQueryParser\";\r\n\r\n/**\r\n * SqlSortInjector injects sort conditions into a SelectQuery model,\r\n * creating ORDER BY clauses based on provided sort conditions.\r\n */\r\nexport class SqlSortInjector {\r\n private tableColumnResolver?: (tableName: string) => string[];\r\n\r\n constructor(tableColumnResolver?: (tableName: string) => string[]) {\r\n this.tableColumnResolver = tableColumnResolver;\r\n }\r\n\r\n /**\r\n * Removes ORDER BY clause from the given query.\r\n * @param query The SelectQuery to modify\r\n * @returns The modified SimpleSelectQuery with ORDER BY clause removed\r\n */\r\n public static removeOrderBy(query: SimpleSelectQuery | string): SimpleSelectQuery {\r\n // Convert string query to SimpleSelectQuery using SelectQueryParser if needed\r\n if (typeof query === 'string') {\r\n query = SelectQueryParser.parse(query) as SimpleSelectQuery;\r\n }\r\n\r\n // Check if query is SimpleSelectQuery\r\n if (!(query instanceof SimpleSelectQuery)) {\r\n throw new Error('Complex queries are not supported for ORDER BY removal');\r\n }\r\n\r\n // Create a new query without ORDER BY clause\r\n return new SimpleSelectQuery({\r\n withClause: query.withClause,\r\n selectClause: query.selectClause,\r\n fromClause: query.fromClause,\r\n whereClause: query.whereClause,\r\n groupByClause: query.groupByClause,\r\n havingClause: query.havingClause,\r\n orderByClause: null, // Remove ORDER BY\r\n windowClause: query.windowClause,\r\n limitClause: query.limitClause,\r\n offsetClause: query.offsetClause,\r\n fetchClause: query.fetchClause,\r\n forClause: query.forClause,\r\n });\r\n }\r\n\r\n /**\r\n * Injects sort conditions as ORDER BY clauses into the given query model.\r\n * Appends to existing ORDER BY clause if present.\r\n * @param query The SelectQuery to modify\r\n * @param sortConditions A record of column names and sort conditions\r\n * @returns The modified SimpleSelectQuery\r\n */\r\n public inject(\r\n query: SimpleSelectQuery | string,\r\n sortConditions: SortConditions\r\n ): SimpleSelectQuery {\r\n // Convert string query to SimpleSelectQuery using SelectQueryParser if needed\r\n if (typeof query === 'string') {\r\n query = SelectQueryParser.parse(query) as SimpleSelectQuery;\r\n }\r\n\r\n // Check if query is SimpleSelectQuery\r\n if (!(query instanceof SimpleSelectQuery)) {\r\n throw new Error('Complex queries are not supported for sorting');\r\n }\r\n\r\n // Collect available columns from the current query only (no upstream search)\r\n const collector = new SelectableColumnCollector(this.tableColumnResolver);\r\n const availableColumns = collector.collect(query);\r\n\r\n // Validate that all specified columns exist\r\n for (const columnName of Object.keys(sortConditions)) {\r\n const columnEntry = availableColumns.find(item => item.name === columnName);\r\n if (!columnEntry) {\r\n throw new Error(`Column or alias '${columnName}' not found in current query`);\r\n }\r\n }\r\n\r\n // Build new ORDER BY items\r\n const newOrderByItems: OrderByItem[] = [];\r\n\r\n for (const [columnName, condition] of Object.entries(sortConditions)) {\r\n const columnEntry = availableColumns.find(item => item.name === columnName);\r\n if (!columnEntry) continue; // Should not happen due to validation above\r\n\r\n const columnRef = columnEntry.value;\r\n\r\n // Validate condition\r\n this.validateSortCondition(columnName, condition);\r\n\r\n // Determine sort direction\r\n let sortDirection: SortDirection;\r\n if (condition.desc) {\r\n sortDirection = SortDirection.Descending;\r\n } else {\r\n sortDirection = SortDirection.Ascending; // Default to ASC\r\n }\r\n\r\n // Determine nulls position\r\n let nullsPosition: NullsSortDirection | null = null;\r\n if (condition.nullsFirst) {\r\n nullsPosition = NullsSortDirection.First;\r\n } else if (condition.nullsLast) {\r\n nullsPosition = NullsSortDirection.Last;\r\n }\r\n\r\n // Create OrderByItem\r\n const orderByItem = new OrderByItem(columnRef, sortDirection, nullsPosition);\r\n newOrderByItems.push(orderByItem);\r\n }\r\n\r\n // Combine with existing ORDER BY clause if present\r\n let finalOrderByItems: (OrderByItem | ValueComponent)[] = [];\r\n\r\n if (query.orderByClause) {\r\n // Append to existing ORDER BY\r\n finalOrderByItems = [...query.orderByClause.order, ...newOrderByItems];\r\n } else {\r\n // Create new ORDER BY\r\n finalOrderByItems = newOrderByItems;\r\n }\r\n\r\n // Create new OrderByClause\r\n const newOrderByClause = finalOrderByItems.length > 0\r\n ? new OrderByClause(finalOrderByItems)\r\n : null;\r\n\r\n // Create new query with updated ORDER BY clause\r\n return new SimpleSelectQuery({\r\n withClause: query.withClause,\r\n selectClause: query.selectClause,\r\n fromClause: query.fromClause,\r\n whereClause: query.whereClause,\r\n groupByClause: query.groupByClause,\r\n havingClause: query.havingClause,\r\n orderByClause: newOrderByClause,\r\n windowClause: query.windowClause,\r\n limitClause: query.limitClause,\r\n offsetClause: query.offsetClause,\r\n fetchClause: query.fetchClause,\r\n forClause: query.forClause,\r\n });\r\n }\r\n\r\n /**\r\n * Validates sort condition for a column\r\n */\r\n private validateSortCondition(columnName: string, condition: SortCondition): void {\r\n // Check for conflicting sort directions\r\n if (condition.asc && condition.desc) {\r\n throw new Error(`Conflicting sort directions for column '${columnName}': both asc and desc specified`);\r\n }\r\n\r\n // Check for conflicting nulls positions\r\n if (condition.nullsFirst && condition.nullsLast) {\r\n throw new Error(`Conflicting nulls positions for column '${columnName}': both nullsFirst and nullsLast specified`);\r\n }\r\n\r\n // Check if at least one option is specified\r\n if (!condition.asc && !condition.desc && !condition.nullsFirst && !condition.nullsLast) {\r\n throw new Error(`Empty sort condition for column '${columnName}': at least one sort option must be specified`);\r\n }\r\n }\r\n}\r\n\r\n// Type definitions\r\nexport type SortCondition = {\r\n asc?: boolean;\r\n desc?: boolean;\r\n nullsFirst?: boolean;\r\n nullsLast?: boolean;\r\n};\r\n\r\nexport type SortConditions = {\r\n [columnName: string]: SortCondition;\r\n};\r\n", "import { SelectQuery, SimpleSelectQuery } from \"../models/SelectQuery\";\r\nimport { LimitClause, OffsetClause } from \"../models/Clause\";\r\nimport { LiteralValue, ParameterExpression } from \"../models/ValueComponent\";\r\nimport { SelectQueryParser } from \"../parsers/SelectQueryParser\";\r\n\r\n/**\r\n * Options for pagination injection\r\n */\r\nexport interface PaginationOptions {\r\n /** Page number (1-based) */\r\n page: number;\r\n /** Number of items per page */\r\n pageSize: number;\r\n}\r\n\r\n/**\r\n * SqlPaginationInjector injects pagination (LIMIT/OFFSET) into a SelectQuery model,\r\n * creating LIMIT and OFFSET clauses based on provided pagination options.\r\n */\r\nexport class SqlPaginationInjector {\r\n\r\n /**\r\n * Injects pagination as LIMIT/OFFSET clauses into the given query model.\r\n * @param query The SelectQuery to modify\r\n * @param pagination Pagination options containing page number and page size\r\n * @returns The modified SimpleSelectQuery with pagination applied\r\n */\r\n public inject(\r\n query: SimpleSelectQuery | string,\r\n pagination: PaginationOptions\r\n ): SimpleSelectQuery {\r\n // Validate pagination options\r\n this.validatePaginationOptions(pagination);\r\n\r\n // Convert string query to SimpleSelectQuery using SelectQueryParser if needed\r\n if (typeof query === 'string') {\r\n query = SelectQueryParser.parse(query) as SimpleSelectQuery;\r\n }\r\n\r\n // Check if query is SimpleSelectQuery\r\n if (!(query instanceof SimpleSelectQuery)) {\r\n throw new Error('Complex queries are not supported for pagination');\r\n }\r\n\r\n // Check if query already has LIMIT or OFFSET clauses\r\n if (query.limitClause || query.offsetClause) {\r\n throw new Error('Query already contains LIMIT or OFFSET clause. Use removePagination() first if you want to override existing pagination.');\r\n }\r\n\r\n // Calculate offset\r\n const offset = (pagination.page - 1) * pagination.pageSize;\r\n\r\n // Create LIMIT clause\r\n const limitClause = new LimitClause(\r\n new ParameterExpression('paging_limit', pagination.pageSize)\r\n );\r\n\r\n // Create OFFSET clause (always include for consistent query caching)\r\n const offsetClause = new OffsetClause(\r\n new ParameterExpression('paging_offset', offset)\r\n );\r\n\r\n // Create a new query with pagination clauses\r\n return new SimpleSelectQuery({\r\n withClause: query.withClause,\r\n selectClause: query.selectClause,\r\n fromClause: query.fromClause,\r\n whereClause: query.whereClause,\r\n groupByClause: query.groupByClause,\r\n havingClause: query.havingClause,\r\n orderByClause: query.orderByClause,\r\n windowClause: query.windowClause,\r\n limitClause: limitClause,\r\n offsetClause: offsetClause,\r\n fetchClause: query.fetchClause,\r\n forClause: query.forClause,\r\n });\r\n }\r\n\r\n /**\r\n * Removes LIMIT and OFFSET clauses from the given query.\r\n * @param query The SelectQuery to modify\r\n * @returns The modified SimpleSelectQuery with pagination removed\r\n */\r\n public static removePagination(query: SimpleSelectQuery | string): SimpleSelectQuery {\r\n // Convert string query to SimpleSelectQuery using SelectQueryParser if needed\r\n if (typeof query === 'string') {\r\n query = SelectQueryParser.parse(query) as SimpleSelectQuery;\r\n }\r\n\r\n // Check if query is SimpleSelectQuery\r\n if (!(query instanceof SimpleSelectQuery)) {\r\n throw new Error('Complex queries are not supported for pagination removal');\r\n }\r\n\r\n // Create a new query without LIMIT and OFFSET clauses\r\n return new SimpleSelectQuery({\r\n withClause: query.withClause,\r\n selectClause: query.selectClause,\r\n fromClause: query.fromClause,\r\n whereClause: query.whereClause,\r\n groupByClause: query.groupByClause,\r\n havingClause: query.havingClause,\r\n orderByClause: query.orderByClause,\r\n windowClause: query.windowClause,\r\n limitClause: null, // Remove LIMIT\r\n offsetClause: null, // Remove OFFSET\r\n fetchClause: query.fetchClause,\r\n forClause: query.forClause,\r\n });\r\n }\r\n\r\n /**\r\n * Validates pagination options\r\n * @param pagination Pagination options to validate\r\n * @throws Error if validation fails\r\n */\r\n private validatePaginationOptions(pagination: PaginationOptions): void {\r\n if (!pagination) {\r\n throw new Error('Pagination options are required');\r\n }\r\n\r\n if (typeof pagination.page !== 'number' || pagination.page < 1) {\r\n throw new Error('Page number must be a positive integer (1 or greater)');\r\n }\r\n\r\n if (typeof pagination.pageSize !== 'number' || pagination.pageSize < 1) {\r\n throw new Error('Page size must be a positive integer (1 or greater)');\r\n }\r\n\r\n // Optional: Set reasonable upper limit for page size to prevent performance issues\r\n if (pagination.pageSize > 1000) {\r\n throw new Error('Page size cannot exceed 1000 items');\r\n }\r\n }\r\n}\r\n", "import { SelectQuery, SimpleSelectQuery } from \"../models/SelectQuery\";\r\nimport { SelectQueryParser } from \"../parsers/SelectQueryParser\";\r\nimport { SqlParamInjector } from \"./SqlParamInjector\";\r\nimport { SqlSortInjector, SortConditions } from \"./SqlSortInjector\";\r\nimport { SqlPaginationInjector, PaginationOptions } from \"./SqlPaginationInjector\";\r\nimport { PostgresJsonQueryBuilder, JsonMapping } from \"./PostgresJsonQueryBuilder\";\r\nimport { QueryBuilder } from \"./QueryBuilder\";\r\n\r\n/**\r\n * Options for dynamic query building\r\n */\r\nexport interface QueryBuildOptions {\r\n /** Filter conditions to inject into WHERE clause */\r\n filter?: Record<string, any>;\r\n /** Sort conditions to inject into ORDER BY clause */\r\n sort?: SortConditions;\r\n /** Pagination options to inject LIMIT/OFFSET clauses */\r\n paging?: PaginationOptions;\r\n /** JSON serialization mapping to transform results into hierarchical JSON\r\n * - JsonMapping object: explicit mapping configuration\r\n * - true: auto-load mapping from corresponding .json file\r\n * - false/undefined: no serialization\r\n */\r\n serialize?: JsonMapping | boolean;\r\n /** \r\n * JSONB usage setting. Must be true (default) for PostgreSQL GROUP BY compatibility.\r\n * Setting to false will throw an error as JSON type cannot be used in GROUP BY clauses.\r\n * @default true\r\n */\r\n jsonb?: boolean;\r\n}\r\n\r\n/**\r\n * DynamicQueryBuilder provides pure JavaScript SQL query building capabilities.\r\n * It combines SQL parsing with dynamic condition injection (filtering, sorting, pagination, serialization).\r\n * \r\n * This class is framework-agnostic and does not perform any file I/O operations.\r\n * It only works with SQL content provided as strings.\r\n * \r\n * Key features:\r\n * - Pure JavaScript/TypeScript - no file system dependencies\r\n * - Framework-agnostic - can be used with any database framework\r\n * - Composable - combines multiple injectors in the correct order\r\n * - Type-safe - provides TypeScript types for all options\r\n * - Testable - easy to unit test without mocking file system\r\n */\r\nexport class DynamicQueryBuilder {\r\n private tableColumnResolver?: (tableName: string) => string[];\r\n /**\r\n * Creates a new DynamicQueryBuilder instance\r\n * @param tableColumnResolver Optional function to resolve table columns for wildcard queries\r\n */\r\n constructor(tableColumnResolver?: (tableName: string) => string[]) {\r\n this.tableColumnResolver = tableColumnResolver;\r\n }\r\n\r\n /**\r\n * Builds a SelectQuery from SQL content with dynamic conditions.\r\n * This is a pure function that does not perform any I/O operations.\r\n * * @param sqlContent Raw SQL string to parse and modify\r\n * @param options Dynamic conditions to apply (filter, sort, paging, serialize)\r\n * @returns Modified SelectQuery with all dynamic conditions applied\r\n * * @example\r\n * ```typescript\r\n * const builder = new DynamicQueryBuilder();\r\n * const query = builder.buildQuery(\r\n * 'SELECT id, name FROM users WHERE active = true',\r\n * {\r\n * filter: { status: 'premium' },\r\n * sort: { created_at: { desc: true } },\r\n * paging: { page: 2, pageSize: 10 },\r\n * serialize: { rootName: 'user', rootEntity: { id: 'user', name: 'User', columns: { id: 'id', name: 'name' } }, nestedEntities: [] }\r\n * }\r\n * );\r\n * ```\r\n */\r\n buildQuery(sqlContent: string, options: QueryBuildOptions = {}): SelectQuery {\r\n // Parse the base SQL\r\n let parsedQuery: SimpleSelectQuery;\r\n try {\r\n parsedQuery = SelectQueryParser.parse(sqlContent) as SimpleSelectQuery;\r\n } catch (error) {\r\n throw new Error(`Failed to parse SQL: ${error instanceof Error ? error.message : 'Unknown error'}`);\r\n }\r\n\r\n // Apply dynamic modifications in the correct order\r\n let modifiedQuery: SelectQuery = parsedQuery;\r\n\r\n // 1. Apply filtering first (most selective, should reduce data early)\r\n if (options.filter && Object.keys(options.filter).length > 0) {\r\n const paramInjector = new SqlParamInjector(this.tableColumnResolver);\r\n // Ensure we have a SimpleSelectQuery for the injector\r\n const simpleQuery = QueryBuilder.buildSimpleQuery(modifiedQuery);\r\n modifiedQuery = paramInjector.inject(simpleQuery, options.filter);\r\n }\r\n\r\n // 2. Apply sorting second (after filtering to sort smaller dataset)\r\n if (options.sort && Object.keys(options.sort).length > 0) {\r\n const sortInjector = new SqlSortInjector(this.tableColumnResolver);\r\n // Ensure we have a SimpleSelectQuery for the injector\r\n const simpleQuery = QueryBuilder.buildSimpleQuery(modifiedQuery);\r\n modifiedQuery = sortInjector.inject(simpleQuery, options.sort);\r\n } // 3. Apply pagination third (after filtering and sorting)\r\n if (options.paging) {\r\n const { page = 1, pageSize } = options.paging;\r\n if (pageSize !== undefined) {\r\n const paginationInjector = new SqlPaginationInjector();\r\n const paginationOptions = { page, pageSize };\r\n // Ensure we have a SimpleSelectQuery for the injector\r\n const simpleQuery = QueryBuilder.buildSimpleQuery(modifiedQuery);\r\n modifiedQuery = paginationInjector.inject(simpleQuery, paginationOptions);\r\n }\r\n }\r\n // 4. Apply serialization last (transform the final query structure to JSON)\r\n // Note: boolean values are handled at RawSqlClient level for auto-loading\r\n if (options.serialize && typeof options.serialize === 'object') {\r\n const jsonBuilder = new PostgresJsonQueryBuilder();\r\n // Ensure we have a SimpleSelectQuery for the JSON builder\r\n const simpleQuery = QueryBuilder.buildSimpleQuery(modifiedQuery);\r\n modifiedQuery = jsonBuilder.buildJsonQuery(simpleQuery, options.serialize);\r\n }\r\n\r\n return modifiedQuery;\r\n }\r\n\r\n /**\r\n * Builds a SelectQuery with only filtering applied.\r\n * Convenience method for when you only need dynamic WHERE conditions.\r\n * \r\n * @param sqlContent Raw SQL string to parse and modify\r\n * @param filter Filter conditions to apply\r\n * @returns Modified SelectQuery with filter conditions applied\r\n */\r\n buildFilteredQuery(sqlContent: string, filter: Record<string, any>): SelectQuery {\r\n return this.buildQuery(sqlContent, { filter });\r\n }\r\n\r\n /**\r\n * Builds a SelectQuery with only sorting applied.\r\n * Convenience method for when you only need dynamic ORDER BY clauses.\r\n * \r\n * @param sqlContent Raw SQL string to parse and modify\r\n * @param sort Sort conditions to apply\r\n * @returns Modified SelectQuery with sort conditions applied\r\n */\r\n buildSortedQuery(sqlContent: string, sort: SortConditions): SelectQuery {\r\n return this.buildQuery(sqlContent, { sort });\r\n } /**\r\n * Builds a SelectQuery with only pagination applied.\r\n * Convenience method for when you only need LIMIT/OFFSET clauses.\r\n * \r\n * @param sqlContent Raw SQL string to parse and modify\r\n * @param paging Pagination options to apply\r\n * @returns Modified SelectQuery with pagination applied\r\n */\r\n buildPaginatedQuery(sqlContent: string, paging: PaginationOptions): SelectQuery {\r\n return this.buildQuery(sqlContent, { paging });\r\n }\r\n\r\n /**\r\n * Builds a SelectQuery with only JSON serialization applied.\r\n * Convenience method for when you only need hierarchical JSON transformation.\r\n * \r\n * @param sqlContent Raw SQL string to parse and modify\r\n * @param serialize JSON mapping configuration to apply\r\n * @returns Modified SelectQuery with JSON serialization applied\r\n */\r\n buildSerializedQuery(sqlContent: string, serialize: JsonMapping): SelectQuery {\r\n return this.buildQuery(sqlContent, { serialize });\r\n }\r\n\r\n /**\r\n * Validates SQL content by attempting to parse it.\r\n * Useful for testing SQL validity without applying any modifications.\r\n * \r\n * @param sqlContent Raw SQL string to validate\r\n * @returns true if SQL is valid, throws error if invalid\r\n * @throws Error if SQL cannot be parsed\r\n */\r\n validateSql(sqlContent: string): boolean {\r\n try {\r\n SelectQueryParser.parse(sqlContent);\r\n return true;\r\n } catch (error) {\r\n throw new Error(`Invalid SQL: ${error instanceof Error ? error.message : 'Unknown error'}`);\r\n }\r\n }\r\n}\r\n", "import { SchemaCollector, TableSchema } from '../transformers/SchemaCollector';\r\nimport { SqlComponent } from '../models/SqlComponent';\r\nimport { TableColumnResolver } from '../transformers/TableColumnResolver';\r\nimport { SelectQueryParser } from '../parsers/SelectQueryParser';\r\n\r\nexport class SqlSchemaValidator {\r\n /**\r\n * Validates a SQL query structure against a provided TableColumnResolver or TableSchema array.\r\n * @param sql The SQL query structure to validate, can be a SQL string or a SqlComponent.\r\n * @param tableResolver The TableColumnResolver or TableSchema array to validate against.\r\n * @throws Error if the query contains undefined tables or columns.\r\n */\r\n public static validate(\r\n sql: string | SqlComponent,\r\n tableResolver: TableColumnResolver | TableSchema[]\r\n ): void {\r\n const sqlComponent = typeof sql === 'string' ? SelectQueryParser.parse(sql) : sql;\r\n\r\n // Convert TableSchema[] to a resolver function if necessary\r\n const resolver = Array.isArray(tableResolver)\r\n ? (tableName: string) => {\r\n const schema = tableResolver.find((t) => t.name === tableName);\r\n return schema ? schema.columns : [];\r\n }\r\n : tableResolver;\r\n\r\n const schemaCollector = new SchemaCollector(resolver);\r\n const tableSchemas = schemaCollector.collect(sqlComponent);\r\n const errors: string[] = [];\r\n\r\n for (const tableSchema of tableSchemas) {\r\n const resolvedColumns = resolver(tableSchema.name);\r\n if (resolvedColumns.length === 0) {\r\n errors.push(`Table '${tableSchema.name}' is not defined.`);\r\n continue;\r\n }\r\n\r\n const undefinedColumns = tableSchema.columns.filter(column => !resolvedColumns.includes(column));\r\n if (undefinedColumns.length > 0) {\r\n errors.push(\r\n `Table '${tableSchema.name}' contains undefined columns: ${undefinedColumns.join(', ')}.`\r\n );\r\n }\r\n }\r\n\r\n if (errors.length > 0) {\r\n throw new Error(errors.join('\\n'));\r\n }\r\n }\r\n}\r\n", "import { JsonMapping } from '../transformers/PostgresJsonQueryBuilder';\r\n\r\n/**\r\n * Type alias for nested entity structure from JsonMapping\r\n */\r\ntype NestedEntity = JsonMapping['nestedEntities'][0];\r\n\r\n/**\r\n * Represents the structure extracted from JsonMapping analysis\r\n */\r\nexport type ExtractedStructure =\r\n | 'primitive'\r\n | { [key: string]: ExtractedStructure }\r\n | ExtractedStructure[];\r\n\r\n/**\r\n * Represents the expected type structure for validation\r\n */\r\nexport type ExpectedTypeStructure =\r\n | 'primitive'\r\n | { [key: string]: ExpectedTypeStructure }\r\n | ExpectedTypeStructure[];\r\n\r\n/**\r\n * Result of JsonMapping validation\r\n */\r\nexport interface ValidationResult {\r\n isValid: boolean;\r\n errors: string[];\r\n missingProperties: string[];\r\n extraProperties: string[];\r\n}\r\n\r\nexport class JsonSchemaValidator {\r\n /**\r\n * Validates JsonMapping structure against an expected type structure.\r\n * Checks if the JsonMapping covers all required properties and relationships.\r\n * \r\n * @param jsonMapping The JsonMapping configuration to validate\r\n * @param expectedStructure The expected type structure to validate against\r\n * @returns ValidationResult containing validation status and detailed errors\r\n */\r\n public static validate(\r\n jsonMapping: JsonMapping,\r\n expectedStructure: ExpectedTypeStructure\r\n ): ValidationResult {\r\n const extractedStructure = this.extractStructureFromJsonMapping(jsonMapping);\r\n return this.compareStructures(extractedStructure, expectedStructure);\r\n }\r\n\r\n /**\r\n * Validates JsonMapping structure and throws an error if validation fails.\r\n * Convenience method for strict validation scenarios.\r\n * \r\n * @param jsonMapping The JsonMapping configuration to validate\r\n * @param expectedStructure The expected type structure to validate against\r\n * @throws Error if validation fails with detailed error messages\r\n */\r\n public static validateStrict(\r\n jsonMapping: JsonMapping,\r\n expectedStructure: ExpectedTypeStructure\r\n ): void {\r\n const result = this.validate(jsonMapping, expectedStructure);\r\n if (!result.isValid) {\r\n const errorMessage = [\r\n 'JsonMapping validation failed:',\r\n ...result.errors\r\n ].join('\\n');\r\n throw new Error(errorMessage);\r\n }\r\n }\r\n\r\n /**\r\n * Extracts structure information from JsonMapping configuration.\r\n * Analyzes rootEntity and nestedEntities to build complete structure map.\r\n * \r\n * @param jsonMapping The JsonMapping to analyze\r\n * @returns ExtractedStructure representing the mapping structure\r\n */\r\n private static extractStructureFromJsonMapping(jsonMapping: JsonMapping): ExtractedStructure {\r\n const structure: ExtractedStructure = {};\r\n\r\n // Extract root entity properties\r\n if (jsonMapping.rootEntity && jsonMapping.rootEntity.columns) {\r\n Object.keys(jsonMapping.rootEntity.columns).forEach(propertyName => {\r\n structure[propertyName] = 'primitive';\r\n });\r\n }\r\n // Extract nested entities\r\n if (jsonMapping.nestedEntities) {\r\n // Process direct children of root entity first\r\n jsonMapping.nestedEntities\r\n .filter((entity: NestedEntity) => entity.parentId === jsonMapping.rootEntity.id)\r\n .forEach((entity: NestedEntity) => {\r\n if (entity.propertyName && entity.columns) {\r\n if (entity.relationshipType === 'object') {\r\n // Single object relationship\r\n structure[entity.propertyName] = this.extractNestedEntityStructure(entity, jsonMapping);\r\n } else if (entity.relationshipType === 'array') {\r\n // Array relationship\r\n structure[entity.propertyName] = [this.extractNestedEntityStructure(entity, jsonMapping)];\r\n }\r\n }\r\n });\r\n }\r\n\r\n return structure;\r\n } /**\r\n * Extracts structure from a nested entity, including its children.\r\n */\r\n private static extractNestedEntityStructure(entity: NestedEntity, jsonMapping: JsonMapping): ExtractedStructure {\r\n const entityStructure: ExtractedStructure = {};\r\n\r\n // Add entity's own columns\r\n if (entity.columns) {\r\n Object.keys(entity.columns).forEach(propName => {\r\n entityStructure[propName] = 'primitive';\r\n });\r\n }\r\n\r\n // Add nested children of this entity\r\n if (jsonMapping.nestedEntities) {\r\n jsonMapping.nestedEntities\r\n .filter((childEntity: NestedEntity) => childEntity.parentId === entity.id)\r\n .forEach((childEntity: NestedEntity) => {\r\n if (childEntity.propertyName && childEntity.columns) {\r\n if (childEntity.relationshipType === 'object') {\r\n entityStructure[childEntity.propertyName] = this.extractNestedEntityStructure(childEntity, jsonMapping);\r\n } else if (childEntity.relationshipType === 'array') {\r\n entityStructure[childEntity.propertyName] = [this.extractNestedEntityStructure(childEntity, jsonMapping)];\r\n }\r\n }\r\n });\r\n }\r\n\r\n return entityStructure;\r\n } /**\r\n * Compares extracted structure with expected structure with proper type guards.\r\n */\r\n private static compareStructures(\r\n extracted: ExtractedStructure,\r\n expected: ExpectedTypeStructure,\r\n path: string = ''\r\n ): ValidationResult {\r\n const errors: string[] = [];\r\n const missingProperties: string[] = [];\r\n const extraProperties: string[] = [];\r\n\r\n // Handle primitive comparison\r\n if (extracted === 'primitive' && expected === 'primitive') {\r\n return { isValid: true, errors: [], missingProperties: [], extraProperties: [] };\r\n }\r\n\r\n // Handle array types\r\n if (Array.isArray(expected) && Array.isArray(extracted)) {\r\n if (expected.length > 0 && extracted.length > 0) {\r\n const nestedResult = this.compareStructures(extracted[0], expected[0], `${path}[]`);\r\n errors.push(...nestedResult.errors);\r\n missingProperties.push(...nestedResult.missingProperties);\r\n extraProperties.push(...nestedResult.extraProperties);\r\n }\r\n return { isValid: errors.length === 0, errors, missingProperties, extraProperties };\r\n } // Both should be objects for property comparison\r\n if (typeof extracted !== 'object' || typeof expected !== 'object' ||\r\n Array.isArray(extracted) || Array.isArray(expected) ||\r\n extracted === null || expected === null) {\r\n return { isValid: true, errors: [], missingProperties: [], extraProperties: [] };\r\n }\r\n\r\n // Now we know both are object types, safe to access properties\r\n const extractedObj = extracted as { [key: string]: ExtractedStructure };\r\n const expectedObj = expected as { [key: string]: ExpectedTypeStructure };\r\n\r\n // Check for missing properties in extracted structure\r\n Object.keys(expectedObj).forEach(key => {\r\n const currentPath = path ? `${path}.${key}` : key;\r\n\r\n if (!(key in extractedObj)) {\r\n missingProperties.push(currentPath);\r\n errors.push(`Missing property: ${currentPath}`);\r\n return;\r\n }\r\n\r\n const extractedValue = extractedObj[key];\r\n const expectedValue = expectedObj[key];\r\n\r\n // Recursively compare nested structures\r\n const nestedResult = this.compareStructures(extractedValue, expectedValue, currentPath);\r\n errors.push(...nestedResult.errors);\r\n missingProperties.push(...nestedResult.missingProperties);\r\n extraProperties.push(...nestedResult.extraProperties);\r\n });\r\n\r\n // Check for extra properties in extracted structure\r\n Object.keys(extractedObj).forEach(key => {\r\n const currentPath = path ? `${path}.${key}` : key;\r\n if (!(key in expectedObj)) {\r\n extraProperties.push(currentPath);\r\n // Note: Extra properties are not considered errors in this implementation\r\n // as JsonMapping might include additional metadata\r\n }\r\n });\r\n\r\n return {\r\n isValid: errors.length === 0,\r\n errors,\r\n missingProperties,\r\n extraProperties\r\n };\r\n }\r\n\r\n /**\r\n * Validates JsonMapping structure against a sample object that implements the expected type.\r\n * This method extracts structure from the sample object and compares it with JsonMapping.\r\n * \r\n * @param jsonMapping The JsonMapping configuration to validate\r\n * @param sampleObject A sample object that implements the expected interface/type\r\n * @returns ValidationResult containing validation status and detailed errors\r\n */\r\n public static validateAgainstSample<T>(\r\n jsonMapping: JsonMapping,\r\n sampleObject: T\r\n ): ValidationResult {\r\n const expectedStructure = this.extractStructureFromSample(sampleObject);\r\n return this.validate(jsonMapping, expectedStructure);\r\n }\r\n\r\n /**\r\n * Validates JsonMapping structure against a sample object and throws an error if validation fails.\r\n * Convenience method for strict validation scenarios with sample objects.\r\n * \r\n * @param jsonMapping The JsonMapping configuration to validate\r\n * @param sampleObject A sample object that implements the expected interface/type\r\n * @throws Error if validation fails with detailed error messages\r\n */\r\n public static validateAgainstSampleStrict<T>(\r\n jsonMapping: JsonMapping,\r\n sampleObject: T\r\n ): void {\r\n const result = this.validateAgainstSample(jsonMapping, sampleObject);\r\n if (!result.isValid) {\r\n const errorMessage = [\r\n 'JsonMapping validation against sample object failed:',\r\n ...result.errors\r\n ].join('\\n');\r\n throw new Error(errorMessage);\r\n }\r\n } /**\r\n * Extracts structure information from a sample object.\r\n * Recursively analyzes the object properties to build a structure map.\r\n * \r\n * @param sampleObject The sample object to analyze\r\n * @returns ExpectedTypeStructure representing the object structure\r\n */\r\n private static extractStructureFromSample(sampleObject: any): ExpectedTypeStructure {\r\n if (sampleObject === null || sampleObject === undefined) {\r\n return 'primitive' as ExpectedTypeStructure;\r\n }\r\n\r\n if (Array.isArray(sampleObject)) {\r\n if (sampleObject.length === 0) {\r\n return [] as ExpectedTypeStructure;\r\n }\r\n return [this.extractStructureFromSample(sampleObject[0])] as ExpectedTypeStructure;\r\n }\r\n\r\n if (typeof sampleObject === 'object') {\r\n const structure: { [key: string]: ExpectedTypeStructure } = {};\r\n Object.keys(sampleObject).forEach(key => {\r\n structure[key] = this.extractStructureFromSample(sampleObject[key]);\r\n });\r\n return structure as ExpectedTypeStructure;\r\n }\r\n\r\n // Primitive types (string, number, boolean, etc.)\r\n return 'primitive' as ExpectedTypeStructure;\r\n }\r\n}\r\n", "/**\r\n * Schema Manager for rawsql-ts\r\n * Provides unified schema definition and automatic conversion to various formats\r\n * Eliminates code duplication and provides type-safe schema management\r\n */\r\n\r\n// Import JsonMapping interface for type safety\r\nimport type { JsonMapping } from '../transformers/PostgresJsonQueryBuilder';\r\n\r\n// === Core Types for User-defined Schemas ===\r\n\r\n/**\r\n * Database column metadata for schema mapping\r\n */\r\nexport interface ColumnDefinition {\r\n /** Column name in database */\r\n name: string;\r\n /** Primary key indicator - used for UPDATE/DELETE query WHERE conditions */\r\n isPrimaryKey?: boolean;\r\n /** Foreign key reference */\r\n foreignKey?: {\r\n table: string;\r\n column: string;\r\n };\r\n /** Alias for JSON output (useful for avoiding conflicts) */\r\n jsonAlias?: string;\r\n}\r\n\r\n/**\r\n * Table relationship definition\r\n */\r\nexport interface RelationshipDefinition {\r\n /** Type of relationship */\r\n type: 'object' | 'array';\r\n /** Target table name */\r\n table: string;\r\n /** Property name in JSON output */\r\n propertyName: string;\r\n /** Optional: Override target table's primary key */\r\n targetKey?: string;\r\n}\r\n\r\n/**\r\n * Complete table schema definition that users write\r\n */\r\nexport interface TableDefinition {\r\n /** Table name in database */\r\n name: string;\r\n /** Human-readable entity name */\r\n displayName?: string;\r\n /** Column definitions */\r\n columns: Record<string, ColumnDefinition>;\r\n /** Relationships with other tables */\r\n relationships?: RelationshipDefinition[];\r\n}\r\n\r\n/**\r\n * Schema registry containing all table definitions\r\n */\r\nexport interface SchemaRegistry {\r\n [tableName: string]: TableDefinition;\r\n}\r\n\r\n// === Schema Manager Class ===\r\n\r\n/**\r\n * Central schema management utility for rawsql-ts\r\n * Converts user-defined schemas to various internal formats\r\n */\r\nexport class SchemaManager {\r\n private schemas: SchemaRegistry;\r\n\r\n constructor(schemas: SchemaRegistry) {\r\n this.schemas = schemas;\r\n this.validateSchemas();\r\n }\r\n\r\n /**\r\n * Validate schema definitions for consistency\r\n * Ensures each table has a primary key (required for UPDATE/DELETE operations)\r\n * and validates relationship references\r\n */\r\n private validateSchemas(): void {\r\n const tableNames = Object.keys(this.schemas);\r\n const errors: string[] = [];\r\n\r\n // Validate each table\r\n Object.entries(this.schemas).forEach(([tableName, table]) => {\r\n // Check primary key exists (required for UPDATE/DELETE WHERE conditions)\r\n const primaryKeys = Object.entries(table.columns)\r\n .filter(([_, col]) => col.isPrimaryKey)\r\n .map(([name, _]) => name);\r\n\r\n if (primaryKeys.length === 0) {\r\n errors.push(`Table '${tableName}' has no primary key defined`);\r\n }\r\n\r\n // Validate foreign key references\r\n table.relationships?.forEach(rel => {\r\n if (!tableNames.includes(rel.table)) {\r\n errors.push(`Table '${tableName}' references unknown table '${rel.table}' in relationship`);\r\n }\r\n });\r\n });\r\n\r\n if (errors.length > 0) {\r\n throw new Error(`Schema validation failed:\\\\n${errors.join('\\\\n')}`);\r\n }\r\n }\r\n\r\n /**\r\n * Get table column names for SqlParamInjector TableColumnResolver\r\n * @param tableName Name of the table\r\n * @returns Array of column names\r\n */\r\n public getTableColumns(tableName: string): string[] {\r\n const table = this.schemas[tableName];\r\n if (!table) {\r\n return [];\r\n }\r\n return Object.keys(table.columns);\r\n }\r\n\r\n /**\r\n * Create TableColumnResolver function for SqlParamInjector\r\n * @returns Function compatible with SqlParamInjector\r\n */\r\n public createTableColumnResolver(): (tableName: string) => string[] {\r\n return (tableName: string) => this.getTableColumns(tableName);\r\n }\r\n\r\n /**\r\n * Generate JSON mapping configuration for PostgresJsonQueryBuilder\r\n * @param rootTableName Root table for the JSON structure\r\n * @returns JSON mapping configuration\r\n */\r\n public createJsonMapping(rootTableName: string): JsonMapping {\r\n const rootTable = this.schemas[rootTableName];\r\n if (!rootTable) {\r\n throw new Error(`Table '${rootTableName}' not found in schema registry`);\r\n }\r\n\r\n // Build root entity columns mapping\r\n const rootColumns: Record<string, string> = {};\r\n Object.entries(rootTable.columns).forEach(([columnName, column]) => {\r\n rootColumns[columnName] = column.jsonAlias || column.name;\r\n });\r\n\r\n // Build nested entities from relationships\r\n const nestedEntities: JsonMapping['nestedEntities'] = [];\r\n\r\n rootTable.relationships?.forEach(rel => {\r\n const relatedTable = this.schemas[rel.table];\r\n if (!relatedTable) {\r\n throw new Error(`Related table '${rel.table}' not found in schema registry`);\r\n }\r\n\r\n // Build columns mapping for related table\r\n const relatedColumns: Record<string, string> = {};\r\n Object.entries(relatedTable.columns).forEach(([columnName, column]) => {\r\n relatedColumns[columnName] = column.jsonAlias || column.name;\r\n });\r\n\r\n // Determine relationship type for JSON builder\r\n const relationshipType = rel.type;\r\n\r\n nestedEntities.push({\r\n id: rel.propertyName,\r\n name: relatedTable.displayName || rel.table,\r\n parentId: rootTableName,\r\n propertyName: rel.propertyName,\r\n relationshipType: relationshipType as 'object' | 'array',\r\n columns: relatedColumns\r\n });\r\n });\r\n\r\n return {\r\n rootName: rootTableName,\r\n rootEntity: {\r\n id: rootTableName,\r\n name: rootTable.displayName || rootTableName,\r\n columns: rootColumns\r\n },\r\n nestedEntities,\r\n resultFormat: \"single\" as const\r\n };\r\n }\r\n\r\n /**\r\n * Get all table names in the schema\r\n * @returns Array of table names\r\n */\r\n public getTableNames(): string[] {\r\n return Object.keys(this.schemas);\r\n }\r\n\r\n /**\r\n * Get table definition by name\r\n * @param tableName Name of the table\r\n * @returns Table definition or undefined\r\n */\r\n public getTable(tableName: string): TableDefinition | undefined {\r\n return this.schemas[tableName];\r\n }\r\n\r\n /**\r\n * Get primary key column name for a table\r\n * Used by QueryBuilder.buildUpdateQuery for WHERE clause conditions\r\n * @param tableName Name of the table\r\n * @returns Primary key column name or undefined\r\n */\r\n public getPrimaryKey(tableName: string): string | undefined {\r\n const table = this.schemas[tableName];\r\n if (!table) return undefined;\r\n\r\n const primaryKeyEntry = Object.entries(table.columns)\r\n .find(([_, col]) => col.isPrimaryKey);\r\n\r\n return primaryKeyEntry ? primaryKeyEntry[0] : undefined;\r\n }\r\n\r\n /**\r\n * Get foreign key relationships for a table\r\n * @param tableName Name of the table\r\n * @returns Array of foreign key relationships\r\n */\r\n public getForeignKeys(tableName: string): Array<{ column: string; referencedTable: string; referencedColumn: string }> {\r\n const table = this.schemas[tableName];\r\n if (!table) return [];\r\n\r\n const foreignKeys: Array<{ column: string; referencedTable: string; referencedColumn: string }> = [];\r\n\r\n Object.entries(table.columns).forEach(([columnName, column]) => {\r\n if (column.foreignKey) {\r\n foreignKeys.push({\r\n column: columnName,\r\n referencedTable: column.foreignKey.table,\r\n referencedColumn: column.foreignKey.column\r\n });\r\n }\r\n });\r\n\r\n return foreignKeys;\r\n }\r\n}\r\n\r\n// === Convenience Functions ===\r\n\r\n/**\r\n * Create a SchemaManager instance from schema definitions\r\n * @param schemas Schema registry object\r\n * @returns SchemaManager instance\r\n */\r\nexport function createSchemaManager(schemas: SchemaRegistry): SchemaManager {\r\n return new SchemaManager(schemas);\r\n}\r\n\r\n/**\r\n * Create TableColumnResolver function from schema definitions\r\n * @param schemas Schema registry object\r\n * @returns TableColumnResolver function for SqlParamInjector\r\n */\r\nexport function createTableColumnResolver(schemas: SchemaRegistry): (tableName: string) => string[] {\r\n const manager = new SchemaManager(schemas);\r\n return manager.createTableColumnResolver();\r\n}\r\n\r\n/**\r\n * Create JSON mapping from schema definitions\r\n * @param schemas Schema registry object\r\n * @param rootTableName Root table name\r\n * @returns JSON mapping for PostgresJsonQueryBuilder\r\n */\r\nexport function createJsonMappingFromSchema(schemas: SchemaRegistry, rootTableName: string): JsonMapping {\r\n const manager = new SchemaManager(schemas);\r\n return manager.createJsonMapping(rootTableName);\r\n}\r\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": ["index_exports", "__export", "ArrayExpression", "ArrayQueryExpression", "BetweenExpression", "BinaryExpression", "BinarySelectQuery", "CTECollector", "CTENormalizer", "CaseExpression", "CaseKeyValuePair", "CastExpression", "ColumnReference", "DuplicateDetectionMode", "DynamicQueryBuilder", "Formatter", "FunctionCall", "IdentifierString", "InlineQuery", "InsertQuery", "InsertQueryParser", "JsonMappingConverter", "JsonSchemaValidator", "LiteralValue", "ParameterExpression", "ParenExpression", "PostgresJsonQueryBuilder", "QualifiedName", "QueryBuilder", "RawString", "SchemaCollector", "SchemaManager", "SelectQueryParser", "SelectValueCollector", "SelectableColumnCollector", "SimpleSelectQuery", "SqlFormatter", "SqlPaginationInjector", "SqlParamInjector", "SqlSchemaValidator", "SqlSortInjector", "StringSpecifierExpression", "SwitchCaseArgument", "TableSchema", "TableSourceCollector", "TupleExpression", "TypeTransformationPostProcessor", "TypeTransformers", "TypeValue", "UnaryExpression", "UpstreamSelectQueryFinder", "VALID_PRESETS", "ValueList", "ValuesQuery", "WindowFrameBound", "WindowFrameBoundStatic", "WindowFrameBoundaryValue", "WindowFrameExpression", "WindowFrameSpec", "WindowFrameType", "convertColumnsToLegacy", "convertModelDrivenMapping", "convertToLegacyJsonMapping", "createJsonMappingFromSchema", "createSchemaManager", "createTableColumnResolver", "extractTypeProtection", "isLegacyFormat", "isModelDrivenFormat", "isUnifiedFormat", "processJsonMapping", "toLegacyMapping", "transformDatabaseResult", "unifyJsonMapping", "validateModelDrivenMapping", "__toCommonJS", "SqlComponent", "visitor", "formatter", "InsertQuery", "SqlComponent", "params", "InlineQuery", "SqlComponent", "selectQuery", "ValueList", "values", "ColumnReference", "IdentifierString", "namespaces", "column", "col", "QualifiedName", "toIdentifierStringArray", "namespace", "FunctionCall", "name", "argument", "over", "WindowFrameType", "WindowFrameBound", "WindowFrameBoundStatic", "bound", "WindowFrameBoundaryValue", "value", "isFollowing", "WindowFrameSpec", "frameType", "startBound", "endBound", "WindowFrameExpression", "partition", "order", "frameSpec", "UnaryExpression", "operator", "expression", "RawString", "BinaryExpression", "left", "right", "LiteralValue", "ParameterExpression", "SwitchCaseArgument", "cases", "elseValue", "CaseKeyValuePair", "key", "alias", "ParenExpression", "CastExpression", "input", "castType", "CaseExpression", "condition", "switchCase", "ArrayExpression", "ArrayQueryExpression", "query", "BetweenExpression", "lower", "upper", "negated", "StringSpecifierExpression", "specifier", "TypeValue", "nameValue", "ns", "TupleExpression", "filteredStrings", "filteredIdentifiers", "SelectItem", "SqlComponent", "value", "name", "IdentifierString", "SelectClause", "items", "distinct", "Distinct", "DistinctOn", "WhereClause", "condition", "PartitionByClause", "WindowFrameClause", "expression", "WindowsClause", "windows", "OrderByClause", "SqlComponent", "items", "OrderByItem", "expression", "sortDirection", "nullsPosition", "GroupByClause", "HavingClause", "condition", "TableSource", "IdentifierString", "namespaces", "table", "tbl", "QualifiedName", "namespace", "RawString", "FunctionSource", "name", "argument", "nameObj", "ParenSource", "source", "SubQuerySource", "query", "SourceExpression", "datasource", "aliasExpression", "JoinOnClause", "JoinUsingClause", "JoinClause", "joinType", "lateral", "FromClause", "join", "sources", "CommonTable", "materialized", "SourceAliasExpression", "WithClause", "recursive", "tables", "LimitClause", "limit", "OffsetClause", "SqlComponent", "value", "FetchClause", "expression", "FetchExpression", "type", "count", "unit", "ForClause", "SqlComponent", "lockMode", "SourceAliasExpression", "alias", "columnAlias", "IdentifierString", "ReturningClause", "columns", "col", "SetClause", "items", "item", "SetClauseItem", "column", "value", "colObj", "QualifiedName", "UpdateClause", "source", "TableSource", "InsertClause", "TokenType", "CharLookupTable", "char", "code", "StringUtils", "_StringUtils", "input", "errPosition", "start", "end", "debugInfo", "caret", "position", "length", "charCode", "comment", "lines", "oldPosition", "lineCommentResult", "blockCommentResult", "result", "CharLookupTable", "BaseTokenReader", "input", "position", "shift", "expectChar", "char", "type", "value", "comments", "errPosition", "StringUtils", "IdentifierTokenReader", "BaseTokenReader", "previous", "char", "result", "StringUtils", "KeywordParser", "trie", "input", "position", "shift", "result", "StringUtils", "matchResult", "lexeme", "previousMatchResult", "KeywordTrie", "keywords", "keyword", "node", "word", "lexeme", "keywords", "trie", "KeywordTrie", "literalKeywordParser", "KeywordParser", "LiteralTokenReader", "BaseTokenReader", "previous", "char", "keyword", "CharLookupTable", "value", "sign", "pos", "result", "start", "hasDot", "hasExponent", "prefixType", "isHex", "c", "includeSingleQuote", "closed", "ParameterTokenReader", "BaseTokenReader", "input", "previous", "start", "identifier", "char", "CharLookupTable", "SpecialSymbolTokenReader", "_SpecialSymbolTokenReader", "BaseTokenReader", "previous", "char", "TokenReaderManager", "input", "position", "reader", "readers", "previous", "lexeme", "maxPosition", "total", "ratio", "trie", "KeywordTrie", "operatorOrTypeTrie", "keywordParser", "KeywordParser", "operatorOrTypeParser", "OperatorTokenReader", "BaseTokenReader", "previous", "char", "CharLookupTable", "start", "current", "resut", "result", "operatorOrTypeParser", "keywordParser", "joinTrie", "KeywordTrie", "keywordTrie", "keywordParser", "KeywordParser", "joinkeywordParser", "CommandTokenReader", "BaseTokenReader", "previous", "keywordJoin", "keyword", "start", "STRING_SPECIFIERS", "UNICODE_STRING_SPECIFIERS", "StringSpecifierTokenReader", "BaseTokenReader", "previous", "start", "trie", "KeywordTrie", "keywordParser", "KeywordParser", "FunctionTokenReader", "BaseTokenReader", "previous", "keyword", "result", "StringUtils", "shift", "trie", "KeywordTrie", "typeParser", "KeywordParser", "TypeTokenReader", "BaseTokenReader", "previous", "keyword", "result", "StringUtils", "EscapedIdentifierTokenReader", "BaseTokenReader", "previous", "char", "identifier", "delimiter", "start", "SqlTokenizer", "input", "TokenReaderManager", "EscapedIdentifierTokenReader", "ParameterTokenReader", "StringSpecifierTokenReader", "LiteralTokenReader", "SpecialSymbolTokenReader", "CommandTokenReader", "OperatorTokenReader", "TypeTokenReader", "FunctionTokenReader", "IdentifierTokenReader", "shift", "estimatedTokens", "lexemes", "lexemeCount", "comment", "pendingComments", "previous", "lexeme", "currentComment", "lastToken", "prefixComments", "suffixComments", "StringUtils", "errPosition", "FullNameParser", "_FullNameParser", "lexemes", "index", "identifiers", "newIndex", "namespaces", "name", "lastTokenType", "IdentifierString", "str", "SqlTokenizer", "result", "idx", "IdentifierParser", "lexemes", "index", "namespaces", "name", "newIndex", "FullNameParser", "ColumnReference", "LiteralParser", "lexemes", "index", "idx", "valueText", "parsedValue", "lex", "literalKeywordParser", "value", "RawString", "LiteralValue", "ParenExpressionParser", "lexemes", "index", "idx", "result", "SelectQueryParser", "InlineQuery", "ValueParser", "ParenExpression", "UnaryExpressionParser", "lexemes", "index", "idx", "operator", "ColumnReference", "result", "ValueParser", "UnaryExpression", "ParameterExpressionParser", "lexemes", "index", "idx", "paramName", "value", "ParameterExpression", "StringSpecifierExpressionParser", "lexemes", "index", "idx", "specifer", "value", "StringSpecifierExpression", "CommandExpressionParser", "lexemes", "index", "idx", "current", "command", "result", "ValueParser", "UnaryExpression", "condition", "switchCaseResult", "CaseExpression", "casewhenResult", "caseWhenList", "initialWhenThenList", "whenThenList", "elseValue", "whenResult", "elseResult", "SwitchCaseArgument", "lexeme", "value", "CaseKeyValuePair", "OrderByClauseParser", "query", "lexemes", "SqlTokenizer", "result", "index", "idx", "items", "item", "OrderByClause", "parsedValue", "ValueParser", "value", "sortDirection", "nullsSortDirection", "OrderByItem", "PartitionByParser", "query", "lexemes", "SqlTokenizer", "result", "index", "idx", "items", "item", "ValueParser", "PartitionByClause", "ValueList", "WindowExpressionParser", "query", "lexemes", "SqlTokenizer", "result", "index", "idx", "partition", "order", "frameSpec", "partitionResult", "PartitionByParser", "orderResult", "OrderByClauseParser", "frameSpecResult", "WindowFrameExpression", "value", "lowerValue", "frameTypeStr", "frameType", "startBoundResult", "startBound", "endBoundResult", "endBound", "WindowFrameSpec", "boundaryResult", "currentValue", "frameBound", "WindowFrameBoundStatic", "valueResult", "ValueParser", "direction", "isFollowing", "WindowFrameBoundaryValue", "OverExpressionParser", "query", "lexemes", "SqlTokenizer", "result", "index", "idx", "name", "IdentifierString", "WindowExpressionParser", "FunctionExpressionParser", "lexemes", "index", "idx", "arg", "ValueParser", "ArrayExpression", "SelectQueryParser", "ArrayQueryExpression", "current", "left", "allowAndOperator", "allowOrOperator", "operator", "typeValue", "CastExpression", "rightResult", "BinaryExpression", "value", "negated", "lower", "upper", "BetweenExpression", "fullNameResult", "FullNameParser", "namespaces", "name", "over", "OverExpressionParser", "FunctionCall", "keywords", "input", "key", "required", "right", "newIndex", "TypeValue", "RawString", "ParseError", "_ParseError", "message", "index", "context", "lexemes", "messagePrefix", "start", "end", "lexeme", "idx", "marker", "typeName", "TokenType", "OperatorPrecedence", "operator", "precedence", "operator1", "operator2", "op", "lowerOp", "ValueParser", "query", "lexemes", "SqlTokenizer", "result", "ParseError", "index", "allowAndOperator", "allowOrOperator", "minPrecedence", "idx", "comment", "left", "operator", "precedence", "OperatorPrecedence", "betweenResult", "FunctionExpressionParser", "typeValue", "CastExpression", "nextMinPrecedence", "rightResult", "BinaryExpression", "current", "first", "IdentifierParser", "second", "LiteralParser", "UnaryExpression", "namespaces", "name", "newIndex", "FullNameParser", "TypeValue", "ColumnReference", "ParenExpressionParser", "UnaryExpressionParser", "ParameterExpressionParser", "StringSpecifierExpressionParser", "CommandExpressionParser", "openToken", "closeToken", "args", "ValueList", "wildcard", "argResult", "openParenIndex", "typeName", "alwaysTypeConstructors", "upperTypeName", "firstArgIndex", "firstArg", "CTECollector", "SimpleSelectQuery", "expr", "BinarySelectQuery", "ValuesQuery", "WithClause", "CommonTable", "SelectItem", "IdentifierString", "RawString", "ColumnReference", "ParameterExpression", "LiteralValue", "SourceExpression", "TableSource", "FunctionSource", "ParenSource", "SubQuerySource", "InlineQuery", "FromClause", "JoinClause", "JoinOnClause", "JoinUsingClause", "WhereClause", "ParenExpression", "BinaryExpression", "UnaryExpression", "CaseExpression", "CaseKeyValuePair", "SwitchCaseArgument", "BetweenExpression", "FunctionCall", "ArrayExpression", "ArrayQueryExpression", "TupleExpression", "CastExpression", "WindowFrameExpression", "WindowFrameSpec", "TypeValue", "ValueList", "StringSpecifierExpression", "SelectClause", "GroupByClause", "HavingClause", "OrderByClause", "WindowFrameClause", "LimitClause", "ForClause", "OrderByItem", "PartitionByClause", "query", "arg", "handler", "kindSymbol", "constructor", "win", "tuple", "withClause", "i", "commonTable", "clause", "item", "fromClause", "join", "source", "subQuery", "inlineQuery", "joinClause", "joinOn", "joinUsing", "whereClause", "switchCase", "caseItem", "pair", "func", "value", "spec", "ident", "raw", "column", "param", "partitionBy", "valueList", "CTEDisabler", "SimpleSelectQuery", "expr", "BinarySelectQuery", "ValuesQuery", "SelectItem", "IdentifierString", "RawString", "ColumnReference", "ParameterExpression", "LiteralValue", "SourceExpression", "TableSource", "ParenSource", "SubQuerySource", "InlineQuery", "FromClause", "JoinClause", "JoinOnClause", "JoinUsingClause", "WhereClause", "ParenExpression", "BinaryExpression", "UnaryExpression", "CaseExpression", "CaseKeyValuePair", "SwitchCaseArgument", "BetweenExpression", "FunctionCall", "ArrayExpression", "ArrayQueryExpression", "TupleExpression", "CastExpression", "WindowFrameExpression", "WindowFrameSpec", "TypeValue", "SelectClause", "GroupByClause", "HavingClause", "OrderByClause", "WindowFrameClause", "LimitClause", "ForClause", "OrderByItem", "arg", "handler", "kindSymbol", "constructor", "table", "WindowsClause", "w", "query", "newTuples", "tuple", "clause", "newItems", "item", "newSource", "newJoins", "join", "subQuery", "newQuery", "inlineQuery", "joinClause", "newCondition", "joinOn", "joinUsing", "whereClause", "newGrouping", "newOrder", "newExpression", "newLimit", "newLeft", "newRight", "newSwitchCase", "switchCase", "newCases", "caseItem", "newElseValue", "pair", "newKey", "newValue", "newLower", "newUpper", "func", "newArgument", "newOver", "newValues", "value", "newInput", "newCastType", "typeValue", "ident", "raw", "column", "source", "newAlias", "param", "newPartition", "newFrameSpec", "spec", "TableSourceCollector", "selectableOnly", "SimpleSelectQuery", "expr", "BinarySelectQuery", "ValuesQuery", "WithClause", "CommonTable", "FromClause", "JoinClause", "JoinOnClause", "JoinUsingClause", "SourceExpression", "TableSource", "FunctionSource", "ParenSource", "SubQuerySource", "InlineQuery", "WhereClause", "GroupByClause", "HavingClause", "OrderByClause", "WindowFrameClause", "LimitClause", "OffsetClause", "FetchClause", "ForClause", "OrderByItem", "SelectClause", "SelectItem", "ParenExpression", "BinaryExpression", "UnaryExpression", "CaseExpression", "CaseKeyValuePair", "SwitchCaseArgument", "BetweenExpression", "FunctionCall", "ArrayExpression", "ArrayQueryExpression", "TupleExpression", "CastExpression", "ValueList", "StringSpecifierExpression", "source", "ns", "RawString", "query", "arg", "handler", "cteCollector", "CTECollector", "commonTables", "cte", "win", "tuple", "withClause", "table", "commonTable", "fromClause", "join", "identifier", "value", "tableName", "subQuery", "inlineQuery", "joinClause", "joinOn", "joinUsing", "whereClause", "clause", "item", "switchCase", "caseItem", "pair", "func", "valueList", "SqlPrintToken", "type", "text", "containerType", "ParameterCollector", "node", "result", "walk", "n", "ParameterExpression", "key", "v", "IdentifierDecorator", "identifierEscape", "text", "ParameterDecorator", "options", "text", "index", "paramText", "UpdateQuery", "SqlComponent", "params", "SetClause", "SelectValueCollector", "_SelectValueCollector", "tableColumnResolver", "initialCommonTables", "CTECollector", "SimpleSelectQuery", "expr", "SelectClause", "SourceExpression", "FromClause", "arg", "items", "handler", "query", "wildcards", "item", "ColumnReference", "wildSourceNames", "fromSourceName", "join", "joinSourceName", "clause", "joinCascade", "sourceName", "source", "commonTable", "innerCommonTables", "columnName", "column", "TableSource", "SubQuerySource", "ParenSource", "name", "value", "CreateTableQuery", "SqlComponent", "params", "IdentifierString", "selectItems", "SelectValueCollector", "val", "SelectItem", "RawString", "SimpleSelectQuery", "SelectClause", "FromClause", "SourceExpression", "TableSource", "FunctionCall", "ColumnReference", "PRESETS", "SqlPrintTokenParser", "_SqlPrintTokenParser", "options", "ParameterDecorator", "IdentifierDecorator", "ValueList", "expr", "ColumnReference", "QualifiedName", "FunctionCall", "UnaryExpression", "BinaryExpression", "LiteralValue", "ParameterExpression", "SwitchCaseArgument", "CaseKeyValuePair", "RawString", "IdentifierString", "ParenExpression", "CastExpression", "CaseExpression", "ArrayExpression", "ArrayQueryExpression", "BetweenExpression", "StringSpecifierExpression", "TypeValue", "TupleExpression", "InlineQuery", "WindowFrameExpression", "WindowFrameSpec", "WindowFrameBoundStatic", "WindowFrameBoundaryValue", "PartitionByClause", "OrderByClause", "OrderByItem", "SelectItem", "SelectClause", "Distinct", "DistinctOn", "TableSource", "FunctionSource", "SourceExpression", "SourceAliasExpression", "FromClause", "JoinClause", "JoinOnClause", "JoinUsingClause", "WhereClause", "GroupByClause", "HavingClause", "WindowsClause", "WindowFrameClause", "LimitClause", "OffsetClause", "FetchClause", "FetchExpression", "ForClause", "WithClause", "CommonTable", "SimpleSelectQuery", "SubQuerySource", "BinarySelectQuery", "ValuesQuery", "InsertQuery", "InsertClause", "UpdateQuery", "UpdateClause", "SetClause", "SetClauseItem", "ReturningClause", "CreateTableQuery", "SqlPrintToken", "arg", "token", "i", "paramsRaw", "ParameterCollector", "a", "b", "style", "paramsObj", "p", "key", "paramsArr", "handler", "text", "kv", "elseValue", "elseToken", "elseValueContainer", "thenValueContainer", "specifier", "value", "first", "defaultName", "fullName", "ns", "query", "subQuery", "values", "queryToken", "LinePrinter", "indentChar", "indentSize", "newline", "result", "line", "level", "current", "PrintLine", "text", "workingIndex", "workLine", "SqlPrinter", "options", "LinePrinter", "token", "level", "current", "text", "keywordToken", "innerLevel", "child", "VALID_PRESETS", "SqlFormatter", "options", "presetConfig", "PRESETS", "parserOptions", "SqlPrintTokenParser", "SqlPrinter", "sql", "token", "params", "Formatter", "SqlFormatter", "arg", "config", "result", "CTEBuilder", "TableSourceCollector", "CTECollector", "Formatter", "commonTables", "WithClause", "resolvedTables", "tableMap", "recursiveCTEs", "dependencies", "sortedTables", "ctesByName", "table", "tableName", "name", "tables", "definitions", "referencedBy", "referencedTables", "referencedTable", "referencedCTEs", "referencedCTE", "referencedName", "recursiveResult", "nonRecursiveResult", "visited", "visiting", "visit", "deps", "dep", "CTEInjector", "CTEBuilder", "CTECollector", "query", "commonTables", "resolvedWithCaluse", "SimpleSelectQuery", "BinarySelectQuery", "withClause", "CTENormalizer", "query", "allCommonTables", "CTECollector", "CTEDisabler", "CTEInjector", "DuplicateDetectionMode", "SelectableColumnCollector", "tableColumnResolver", "includeWildCard", "duplicateDetection", "options", "CTECollector", "SimpleSelectQuery", "expr", "SelectClause", "FromClause", "WhereClause", "GroupByClause", "HavingClause", "OrderByClause", "WindowFrameClause", "LimitClause", "OffsetClause", "FetchClause", "JoinOnClause", "JoinUsingClause", "ColumnReference", "BinaryExpression", "UnaryExpression", "FunctionCall", "ParenExpression", "CaseExpression", "CastExpression", "BetweenExpression", "ArrayExpression", "ArrayQueryExpression", "ValueList", "WindowFrameExpression", "PartitionByClause", "arg", "items", "name", "value", "item", "tableName", "key", "itemTable", "handler", "query", "win", "clause", "sourceValues", "SelectValueCollector", "join", "joinOnClause", "joinUsingClause", "columnRef", "func", "SourceParser", "_SourceParser", "query", "lexemes", "SqlTokenizer", "result", "index", "fullNameResult", "FullNameParser", "idx", "namespaces", "name", "newIndex", "TableSource", "argument", "ValueParser", "functionName", "FunctionSource", "keyword", "selectQuery", "SelectQueryParser", "SubQuerySource", "UpstreamSelectQueryFinder", "tableColumnResolver", "options", "SelectableColumnCollector", "query", "columnNames", "namesArray", "ctes", "CTECollector", "cteMap", "cte", "src", "nextCteMap", "result", "fromClause", "sources", "allBranchResults", "allBranchesOk", "validBranchCount", "sourceExpr", "branchResult", "TableSource", "SubQuerySource", "ValuesQuery", "SimpleSelectQuery", "columns", "col", "cteColumns", "allColumns", "normalize", "s", "name", "BinarySelectQuery", "left", "right", "error", "SourceAliasExpressionParser", "lexemes", "index", "idx", "table", "columns", "SourceAliasExpression", "SourceExpressionParser", "query", "lexemes", "SqlTokenizer", "result", "index", "SourceParser", "SourceExpression", "idx", "sourceResult", "aliasResult", "SourceAliasExpressionParser", "type", "QueryBuilder", "_QueryBuilder", "queries", "operator", "wrap", "q", "ValuesQuery", "result", "BinarySelectQuery", "CTENormalizer", "query", "SimpleSelectQuery", "subQuerySource", "SubQuerySource", "sourceExpr", "SourceExpression", "SourceAliasExpression", "fromClause", "FromClause", "selectClause", "columnCount", "selectItems", "name", "SelectItem", "ColumnReference", "SelectClause", "columnRef", "selectItem", "tableName", "isTemporary", "CreateTableQuery", "selectQuery", "cols", "count", "SelectValueCollector", "item", "SourceExpressionParser", "InsertQuery", "InsertClause", "selectSourceName", "updateTableExprRaw", "primaryKeys", "updateClause", "UpdateClause", "pkArray", "collectedCTEs", "CTECollector", "CTEDisabler", "pk", "updateSourceName", "setItems", "col", "SetClauseItem", "setClause", "SetClause", "from", "where", "cond", "BinaryExpression", "whereClause", "WhereClause", "UpdateQuery", "WithClause", "ParameterHelper", "query", "name", "value", "params", "ParameterCollector", "found", "p", "SimpleSelectQuery", "SqlComponent", "params", "rightQuery", "operator", "QueryBuilder", "rawCondition", "parsedCondition", "ValueParser", "condition", "BinaryExpression", "WhereClause", "HavingClause", "joinSourceRawText", "alias", "columns", "resolver", "sourceExpr", "joinType", "tableSource", "SourceParser", "SourceExpression", "SourceAliasExpression", "columnsArr", "valueSets", "SelectableColumnCollector", "joinCondition", "count", "sourceAlias", "valueSet", "col", "expr", "ColumnReference", "joinOnClause", "JoinOnClause", "joinClause", "JoinClause", "CTENormalizer", "SubQuerySource", "commonTable", "tables", "WithClause", "rawText", "query", "SelectQueryParser", "CommonTable", "columnName", "fn", "items", "item", "exprSql", "Formatter", "newValue", "exprBuilder", "options", "queries", "UpstreamSelectQueryFinder", "collector", "formatter", "q", "exprs", "exprStr", "name", "value", "ParameterHelper", "BinarySelectQuery", "_BinarySelectQuery", "SqlComponent", "left", "operator", "right", "RawString", "query", "CTENormalizer", "sql", "parsedQuery", "SelectQueryParser", "alias", "SourceExpression", "SubQuerySource", "SourceAliasExpression", "name", "value", "ParameterHelper", "ValuesQuery", "SqlComponent", "tuples", "columnAliases", "QueryBuilder", "name", "value", "ParameterHelper", "SelectClauseParser", "query", "lexemes", "SqlTokenizer", "result", "index", "idx", "distinct", "Distinct", "argument", "ValueParser", "DistinctOn", "items", "item", "SelectItemParser", "SelectClause", "parsedValue", "value", "alias", "SelectItem", "ColumnReference", "JoinOnClauseParser", "lexemes", "index", "idx", "condition", "ValueParser", "JoinOnClause", "JoinUsingClauseParser", "lexemes", "index", "idx", "result", "ValueParser", "usingColumns", "JoinUsingClause", "JoinClauseParser", "lexemes", "index", "idx", "joins", "joinClause", "value", "joinkeywordParser", "joinType", "lateralResult", "lateral", "sourceResult", "SourceExpressionParser", "onResult", "JoinOnClauseParser", "JoinClause", "usingResult", "JoinUsingClauseParser", "FromClauseParser", "query", "lexemes", "SqlTokenizer", "result", "index", "idx", "sourceExpression", "SourceExpressionParser", "join", "JoinClauseParser", "FromClause", "WhereClauseParser", "query", "lexemes", "SqlTokenizer", "result", "index", "idx", "item", "ValueParser", "WhereClause", "GroupByClauseParser", "query", "lexemes", "SqlTokenizer", "result", "index", "idx", "items", "item", "GroupByClause", "parsedValue", "ValueParser", "value", "HavingClauseParser", "query", "lexemes", "SqlTokenizer", "result", "index", "idx", "item", "ValueParser", "HavingClause", "WindowClauseParser", "query", "lexemes", "SqlTokenizer", "result", "index", "idx", "windows", "name", "expr", "WindowExpressionParser", "WindowFrameClause", "WindowsClause", "LimitClauseParser", "query", "lexemes", "SqlTokenizer", "result", "index", "idx", "limitItem", "ValueParser", "LimitClause", "ForClauseParser", "query", "lexemes", "SqlTokenizer", "result", "index", "idx", "lockModeValue", "lockMode", "ForClause", "CommonTableParser", "query", "lexemes", "SqlTokenizer", "result", "index", "idx", "aliasResult", "SourceAliasExpressionParser", "materialized", "currentValue", "queryResult", "SelectQueryParser", "CommonTable", "WithClauseParser", "query", "lexemes", "SqlTokenizer", "result", "index", "idx", "recursive", "tables", "firstCte", "CommonTableParser", "cteResult", "WithClause", "ValuesQueryParser", "query", "lexemes", "SqlTokenizer", "result", "index", "idx", "tuples", "firstTuple", "tuple", "ValuesQuery", "values", "TupleExpression", "firstValue", "ValueParser", "value", "FetchClauseParser", "lexemes", "index", "idx", "fetchExprResult", "FetchExpressionParser", "fetchExpr", "FetchClause", "type", "typeToken", "count", "unit", "LiteralValue", "FetchExpression", "countResult", "ValueParser", "OffsetClauseParser", "query", "lexemes", "SqlTokenizer", "result", "index", "idx", "offsetItem", "ValueParser", "OffsetClause", "SelectQueryParser", "query", "lexemes", "SqlTokenizer", "result", "index", "idx", "firstToken", "firstResult", "operator", "nextToken", "BinarySelectQuery", "withClauseResult", "WithClauseParser", "selectClauseResult", "SelectClauseParser", "fromClauseResult", "FromClauseParser", "whereClauseResult", "WhereClauseParser", "groupByClauseResult", "GroupByClauseParser", "havingClauseResult", "HavingClauseParser", "windowClauseResult", "WindowClauseParser", "orderByClauseResult", "OrderByClauseParser", "limitClauseResult", "LimitClauseParser", "offsetClauseResult", "OffsetClauseParser", "fetchClauseResult", "FetchClauseParser", "forClauseResult", "ForClauseParser", "SimpleSelectQuery", "ValuesQueryParser", "InsertQueryParser", "query", "lexemes", "SqlTokenizer", "result", "index", "idx", "withclause", "WithClauseParser", "sourceResult", "SourceExpressionParser", "columns", "selectResult", "SelectQueryParser", "SimpleSelectQuery", "InsertQuery", "InsertClause", "PostgresObjectEntityCteBuilder", "_PostgresObjectEntityCteBuilder", "initialCte", "allEntities", "mapping", "ctes", "previousCteAlias", "objectEntityInfos", "entitiesByDepth", "depths", "a", "b", "depth", "entitiesAtDepth", "cteAlias", "cte", "entityName", "entityId", "columnName", "objectInfos", "calculateActualObjectNestingDepth", "entityIdOfObject", "initialEntity", "currentParentIdInHierarchy", "calculatedObjectDepth", "visitedInPath", "parentEntityData", "parentIsConsideredAnObjectForNesting", "parentDefinition", "ne", "nestedEntity", "entity", "info", "selectItems", "SelectItem", "ColumnReference", "IdentifierString", "jsonColumn", "cteSelect", "SimpleSelectQuery", "SelectClause", "FromClause", "SourceExpression", "TableSource", "CommonTable", "SourceAliasExpression", "jsonObjectArgs", "nullChecks", "jsonObject", "nullCondition", "caseExpr", "jsonColumnName", "currentParentId", "parentEntity", "e", "jsonKey", "sqlColumn", "LiteralValue", "BinaryExpression", "childEntity", "child", "args", "jsonBuildFunction", "FunctionCall", "RawString", "ValueList", "acc", "check", "CaseExpression", "SwitchCaseArgument", "CaseKeyValuePair", "PostgresArrayEntityCteBuilder", "_PostgresArrayEntityCteBuilder", "ctesSoFar", "aliasOfCteToBuildUpon", "allEntities", "mapping", "columnMappings", "currentCtes", "currentCteAlias", "sortedArrayInfos", "entitiesByDepth", "depths", "a", "b", "depth", "infos", "cte", "newCteAlias", "arrayEntityInfos", "getDepth", "entityId", "entity", "ne", "currentArrayEntity", "parentEntity", "parentSqlColumns", "parentIdColumnSqlName", "arrayInfos", "info", "arrayColumns", "col", "collectNestedColumns", "parentEntityId", "nestedEntity", "column", "columnName", "prevCte", "c", "prevSelects", "SelectValueCollector", "groupByItems", "selectItems", "currentLevelArrayColumns", "arrayEntityColumns", "arrayInternalObjectColumns", "objectEntity", "columnMapping", "cm", "agg", "SelectItem", "cteAlias", "cteSelect", "SimpleSelectQuery", "SelectClause", "FromClause", "SourceExpression", "TableSource", "IdentifierString", "GroupByClause", "CommonTable", "SourceAliasExpression", "nestedEntities", "jsonBuildFunction", "args", "jsonKey", "sqlColumn", "LiteralValue", "ColumnReference", "childEntity", "propertyNameForJson", "availableMappings", "m", "jsonObject", "FunctionCall", "RawString", "ValueList", "jsonAggFunction", "primaryColumn", "currentDepth", "arrayEntitiesByDepth", "maxDepth", "d", "entityDepth", "currentEntity", "e", "targetDepth", "sv", "isJsonColumn", "shouldInclude", "columns", "entityMatch", "PostgresJsonQueryBuilder", "SelectValueCollector", "PostgresObjectEntityCteBuilder", "PostgresArrayEntityCteBuilder", "query", "mapping", "selectedValues", "availableColumns", "sv", "jsonKey", "columnDef", "sourceColumn", "entityIds", "parentToChildrenMap", "ne", "entity", "allParentIds", "parentId", "directChildren", "c", "parentName", "propertyNames", "child", "originalQuery", "options", "simpleQuery", "SimpleSelectQuery", "QueryBuilder", "initialCte", "initialCteAlias", "ctesForProcessing", "currentAliasToBuildUpon", "allEntities", "objectEntityResult", "columnMappings", "arrayCteBuildResult", "originCteAlias", "CommonTable", "SourceAliasExpression", "finalCtesList", "lastCteAliasForFromClause", "currentCtes", "rootObjectCteAlias", "rootEntity", "rootObjectBuilderExpression", "rootObjectSelectItem", "SelectItem", "rootObjectCte", "SelectClause", "FromClause", "SourceExpression", "TableSource", "IdentifierString", "aggregationFunc", "aggregateExpression", "FunctionCall", "RawString", "ValueList", "ColumnReference", "WithClause", "LimitClause", "LiteralValue", "sourceAlias", "nestedEntities", "jsonBuildFunction", "args", "sqlColumn", "childEntity", "m", "convertModelDrivenMapping", "modelMapping", "protectedStringFields", "entityIdCounter", "propertyNameCounters", "generateEntityId", "generateUniquePropertyName", "baseName", "processStructure", "structure", "parentId", "columns", "nestedEntities", "fieldName", "config", "fieldConfig", "nestedStructure", "uniquePropertyName", "entityId", "processedNested", "entity", "processed", "jsonMapping", "validateModelDrivenMapping", "mapping", "errors", "convertColumnsToLegacy", "columns", "result", "key", "config", "convertToLegacyJsonMapping", "input", "col", "entity", "toLegacyMapping", "enhanced", "extractTypeProtection", "protectedStringFields", "dateFields", "numberFields", "columnName", "isValidMappingInput", "input", "EnhancedFormatStrategy", "candidate", "hasEnhancedColumns", "columns", "col", "entity", "toLegacyMapping", "extractTypeProtection", "ModelDrivenFormatStrategy", "converted", "convertModelDrivenMapping", "LegacyFormatStrategy", "JsonMappingConverter", "strategy", "errors", "result", "error", "legacy", "typeInfo", "detectMappingFormat", "input", "convertLegacyFormat", "input", "result", "propertyName", "relationship", "rel", "processJsonMapping", "JsonMappingConverter", "format", "unifyJsonMapping", "isModelDrivenFormat", "detectMappingFormat", "isUnifiedFormat", "isLegacyFormat", "TypeTransformationPostProcessor", "config", "result", "item", "obj", "transformed", "key", "value", "columnTransform", "detectedTransform", "globalTransform", "v", "date", "transformation", "integerValue", "error", "columnMappings", "transformDatabaseResult", "TypeTransformers", "TableSchema", "name", "columns", "SchemaCollector", "tableColumnResolver", "SimpleSelectQuery", "expr", "BinarySelectQuery", "arg", "cteCollector", "CTECollector", "handler", "consolidatedSchemas", "schema", "existingColumns", "column", "nameA", "nameB", "source", "queryColumns", "includeUnnamed", "TableSource", "tableName", "cte", "table", "tableAlias", "query", "SelectableColumnCollector", "ColumnReference", "columnRef", "columnsWithoutTable", "SubQuerySource", "join", "errorMessage", "tableColumns", "tableSchema", "SqlParamInjector", "optionsOrResolver", "options", "query", "state", "SelectQueryParser", "finder", "UpstreamSelectQueryFinder", "collector", "SelectableColumnCollector", "normalize", "s", "allowedOps", "stateValues", "value", "name", "stateValue", "injectOrConditions", "injectAndConditions", "injectSimpleCondition", "injectComplexConditions", "validateOperators", "q", "baseName", "andConditions", "availableColumns", "i", "andCondition", "columnName", "entry", "item", "columnRef", "paramName", "paramExpr", "ParameterExpression", "BinaryExpression", "prms", "v", "j", "ParenExpression", "ValueList", "FunctionCall", "orConditions", "orExpressions", "orCondition", "branchConditions", "branchExpr", "finalOrExpr", "op", "conditions", "paramEq", "paramMin", "paramMax", "paramLike", "paramIlike", "paramAny", "paramLT", "paramGT", "paramNEQ", "paramNE", "paramLE", "paramGE", "combinedExpr", "targetQuery", "allColumns", "explicitColumnName", "queries", "targetColumn", "targetColumnName", "explicitEntry", "referencedColumns", "cond", "col", "index", "arr", "colName", "conditionType", "columns", "cteColumns", "cte", "error", "SimpleSelectQuery", "BinarySelectQuery", "SqlSortInjector", "tableColumnResolver", "query", "SelectQueryParser", "SimpleSelectQuery", "sortConditions", "availableColumns", "SelectableColumnCollector", "columnName", "item", "newOrderByItems", "condition", "columnEntry", "columnRef", "sortDirection", "nullsPosition", "orderByItem", "OrderByItem", "finalOrderByItems", "newOrderByClause", "OrderByClause", "SqlPaginationInjector", "query", "pagination", "SelectQueryParser", "SimpleSelectQuery", "offset", "limitClause", "LimitClause", "ParameterExpression", "offsetClause", "OffsetClause", "DynamicQueryBuilder", "tableColumnResolver", "sqlContent", "options", "parsedQuery", "SelectQueryParser", "error", "modifiedQuery", "paramInjector", "SqlParamInjector", "simpleQuery", "QueryBuilder", "sortInjector", "SqlSortInjector", "page", "pageSize", "paginationInjector", "SqlPaginationInjector", "paginationOptions", "jsonBuilder", "PostgresJsonQueryBuilder", "filter", "sort", "paging", "serialize", "SqlSchemaValidator", "sql", "tableResolver", "sqlComponent", "SelectQueryParser", "resolver", "tableName", "schema", "t", "tableSchemas", "SchemaCollector", "errors", "tableSchema", "resolvedColumns", "undefinedColumns", "column", "JsonSchemaValidator", "jsonMapping", "expectedStructure", "extractedStructure", "result", "errorMessage", "structure", "propertyName", "entity", "entityStructure", "propName", "childEntity", "extracted", "expected", "path", "errors", "missingProperties", "extraProperties", "nestedResult", "extractedObj", "expectedObj", "key", "currentPath", "extractedValue", "expectedValue", "sampleObject", "SchemaManager", "schemas", "tableNames", "errors", "tableName", "table", "_", "col", "name", "rel", "rootTableName", "rootTable", "rootColumns", "columnName", "column", "nestedEntities", "relatedTable", "relatedColumns", "relationshipType", "primaryKeyEntry", "foreignKeys", "createSchemaManager", "createTableColumnResolver", "createJsonMappingFromSchema"]
|
|
7
7
|
}
|