sqlparser-rs 0.60.3 → 0.60.4

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/README.md CHANGED
@@ -2,8 +2,6 @@
2
2
 
3
3
  [![npm version](https://img.shields.io/npm/v/sqlparser-rs.svg)](https://www.npmjs.com/package/sqlparser-rs)
4
4
  [![License](https://img.shields.io/badge/license-Apache--2.0-blue.svg)](LICENSE)
5
- [![TypeScript](https://img.shields.io/badge/TypeScript-5.0+-blue.svg)](https://www.typescriptlang.org/)
6
- [![Node.js](https://img.shields.io/badge/Node.js-16+-green.svg)](https://nodejs.org/)
7
5
  [![WebAssembly](https://img.shields.io/badge/WebAssembly-powered-blueviolet.svg)](https://webassembly.org/)
8
6
  [![sqlparser](https://img.shields.io/badge/sqlparser--rs-v0.60.0-orange.svg)](https://github.com/apache/datafusion-sqlparser-rs)
9
7
 
@@ -11,11 +9,11 @@ A SQL parser for JavaScript and TypeScript, powered by [datafusion-sqlparser-rs]
11
9
 
12
10
  ## Features
13
11
 
14
- - Parse SQL into a detailed Abstract Syntax Tree (AST)
15
- - Support for 13+ SQL dialects (PostgreSQL, MySQL, SQLite, BigQuery, etc.)
16
- - Full TypeScript type definitions
17
- - Fast and accurate parsing using the battle-tested Rust implementation
18
- - Zero native dependencies
12
+ - Parse SQL into a detailed AST with full TypeScript types
13
+ - Support 14 SQL dialects (PostgreSQL, MySQL, SQLite, BigQuery, and more)
14
+ - Run in Node.js and browsers
15
+ - Stay small (~600KB gzipped) and fast (Rust + WebAssembly)
16
+ - Ship zero native dependencies
19
17
 
20
18
  ## Installation
21
19
 
@@ -23,187 +21,59 @@ A SQL parser for JavaScript and TypeScript, powered by [datafusion-sqlparser-rs]
23
21
  npm install sqlparser-rs
24
22
  ```
25
23
 
26
- ## Quick Start
24
+ ## Usage
27
25
 
28
26
  ```typescript
29
- import { Parser, GenericDialect, PostgreSqlDialect } from 'sqlparser-rs';
27
+ import { parse, format, validate } from 'sqlparser-rs';
30
28
 
31
- // Simple parsing
32
- const statements = Parser.parse('SELECT * FROM users', new GenericDialect());
33
- console.log(statements);
29
+ // Parse SQL into AST
30
+ const ast = parse('SELECT * FROM users');
34
31
 
35
32
  // With specific dialect
36
- const pgStatements = Parser.parse(
37
- 'SELECT * FROM users WHERE id = $1',
38
- new PostgreSqlDialect()
39
- );
33
+ const ast = parse('SELECT * FROM users WHERE id = $1', 'postgresql');
40
34
 
41
35
  // Format SQL
42
- const formatted = Parser.format('select * from users', new GenericDialect());
43
- console.log(formatted); // "SELECT * FROM users"
36
+ const sql = format('select * from users');
37
+ // "SELECT * FROM users"
44
38
 
45
- // Validate SQL
46
- try {
47
- Parser.validate('SELEC * FROM users', new GenericDialect());
48
- } catch (error) {
49
- console.log('Invalid SQL:', error.message);
50
- }
39
+ // Validate SQL (throws on invalid)
40
+ validate('SELECT * FROM users'); // ok
51
41
  ```
52
42
 
53
- ## API
54
-
55
- ### Parser
56
-
57
- The main class for parsing SQL.
58
-
59
- #### Static Methods
43
+ ### Working with AST
60
44
 
61
45
  ```typescript
62
- // Parse SQL into statements
63
- const statements = Parser.parse(sql: string, dialect: Dialect): Statement[];
64
-
65
- // Parse and return JSON string
66
- const json = Parser.parseToJson(sql: string, dialect: Dialect): string;
67
-
68
- // Parse and return formatted SQL string
69
- const formatted = Parser.parseToString(sql: string, dialect: Dialect): string;
70
-
71
- // Format SQL (round-trip through parser)
72
- const formatted = Parser.format(sql: string, dialect: Dialect): string;
73
-
74
- // Validate SQL syntax
75
- const isValid = Parser.validate(sql: string, dialect: Dialect): boolean;
76
-
77
- // Get list of supported dialects
78
- const dialects = Parser.getSupportedDialects(): string[];
79
- ```
80
-
81
- #### Instance Methods (Builder Pattern)
82
-
83
- ```typescript
84
- import { Parser, PostgreSqlDialect } from 'sqlparser-rs';
85
-
86
- const parser = new Parser(new PostgreSqlDialect())
87
- .withRecursionLimit(50) // Set max recursion depth
88
- .withOptions({ // Set parser options
89
- trailingCommas: true
90
- });
91
-
92
- const statements = parser.parse('SELECT * FROM users');
93
- ```
94
-
95
- ### Dialects
96
-
97
- All dialects from the upstream Rust crate are supported:
98
-
99
- ```typescript
100
- import {
101
- GenericDialect, // Permissive, accepts most SQL syntax
102
- AnsiDialect, // ANSI SQL standard
103
- MySqlDialect, // MySQL
104
- PostgreSqlDialect, // PostgreSQL
105
- SQLiteDialect, // SQLite
106
- SnowflakeDialect, // Snowflake
107
- RedshiftDialect, // Amazon Redshift
108
- MsSqlDialect, // Microsoft SQL Server
109
- ClickHouseDialect, // ClickHouse
110
- BigQueryDialect, // Google BigQuery
111
- DuckDbDialect, // DuckDB
112
- DatabricksDialect, // Databricks
113
- HiveDialect, // Apache Hive
114
- } from 'sqlparser-rs';
115
-
116
- // Create dialect from string
117
- import { dialectFromString } from 'sqlparser-rs';
118
- const dialect = dialectFromString('postgresql'); // Returns PostgreSqlDialect instance
46
+ // Parse and inspect
47
+ const ast = parse('SELECT id, name FROM users WHERE active = true');
48
+ console.log(JSON.stringify(ast, null, 2));
49
+
50
+ // Multiple statements
51
+ const statements = parse(`
52
+ SELECT * FROM users;
53
+ SELECT * FROM orders;
54
+ `);
55
+ console.log(statements.length); // 2
56
+
57
+ // Modify AST and convert back to SQL
58
+ const ast = parse('SELECT * FROM users')[0];
59
+ // ... modify ast ...
60
+ const sql = format(JSON.stringify([ast]));
119
61
  ```
120
62
 
121
63
  ### Error Handling
122
64
 
123
65
  ```typescript
124
- import { Parser, GenericDialect, ParserError } from 'sqlparser-rs';
125
-
126
66
  try {
127
- Parser.parse('SELEC * FROM users', new GenericDialect());
128
- } catch (error) {
129
- if (error instanceof ParserError) {
130
- console.log('Parse error:', error.message);
131
- if (error.location) {
132
- console.log(`At line ${error.location.line}, column ${error.location.column}`);
133
- }
134
- }
135
- }
136
- ```
137
-
138
- ### AST Types
139
-
140
- Full TypeScript types are provided for the AST:
141
-
142
- ```typescript
143
- import type { Statement, Query, Expr, Ident, ObjectName } from 'sqlparser-rs';
144
-
145
- const statements: Statement[] = Parser.parse('SELECT 1', new GenericDialect());
146
-
147
- // Statement is a discriminated union type
148
- for (const stmt of statements) {
149
- if ('Query' in stmt) {
150
- const query: Query = stmt.Query;
151
- console.log('Found SELECT query');
152
- } else if ('Insert' in stmt) {
153
- console.log('Found INSERT statement');
154
- }
67
+ parse('SELEC * FORM users');
68
+ } catch (e) {
69
+ console.error(e.message); // Parse error details
155
70
  }
156
71
  ```
157
72
 
158
- ## Development
159
-
160
- ### Prerequisites
73
+ ## Supported Dialects
161
74
 
162
- - Rust toolchain (1.70+)
163
- - wasm-pack (`cargo install wasm-pack`)
164
- - Node.js (16+)
165
-
166
- ### Build
167
-
168
- ```bash
169
- # Build everything
170
- ./scripts/build.sh
171
-
172
- # Or step by step:
173
- # 1. Build WASM
174
- wasm-pack build --target nodejs --out-dir ts/wasm
175
-
176
- # 2. Build TypeScript
177
- cd ts
178
- npm install
179
- npm run build
180
- ```
181
-
182
- ### Tests
183
-
184
- ```bash
185
- cd ts
186
- npm test
187
- ```
188
-
189
- ## Versioning
190
-
191
- This package follows the upstream [sqlparser-rs](https://github.com/apache/datafusion-sqlparser-rs) version:
192
-
193
- - **Major.Minor** matches the upstream Rust crate version
194
- - **Patch** is for TypeScript binding fixes (e.g., `0.60.3` = upstream `0.60.0` + binding fix)
195
-
196
- | This package | sqlparser-rs |
197
- |--------------|--------------|
198
- | 0.60.x | 0.60.0 |
199
-
200
- This approach is similar to [esbuild-wasm](https://github.com/evanw/esbuild) and [duckdb-wasm](https://github.com/duckdb/duckdb-wasm).
75
+ `generic`, `ansi`, `mysql`, `postgresql`, `sqlite`, `snowflake`, `redshift`, `mssql`, `clickhouse`, `bigquery`, `duckdb`, `databricks`, `hive`, `oracle`
201
76
 
202
77
  ## License
203
78
 
204
79
  Apache-2.0
205
-
206
- ## Related Projects
207
-
208
- - [datafusion-sqlparser-rs](https://github.com/apache/datafusion-sqlparser-rs) - The Rust SQL parser this package wraps
209
- - [Apache DataFusion](https://github.com/apache/datafusion) - Query execution framework using sqlparser-rs
package/dist/index.cjs CHANGED
@@ -1,6 +1,3 @@
1
- let node_module = require("node:module");
2
- let node_url = require("node:url");
3
- let node_path = require("node:path");
4
1
 
5
2
  //#region src/dialects.ts
6
3
  /**
@@ -153,20 +150,7 @@ const DIALECT_MAP = {
153
150
  hive: HiveDialect,
154
151
  oracle: OracleDialect
155
152
  };
156
- /**
157
- * Create a dialect instance from a string name
158
- *
159
- * @param name - The name of the dialect (case-insensitive)
160
- * @returns A dialect instance, or undefined if the dialect is not recognized
161
- *
162
- * @example
163
- * ```typescript
164
- * const dialect = dialectFromString('postgresql');
165
- * if (dialect) {
166
- * const ast = Parser.parse('SELECT 1', dialect);
167
- * }
168
- * ```
169
- */
153
+ /** Create a dialect instance from a string name (case-insensitive) */
170
154
  function dialectFromString(name) {
171
155
  const normalized = name.toLowerCase();
172
156
  const DialectClass = DIALECT_MAP[{
@@ -217,64 +201,96 @@ var WasmInitError = class WasmInitError extends Error {
217
201
  };
218
202
 
219
203
  //#endregion
220
- //#region src/parser.ts
204
+ //#region src/wasm.ts
221
205
  let wasmModule = null;
206
+ let initPromise = null;
207
+ let initStarted = false;
208
+ const isBrowser = typeof window !== "undefined" && typeof process === "undefined";
209
+ function startInit() {
210
+ if (initStarted) return;
211
+ initStarted = true;
212
+ initPromise = initWasm().catch(() => {});
213
+ }
214
+ startInit();
215
+ /** Get initialized WASM module or throw */
222
216
  function getWasmModule() {
223
217
  if (wasmModule) return wasmModule;
218
+ throw new WasmInitError("WASM module not yet initialized. Use the async import or wait for module to load: import(\"sqlparser-rs\").then(({ parse }) => parse(sql))");
219
+ }
220
+ /**
221
+ * Wait for WASM module to be ready
222
+ */
223
+ async function ready() {
224
+ startInit();
225
+ await initPromise;
226
+ }
227
+ /**
228
+ * Initialize the WASM module explicitly.
229
+ * Usually not needed - the module auto-initializes on first use.
230
+ */
231
+ async function initWasm() {
232
+ if (wasmModule) return;
233
+ if (isBrowser) {
234
+ try {
235
+ const wasmJsUrl = new URL("../wasm/sqlparser_rs_wasm_web.js", require("url").pathToFileURL(__filename).href);
236
+ const wasmBinaryUrl = new URL("../wasm/sqlparser_rs_wasm_web_bg.wasm", require("url").pathToFileURL(__filename).href);
237
+ const wasm = await import(
238
+ /* @vite-ignore */
239
+ wasmJsUrl.href
240
+ );
241
+ if (typeof wasm.default === "function") await wasm.default({ module_or_path: wasmBinaryUrl });
242
+ wasmModule = wasm;
243
+ } catch (error) {
244
+ throw new WasmInitError(`Failed to load WASM module in browser: ${error instanceof Error ? error.message : String(error)}`);
245
+ }
246
+ return;
247
+ }
224
248
  try {
225
- const wasmPath = (0, node_path.join)((0, node_path.dirname)((0, node_url.fileURLToPath)(require("url").pathToFileURL(__filename).href)), "../wasm/sqlparser_rs_wasm.js");
226
- wasmModule = (0, node_module.createRequire)(require("url").pathToFileURL(__filename).href)(wasmPath);
227
- return wasmModule;
249
+ wasmModule = await import(
250
+ /* @vite-ignore */
251
+ new URL("../wasm/sqlparser_rs_wasm.js", require("url").pathToFileURL(__filename).href).href
252
+ );
228
253
  } catch (error) {
229
254
  throw new WasmInitError(`Failed to load WASM module: ${error instanceof Error ? error.message : String(error)}`);
230
255
  }
231
256
  }
257
+
258
+ //#endregion
259
+ //#region src/parser.ts
260
+ function resolveDialect(dialect = "generic") {
261
+ if (typeof dialect === "string") {
262
+ const resolved = dialectFromString(dialect);
263
+ if (!resolved) throw new Error(`Unknown dialect: ${dialect}`);
264
+ return resolved;
265
+ }
266
+ return dialect;
267
+ }
232
268
  /**
233
- * SQL Parser
234
- *
235
- * Parses SQL statements into an Abstract Syntax Tree (AST).
269
+ * SQL Parser - parses SQL statements into AST
236
270
  *
237
271
  * @example
238
272
  * ```typescript
239
273
  * import { Parser, PostgreSqlDialect } from 'sqlparser-rs';
240
274
  *
241
- * // Simple parsing
242
- * const statements = Parser.parse('SELECT * FROM users', new PostgreSqlDialect());
275
+ * const statements = Parser.parse('SELECT * FROM users', 'postgresql');
243
276
  *
244
- * // With builder pattern
277
+ * // With options
245
278
  * const parser = new Parser(new PostgreSqlDialect())
246
- * .withRecursionLimit(50)
247
279
  * .withOptions({ trailingCommas: true });
248
- *
249
- * const ast = parser.parse('SELECT * FROM users');
280
+ * const ast = parser.parse('SELECT a, b, FROM users');
250
281
  * ```
251
282
  */
252
283
  var Parser = class Parser {
253
- /**
254
- * Create a new parser instance
255
- *
256
- * @param dialect - The SQL dialect to use (defaults to GenericDialect)
257
- */
258
284
  constructor(dialect = new GenericDialect()) {
259
285
  this.dialect = dialect;
260
286
  this.options = {};
261
287
  }
262
- /**
263
- * Set the recursion limit for parsing nested expressions
264
- *
265
- * @param limit - Maximum recursion depth
266
- * @returns This parser instance for chaining
267
- */
288
+ /** Set recursion limit for parsing nested expressions */
268
289
  withRecursionLimit(limit) {
269
290
  this.options.recursionLimit = limit;
270
291
  return this;
271
292
  }
272
- /**
273
- * Set parser options
274
- *
275
- * @param options - Parser options
276
- * @returns This parser instance for chaining
277
- */
293
+ /** Set parser options */
278
294
  withOptions(options) {
279
295
  this.options = {
280
296
  ...this.options,
@@ -282,103 +298,83 @@ var Parser = class Parser {
282
298
  };
283
299
  return this;
284
300
  }
285
- /**
286
- * Parse SQL statements
287
- *
288
- * @param sql - SQL string to parse
289
- * @returns Array of parsed statements
290
- */
301
+ /** Parse SQL statements */
291
302
  parse(sql) {
292
303
  const wasm = getWasmModule();
293
304
  try {
294
305
  if (Object.keys(this.options).length > 0) return wasm.parse_sql_with_options(this.dialect.name, sql, this.options);
295
- else return wasm.parse_sql(this.dialect.name, sql);
306
+ return wasm.parse_sql(this.dialect.name, sql);
296
307
  } catch (error) {
297
308
  throw ParserError.fromWasmError(error);
298
309
  }
299
310
  }
300
- /**
301
- * Parse SQL statements
302
- *
303
- * @param sql - SQL string to parse
304
- * @param dialect - SQL dialect to use
305
- * @returns Array of parsed statements
306
- *
307
- * @example
308
- * ```typescript
309
- * const statements = Parser.parse('SELECT 1', new GenericDialect());
310
- * ```
311
- */
312
- static parse(sql, dialect = new GenericDialect()) {
313
- return new Parser(dialect).parse(sql);
311
+ /** Parse SQL into AST */
312
+ static parse(sql, dialect = "generic") {
313
+ return new Parser(resolveDialect(dialect)).parse(sql);
314
314
  }
315
- /**
316
- * Parse SQL and return the AST as a JSON string
317
- *
318
- * @param sql - SQL string to parse
319
- * @param dialect - SQL dialect to use
320
- * @returns JSON string representation of the AST
321
- */
322
- static parseToJson(sql, dialect = new GenericDialect()) {
315
+ /** Parse SQL and return AST as JSON string */
316
+ static parseToJson(sql, dialect = "generic") {
323
317
  const wasm = getWasmModule();
324
318
  try {
325
- return wasm.parse_sql_to_json_string(dialect.name, sql);
319
+ return wasm.parse_sql_to_json_string(resolveDialect(dialect).name, sql);
326
320
  } catch (error) {
327
321
  throw ParserError.fromWasmError(error);
328
322
  }
329
323
  }
330
- /**
331
- * Parse SQL and return a formatted string representation
332
- *
333
- * @param sql - SQL string to parse
334
- * @param dialect - SQL dialect to use
335
- * @returns String representation of the parsed SQL
336
- */
337
- static parseToString(sql, dialect = new GenericDialect()) {
324
+ /** Parse SQL and return formatted string representation */
325
+ static parseToString(sql, dialect = "generic") {
338
326
  const wasm = getWasmModule();
339
327
  try {
340
- return wasm.parse_sql_to_string(dialect.name, sql);
328
+ return wasm.parse_sql_to_string(resolveDialect(dialect).name, sql);
341
329
  } catch (error) {
342
330
  throw ParserError.fromWasmError(error);
343
331
  }
344
332
  }
345
- /**
346
- * Format SQL by parsing and regenerating it (round-trip)
347
- *
348
- * @param sql - SQL string to format
349
- * @param dialect - SQL dialect to use
350
- * @returns Formatted SQL string
351
- */
352
- static format(sql, dialect = new GenericDialect()) {
333
+ /** Format SQL by parsing and regenerating it */
334
+ static format(sql, dialect = "generic") {
353
335
  const wasm = getWasmModule();
354
336
  try {
355
- return wasm.format_sql(dialect.name, sql);
337
+ return wasm.format_sql(resolveDialect(dialect).name, sql);
356
338
  } catch (error) {
357
339
  throw ParserError.fromWasmError(error);
358
340
  }
359
341
  }
360
342
  /**
361
- * Validate SQL syntax without returning the full AST
362
- *
363
- * @param sql - SQL string to validate
364
- * @param dialect - SQL dialect to use
365
- * @returns true if valid, throws ParserError if invalid
343
+ * Validate SQL syntax
344
+ * @throws ParserError if SQL is invalid
366
345
  */
367
- static validate(sql, dialect = new GenericDialect()) {
346
+ static validate(sql, dialect = "generic") {
368
347
  const wasm = getWasmModule();
369
348
  try {
370
- return wasm.validate_sql(dialect.name, sql);
349
+ return wasm.validate_sql(resolveDialect(dialect).name, sql);
371
350
  } catch (error) {
372
351
  throw ParserError.fromWasmError(error);
373
352
  }
374
353
  }
375
- /**
376
- * Get the list of supported dialect names
377
- */
354
+ /** Get list of supported dialect names */
378
355
  static getSupportedDialects() {
379
356
  return getWasmModule().get_supported_dialects();
380
357
  }
381
358
  };
359
+ /**
360
+ * Parse SQL into AST
361
+ */
362
+ function parse(sql, dialect = "generic") {
363
+ return Parser.parse(sql, dialect);
364
+ }
365
+ /**
366
+ * Validate SQL syntax
367
+ * @throws ParserError if SQL is invalid
368
+ */
369
+ function validate(sql, dialect = "generic") {
370
+ return Parser.validate(sql, dialect);
371
+ }
372
+ /**
373
+ * Format SQL by parsing and regenerating it
374
+ */
375
+ function format(sql, dialect = "generic") {
376
+ return Parser.format(sql, dialect);
377
+ }
382
378
 
383
379
  //#endregion
384
380
  exports.AnsiDialect = AnsiDialect;
@@ -399,4 +395,9 @@ exports.SQLiteDialect = SQLiteDialect;
399
395
  exports.SUPPORTED_DIALECTS = SUPPORTED_DIALECTS;
400
396
  exports.SnowflakeDialect = SnowflakeDialect;
401
397
  exports.WasmInitError = WasmInitError;
402
- exports.dialectFromString = dialectFromString;
398
+ exports.dialectFromString = dialectFromString;
399
+ exports.format = format;
400
+ exports.initWasm = initWasm;
401
+ exports.parse = parse;
402
+ exports.ready = ready;
403
+ exports.validate = validate;