Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
137 changes: 137 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -124,3 +124,140 @@ jobs:
- name: Run Tests 🔍
run: pnpm run test
working-directory: ${{ matrix.package.path }}

build-parser:
name: Build Parser Package 📦
needs: build-wasm
runs-on: ubuntu-latest
steps:
- name: Checkout Repository 📥
uses: actions/checkout@v4

- name: Setup Node.js 🌐
uses: actions/setup-node@v4
with:
node-version: '20.x'

- name: Setup pnpm 📦
uses: pnpm/action-setup@v2
with:
version: 8.15.1

- name: Get pnpm store directory 📁
shell: bash
run: |
echo "STORE_PATH=$(pnpm store path --silent)" >> $GITHUB_ENV

- name: Setup pnpm cache 🗄️
uses: actions/cache@v3
with:
path: ${{ env.STORE_PATH }}
key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }}
restore-keys: |
${{ runner.os }}-pnpm-store-

- name: Install Dependencies 🧶
run: pnpm install

- name: Install Parser Dependencies 📦
run: pnpm install
working-directory: parser

- name: Download v15 WASM Artifacts 📥
uses: actions/download-artifact@v4
with:
name: wasm-artifacts-v15
path: versions/15/wasm/

- name: Download v16 WASM Artifacts 📥
uses: actions/download-artifact@v4
with:
name: wasm-artifacts-v16
path: versions/16/wasm/

- name: Download v17 WASM Artifacts 📥
uses: actions/download-artifact@v4
with:
name: wasm-artifacts-v17
path: versions/17/wasm/

- name: Build Parser 🏗
run: pnpm run build
working-directory: parser

- name: Upload Parser Artifacts 📦
uses: actions/upload-artifact@v4
with:
name: parser-artifacts
path: parser/wasm/
retention-days: 1

test-parser:
name: Test Parser on ${{ matrix.os }} ${{ matrix.os == 'ubuntu-latest' && '🐧' || matrix.os == 'macos-latest' && '🍎' || '🪟' }}
needs: build-parser
strategy:
matrix:
os: [ubuntu-latest, macos-latest, windows-latest]
fail-fast: false
runs-on: ${{ matrix.os }}
steps:
- name: Checkout Repository 📥
uses: actions/checkout@v4

- name: Setup Node.js 🌐
uses: actions/setup-node@v4
with:
node-version: '20.x'

- name: Setup pnpm 📦
uses: pnpm/action-setup@v2
with:
version: 8.15.1

- name: Get pnpm store directory 📁
shell: bash
run: |
echo "STORE_PATH=$(pnpm store path --silent)" >> $GITHUB_ENV

- name: Setup pnpm cache 🗄️
uses: actions/cache@v3
with:
path: ${{ env.STORE_PATH }}
key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }}
restore-keys: |
${{ runner.os }}-pnpm-store-

- name: Install Dependencies 🧶
run: pnpm install

- name: Install Parser Dependencies 📦
run: pnpm install
working-directory: parser

- name: Download v15 WASM Artifacts 📥
uses: actions/download-artifact@v4
with:
name: wasm-artifacts-v15
path: versions/15/wasm/

- name: Download v16 WASM Artifacts 📥
uses: actions/download-artifact@v4
with:
name: wasm-artifacts-v16
path: versions/16/wasm/

- name: Download v17 WASM Artifacts 📥
uses: actions/download-artifact@v4
with:
name: wasm-artifacts-v17
path: versions/17/wasm/

- name: Download Parser Artifacts 📥
uses: actions/download-artifact@v4
with:
name: parser-artifacts
path: parser/wasm/

- name: Run Parser Tests 🔍
run: pnpm run test
working-directory: parser
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# libpg-query

<p align="center" width="100%">
<img src="https://github.com/launchql/libpg-query-node/assets/545047/5fd420cc-cdc6-4211-9b0f-0eca8321ba72" alt="webincubator" width="100">
<img src="https://github.com/launchql/libpg-query-node/assets/545047/5fd420cc-cdc6-4211-9b0f-0eca8321ba72" alt="hyperweb.io" width="100">
</p>

<p align="center" width="100%">
Expand Down Expand Up @@ -30,7 +30,7 @@ Built to power [pgsql-parser](https://github.com/pyramation/pgsql-parser), this
* 🌐 **Node.js & Browser Support** – Consistent behavior in any JS environment
* 📦 **No Native Builds Required** – No compilation, no system-specific dependencies
* 🧠 **Spec-Accurate Parsing** – Produces faithful, standards-compliant ASTs
* 🚀 **Production-Grade** – Millions of downloads powering 1000s of projects
* 🚀 **Production-Grade** – Millions of downloads and trusted by countless projects and top teams

## 🚀 For Round-trip Codegen

Expand Down
4 changes: 2 additions & 2 deletions full/README.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# @libpg-query/parser

<p align="center" width="100%">
<img src="https://github.com/launchql/libpg-query-node/assets/545047/5fd420cc-cdc6-4211-9b0f-0eca8321ba72" alt="webincubator" width="100">
<img src="https://github.com/launchql/libpg-query-node/assets/545047/5fd420cc-cdc6-4211-9b0f-0eca8321ba72" alt="hyperweb.io" width="100">
</p>

<p align="center" width="100%">
Expand Down Expand Up @@ -30,7 +30,7 @@ Built to power [pgsql-parser](https://github.com/pyramation/pgsql-parser), this
* 🌐 **Node.js & Browser Support** – Consistent behavior in any JS environment
* 📦 **No Native Builds Required** – No compilation, no system-specific dependencies
* 🧠 **Spec-Accurate Parsing** – Produces faithful, standards-compliant ASTs
* 🚀 **Production-Grade** – Millions of downloads powering 1000s of projects
* 🚀 **Production-Grade** – Millions of downloads and trusted by countless projects and top teams

## 🚀 For Round-trip Codegen

Expand Down
5 changes: 4 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,10 @@
"publish:types": "node scripts/publish-types.js",
"publish:enums": "node scripts/publish-enums.js",
"publish:versions": "node scripts/publish-versions.js",
"update:versions-types": "node scripts/update-versions-types.js"
"update:versions-types": "node scripts/update-versions-types.js",
"build:parser": "pnpm --filter @pgsql/parser build",
"test:parser": "pnpm --filter @pgsql/parser test",
"publish:parser": "pnpm --filter @pgsql/parser publish"
},
"devDependencies": {
"@types/node": "^20.0.0",
Expand Down
10 changes: 10 additions & 0 deletions parser/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
node_modules/
dist/
dist-esm/
*.log
.DS_Store
src/wasm/*.wasm
src/wasm/*.js
src/types/15/
src/types/16/
src/types/17/
42 changes: 42 additions & 0 deletions parser/Makefile.shared
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
# Shared Makefile for building PostgreSQL parser WASM
VERSION ?= 17
TAG_15 = 15-4.2.4
TAG_16 = 16-5.2.0
TAG_17 = 17-6.1.0
TAG = $(TAG_$(VERSION))

# Emscripten flags
EMCC_CFLAGS = -O3 -flto -s WASM=1 -s TOTAL_MEMORY=16777216 \
-s EXPORTED_FUNCTIONS="['_parse_sql']" \
-s EXPORTED_RUNTIME_METHODS="['ccall','cwrap']" \
-s MODULARIZE=1 \
-s EXPORT_NAME="LibPGQuery$(VERSION)"

.PHONY: all
all: clean download build-wasm

.PHONY: download
download:
@echo "Downloading libpg_query $(TAG)..."
curl -L "https://github.com/pganalyze/libpg_query/archive/refs/tags/$(TAG).tar.gz" | tar -xz
mv libpg_query-$(TAG) libpg_query

.PHONY: build-wasm
build-wasm:
@echo "Building WASM for PostgreSQL $(VERSION)..."
cd libpg_query && make build_shared
emcc $(EMCC_CFLAGS) \
-I./libpg_query \
./wasm_wrapper.c \
./libpg_query/libpg_query.a \
-o libpg-query.js

.PHONY: clean
clean:
rm -rf libpg_query libpg-query.js libpg-query.wasm

.PHONY: info
info:
@echo "Building PostgreSQL $(VERSION) parser"
@echo "Tag: $(TAG)"
@echo "Export name: LibPGQuery$(VERSION)"
130 changes: 130 additions & 0 deletions parser/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
# @pgsql/parser

<p align="center" width="100%">
<img src="https://github.com/launchql/libpg-query-node/assets/545047/5fd420cc-cdc6-4211-9b0f-0eca8321ba72" alt="hyperweb.io" width="100">
</p>

<p align="center" width="100%">
<a href="https://github.com/launchql/libpg-query/blob/main/LICENSE-MIT"><img height="20" src="https://img.shields.io/badge/license-MIT-blue.svg"/></a>
<a href="https://www.npmjs.com/package/libpg-query"><img height="20" src="https://img.shields.io/github/package-json/v/launchql/libpg-query-node?filename=versions%2F17%2Fpackage.json"/></a><br />
<a href="https://github.com/launchql/libpg-query-node/actions/workflows/ci.yml"><img height="20" src="https://github.com/launchql/libpg-query-node/actions/workflows/ci.yml/badge.svg" /></a>
<a href="https://github.com/launchql/libpg-query-node/actions/workflows/ci.yml"><img height="20" src="https://img.shields.io/badge/macOS-available-333333?logo=apple&logoColor=white" /></a>
<a href="https://github.com/launchql/libpg-query-node/actions/workflows/ci.yml"><img height="20" src="https://img.shields.io/badge/Windows-available-333333?logo=windows&logoColor=white" /></a>
<a href="https://github.com/launchql/libpg-query-node/actions/workflows/ci.yml"><img height="20" src="https://img.shields.io/badge/Linux-available-333333?logo=linux&logoColor=white" /></a>
</p>

Multi-version PostgreSQL parser with dynamic version selection. This package provides a unified interface to parse PostgreSQL queries using different parser versions (15, 16, 17).

## Installation

```bash
npm install @pgsql/parser
```

## Usage

### Dynamic Version Selection

```javascript
import { parse, PgParser } from '@pgsql/parser';

// Parse with default version (17)
const result = await parse('SELECT 1+1 as sum');
console.log(result);
// { version: 17, result: { version: 170004, stmts: [...] } }

// Parse with specific version
const result15 = await parse('SELECT 1+1 as sum', 15);
console.log(result15);
// { version: 15, result: { version: 150007, stmts: [...] } }

// Using PgParser class
const parser = new PgParser(16);
const result16 = await parser.parse('SELECT * FROM users');
```

### Static Version Imports

For better tree-shaking and when you know which version you need:

```javascript
// Import specific version
import * as pg17 from '@pgsql/parser/v17';

await pg17.loadModule();
const result = await pg17.parse('SELECT 1');
console.log(result);
// { version: 170004, stmts: [...] }
```

### Error Handling

The parser returns errors in a consistent format:

```javascript
const result = await parse('INVALID SQL');
if (result.error) {
console.error(result.error);
// { type: 'syntax', message: 'syntax error at or near "INVALID"', position: 0 }
}
```

## API

### `parse(query: string, version?: 15 | 16 | 17): Promise<ParseResult>`

Parse a SQL query with the specified PostgreSQL version.

- `query`: The SQL query string to parse
- `version`: PostgreSQL version (15, 16, or 17). Defaults to 17.

Returns a promise that resolves to:
- On success: `{ version: number, result: AST }`
- On error: `{ version: number, error: { type: string, message: string, position: number } }`

### `PgParser`

Class for creating a parser instance with a specific version.

```javascript
const parser = new PgParser(version);
await parser.parse(query);
parser.parseSync(query); // Only available after first parse()
```

## Version Exports

- `@pgsql/parser/v15` - PostgreSQL 15 parser
- `@pgsql/parser/v16` - PostgreSQL 16 parser
- `@pgsql/parser/v17` - PostgreSQL 17 parser

Each version export provides:
- `loadModule()`: Initialize the WASM module
- `parse(query)`: Parse a query (async)
- `parseSync(query)`: Parse a query (sync, requires loadModule first)

## Credits

Built on the excellent work of several contributors:

* **[Dan Lynch](https://github.com/pyramation)** — official maintainer since 2018 and architect of the current implementation
* **[Lukas Fittl](https://github.com/lfittl)** for [libpg_query](https://github.com/pganalyze/libpg_query) — the core PostgreSQL parser that powers this project
* **[Greg Richardson](https://github.com/gregnr)** for AST guidance and pushing the transition to WASM for better interoperability
* **[Ethan Resnick](https://github.com/ethanresnick)** for the original Node.js N-API bindings
* **[Zac McCormick](https://github.com/zhm)** for the foundational [node-pg-query-native](https://github.com/zhm/node-pg-query-native) parser

## Related

* [pgsql-parser](https://www.npmjs.com/package/pgsql-parser): The real PostgreSQL parser for Node.js, providing symmetric parsing and deparsing of SQL statements with actual PostgreSQL parser integration.
* [pgsql-deparser](https://www.npmjs.com/package/pgsql-deparser): A streamlined tool designed for converting PostgreSQL ASTs back into SQL queries, focusing solely on deparser functionality to complement `pgsql-parser`.
* [@pgsql/types](https://www.npmjs.com/package/@pgsql/types): Offers TypeScript type definitions for PostgreSQL AST nodes, facilitating type-safe construction, analysis, and manipulation of ASTs.
* [@pgsql/enums](https://www.npmjs.com/package/@pgsql/enums): Provides TypeScript enum definitions for PostgreSQL constants, enabling type-safe usage of PostgreSQL enums and constants in your applications.
* [@pgsql/utils](https://www.npmjs.com/package/@pgsql/utils): A comprehensive utility library for PostgreSQL, offering type-safe AST node creation and enum value conversions, simplifying the construction and manipulation of PostgreSQL ASTs.
* [pg-proto-parser](https://www.npmjs.com/package/pg-proto-parser): A TypeScript tool that parses PostgreSQL Protocol Buffers definitions to generate TypeScript interfaces, utility functions, and JSON mappings for enums.
* [libpg-query](https://github.com/launchql/libpg-query-node): The real PostgreSQL parser exposed for Node.js, used primarily in `pgsql-parser` for parsing and deparsing SQL queries.

## Disclaimer

AS DESCRIBED IN THE LICENSES, THE SOFTWARE IS PROVIDED "AS IS", AT YOUR OWN RISK, AND WITHOUT WARRANTIES OF ANY KIND.

No developer or entity involved in creating Software will be liable for any claims or damages whatsoever associated with your use, inability to use, or your interaction with other users of the Software code or Software CLI, including any direct, indirect, incidental, special, exemplary, punitive or consequential damages, or loss of profits, cryptocurrencies, tokens, or anything else of value.
Loading