rawsql-ts 0.6.0-beta → 0.7.0-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.
Files changed (188) hide show
  1. package/README.md +141 -121
  2. package/dist/esm/index.js +1 -0
  3. package/dist/esm/index.js.map +1 -1
  4. package/dist/esm/models/Clause.js +111 -43
  5. package/dist/esm/models/Clause.js.map +1 -1
  6. package/dist/esm/models/CreateTableQuery.js +12 -22
  7. package/dist/esm/models/CreateTableQuery.js.map +1 -1
  8. package/dist/esm/models/KeywordTrie.js +2 -0
  9. package/dist/esm/models/KeywordTrie.js.map +1 -1
  10. package/dist/esm/models/SimpleSelectQuery.js +17 -15
  11. package/dist/esm/models/SimpleSelectQuery.js.map +1 -1
  12. package/dist/esm/models/SqlPrintToken.js +94 -0
  13. package/dist/esm/models/SqlPrintToken.js.map +1 -0
  14. package/dist/esm/models/ValueComponent.js +86 -17
  15. package/dist/esm/models/ValueComponent.js.map +1 -1
  16. package/dist/esm/parsers/FetchClauseParser.js +84 -0
  17. package/dist/esm/parsers/FetchClauseParser.js.map +1 -0
  18. package/dist/esm/parsers/FullNameParser.js +6 -1
  19. package/dist/esm/parsers/FullNameParser.js.map +1 -1
  20. package/dist/esm/parsers/IdentifierDecorator.js +13 -0
  21. package/dist/esm/parsers/IdentifierDecorator.js.map +1 -0
  22. package/dist/esm/parsers/InsertQueryParser.js +1 -1
  23. package/dist/esm/parsers/JoinClauseParser.js +13 -35
  24. package/dist/esm/parsers/JoinClauseParser.js.map +1 -1
  25. package/dist/esm/parsers/JoinOnClauseParser.js +17 -0
  26. package/dist/esm/parsers/JoinOnClauseParser.js.map +1 -0
  27. package/dist/esm/parsers/JoinUsingClauseParser.js +19 -0
  28. package/dist/esm/parsers/JoinUsingClauseParser.js.map +1 -0
  29. package/dist/esm/parsers/LimitClauseParser.js +1 -13
  30. package/dist/esm/parsers/LimitClauseParser.js.map +1 -1
  31. package/dist/esm/parsers/OffsetClauseParser.js +38 -0
  32. package/dist/esm/parsers/OffsetClauseParser.js.map +1 -0
  33. package/dist/esm/parsers/ParameterDecorator.js +36 -0
  34. package/dist/esm/parsers/ParameterDecorator.js.map +1 -0
  35. package/dist/esm/parsers/SelectClauseParser.js +25 -2
  36. package/dist/esm/parsers/SelectClauseParser.js.map +1 -1
  37. package/dist/esm/parsers/SelectQueryParser.js +40 -13
  38. package/dist/esm/parsers/SelectQueryParser.js.map +1 -1
  39. package/dist/esm/parsers/SourceParser.js +17 -13
  40. package/dist/esm/parsers/SourceParser.js.map +1 -1
  41. package/dist/esm/parsers/SqlPrintTokenParser.js +1058 -0
  42. package/dist/esm/parsers/SqlPrintTokenParser.js.map +1 -0
  43. package/dist/esm/parsers/WindowClauseParser.js +27 -15
  44. package/dist/esm/parsers/WindowClauseParser.js.map +1 -1
  45. package/dist/esm/tokenReaders/BaseTokenReader.js +3 -3
  46. package/dist/esm/tokenReaders/BaseTokenReader.js.map +1 -1
  47. package/dist/esm/tokenReaders/CommandTokenReader.js +8 -2
  48. package/dist/esm/tokenReaders/CommandTokenReader.js.map +1 -1
  49. package/dist/esm/transformers/CTECollector.js +9 -10
  50. package/dist/esm/transformers/CTECollector.js.map +1 -1
  51. package/dist/esm/transformers/CTEDisabler.js +10 -9
  52. package/dist/esm/transformers/CTEDisabler.js.map +1 -1
  53. package/dist/esm/transformers/CTEInjector.js +2 -2
  54. package/dist/esm/transformers/Formatter.js +19 -646
  55. package/dist/esm/transformers/Formatter.js.map +1 -1
  56. package/dist/esm/transformers/LinePrinter.js +81 -0
  57. package/dist/esm/transformers/LinePrinter.js.map +1 -0
  58. package/dist/esm/transformers/QueryBuilder.js +8 -18
  59. package/dist/esm/transformers/QueryBuilder.js.map +1 -1
  60. package/dist/esm/transformers/SelectableColumnCollector.js +26 -9
  61. package/dist/esm/transformers/SelectableColumnCollector.js.map +1 -1
  62. package/dist/esm/transformers/SqlFormatter.js +31 -0
  63. package/dist/esm/transformers/SqlFormatter.js.map +1 -0
  64. package/dist/esm/transformers/SqlOutputToken.js +9 -0
  65. package/dist/esm/transformers/SqlOutputToken.js.map +1 -0
  66. package/dist/esm/transformers/SqlPrinter.js +144 -0
  67. package/dist/esm/transformers/SqlPrinter.js.map +1 -0
  68. package/dist/esm/transformers/TableSourceCollector.js +32 -16
  69. package/dist/esm/transformers/TableSourceCollector.js.map +1 -1
  70. package/dist/esm/types/index.d.ts +1 -0
  71. package/dist/esm/types/models/Clause.d.ts +64 -13
  72. package/dist/esm/types/models/SimpleSelectQuery.d.ts +20 -5
  73. package/dist/esm/types/models/SqlPrintToken.d.ts +102 -0
  74. package/dist/esm/types/models/ValueComponent.d.ts +43 -9
  75. package/dist/esm/types/parsers/FetchClauseParser.d.ts +24 -0
  76. package/dist/esm/types/parsers/FullNameParser.d.ts +1 -0
  77. package/dist/esm/types/parsers/IdentifierDecorator.d.ts +9 -0
  78. package/dist/esm/types/parsers/JoinClauseParser.d.ts +0 -2
  79. package/dist/esm/types/parsers/JoinOnClauseParser.d.ts +8 -0
  80. package/dist/esm/types/parsers/JoinUsingClauseParser.d.ts +8 -0
  81. package/dist/esm/types/parsers/OffsetClauseParser.d.ts +9 -0
  82. package/dist/esm/types/parsers/ParameterDecorator.d.ts +20 -0
  83. package/dist/esm/types/parsers/SelectClauseParser.d.ts +19 -2
  84. package/dist/esm/types/parsers/SqlPrintTokenParser.d.ts +144 -0
  85. package/dist/esm/types/parsers/WindowClauseParser.d.ts +3 -3
  86. package/dist/esm/types/transformers/Formatter.d.ts +8 -105
  87. package/dist/esm/types/transformers/LinePrinter.d.ts +41 -0
  88. package/dist/esm/types/transformers/SelectableColumnCollector.d.ts +2 -0
  89. package/dist/esm/types/transformers/SqlFormatter.d.ts +40 -0
  90. package/dist/esm/types/transformers/SqlOutputToken.d.ts +6 -0
  91. package/dist/esm/types/transformers/SqlPrinter.d.ts +54 -0
  92. package/dist/esm/types/transformers/TableSourceCollector.d.ts +2 -0
  93. package/dist/esm/utils/stringUtils.js +17 -0
  94. package/dist/esm/utils/stringUtils.js.map +1 -1
  95. package/dist/index.d.ts +1 -0
  96. package/dist/index.js +1 -0
  97. package/dist/index.js.map +1 -1
  98. package/dist/models/Clause.d.ts +64 -13
  99. package/dist/models/Clause.js +115 -44
  100. package/dist/models/Clause.js.map +1 -1
  101. package/dist/models/CreateTableQuery.js +12 -22
  102. package/dist/models/CreateTableQuery.js.map +1 -1
  103. package/dist/models/KeywordTrie.js +2 -0
  104. package/dist/models/KeywordTrie.js.map +1 -1
  105. package/dist/models/SimpleSelectQuery.d.ts +20 -5
  106. package/dist/models/SimpleSelectQuery.js +17 -15
  107. package/dist/models/SimpleSelectQuery.js.map +1 -1
  108. package/dist/models/SqlPrintToken.d.ts +102 -0
  109. package/dist/models/SqlPrintToken.js +98 -0
  110. package/dist/models/SqlPrintToken.js.map +1 -0
  111. package/dist/models/ValueComponent.d.ts +43 -9
  112. package/dist/models/ValueComponent.js +88 -18
  113. package/dist/models/ValueComponent.js.map +1 -1
  114. package/dist/parsers/FetchClauseParser.d.ts +24 -0
  115. package/dist/parsers/FetchClauseParser.js +89 -0
  116. package/dist/parsers/FetchClauseParser.js.map +1 -0
  117. package/dist/parsers/FullNameParser.d.ts +1 -0
  118. package/dist/parsers/FullNameParser.js +6 -1
  119. package/dist/parsers/FullNameParser.js.map +1 -1
  120. package/dist/parsers/IdentifierDecorator.d.ts +9 -0
  121. package/dist/parsers/IdentifierDecorator.js +17 -0
  122. package/dist/parsers/IdentifierDecorator.js.map +1 -0
  123. package/dist/parsers/InsertQueryParser.js +1 -1
  124. package/dist/parsers/JoinClauseParser.d.ts +0 -2
  125. package/dist/parsers/JoinClauseParser.js +12 -34
  126. package/dist/parsers/JoinClauseParser.js.map +1 -1
  127. package/dist/parsers/JoinOnClauseParser.d.ts +8 -0
  128. package/dist/parsers/JoinOnClauseParser.js +21 -0
  129. package/dist/parsers/JoinOnClauseParser.js.map +1 -0
  130. package/dist/parsers/JoinUsingClauseParser.d.ts +8 -0
  131. package/dist/parsers/JoinUsingClauseParser.js +23 -0
  132. package/dist/parsers/JoinUsingClauseParser.js.map +1 -0
  133. package/dist/parsers/LimitClauseParser.js +1 -13
  134. package/dist/parsers/LimitClauseParser.js.map +1 -1
  135. package/dist/parsers/OffsetClauseParser.d.ts +9 -0
  136. package/dist/parsers/OffsetClauseParser.js +42 -0
  137. package/dist/parsers/OffsetClauseParser.js.map +1 -0
  138. package/dist/parsers/ParameterDecorator.d.ts +20 -0
  139. package/dist/parsers/ParameterDecorator.js +40 -0
  140. package/dist/parsers/ParameterDecorator.js.map +1 -0
  141. package/dist/parsers/SelectClauseParser.d.ts +19 -2
  142. package/dist/parsers/SelectClauseParser.js +28 -4
  143. package/dist/parsers/SelectClauseParser.js.map +1 -1
  144. package/dist/parsers/SelectQueryParser.js +40 -13
  145. package/dist/parsers/SelectQueryParser.js.map +1 -1
  146. package/dist/parsers/SourceParser.js +17 -13
  147. package/dist/parsers/SourceParser.js.map +1 -1
  148. package/dist/parsers/SqlPrintTokenParser.d.ts +144 -0
  149. package/dist/parsers/SqlPrintTokenParser.js +1062 -0
  150. package/dist/parsers/SqlPrintTokenParser.js.map +1 -0
  151. package/dist/parsers/WindowClauseParser.d.ts +3 -3
  152. package/dist/parsers/WindowClauseParser.js +26 -14
  153. package/dist/parsers/WindowClauseParser.js.map +1 -1
  154. package/dist/tokenReaders/BaseTokenReader.js +3 -3
  155. package/dist/tokenReaders/BaseTokenReader.js.map +1 -1
  156. package/dist/tokenReaders/CommandTokenReader.js +8 -2
  157. package/dist/tokenReaders/CommandTokenReader.js.map +1 -1
  158. package/dist/transformers/CTECollector.js +9 -10
  159. package/dist/transformers/CTECollector.js.map +1 -1
  160. package/dist/transformers/CTEDisabler.js +9 -8
  161. package/dist/transformers/CTEDisabler.js.map +1 -1
  162. package/dist/transformers/CTEInjector.js +2 -2
  163. package/dist/transformers/Formatter.d.ts +8 -105
  164. package/dist/transformers/Formatter.js +20 -647
  165. package/dist/transformers/Formatter.js.map +1 -1
  166. package/dist/transformers/LinePrinter.d.ts +41 -0
  167. package/dist/transformers/LinePrinter.js +86 -0
  168. package/dist/transformers/LinePrinter.js.map +1 -0
  169. package/dist/transformers/QueryBuilder.js +8 -18
  170. package/dist/transformers/QueryBuilder.js.map +1 -1
  171. package/dist/transformers/SelectableColumnCollector.d.ts +2 -0
  172. package/dist/transformers/SelectableColumnCollector.js +25 -8
  173. package/dist/transformers/SelectableColumnCollector.js.map +1 -1
  174. package/dist/transformers/SqlFormatter.d.ts +40 -0
  175. package/dist/transformers/SqlFormatter.js +35 -0
  176. package/dist/transformers/SqlFormatter.js.map +1 -0
  177. package/dist/transformers/SqlOutputToken.d.ts +6 -0
  178. package/dist/transformers/SqlOutputToken.js +13 -0
  179. package/dist/transformers/SqlOutputToken.js.map +1 -0
  180. package/dist/transformers/SqlPrinter.d.ts +54 -0
  181. package/dist/transformers/SqlPrinter.js +148 -0
  182. package/dist/transformers/SqlPrinter.js.map +1 -0
  183. package/dist/transformers/TableSourceCollector.d.ts +2 -0
  184. package/dist/transformers/TableSourceCollector.js +30 -14
  185. package/dist/transformers/TableSourceCollector.js.map +1 -1
  186. package/dist/utils/stringUtils.js +17 -0
  187. package/dist/utils/stringUtils.js.map +1 -1
  188. package/package.json +2 -1
package/README.md CHANGED
@@ -24,8 +24,14 @@ With rawsql-ts, raw SQL can be represented as objects, enabling flexible manipul
24
24
  ## Features
25
25
 
26
26
  - Zero dependencies: fully self-contained and lightweight
27
- - High-speed SQL parsing and AST analysis
27
+ - High-speed SQL parsing and AST analysis (over 3x faster than major libraries)
28
28
  - Rich utilities for SQL structure transformation and analysis
29
+ - Advanced SQL formatting capabilities, including multi-line formatting and customizable styles
30
+
31
+ ![Benchmark Results](https://quickchart.io/chart?c={type:'bar',data:{labels:['Tokens20','Tokens70','Tokens140','Tokens230'],datasets:[{label:'rawsql-ts',data:[0.029,0.075,0.137,0.239],backgroundColor:'rgba(54,162,235,0.8)',borderColor:'rgba(54,162,235,1)',borderWidth:1},{label:'node-sql-parser',data:[0.210,0.223,0.420,0.871],backgroundColor:'rgba(255,206,86,0.8)',borderColor:'rgba(255,206,86,1)',borderWidth:1},{label:'sql-formatter',data:[0.228,0.547,1.057,1.906],backgroundColor:'rgba(255,99,132,0.8)',borderColor:'rgba(255,99,132,1)',borderWidth:1}]},options:{plugins:{legend:{labels:{color:'black'}}},scales:{x:{ticks:{color:'black'}},y:{ticks:{color:'black'}}},backgroundColor:'white'}})
32
+
33
+ > [!Note]
34
+ > The "Mean" column represents the average time taken to process a query. Lower values indicate faster performance. For more details, see the [Benchmark](#benchmarks).
29
35
 
30
36
  ## ✨ Browser & CDN Ready!
31
37
 
@@ -58,12 +64,12 @@ npm install rawsql-ts
58
64
  ## Quick Start
59
65
 
60
66
  ```typescript
61
- import { SelectQueryParser, Formatter } from 'rawsql-ts';
67
+ import { SelectQueryParser, SqlFormatter } from 'rawsql-ts';
62
68
 
63
69
  const sql = `SELECT user_id, name FROM users WHERE active = TRUE`;
64
70
  const query = SelectQueryParser.parse(sql);
65
- const formatter = new Formatter();
66
- const formattedSql = formatter.format(query);
71
+ const formatter = new SqlFormatter();
72
+ const { formattedSql } = formatter.format(query);
67
73
 
68
74
  console.log(formattedSql);
69
75
  // => select "user_id", "name" from "users" where "active" = true
@@ -73,141 +79,152 @@ console.log(formattedSql);
73
79
 
74
80
  ## Formatter Functionality
75
81
 
76
- The `Formatter` class in rawsql-ts converts a parsed query object (AST) back into a formatted SQL string. This is useful for programmatically manipulating SQL and then generating a string for execution or display.
82
+ The `SqlFormatter` class in rawsql-ts is the recommended way to format SQL queries. It provides advanced SQL formatting capabilities, including support for indentation, keyword casing, and line breaks, making it ideal for generating human-readable SQL.
83
+
84
+ > [!Note]
85
+ > While the older `Formatter` class is still available for backward compatibility, `SqlFormatter` offers enhanced functionality and is the preferred choice for new projects. `SqlFormatter` is available starting from version 0.7.
86
+
87
+ ### Key Features of SqlFormatter
77
88
 
78
- ### Preset Configurations (Formatter.PRESETS)
89
+ - **Indentation and Keyword Casing**: Supports customizable indentation and keyword casing (e.g., UPPERCASE, lowercase).
90
+ - **Preset Configurations**: Includes presets for common SQL dialects (MySQL, PostgreSQL, SQL Server, SQLite) to simplify configuration.
91
+ - **Customizable Options**: Allows fine-grained control over formatting styles, such as comma placement, parameter styles, and newline characters.
92
+ - **Parameterized Query Formatting**: Supports anonymous (`?`), indexed (`$1`, `$2`), and named (`:name`, `@name`) parameter styles for compatibility with various database systems.
79
93
 
80
- The `Formatter` class provides preset configurations for common SQL dialects. Use these presets to quickly format queries for MySQL, PostgreSQL, SQL Server, or SQLite without manually specifying options each time.
94
+ ### Preset Configurations (SqlFormatter.PRESETS)
95
+
96
+ The `SqlFormatter` class provides preset configurations for common SQL dialects. Use these presets to quickly format queries without manually specifying options each time.
81
97
 
82
98
  ```typescript
83
- const mysqlSql = formatter.format(query, Formatter.PRESETS.mysql);
84
- const pgSql = formatter.format(query, Formatter.PRESETS.postgres);
85
- const mssqlSql = formatter.format(query, Formatter.PRESETS.sqlserver);
86
- const sqliteSql = formatter.format(query, Formatter.PRESETS.sqlite);
99
+ const formatter = new SqlFormatter({ preset: 'mysql' });
100
+ const { formattedSql } = formatter.format(query);
101
+ console.log(formattedSql);
87
102
  ```
88
103
 
89
104
  **Preset Details:**
90
- - `Formatter.PRESETS.mysql`: Backtick identifier, `?` parameter, no named parameters
91
- - `Formatter.PRESETS.postgres`: Double quote identifier, `:` parameter, named parameters supported
92
- - `Formatter.PRESETS.sqlserver`: Square bracket identifier, `@` parameter, named parameters supported
93
- - `Formatter.PRESETS.sqlite`: Double quote identifier, `:` parameter, named parameters supported
105
+ - `mysql`: Backtick identifier, `?` parameter, no named parameters
106
+ - `postgres`: Double quote identifier, `$` parameter, indexed parameters
107
+ - `sqlserver`: Square bracket identifier, `@` parameter, named parameters
108
+ - `sqlite`: Double quote identifier, `:` parameter, named parameters
94
109
 
95
- ### How to Customize Presets
110
+ ### Customizing SqlFormatter
96
111
 
97
112
  You can override any preset option as needed. For example, to use variable-style parameters (`${name}`):
98
113
 
99
114
  ```typescript
100
- const variableSql = formatter.format(query, {
101
- ...Formatter.PRESETS.postgres,
115
+ const formatter = new SqlFormatter({
116
+ preset: 'postgres',
102
117
  parameterSymbol: { start: '${', end: '}' },
103
118
  });
119
+ const { formattedSql } = formatter.format(query);
120
+ console.log(formattedSql);
104
121
  // => select "user_id", "name" from "users" where "active" = ${active}
105
122
  ```
106
123
 
107
- Or to change only the identifier escape style:
124
+ ### Configurable Options
108
125
 
109
- ```typescript
110
- const customSql = formatter.format(query, {
111
- ...Formatter.PRESETS.mysql,
112
- identifierEscape: { start: '"', end: '"' }
113
- });
114
- ```
126
+ SqlFormatter supports a wide range of options to customize the output:
115
127
 
116
- ### Configurable Options
128
+ - `identifierEscape`: How identifiers are escaped (e.g., `"`, `[`, `` ` ``).
129
+ - `parameterSymbol`: The symbol or pattern for parameters (e.g., `:`, `@`, `?`, or `{ start: '${', end: '}' }`).
130
+ - `parameterStyle`: Controls the parameter style (anonymous, indexed, or named).
131
+ - `indentSize`: Number of spaces or tabs for indentation.
132
+ - `keywordCase`: Casing for SQL keywords (`upper`, `lower`, or `none`).
133
+ - `commaBreak`: Placement of commas (`before` or `after`).
134
+ - `andBreak`: Placement of `AND`/`OR` in conditions (`before` or `after`).
135
+ - `newline`: Specifies the newline character used in the output (e.g., `\n`, `\r\n`, or a single space for compact formatting).
117
136
 
118
- Formatting options are provided as the second argument to the `formatWithParameters()` method. You can customize:
119
- - `identifierEscape`: How identifiers are escaped (e.g., `"`, `[`, `` ` ``)
120
- - `parameterSymbol`: The symbol or pattern for parameters (e.g., `:`, `@`, `?`, or `{ start: '${', end: '}' }`)
121
- - `parameterStyle`: Controls the parameter style (anonymous, indexed, or named)
137
+ ### Parameterized Query Formatting
122
138
 
123
- > [!Note]
124
- > The traditional `format()` method is also available. If you only need the SQL string without parameter information, use the `format` method instead of `formatWithParameters()`.
139
+ `SqlFormatter` supports advanced parameterized query formatting for all major SQL dialects. You can output SQL with parameters in three styles:
140
+
141
+ - **Anonymous** (`?`): For MySQL and similar drivers. Parameters are output as `?` and values are provided as an array.
142
+ - **Indexed** (`$1`, `$2`, ...): For PostgreSQL and compatible drivers. Parameters are output as `$1`, `$2`, ... and values are provided as an array in the correct order.
143
+ - **Named** (`:name`, `@name`): For SQL Server, SQLite, and ORMs. Parameters are output as `:name` or `@name` and values are provided as an object.
144
+
145
+ The `parameterStyle` option in `SqlFormatter` allows you to control the parameter style, or you can use built-in presets (e.g., `mysql`, `postgres`, `sqlserver`, `sqlite`) to apply the correct style automatically.
125
146
 
126
147
  ### Usage Example
127
148
 
128
149
  #### Using a Preset
129
150
 
130
151
  ```typescript
131
- import { SelectQueryParser, Formatter } from 'rawsql-ts';
152
+ import { SqlFormatter } from 'rawsql-ts';
132
153
 
133
154
  const sql = `SELECT user_id, name FROM users WHERE active = TRUE`;
134
155
  const query = SelectQueryParser.parse(sql);
135
- const formatter = new Formatter();
136
- const formatted = formatter.formatWithParameters(query, Formatter.PRESETS.postgres);
137
- console.log(formatted.sql);
138
- // => select "user_id", "name" from "users" where "active" = true
139
- console.log(formatted.params);
140
- // => { ... } (parameters object or array depending on style)
156
+ const formatter = new SqlFormatter({ preset: 'postgres' });
157
+ const { formattedSql } = formatter.format(query);
158
+ console.log(formattedSql);
159
+ /*
160
+ select "user_id", "name" from "users" where "active" = true
161
+ */
141
162
  ```
142
163
 
143
- #### Using Manual Configuration
164
+ #### Using Custom Configuration
144
165
 
145
166
  ```typescript
146
- import { SelectQueryParser, Formatter } from 'rawsql-ts';
167
+ import { SqlFormatter } from 'rawsql-ts';
147
168
 
148
169
  const sql = `SELECT user_id, name FROM users WHERE active = TRUE`;
149
170
  const query = SelectQueryParser.parse(sql);
150
- const formatter = new Formatter();
151
- const formatted = formatter.formatWithParameters(query, {
171
+ const formatter = new SqlFormatter({
152
172
  identifierEscape: { start: '`', end: '`' },
153
173
  parameterSymbol: '?',
154
174
  parameterStyle: 'anonymous',
175
+ indentSize: 2,
176
+ keywordCase: 'upper',
177
+ newline: '\r\n',
178
+ commaBreak: 'before', // Specify the "before comma" option
155
179
  });
156
- console.log(formatted.sql);
157
- // => select `user_id`, `name` from `users` where `active` = ?
158
- console.log(formatted.params);
159
- // => [ ... ] (parameters array)
180
+ const { formattedSql } = formatter.format(query);
181
+ console.log(formattedSql);
182
+ /*
183
+ SELECT
184
+ `user_id`
185
+ , `name`
186
+ FROM
187
+ `users`
188
+ WHERE
189
+ `active` = ?
190
+ */
160
191
  ```
161
192
 
162
- rawsql-ts is designed to be flexible and support various SQL dialects. The `Formatter` class can be customized to handle different dialects by adjusting the identifier escape characters, parameter symbols, and parameter style. This makes it easy to work with SQL queries for different database systems using a consistent API.
163
-
164
- ---
165
-
166
- ### Advanced Parameterized Query Formatting
167
-
168
- rawsql-ts's `Formatter` class supports advanced parameterized query formatting for all major SQL dialects. You can output SQL with parameters in three styles:
169
-
170
- - **Anonymous** (`?`): For MySQL and similar drivers. Parameters are output as `?` and values are provided as an array.
171
- - **Indexed** (`$1`, `$2`, ...): For PostgreSQL and compatible drivers. Parameters are output as `$1`, `$2`, ... and values are provided as an array in the correct order.
172
- - **Named** (`:name`, `@name`, `$name`): For SQL Server, SQLite, and ORMs that support named parameters. Parameters are output as `:name`, `@name`, or `$name` and values are provided as an object (dictionary).
173
-
174
- You can control the parameter style using the `parameterStyle` option in the Formatter configuration, or by using one of the built-in presets. **In most cases, you do not need to set this manually—just use the appropriate preset (e.g., `Formatter.PRESETS.mysql`, `Formatter.PRESETS.postgres`, etc.) and the correct parameter style will be applied automatically.**
175
-
176
- #### Example: Parameterized Query Output
193
+ #### Parameterized Query Output
177
194
 
178
195
  ```typescript
179
- import { SelectQueryParser, Formatter, ParameterStyle } from 'rawsql-ts';
196
+ import { SelectQueryParser, SqlFormatter } from 'rawsql-ts';
180
197
 
181
198
  const sql = 'SELECT * FROM users WHERE id = :id AND status = :status';
182
199
  const query = SelectQueryParser.parse(sql);
183
200
  query.setParameter('id', 123);
184
201
  query.setParameter('status', 'active');
185
- const formatter = new Formatter();
186
-
187
- // Anonymous style (MySQL)
188
- const anon = formatter.formatWithParameters(query, { parameterStyle: ParameterStyle.Anonymous });
189
- // anon.sql: 'select * from "users" where "id" = ? and "status" = ?'
190
- // anon.params: [123, 'active']
191
-
192
- // Indexed style (PostgreSQL)
193
- const indexed = formatter.formatWithParameters(query, { parameterStyle: ParameterStyle.Indexed });
194
- // indexed.sql: 'select * from "users" where "id" = $1 and "status" = $2'
195
- // indexed.params: [123, 'active']
196
-
197
- // Named style (SQL Server, SQLite, ORMs)
198
- const named = formatter.formatWithParameters(query, { parameterStyle: ParameterStyle.Named });
199
- // named.sql: 'select * from "users" where "id" = :id and "status" = :status'
200
- // named.params: { id: 123, status: 'active' }
202
+
203
+ const formatter = new SqlFormatter({ parameterStyle: 'named' });
204
+ const { formattedSql, params } = formatter.format(query);
205
+
206
+ console.log(formattedSql);
207
+ // => select * from "users" where "id" = :id and "status" = :status
208
+ console.log(params);
209
+ // => { id: 123, status: 'active' }
201
210
  ```
202
211
 
203
- The formatter automatically assigns parameter indexes in the order they appear in the query, even for complex queries with CTEs, subqueries, or set operations (UNION, INTERSECT, etc.). When combining queries, parameter indexes are always reassigned to ensure correct binding order for your database client.
212
+ For anonymous or indexed styles, simply change the `parameterStyle` option:
204
213
 
205
- This makes rawsql-ts ideal for building safe, maintainable, and highly portable SQL in TypeScript, with zero risk of SQL injection and maximum compatibility across database systems.
214
+ ```typescript
215
+ const formatter = new SqlFormatter({ parameterStyle: 'anonymous' });
216
+ // formattedSql: 'select * from "users" where "id" = ? and "status" = ?'
217
+ // params: [123, 'active']
206
218
 
207
- A unique feature of rawsql-ts is the `setParameter` method. Instead of passing parameter values at formatting time, you assign values directly to the query object using `setParameter`. This makes your code highly portable and decouples query construction from parameter binding. Parameter indexes (for indexed or anonymous styles) are always assigned at formatting time, so even if you modify or combine queries (e.g., with UNION, CTEs, or subqueries), the parameter order and binding will always be correct and never break.
219
+ const formatterIndexed = new SqlFormatter({ parameterStyle: 'indexed' });
220
+ // formattedSql: 'select * from "users" where "id" = $1 and "status" = $2'
221
+ // params: [123, 'active']
222
+ ```
223
+
224
+ `SqlFormatter` ensures parameter indexes are assigned correctly, even for complex queries with CTEs, subqueries, or set operations. This makes it easy to build safe, maintainable, and portable SQL in TypeScript.
208
225
 
209
226
  > [!Tip]
210
- > While rawsql-ts supports anonymous and indexed parameters, it is highly recommended to use named parameters in your source code. Using names makes your queries much more readable and maintainable, and the setParameter method assigns values by name, reducing the risk of mistakes. You can always output the final SQL and parameters in the style required by your database client (e.g., anonymous or indexed) at formatting time. This approach lets you write clear, maintainable code during development, while still generating the exact parameter style needed for your production environment.
227
+ > Use named parameters in your source code for better readability and maintainability. You can always output the final SQL and parameters in the style required by your database client (e.g., anonymous or indexed) at formatting time.
211
228
 
212
229
  ---
213
230
 
@@ -319,7 +336,7 @@ const query = SelectQueryParser.parse(`
319
336
  // Add a filter to the CTE using upstream support
320
337
  query.appendWhereExpr('amount', expr => `${expr} > 100`, { upstream: true });
321
338
 
322
- const sql = new Formatter().format(query);
339
+ const sql = new SqlFormatter().format(query).formattedSql;
323
340
  console.log(sql);
324
341
  // => with "temp_sales" as (select "id", "amount", "date" from "sales" where "date" >= '2024-01-01' and "amount" > 100) select * from "temp_sales"
325
342
  ```
@@ -345,7 +362,7 @@ const query = SelectQueryParser.parse(`
345
362
  // Add a filter to all upstream queries that provide 'amount'
346
363
  query.appendWhereExpr('amount', expr => `${expr} > 100`, { upstream: true });
347
364
 
348
- const sql = new Formatter().format(query);
365
+ const sql = new SqlFormatter().format(query).formattedSql;
349
366
  console.log(sql);
350
367
  // => with "sales_transactions" as (select ... where ... and "amount" > 100),
351
368
  // "support_transactions" as (select ... where ... and "fee" > 100)
@@ -388,8 +405,8 @@ A suite of utilities for transforming and analyzing SQL ASTs.
388
405
 
389
406
  ### Main Transformers
390
407
 
391
- - **Formatter**
392
- Converts ASTs to formatted SQL strings. Handles identifier escaping. Output is currently single-line (compact) style.
408
+ - **SqlFormatter**
409
+ Converts ASTs to formatted SQL strings. Handles identifier escaping. Supports both single-line (compact) and multi-line (formatted) styles.
393
410
  - **SelectValueCollector**
394
411
  Extracts all columns, aliases, and expressions from SELECT clauses. Supports wildcard expansion (e.g., `*`, `table.*`) with TableColumnResolver.
395
412
  - **SelectableColumnCollector**
@@ -431,7 +448,7 @@ A suite of utilities for transforming and analyzing SQL ASTs.
431
448
  ## Usage Example
432
449
 
433
450
  ```typescript
434
- import { TableColumnResolver, SelectQueryParser, SelectableColumnCollector, SelectValueCollector, TableSourceCollector, Formatter } from 'rawsql-ts';
451
+ import { TableColumnResolver, SelectQueryParser, SelectableColumnCollector, SelectValueCollector, TableSourceCollector, SqlFormatter } from 'rawsql-ts';
435
452
 
436
453
  // TableColumnResolver example
437
454
  const resolver: TableColumnResolver = (tableName) => {
@@ -442,7 +459,7 @@ const resolver: TableColumnResolver = (tableName) => {
442
459
 
443
460
  const sql = `SELECT u.*, p.title as post_title FROM users u INNER JOIN posts p ON u.user_id = p.user_id`;
444
461
  const query = SelectQueryParser.parse(sql);
445
- const formatter = new Formatter();
462
+ const formatter = new SqlFormatter();
446
463
 
447
464
  // Collects information from the SELECT clause.
448
465
  // To expand wildcards, you must specify a TableColumnResolver.
@@ -451,7 +468,7 @@ const selectValues = selectValueCollector.collect(query);
451
468
  // Log the name and formatted value of each select value
452
469
  console.log('Select values:');
453
470
  selectValues.forEach(val => {
454
- console.log(` name: ${val.name}, value: ${formatter.format(val.value)}`);
471
+ console.log(` name: ${val.name}, value: ${formatter.format(val.value).formattedSql}`);
455
472
  });
456
473
  /*
457
474
  Select values:
@@ -471,7 +488,7 @@ const selectableColumns = selectableColumnCollector.collect(query);
471
488
  // Log detailed info for each selectable column
472
489
  console.log('Selectable columns:');
473
490
  selectableColumns.forEach(val => {
474
- console.log(` name: ${val.name}, value: ${formatter.format(val.value)}`);
491
+ console.log(` name: ${val.name}, value: ${formatter.format(val.value).formattedSql}`);
475
492
  });
476
493
  /*
477
494
  Selectable columns:
@@ -487,16 +504,16 @@ Selectable columns:
487
504
 
488
505
  ```typescript
489
506
  // Create Table from SELECT Example
490
- import { QueryBuilder, SelectQueryParser, Formatter } from 'rawsql-ts';
507
+ import { QueryBuilder, SelectQueryParser, SqlFormatter } from 'rawsql-ts';
491
508
 
492
509
  const select = SelectQueryParser.parse('SELECT id, name FROM users');
493
510
  const create = QueryBuilder.buildCreateTableQuery(select, 'my_table');
494
- const sqlCreate = new Formatter().format(create);
511
+ const sqlCreate = new SqlFormatter().format(create).formattedSql;
495
512
  console.log(sqlCreate);
496
513
  // => create table "my_table" as select "id", "name" from "users"
497
514
 
498
515
  const createTemp = QueryBuilder.buildCreateTableQuery(select, 'tmp_table', true);
499
- const sqlTemp = new Formatter().format(createTemp);
516
+ const sqlTemp = new SqlFormatter().format(createTemp).formattedSql;
500
517
  console.log(sqlTemp);
501
518
  // => create temporary table "tmp_table" as select "id", "name" from "users"
502
519
  ```
@@ -524,7 +541,7 @@ TableSources:
524
541
  This example demonstrates how to join two tables using rawsql-ts. You do not need to understand the internal structure or manage aliases manually. By specifying the join key(s), the ON clause is generated automatically.
525
542
 
526
543
  ```typescript
527
- import { SelectQueryParser, Formatter, SimpleSelectQuery } from 'rawsql-ts';
544
+ import { SelectQueryParser, SqlFormatter, SimpleSelectQuery } from 'rawsql-ts';
528
545
 
529
546
  // Parse the base query
530
547
  const query = SelectQueryParser.parse('SELECT u.user_id, u.name FROM users u') as SimpleSelectQuery;
@@ -535,8 +552,8 @@ query.leftJoinRaw('orders', 'o', ['user_id']);
535
552
  // Add WHERE clause
536
553
  query.appendWhereRaw('o.order_id IS NULL');
537
554
 
538
- const formatter = new Formatter();
539
- const formattedSql = formatter.format(query);
555
+ const formatter = new SqlFormatter();
556
+ const formattedSql = formatter.format(query).formattedSql;
540
557
 
541
558
  console.log(formattedSql);
542
559
  // => select "u"."user_id", "u"."name" from "users" as "u" left join "orders" as "o" on "u"."user_id" = "o"."user_id" where "o"."order_id" is null
@@ -581,39 +598,42 @@ Node.js v22.14.0
581
598
  ### Results
582
599
 
583
600
  #### Tokens20
584
- | Method | Mean | Error | StdDev |
585
- |------------------|----------:|----------:|----------:|
586
- | rawsql-ts | 0.021 ms | 0.0044 ms | 0.0023 ms |
587
- | node-sql-parser | 0.169 ms | 0.0695 ms | 0.0355 ms |
588
- | sql-formatter | 0.208 ms | 0.0556 ms | 0.0284 ms |
601
+ | Method | Mean (ms) | Error (ms) | StdDev (ms) | Times slower vs rawsql-ts |
602
+ |---------------------------------- |-----------:|----------:|----------:|--------------------------:|
603
+ | rawsql-ts | 0.029 | 0.0087 | 0.0044 | - |
604
+ | node-sql-parser | 0.210 | 0.4505 | 0.2298 | 7.3x |
605
+ | sql-formatter | 0.228 | 0.1598 | 0.0815 | 8.0x |
606
+
607
+ > [!Note] When the token count is extremely low, `rawsql-ts` becomes disproportionately fast. However, such small queries are rare in real-world scenarios, so this result is excluded from the overall performance summary.
589
608
 
590
609
  #### Tokens70
591
- | Method | Mean | Error | StdDev |
592
- |------------------|----------:|----------:|----------:|
593
- | rawsql-ts | 0.057 ms | 0.0143 ms | 0.0073 ms |
594
- | node-sql-parser | 0.216 ms | 0.0780 ms | 0.0398 ms |
595
- | sql-formatter | 0.512 ms | 0.1251 ms | 0.0638 ms |
610
+ | Method | Mean (ms) | Error (ms) | StdDev (ms) | Times slower vs rawsql-ts |
611
+ |---------------------------------- |-----------:|----------:|----------:|--------------------------:|
612
+ | rawsql-ts | 0.075 | 0.0541 | 0.0276 | - |
613
+ | node-sql-parser | 0.223 | 0.0848 | 0.0432 | 3.0x |
614
+ | sql-formatter | 0.547 | 0.1432 | 0.0731 | 7.3x |
596
615
 
597
616
  #### Tokens140
598
- | Method | Mean | Error | StdDev |
599
- |------------------|----------:|----------:|----------:|
600
- | rawsql-ts | 0.112 ms | 0.0236 ms | 0.0120 ms |
601
- | node-sql-parser | 0.404 ms | 0.0926 ms | 0.0472 ms |
602
- | sql-formatter | 1.004 ms | 0.3027 ms | 0.1545 ms |
617
+ | Method | Mean (ms) | Error (ms) | StdDev (ms) | Times slower vs rawsql-ts |
618
+ |---------------------------------- |-----------:|----------:|----------:|--------------------------:|
619
+ | rawsql-ts | 0.137 | 0.0175 | 0.0089 | - |
620
+ | node-sql-parser | 0.420 | 0.1030 | 0.0526 | 3.1x |
621
+ | sql-formatter | 1.057 | 0.2390 | 0.1220 | 7.7x |
603
622
 
604
623
  #### Tokens230
605
- | Method | Mean | Error | StdDev |
606
- |------------------|----------:|----------:|----------:|
607
- | rawsql-ts | 0.182 ms | 0.0371 ms | 0.0189 ms |
608
- | node-sql-parser | 0.865 ms | 0.3325 ms | 0.1696 ms |
609
- | sql-formatter | 1.696 ms | 0.2754 ms | 0.1405 ms |
624
+ | Method | Mean (ms) | Error (ms) | StdDev (ms) | Times slower vs rawsql-ts |
625
+ |---------------------------------- |-----------:|----------:|----------:|--------------------------:|
626
+ | rawsql-ts | 0.239 | 0.0577 | 0.0294 | - |
627
+ | node-sql-parser | 0.871 | 0.2042 | 0.1042 | 3.6x |
628
+ | sql-formatter | 1.906 | 1.4631 | 0.7465 | 8.0x |
610
629
 
611
630
  ### Performance Summary
612
631
 
613
- - `rawsql-ts` consistently outperforms both `node-sql-parser` and `sql-formatter` in all tested scenarios.
614
- - Approximately 4x faster than `node-sql-parser`.
615
- - Approximately 910x faster than `sql-formatter`.
616
- - Maintains high performance even with complex SQL while providing comprehensive features.
632
+ - `rawsql-ts` remains one of the fastest parsers, though it is approximately 10% slower in version 0.7 compared to previous versions. This is due to the addition of enhanced parameterized query parsing and SQL formatting capabilities.
633
+ - About 3–4x faster than `node-sql-parser`.
634
+ - About 45x faster than `sql-parser-cst`.
635
+ - About 7–8x faster than `sql-formatter`.
636
+ - Maintains high performance even for complex SQL, while providing comprehensive features.
617
637
 
618
638
  > **Note:** These benchmarks are based on a specific hardware and software environment. Actual performance may vary depending on system configuration and query complexity.
619
639
 
package/dist/esm/index.js CHANGED
@@ -8,6 +8,7 @@ export * from './models/ValuesQuery';
8
8
  export * from './transformers/CTECollector';
9
9
  export * from './transformers/CTENormalizer';
10
10
  export * from './transformers/Formatter';
11
+ export * from './transformers/SqlFormatter';
11
12
  export * from './transformers/QueryBuilder'; // old name:QueryConverter
12
13
  export * from './transformers/SelectValueCollector';
13
14
  export * from './transformers/SelectableColumnCollector';
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,oCAAoC;AACpC,cAAc,6BAA6B,CAAC;AAC5C,cAAc,6BAA6B,CAAC;AAE5C,cAAc,4BAA4B,CAAC;AAC3C,cAAc,sBAAsB,CAAC;AACrC,cAAc,yBAAyB,CAAC;AACxC,cAAc,sBAAsB,CAAC;AAErC,cAAc,6BAA6B,CAAC;AAC5C,cAAc,8BAA8B,CAAC;AAC7C,cAAc,0BAA0B,CAAC;AACzC,cAAc,6BAA6B,CAAC,CAAC,0BAA0B;AACvE,cAAc,qCAAqC,CAAC;AACpD,cAAc,0CAA0C,CAAC;AACzD,cAAc,oCAAoC,CAAC;AACnD,cAAc,qCAAqC,CAAC;AACpD,cAAc,0CAA0C,CAAC;AACzD,oEAAoE"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,oCAAoC;AACpC,cAAc,6BAA6B,CAAC;AAC5C,cAAc,6BAA6B,CAAC;AAE5C,cAAc,4BAA4B,CAAC;AAC3C,cAAc,sBAAsB,CAAC;AACrC,cAAc,yBAAyB,CAAC;AACxC,cAAc,sBAAsB,CAAC;AAErC,cAAc,6BAA6B,CAAC;AAC5C,cAAc,8BAA8B,CAAC;AAC7C,cAAc,0BAA0B,CAAC;AACzC,cAAc,6BAA6B,CAAC;AAC5C,cAAc,6BAA6B,CAAC,CAAC,0BAA0B;AACvE,cAAc,qCAAqC,CAAC;AACpD,cAAc,0CAA0C,CAAC;AACzD,cAAc,oCAAoC,CAAC;AACnD,cAAc,qCAAqC,CAAC;AACpD,cAAc,0CAA0C,CAAC;AACzD,oEAAoE"}