# sqlparser-rs

[![npm version](https://img.shields.io/npm/v/sqlparser-rs.svg)](https://www.npmjs.com/package/sqlparser-rs)
[![License](https://img.shields.io/badge/license-Apache--2.0-blue.svg)](LICENSE)
[![TypeScript](https://img.shields.io/badge/TypeScript-5.0+-blue.svg)](https://www.typescriptlang.org/)
[![Node.js](https://img.shields.io/badge/Node.js-16+-green.svg)](https://nodejs.org/)
[![WebAssembly](https://img.shields.io/badge/WebAssembly-powered-blueviolet.svg)](https://webassembly.org/)
[![sqlparser](https://img.shields.io/badge/sqlparser--rs-v0.60.0-orange.svg)](https://github.com/apache/datafusion-sqlparser-rs)

A SQL parser for JavaScript and TypeScript, powered by [datafusion-sqlparser-rs](https://github.com/apache/datafusion-sqlparser-rs) via WebAssembly.

## Features

- Parse SQL into a detailed Abstract Syntax Tree (AST)
- Support for 13+ SQL dialects (PostgreSQL, MySQL, SQLite, BigQuery, etc.)
- Full TypeScript type definitions
- Fast and accurate parsing using the battle-tested Rust implementation
- Zero native dependencies

## Installation

```bash
npm install sqlparser-rs
```

## Quick Start

```typescript
import { parse, format, validate } from 'sqlparser-rs';

// Simple parsing (uses generic dialect by default)
const statements = parse('SELECT * FROM users');
console.log(statements);

// With specific dialect (string name)
const pgStatements = parse('SELECT * FROM users WHERE id = $1', 'postgresql');

// Format SQL
const formatted = format('select   *   from   users');
console.log(formatted); // "SELECT * FROM users"

// Validate SQL
try {
  validate('SELEC * FROM users');
} catch (error) {
  console.log('Invalid SQL:', error.message);
}
```

## API

### Top-Level Functions

The simplest way to use the parser:

```typescript
import { parse, format, validate } from 'sqlparser-rs';

// Parse SQL - dialect defaults to 'generic'
parse('SELECT * FROM users');
parse('SELECT * FROM users', 'postgresql');
parse('SELECT * FROM users', 'mysql');

// Format SQL (round-trip through parser)
format('select * from users');  // "SELECT * FROM users"

// Validate SQL syntax (throws ParserError if invalid)
validate('SELECT * FROM users');  // true
```

### Dialect Options

Dialects can be specified as strings or class instances:

```typescript
import { parse, PostgreSqlDialect } from 'sqlparser-rs';

// String dialect names (recommended)
parse('SELECT $1', 'postgresql');
parse('SELECT `col` FROM t', 'mysql');

// Or dialect instances
parse('SELECT $1', new PostgreSqlDialect());
```

Supported dialect strings: `'generic'`, `'ansi'`, `'mysql'`, `'postgresql'`, `'sqlite'`, `'snowflake'`, `'redshift'`, `'mssql'`, `'clickhouse'`, `'bigquery'`, `'duckdb'`, `'databricks'`, `'hive'`, `'oracle'`

### Parser Class

For advanced use cases with options:

```typescript
import { Parser, PostgreSqlDialect } from 'sqlparser-rs';

// Static methods (same as top-level functions)
Parser.parse('SELECT 1');
Parser.parse('SELECT 1', 'postgresql');
Parser.format('select 1');
Parser.validate('SELECT 1');
Parser.parseToJson('SELECT 1');      // Returns JSON string
Parser.parseToString('SELECT 1');    // Returns formatted string
Parser.getSupportedDialects();       // Returns dialect names

// Builder pattern for custom options
const parser = new Parser(new PostgreSqlDialect())
  .withRecursionLimit(50)
  .withOptions({ trailingCommas: true });

const statements = parser.parse('SELECT * FROM users');
```

### WASM Initialization

The WASM module auto-initializes on import. For most use cases, no action is needed.

If you need to ensure WASM is ready before calling sync APIs (e.g., in tests):

```typescript
import { ready, parse } from 'sqlparser-rs';

// Wait for WASM to be ready
await ready();

// Now sync APIs are guaranteed to work
const ast = parse('SELECT 1');
```

### Dialects

All dialects from the upstream Rust crate are supported. You can use string names directly with `parse()`, `format()`, and `validate()`:

```typescript
// String names (recommended)
parse('SELECT 1', 'postgresql');
parse('SELECT 1', 'mysql');
parse('SELECT 1', 'bigquery');

// Or import dialect classes for type safety
import {
  GenericDialect,      // Permissive, accepts most SQL syntax
  AnsiDialect,         // ANSI SQL standard
  MySqlDialect,        // MySQL
  PostgreSqlDialect,   // PostgreSQL
  SQLiteDialect,       // SQLite
  SnowflakeDialect,    // Snowflake
  RedshiftDialect,     // Amazon Redshift
  MsSqlDialect,        // Microsoft SQL Server
  ClickHouseDialect,   // ClickHouse
  BigQueryDialect,     // Google BigQuery
  DuckDbDialect,       // DuckDB
  DatabricksDialect,   // Databricks
  HiveDialect,         // Apache Hive
  OracleDialect,       // Oracle
} from 'sqlparser-rs';

// Create dialect from string programmatically
import { dialectFromString } from 'sqlparser-rs';
const dialect = dialectFromString('postgresql'); // Returns PostgreSqlDialect instance
```

### Error Handling

```typescript
import { parse, ParserError } from 'sqlparser-rs';

try {
  parse('SELEC * FROM users');
} catch (error) {
  if (error instanceof ParserError) {
    console.log('Parse error:', error.message);
    if (error.location) {
      console.log(`At line ${error.location.line}, column ${error.location.column}`);
    }
  }
}
```

### AST Types

Full TypeScript types are provided for the AST:

```typescript
import { parse } from 'sqlparser-rs';
import type { Statement, Query } from 'sqlparser-rs';

const statements: Statement[] = parse('SELECT 1');

// Statement is a discriminated union type
for (const stmt of statements) {
  if ('Query' in stmt) {
    const query: Query = stmt.Query;
    console.log('Found SELECT query');
  } else if ('Insert' in stmt) {
    console.log('Found INSERT statement');
  }
}
```

## Bundler Configuration

### Vite

Exclude `sqlparser-rs` from dependency optimization to ensure WASM files load correctly:

```typescript
// vite.config.ts
export default defineConfig({
  optimizeDeps: {
    exclude: ["sqlparser-rs"],
  },
});
```

This is required because Vite's pre-bundling breaks the WASM file path resolution.

## Development

### Prerequisites

- Rust toolchain (1.70+)
- wasm-pack (`cargo install wasm-pack`)
- Node.js (16+)

### Build

```bash
# Build everything
./scripts/build.sh

# Or step by step:
# 1. Build WASM
wasm-pack build --target nodejs --out-dir ts/wasm

# 2. Build TypeScript
cd ts
npm install
npm run build
```

### Tests

```bash
cd ts
npm test
```

## Versioning

This package follows the upstream [sqlparser-rs](https://github.com/apache/datafusion-sqlparser-rs) version:

- **Major.Minor** matches the upstream Rust crate version
- **Patch** is for TypeScript binding fixes (e.g., `0.60.3-rc4` = upstream `0.60.0` + binding fix)

| This package | sqlparser-rs |
|--------------|--------------|
| 0.60.x       | 0.60.0       |

This approach is similar to [esbuild-wasm](https://github.com/evanw/esbuild) and [duckdb-wasm](https://github.com/duckdb/duckdb-wasm).

## License

Apache-2.0

## Related Projects

- [datafusion-sqlparser-rs](https://github.com/apache/datafusion-sqlparser-rs) - The Rust SQL parser this package wraps
- [Apache DataFusion](https://github.com/apache/datafusion) - Query execution framework using sqlparser-rs
