rawsql-ts 0.1.0-beta.3 → 0.1.0-beta.5

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.
Files changed (135) hide show
  1. package/README.md +143 -199
  2. package/dist/index.js +32 -0
  3. package/dist/index.js.map +1 -0
  4. package/dist/models/BinarySelectQuery.js +140 -0
  5. package/dist/models/BinarySelectQuery.js.map +1 -0
  6. package/dist/models/Clause.js +318 -0
  7. package/dist/models/Clause.js.map +1 -0
  8. package/dist/models/KeywordTrie.js +52 -0
  9. package/dist/models/KeywordTrie.js.map +1 -0
  10. package/dist/models/Lexeme.js +21 -0
  11. package/dist/models/Lexeme.js.map +1 -0
  12. package/dist/models/SelectQuery.js +10 -0
  13. package/dist/models/SelectQuery.js.map +1 -0
  14. package/dist/models/SimpleSelectQuery.js +290 -0
  15. package/dist/models/SimpleSelectQuery.js.map +1 -0
  16. package/dist/models/SqlComponent.js +27 -0
  17. package/dist/models/SqlComponent.js.map +1 -0
  18. package/dist/models/ValueComponent.js +250 -0
  19. package/dist/models/ValueComponent.js.map +1 -0
  20. package/dist/models/ValuesQuery.js +16 -0
  21. package/dist/models/ValuesQuery.js.map +1 -0
  22. package/dist/parsers/CommandExpressionParser.js +124 -0
  23. package/dist/parsers/CommandExpressionParser.js.map +1 -0
  24. package/dist/parsers/CommonTableParser.js +60 -0
  25. package/dist/parsers/CommonTableParser.js.map +1 -0
  26. package/dist/parsers/ForClauseParser.js +56 -0
  27. package/dist/parsers/ForClauseParser.js.map +1 -0
  28. package/dist/parsers/FromClauseParser.js +45 -0
  29. package/dist/parsers/FromClauseParser.js.map +1 -0
  30. package/dist/parsers/FunctionExpressionParser.js +178 -0
  31. package/dist/parsers/FunctionExpressionParser.js.map +1 -0
  32. package/dist/parsers/GroupByParser.js +56 -0
  33. package/dist/parsers/GroupByParser.js.map +1 -0
  34. package/dist/parsers/HavingParser.js +34 -0
  35. package/dist/parsers/HavingParser.js.map +1 -0
  36. package/dist/parsers/IdentifierParser.js +39 -0
  37. package/dist/parsers/IdentifierParser.js.map +1 -0
  38. package/dist/parsers/JoinClauseParser.js +105 -0
  39. package/dist/parsers/JoinClauseParser.js.map +1 -0
  40. package/dist/parsers/KeywordParser.js +91 -0
  41. package/dist/parsers/KeywordParser.js.map +1 -0
  42. package/dist/parsers/LimitClauseParser.js +48 -0
  43. package/dist/parsers/LimitClauseParser.js.map +1 -0
  44. package/dist/parsers/LiteralParser.js +38 -0
  45. package/dist/parsers/LiteralParser.js.map +1 -0
  46. package/dist/parsers/OrderByClauseParser.js +75 -0
  47. package/dist/parsers/OrderByClauseParser.js.map +1 -0
  48. package/dist/parsers/OverExpressionParser.js +44 -0
  49. package/dist/parsers/OverExpressionParser.js.map +1 -0
  50. package/dist/parsers/ParameterExpressionParser.js +15 -0
  51. package/dist/parsers/ParameterExpressionParser.js.map +1 -0
  52. package/dist/parsers/ParenExpressionParser.js +33 -0
  53. package/dist/parsers/ParenExpressionParser.js.map +1 -0
  54. package/dist/parsers/PartitionByParser.js +51 -0
  55. package/dist/parsers/PartitionByParser.js.map +1 -0
  56. package/dist/parsers/SelectClauseParser.js +82 -0
  57. package/dist/parsers/SelectClauseParser.js.map +1 -0
  58. package/dist/parsers/SelectQueryParser.js +151 -0
  59. package/dist/parsers/SelectQueryParser.js.map +1 -0
  60. package/dist/parsers/SourceAliasExpressionParser.js +48 -0
  61. package/dist/parsers/SourceAliasExpressionParser.js.map +1 -0
  62. package/dist/parsers/SourceExpressionParser.js +34 -0
  63. package/dist/parsers/SourceExpressionParser.js.map +1 -0
  64. package/dist/parsers/SourceParser.js +116 -0
  65. package/dist/parsers/SourceParser.js.map +1 -0
  66. package/dist/parsers/SqlTokenizer.js +174 -0
  67. package/dist/parsers/SqlTokenizer.js.map +1 -0
  68. package/dist/parsers/StringSpecifierExpressionParser.js +22 -0
  69. package/dist/parsers/StringSpecifierExpressionParser.js.map +1 -0
  70. package/dist/parsers/UnaryExpressionParser.js +30 -0
  71. package/dist/parsers/UnaryExpressionParser.js.map +1 -0
  72. package/dist/parsers/ValueParser.js +134 -0
  73. package/dist/parsers/ValueParser.js.map +1 -0
  74. package/dist/parsers/ValuesQueryParser.js +86 -0
  75. package/dist/parsers/ValuesQueryParser.js.map +1 -0
  76. package/dist/parsers/WhereClauseParser.js +34 -0
  77. package/dist/parsers/WhereClauseParser.js.map +1 -0
  78. package/dist/parsers/WindowClauseParser.js +43 -0
  79. package/dist/parsers/WindowClauseParser.js.map +1 -0
  80. package/dist/parsers/WindowExpressionParser.js +151 -0
  81. package/dist/parsers/WindowExpressionParser.js.map +1 -0
  82. package/dist/parsers/WithClauseParser.js +55 -0
  83. package/dist/parsers/WithClauseParser.js.map +1 -0
  84. package/dist/tokenReaders/BaseTokenReader.js +82 -0
  85. package/dist/tokenReaders/BaseTokenReader.js.map +1 -0
  86. package/dist/tokenReaders/CommandTokenReader.js +145 -0
  87. package/dist/tokenReaders/CommandTokenReader.js.map +1 -0
  88. package/dist/tokenReaders/FunctionTokenReader.js +45 -0
  89. package/dist/tokenReaders/FunctionTokenReader.js.map +1 -0
  90. package/dist/tokenReaders/IdentifierTokenReader.js +70 -0
  91. package/dist/tokenReaders/IdentifierTokenReader.js.map +1 -0
  92. package/dist/tokenReaders/LiteralTokenReader.js +189 -0
  93. package/dist/tokenReaders/LiteralTokenReader.js.map +1 -0
  94. package/dist/tokenReaders/OperatorTokenReader.js +98 -0
  95. package/dist/tokenReaders/OperatorTokenReader.js.map +1 -0
  96. package/dist/tokenReaders/ParameterTokenReader.js +44 -0
  97. package/dist/tokenReaders/ParameterTokenReader.js.map +1 -0
  98. package/dist/tokenReaders/StringSpecifierTokenReader.js +31 -0
  99. package/dist/tokenReaders/StringSpecifierTokenReader.js.map +1 -0
  100. package/dist/tokenReaders/SymbolTokenReader.js +35 -0
  101. package/dist/tokenReaders/SymbolTokenReader.js.map +1 -0
  102. package/dist/tokenReaders/TokenReaderManager.js +110 -0
  103. package/dist/tokenReaders/TokenReaderManager.js.map +1 -0
  104. package/dist/tokenReaders/TypeTokenReader.js +59 -0
  105. package/dist/tokenReaders/TypeTokenReader.js.map +1 -0
  106. package/dist/transformers/CTEBuilder.js +188 -0
  107. package/dist/transformers/CTEBuilder.js.map +1 -0
  108. package/dist/transformers/CTECollector.js +384 -0
  109. package/dist/transformers/CTECollector.js.map +1 -0
  110. package/dist/transformers/CTEDisabler.js +325 -0
  111. package/dist/transformers/CTEDisabler.js.map +1 -0
  112. package/dist/transformers/CTEInjector.js +83 -0
  113. package/dist/transformers/CTEInjector.js.map +1 -0
  114. package/dist/transformers/CTENormalizer.js +42 -0
  115. package/dist/transformers/CTENormalizer.js.map +1 -0
  116. package/dist/transformers/Formatter.js +452 -0
  117. package/dist/transformers/Formatter.js.map +1 -0
  118. package/dist/transformers/QueryNormalizer.js +114 -0
  119. package/dist/transformers/QueryNormalizer.js.map +1 -0
  120. package/dist/transformers/SelectValueCollector.js +249 -0
  121. package/dist/transformers/SelectValueCollector.js.map +1 -0
  122. package/dist/transformers/SelectableColumnCollector.js +308 -0
  123. package/dist/transformers/SelectableColumnCollector.js.map +1 -0
  124. package/dist/transformers/TableSourceCollector.js +384 -0
  125. package/dist/transformers/TableSourceCollector.js.map +1 -0
  126. package/dist/transformers/UpstreamSelectQueryFinder.js +129 -0
  127. package/dist/transformers/UpstreamSelectQueryFinder.js.map +1 -0
  128. package/dist/utils/charLookupTable.js +73 -0
  129. package/dist/utils/charLookupTable.js.map +1 -0
  130. package/dist/utils/stringUtils.js +168 -0
  131. package/dist/utils/stringUtils.js.map +1 -0
  132. package/package.json +2 -2
  133. package/dist/tsconfig.tsbuildinfo +0 -1
  134. package/dist/vitest.config.js +0 -15
  135. package/dist/vitest.config.js.map +0 -1
@@ -0,0 +1,98 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.OperatorTokenReader = void 0;
4
+ const BaseTokenReader_1 = require("./BaseTokenReader");
5
+ const Lexeme_1 = require("../models/Lexeme");
6
+ const charLookupTable_1 = require("../utils/charLookupTable");
7
+ const KeywordParser_1 = require("../parsers/KeywordParser");
8
+ const KeywordTrie_1 = require("../models/KeywordTrie");
9
+ const trie = new KeywordTrie_1.KeywordTrie([
10
+ // binary
11
+ ["and"],
12
+ ["or"],
13
+ ["is"],
14
+ ["is", "not"],
15
+ ["is", "distinct", "from"],
16
+ ["is", "not", "distinct", "from"],
17
+ ["like"],
18
+ ["in"],
19
+ ["exists"],
20
+ ["between"],
21
+ ["not", "like"],
22
+ ["not", "in"],
23
+ ["not", "exists"],
24
+ ["not", "between"],
25
+ ["escape"], // e.g. '10% OFF on all items' like '10\%%' escape '\'
26
+ ["uescape"], // e.g. U&'d!0061t!+000061' uescape '!'
27
+ ["similar"], // e.g. substring('abcdef' similar '%#"cd#"%' escape '#')
28
+ ["placing"], // e.g. overlay('abcdef' placing 'cd' from 3 for 2)
29
+ // unary
30
+ ["not"],
31
+ // unary - trim
32
+ ["both"],
33
+ ["leading"],
34
+ ["trailing"],
35
+ ["both", "from"], // Postgres
36
+ ["leading", "from"], // Postgres
37
+ ["trailing", "from"], // Postgres
38
+ // unary - extract
39
+ ["year", "from"],
40
+ ["month", "from"],
41
+ ["day", "from"],
42
+ ["hour", "from"],
43
+ ["minute", "from"],
44
+ ["second", "from"],
45
+ ["dow", "from"],
46
+ ["doy", "from"],
47
+ ["isodow", "from"],
48
+ ["quarter", "from"],
49
+ ["week", "from"],
50
+ ["epoch", "from"],
51
+ ["at", "time", "zone"],
52
+ ["interval"],
53
+ // The following are not considered operators.
54
+ // ["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.
55
+ // ["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.
56
+ ]);
57
+ const keywordParser = new KeywordParser_1.KeywordParser(trie);
58
+ class OperatorTokenReader extends BaseTokenReader_1.BaseTokenReader {
59
+ tryRead(previous) {
60
+ if (this.isEndOfInput()) {
61
+ return null;
62
+ }
63
+ /*
64
+ NOTE:
65
+ Asterisks could potentially be wildcard identifiers,
66
+ but since they're indistinguishable at this stage, they're treated as Operators at the token level.
67
+ The Parser needs to determine whether they are appropriate Operators or Identifiers.
68
+ */
69
+ const char = this.input[this.position];
70
+ if (charLookupTable_1.CharLookupTable.isOperatorSymbol(char)) {
71
+ const start = this.position;
72
+ while (this.canRead() && charLookupTable_1.CharLookupTable.isOperatorSymbol(this.input[this.position])) {
73
+ // check for `--` and `/*` comments
74
+ if (this.canRead(1)) {
75
+ const current = this.input[this.position];
76
+ if (current === '-' && this.input[this.position + 1] === '-') {
77
+ break;
78
+ }
79
+ else if (current === '/' && this.input[this.position + 1] === '*') {
80
+ break; // end of operator
81
+ }
82
+ }
83
+ this.position++;
84
+ }
85
+ const resut = this.input.slice(start, this.position);
86
+ return this.createLexeme(Lexeme_1.TokenType.Operator, resut);
87
+ }
88
+ // Logical operators
89
+ const result = keywordParser.parse(this.input, this.position);
90
+ if (result !== null) {
91
+ this.position = result.newPosition;
92
+ return this.createLexeme(Lexeme_1.TokenType.Operator, result.keyword);
93
+ }
94
+ return null;
95
+ }
96
+ }
97
+ exports.OperatorTokenReader = OperatorTokenReader;
98
+ //# sourceMappingURL=OperatorTokenReader.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"OperatorTokenReader.js","sourceRoot":"","sources":["../../src/tokenReaders/OperatorTokenReader.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,44 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ParameterTokenReader = void 0;
4
+ const BaseTokenReader_1 = require("./BaseTokenReader");
5
+ const Lexeme_1 = require("../models/Lexeme");
6
+ const charLookupTable_1 = require("../utils/charLookupTable");
7
+ /**
8
+ * Reads SQL parameter tokens (@param, :param, $param, ?)
9
+ */
10
+ class ParameterTokenReader extends BaseTokenReader_1.BaseTokenReader {
11
+ /**
12
+ * Try to read a parameter token
13
+ */
14
+ tryRead(previous) {
15
+ if (this.isEndOfInput()) {
16
+ return null;
17
+ }
18
+ const char = this.input[this.position];
19
+ // named parameter (@param, :param, $param)
20
+ if (charLookupTable_1.CharLookupTable.isNamedParameterPrefix(char)) {
21
+ // However, do not recognize as a parameter if the next character is an operator symbol
22
+ // To avoid postgres `::`
23
+ if (this.canRead(1) && charLookupTable_1.CharLookupTable.isOperatorSymbol(this.input[this.position + 1])) {
24
+ return null;
25
+ }
26
+ this.position++;
27
+ // Read the identifier part after the prefix
28
+ const start = this.position;
29
+ while (this.canRead() && !charLookupTable_1.CharLookupTable.isDelimiter(this.input[this.position])) {
30
+ this.position++;
31
+ }
32
+ const identifier = this.input.slice(start, this.position);
33
+ return this.createLexeme(Lexeme_1.TokenType.Parameter, char + identifier);
34
+ }
35
+ // nameless parameter (?)
36
+ if (char === '?') {
37
+ this.position++;
38
+ return this.createLexeme(Lexeme_1.TokenType.Parameter, char);
39
+ }
40
+ return null;
41
+ }
42
+ }
43
+ exports.ParameterTokenReader = ParameterTokenReader;
44
+ //# sourceMappingURL=ParameterTokenReader.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ParameterTokenReader.js","sourceRoot":"","sources":["../../src/tokenReaders/ParameterTokenReader.ts"],"names":[],"mappings":";;;AAAA,uDAAoD;AACpD,6CAAqD;AACrD,8DAA2D;AAE3D;;GAEG;AACH,MAAa,oBAAqB,SAAQ,iCAAe;IACrD;;OAEG;IACI,OAAO,CAAC,QAAuB;QAClC,IAAI,IAAI,CAAC,YAAY,EAAE,EAAE,CAAC;YACtB,OAAO,IAAI,CAAC;QAChB,CAAC;QAED,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QAEvC,2CAA2C;QAC3C,IAAI,iCAAe,CAAC,sBAAsB,CAAC,IAAI,CAAC,EAAE,CAAC;YAE/C,uFAAuF;YACvF,yBAAyB;YACzB,IAAI,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,iCAAe,CAAC,gBAAgB,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,QAAQ,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC;gBACrF,OAAO,IAAI,CAAC;YAChB,CAAC;YAED,IAAI,CAAC,QAAQ,EAAE,CAAC;YAEhB,4CAA4C;YAC5C,MAAM,KAAK,GAAG,IAAI,CAAC,QAAQ,CAAC;YAC5B,OAAO,IAAI,CAAC,OAAO,EAAE,IAAI,CAAC,iCAAe,CAAC,WAAW,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,EAAE,CAAC;gBAC/E,IAAI,CAAC,QAAQ,EAAE,CAAC;YACpB,CAAC;YAED,MAAM,UAAU,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,KAAK,EAAE,IAAI,CAAC,QAAQ,CAAC,CAAC;YAC1D,OAAO,IAAI,CAAC,YAAY,CAAC,kBAAS,CAAC,SAAS,EAAE,IAAI,GAAG,UAAU,CAAC,CAAC;QACrE,CAAC;QAED,yBAAyB;QACzB,IAAI,IAAI,KAAK,GAAG,EAAE,CAAC;YACf,IAAI,CAAC,QAAQ,EAAE,CAAC;YAChB,OAAO,IAAI,CAAC,YAAY,CAAC,kBAAS,CAAC,SAAS,EAAE,IAAI,CAAC,CAAC;QACxD,CAAC;QAED,OAAO,IAAI,CAAC;IAChB,CAAC;CACJ;AAxCD,oDAwCC"}
@@ -0,0 +1,31 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.StringSpecifierTokenReader = void 0;
4
+ const Lexeme_1 = require("../models/Lexeme");
5
+ const BaseTokenReader_1 = require("./BaseTokenReader");
6
+ // Prefix sets for quick checks
7
+ const STRING_SPECIFIERS = new Set(['e\'', 'E\'', 'x\'', 'X\'', 'b\'', 'B\'']);
8
+ const UNICODE_STRING_SPECIFIERS = new Set(['u&\'', 'U&\'']);
9
+ class StringSpecifierTokenReader extends BaseTokenReader_1.BaseTokenReader {
10
+ /**
11
+ * Try to read an escaped literal like e'...', x'...', etc.
12
+ */
13
+ tryRead(previous) {
14
+ const start = this.position;
15
+ // Check for prefixed literals: e', x', b'
16
+ if (this.canRead(1) && STRING_SPECIFIERS.has(this.input.slice(start, start + 2))) {
17
+ this.position += 1;
18
+ const result = this.createLexeme(Lexeme_1.TokenType.StringSpecifier, this.input.slice(start, this.position));
19
+ return result;
20
+ }
21
+ // Check for unicode literal: u&'
22
+ if (this.canRead(2) && UNICODE_STRING_SPECIFIERS.has(this.input.slice(start, start + 3))) {
23
+ this.position += 2;
24
+ const result = this.createLexeme(Lexeme_1.TokenType.StringSpecifier, this.input.slice(start, this.position));
25
+ return result;
26
+ }
27
+ return null;
28
+ }
29
+ }
30
+ exports.StringSpecifierTokenReader = StringSpecifierTokenReader;
31
+ //# sourceMappingURL=StringSpecifierTokenReader.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"StringSpecifierTokenReader.js","sourceRoot":"","sources":["../../src/tokenReaders/StringSpecifierTokenReader.ts"],"names":[],"mappings":";;;AAAA,6CAAqD;AACrD,uDAAoD;AAEpD,+BAA+B;AAC/B,MAAM,iBAAiB,GAAG,IAAI,GAAG,CAAC,CAAC,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,CAAC,CAAC,CAAC;AAC9E,MAAM,yBAAyB,GAAG,IAAI,GAAG,CAAC,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;AAE5D,MAAa,0BAA2B,SAAQ,iCAAe;IAE3D;;OAEG;IACI,OAAO,CAAC,QAAuB;QAClC,MAAM,KAAK,GAAG,IAAI,CAAC,QAAQ,CAAC;QAE5B,0CAA0C;QAC1C,IAAI,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,iBAAiB,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,KAAK,EAAE,KAAK,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC;YAC/E,IAAI,CAAC,QAAQ,IAAI,CAAC,CAAC;YACnB,MAAM,MAAM,GAAG,IAAI,CAAC,YAAY,CAAC,kBAAS,CAAC,eAAe,EAAE,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,KAAK,EAAE,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC;YACpG,OAAO,MAAM,CAAC;QAClB,CAAC;QAED,iCAAiC;QACjC,IAAI,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,yBAAyB,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,KAAK,EAAE,KAAK,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC;YACvF,IAAI,CAAC,QAAQ,IAAI,CAAC,CAAC;YACnB,MAAM,MAAM,GAAG,IAAI,CAAC,YAAY,CAAC,kBAAS,CAAC,eAAe,EAAE,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,KAAK,EAAE,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC;YACpG,OAAO,MAAM,CAAC;QAClB,CAAC;QAED,OAAO,IAAI,CAAC;IAChB,CAAC;CACJ;AAxBD,gEAwBC"}
@@ -0,0 +1,35 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.SpecialSymbolTokenReader = void 0;
4
+ const BaseTokenReader_1 = require("./BaseTokenReader");
5
+ const Lexeme_1 = require("../models/Lexeme");
6
+ /**
7
+ * Reads SQL symbol tokens (., ,, (, ))
8
+ */
9
+ class SpecialSymbolTokenReader extends BaseTokenReader_1.BaseTokenReader {
10
+ /**
11
+ * Try to read a symbol token
12
+ */
13
+ tryRead(previous) {
14
+ if (this.isEndOfInput()) {
15
+ return null;
16
+ }
17
+ const char = this.input[this.position];
18
+ // symbol tokens
19
+ if (char in SpecialSymbolTokenReader.SPECIAL_SYMBOL_TOKENS) {
20
+ this.position++;
21
+ return this.createLexeme(SpecialSymbolTokenReader.SPECIAL_SYMBOL_TOKENS[char], char);
22
+ }
23
+ return null;
24
+ }
25
+ }
26
+ exports.SpecialSymbolTokenReader = SpecialSymbolTokenReader;
27
+ SpecialSymbolTokenReader.SPECIAL_SYMBOL_TOKENS = {
28
+ '.': Lexeme_1.TokenType.Dot,
29
+ ',': Lexeme_1.TokenType.Comma,
30
+ '(': Lexeme_1.TokenType.OpenParen,
31
+ ')': Lexeme_1.TokenType.CloseParen,
32
+ '[': Lexeme_1.TokenType.OpenBracket,
33
+ ']': Lexeme_1.TokenType.CloseBracket,
34
+ };
35
+ //# sourceMappingURL=SymbolTokenReader.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SymbolTokenReader.js","sourceRoot":"","sources":["../../src/tokenReaders/SymbolTokenReader.ts"],"names":[],"mappings":";;;AAAA,uDAAoD;AACpD,6CAAqD;AAErD;;GAEG;AACH,MAAa,wBAAyB,SAAQ,iCAAe;IAUzD;;OAEG;IACI,OAAO,CAAC,QAAuB;QAClC,IAAI,IAAI,CAAC,YAAY,EAAE,EAAE,CAAC;YACtB,OAAO,IAAI,CAAC;QAChB,CAAC;QAED,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QAEvC,gBAAgB;QAChB,IAAI,IAAI,IAAI,wBAAwB,CAAC,qBAAqB,EAAE,CAAC;YACzD,IAAI,CAAC,QAAQ,EAAE,CAAC;YAChB,OAAO,IAAI,CAAC,YAAY,CACpB,wBAAwB,CAAC,qBAAqB,CAAC,IAAI,CAAC,EACpD,IAAI,CACP,CAAC;QACN,CAAC;QACD,OAAO,IAAI,CAAC;IAChB,CAAC;;AA7BL,4DA8BC;AA7B2B,8CAAqB,GAA8B;IACvE,GAAG,EAAE,kBAAS,CAAC,GAAG;IAClB,GAAG,EAAE,kBAAS,CAAC,KAAK;IACpB,GAAG,EAAE,kBAAS,CAAC,SAAS;IACxB,GAAG,EAAE,kBAAS,CAAC,UAAU;IACzB,GAAG,EAAE,kBAAS,CAAC,WAAW;IAC1B,GAAG,EAAE,kBAAS,CAAC,YAAY;CAC9B,CAAC"}
@@ -0,0 +1,110 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.TokenReaderManager = void 0;
4
+ /**
5
+ * Manages and coordinates multiple token readers
6
+ */
7
+ class TokenReaderManager {
8
+ constructor(input, position = 0) {
9
+ this.cacheHits = 0;
10
+ this.cacheMisses = 0;
11
+ this.input = input;
12
+ this.position = position;
13
+ this.readers = [];
14
+ this.tokenCache = new Map();
15
+ }
16
+ /**
17
+ * Register a token reader
18
+ * @param reader The reader to register
19
+ * @returns This manager instance for chaining
20
+ */
21
+ register(reader) {
22
+ this.readers.push(reader);
23
+ return this;
24
+ }
25
+ /**
26
+ * Register multiple token readers
27
+ * @param readers The readers to register
28
+ * @returns This manager instance for chaining
29
+ */
30
+ registerAll(readers) {
31
+ readers.forEach(reader => this.register(reader));
32
+ return this;
33
+ }
34
+ /**
35
+ * Update the position for all readers
36
+ */
37
+ setPosition(position) {
38
+ this.position = position;
39
+ for (const reader of this.readers) {
40
+ reader.setPosition(position);
41
+ }
42
+ }
43
+ /**
44
+ * Try to read a token using all registered readers
45
+ * @param position The position to read from
46
+ * @param previous The previous token, if any
47
+ * @returns The lexeme if a reader could read it, null otherwise
48
+ */
49
+ tryRead(position, previous) {
50
+ // Check cache - using position as the key
51
+ if (this.tokenCache.has(position)) {
52
+ // Cache hit
53
+ this.cacheHits++;
54
+ const lexeme = this.tokenCache.get(position) || null;
55
+ return lexeme;
56
+ }
57
+ // Cache miss - create new entry
58
+ this.cacheMisses++;
59
+ this.setPosition(position);
60
+ // Try to read with each reader
61
+ let lexeme = null;
62
+ for (const reader of this.readers) {
63
+ lexeme = reader.tryRead(previous);
64
+ if (lexeme) {
65
+ this.position = reader.getPosition();
66
+ break;
67
+ }
68
+ }
69
+ // Update all readers' positions
70
+ for (const reader of this.readers) {
71
+ reader.setPosition(this.position);
72
+ }
73
+ // Save to cache (even if null)
74
+ this.tokenCache.set(position, lexeme);
75
+ return lexeme;
76
+ }
77
+ /**
78
+ * Get the maximum position among all readers
79
+ */
80
+ getMaxPosition() {
81
+ let maxPosition = this.position;
82
+ for (const reader of this.readers) {
83
+ const position = reader.getPosition();
84
+ if (position > maxPosition) {
85
+ maxPosition = position;
86
+ }
87
+ }
88
+ return maxPosition;
89
+ }
90
+ /**
91
+ * Get the input string
92
+ */
93
+ getInput() {
94
+ return this.input;
95
+ }
96
+ /**
97
+ * Get cache statistics
98
+ */
99
+ getCacheStats() {
100
+ const total = this.cacheHits + this.cacheMisses;
101
+ const ratio = total > 0 ? this.cacheHits / total : 0;
102
+ return {
103
+ hits: this.cacheHits,
104
+ misses: this.cacheMisses,
105
+ ratio: ratio
106
+ };
107
+ }
108
+ }
109
+ exports.TokenReaderManager = TokenReaderManager;
110
+ //# sourceMappingURL=TokenReaderManager.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"TokenReaderManager.js","sourceRoot":"","sources":["../../src/tokenReaders/TokenReaderManager.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,59 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.TypeTokenReader = void 0;
4
+ const BaseTokenReader_1 = require("./BaseTokenReader");
5
+ const Lexeme_1 = require("../models/Lexeme");
6
+ const stringUtils_1 = require("../utils/stringUtils");
7
+ const KeywordTrie_1 = require("../models/KeywordTrie");
8
+ const KeywordParser_1 = require("../parsers/KeywordParser");
9
+ // Use KeywordTrie to identify type names composed of multiple words.
10
+ const trie = new KeywordTrie_1.KeywordTrie([
11
+ // type
12
+ ["double", "precision"],
13
+ ["character", "varying"],
14
+ ["time", "without", "time", "zone"],
15
+ ["time", "with", "time", "zone"],
16
+ ["timestamp", "without", "time", "zone"],
17
+ ["timestamp", "with", "time", "zone"],
18
+ ]);
19
+ const typeParser = new KeywordParser_1.KeywordParser(trie);
20
+ /**
21
+ * Reads SQL identifier tokens
22
+ */
23
+ class TypeTokenReader extends BaseTokenReader_1.BaseTokenReader {
24
+ /**
25
+ * Try to read an identifier token
26
+ */
27
+ tryRead(previous) {
28
+ if (this.isEndOfInput()) {
29
+ return null;
30
+ }
31
+ // Check for keyword identifiers
32
+ const keyword = typeParser.parse(this.input, this.position);
33
+ if (keyword !== null) {
34
+ this.position = keyword.newPosition;
35
+ return this.createLexeme(Lexeme_1.TokenType.Type, keyword.keyword);
36
+ }
37
+ // check pervious token
38
+ if (previous === null) {
39
+ return null;
40
+ }
41
+ const result = stringUtils_1.StringUtils.tryReadRegularIdentifier(this.input, this.position);
42
+ if (!result) {
43
+ return null;
44
+ }
45
+ this.position = result.newPosition;
46
+ // type cast command
47
+ if (previous.type === Lexeme_1.TokenType.Command && previous.value === "as") {
48
+ // If the previous token is the `as` keyword, it could be a type cast or an identifier
49
+ return this.createLexeme(Lexeme_1.TokenType.Identifier, result.identifier, true);
50
+ }
51
+ // postgres type conversion
52
+ if (previous.type === Lexeme_1.TokenType.Operator && previous.value === "::") {
53
+ return this.createLexeme(Lexeme_1.TokenType.Type, result.identifier);
54
+ }
55
+ return null;
56
+ }
57
+ }
58
+ exports.TypeTokenReader = TypeTokenReader;
59
+ //# sourceMappingURL=TypeTokenReader.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"TypeTokenReader.js","sourceRoot":"","sources":["../../src/tokenReaders/TypeTokenReader.ts"],"names":[],"mappings":";;;AAAA,uDAAoD;AACpD,6CAAqD;AACrD,sDAAmD;AACnD,uDAAoD;AACpD,4DAAyD;AAEzD,qEAAqE;AACrE,MAAM,IAAI,GAAG,IAAI,yBAAW,CAAC;IACzB,OAAO;IACP,CAAC,QAAQ,EAAE,WAAW,CAAC;IACvB,CAAC,WAAW,EAAE,SAAS,CAAC;IACxB,CAAC,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,CAAC;IACnC,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC;IAChC,CAAC,WAAW,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,CAAC;IACxC,CAAC,WAAW,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC;CACxC,CAAC,CAAC;AACH,MAAM,UAAU,GAAG,IAAI,6BAAa,CAAC,IAAI,CAAC,CAAC;AAE3C;;GAEG;AACH,MAAa,eAAgB,SAAQ,iCAAe;IAChD;;OAEG;IACI,OAAO,CAAC,QAAuB;QAClC,IAAI,IAAI,CAAC,YAAY,EAAE,EAAE,CAAC;YACtB,OAAO,IAAI,CAAC;QAChB,CAAC;QAED,gCAAgC;QAChC,MAAM,OAAO,GAAG,UAAU,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,EAAE,IAAI,CAAC,QAAQ,CAAC,CAAC;QAC5D,IAAI,OAAO,KAAK,IAAI,EAAE,CAAC;YACnB,IAAI,CAAC,QAAQ,GAAG,OAAO,CAAC,WAAW,CAAC;YACpC,OAAO,IAAI,CAAC,YAAY,CAAC,kBAAS,CAAC,IAAI,EAAE,OAAO,CAAC,OAAO,CAAC,CAAC;QAC9D,CAAC;QAED,uBAAuB;QACvB,IAAI,QAAQ,KAAK,IAAI,EAAE,CAAC;YACpB,OAAO,IAAI,CAAC;QAChB,CAAC;QAED,MAAM,MAAM,GAAG,yBAAW,CAAC,wBAAwB,CAAC,IAAI,CAAC,KAAK,EAAE,IAAI,CAAC,QAAQ,CAAC,CAAC;QAC/E,IAAI,CAAC,MAAM,EAAE,CAAC;YACV,OAAO,IAAI,CAAC;QAChB,CAAC;QACD,IAAI,CAAC,QAAQ,GAAG,MAAM,CAAC,WAAW,CAAC;QAEnC,oBAAoB;QACpB,IAAI,QAAQ,CAAC,IAAI,KAAK,kBAAS,CAAC,OAAO,IAAI,QAAQ,CAAC,KAAK,KAAK,IAAI,EAAE,CAAC;YACjE,sFAAsF;YACtF,OAAO,IAAI,CAAC,YAAY,CAAC,kBAAS,CAAC,UAAU,EAAE,MAAM,CAAC,UAAU,EAAE,IAAI,CAAC,CAAC;QAC5E,CAAC;QAED,2BAA2B;QAC3B,IAAI,QAAQ,CAAC,IAAI,KAAK,kBAAS,CAAC,QAAQ,IAAI,QAAQ,CAAC,KAAK,KAAK,IAAI,EAAE,CAAC;YAClE,OAAO,IAAI,CAAC,YAAY,CAAC,kBAAS,CAAC,IAAI,EAAE,MAAM,CAAC,UAAU,CAAC,CAAC;QAChE,CAAC;QAED,OAAO,IAAI,CAAC;IAChB,CAAC;CACJ;AAxCD,0CAwCC"}
@@ -0,0 +1,188 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.CTEBuilder = void 0;
4
+ const Clause_1 = require("../models/Clause");
5
+ const CTECollector_1 = require("./CTECollector");
6
+ const TableSourceCollector_1 = require("./TableSourceCollector");
7
+ const Formatter_1 = require("./Formatter");
8
+ /**
9
+ * CTENameConflictResolver is responsible for resolving name conflicts among Common Table Expressions (CTEs).
10
+ * It also sorts the tables in the proper order based on dependencies and recursiveness.
11
+ */
12
+ class CTEBuilder {
13
+ constructor() {
14
+ this.sourceCollector = new TableSourceCollector_1.TableSourceCollector(true);
15
+ this.cteCollector = new CTECollector_1.CTECollector();
16
+ this.formatter = new Formatter_1.Formatter();
17
+ }
18
+ /**
19
+ * Resolves name conflicts among CommonTables.
20
+ * If there are duplicate CTE names, they must have identical definitions.
21
+ * Also sorts the tables so that:
22
+ * 1. Recursive CTEs come first (CTEs that reference themselves)
23
+ * 2. Then remaining tables are sorted so inner (deeper) CTEs come before outer CTEs
24
+ *
25
+ * @param commonTables The list of CommonTables to check for name conflicts
26
+ * @returns An object containing:
27
+ * - needRecursive: boolean indicating if any recursive CTEs are present
28
+ * - commonTables: A new list of CommonTables with resolved name conflicts and proper order
29
+ * @throws Error if there are duplicate CTE names with different definitions
30
+ */
31
+ build(commonTables) {
32
+ // Early return for empty CTEs
33
+ // Note:
34
+ // Although it may seem reasonable to return early when there is only one element,
35
+ // the 'recursive' property is determined dynamically. Therefore, if there is at least one element,
36
+ // the CTEs must be rebuilt to ensure correct recursive detection.
37
+ if (commonTables.length === 0) {
38
+ return new Clause_1.WithClause(false, commonTables);
39
+ }
40
+ // Step 1: Resolve name conflicts
41
+ const resolvedTables = this.resolveDuplicateNames(commonTables);
42
+ // Step 2: Identify recursive CTEs and build dependency graph
43
+ const { tableMap, recursiveCTEs, dependencies } = this.buildDependencyGraph(resolvedTables);
44
+ // Step 3: Sort tables according to dependencies and recursiveness
45
+ const sortedTables = this.sortCommonTables(resolvedTables, tableMap, recursiveCTEs, dependencies);
46
+ return new Clause_1.WithClause(recursiveCTEs.size > 0, sortedTables);
47
+ }
48
+ /**
49
+ * Resolves duplicate CTE names by checking if they have identical definitions.
50
+ * If definitions differ, throws an error.
51
+ *
52
+ * @param commonTables The list of CTEs to check for duplicates
53
+ * @returns A list of CTEs with duplicates removed
54
+ * @throws Error if there are duplicate CTE names with different definitions
55
+ */
56
+ resolveDuplicateNames(commonTables) {
57
+ // Group CTEs by their names
58
+ const ctesByName = new Map();
59
+ for (const table of commonTables) {
60
+ const tableName = table.aliasExpression.table.name;
61
+ if (!ctesByName.has(tableName)) {
62
+ ctesByName.set(tableName, []);
63
+ }
64
+ ctesByName.get(tableName).push(table);
65
+ }
66
+ // Resolve name duplications
67
+ const resolvedTables = [];
68
+ for (const [name, tables] of ctesByName.entries()) {
69
+ if (tables.length === 1) {
70
+ // No duplication
71
+ resolvedTables.push(tables[0]);
72
+ continue;
73
+ }
74
+ // For duplicate names, check if definitions are identical
75
+ const definitions = tables.map(table => this.formatter.visit(table.query));
76
+ const uniqueDefinitions = new Set(definitions);
77
+ if (uniqueDefinitions.size === 1) {
78
+ // If all definitions are identical, use only the first one
79
+ resolvedTables.push(tables[0]);
80
+ }
81
+ else {
82
+ // Error if definitions differ
83
+ throw new Error(`CTE name conflict detected: '${name}' has multiple different definitions`);
84
+ }
85
+ }
86
+ return resolvedTables;
87
+ }
88
+ /**
89
+ * Builds a dependency graph of CTEs and identifies recursive CTEs.
90
+ *
91
+ * @param tables The list of CTEs to analyze
92
+ * @returns Object containing the table map, set of recursive CTEs, and dependency map
93
+ */
94
+ buildDependencyGraph(tables) {
95
+ // Create a map of table names for quick lookup
96
+ const tableMap = new Map();
97
+ for (const table of tables) {
98
+ tableMap.set(table.aliasExpression.table.name, table);
99
+ }
100
+ // Identify recursive CTEs (those that reference themselves)
101
+ const recursiveCTEs = new Set();
102
+ // Build dependency graph: which tables reference which other tables
103
+ const dependencies = new Map();
104
+ const referencedBy = new Map();
105
+ for (const table of tables) {
106
+ const tableName = table.aliasExpression.table.name;
107
+ // Check for self-references (recursive CTEs)
108
+ const referencedTables = this.sourceCollector.collect(table.query);
109
+ // Check if this CTE references itself
110
+ for (const referencedTable of referencedTables) {
111
+ if (referencedTable.table.name === tableName) {
112
+ recursiveCTEs.add(tableName);
113
+ break;
114
+ }
115
+ }
116
+ // Setup dependencies
117
+ if (!dependencies.has(tableName)) {
118
+ dependencies.set(tableName, new Set());
119
+ }
120
+ // Find any references to other CTEs in this table's query
121
+ const referencedCTEs = this.cteCollector.collect(table.query);
122
+ for (const referencedCTE of referencedCTEs) {
123
+ const referencedName = referencedCTE.aliasExpression.table.name;
124
+ // Only consider references to tables in our collection
125
+ if (tableMap.has(referencedName)) {
126
+ dependencies.get(tableName).add(referencedName);
127
+ // Add the reverse relationship
128
+ if (!referencedBy.has(referencedName)) {
129
+ referencedBy.set(referencedName, new Set());
130
+ }
131
+ referencedBy.get(referencedName).add(tableName);
132
+ }
133
+ }
134
+ }
135
+ return { tableMap, recursiveCTEs, dependencies };
136
+ }
137
+ /**
138
+ * Sorts the CTEs using topological sort, with recursive CTEs coming first.
139
+ *
140
+ * @param tables The list of CTEs to sort
141
+ * @param tableMap Map of table names to their CommonTable objects
142
+ * @param recursiveCTEs Set of table names that are recursive (self-referential)
143
+ * @param dependencies Map of table dependencies
144
+ * @returns Sorted list of CTEs
145
+ * @throws Error if a circular reference is detected
146
+ */
147
+ sortCommonTables(tables, tableMap, recursiveCTEs, dependencies) {
148
+ const recursiveResult = [];
149
+ const nonRecursiveResult = [];
150
+ const visited = new Set();
151
+ const visiting = new Set();
152
+ // Topological sort function
153
+ const visit = (tableName) => {
154
+ if (visited.has(tableName))
155
+ return;
156
+ if (visiting.has(tableName)) {
157
+ throw new Error(`Circular reference detected in CTE: ${tableName}`);
158
+ }
159
+ visiting.add(tableName);
160
+ // Process dependencies first (inner CTEs)
161
+ const deps = dependencies.get(tableName) || new Set();
162
+ for (const dep of deps) {
163
+ visit(dep);
164
+ }
165
+ visiting.delete(tableName);
166
+ visited.add(tableName);
167
+ // Add this table after its dependencies
168
+ // Recursive CTEs go to recursiveResult, others to nonRecursiveResult
169
+ if (recursiveCTEs.has(tableName)) {
170
+ recursiveResult.push(tableMap.get(tableName));
171
+ }
172
+ else {
173
+ nonRecursiveResult.push(tableMap.get(tableName));
174
+ }
175
+ };
176
+ // Process all tables
177
+ for (const table of tables) {
178
+ const tableName = table.aliasExpression.table.name;
179
+ if (!visited.has(tableName)) {
180
+ visit(tableName);
181
+ }
182
+ }
183
+ // Combine the results: recursive CTEs first, then non-recursive CTEs
184
+ return [...recursiveResult, ...nonRecursiveResult];
185
+ }
186
+ }
187
+ exports.CTEBuilder = CTEBuilder;
188
+ //# sourceMappingURL=CTEBuilder.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"CTEBuilder.js","sourceRoot":"","sources":["../../src/transformers/CTEBuilder.ts"],"names":[],"mappings":"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"}