├── full ├── libpg_query │ └── protobuf │ │ └── .gitkeep ├── tsconfig.esm.json ├── .npmignore ├── src │ ├── proto.d.ts │ └── libpg-query.d.ts ├── tsconfig.json ├── scripts │ ├── build.js │ └── protogen.js ├── CHANGELOG.md ├── package.json ├── test │ ├── plpgsql.test.js │ ├── fingerprint.test.js │ ├── deparsing.test.js │ ├── normalize.test.js │ └── parsing.test.js └── Makefile ├── parser ├── .gitignore ├── package.json ├── templates │ ├── index.js.template │ ├── index.cjs.template │ └── index.d.ts.template └── test │ ├── errors.test.js │ └── parsing.test.js ├── types ├── 13 │ ├── src │ │ └── index.ts │ ├── tsconfig.esm.json │ ├── tsconfig.json │ ├── scripts │ │ └── pg-proto-parser.ts │ ├── jest.config.js │ ├── CHANGELOG.md │ └── package.json ├── 14 │ ├── src │ │ └── index.ts │ ├── tsconfig.esm.json │ ├── tsconfig.json │ ├── scripts │ │ └── pg-proto-parser.ts │ ├── jest.config.js │ ├── CHANGELOG.md │ └── package.json ├── 15 │ ├── src │ │ └── index.ts │ ├── tsconfig.esm.json │ ├── tsconfig.json │ ├── scripts │ │ └── pg-proto-parser.ts │ ├── jest.config.js │ ├── CHANGELOG.md │ └── package.json ├── 16 │ ├── src │ │ └── index.ts │ ├── tsconfig.esm.json │ ├── tsconfig.json │ ├── scripts │ │ └── pg-proto-parser.ts │ ├── jest.config.js │ ├── CHANGELOG.md │ └── package.json └── 17 │ ├── src │ └── index.ts │ ├── tsconfig.esm.json │ ├── tsconfig.json │ ├── scripts │ └── pg-proto-parser.ts │ ├── jest.config.js │ ├── CHANGELOG.md │ └── package.json ├── .vscode └── settings.json ├── enums ├── 13 │ ├── tsconfig.esm.json │ ├── tsconfig.json │ ├── scripts │ │ └── pg-proto-parser.ts │ ├── jest.config.js │ ├── package.json │ └── README.md ├── 14 │ ├── tsconfig.esm.json │ ├── tsconfig.json │ ├── scripts │ │ └── pg-proto-parser.ts │ ├── jest.config.js │ ├── package.json │ └── README.md ├── 15 │ ├── tsconfig.esm.json │ ├── tsconfig.json │ ├── scripts │ │ └── pg-proto-parser.ts │ ├── jest.config.js │ └── package.json ├── 16 │ ├── tsconfig.esm.json │ ├── tsconfig.json │ ├── scripts │ │ └── pg-proto-parser.ts │ ├── jest.config.js │ └── package.json └── 17 │ ├── tsconfig.esm.json │ ├── tsconfig.json │ ├── scripts │ └── pg-proto-parser.ts │ ├── jest.config.js │ └── package.json ├── versions ├── 13 │ ├── tsconfig.esm.json │ ├── tsconfig.json │ ├── src │ │ ├── libpg-query.d.ts │ │ └── wasm_wrapper.c │ ├── patches │ │ └── emscripten_disable_spinlocks.patch │ ├── LICENSE │ ├── scripts │ │ └── build.js │ ├── package.json │ ├── test │ │ └── parsing.test.js │ └── Makefile ├── 14 │ ├── tsconfig.esm.json │ ├── tsconfig.json │ ├── src │ │ ├── libpg-query.d.ts │ │ └── wasm_wrapper.c │ ├── LICENSE │ ├── scripts │ │ └── build.js │ ├── package.json │ ├── test │ │ └── parsing.test.js │ └── Makefile ├── 15 │ ├── tsconfig.esm.json │ ├── tsconfig.json │ ├── src │ │ ├── libpg-query.d.ts │ │ └── wasm_wrapper.c │ ├── LICENSE │ ├── scripts │ │ └── build.js │ ├── package.json │ ├── test │ │ └── parsing.test.js │ └── Makefile ├── 16 │ ├── tsconfig.esm.json │ ├── tsconfig.json │ ├── src │ │ ├── libpg-query.d.ts │ │ └── wasm_wrapper.c │ ├── LICENSE │ ├── scripts │ │ └── build.js │ ├── package.json │ ├── test │ │ └── parsing.test.js │ └── Makefile └── 17 │ ├── tsconfig.esm.json │ ├── tsconfig.json │ ├── src │ ├── libpg-query.d.ts │ └── wasm_wrapper.c │ ├── LICENSE │ ├── scripts │ └── build.js │ ├── package.json │ ├── test │ └── parsing.test.js │ ├── Makefile │ └── README_ERROR_HANDLING.md ├── pnpm-workspace.yaml ├── .gitignore ├── templates ├── libpg-query.d.ts ├── wasm_wrapper.c ├── LICENSE ├── README.md └── Makefile.template ├── tsconfig.json ├── LOADING_WASM.md ├── .npmrc ├── REPO_NOTES.md ├── LICENSE ├── .github └── workflows │ ├── build-wasm.yml │ └── build-wasm-no-docker.yaml ├── scripts ├── README.md ├── publish-single-version.js ├── build-enums.js ├── build-types.js ├── fetch-protos.js ├── prepare-enums.js ├── prepare-types.js ├── update-versions-types.js └── copy-templates.js └── package.json /full/libpg_query/protobuf/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /parser/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | wasm/ 3 | *.log 4 | .DS_Store -------------------------------------------------------------------------------- /types/13/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from './types'; 2 | export * from './enums'; 3 | -------------------------------------------------------------------------------- /types/14/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from './types'; 2 | export * from './enums'; 3 | -------------------------------------------------------------------------------- /types/15/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from './types'; 2 | export * from './enums'; 3 | -------------------------------------------------------------------------------- /types/16/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from './types'; 2 | export * from './enums'; 3 | -------------------------------------------------------------------------------- /types/17/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from './types'; 2 | export * from './enums'; 3 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "workbench.colorTheme": "Default Dark Modern", 3 | "workbench.startupEditor": "none" 4 | } 5 | -------------------------------------------------------------------------------- /enums/17/tsconfig.esm.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "dist/esm", 5 | "module": "es2022", 6 | "rootDir": "src/", 7 | "declaration": false 8 | } 9 | } -------------------------------------------------------------------------------- /full/tsconfig.esm.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "module": "es2022", 5 | "rootDir": "src/", 6 | "declaration": false, 7 | "outDir": "esm/" 8 | } 9 | } -------------------------------------------------------------------------------- /enums/13/tsconfig.esm.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "dist/esm", 5 | "module": "es2022", 6 | "rootDir": "src/", 7 | "declaration": false 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /enums/14/tsconfig.esm.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "dist/esm", 5 | "module": "es2022", 6 | "rootDir": "src/", 7 | "declaration": false 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /enums/15/tsconfig.esm.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "dist/esm", 5 | "module": "es2022", 6 | "rootDir": "src/", 7 | "declaration": false 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /enums/16/tsconfig.esm.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "dist/esm", 5 | "module": "es2022", 6 | "rootDir": "src/", 7 | "declaration": false 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /types/13/tsconfig.esm.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "dist/esm", 5 | "module": "es2022", 6 | "rootDir": "src/", 7 | "declaration": false 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /types/14/tsconfig.esm.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "dist/esm", 5 | "module": "es2022", 6 | "rootDir": "src/", 7 | "declaration": false 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /types/15/tsconfig.esm.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "dist/esm", 5 | "module": "es2022", 6 | "rootDir": "src/", 7 | "declaration": false 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /types/16/tsconfig.esm.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "dist/esm", 5 | "module": "es2022", 6 | "rootDir": "src/", 7 | "declaration": false 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /types/17/tsconfig.esm.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "dist/esm", 5 | "module": "es2022", 6 | "rootDir": "src/", 7 | "declaration": false 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /versions/13/tsconfig.esm.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "module": "es2022", 5 | "rootDir": "src/", 6 | "declaration": false, 7 | "outDir": "esm/" 8 | } 9 | } -------------------------------------------------------------------------------- /versions/14/tsconfig.esm.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "module": "es2022", 5 | "rootDir": "src/", 6 | "declaration": false, 7 | "outDir": "esm/" 8 | } 9 | } -------------------------------------------------------------------------------- /versions/15/tsconfig.esm.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "module": "es2022", 5 | "rootDir": "src/", 6 | "declaration": false, 7 | "outDir": "esm/" 8 | } 9 | } -------------------------------------------------------------------------------- /versions/16/tsconfig.esm.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "module": "es2022", 5 | "rootDir": "src/", 6 | "declaration": false, 7 | "outDir": "esm/" 8 | } 9 | } -------------------------------------------------------------------------------- /versions/17/tsconfig.esm.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "module": "es2022", 5 | "rootDir": "src/", 6 | "declaration": false, 7 | "outDir": "esm/" 8 | } 9 | } -------------------------------------------------------------------------------- /enums/17/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "dist", 5 | "rootDir": "src/" 6 | }, 7 | "include": ["src/**/*.ts"], 8 | "exclude": ["dist", "node_modules", "**/*.spec.*", "**/*.test.*"] 9 | } -------------------------------------------------------------------------------- /enums/13/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "dist", 5 | "rootDir": "src/" 6 | }, 7 | "include": ["src/**/*.ts"], 8 | "exclude": ["dist", "node_modules", "**/*.spec.*", "**/*.test.*"] 9 | } 10 | -------------------------------------------------------------------------------- /enums/14/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "dist", 5 | "rootDir": "src/" 6 | }, 7 | "include": ["src/**/*.ts"], 8 | "exclude": ["dist", "node_modules", "**/*.spec.*", "**/*.test.*"] 9 | } 10 | -------------------------------------------------------------------------------- /enums/15/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "dist", 5 | "rootDir": "src/" 6 | }, 7 | "include": ["src/**/*.ts"], 8 | "exclude": ["dist", "node_modules", "**/*.spec.*", "**/*.test.*"] 9 | } 10 | -------------------------------------------------------------------------------- /enums/16/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "dist", 5 | "rootDir": "src/" 6 | }, 7 | "include": ["src/**/*.ts"], 8 | "exclude": ["dist", "node_modules", "**/*.spec.*", "**/*.test.*"] 9 | } 10 | -------------------------------------------------------------------------------- /types/13/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "dist", 5 | "rootDir": "src/" 6 | }, 7 | "include": ["src/**/*.ts"], 8 | "exclude": ["dist", "node_modules", "**/*.spec.*", "**/*.test.*"] 9 | } 10 | -------------------------------------------------------------------------------- /types/14/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "dist", 5 | "rootDir": "src/" 6 | }, 7 | "include": ["src/**/*.ts"], 8 | "exclude": ["dist", "node_modules", "**/*.spec.*", "**/*.test.*"] 9 | } 10 | -------------------------------------------------------------------------------- /types/15/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "dist", 5 | "rootDir": "src/" 6 | }, 7 | "include": ["src/**/*.ts"], 8 | "exclude": ["dist", "node_modules", "**/*.spec.*", "**/*.test.*"] 9 | } 10 | -------------------------------------------------------------------------------- /types/16/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "dist", 5 | "rootDir": "src/" 6 | }, 7 | "include": ["src/**/*.ts"], 8 | "exclude": ["dist", "node_modules", "**/*.spec.*", "**/*.test.*"] 9 | } 10 | -------------------------------------------------------------------------------- /types/17/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "dist", 5 | "rootDir": "src/" 6 | }, 7 | "include": ["src/**/*.ts"], 8 | "exclude": ["dist", "node_modules", "**/*.spec.*", "**/*.test.*"] 9 | } 10 | -------------------------------------------------------------------------------- /full/.npmignore: -------------------------------------------------------------------------------- 1 | # project files 2 | test 3 | .gitignore 4 | package.json 5 | build 6 | 7 | *.log 8 | npm-debug.log* 9 | 10 | # Dependency directories 11 | node_modules 12 | 13 | libpg_query/* 14 | 15 | # npm package lock 16 | package-lock.json 17 | yarn.lock 18 | 19 | -------------------------------------------------------------------------------- /pnpm-workspace.yaml: -------------------------------------------------------------------------------- 1 | packages: 2 | - 'parser' 3 | - 'full' 4 | - 'versions/17' 5 | - 'versions/16' 6 | - 'versions/15' 7 | - 'versions/14' 8 | - 'versions/13' 9 | - 'types/17' 10 | - 'types/16' 11 | - 'types/15' 12 | - 'types/14' 13 | - 'types/13' 14 | - 'enums/17' 15 | - 'enums/16' 16 | - 'enums/15' 17 | - 'enums/14' 18 | - 'enums/13' -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Dependencies 2 | node_modules/ 3 | .pnpm-store/ 4 | 5 | # Build artifacts 6 | build/ 7 | libs/ 8 | esm/ 9 | cjs/ 10 | dist/ 11 | 12 | # WASM build outputs 13 | wasm/ 14 | versions/*/wasm/ 15 | *.wasm 16 | wasm/libpg-query.js 17 | 18 | # Build cache and temporary files 19 | .cache 20 | 21 | # Generated files 22 | libpg_query/**/*.proto 23 | 24 | # Development tools and logs 25 | npm-debug.log 26 | .claude 27 | .openhands/ 28 | .DS_Store 29 | -------------------------------------------------------------------------------- /full/src/proto.d.ts: -------------------------------------------------------------------------------- 1 | declare module '../proto.js' { 2 | export namespace pg_query { 3 | interface ParseResult { 4 | version: number; 5 | stmts: Statement[]; 6 | } 7 | 8 | interface Statement { 9 | stmt_type: string; 10 | stmt_len: number; 11 | stmt_location: number; 12 | query: string; 13 | } 14 | 15 | class ParseResult { 16 | static fromObject(obj: ParseResult): ParseResult; 17 | static encode(msg: ParseResult): { finish(): Uint8Array }; 18 | } 19 | } 20 | } -------------------------------------------------------------------------------- /full/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es2022", 4 | "module": "commonjs", 5 | "esModuleInterop": true, 6 | "forceConsistentCasingInFileNames": true, 7 | "strict": true, 8 | "strictNullChecks": false, 9 | "skipLibCheck": true, 10 | "sourceMap": false, 11 | "declaration": true, 12 | "resolveJsonModule": true, 13 | "moduleResolution": "node", 14 | "outDir": "cjs/", 15 | "rootDir": "src" 16 | }, 17 | "exclude": ["cjs", "esm", "wasm", "node_modules", "**/*.test.ts"] 18 | } -------------------------------------------------------------------------------- /versions/13/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es2022", 4 | "module": "commonjs", 5 | "esModuleInterop": true, 6 | "forceConsistentCasingInFileNames": true, 7 | "strict": true, 8 | "strictNullChecks": false, 9 | "skipLibCheck": true, 10 | "sourceMap": false, 11 | "declaration": true, 12 | "resolveJsonModule": true, 13 | "moduleResolution": "node", 14 | "outDir": "cjs/", 15 | "rootDir": "src" 16 | }, 17 | "exclude": ["cjs", "esm", "wasm", "node_modules", "**/*.test.ts"] 18 | } -------------------------------------------------------------------------------- /versions/14/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es2022", 4 | "module": "commonjs", 5 | "esModuleInterop": true, 6 | "forceConsistentCasingInFileNames": true, 7 | "strict": true, 8 | "strictNullChecks": false, 9 | "skipLibCheck": true, 10 | "sourceMap": false, 11 | "declaration": true, 12 | "resolveJsonModule": true, 13 | "moduleResolution": "node", 14 | "outDir": "cjs/", 15 | "rootDir": "src" 16 | }, 17 | "exclude": ["cjs", "esm", "wasm", "node_modules", "**/*.test.ts"] 18 | } -------------------------------------------------------------------------------- /versions/15/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es2022", 4 | "module": "commonjs", 5 | "esModuleInterop": true, 6 | "forceConsistentCasingInFileNames": true, 7 | "strict": true, 8 | "strictNullChecks": false, 9 | "skipLibCheck": true, 10 | "sourceMap": false, 11 | "declaration": true, 12 | "resolveJsonModule": true, 13 | "moduleResolution": "node", 14 | "outDir": "cjs/", 15 | "rootDir": "src" 16 | }, 17 | "exclude": ["cjs", "esm", "wasm", "node_modules", "**/*.test.ts"] 18 | } -------------------------------------------------------------------------------- /versions/16/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es2022", 4 | "module": "commonjs", 5 | "esModuleInterop": true, 6 | "forceConsistentCasingInFileNames": true, 7 | "strict": true, 8 | "strictNullChecks": false, 9 | "skipLibCheck": true, 10 | "sourceMap": false, 11 | "declaration": true, 12 | "resolveJsonModule": true, 13 | "moduleResolution": "node", 14 | "outDir": "cjs/", 15 | "rootDir": "src" 16 | }, 17 | "exclude": ["cjs", "esm", "wasm", "node_modules", "**/*.test.ts"] 18 | } -------------------------------------------------------------------------------- /versions/17/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es2022", 4 | "module": "commonjs", 5 | "esModuleInterop": true, 6 | "forceConsistentCasingInFileNames": true, 7 | "strict": true, 8 | "strictNullChecks": false, 9 | "skipLibCheck": true, 10 | "sourceMap": false, 11 | "declaration": true, 12 | "resolveJsonModule": true, 13 | "moduleResolution": "node", 14 | "outDir": "cjs/", 15 | "rootDir": "src" 16 | }, 17 | "exclude": ["cjs", "esm", "wasm", "node_modules", "**/*.test.ts"] 18 | } -------------------------------------------------------------------------------- /enums/13/scripts/pg-proto-parser.ts: -------------------------------------------------------------------------------- 1 | import { PgProtoParser, PgProtoParserOptions } from 'pg-proto-parser'; 2 | import { resolve, join } from 'path'; 3 | 4 | const inFile: string = join(__dirname, '../../../protos/13/pg_query.proto'); 5 | const outDir: string = resolve(join(__dirname, '../src')); 6 | 7 | const options: PgProtoParserOptions = { 8 | outDir, 9 | enums: { 10 | enabled: true, 11 | enumsAsTypeUnion: false, 12 | filename: 'index.ts' 13 | } 14 | }; 15 | const parser = new PgProtoParser(inFile, options); 16 | 17 | parser.write(); -------------------------------------------------------------------------------- /enums/14/scripts/pg-proto-parser.ts: -------------------------------------------------------------------------------- 1 | import { PgProtoParser, PgProtoParserOptions } from 'pg-proto-parser'; 2 | import { resolve, join } from 'path'; 3 | 4 | const inFile: string = join(__dirname, '../../../protos/14/pg_query.proto'); 5 | const outDir: string = resolve(join(__dirname, '../src')); 6 | 7 | const options: PgProtoParserOptions = { 8 | outDir, 9 | enums: { 10 | enabled: true, 11 | enumsAsTypeUnion: false, 12 | filename: 'index.ts' 13 | } 14 | }; 15 | const parser = new PgProtoParser(inFile, options); 16 | 17 | parser.write(); -------------------------------------------------------------------------------- /enums/15/scripts/pg-proto-parser.ts: -------------------------------------------------------------------------------- 1 | import { PgProtoParser, PgProtoParserOptions } from 'pg-proto-parser'; 2 | import { resolve, join } from 'path'; 3 | 4 | const inFile: string = join(__dirname, '../../../protos/15/pg_query.proto'); 5 | const outDir: string = resolve(join(__dirname, '../src')); 6 | 7 | const options: PgProtoParserOptions = { 8 | outDir, 9 | enums: { 10 | enabled: true, 11 | enumsAsTypeUnion: false, 12 | filename: 'index.ts' 13 | } 14 | }; 15 | const parser = new PgProtoParser(inFile, options); 16 | 17 | parser.write(); -------------------------------------------------------------------------------- /enums/16/scripts/pg-proto-parser.ts: -------------------------------------------------------------------------------- 1 | import { PgProtoParser, PgProtoParserOptions } from 'pg-proto-parser'; 2 | import { resolve, join } from 'path'; 3 | 4 | const inFile: string = join(__dirname, '../../../protos/16/pg_query.proto'); 5 | const outDir: string = resolve(join(__dirname, '../src')); 6 | 7 | const options: PgProtoParserOptions = { 8 | outDir, 9 | enums: { 10 | enabled: true, 11 | enumsAsTypeUnion: false, 12 | filename: 'index.ts' 13 | } 14 | }; 15 | const parser = new PgProtoParser(inFile, options); 16 | 17 | parser.write(); -------------------------------------------------------------------------------- /enums/17/scripts/pg-proto-parser.ts: -------------------------------------------------------------------------------- 1 | import { PgProtoParser, PgProtoParserOptions } from 'pg-proto-parser'; 2 | import { resolve, join } from 'path'; 3 | 4 | const inFile: string = join(__dirname, '../../../protos/17/pg_query.proto'); 5 | const outDir: string = resolve(join(__dirname, '../src')); 6 | 7 | const options: PgProtoParserOptions = { 8 | outDir, 9 | enums: { 10 | enabled: true, 11 | enumsAsTypeUnion: false, 12 | filename: 'index.ts' 13 | } 14 | }; 15 | const parser = new PgProtoParser(inFile, options); 16 | 17 | parser.write(); -------------------------------------------------------------------------------- /templates/libpg-query.d.ts: -------------------------------------------------------------------------------- 1 | declare module './libpg-query.js' { 2 | interface WasmModule { 3 | _malloc: (size: number) => number; 4 | _free: (ptr: number) => void; 5 | _wasm_free_string: (ptr: number) => void; 6 | _wasm_parse_query: (queryPtr: number) => number; 7 | lengthBytesUTF8: (str: string) => number; 8 | stringToUTF8: (str: string, ptr: number, len: number) => void; 9 | UTF8ToString: (ptr: number) => string; 10 | HEAPU8: Uint8Array; 11 | } 12 | 13 | const PgQueryModule: () => Promise; 14 | export default PgQueryModule; 15 | } -------------------------------------------------------------------------------- /types/13/scripts/pg-proto-parser.ts: -------------------------------------------------------------------------------- 1 | import { PgProtoParser, PgProtoParserOptions } from 'pg-proto-parser'; 2 | import { resolve, join } from 'path'; 3 | 4 | const inFile: string = join(__dirname, '../../../protos/13/pg_query.proto'); 5 | const outDir: string = resolve(join(__dirname, '../src')); 6 | 7 | const options: PgProtoParserOptions = { 8 | outDir, 9 | types: { 10 | enabled: true, 11 | wrappedNodeTypeExport: true 12 | }, 13 | enums: { 14 | enabled: true, 15 | enumsAsTypeUnion: true 16 | } 17 | }; 18 | const parser = new PgProtoParser(inFile, options); 19 | 20 | parser.write(); 21 | -------------------------------------------------------------------------------- /types/14/scripts/pg-proto-parser.ts: -------------------------------------------------------------------------------- 1 | import { PgProtoParser, PgProtoParserOptions } from 'pg-proto-parser'; 2 | import { resolve, join } from 'path'; 3 | 4 | const inFile: string = join(__dirname, '../../../protos/14/pg_query.proto'); 5 | const outDir: string = resolve(join(__dirname, '../src')); 6 | 7 | const options: PgProtoParserOptions = { 8 | outDir, 9 | types: { 10 | enabled: true, 11 | wrappedNodeTypeExport: true 12 | }, 13 | enums: { 14 | enabled: true, 15 | enumsAsTypeUnion: true 16 | } 17 | }; 18 | const parser = new PgProtoParser(inFile, options); 19 | 20 | parser.write(); 21 | -------------------------------------------------------------------------------- /types/15/scripts/pg-proto-parser.ts: -------------------------------------------------------------------------------- 1 | import { PgProtoParser, PgProtoParserOptions } from 'pg-proto-parser'; 2 | import { resolve, join } from 'path'; 3 | 4 | const inFile: string = join(__dirname, '../../../protos/15/pg_query.proto'); 5 | const outDir: string = resolve(join(__dirname, '../src')); 6 | 7 | const options: PgProtoParserOptions = { 8 | outDir, 9 | types: { 10 | enabled: true, 11 | wrappedNodeTypeExport: true 12 | }, 13 | enums: { 14 | enabled: true, 15 | enumsAsTypeUnion: true 16 | } 17 | }; 18 | const parser = new PgProtoParser(inFile, options); 19 | 20 | parser.write(); 21 | -------------------------------------------------------------------------------- /types/16/scripts/pg-proto-parser.ts: -------------------------------------------------------------------------------- 1 | import { PgProtoParser, PgProtoParserOptions } from 'pg-proto-parser'; 2 | import { resolve, join } from 'path'; 3 | 4 | const inFile: string = join(__dirname, '../../../protos/16/pg_query.proto'); 5 | const outDir: string = resolve(join(__dirname, '../src')); 6 | 7 | const options: PgProtoParserOptions = { 8 | outDir, 9 | types: { 10 | enabled: true, 11 | wrappedNodeTypeExport: true 12 | }, 13 | enums: { 14 | enabled: true, 15 | enumsAsTypeUnion: true 16 | } 17 | }; 18 | const parser = new PgProtoParser(inFile, options); 19 | 20 | parser.write(); 21 | -------------------------------------------------------------------------------- /types/17/scripts/pg-proto-parser.ts: -------------------------------------------------------------------------------- 1 | import { PgProtoParser, PgProtoParserOptions } from 'pg-proto-parser'; 2 | import { resolve, join } from 'path'; 3 | 4 | const inFile: string = join(__dirname, '../../../protos/17/pg_query.proto'); 5 | const outDir: string = resolve(join(__dirname, '../src')); 6 | 7 | const options: PgProtoParserOptions = { 8 | outDir, 9 | types: { 10 | enabled: true, 11 | wrappedNodeTypeExport: true 12 | }, 13 | enums: { 14 | enabled: true, 15 | enumsAsTypeUnion: true 16 | } 17 | }; 18 | const parser = new PgProtoParser(inFile, options); 19 | 20 | parser.write(); 21 | -------------------------------------------------------------------------------- /enums/17/jest.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('ts-jest').JestConfigWithTsJest} */ 2 | module.exports = { 3 | preset: "ts-jest", 4 | testEnvironment: "node", 5 | transform: { 6 | "^.+\\.tsx?$": [ 7 | "ts-jest", 8 | { 9 | babelConfig: false, 10 | tsconfig: "tsconfig.json", 11 | }, 12 | ], 13 | }, 14 | transformIgnorePatterns: [`/node_modules/*`], 15 | testRegex: "(/__tests__/.*|(\\.|/)(test|spec))\\.(jsx?|tsx?)$", 16 | moduleFileExtensions: ["ts", "tsx", "js", "jsx", "json", "node"], 17 | modulePathIgnorePatterns: ["dist/*"] 18 | }; -------------------------------------------------------------------------------- /enums/13/jest.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('ts-jest').JestConfigWithTsJest} */ 2 | module.exports = { 3 | preset: "ts-jest", 4 | testEnvironment: "node", 5 | transform: { 6 | "^.+\.tsx?$": [ 7 | "ts-jest", 8 | { 9 | babelConfig: false, 10 | tsconfig: "tsconfig.json", 11 | }, 12 | ], 13 | }, 14 | transformIgnorePatterns: [`/node_modules/*`], 15 | testRegex: "(/__tests__/.*|(\.|/)(test|spec))\.(jsx?|tsx?)$", 16 | moduleFileExtensions: ["ts", "tsx", "js", "jsx", "json", "node"], 17 | modulePathIgnorePatterns: ["dist/*"] 18 | }; 19 | -------------------------------------------------------------------------------- /enums/14/jest.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('ts-jest').JestConfigWithTsJest} */ 2 | module.exports = { 3 | preset: "ts-jest", 4 | testEnvironment: "node", 5 | transform: { 6 | "^.+\.tsx?$": [ 7 | "ts-jest", 8 | { 9 | babelConfig: false, 10 | tsconfig: "tsconfig.json", 11 | }, 12 | ], 13 | }, 14 | transformIgnorePatterns: [`/node_modules/*`], 15 | testRegex: "(/__tests__/.*|(\.|/)(test|spec))\.(jsx?|tsx?)$", 16 | moduleFileExtensions: ["ts", "tsx", "js", "jsx", "json", "node"], 17 | modulePathIgnorePatterns: ["dist/*"] 18 | }; 19 | -------------------------------------------------------------------------------- /enums/15/jest.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('ts-jest').JestConfigWithTsJest} */ 2 | module.exports = { 3 | preset: "ts-jest", 4 | testEnvironment: "node", 5 | transform: { 6 | "^.+\.tsx?$": [ 7 | "ts-jest", 8 | { 9 | babelConfig: false, 10 | tsconfig: "tsconfig.json", 11 | }, 12 | ], 13 | }, 14 | transformIgnorePatterns: [`/node_modules/*`], 15 | testRegex: "(/__tests__/.*|(\.|/)(test|spec))\.(jsx?|tsx?)$", 16 | moduleFileExtensions: ["ts", "tsx", "js", "jsx", "json", "node"], 17 | modulePathIgnorePatterns: ["dist/*"] 18 | }; 19 | -------------------------------------------------------------------------------- /enums/16/jest.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('ts-jest').JestConfigWithTsJest} */ 2 | module.exports = { 3 | preset: "ts-jest", 4 | testEnvironment: "node", 5 | transform: { 6 | "^.+\.tsx?$": [ 7 | "ts-jest", 8 | { 9 | babelConfig: false, 10 | tsconfig: "tsconfig.json", 11 | }, 12 | ], 13 | }, 14 | transformIgnorePatterns: [`/node_modules/*`], 15 | testRegex: "(/__tests__/.*|(\.|/)(test|spec))\.(jsx?|tsx?)$", 16 | moduleFileExtensions: ["ts", "tsx", "js", "jsx", "json", "node"], 17 | modulePathIgnorePatterns: ["dist/*"] 18 | }; 19 | -------------------------------------------------------------------------------- /types/13/jest.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('ts-jest').JestConfigWithTsJest} */ 2 | module.exports = { 3 | preset: "ts-jest", 4 | testEnvironment: "node", 5 | transform: { 6 | "^.+\\.tsx?$": [ 7 | "ts-jest", 8 | { 9 | babelConfig: false, 10 | tsconfig: "tsconfig.json", 11 | }, 12 | ], 13 | }, 14 | transformIgnorePatterns: [`/node_modules/*`], 15 | testRegex: "(/__tests__/.*|(\\.|/)(test|spec))\\.(jsx?|tsx?)$", 16 | moduleFileExtensions: ["ts", "tsx", "js", "jsx", "json", "node"], 17 | modulePathIgnorePatterns: ["dist/*"] 18 | }; 19 | -------------------------------------------------------------------------------- /types/14/jest.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('ts-jest').JestConfigWithTsJest} */ 2 | module.exports = { 3 | preset: "ts-jest", 4 | testEnvironment: "node", 5 | transform: { 6 | "^.+\\.tsx?$": [ 7 | "ts-jest", 8 | { 9 | babelConfig: false, 10 | tsconfig: "tsconfig.json", 11 | }, 12 | ], 13 | }, 14 | transformIgnorePatterns: [`/node_modules/*`], 15 | testRegex: "(/__tests__/.*|(\\.|/)(test|spec))\\.(jsx?|tsx?)$", 16 | moduleFileExtensions: ["ts", "tsx", "js", "jsx", "json", "node"], 17 | modulePathIgnorePatterns: ["dist/*"] 18 | }; 19 | -------------------------------------------------------------------------------- /types/15/jest.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('ts-jest').JestConfigWithTsJest} */ 2 | module.exports = { 3 | preset: "ts-jest", 4 | testEnvironment: "node", 5 | transform: { 6 | "^.+\\.tsx?$": [ 7 | "ts-jest", 8 | { 9 | babelConfig: false, 10 | tsconfig: "tsconfig.json", 11 | }, 12 | ], 13 | }, 14 | transformIgnorePatterns: [`/node_modules/*`], 15 | testRegex: "(/__tests__/.*|(\\.|/)(test|spec))\\.(jsx?|tsx?)$", 16 | moduleFileExtensions: ["ts", "tsx", "js", "jsx", "json", "node"], 17 | modulePathIgnorePatterns: ["dist/*"] 18 | }; 19 | -------------------------------------------------------------------------------- /types/16/jest.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('ts-jest').JestConfigWithTsJest} */ 2 | module.exports = { 3 | preset: "ts-jest", 4 | testEnvironment: "node", 5 | transform: { 6 | "^.+\\.tsx?$": [ 7 | "ts-jest", 8 | { 9 | babelConfig: false, 10 | tsconfig: "tsconfig.json", 11 | }, 12 | ], 13 | }, 14 | transformIgnorePatterns: [`/node_modules/*`], 15 | testRegex: "(/__tests__/.*|(\\.|/)(test|spec))\\.(jsx?|tsx?)$", 16 | moduleFileExtensions: ["ts", "tsx", "js", "jsx", "json", "node"], 17 | modulePathIgnorePatterns: ["dist/*"] 18 | }; 19 | -------------------------------------------------------------------------------- /types/17/jest.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('ts-jest').JestConfigWithTsJest} */ 2 | module.exports = { 3 | preset: "ts-jest", 4 | testEnvironment: "node", 5 | transform: { 6 | "^.+\\.tsx?$": [ 7 | "ts-jest", 8 | { 9 | babelConfig: false, 10 | tsconfig: "tsconfig.json", 11 | }, 12 | ], 13 | }, 14 | transformIgnorePatterns: [`/node_modules/*`], 15 | testRegex: "(/__tests__/.*|(\\.|/)(test|spec))\\.(jsx?|tsx?)$", 16 | moduleFileExtensions: ["ts", "tsx", "js", "jsx", "json", "node"], 17 | modulePathIgnorePatterns: ["dist/*"] 18 | }; 19 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ES2020", 4 | "module": "commonjs", 5 | "lib": ["ES2020"], 6 | "declaration": true, 7 | "outDir": "./dist", 8 | "strict": true, 9 | "noUnusedLocals": false, 10 | "noUnusedParameters": false, 11 | "noImplicitReturns": true, 12 | "noFallthroughCasesInSwitch": true, 13 | "moduleResolution": "node", 14 | "baseUrl": ".", 15 | "esModuleInterop": true, 16 | "experimentalDecorators": true, 17 | "emitDecoratorMetadata": true, 18 | "skipLibCheck": true, 19 | "forceConsistentCasingInFileNames": true 20 | }, 21 | "exclude": [ 22 | "node_modules", 23 | "dist", 24 | "**/*.test.*", 25 | "**/*.spec.*" 26 | ] 27 | } -------------------------------------------------------------------------------- /versions/13/src/libpg-query.d.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * DO NOT MODIFY MANUALLY — this is generated from the templates dir 3 | * 4 | * To make changes, edit the files in the templates/ directory and run: 5 | * npm run copy:templates 6 | */ 7 | 8 | declare module './libpg-query.js' { 9 | interface WasmModule { 10 | _malloc: (size: number) => number; 11 | _free: (ptr: number) => void; 12 | _wasm_free_string: (ptr: number) => void; 13 | _wasm_parse_query: (queryPtr: number) => number; 14 | lengthBytesUTF8: (str: string) => number; 15 | stringToUTF8: (str: string, ptr: number, len: number) => void; 16 | UTF8ToString: (ptr: number) => string; 17 | HEAPU8: Uint8Array; 18 | } 19 | 20 | const PgQueryModule: () => Promise; 21 | export default PgQueryModule; 22 | } -------------------------------------------------------------------------------- /versions/14/src/libpg-query.d.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * DO NOT MODIFY MANUALLY — this is generated from the templates dir 3 | * 4 | * To make changes, edit the files in the templates/ directory and run: 5 | * npm run copy:templates 6 | */ 7 | 8 | declare module './libpg-query.js' { 9 | interface WasmModule { 10 | _malloc: (size: number) => number; 11 | _free: (ptr: number) => void; 12 | _wasm_free_string: (ptr: number) => void; 13 | _wasm_parse_query: (queryPtr: number) => number; 14 | lengthBytesUTF8: (str: string) => number; 15 | stringToUTF8: (str: string, ptr: number, len: number) => void; 16 | UTF8ToString: (ptr: number) => string; 17 | HEAPU8: Uint8Array; 18 | } 19 | 20 | const PgQueryModule: () => Promise; 21 | export default PgQueryModule; 22 | } -------------------------------------------------------------------------------- /versions/15/src/libpg-query.d.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * DO NOT MODIFY MANUALLY — this is generated from the templates dir 3 | * 4 | * To make changes, edit the files in the templates/ directory and run: 5 | * npm run copy:templates 6 | */ 7 | 8 | declare module './libpg-query.js' { 9 | interface WasmModule { 10 | _malloc: (size: number) => number; 11 | _free: (ptr: number) => void; 12 | _wasm_free_string: (ptr: number) => void; 13 | _wasm_parse_query: (queryPtr: number) => number; 14 | lengthBytesUTF8: (str: string) => number; 15 | stringToUTF8: (str: string, ptr: number, len: number) => void; 16 | UTF8ToString: (ptr: number) => string; 17 | HEAPU8: Uint8Array; 18 | } 19 | 20 | const PgQueryModule: () => Promise; 21 | export default PgQueryModule; 22 | } -------------------------------------------------------------------------------- /versions/16/src/libpg-query.d.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * DO NOT MODIFY MANUALLY — this is generated from the templates dir 3 | * 4 | * To make changes, edit the files in the templates/ directory and run: 5 | * npm run copy:templates 6 | */ 7 | 8 | declare module './libpg-query.js' { 9 | interface WasmModule { 10 | _malloc: (size: number) => number; 11 | _free: (ptr: number) => void; 12 | _wasm_free_string: (ptr: number) => void; 13 | _wasm_parse_query: (queryPtr: number) => number; 14 | lengthBytesUTF8: (str: string) => number; 15 | stringToUTF8: (str: string, ptr: number, len: number) => void; 16 | UTF8ToString: (ptr: number) => string; 17 | HEAPU8: Uint8Array; 18 | } 19 | 20 | const PgQueryModule: () => Promise; 21 | export default PgQueryModule; 22 | } -------------------------------------------------------------------------------- /versions/17/src/libpg-query.d.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * DO NOT MODIFY MANUALLY — this is generated from the templates dir 3 | * 4 | * To make changes, edit the files in the templates/ directory and run: 5 | * npm run copy:templates 6 | */ 7 | 8 | declare module './libpg-query.js' { 9 | interface WasmModule { 10 | _malloc: (size: number) => number; 11 | _free: (ptr: number) => void; 12 | _wasm_free_string: (ptr: number) => void; 13 | _wasm_parse_query: (queryPtr: number) => number; 14 | lengthBytesUTF8: (str: string) => number; 15 | stringToUTF8: (str: string, ptr: number, len: number) => void; 16 | UTF8ToString: (ptr: number) => string; 17 | HEAPU8: Uint8Array; 18 | } 19 | 20 | const PgQueryModule: () => Promise; 21 | export default PgQueryModule; 22 | } -------------------------------------------------------------------------------- /full/src/libpg-query.d.ts: -------------------------------------------------------------------------------- 1 | declare module './libpg-query.js' { 2 | interface WasmModule { 3 | _malloc: (size: number) => number; 4 | _free: (ptr: number) => void; 5 | _wasm_free_string: (ptr: number) => void; 6 | _wasm_parse_query: (queryPtr: number) => number; 7 | _wasm_deparse_protobuf: (dataPtr: number, length: number) => number; 8 | _wasm_parse_plpgsql: (queryPtr: number) => number; 9 | _wasm_fingerprint: (queryPtr: number) => number; 10 | _wasm_normalize_query: (queryPtr: number) => number; 11 | lengthBytesUTF8: (str: string) => number; 12 | stringToUTF8: (str: string, ptr: number, len: number) => void; 13 | UTF8ToString: (ptr: number) => string; 14 | HEAPU8: Uint8Array; 15 | } 16 | 17 | const PgQueryModule: () => Promise; 18 | export default PgQueryModule; 19 | } -------------------------------------------------------------------------------- /LOADING_WASM.md: -------------------------------------------------------------------------------- 1 | ### ⚙️ TL;DR — Serving the `.wasm` File 2 | 3 | The core issue isn’t the library — it’s that the **`.wasm` file lives in `node_modules` and isn’t automatically served** by Next.js, Webpack, or Turbopack. 4 | You just need to make sure it’s fetchable at runtime. 5 | 6 | #### ✅ Easiest Fix 7 | 8 | Copy the `.wasm` file once and serve it from `/public`: 9 | 10 | ```bash 11 | cp node_modules/libpg-query/wasm/libpg-query.wasm public/ 12 | ``` 13 | 14 | #### ⚠️ Why 15 | 16 | Bundlers don’t emit `.wasm` files by default — they stay inside `node_modules`, so the runtime can’t fetch them. 17 | 18 | #### 🧩 Workarounds 19 | 20 | * **Next.js + Webpack:** Add a `.wasm` asset rule or use the copy method. 21 | * **Turbopack:** Only the copy method works for now. 22 | * **Dev mode:** Optionally use a watcher script to auto-copy on rebuilds. -------------------------------------------------------------------------------- /.npmrc: -------------------------------------------------------------------------------- 1 | # PNPM workspace optimization settings 2 | 3 | # Use hard links to save disk space (when possible) 4 | node-linker=hoisted 5 | 6 | # Strict peer dependency resolution 7 | strict-peer-dependencies=true 8 | 9 | # Auto-install peers (useful for workspace packages) 10 | auto-install-peers=true 11 | 12 | # Save exact versions in package.json 13 | save-exact=true 14 | 15 | # Use workspace protocol for local dependencies 16 | link-workspace-packages=true 17 | 18 | # Prefer workspace packages over registry 19 | prefer-workspace-packages=true 20 | 21 | # Hoist pattern for shared dependencies 22 | # This helps reduce duplication 23 | public-hoist-pattern[]=*types* 24 | public-hoist-pattern[]=*eslint* 25 | public-hoist-pattern[]=*prettier* 26 | 27 | # Shamefully hoist these common dev dependencies 28 | shamefully-hoist=false 29 | 30 | # Enable workspace protocol 31 | enable-pre-post-scripts=true -------------------------------------------------------------------------------- /REPO_NOTES.md: -------------------------------------------------------------------------------- 1 | ⚠️ Due to the managing of many versions, we do have some duplication, please beware! 2 | 3 | There is a templates/ dir to solve some of this. 4 | 5 | ## Code Duplication 📋 6 | 7 | ### 1. Identical Test Files 8 | - All `versions/*/test/errors.test.js` files are identical (324 lines each) 9 | - All `versions/*/test/parsing.test.js` files are identical (89 lines each) 10 | - **Recommendation**: Consider using the template approach mentioned by the user 11 | 12 | ### 2. Nearly Identical Source Files 13 | - `versions/*/src/index.ts` are nearly identical except for version numbers 14 | - `versions/*/src/wasm_wrapper.c` are identical 15 | - `versions/*/Makefile` differ only in: 16 | - `LIBPG_QUERY_TAG` version 17 | - Version 13 has an extra emscripten patch 18 | 19 | ## Consistency Issues 🔧 20 | 21 | ### 1. Version 13 Makefile Difference 22 | - Version 13 applies an extra patch: `emscripten_disable_spinlocks.patch` 23 | - Other versions don't have this patch 24 | - **Status**: Patch file exists and is likely needed for v13 compatibility -------------------------------------------------------------------------------- /templates/wasm_wrapper.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | static int validate_input(const char* input) { 7 | return input != NULL && strlen(input) > 0; 8 | } 9 | 10 | static void* safe_malloc(size_t size) { 11 | void* ptr = malloc(size); 12 | if (!ptr && size > 0) { 13 | return NULL; 14 | } 15 | return ptr; 16 | } 17 | 18 | // Raw struct access functions for parse 19 | EMSCRIPTEN_KEEPALIVE 20 | PgQueryParseResult* wasm_parse_query_raw(const char* input) { 21 | if (!validate_input(input)) { 22 | return NULL; 23 | } 24 | 25 | PgQueryParseResult* result = (PgQueryParseResult*)safe_malloc(sizeof(PgQueryParseResult)); 26 | if (!result) { 27 | return NULL; 28 | } 29 | 30 | *result = pg_query_parse(input); 31 | return result; 32 | } 33 | 34 | EMSCRIPTEN_KEEPALIVE 35 | void wasm_free_parse_result(PgQueryParseResult* result) { 36 | if (result) { 37 | pg_query_free_parse_result(*result); 38 | free(result); 39 | } 40 | } -------------------------------------------------------------------------------- /full/scripts/build.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs'); 2 | const path = require('path'); 3 | const { execSync } = require('child_process'); 4 | 5 | // Run TypeScript compilation 6 | console.log('Compiling TypeScript...'); 7 | execSync('tsc', { stdio: 'inherit' }); 8 | execSync('tsc -p tsconfig.esm.json', { stdio: 'inherit' }); 9 | 10 | // Rename files to have correct extensions 11 | const wasmDir = path.join(__dirname, '../wasm'); 12 | const cjsDir = path.join(__dirname, '../cjs'); 13 | const esmDir = path.join(__dirname, '../esm'); 14 | 15 | // Ensure wasm directory exists 16 | if (!fs.existsSync(wasmDir)) { 17 | fs.mkdirSync(wasmDir, { recursive: true }); 18 | } 19 | 20 | // Rename CommonJS files 21 | fs.renameSync( 22 | path.join(cjsDir, 'index.js'), 23 | path.join(wasmDir, 'index.cjs') 24 | ); 25 | 26 | // Rename ESM files 27 | fs.renameSync( 28 | path.join(esmDir, 'index.js'), 29 | path.join(wasmDir, 'index.js') 30 | ); 31 | 32 | // Rename declaration files 33 | fs.renameSync( 34 | path.join(cjsDir, 'index.d.ts'), 35 | path.join(wasmDir, 'index.d.ts') 36 | ); 37 | 38 | console.log('Build completed successfully!'); -------------------------------------------------------------------------------- /versions/13/patches/emscripten_disable_spinlocks.patch: -------------------------------------------------------------------------------- 1 | --- a/Makefile 2 | +++ b/Makefile 3 | @@ -36,6 +36,11 @@ OBJ_FILES := $(filter-out $(NOT_OBJ_FILES), $(SRC_FILES:.c=.o)) 4 | override CFLAGS += -g -I. -I./vendor -I./src/postgres/include -Wall -Wno-unused-function -Wno-unused-value -Wno-unused-variable -fno-strict-aliasing -fwrapv -fPIC 5 | 6 | override PG_CONFIGURE_FLAGS += -q --without-readline --without-zlib 7 | + 8 | +# Disable spinlocks when building with Emscripten 9 | +ifdef EMSCRIPTEN 10 | +override PG_CONFIGURE_FLAGS += --disable-spinlocks 11 | +endif 12 | 13 | override TEST_CFLAGS += -I. -I./vendor -g 14 | override TEST_LDFLAGS += -pthread 15 | @@ -149,6 +154,9 @@ extract_source: $(PGDIR) 16 | echo "#undef LOCALE_T_IN_XLOCALE" >> ./src/postgres/include/pg_config.h 17 | echo "#undef WCSTOMBS_L_IN_XLOCALE" >> ./src/postgres/include/pg_config.h 18 | # Support 32-bit systems without reconfiguring 19 | +ifdef EMSCRIPTEN 20 | + echo "#undef HAVE_SPINLOCKS" >> ./src/postgres/include/pg_config.h 21 | +endif 22 | echo "#undef PG_INT128_TYPE" >> ./src/postgres/include/pg_config.h 23 | # Support gcc earlier than 4.6.0 without reconfiguring 24 | echo "#undef HAVE__STATIC_ASSERT" >> ./src/postgres/include/pg_config.h -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2021 Dan Lynch 4 | Copyright (c) 2025 Constructive 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in all 14 | copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | SOFTWARE. 23 | -------------------------------------------------------------------------------- /full/scripts/protogen.js: -------------------------------------------------------------------------------- 1 | const { exec } = require('child_process'); 2 | 3 | // IMPORTANT — SEE ISSUE: https://github.com/constructive-io/libpg-query-node/issues/92 4 | 5 | // Configuration Variables 6 | const branchName = '17-6.1.0'; 7 | const protoUrl = `https://raw.githubusercontent.com/pganalyze/libpg_query/${branchName}/protobuf/pg_query.proto`; 8 | const inFile = 'libpg_query/protobuf/pg_query.proto'; 9 | const outFile = 'proto.js'; 10 | 11 | const protogenCmd = [ 12 | 'pg-proto-parser', 13 | 'protogen', 14 | '--protoUrl', 15 | protoUrl, 16 | '--inFile', 17 | inFile, 18 | '--outFile', 19 | outFile, 20 | '--originalPackageName', 21 | 'protobufjs/minimal', 22 | '--newPackageName', 23 | '@launchql/protobufjs/minimal' 24 | ]; 25 | 26 | // Step 2: Generate proto.js using pbjs (Assuming pbjs is installed and accessible) 27 | function generateProtoJS(callback) { 28 | exec(protogenCmd.join(' '), (error, stdout, stderr) => { 29 | if (error) { 30 | console.error(`Error during code generation: ${error.message}`); 31 | return; 32 | } 33 | console.log('Generated proto.js from proto file.'); 34 | callback(); 35 | }); 36 | } 37 | 38 | generateProtoJS(() => { 39 | console.log('all done 🎉'); 40 | }); -------------------------------------------------------------------------------- /templates/LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2021 Dan Lynch 4 | Copyright (c) 2025 Constructive 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in all 14 | copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | SOFTWARE. 23 | -------------------------------------------------------------------------------- /versions/13/LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2021 Dan Lynch 4 | Copyright (c) 2025 Constructive 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in all 14 | copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | SOFTWARE. 23 | -------------------------------------------------------------------------------- /versions/14/LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2021 Dan Lynch 4 | Copyright (c) 2025 Constructive 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in all 14 | copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | SOFTWARE. 23 | -------------------------------------------------------------------------------- /versions/15/LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2021 Dan Lynch 4 | Copyright (c) 2025 Constructive 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in all 14 | copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | SOFTWARE. 23 | -------------------------------------------------------------------------------- /versions/16/LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2021 Dan Lynch 4 | Copyright (c) 2025 Constructive 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in all 14 | copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | SOFTWARE. 23 | -------------------------------------------------------------------------------- /versions/17/LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2021 Dan Lynch 4 | Copyright (c) 2025 Constructive 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in all 14 | copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | SOFTWARE. 23 | -------------------------------------------------------------------------------- /types/13/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Change Log 2 | 3 | All notable changes to this project will be documented in this file. 4 | See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. 5 | 6 | ## [17.4.2](https://github.com/constructive-io/pgsql-parser/compare/@pgsql/types@17.4.1...@pgsql/types@17.4.2) (2025-06-22) 7 | 8 | **Note:** Version bump only for package @pgsql/types 9 | 10 | 11 | 12 | 13 | 14 | ## [17.4.1](https://github.com/constructive-io/pgsql-parser/compare/@pgsql/types@17.4.0...@pgsql/types@17.4.1) (2025-06-21) 15 | 16 | **Note:** Version bump only for package @pgsql/types 17 | 18 | 19 | 20 | 21 | 22 | # [17.4.0](https://github.com/constructive-io/pgsql-parser/compare/@pgsql/types@17.1.0...@pgsql/types@17.4.0) (2025-06-21) 23 | 24 | **Note:** Version bump only for package @pgsql/types 25 | 26 | 27 | 28 | 29 | 30 | # [17.2.0](https://github.com/constructive-io/pgsql-parser/compare/@pgsql/types@17.1.0...@pgsql/types@17.2.0) (2025-06-21) 31 | 32 | **Note:** Version bump only for package @pgsql/types 33 | 34 | 35 | 36 | 37 | 38 | # [17.1.0](https://github.com/constructive-io/pgsql-parser/compare/@pgsql/types@13.9.0...@pgsql/types@17.1.0) (2025-06-21) 39 | 40 | **Note:** Version bump only for package @pgsql/types 41 | -------------------------------------------------------------------------------- /types/14/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Change Log 2 | 3 | All notable changes to this project will be documented in this file. 4 | See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. 5 | 6 | ## [17.4.2](https://github.com/constructive-io/pgsql-parser/compare/@pgsql/types@17.4.1...@pgsql/types@17.4.2) (2025-06-22) 7 | 8 | **Note:** Version bump only for package @pgsql/types 9 | 10 | 11 | 12 | 13 | 14 | ## [17.4.1](https://github.com/constructive-io/pgsql-parser/compare/@pgsql/types@17.4.0...@pgsql/types@17.4.1) (2025-06-21) 15 | 16 | **Note:** Version bump only for package @pgsql/types 17 | 18 | 19 | 20 | 21 | 22 | # [17.4.0](https://github.com/constructive-io/pgsql-parser/compare/@pgsql/types@17.1.0...@pgsql/types@17.4.0) (2025-06-21) 23 | 24 | **Note:** Version bump only for package @pgsql/types 25 | 26 | 27 | 28 | 29 | 30 | # [17.2.0](https://github.com/constructive-io/pgsql-parser/compare/@pgsql/types@17.1.0...@pgsql/types@17.2.0) (2025-06-21) 31 | 32 | **Note:** Version bump only for package @pgsql/types 33 | 34 | 35 | 36 | 37 | 38 | # [17.1.0](https://github.com/constructive-io/pgsql-parser/compare/@pgsql/types@13.9.0...@pgsql/types@17.1.0) (2025-06-21) 39 | 40 | **Note:** Version bump only for package @pgsql/types 41 | -------------------------------------------------------------------------------- /types/15/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Change Log 2 | 3 | All notable changes to this project will be documented in this file. 4 | See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. 5 | 6 | ## [17.4.2](https://github.com/constructive-io/pgsql-parser/compare/@pgsql/types@17.4.1...@pgsql/types@17.4.2) (2025-06-22) 7 | 8 | **Note:** Version bump only for package @pgsql/types 9 | 10 | 11 | 12 | 13 | 14 | ## [17.4.1](https://github.com/constructive-io/pgsql-parser/compare/@pgsql/types@17.4.0...@pgsql/types@17.4.1) (2025-06-21) 15 | 16 | **Note:** Version bump only for package @pgsql/types 17 | 18 | 19 | 20 | 21 | 22 | # [17.4.0](https://github.com/constructive-io/pgsql-parser/compare/@pgsql/types@17.1.0...@pgsql/types@17.4.0) (2025-06-21) 23 | 24 | **Note:** Version bump only for package @pgsql/types 25 | 26 | 27 | 28 | 29 | 30 | # [17.2.0](https://github.com/constructive-io/pgsql-parser/compare/@pgsql/types@17.1.0...@pgsql/types@17.2.0) (2025-06-21) 31 | 32 | **Note:** Version bump only for package @pgsql/types 33 | 34 | 35 | 36 | 37 | 38 | # [17.1.0](https://github.com/constructive-io/pgsql-parser/compare/@pgsql/types@13.9.0...@pgsql/types@17.1.0) (2025-06-21) 39 | 40 | **Note:** Version bump only for package @pgsql/types 41 | -------------------------------------------------------------------------------- /types/16/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Change Log 2 | 3 | All notable changes to this project will be documented in this file. 4 | See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. 5 | 6 | ## [17.4.2](https://github.com/constructive-io/pgsql-parser/compare/@pgsql/types@17.4.1...@pgsql/types@17.4.2) (2025-06-22) 7 | 8 | **Note:** Version bump only for package @pgsql/types 9 | 10 | 11 | 12 | 13 | 14 | ## [17.4.1](https://github.com/constructive-io/pgsql-parser/compare/@pgsql/types@17.4.0...@pgsql/types@17.4.1) (2025-06-21) 15 | 16 | **Note:** Version bump only for package @pgsql/types 17 | 18 | 19 | 20 | 21 | 22 | # [17.4.0](https://github.com/constructive-io/pgsql-parser/compare/@pgsql/types@17.1.0...@pgsql/types@17.4.0) (2025-06-21) 23 | 24 | **Note:** Version bump only for package @pgsql/types 25 | 26 | 27 | 28 | 29 | 30 | # [17.2.0](https://github.com/constructive-io/pgsql-parser/compare/@pgsql/types@17.1.0...@pgsql/types@17.2.0) (2025-06-21) 31 | 32 | **Note:** Version bump only for package @pgsql/types 33 | 34 | 35 | 36 | 37 | 38 | # [17.1.0](https://github.com/constructive-io/pgsql-parser/compare/@pgsql/types@13.9.0...@pgsql/types@17.1.0) (2025-06-21) 39 | 40 | **Note:** Version bump only for package @pgsql/types 41 | -------------------------------------------------------------------------------- /types/17/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Change Log 2 | 3 | All notable changes to this project will be documented in this file. 4 | See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. 5 | 6 | ## [17.4.2](https://github.com/constructive-io/pgsql-parser/compare/@pgsql/types@17.4.1...@pgsql/types@17.4.2) (2025-06-22) 7 | 8 | **Note:** Version bump only for package @pgsql/types 9 | 10 | 11 | 12 | 13 | 14 | ## [17.4.1](https://github.com/constructive-io/pgsql-parser/compare/@pgsql/types@17.4.0...@pgsql/types@17.4.1) (2025-06-21) 15 | 16 | **Note:** Version bump only for package @pgsql/types 17 | 18 | 19 | 20 | 21 | 22 | # [17.4.0](https://github.com/constructive-io/pgsql-parser/compare/@pgsql/types@17.1.0...@pgsql/types@17.4.0) (2025-06-21) 23 | 24 | **Note:** Version bump only for package @pgsql/types 25 | 26 | 27 | 28 | 29 | 30 | # [17.2.0](https://github.com/constructive-io/pgsql-parser/compare/@pgsql/types@17.1.0...@pgsql/types@17.2.0) (2025-06-21) 31 | 32 | **Note:** Version bump only for package @pgsql/types 33 | 34 | 35 | 36 | 37 | 38 | # [17.1.0](https://github.com/constructive-io/pgsql-parser/compare/@pgsql/types@13.9.0...@pgsql/types@17.1.0) (2025-06-21) 39 | 40 | **Note:** Version bump only for package @pgsql/types 41 | -------------------------------------------------------------------------------- /versions/13/scripts/build.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs'); 2 | const path = require('path'); 3 | const { execSync } = require('child_process'); 4 | 5 | // Run TypeScript compilation 6 | console.log('Compiling TypeScript...'); 7 | const tscPath = path.join(__dirname, '../../../node_modules/.bin/tsc'); 8 | execSync(`${tscPath}`, { stdio: 'inherit', cwd: path.join(__dirname, '..') }); 9 | execSync(`${tscPath} -p tsconfig.esm.json`, { stdio: 'inherit', cwd: path.join(__dirname, '..') }); 10 | 11 | // Rename files to have correct extensions 12 | const wasmDir = path.join(__dirname, '../wasm'); 13 | const cjsDir = path.join(__dirname, '../cjs'); 14 | const esmDir = path.join(__dirname, '../esm'); 15 | 16 | // Ensure wasm directory exists 17 | if (!fs.existsSync(wasmDir)) { 18 | fs.mkdirSync(wasmDir, { recursive: true }); 19 | } 20 | 21 | // Rename CommonJS files 22 | fs.renameSync( 23 | path.join(cjsDir, 'index.js'), 24 | path.join(wasmDir, 'index.cjs') 25 | ); 26 | 27 | // Rename ESM files 28 | fs.renameSync( 29 | path.join(esmDir, 'index.js'), 30 | path.join(wasmDir, 'index.js') 31 | ); 32 | 33 | // Rename declaration files 34 | fs.renameSync( 35 | path.join(cjsDir, 'index.d.ts'), 36 | path.join(wasmDir, 'index.d.ts') 37 | ); 38 | 39 | console.log('Build completed successfully!'); -------------------------------------------------------------------------------- /versions/14/scripts/build.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs'); 2 | const path = require('path'); 3 | const { execSync } = require('child_process'); 4 | 5 | // Run TypeScript compilation 6 | console.log('Compiling TypeScript...'); 7 | const tscPath = path.join(__dirname, '../../../node_modules/.bin/tsc'); 8 | execSync(`${tscPath}`, { stdio: 'inherit', cwd: path.join(__dirname, '..') }); 9 | execSync(`${tscPath} -p tsconfig.esm.json`, { stdio: 'inherit', cwd: path.join(__dirname, '..') }); 10 | 11 | // Rename files to have correct extensions 12 | const wasmDir = path.join(__dirname, '../wasm'); 13 | const cjsDir = path.join(__dirname, '../cjs'); 14 | const esmDir = path.join(__dirname, '../esm'); 15 | 16 | // Ensure wasm directory exists 17 | if (!fs.existsSync(wasmDir)) { 18 | fs.mkdirSync(wasmDir, { recursive: true }); 19 | } 20 | 21 | // Rename CommonJS files 22 | fs.renameSync( 23 | path.join(cjsDir, 'index.js'), 24 | path.join(wasmDir, 'index.cjs') 25 | ); 26 | 27 | // Rename ESM files 28 | fs.renameSync( 29 | path.join(esmDir, 'index.js'), 30 | path.join(wasmDir, 'index.js') 31 | ); 32 | 33 | // Rename declaration files 34 | fs.renameSync( 35 | path.join(cjsDir, 'index.d.ts'), 36 | path.join(wasmDir, 'index.d.ts') 37 | ); 38 | 39 | console.log('Build completed successfully!'); -------------------------------------------------------------------------------- /versions/15/scripts/build.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs'); 2 | const path = require('path'); 3 | const { execSync } = require('child_process'); 4 | 5 | // Run TypeScript compilation 6 | console.log('Compiling TypeScript...'); 7 | const tscPath = path.join(__dirname, '../../../node_modules/.bin/tsc'); 8 | execSync(`${tscPath}`, { stdio: 'inherit', cwd: path.join(__dirname, '..') }); 9 | execSync(`${tscPath} -p tsconfig.esm.json`, { stdio: 'inherit', cwd: path.join(__dirname, '..') }); 10 | 11 | // Rename files to have correct extensions 12 | const wasmDir = path.join(__dirname, '../wasm'); 13 | const cjsDir = path.join(__dirname, '../cjs'); 14 | const esmDir = path.join(__dirname, '../esm'); 15 | 16 | // Ensure wasm directory exists 17 | if (!fs.existsSync(wasmDir)) { 18 | fs.mkdirSync(wasmDir, { recursive: true }); 19 | } 20 | 21 | // Rename CommonJS files 22 | fs.renameSync( 23 | path.join(cjsDir, 'index.js'), 24 | path.join(wasmDir, 'index.cjs') 25 | ); 26 | 27 | // Rename ESM files 28 | fs.renameSync( 29 | path.join(esmDir, 'index.js'), 30 | path.join(wasmDir, 'index.js') 31 | ); 32 | 33 | // Rename declaration files 34 | fs.renameSync( 35 | path.join(cjsDir, 'index.d.ts'), 36 | path.join(wasmDir, 'index.d.ts') 37 | ); 38 | 39 | console.log('Build completed successfully!'); -------------------------------------------------------------------------------- /versions/16/scripts/build.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs'); 2 | const path = require('path'); 3 | const { execSync } = require('child_process'); 4 | 5 | // Run TypeScript compilation 6 | console.log('Compiling TypeScript...'); 7 | const tscPath = path.join(__dirname, '../../../node_modules/.bin/tsc'); 8 | execSync(`${tscPath}`, { stdio: 'inherit', cwd: path.join(__dirname, '..') }); 9 | execSync(`${tscPath} -p tsconfig.esm.json`, { stdio: 'inherit', cwd: path.join(__dirname, '..') }); 10 | 11 | // Rename files to have correct extensions 12 | const wasmDir = path.join(__dirname, '../wasm'); 13 | const cjsDir = path.join(__dirname, '../cjs'); 14 | const esmDir = path.join(__dirname, '../esm'); 15 | 16 | // Ensure wasm directory exists 17 | if (!fs.existsSync(wasmDir)) { 18 | fs.mkdirSync(wasmDir, { recursive: true }); 19 | } 20 | 21 | // Rename CommonJS files 22 | fs.renameSync( 23 | path.join(cjsDir, 'index.js'), 24 | path.join(wasmDir, 'index.cjs') 25 | ); 26 | 27 | // Rename ESM files 28 | fs.renameSync( 29 | path.join(esmDir, 'index.js'), 30 | path.join(wasmDir, 'index.js') 31 | ); 32 | 33 | // Rename declaration files 34 | fs.renameSync( 35 | path.join(cjsDir, 'index.d.ts'), 36 | path.join(wasmDir, 'index.d.ts') 37 | ); 38 | 39 | console.log('Build completed successfully!'); -------------------------------------------------------------------------------- /versions/17/scripts/build.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs'); 2 | const path = require('path'); 3 | const { execSync } = require('child_process'); 4 | 5 | // Run TypeScript compilation 6 | console.log('Compiling TypeScript...'); 7 | const tscPath = path.join(__dirname, '../../../node_modules/.bin/tsc'); 8 | execSync(`${tscPath}`, { stdio: 'inherit', cwd: path.join(__dirname, '..') }); 9 | execSync(`${tscPath} -p tsconfig.esm.json`, { stdio: 'inherit', cwd: path.join(__dirname, '..') }); 10 | 11 | // Rename files to have correct extensions 12 | const wasmDir = path.join(__dirname, '../wasm'); 13 | const cjsDir = path.join(__dirname, '../cjs'); 14 | const esmDir = path.join(__dirname, '../esm'); 15 | 16 | // Ensure wasm directory exists 17 | if (!fs.existsSync(wasmDir)) { 18 | fs.mkdirSync(wasmDir, { recursive: true }); 19 | } 20 | 21 | // Rename CommonJS files 22 | fs.renameSync( 23 | path.join(cjsDir, 'index.js'), 24 | path.join(wasmDir, 'index.cjs') 25 | ); 26 | 27 | // Rename ESM files 28 | fs.renameSync( 29 | path.join(esmDir, 'index.js'), 30 | path.join(wasmDir, 'index.js') 31 | ); 32 | 33 | // Rename declaration files 34 | fs.renameSync( 35 | path.join(cjsDir, 'index.d.ts'), 36 | path.join(wasmDir, 'index.d.ts') 37 | ); 38 | 39 | console.log('Build completed successfully!'); -------------------------------------------------------------------------------- /versions/13/src/wasm_wrapper.c: -------------------------------------------------------------------------------- 1 | /** 2 | * DO NOT MODIFY MANUALLY — this is generated from the templates dir 3 | * 4 | * To make changes, edit the files in the templates/ directory and run: 5 | * npm run copy:templates 6 | */ 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | static int validate_input(const char* input) { 14 | return input != NULL && strlen(input) > 0; 15 | } 16 | 17 | static void* safe_malloc(size_t size) { 18 | void* ptr = malloc(size); 19 | if (!ptr && size > 0) { 20 | return NULL; 21 | } 22 | return ptr; 23 | } 24 | 25 | // Raw struct access functions for parse 26 | EMSCRIPTEN_KEEPALIVE 27 | PgQueryParseResult* wasm_parse_query_raw(const char* input) { 28 | if (!validate_input(input)) { 29 | return NULL; 30 | } 31 | 32 | PgQueryParseResult* result = (PgQueryParseResult*)safe_malloc(sizeof(PgQueryParseResult)); 33 | if (!result) { 34 | return NULL; 35 | } 36 | 37 | *result = pg_query_parse(input); 38 | return result; 39 | } 40 | 41 | EMSCRIPTEN_KEEPALIVE 42 | void wasm_free_parse_result(PgQueryParseResult* result) { 43 | if (result) { 44 | pg_query_free_parse_result(*result); 45 | free(result); 46 | } 47 | } -------------------------------------------------------------------------------- /versions/14/src/wasm_wrapper.c: -------------------------------------------------------------------------------- 1 | /** 2 | * DO NOT MODIFY MANUALLY — this is generated from the templates dir 3 | * 4 | * To make changes, edit the files in the templates/ directory and run: 5 | * npm run copy:templates 6 | */ 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | static int validate_input(const char* input) { 14 | return input != NULL && strlen(input) > 0; 15 | } 16 | 17 | static void* safe_malloc(size_t size) { 18 | void* ptr = malloc(size); 19 | if (!ptr && size > 0) { 20 | return NULL; 21 | } 22 | return ptr; 23 | } 24 | 25 | // Raw struct access functions for parse 26 | EMSCRIPTEN_KEEPALIVE 27 | PgQueryParseResult* wasm_parse_query_raw(const char* input) { 28 | if (!validate_input(input)) { 29 | return NULL; 30 | } 31 | 32 | PgQueryParseResult* result = (PgQueryParseResult*)safe_malloc(sizeof(PgQueryParseResult)); 33 | if (!result) { 34 | return NULL; 35 | } 36 | 37 | *result = pg_query_parse(input); 38 | return result; 39 | } 40 | 41 | EMSCRIPTEN_KEEPALIVE 42 | void wasm_free_parse_result(PgQueryParseResult* result) { 43 | if (result) { 44 | pg_query_free_parse_result(*result); 45 | free(result); 46 | } 47 | } -------------------------------------------------------------------------------- /versions/15/src/wasm_wrapper.c: -------------------------------------------------------------------------------- 1 | /** 2 | * DO NOT MODIFY MANUALLY — this is generated from the templates dir 3 | * 4 | * To make changes, edit the files in the templates/ directory and run: 5 | * npm run copy:templates 6 | */ 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | static int validate_input(const char* input) { 14 | return input != NULL && strlen(input) > 0; 15 | } 16 | 17 | static void* safe_malloc(size_t size) { 18 | void* ptr = malloc(size); 19 | if (!ptr && size > 0) { 20 | return NULL; 21 | } 22 | return ptr; 23 | } 24 | 25 | // Raw struct access functions for parse 26 | EMSCRIPTEN_KEEPALIVE 27 | PgQueryParseResult* wasm_parse_query_raw(const char* input) { 28 | if (!validate_input(input)) { 29 | return NULL; 30 | } 31 | 32 | PgQueryParseResult* result = (PgQueryParseResult*)safe_malloc(sizeof(PgQueryParseResult)); 33 | if (!result) { 34 | return NULL; 35 | } 36 | 37 | *result = pg_query_parse(input); 38 | return result; 39 | } 40 | 41 | EMSCRIPTEN_KEEPALIVE 42 | void wasm_free_parse_result(PgQueryParseResult* result) { 43 | if (result) { 44 | pg_query_free_parse_result(*result); 45 | free(result); 46 | } 47 | } -------------------------------------------------------------------------------- /versions/16/src/wasm_wrapper.c: -------------------------------------------------------------------------------- 1 | /** 2 | * DO NOT MODIFY MANUALLY — this is generated from the templates dir 3 | * 4 | * To make changes, edit the files in the templates/ directory and run: 5 | * npm run copy:templates 6 | */ 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | static int validate_input(const char* input) { 14 | return input != NULL && strlen(input) > 0; 15 | } 16 | 17 | static void* safe_malloc(size_t size) { 18 | void* ptr = malloc(size); 19 | if (!ptr && size > 0) { 20 | return NULL; 21 | } 22 | return ptr; 23 | } 24 | 25 | // Raw struct access functions for parse 26 | EMSCRIPTEN_KEEPALIVE 27 | PgQueryParseResult* wasm_parse_query_raw(const char* input) { 28 | if (!validate_input(input)) { 29 | return NULL; 30 | } 31 | 32 | PgQueryParseResult* result = (PgQueryParseResult*)safe_malloc(sizeof(PgQueryParseResult)); 33 | if (!result) { 34 | return NULL; 35 | } 36 | 37 | *result = pg_query_parse(input); 38 | return result; 39 | } 40 | 41 | EMSCRIPTEN_KEEPALIVE 42 | void wasm_free_parse_result(PgQueryParseResult* result) { 43 | if (result) { 44 | pg_query_free_parse_result(*result); 45 | free(result); 46 | } 47 | } -------------------------------------------------------------------------------- /versions/17/src/wasm_wrapper.c: -------------------------------------------------------------------------------- 1 | /** 2 | * DO NOT MODIFY MANUALLY — this is generated from the templates dir 3 | * 4 | * To make changes, edit the files in the templates/ directory and run: 5 | * npm run copy:templates 6 | */ 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | static int validate_input(const char* input) { 14 | return input != NULL && strlen(input) > 0; 15 | } 16 | 17 | static void* safe_malloc(size_t size) { 18 | void* ptr = malloc(size); 19 | if (!ptr && size > 0) { 20 | return NULL; 21 | } 22 | return ptr; 23 | } 24 | 25 | // Raw struct access functions for parse 26 | EMSCRIPTEN_KEEPALIVE 27 | PgQueryParseResult* wasm_parse_query_raw(const char* input) { 28 | if (!validate_input(input)) { 29 | return NULL; 30 | } 31 | 32 | PgQueryParseResult* result = (PgQueryParseResult*)safe_malloc(sizeof(PgQueryParseResult)); 33 | if (!result) { 34 | return NULL; 35 | } 36 | 37 | *result = pg_query_parse(input); 38 | return result; 39 | } 40 | 41 | EMSCRIPTEN_KEEPALIVE 42 | void wasm_free_parse_result(PgQueryParseResult* result) { 43 | if (result) { 44 | pg_query_free_parse_result(*result); 45 | free(result); 46 | } 47 | } -------------------------------------------------------------------------------- /.github/workflows/build-wasm.yml: -------------------------------------------------------------------------------- 1 | name: Build Wasm 🛠 2 | 3 | on: 4 | workflow_dispatch: 5 | 6 | jobs: 7 | build-wasm: 8 | runs-on: macos-latest 9 | steps: 10 | - name: Checkout Repository 📥 11 | uses: actions/checkout@v4 12 | 13 | - name: Setup Node.js 🌐 14 | uses: actions/setup-node@v4 15 | with: 16 | node-version: '20.x' 17 | 18 | - name: Setup pnpm 📦 19 | uses: pnpm/action-setup@v2 20 | with: 21 | version: 8.15.0 22 | 23 | - name: Get pnpm store directory 📁 24 | shell: bash 25 | run: | 26 | echo "STORE_PATH=$(pnpm store path --silent)" >> $GITHUB_ENV 27 | 28 | - name: Setup pnpm cache 🗄️ 29 | uses: actions/cache@v3 30 | with: 31 | path: ${{ env.STORE_PATH }} 32 | key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }} 33 | restore-keys: | 34 | ${{ runner.os }}-pnpm-store- 35 | 36 | - name: Install Dependencies 🧶 37 | run: pnpm install 38 | 39 | - name: Build WASM 🏗 40 | run: pnpm run build 41 | working-directory: full 42 | 43 | - name: Archive production artifacts 🏛 44 | uses: actions/upload-artifact@v4 45 | with: 46 | name: wasm-artifacts 47 | path: full/wasm/ 48 | retention-days: 7 49 | -------------------------------------------------------------------------------- /full/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # 17.2.1 2 | * Add normalize() and normalizeSync() functions for SQL normalization 3 | * Add fingerprint() and fingerprintSync() functions for query fingerprinting 4 | * Add isReady() function to check WASM module initialization status 5 | * Improve memory management and error handling in WASM wrapper 6 | * Remove unused dependencies (lodash, deasync, @launchql/protobufjs) 7 | * Split test suite into separate files for better organization 8 | * Update documentation with comprehensive function examples 9 | 10 | # 1.2.1 11 | * Rename package 12 | 13 | # 1.2.0 14 | * Add TS typings 15 | 16 | # 1.1.2 (07/23/19) 17 | * Fix build script 18 | 19 | # 1.1.0 (Republish, 07/23/19) 20 | * Rewrite to use Node-Addons-API (C++ wrapper for the stable N-API) 21 | * Support PL/PGSql Parsing 22 | * Support async parsing 23 | 24 | ## 0.0.5 (November 19, 2015) 25 | * Update libpg_query to include latest A_CONST fixes 26 | 27 | ## 0.0.4 (November 16, 2015) 28 | * Update libpg_query to include fix for empty string constants 29 | * Warning fixed in 0.0.3 is back for now until libpg_query has support for custom CFLAGS 30 | 31 | ## 0.0.3 (November 14, 2015) 32 | * Update OSX static library to include `-mmacosx-version-min=10.5` to fix warnings on installation 33 | 34 | ## 0.0.2 (November 14, 2015) 35 | * Rename repo to pg-query-native 36 | 37 | ## 0.0.1 (November 14, 2015) 38 | * First version 39 | -------------------------------------------------------------------------------- /scripts/README.md: -------------------------------------------------------------------------------- 1 | # Scripts Directory 2 | 3 | This directory contains various build and maintenance scripts for the libpg-query monorepo. 4 | 5 | ## Scripts 6 | 7 | ### copy-templates.js 8 | 9 | Copies template files from the `templates/` directory to each PostgreSQL version directory. 10 | 11 | **Usage:** 12 | ```bash 13 | npm run copy:templates 14 | ``` 15 | 16 | **Features:** 17 | - Processes template placeholders (e.g., `{{LIBPG_QUERY_TAG}}`) 18 | - Handles conditional blocks using mustache-like syntax 19 | - Adds auto-generated headers to source files 20 | - Maintains version-specific configurations 21 | 22 | **Version Configurations:** 23 | - Version 13: Uses emscripten patch (`useEmscriptenPatch: true`) 24 | - Versions 14-17: No special patches 25 | 26 | ### Other Scripts 27 | 28 | - `analyze-sizes.js` - Analyzes build artifact sizes 29 | - `fetch-protos.js` - Fetches protocol buffer definitions 30 | - `build-types.js` - Builds TypeScript type definitions 31 | - `prepare-types.js` - Prepares type definitions for publishing 32 | - `build-enums.js` - Builds enum definitions 33 | - `prepare-enums.js` - Prepares enum definitions for publishing 34 | - `publish-types.js` - Publishes @pgsql/types package 35 | - `publish-enums.js` - Publishes @pgsql/enums package 36 | - `publish-versions.js` - Publishes version-specific packages 37 | - `update-versions-types.js` - Updates type dependencies in version packages -------------------------------------------------------------------------------- /scripts/publish-single-version.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | const fs = require('fs'); 4 | const path = require('path'); 5 | const { execSync } = require('child_process'); 6 | 7 | const pkgPath = path.join(process.cwd(), 'package.json'); 8 | 9 | if (!fs.existsSync(pkgPath)) { 10 | console.error('❌ No package.json found in current directory.'); 11 | process.exit(1); 12 | } 13 | 14 | const original = JSON.parse(fs.readFileSync(pkgPath, 'utf8')); 15 | const publishMeta = original['x-publish'] || {}; 16 | 17 | const publishName = publishMeta.publishName || 'libpg-query'; 18 | const distTag = process.env.TAG || publishMeta.distTag || 'latest'; 19 | 20 | if (!original.name || !original.version) { 21 | console.error('❌ package.json must include name and version'); 22 | process.exit(1); 23 | } 24 | 25 | const modified = { ...original, name: publishName }; 26 | 27 | try { 28 | console.log(`📦 Publishing ${publishName}@${original.version} with tag '${distTag}'...`); 29 | fs.writeFileSync(pkgPath, JSON.stringify(modified, null, 2)); 30 | // npm OK here since it's version, not dist/ package... 31 | execSync(`npm publish --tag ${distTag}`, { stdio: 'inherit' }); 32 | console.log('✅ Publish complete.'); 33 | } catch (err) { 34 | console.error('❌ Publish failed:', err.message); 35 | } finally { 36 | fs.writeFileSync(pkgPath, JSON.stringify(original, null, 2)); 37 | console.log('🔄 Restored original package.json'); 38 | } 39 | -------------------------------------------------------------------------------- /enums/14/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@libpg-query/enums14", 3 | "version": "14.9.2", 4 | "author": "Constructive ", 5 | "description": "PostgreSQL AST enums from the real Postgres parser", 6 | "main": "index.js", 7 | "module": "esm/index.js", 8 | "types": "index.d.ts", 9 | "homepage": "https://github.com/constructive-io/libpg-query-node", 10 | "license": "MIT", 11 | "publishConfig": { 12 | "access": "public", 13 | "directory": "dist" 14 | }, 15 | "repository": { 16 | "type": "git", 17 | "url": "https://github.com/constructive-io/libpg-query-node" 18 | }, 19 | "bugs": { 20 | "url": "https://github.com/constructive-io/libpg-query-node/issues" 21 | }, 22 | "x-publish": { 23 | "publishName": "@pgsql/enums", 24 | "distTag": "pg14" 25 | }, 26 | "scripts": { 27 | "copy": "copyfiles -f ../../LICENSE README.md package.json dist", 28 | "clean": "rimraf dist", 29 | "build": "pnpm run clean && tsc && tsc -p tsconfig.esm.json && pnpm run copy", 30 | "build:dev": "pnpm run clean && tsc --declarationMap && tsc -p tsconfig.esm.json && pnpm run copy", 31 | "build:proto": "ts-node scripts/pg-proto-parser", 32 | "prepare:enums": "node -e \"require('../../scripts/prepare-enums.js').preparePackageForPublish('.')\"", 33 | "lint": "eslint . --fix" 34 | }, 35 | "keywords": [], 36 | "devDependencies": { 37 | "pg-proto-parser": "^1.28.2" 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /enums/15/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@libpg-query/enums15", 3 | "version": "15.9.2", 4 | "author": "Constructive ", 5 | "description": "PostgreSQL AST enums from the real Postgres parser", 6 | "main": "index.js", 7 | "module": "esm/index.js", 8 | "types": "index.d.ts", 9 | "homepage": "https://github.com/constructive-io/libpg-query-node", 10 | "license": "MIT", 11 | "publishConfig": { 12 | "access": "public", 13 | "directory": "dist" 14 | }, 15 | "repository": { 16 | "type": "git", 17 | "url": "https://github.com/constructive-io/libpg-query-node" 18 | }, 19 | "bugs": { 20 | "url": "https://github.com/constructive-io/libpg-query-node/issues" 21 | }, 22 | "x-publish": { 23 | "publishName": "@pgsql/enums", 24 | "distTag": "pg15" 25 | }, 26 | "scripts": { 27 | "copy": "copyfiles -f ../../LICENSE README.md package.json dist", 28 | "clean": "rimraf dist", 29 | "build": "pnpm run clean && tsc && tsc -p tsconfig.esm.json && pnpm run copy", 30 | "build:dev": "pnpm run clean && tsc --declarationMap && tsc -p tsconfig.esm.json && pnpm run copy", 31 | "build:proto": "ts-node scripts/pg-proto-parser", 32 | "prepare:enums": "node -e \"require('../../scripts/prepare-enums.js').preparePackageForPublish('.')\"", 33 | "lint": "eslint . --fix" 34 | }, 35 | "keywords": [], 36 | "devDependencies": { 37 | "pg-proto-parser": "^1.28.2" 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /enums/16/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@libpg-query/enums16", 3 | "version": "16.9.2", 4 | "author": "Constructive ", 5 | "description": "PostgreSQL AST enums from the real Postgres parser", 6 | "main": "index.js", 7 | "module": "esm/index.js", 8 | "types": "index.d.ts", 9 | "homepage": "https://github.com/constructive-io/libpg-query-node", 10 | "license": "MIT", 11 | "publishConfig": { 12 | "access": "public", 13 | "directory": "dist" 14 | }, 15 | "repository": { 16 | "type": "git", 17 | "url": "https://github.com/constructive-io/libpg-query-node" 18 | }, 19 | "bugs": { 20 | "url": "https://github.com/constructive-io/libpg-query-node/issues" 21 | }, 22 | "x-publish": { 23 | "publishName": "@pgsql/enums", 24 | "distTag": "pg16" 25 | }, 26 | "scripts": { 27 | "copy": "copyfiles -f ../../LICENSE README.md package.json dist", 28 | "clean": "rimraf dist", 29 | "build": "pnpm run clean && tsc && tsc -p tsconfig.esm.json && pnpm run copy", 30 | "build:dev": "pnpm run clean && tsc --declarationMap && tsc -p tsconfig.esm.json && pnpm run copy", 31 | "build:proto": "ts-node scripts/pg-proto-parser", 32 | "prepare:enums": "node -e \"require('../../scripts/prepare-enums.js').preparePackageForPublish('.')\"", 33 | "lint": "eslint . --fix" 34 | }, 35 | "keywords": [], 36 | "devDependencies": { 37 | "pg-proto-parser": "^1.28.2" 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /enums/17/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@libpg-query/enums17", 3 | "version": "17.9.2", 4 | "author": "Constructive ", 5 | "description": "PostgreSQL AST enums from the real Postgres parser", 6 | "main": "index.js", 7 | "module": "esm/index.js", 8 | "types": "index.d.ts", 9 | "homepage": "https://github.com/constructive-io/libpg-query-node", 10 | "license": "MIT", 11 | "publishConfig": { 12 | "access": "public", 13 | "directory": "dist" 14 | }, 15 | "repository": { 16 | "type": "git", 17 | "url": "https://github.com/constructive-io/libpg-query-node" 18 | }, 19 | "bugs": { 20 | "url": "https://github.com/constructive-io/libpg-query-node/issues" 21 | }, 22 | "x-publish": { 23 | "publishName": "@pgsql/enums", 24 | "distTag": "pg17" 25 | }, 26 | "scripts": { 27 | "copy": "copyfiles -f ../../LICENSE README.md package.json dist", 28 | "clean": "rimraf dist", 29 | "build": "pnpm run clean && tsc && tsc -p tsconfig.esm.json && pnpm run copy", 30 | "build:dev": "pnpm run clean && tsc --declarationMap && tsc -p tsconfig.esm.json && pnpm run copy", 31 | "build:proto": "ts-node scripts/pg-proto-parser", 32 | "prepare:enums": "node -e \"require('../../scripts/prepare-enums.js').preparePackageForPublish('.')\"", 33 | "lint": "eslint . --fix" 34 | }, 35 | "keywords": [], 36 | "devDependencies": { 37 | "pg-proto-parser": "^1.28.2" 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /types/14/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@libpg-query/types14", 3 | "version": "14.1.2", 4 | "author": "Constructive ", 5 | "description": "PostgreSQL AST types from the real Postgres parser", 6 | "main": "index.js", 7 | "module": "esm/index.js", 8 | "types": "index.d.ts", 9 | "homepage": "https://github.com/constructive-io/libpg-query-node", 10 | "license": "MIT", 11 | "publishConfig": { 12 | "access": "public", 13 | "directory": "dist" 14 | }, 15 | "repository": { 16 | "type": "git", 17 | "url": "https://github.com/constructive-io/libpg-query-node" 18 | }, 19 | "bugs": { 20 | "url": "https://github.com/constructive-io/libpg-query-node/issues" 21 | }, 22 | "x-publish": { 23 | "publishName": "@pgsql/types", 24 | "distTag": "pg14" 25 | }, 26 | "scripts": { 27 | "copy": "copyfiles -f ../../LICENSE README.md package.json dist", 28 | "clean": "rimraf dist", 29 | "build": "pnpm run clean && tsc && tsc -p tsconfig.esm.json && pnpm run copy", 30 | "build:dev": "pnpm run clean && tsc --declarationMap && tsc -p tsconfig.esm.json && pnpm run copy", 31 | "build:proto": "ts-node scripts/pg-proto-parser", 32 | "prepare:types": "node -e \"require('../../scripts/prepare-types.js').preparePackageForPublish('.')\"", 33 | "lint": "eslint . --fix" 34 | }, 35 | "keywords": [], 36 | "devDependencies": { 37 | "pg-proto-parser": "^1.28.2" 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /types/15/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@libpg-query/types15", 3 | "version": "15.1.2", 4 | "author": "Constructive ", 5 | "description": "PostgreSQL AST types from the real Postgres parser", 6 | "main": "index.js", 7 | "module": "esm/index.js", 8 | "types": "index.d.ts", 9 | "homepage": "https://github.com/constructive-io/libpg-query-node", 10 | "license": "MIT", 11 | "publishConfig": { 12 | "access": "public", 13 | "directory": "dist" 14 | }, 15 | "repository": { 16 | "type": "git", 17 | "url": "https://github.com/constructive-io/libpg-query-node" 18 | }, 19 | "bugs": { 20 | "url": "https://github.com/constructive-io/libpg-query-node/issues" 21 | }, 22 | "x-publish": { 23 | "publishName": "@pgsql/types", 24 | "distTag": "pg15" 25 | }, 26 | "scripts": { 27 | "copy": "copyfiles -f ../../LICENSE README.md package.json dist", 28 | "clean": "rimraf dist", 29 | "build": "pnpm run clean && tsc && tsc -p tsconfig.esm.json && pnpm run copy", 30 | "build:dev": "pnpm run clean && tsc --declarationMap && tsc -p tsconfig.esm.json && pnpm run copy", 31 | "build:proto": "ts-node scripts/pg-proto-parser", 32 | "prepare:types": "node -e \"require('../../scripts/prepare-types.js').preparePackageForPublish('.')\"", 33 | "lint": "eslint . --fix" 34 | }, 35 | "keywords": [], 36 | "devDependencies": { 37 | "pg-proto-parser": "^1.28.2" 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /types/16/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@libpg-query/types16", 3 | "version": "16.1.2", 4 | "author": "Constructive ", 5 | "description": "PostgreSQL AST types from the real Postgres parser", 6 | "main": "index.js", 7 | "module": "esm/index.js", 8 | "types": "index.d.ts", 9 | "homepage": "https://github.com/constructive-io/libpg-query-node", 10 | "license": "MIT", 11 | "publishConfig": { 12 | "access": "public", 13 | "directory": "dist" 14 | }, 15 | "repository": { 16 | "type": "git", 17 | "url": "https://github.com/constructive-io/libpg-query-node" 18 | }, 19 | "bugs": { 20 | "url": "https://github.com/constructive-io/libpg-query-node/issues" 21 | }, 22 | "x-publish": { 23 | "publishName": "@pgsql/types", 24 | "distTag": "pg16" 25 | }, 26 | "scripts": { 27 | "copy": "copyfiles -f ../../LICENSE README.md package.json dist", 28 | "clean": "rimraf dist", 29 | "build": "pnpm run clean && tsc && tsc -p tsconfig.esm.json && pnpm run copy", 30 | "build:dev": "pnpm run clean && tsc --declarationMap && tsc -p tsconfig.esm.json && pnpm run copy", 31 | "build:proto": "ts-node scripts/pg-proto-parser", 32 | "prepare:types": "node -e \"require('../../scripts/prepare-types.js').preparePackageForPublish('.')\"", 33 | "lint": "eslint . --fix" 34 | }, 35 | "keywords": [], 36 | "devDependencies": { 37 | "pg-proto-parser": "^1.28.2" 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /types/17/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@libpg-query/types17", 3 | "version": "17.6.2", 4 | "author": "Constructive ", 5 | "description": "PostgreSQL AST types from the real Postgres parser", 6 | "main": "index.js", 7 | "module": "esm/index.js", 8 | "types": "index.d.ts", 9 | "homepage": "https://github.com/constructive-io/libpg-query-node", 10 | "license": "MIT", 11 | "publishConfig": { 12 | "access": "public", 13 | "directory": "dist" 14 | }, 15 | "repository": { 16 | "type": "git", 17 | "url": "https://github.com/constructive-io/libpg-query-node" 18 | }, 19 | "bugs": { 20 | "url": "https://github.com/constructive-io/libpg-query-node/issues" 21 | }, 22 | "x-publish": { 23 | "publishName": "@pgsql/types", 24 | "distTag": "pg17" 25 | }, 26 | "scripts": { 27 | "copy": "copyfiles -f ../../LICENSE README.md package.json dist", 28 | "clean": "rimraf dist", 29 | "build": "pnpm run clean && tsc && tsc -p tsconfig.esm.json && pnpm run copy", 30 | "build:dev": "pnpm run clean && tsc --declarationMap && tsc -p tsconfig.esm.json && pnpm run copy", 31 | "build:proto": "ts-node scripts/pg-proto-parser", 32 | "prepare:types": "node -e \"require('../../scripts/prepare-types.js').preparePackageForPublish('.')\"", 33 | "lint": "eslint . --fix" 34 | }, 35 | "keywords": [], 36 | "devDependencies": { 37 | "pg-proto-parser": "^1.28.2" 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /enums/13/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@libpg-query/enums13", 3 | "version": "13.13.2", 4 | "author": "Constructive ", 5 | "description": "PostgreSQL AST enums from the real Postgres parser", 6 | "main": "index.js", 7 | "module": "esm/index.js", 8 | "types": "index.d.ts", 9 | "homepage": "https://github.com/constructive-io/libpg-query-node", 10 | "license": "MIT", 11 | "publishConfig": { 12 | "access": "public", 13 | "directory": "dist" 14 | }, 15 | "repository": { 16 | "type": "git", 17 | "url": "https://github.com/constructive-io/libpg-query-node" 18 | }, 19 | "bugs": { 20 | "url": "https://github.com/constructive-io/libpg-query-node/issues" 21 | }, 22 | "x-publish": { 23 | "publishName": "@pgsql/enums", 24 | "distTag": "pg13" 25 | }, 26 | "scripts": { 27 | "copy": "copyfiles -f ../../LICENSE README.md package.json dist", 28 | "clean": "rimraf dist", 29 | "build": "pnpm run clean && tsc && tsc -p tsconfig.esm.json && pnpm run copy", 30 | "build:dev": "pnpm run clean && tsc --declarationMap && tsc -p tsconfig.esm.json && pnpm run copy", 31 | "build:proto": "ts-node scripts/pg-proto-parser", 32 | "prepare:enums": "node -e \"require('../../scripts/prepare-enums.js').preparePackageForPublish('.')\"", 33 | "lint": "eslint . --fix" 34 | }, 35 | "keywords": [], 36 | "devDependencies": { 37 | "pg-proto-parser": "^1.28.2" 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /types/13/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@libpg-query/types13", 3 | "version": "13.11.2", 4 | "author": "Constructive ", 5 | "description": "PostgreSQL AST types from the real Postgres parser", 6 | "main": "index.js", 7 | "module": "esm/index.js", 8 | "types": "index.d.ts", 9 | "homepage": "https://github.com/constructive-io/libpg-query-node", 10 | "license": "MIT", 11 | "publishConfig": { 12 | "access": "public", 13 | "directory": "dist" 14 | }, 15 | "repository": { 16 | "type": "git", 17 | "url": "https://github.com/constructive-io/libpg-query-node" 18 | }, 19 | "bugs": { 20 | "url": "https://github.com/constructive-io/libpg-query-node/issues" 21 | }, 22 | "x-publish": { 23 | "publishName": "@pgsql/types", 24 | "distTag": "pg13" 25 | }, 26 | "scripts": { 27 | "copy": "copyfiles -f ../../LICENSE README.md package.json dist", 28 | "clean": "rimraf dist", 29 | "build": "pnpm run clean && tsc && tsc -p tsconfig.esm.json && pnpm run copy", 30 | "build:dev": "pnpm run clean && tsc --declarationMap && tsc -p tsconfig.esm.json && pnpm run copy", 31 | "build:proto": "ts-node scripts/pg-proto-parser", 32 | "prepare:types": "node -e \"require('../../scripts/prepare-types.js').preparePackageForPublish('.')\"", 33 | "lint": "eslint . --fix" 34 | }, 35 | "keywords": [], 36 | "devDependencies": { 37 | "pg-proto-parser": "^1.28.2" 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /versions/14/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@libpg-query/v14", 3 | "version": "14.4.3", 4 | "description": "The real PostgreSQL query parser", 5 | "homepage": "https://github.com/constructive-io/libpg-query-node", 6 | "main": "./wasm/index.cjs", 7 | "module": "./wasm/index.js", 8 | "typings": "./wasm/index.d.ts", 9 | "publishConfig": { 10 | "access": "public" 11 | }, 12 | "x-publish": { 13 | "publishName": "libpg-query", 14 | "pgVersion": "14", 15 | "distTag": "pg14", 16 | "libpgQueryTag": "14-3.0.0" 17 | }, 18 | "files": [ 19 | "wasm/*" 20 | ], 21 | "scripts": { 22 | "clean": "pnpm wasm:clean && rimraf wasm/*.js wasm/*.cjs wasm/*.d.ts", 23 | "build:js": "node scripts/build.js", 24 | "build": "pnpm clean && pnpm wasm:build && pnpm build:js", 25 | "publish:pkg": "node ../../scripts/publish-single-version.js", 26 | "wasm:make": "docker run --rm -v $(pwd):/src -u $(id -u):$(id -g) emscripten/emsdk emmake make", 27 | "wasm:build": "pnpm wasm:make build", 28 | "wasm:rebuild": "pnpm wasm:make rebuild", 29 | "wasm:clean": "pnpm wasm:make clean", 30 | "wasm:clean-cache": "pnpm wasm:make clean-cache", 31 | "test": "node --test test/parsing.test.js test/errors.test.js" 32 | }, 33 | "author": "Constructive ", 34 | "license": "MIT", 35 | "repository": { 36 | "type": "git", 37 | "url": "git://github.com/constructive-io/libpg-query-node.git" 38 | }, 39 | "devDependencies": {}, 40 | "dependencies": { 41 | "@pgsql/types": "^14.1.2" 42 | }, 43 | "keywords": [ 44 | "sql", 45 | "postgres", 46 | "postgresql", 47 | "pg", 48 | "query", 49 | "plpgsql", 50 | "database" 51 | ] 52 | } 53 | -------------------------------------------------------------------------------- /versions/15/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@libpg-query/v15", 3 | "version": "15.6.3", 4 | "description": "The real PostgreSQL query parser", 5 | "homepage": "https://github.com/constructive-io/libpg-query-node", 6 | "main": "./wasm/index.cjs", 7 | "module": "./wasm/index.js", 8 | "typings": "./wasm/index.d.ts", 9 | "publishConfig": { 10 | "access": "public" 11 | }, 12 | "x-publish": { 13 | "publishName": "libpg-query", 14 | "pgVersion": "15", 15 | "distTag": "pg15", 16 | "libpgQueryTag": "15-4.2.4" 17 | }, 18 | "files": [ 19 | "wasm/*" 20 | ], 21 | "scripts": { 22 | "clean": "pnpm wasm:clean && rimraf wasm/*.js wasm/*.cjs wasm/*.d.ts", 23 | "build:js": "node scripts/build.js", 24 | "build": "pnpm clean && pnpm wasm:build && pnpm build:js", 25 | "publish:pkg": "node ../../scripts/publish-single-version.js", 26 | "wasm:make": "docker run --rm -v $(pwd):/src -u $(id -u):$(id -g) emscripten/emsdk emmake make", 27 | "wasm:build": "pnpm wasm:make build", 28 | "wasm:rebuild": "pnpm wasm:make rebuild", 29 | "wasm:clean": "pnpm wasm:make clean", 30 | "wasm:clean-cache": "pnpm wasm:make clean-cache", 31 | "test": "node --test test/parsing.test.js test/errors.test.js" 32 | }, 33 | "author": "Constructive ", 34 | "license": "MIT", 35 | "repository": { 36 | "type": "git", 37 | "url": "git://github.com/constructive-io/libpg-query-node.git" 38 | }, 39 | "devDependencies": {}, 40 | "dependencies": { 41 | "@pgsql/types": "^15.1.2" 42 | }, 43 | "keywords": [ 44 | "sql", 45 | "postgres", 46 | "postgresql", 47 | "pg", 48 | "query", 49 | "plpgsql", 50 | "database" 51 | ] 52 | } 53 | -------------------------------------------------------------------------------- /versions/16/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@libpg-query/v16", 3 | "version": "16.7.3", 4 | "description": "The real PostgreSQL query parser", 5 | "homepage": "https://github.com/constructive-io/libpg-query-node", 6 | "main": "./wasm/index.cjs", 7 | "module": "./wasm/index.js", 8 | "typings": "./wasm/index.d.ts", 9 | "publishConfig": { 10 | "access": "public" 11 | }, 12 | "x-publish": { 13 | "publishName": "libpg-query", 14 | "pgVersion": "16", 15 | "distTag": "pg16", 16 | "libpgQueryTag": "16-5.2.0" 17 | }, 18 | "files": [ 19 | "wasm/*" 20 | ], 21 | "scripts": { 22 | "clean": "pnpm wasm:clean && rimraf wasm/*.js wasm/*.cjs wasm/*.d.ts", 23 | "build:js": "node scripts/build.js", 24 | "build": "pnpm clean && pnpm wasm:build && pnpm build:js", 25 | "publish:pkg": "node ../../scripts/publish-single-version.js", 26 | "wasm:make": "docker run --rm -v $(pwd):/src -u $(id -u):$(id -g) emscripten/emsdk emmake make", 27 | "wasm:build": "pnpm wasm:make build", 28 | "wasm:rebuild": "pnpm wasm:make rebuild", 29 | "wasm:clean": "pnpm wasm:make clean", 30 | "wasm:clean-cache": "pnpm wasm:make clean-cache", 31 | "test": "node --test test/parsing.test.js test/errors.test.js" 32 | }, 33 | "author": "Constructive ", 34 | "license": "MIT", 35 | "repository": { 36 | "type": "git", 37 | "url": "git://github.com/constructive-io/libpg-query-node.git" 38 | }, 39 | "devDependencies": {}, 40 | "dependencies": { 41 | "@pgsql/types": "^16.1.2" 42 | }, 43 | "keywords": [ 44 | "sql", 45 | "postgres", 46 | "postgresql", 47 | "pg", 48 | "query", 49 | "plpgsql", 50 | "database" 51 | ] 52 | } 53 | -------------------------------------------------------------------------------- /versions/17/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@libpg-query/v17", 3 | "version": "17.7.3", 4 | "description": "The real PostgreSQL query parser", 5 | "homepage": "https://github.com/constructive-io/libpg-query-node", 6 | "main": "./wasm/index.cjs", 7 | "module": "./wasm/index.js", 8 | "typings": "./wasm/index.d.ts", 9 | "publishConfig": { 10 | "access": "public" 11 | }, 12 | "x-publish": { 13 | "publishName": "libpg-query", 14 | "pgVersion": "17", 15 | "distTag": "pg17", 16 | "libpgQueryTag": "17-6.1.0" 17 | }, 18 | "files": [ 19 | "wasm/*" 20 | ], 21 | "scripts": { 22 | "clean": "pnpm wasm:clean && rimraf wasm/*.js wasm/*.cjs wasm/*.d.ts", 23 | "build:js": "node scripts/build.js", 24 | "build": "pnpm clean && pnpm wasm:build && pnpm build:js", 25 | "publish:pkg": "node ../../scripts/publish-single-version.js", 26 | "wasm:make": "docker run --rm -v $(pwd):/src -u $(id -u):$(id -g) emscripten/emsdk emmake make", 27 | "wasm:build": "pnpm wasm:make build", 28 | "wasm:rebuild": "pnpm wasm:make rebuild", 29 | "wasm:clean": "pnpm wasm:make clean", 30 | "wasm:clean-cache": "pnpm wasm:make clean-cache", 31 | "test": "node --test test/parsing.test.js test/errors.test.js" 32 | }, 33 | "author": "Constructive ", 34 | "license": "MIT", 35 | "repository": { 36 | "type": "git", 37 | "url": "git://github.com/constructive-io/libpg-query-node.git" 38 | }, 39 | "devDependencies": {}, 40 | "dependencies": { 41 | "@pgsql/types": "^17.6.2" 42 | }, 43 | "keywords": [ 44 | "sql", 45 | "postgres", 46 | "postgresql", 47 | "pg", 48 | "query", 49 | "plpgsql", 50 | "database" 51 | ] 52 | } 53 | -------------------------------------------------------------------------------- /versions/13/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@libpg-query/v13", 3 | "version": "13.7.3", 4 | "description": "The real PostgreSQL query parser", 5 | "homepage": "https://github.com/constructive-io/libpg-query-node", 6 | "main": "./wasm/index.cjs", 7 | "module": "./wasm/index.js", 8 | "typings": "./wasm/index.d.ts", 9 | "publishConfig": { 10 | "access": "public" 11 | }, 12 | "x-publish": { 13 | "publishName": "libpg-query", 14 | "pgVersion": "13", 15 | "distTag": "pg13", 16 | "libpgQueryTag": "13-2.2.0" 17 | }, 18 | "files": [ 19 | "wasm/*" 20 | ], 21 | "scripts": { 22 | "clean": "pnpm wasm:clean && rimraf wasm/*.js wasm/*.cjs wasm/*.d.ts", 23 | "build:js": "node scripts/build.js", 24 | "build": "pnpm clean && pnpm wasm:build && pnpm build:js", 25 | "publish:pkg": "node ../../scripts/publish-single-version.js", 26 | "wasm:make": "docker run --rm -v $(pwd):/src -u $(id -u):$(id -g) -e EMSCRIPTEN=1 emscripten/emsdk emmake make", 27 | "wasm:build": "pnpm wasm:make build", 28 | "wasm:rebuild": "pnpm wasm:make rebuild", 29 | "wasm:clean": "pnpm wasm:make clean", 30 | "wasm:clean-cache": "pnpm wasm:make clean-cache", 31 | "test": "node --test test/parsing.test.js test/errors.test.js" 32 | }, 33 | "author": "Constructive ", 34 | "license": "MIT", 35 | "repository": { 36 | "type": "git", 37 | "url": "git://github.com/constructive-io/libpg-query-node.git" 38 | }, 39 | "devDependencies": {}, 40 | "dependencies": { 41 | "@pgsql/types": "^13.11.2" 42 | }, 43 | "keywords": [ 44 | "sql", 45 | "postgres", 46 | "postgresql", 47 | "pg", 48 | "query", 49 | "plpgsql", 50 | "database" 51 | ] 52 | } 53 | -------------------------------------------------------------------------------- /full/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@libpg-query/parser", 3 | "version": "17.6.9", 4 | "description": "The real PostgreSQL query parser", 5 | "homepage": "https://github.com/constructive-io/libpg-query-node", 6 | "main": "./wasm/index.cjs", 7 | "module": "./wasm/index.js", 8 | "typings": "./wasm/index.d.ts", 9 | "publishConfig": { 10 | "access": "public" 11 | }, 12 | "files": [ 13 | "wasm/*", 14 | "proto.js" 15 | ], 16 | "scripts": { 17 | "clean": "pnpm wasm:clean && rimraf cjs esm", 18 | "build:js": "node scripts/build.js", 19 | "build": "pnpm clean; pnpm wasm:build; pnpm build:js", 20 | "wasm:make": "docker run --rm -v $(pwd):/src -u $(id -u):$(id -g) emscripten/emsdk emmake make", 21 | "wasm:build": "pnpm wasm:make build", 22 | "wasm:rebuild": "pnpm wasm:make rebuild", 23 | "wasm:clean": "pnpm wasm:make clean", 24 | "wasm:clean-cache": "pnpm wasm:make clean-cache", 25 | "test": "node --test test/parsing.test.js test/deparsing.test.js test/fingerprint.test.js test/normalize.test.js test/plpgsql.test.js test/scan.test.js test/errors.test.js", 26 | "yamlize": "node ./scripts/yamlize.js", 27 | "protogen": "node ./scripts/protogen.js" 28 | }, 29 | "author": "Constructive ", 30 | "license": "MIT", 31 | "repository": { 32 | "type": "git", 33 | "url": "git://github.com/constructive-io/libpg-query-node.git" 34 | }, 35 | "devDependencies": { 36 | "@launchql/proto-cli": "1.25.0", 37 | "@yamlize/cli": "^0.8.0" 38 | }, 39 | "dependencies": { 40 | "@pgsql/types": "^17.6.0", 41 | "@launchql/protobufjs": "7.2.6" 42 | }, 43 | "keywords": [ 44 | "sql", 45 | "postgres", 46 | "postgresql", 47 | "pg", 48 | "query", 49 | "plpgsql", 50 | "database" 51 | ] 52 | } 53 | -------------------------------------------------------------------------------- /.github/workflows/build-wasm-no-docker.yaml: -------------------------------------------------------------------------------- 1 | name: Build Wasm No Docker 🛠 2 | 'on': 3 | workflow_dispatch: null 4 | jobs: 5 | build-wasm-no-docker: 6 | runs-on: ubuntu-latest 7 | steps: 8 | - name: Checkout Repository 📥 9 | uses: actions/checkout@v4 10 | - name: Setup Node.js 🌐 11 | uses: actions/setup-node@v4 12 | with: 13 | node-version: 20.x 14 | 15 | - name: Setup pnpm 📦 16 | uses: pnpm/action-setup@v2 17 | with: 18 | version: 8.15.0 19 | 20 | - name: Get pnpm store directory 📁 21 | shell: bash 22 | run: | 23 | echo "STORE_PATH=$(pnpm store path --silent)" >> $GITHUB_ENV 24 | 25 | - name: Setup pnpm cache 🗄️ 26 | uses: actions/cache@v3 27 | with: 28 | path: ${{ env.STORE_PATH }} 29 | key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }} 30 | restore-keys: | 31 | ${{ runner.os }}-pnpm-store- 32 | 33 | - name: Install Dependencies 🧶 34 | run: pnpm install 35 | 36 | - name: Install Emscripten ✍🏻 37 | run: | 38 | sudo apt-get update 39 | sudo apt-get install cmake python3 python3-pip 40 | git clone --branch 3.1.59 --depth 1 https://github.com/emscripten-core/emsdk.git 41 | cd emsdk 42 | ./emsdk install 3.1.59 43 | ./emsdk activate 3.1.59 44 | source ./emsdk_env.sh 45 | working-directory: full 46 | - name: Build with Emscripten 🏗 47 | run: | 48 | source ./emsdk/emsdk_env.sh 49 | emmake make 50 | emmake make build 51 | working-directory: full 52 | - name: Archive production artifacts 🏛 53 | uses: actions/upload-artifact@v4 54 | with: 55 | name: wasm-artifacts 56 | path: full/wasm 57 | -------------------------------------------------------------------------------- /parser/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@pgsql/parser", 3 | "version": "1.2.1", 4 | "author": "Constructive ", 5 | "description": "Multi-version PostgreSQL parser with dynamic version selection", 6 | "main": "./wasm/index.cjs", 7 | "module": "./wasm/index.js", 8 | "types": "./wasm/index.d.ts", 9 | "exports": { 10 | ".": { 11 | "import": "./wasm/index.js", 12 | "require": "./wasm/index.cjs", 13 | "types": "./wasm/index.d.ts" 14 | }, 15 | "./v13": { 16 | "import": "./wasm/v13.js", 17 | "require": "./wasm/v13.cjs", 18 | "types": "./wasm/v13.d.ts" 19 | }, 20 | "./v14": { 21 | "import": "./wasm/v14.js", 22 | "require": "./wasm/v14.cjs", 23 | "types": "./wasm/v14.d.ts" 24 | }, 25 | "./v15": { 26 | "import": "./wasm/v15.js", 27 | "require": "./wasm/v15.cjs", 28 | "types": "./wasm/v15.d.ts" 29 | }, 30 | "./v16": { 31 | "import": "./wasm/v16.js", 32 | "require": "./wasm/v16.cjs", 33 | "types": "./wasm/v16.d.ts" 34 | }, 35 | "./v17": { 36 | "import": "./wasm/v17.js", 37 | "require": "./wasm/v17.cjs", 38 | "types": "./wasm/v17.d.ts" 39 | } 40 | }, 41 | "files": [ 42 | "wasm/**/*" 43 | ], 44 | "scripts": { 45 | "clean": "rimraf wasm", 46 | "prepare": "node scripts/prepare.js", 47 | "build": "npm run clean && npm run prepare", 48 | "build:full": "npm run clean && cross-env PARSER_BUILD_TYPE=full npm run prepare", 49 | "build:lts": "npm run clean && cross-env PARSER_BUILD_TYPE=lts npm run prepare", 50 | "test": "node --test test/parsing.test.js test/errors.test.js" 51 | }, 52 | "keywords": [ 53 | "postgresql", 54 | "parser", 55 | "sql", 56 | "ast", 57 | "multi-version" 58 | ], 59 | "license": "MIT", 60 | "devDependencies": { 61 | "cross-env": "^7.0.3", 62 | "rimraf": "^5.0.0" 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "libpg-query-monorepo", 3 | "private": true, 4 | "description": "PostgreSQL query parser monorepo", 5 | "packageManager": "pnpm@8.15.0", 6 | "scripts": { 7 | "build": "pnpm --filter libpg-query build", 8 | "test": "pnpm --filter libpg-query test", 9 | "clean": "pnpm --filter libpg-query clean", 10 | "build:all": "pnpm -r build", 11 | "test:all": "pnpm -r test", 12 | "clean:all": "pnpm -r clean", 13 | "build:versions": "pnpm --filter './versions/*' build", 14 | "test:versions": "pnpm --filter './versions/*' test", 15 | "clean:versions": "pnpm --filter './versions/*' clean", 16 | "analyze:sizes": "node scripts/analyze-sizes.js", 17 | "fetch:protos": "node scripts/fetch-protos.js", 18 | "build:types": "node scripts/build-types.js", 19 | "prepare:types": "node scripts/prepare-types.js", 20 | "build:enums": "node scripts/build-enums.js", 21 | "prepare:enums": "node scripts/prepare-enums.js", 22 | "publish:types": "node scripts/publish-types.js", 23 | "publish:enums": "node scripts/publish-enums.js", 24 | "publish:versions": "node scripts/publish-versions.js", 25 | "update:versions-types": "node scripts/update-versions-types.js", 26 | "copy:templates": "node scripts/copy-templates.js", 27 | "build:parser": "pnpm --filter @pgsql/parser build", 28 | "build:parser:lts": "PARSER_BUILD_TYPE=lts pnpm --filter @pgsql/parser build", 29 | "build:parser:full": "PARSER_BUILD_TYPE=full pnpm --filter @pgsql/parser build", 30 | "build:parser:legacy": "PARSER_BUILD_TYPE=legacy pnpm --filter @pgsql/parser build", 31 | "test:parser": "pnpm --filter @pgsql/parser test", 32 | "publish:parser": "pnpm --filter @pgsql/parser publish" 33 | }, 34 | "devDependencies": { 35 | "@types/node": "^20.0.0", 36 | "copyfiles": "^2.4.1", 37 | "glob": "11.0.3", 38 | "pg-proto-parser": "^1.28.2", 39 | "rimraf": "^5.0.0", 40 | "ts-node": "^10.9.1", 41 | "typescript": "^5.3.3" 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /templates/README.md: -------------------------------------------------------------------------------- 1 | # Template Files 2 | 3 | This directory contains template files that are shared across all PostgreSQL versions in the `versions/` directory. 4 | 5 | ## Files 6 | 7 | - `LICENSE` - The BSD 3-Clause license file 8 | - `Makefile.template` - The build configuration with placeholders for version-specific values 9 | - `index.ts` - TypeScript entry point 10 | - `libpg-query.d.ts` - TypeScript type definitions 11 | - `wasm_wrapper.c` - C wrapper for WASM compilation 12 | 13 | ## Usage 14 | 15 | To update the version-specific files from these templates, run: 16 | 17 | ```bash 18 | npm run copy:templates 19 | ``` 20 | 21 | This script will: 22 | 1. Copy all template files to each version directory 23 | 2. Replace placeholders with version-specific values 24 | 3. Add a header comment to source files indicating they are auto-generated 25 | 4. Handle special cases (e.g., the emscripten patch for version 13) 26 | 27 | ## Placeholders 28 | 29 | The following placeholders are used in template files: 30 | 31 | - `{{VERSION_TAG}}` - The libpg_query version tag (e.g., "14-3.0.0") 32 | - `{{#USE_EMSCRIPTEN_PATCH}}...{{/USE_EMSCRIPTEN_PATCH}}` - Conditional block for version-specific patches (currently only used in version 13) 33 | 34 | ## Version-Specific Configurations 35 | 36 | The `scripts/copy-templates.js` script automatically reads version-specific configurations from each version's `package.json` file. It looks for the `x-publish` section: 37 | 38 | ```json 39 | "x-publish": { 40 | "publishName": "libpg-query", 41 | "pgVersion": "15", 42 | "distTag": "pg15", 43 | "libpgQueryTag": "15-4.2.4" 44 | } 45 | ``` 46 | 47 | The script uses: 48 | - `pgVersion` to identify the PostgreSQL version 49 | - `libpgQueryTag` for the {{VERSION_TAG}} placeholder replacement 50 | - Version 13 automatically gets the emscripten patch applied 51 | 52 | ## Important Notes 53 | 54 | - DO NOT edit files directly in the `versions/*/` directories for these common files 55 | - Always edit the templates and run the copy script 56 | - The script preserves version-specific configurations while maintaining consistency 57 | - Generated files will have a header warning about manual modifications -------------------------------------------------------------------------------- /full/test/plpgsql.test.js: -------------------------------------------------------------------------------- 1 | const query = require("../"); 2 | const { describe, it, before, after, beforeEach, afterEach } = require('node:test'); 3 | const assert = require('node:assert/strict'); 4 | 5 | describe("PL/pgSQL Parsing", () => { 6 | before(async () => { 7 | await query.parse("SELECT 1"); 8 | }); 9 | 10 | describe("Sync PL/pgSQL Parsing", () => { 11 | it("should parse a simple PL/pgSQL function", () => { 12 | const funcSql = ` 13 | CREATE OR REPLACE FUNCTION test_func() 14 | RETURNS INTEGER AS $$ 15 | BEGIN 16 | RETURN 42; 17 | END; 18 | $$ LANGUAGE plpgsql; 19 | `; 20 | 21 | const result = query.parsePlPgSQLSync(funcSql); 22 | assert.equal(typeof result, "object"); 23 | assert.ok(Array.isArray(result.plpgsql_funcs)); 24 | }); 25 | 26 | it("should parse function with parameters", () => { 27 | const funcSql = ` 28 | CREATE OR REPLACE FUNCTION add_numbers(a INTEGER, b INTEGER) 29 | RETURNS INTEGER AS $$ 30 | BEGIN 31 | RETURN a + b; 32 | END; 33 | $$ LANGUAGE plpgsql; 34 | `; 35 | 36 | const result = query.parsePlPgSQLSync(funcSql); 37 | assert.ok(result.plpgsql_funcs.length > 0); 38 | }); 39 | 40 | it("should fail on invalid PL/pgSQL", () => { 41 | assert.throws(() => query.parsePlPgSQLSync("NOT A FUNCTION"), Error); 42 | }); 43 | }); 44 | 45 | describe("Async PL/pgSQL Parsing", () => { 46 | it("should return a promise resolving to same result", async () => { 47 | const funcSql = ` 48 | CREATE OR REPLACE FUNCTION test_func() 49 | RETURNS INTEGER AS $$ 50 | BEGIN 51 | RETURN 42; 52 | END; 53 | $$ LANGUAGE plpgsql; 54 | `; 55 | 56 | const resultPromise = query.parsePlPgSQL(funcSql); 57 | const result = await resultPromise; 58 | 59 | assert.ok(resultPromise instanceof Promise); 60 | assert.deepEqual(result, query.parsePlPgSQLSync(funcSql)); 61 | }); 62 | 63 | it("should reject on invalid PL/pgSQL", async () => { 64 | return query.parsePlPgSQL("NOT A FUNCTION").then( 65 | () => { 66 | throw new Error("should have rejected"); 67 | }, 68 | (e) => { 69 | assert.ok(e instanceof Error); 70 | assert.match(e.message, /NOT/); 71 | } 72 | ); 73 | }); 74 | }); 75 | }); 76 | -------------------------------------------------------------------------------- /full/test/fingerprint.test.js: -------------------------------------------------------------------------------- 1 | const query = require("../"); 2 | const { describe, it, before, after, beforeEach, afterEach } = require('node:test'); 3 | const assert = require('node:assert/strict'); 4 | 5 | describe("Query Fingerprinting", () => { 6 | before(async () => { 7 | await query.parse("SELECT 1"); 8 | }); 9 | 10 | describe("Sync Fingerprinting", () => { 11 | it("should return a fingerprint for a simple query", () => { 12 | const fingerprint = query.fingerprintSync("select 1"); 13 | assert.equal(typeof fingerprint, "string"); 14 | assert.equal(fingerprint.length, 16); 15 | }); 16 | 17 | it("should return same fingerprint for equivalent queries", () => { 18 | const fp1 = query.fingerprintSync("select 1"); 19 | const fp2 = query.fingerprintSync("SELECT 1"); 20 | const fp3 = query.fingerprintSync("select 1"); 21 | 22 | assert.equal(fp1, fp2); 23 | assert.equal(fp1, fp3); 24 | }); 25 | 26 | it("should return different fingerprints for different queries", () => { 27 | const fp1 = query.fingerprintSync("select name from users"); 28 | const fp2 = query.fingerprintSync("select id from customers"); 29 | 30 | assert.notEqual(fp1, fp2); 31 | }); 32 | 33 | it("should normalize parameter values", () => { 34 | const fp1 = query.fingerprintSync("select * from users where id = 123"); 35 | const fp2 = query.fingerprintSync("select * from users where id = 456"); 36 | 37 | assert.equal(fp1, fp2); 38 | }); 39 | 40 | it("should fail on invalid queries", () => { 41 | assert.throws(() => query.fingerprintSync("NOT A QUERY"), Error); 42 | }); 43 | }); 44 | 45 | describe("Async Fingerprinting", () => { 46 | it("should return a promise resolving to same result", async () => { 47 | const testQuery = "select * from users"; 48 | const fpPromise = query.fingerprint(testQuery); 49 | const fp = await fpPromise; 50 | 51 | assert.ok(fpPromise instanceof Promise); 52 | assert.equal(fp, query.fingerprintSync(testQuery)); 53 | }); 54 | 55 | it("should reject on bogus queries", async () => { 56 | return query.fingerprint("NOT A QUERY").then( 57 | () => { 58 | throw new Error("should have rejected"); 59 | }, 60 | (e) => { 61 | assert.ok(e instanceof Error); 62 | assert.match(e.message, /NOT/); 63 | } 64 | ); 65 | }); 66 | }); 67 | }); 68 | -------------------------------------------------------------------------------- /full/test/deparsing.test.js: -------------------------------------------------------------------------------- 1 | const query = require("../"); 2 | const { describe, it, before, after, beforeEach, afterEach } = require('node:test'); 3 | const assert = require('node:assert/strict'); 4 | 5 | describe("Query Deparsing", () => { 6 | before(async () => { 7 | await query.parse("SELECT 1"); 8 | }); 9 | 10 | describe("Sync Deparsing", () => { 11 | it("should deparse a simple query", () => { 12 | const sql = 'SELECT * FROM users'; 13 | const parseTree = query.parseSync(sql); 14 | const deparsed = query.deparseSync(parseTree); 15 | assert.equal(deparsed, sql); 16 | }); 17 | 18 | it("should deparse a complex query", () => { 19 | const sql = 'SELECT a, b, c FROM t1 JOIN t2 ON t1.id = t2.id WHERE t1.x > 10'; 20 | const parseTree = query.parseSync(sql); 21 | const deparsed = query.deparseSync(parseTree); 22 | assert.equal(deparsed, sql); 23 | }); 24 | 25 | it("should fail to deparse without protobuf data", () => { 26 | assert.throws(() => query.deparseSync({}), /No parseTree provided/); 27 | }); 28 | }); 29 | 30 | describe("Async Deparsing", () => { 31 | it("should return a promise resolving to same result", async () => { 32 | const sql = 'SELECT * FROM users'; 33 | const parseTree = await query.parse(sql); 34 | const deparsed = await query.deparse(parseTree); 35 | assert.equal(deparsed, sql); 36 | }); 37 | 38 | it("should reject when no protobuf data", async () => { 39 | try { 40 | await query.deparse({}); 41 | throw new Error('should have rejected'); 42 | } catch (err) { 43 | assert.equal(err.message, 'No parseTree provided'); 44 | } 45 | }); 46 | }); 47 | 48 | describe("Round-trip parsing and deparsing", () => { 49 | it("should maintain query semantics through round-trip", async () => { 50 | const sql = 'SELECT a, b, c FROM t1 JOIN t2 ON t1.id = t2.id WHERE t1.x > 10'; 51 | const parseTree = await query.parse(sql); 52 | const deparsed = await query.deparse(parseTree); 53 | assert.equal(deparsed, sql); 54 | }); 55 | }); 56 | 57 | it('should deparse a parse tree', async () => { 58 | const sql = 'SELECT * FROM users'; 59 | const parseTree = await query.parse(sql); 60 | const deparsed = await query.deparse(parseTree); 61 | assert.equal(deparsed, sql); 62 | }); 63 | 64 | it('should throw on invalid parse tree', () => { 65 | try { 66 | query.deparseSync({}); 67 | } catch (err) { } 68 | assert.throws(() => query.deparseSync({}), /No parseTree provided/); 69 | }); 70 | }); 71 | -------------------------------------------------------------------------------- /parser/templates/index.js.template: -------------------------------------------------------------------------------- 1 | // Main entry point for @pgsql/parser 2 | // Provides dynamic version loading for PostgreSQL parsers 3 | 4 | const SUPPORTED_VERSIONS = [${VERSIONS}]; 5 | 6 | export class Parser { 7 | constructor(options = {}) { 8 | const version = options.version || ${DEFAULT_VERSION}; 9 | 10 | if (!SUPPORTED_VERSIONS.includes(version)) { 11 | throw new Error(`Unsupported PostgreSQL version: ${version}. Supported versions are ${VERSIONS}.`); 12 | } 13 | 14 | this.version = version; 15 | this.parser = null; 16 | this._loadPromise = null; 17 | 18 | // Create the ready promise 19 | this.ready = new Promise((resolve) => { 20 | this._resolveReady = resolve; 21 | }); 22 | } 23 | 24 | async loadParser() { 25 | if (this.parser) return; 26 | 27 | // Ensure we only load once 28 | if (!this._loadPromise) { 29 | this._loadPromise = this._doLoad(); 30 | } 31 | 32 | return this._loadPromise; 33 | } 34 | 35 | async _doLoad() { 36 | const module = await import(`./v${this.version}/index.js`); 37 | this.parser = module; 38 | 39 | if (this.parser.loadModule) { 40 | await this.parser.loadModule(); 41 | } 42 | 43 | // Resolve the ready promise 44 | this._resolveReady(); 45 | } 46 | 47 | async parse(query) { 48 | if (!this.parser) { 49 | await this.loadParser(); 50 | } 51 | try { 52 | return await this.parser.parse(query); 53 | } catch (error) { 54 | // Preserve the original error if it's a SqlError 55 | if (error.name === 'SqlError') { 56 | throw error; 57 | } 58 | throw new Error(`Parse error in PostgreSQL ${this.version}: ${error.message}`); 59 | } 60 | } 61 | 62 | parseSync(query) { 63 | if (!this.parser) { 64 | throw new Error('Parser not loaded. Call loadParser() first or use parse() for automatic loading.'); 65 | } 66 | try { 67 | return this.parser.parseSync(query); 68 | } catch (error) { 69 | // Preserve the original error if it's a SqlError 70 | if (error.name === 'SqlError') { 71 | throw error; 72 | } 73 | throw new Error(`Parse error in PostgreSQL ${this.version}: ${error.message}`); 74 | } 75 | } 76 | } 77 | 78 | // Utility functions 79 | export function isSupportedVersion(version) { 80 | return SUPPORTED_VERSIONS.includes(version); 81 | } 82 | 83 | export function getSupportedVersions() { 84 | return [...SUPPORTED_VERSIONS]; 85 | } 86 | 87 | // Re-export all versions for direct access 88 | ${VERSION_EXPORTS} 89 | 90 | // Default export 91 | export default Parser; -------------------------------------------------------------------------------- /parser/templates/index.cjs.template: -------------------------------------------------------------------------------- 1 | // CommonJS entry point for @pgsql/parser 2 | // Provides dynamic version loading for PostgreSQL parsers 3 | 4 | const SUPPORTED_VERSIONS = [${VERSIONS}]; 5 | 6 | class Parser { 7 | constructor(options = {}) { 8 | const version = options.version || ${DEFAULT_VERSION}; 9 | 10 | if (!SUPPORTED_VERSIONS.includes(version)) { 11 | throw new Error(`Unsupported PostgreSQL version: ${version}. Supported versions are ${VERSIONS}.`); 12 | } 13 | 14 | this.version = version; 15 | this.parser = null; 16 | this._loadPromise = null; 17 | 18 | // Create the ready promise 19 | this.ready = new Promise((resolve) => { 20 | this._resolveReady = resolve; 21 | }); 22 | } 23 | 24 | async loadParser() { 25 | if (this.parser) return; 26 | 27 | // Ensure we only load once 28 | if (!this._loadPromise) { 29 | this._loadPromise = this._doLoad(); 30 | } 31 | 32 | return this._loadPromise; 33 | } 34 | 35 | async _doLoad() { 36 | // Dynamic require for CommonJS 37 | this.parser = require(`./v${this.version}/index.cjs`); 38 | 39 | if (this.parser.loadModule) { 40 | await this.parser.loadModule(); 41 | } 42 | 43 | // Resolve the ready promise 44 | this._resolveReady(); 45 | } 46 | 47 | async parse(query) { 48 | if (!this.parser) { 49 | await this.loadParser(); 50 | } 51 | try { 52 | return await this.parser.parse(query); 53 | } catch (error) { 54 | // Preserve the original error if it's a SqlError 55 | if (error.name === 'SqlError') { 56 | throw error; 57 | } 58 | throw new Error(`Parse error in PostgreSQL ${this.version}: ${error.message}`); 59 | } 60 | } 61 | 62 | parseSync(query) { 63 | if (!this.parser) { 64 | throw new Error('Parser not loaded. Call loadParser() first or use parse() for automatic loading.'); 65 | } 66 | try { 67 | return this.parser.parseSync(query); 68 | } catch (error) { 69 | // Preserve the original error if it's a SqlError 70 | if (error.name === 'SqlError') { 71 | throw error; 72 | } 73 | throw new Error(`Parse error in PostgreSQL ${this.version}: ${error.message}`); 74 | } 75 | } 76 | } 77 | 78 | // Utility functions 79 | function isSupportedVersion(version) { 80 | return SUPPORTED_VERSIONS.includes(version); 81 | } 82 | 83 | function getSupportedVersions() { 84 | return [...SUPPORTED_VERSIONS]; 85 | } 86 | 87 | // Export versions 88 | module.exports = { 89 | Parser, 90 | default: Parser, 91 | isSupportedVersion, 92 | getSupportedVersions, 93 | ${VERSION_REQUIRES} 94 | }; -------------------------------------------------------------------------------- /full/test/normalize.test.js: -------------------------------------------------------------------------------- 1 | const query = require("../"); 2 | const { describe, it, before, after, beforeEach, afterEach } = require('node:test'); 3 | const assert = require('node:assert/strict'); 4 | 5 | describe("Query Normalization", () => { 6 | before(async () => { 7 | await query.parse("SELECT 1"); 8 | }); 9 | 10 | describe("Sync Normalization", () => { 11 | it("should normalize a simple query", () => { 12 | const normalized = query.normalizeSync("select 1"); 13 | assert.equal(typeof normalized, "string"); 14 | assert.ok(normalized.includes("$1")); 15 | }); 16 | 17 | it("should normalize parameter values", () => { 18 | const normalized1 = query.normalizeSync("select * from users where id = 123"); 19 | const normalized2 = query.normalizeSync("select * from users where id = 456"); 20 | 21 | assert.equal(normalized1, normalized2); 22 | assert.ok(normalized1.includes("$1")); 23 | }); 24 | 25 | it("should normalize string literals", () => { 26 | const normalized1 = query.normalizeSync("select * from users where name = 'john'"); 27 | const normalized2 = query.normalizeSync("select * from users where name = 'jane'"); 28 | 29 | assert.equal(normalized1, normalized2); 30 | assert.ok(normalized1.includes("$1")); 31 | }); 32 | 33 | it("should preserve query structure", () => { 34 | const normalized = query.normalizeSync("SELECT id, name FROM users WHERE active = true ORDER BY name"); 35 | 36 | assert.ok(normalized.includes("SELECT")); 37 | assert.ok(normalized.includes("FROM")); 38 | assert.ok(normalized.includes("WHERE")); 39 | assert.ok(normalized.includes("ORDER BY")); 40 | }); 41 | 42 | it("should fail on invalid queries", () => { 43 | assert.throws(() => query.normalizeSync("NOT A QUERY"), Error); 44 | }); 45 | }); 46 | 47 | describe("Async Normalization", () => { 48 | it("should return a promise resolving to same result", async () => { 49 | const testQuery = "select * from users where id = 123"; 50 | const normalizedPromise = query.normalize(testQuery); 51 | const normalized = await normalizedPromise; 52 | 53 | assert.ok(normalizedPromise instanceof Promise); 54 | assert.equal(normalized, query.normalizeSync(testQuery)); 55 | }); 56 | 57 | it("should reject on bogus queries", async () => { 58 | return query.normalize("NOT A QUERY").then( 59 | () => { 60 | throw new Error("should have rejected"); 61 | }, 62 | (e) => { 63 | assert.ok(e instanceof Error); 64 | assert.match(e.message, /NOT/); 65 | } 66 | ); 67 | }); 68 | }); 69 | }); 70 | -------------------------------------------------------------------------------- /scripts/build-enums.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | const { execSync } = require('child_process'); 4 | const fs = require('fs'); 5 | const path = require('path'); 6 | 7 | // Get all enums directories 8 | function getEnumsDirectories() { 9 | const enumsDir = path.join(__dirname, '..', 'enums'); 10 | if (!fs.existsSync(enumsDir)) { 11 | console.log('No enums directory found'); 12 | return []; 13 | } 14 | 15 | return fs.readdirSync(enumsDir) 16 | .filter(dir => { 17 | const fullPath = path.join(enumsDir, dir); 18 | return fs.statSync(fullPath).isDirectory(); 19 | }) 20 | .sort(); 21 | } 22 | 23 | // Build a single enums package 24 | function buildEnumsPackage(version) { 25 | const packagePath = path.join(__dirname, '..', 'enums', version); 26 | const packageJsonPath = path.join(packagePath, 'package.json'); 27 | 28 | if (!fs.existsSync(packageJsonPath)) { 29 | console.log(`⚠️ Skipping enums/${version} - no package.json found`); 30 | return false; 31 | } 32 | 33 | console.log(`🔨 Building enums/${version}...`); 34 | 35 | try { 36 | // First run build:proto to generate enums from protobuf 37 | console.log(` 📋 Running build:proto for enums/${version}...`); 38 | execSync('pnpm run build:proto', { 39 | cwd: packagePath, 40 | stdio: 'inherit' 41 | }); 42 | 43 | // Then run the main build command 44 | console.log(` 🏗️ Running build for enums/${version}...`); 45 | execSync('pnpm run build', { 46 | cwd: packagePath, 47 | stdio: 'inherit' 48 | }); 49 | 50 | console.log(`✅ Successfully built enums/${version}\n`); 51 | return true; 52 | } catch (error) { 53 | console.error(`❌ Failed to build enums/${version}: ${error.message}\n`); 54 | return false; 55 | } 56 | } 57 | 58 | // Main function 59 | function buildAllEnums() { 60 | const enumsDirectories = getEnumsDirectories(); 61 | 62 | if (enumsDirectories.length === 0) { 63 | console.log('No enums packages found to build'); 64 | return; 65 | } 66 | 67 | console.log(`Found ${enumsDirectories.length} enums packages: ${enumsDirectories.join(', ')}\n`); 68 | 69 | let successful = 0; 70 | let failed = 0; 71 | 72 | for (const version of enumsDirectories) { 73 | if (buildEnumsPackage(version)) { 74 | successful++; 75 | } else { 76 | failed++; 77 | } 78 | } 79 | 80 | console.log('='.repeat(50)); 81 | console.log(`Build Summary:`); 82 | console.log(`✅ Successful: ${successful}`); 83 | console.log(`❌ Failed: ${failed}`); 84 | console.log(`📦 Total packages: ${enumsDirectories.length}`); 85 | 86 | if (failed > 0) { 87 | process.exit(1); 88 | } 89 | } 90 | 91 | // Run the script 92 | if (require.main === module) { 93 | buildAllEnums(); 94 | } 95 | 96 | module.exports = { buildAllEnums, buildEnumsPackage, getEnumsDirectories }; -------------------------------------------------------------------------------- /scripts/build-types.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | const { execSync } = require('child_process'); 4 | const fs = require('fs'); 5 | const path = require('path'); 6 | 7 | // Get all types directories 8 | function getTypesDirectories() { 9 | const typesDir = path.join(__dirname, '..', 'types'); 10 | if (!fs.existsSync(typesDir)) { 11 | console.log('No types directory found'); 12 | return []; 13 | } 14 | 15 | return fs.readdirSync(typesDir) 16 | .filter(dir => { 17 | const fullPath = path.join(typesDir, dir); 18 | return fs.statSync(fullPath).isDirectory(); 19 | }) 20 | .sort(); 21 | } 22 | 23 | // Build a single types package 24 | function buildTypesPackage(version) { 25 | const packagePath = path.join(__dirname, '..', 'types', version); 26 | const packageJsonPath = path.join(packagePath, 'package.json'); 27 | 28 | if (!fs.existsSync(packageJsonPath)) { 29 | console.log(`⚠️ Skipping types/${version} - no package.json found`); 30 | return false; 31 | } 32 | 33 | console.log(`🔨 Building types/${version}...`); 34 | 35 | try { 36 | // First run build:proto to generate types from protobuf 37 | console.log(` 📋 Running build:proto for types/${version}...`); 38 | execSync('pnpm run build:proto', { 39 | cwd: packagePath, 40 | stdio: 'inherit' 41 | }); 42 | 43 | // Then run the main build command 44 | console.log(` 🏗️ Running build for types/${version}...`); 45 | execSync('pnpm run build', { 46 | cwd: packagePath, 47 | stdio: 'inherit' 48 | }); 49 | 50 | console.log(`✅ Successfully built types/${version}\n`); 51 | return true; 52 | } catch (error) { 53 | console.error(`❌ Failed to build types/${version}: ${error.message}\n`); 54 | return false; 55 | } 56 | } 57 | 58 | // Main function 59 | function buildAllTypes() { 60 | const typesDirectories = getTypesDirectories(); 61 | 62 | if (typesDirectories.length === 0) { 63 | console.log('No types packages found to build'); 64 | return; 65 | } 66 | 67 | console.log(`Found ${typesDirectories.length} types packages: ${typesDirectories.join(', ')}\n`); 68 | 69 | let successful = 0; 70 | let failed = 0; 71 | 72 | for (const version of typesDirectories) { 73 | if (buildTypesPackage(version)) { 74 | successful++; 75 | } else { 76 | failed++; 77 | } 78 | } 79 | 80 | console.log('='.repeat(50)); 81 | console.log(`Build Summary:`); 82 | console.log(`✅ Successful: ${successful}`); 83 | console.log(`❌ Failed: ${failed}`); 84 | console.log(`📦 Total packages: ${typesDirectories.length}`); 85 | 86 | if (failed > 0) { 87 | process.exit(1); 88 | } 89 | } 90 | 91 | // Run the script 92 | if (require.main === module) { 93 | buildAllTypes(); 94 | } 95 | 96 | module.exports = { buildAllTypes, buildTypesPackage, getTypesDirectories }; -------------------------------------------------------------------------------- /parser/templates/index.d.ts.template: -------------------------------------------------------------------------------- 1 | // TypeScript definitions for @pgsql/parser 2 | 3 | // Supported versions 4 | export type SupportedVersion = ${VERSION_UNION}; 5 | 6 | // Version-specific type imports 7 | ${VERSION_TYPE_IMPORTS} 8 | 9 | // Version-specific type mappings 10 | type ParseResultVersionMap = { 11 | ${VERSION_PARSE_RESULT_MAP} 12 | }; 13 | 14 | type NodeVersionMap = { 15 | ${VERSION_NODE_MAP} 16 | }; 17 | 18 | // Generic types with version constraints 19 | export type ParseResult = 20 | ParseResultVersionMap[Version]; 21 | 22 | export type Node = 23 | NodeVersionMap[Version]; 24 | 25 | // SQL Error types 26 | export interface SqlErrorDetails { 27 | message: string; 28 | cursorPosition: number; 29 | fileName?: string; 30 | functionName?: string; 31 | lineNumber?: number; 32 | context?: string; 33 | } 34 | 35 | export declare class SqlError extends Error { 36 | readonly name: 'SqlError'; 37 | sqlDetails?: SqlErrorDetails; 38 | constructor(message: string, details?: SqlErrorDetails); 39 | } 40 | 41 | // Parser options 42 | export interface ParserOptions { 43 | version?: Version; 44 | } 45 | 46 | // Main Parser class with generic version support 47 | export declare class Parser { 48 | readonly version: Version; 49 | readonly ready: Promise; 50 | 51 | constructor(options?: ParserOptions); 52 | 53 | /** 54 | * Parse SQL asynchronously. Returns a properly typed ParseResult for the parser version. 55 | * @throws {SqlError} if parsing fails 56 | */ 57 | parse(query: string): Promise>; 58 | 59 | /** 60 | * Parse SQL synchronously. Returns a properly typed ParseResult for the parser version. 61 | * @throws {SqlError} if parsing fails 62 | */ 63 | parseSync(query: string): ParseResult; 64 | 65 | /** 66 | * Load the parser module. This is called automatically on first parse, 67 | * but can be called manually to pre-load the WASM module. 68 | */ 69 | loadParser(): Promise; 70 | } 71 | 72 | // Legacy compatibility interface (for backward compatibility) 73 | export interface LegacyParseResult { 74 | parse_tree?: any; 75 | stderr_buffer?: string; 76 | error?: { 77 | message: string; 78 | funcname: string; 79 | filename: string; 80 | lineno: number; 81 | cursorpos: number; 82 | context?: string; 83 | }; 84 | } 85 | 86 | // Utility functions 87 | export declare function isSupportedVersion(version: unknown): version is SupportedVersion; 88 | export declare function getSupportedVersions(): readonly SupportedVersion[]; 89 | 90 | export default Parser; 91 | 92 | // Version-specific exports 93 | ${VERSION_TYPE_EXPORTS} 94 | 95 | // Re-export types from the default version 96 | export * from './v${DEFAULT_VERSION}/types'; -------------------------------------------------------------------------------- /full/test/parsing.test.js: -------------------------------------------------------------------------------- 1 | const query = require("../"); 2 | const { describe, it, before, after, beforeEach, afterEach } = require('node:test'); 3 | const assert = require('node:assert/strict'); 4 | 5 | function removeLocationProperties(obj) { 6 | if (typeof obj !== 'object' || obj === null) { 7 | return obj; 8 | } 9 | 10 | if (Array.isArray(obj)) { 11 | return obj.map(item => removeLocationProperties(item)); 12 | } 13 | 14 | const result = {}; 15 | for (const key in obj) { 16 | if (obj.hasOwnProperty(key)) { 17 | if (key === 'location' || key === 'stmt_len' || key === 'stmt_location') { 18 | continue; // Skip location-related properties 19 | } 20 | result[key] = removeLocationProperties(obj[key]); 21 | } 22 | } 23 | return result; 24 | } 25 | 26 | describe("Query Parsing", () => { 27 | before(async () => { 28 | await query.parse("SELECT 1"); 29 | }); 30 | 31 | describe("Sync Parsing", () => { 32 | it("should return a single-item parse result for common queries", () => { 33 | const queries = ["select 1", "select null", "select ''", "select a, b"]; 34 | const results = queries.map(query.parseSync); 35 | results.forEach((res) => { 36 | assert.equal(res.stmts.length, 1); 37 | }); 38 | 39 | const selectedDatas = results.map( 40 | (it) => it.stmts[0].stmt.SelectStmt.targetList 41 | ); 42 | 43 | assert.equal(selectedDatas[0][0].ResTarget.val.A_Const.ival.ival, 1); 44 | assert.equal(selectedDatas[1][0].ResTarget.val.A_Const.isnull, true); 45 | assert.equal(selectedDatas[2][0].ResTarget.val.A_Const.sval.sval, ""); 46 | assert.equal(selectedDatas[3].length, 2); 47 | }); 48 | 49 | it("should support parsing multiple queries", () => { 50 | const res = query.parseSync("select 1; select null;"); 51 | assert.deepEqual(res.stmts.map(removeLocationProperties), [ 52 | ...query.parseSync("select 1;").stmts.map(removeLocationProperties), 53 | ...query.parseSync("select null;").stmts.map(removeLocationProperties), 54 | ]); 55 | }); 56 | 57 | it("should not parse a bogus query", () => { 58 | assert.throws(() => query.parseSync("NOT A QUERY"), Error); 59 | }); 60 | }); 61 | 62 | describe("Async parsing", () => { 63 | it("should return a promise resolving to same result", async () => { 64 | const testQuery = "select * from john;"; 65 | const resPromise = query.parse(testQuery); 66 | const res = await resPromise; 67 | 68 | assert.ok(resPromise instanceof Promise); 69 | assert.deepEqual(res, query.parseSync(testQuery)); 70 | }); 71 | 72 | it("should reject on bogus queries", async () => { 73 | return query.parse("NOT A QUERY").then( 74 | () => { 75 | throw new Error("should have rejected"); 76 | }, 77 | (e) => { 78 | assert.ok(e instanceof Error); 79 | assert.match(e.message, /NOT/); 80 | } 81 | ); 82 | }); 83 | }); 84 | }); 85 | -------------------------------------------------------------------------------- /versions/13/test/parsing.test.js: -------------------------------------------------------------------------------- 1 | const { describe, it, before } = require('node:test'); 2 | const assert = require('node:assert/strict'); 3 | const query = require("../"); 4 | 5 | function removeLocationProperties(obj) { 6 | if (typeof obj !== 'object' || obj === null) { 7 | return obj; 8 | } 9 | 10 | if (Array.isArray(obj)) { 11 | return obj.map(item => removeLocationProperties(item)); 12 | } 13 | 14 | const result = {}; 15 | for (const key in obj) { 16 | if (obj.hasOwnProperty(key)) { 17 | if (key === 'location' || key === 'stmt_len' || key === 'stmt_location') { 18 | continue; // Skip location-related properties 19 | } 20 | result[key] = removeLocationProperties(obj[key]); 21 | } 22 | } 23 | return result; 24 | } 25 | 26 | describe("Query Parsing", () => { 27 | before(async () => { 28 | await query.loadModule(); 29 | }); 30 | 31 | describe("Sync Parsing", () => { 32 | it("should return a single-item parse result for common queries", () => { 33 | const queries = ["select 1", "select null", "select ''", "select a, b"]; 34 | const results = queries.map(query.parseSync); 35 | results.forEach((res) => { 36 | assert.equal(res.stmts.length, 1); 37 | }); 38 | 39 | const selectedDatas = results.map( 40 | (it) => it.stmts[0].stmt.SelectStmt.targetList 41 | ); 42 | 43 | assert.equal(selectedDatas[0][0].ResTarget.val.A_Const.val.Integer.ival, 1); 44 | assert.ok(selectedDatas[1][0].ResTarget.val.A_Const.val.Null); 45 | assert.equal(selectedDatas[2][0].ResTarget.val.A_Const.val.String.str, ""); 46 | assert.equal(selectedDatas[3].length, 2); 47 | }); 48 | 49 | it("should support parsing multiple queries", () => { 50 | const res = query.parseSync("select 1; select null;"); 51 | assert.deepEqual( 52 | res.stmts.map(removeLocationProperties), 53 | [ 54 | ...query.parseSync("select 1;").stmts.map(removeLocationProperties), 55 | ...query.parseSync("select null;").stmts.map(removeLocationProperties), 56 | ] 57 | ); 58 | }); 59 | 60 | it("should not parse a bogus query", () => { 61 | assert.throws( 62 | () => query.parseSync("NOT A QUERY"), 63 | Error 64 | ); 65 | }); 66 | }); 67 | 68 | describe("Async parsing", () => { 69 | it("should return a promise resolving to same result", async () => { 70 | const testQuery = "select * from john;"; 71 | const resPromise = query.parse(testQuery); 72 | const res = await resPromise; 73 | 74 | assert.ok(resPromise instanceof Promise); 75 | assert.deepEqual(res, query.parseSync(testQuery)); 76 | }); 77 | 78 | it("should reject on bogus queries", async () => { 79 | await assert.rejects( 80 | query.parse("NOT A QUERY"), 81 | (err) => { 82 | assert.ok(err instanceof Error); 83 | assert.match(err.message, /NOT/); 84 | return true; 85 | } 86 | ); 87 | }); 88 | }); 89 | }); 90 | -------------------------------------------------------------------------------- /versions/14/test/parsing.test.js: -------------------------------------------------------------------------------- 1 | const { describe, it, before } = require('node:test'); 2 | const assert = require('node:assert/strict'); 3 | const query = require("../"); 4 | 5 | function removeLocationProperties(obj) { 6 | if (typeof obj !== 'object' || obj === null) { 7 | return obj; 8 | } 9 | 10 | if (Array.isArray(obj)) { 11 | return obj.map(item => removeLocationProperties(item)); 12 | } 13 | 14 | const result = {}; 15 | for (const key in obj) { 16 | if (obj.hasOwnProperty(key)) { 17 | if (key === 'location' || key === 'stmt_len' || key === 'stmt_location') { 18 | continue; // Skip location-related properties 19 | } 20 | result[key] = removeLocationProperties(obj[key]); 21 | } 22 | } 23 | return result; 24 | } 25 | 26 | describe("Query Parsing", () => { 27 | before(async () => { 28 | await query.loadModule(); 29 | }); 30 | 31 | describe("Sync Parsing", () => { 32 | it("should return a single-item parse result for common queries", () => { 33 | const queries = ["select 1", "select null", "select ''", "select a, b"]; 34 | const results = queries.map(query.parseSync); 35 | results.forEach((res) => { 36 | assert.equal(res.stmts.length, 1); 37 | }); 38 | 39 | const selectedDatas = results.map( 40 | (it) => it.stmts[0].stmt.SelectStmt.targetList 41 | ); 42 | 43 | assert.equal(selectedDatas[0][0].ResTarget.val.A_Const.val.Integer.ival, 1); 44 | assert.ok(selectedDatas[1][0].ResTarget.val.A_Const.val.Null); 45 | assert.equal(selectedDatas[2][0].ResTarget.val.A_Const.val.String.str, ""); 46 | assert.equal(selectedDatas[3].length, 2); 47 | }); 48 | 49 | it("should support parsing multiple queries", () => { 50 | const res = query.parseSync("select 1; select null;"); 51 | assert.deepEqual( 52 | res.stmts.map(removeLocationProperties), 53 | [ 54 | ...query.parseSync("select 1;").stmts.map(removeLocationProperties), 55 | ...query.parseSync("select null;").stmts.map(removeLocationProperties), 56 | ] 57 | ); 58 | }); 59 | 60 | it("should not parse a bogus query", () => { 61 | assert.throws( 62 | () => query.parseSync("NOT A QUERY"), 63 | Error 64 | ); 65 | }); 66 | }); 67 | 68 | describe("Async parsing", () => { 69 | it("should return a promise resolving to same result", async () => { 70 | const testQuery = "select * from john;"; 71 | const resPromise = query.parse(testQuery); 72 | const res = await resPromise; 73 | 74 | assert.ok(resPromise instanceof Promise); 75 | assert.deepEqual(res, query.parseSync(testQuery)); 76 | }); 77 | 78 | it("should reject on bogus queries", async () => { 79 | await assert.rejects( 80 | query.parse("NOT A QUERY"), 81 | (err) => { 82 | assert.ok(err instanceof Error); 83 | assert.match(err.message, /NOT/); 84 | return true; 85 | } 86 | ); 87 | }); 88 | }); 89 | }); 90 | -------------------------------------------------------------------------------- /versions/15/test/parsing.test.js: -------------------------------------------------------------------------------- 1 | const { describe, it, before } = require('node:test'); 2 | const assert = require('node:assert/strict'); 3 | const query = require("../"); 4 | 5 | function removeLocationProperties(obj) { 6 | if (typeof obj !== 'object' || obj === null) { 7 | return obj; 8 | } 9 | 10 | if (Array.isArray(obj)) { 11 | return obj.map(item => removeLocationProperties(item)); 12 | } 13 | 14 | const result = {}; 15 | for (const key in obj) { 16 | if (obj.hasOwnProperty(key)) { 17 | if (key === 'location' || key === 'stmt_len' || key === 'stmt_location') { 18 | continue; // Skip location-related properties 19 | } 20 | result[key] = removeLocationProperties(obj[key]); 21 | } 22 | } 23 | return result; 24 | } 25 | 26 | describe("Query Parsing", () => { 27 | before(async () => { 28 | await query.parse("SELECT 1"); 29 | }); 30 | 31 | describe("Sync Parsing", () => { 32 | it("should return a single-item parse result for common queries", () => { 33 | const queries = ["select 1", "select null", "select ''", "select a, b"]; 34 | const results = queries.map(query.parseSync); 35 | results.forEach((res) => { 36 | assert.equal(res.stmts.length, 1); 37 | }); 38 | 39 | const selectedDatas = results.map( 40 | (it) => it.stmts[0].stmt.SelectStmt.targetList 41 | ); 42 | 43 | assert.equal(selectedDatas[0][0].ResTarget.val.A_Const.ival.ival, 1); 44 | assert.equal(selectedDatas[1][0].ResTarget.val.A_Const.isnull, true); 45 | assert.equal(selectedDatas[2][0].ResTarget.val.A_Const.sval.sval, ""); 46 | assert.equal(selectedDatas[3].length, 2); 47 | }); 48 | 49 | it("should support parsing multiple queries", () => { 50 | const res = query.parseSync("select 1; select null;"); 51 | assert.deepEqual( 52 | res.stmts.map(removeLocationProperties), 53 | [ 54 | ...query.parseSync("select 1;").stmts.map(removeLocationProperties), 55 | ...query.parseSync("select null;").stmts.map(removeLocationProperties), 56 | ] 57 | ); 58 | }); 59 | 60 | it("should not parse a bogus query", () => { 61 | assert.throws( 62 | () => query.parseSync("NOT A QUERY"), 63 | Error 64 | ); 65 | }); 66 | }); 67 | 68 | describe("Async parsing", () => { 69 | it("should return a promise resolving to same result", async () => { 70 | const testQuery = "select * from john;"; 71 | const resPromise = query.parse(testQuery); 72 | const res = await resPromise; 73 | 74 | assert.ok(resPromise instanceof Promise); 75 | assert.deepEqual(res, query.parseSync(testQuery)); 76 | }); 77 | 78 | it("should reject on bogus queries", async () => { 79 | await assert.rejects( 80 | query.parse("NOT A QUERY"), 81 | (err) => { 82 | assert.ok(err instanceof Error); 83 | assert.match(err.message, /NOT/); 84 | return true; 85 | } 86 | ); 87 | }); 88 | }); 89 | }); 90 | -------------------------------------------------------------------------------- /versions/16/test/parsing.test.js: -------------------------------------------------------------------------------- 1 | const { describe, it, before } = require('node:test'); 2 | const assert = require('node:assert/strict'); 3 | const query = require("../"); 4 | 5 | function removeLocationProperties(obj) { 6 | if (typeof obj !== 'object' || obj === null) { 7 | return obj; 8 | } 9 | 10 | if (Array.isArray(obj)) { 11 | return obj.map(item => removeLocationProperties(item)); 12 | } 13 | 14 | const result = {}; 15 | for (const key in obj) { 16 | if (obj.hasOwnProperty(key)) { 17 | if (key === 'location' || key === 'stmt_len' || key === 'stmt_location') { 18 | continue; // Skip location-related properties 19 | } 20 | result[key] = removeLocationProperties(obj[key]); 21 | } 22 | } 23 | return result; 24 | } 25 | 26 | describe("Query Parsing", () => { 27 | before(async () => { 28 | await query.parse("SELECT 1"); 29 | }); 30 | 31 | describe("Sync Parsing", () => { 32 | it("should return a single-item parse result for common queries", () => { 33 | const queries = ["select 1", "select null", "select ''", "select a, b"]; 34 | const results = queries.map(query.parseSync); 35 | results.forEach((res) => { 36 | assert.equal(res.stmts.length, 1); 37 | }); 38 | 39 | const selectedDatas = results.map( 40 | (it) => it.stmts[0].stmt.SelectStmt.targetList 41 | ); 42 | 43 | assert.equal(selectedDatas[0][0].ResTarget.val.A_Const.ival.ival, 1); 44 | assert.equal(selectedDatas[1][0].ResTarget.val.A_Const.isnull, true); 45 | assert.equal(selectedDatas[2][0].ResTarget.val.A_Const.sval.sval, ""); 46 | assert.equal(selectedDatas[3].length, 2); 47 | }); 48 | 49 | it("should support parsing multiple queries", () => { 50 | const res = query.parseSync("select 1; select null;"); 51 | assert.deepEqual( 52 | res.stmts.map(removeLocationProperties), 53 | [ 54 | ...query.parseSync("select 1;").stmts.map(removeLocationProperties), 55 | ...query.parseSync("select null;").stmts.map(removeLocationProperties), 56 | ] 57 | ); 58 | }); 59 | 60 | it("should not parse a bogus query", () => { 61 | assert.throws( 62 | () => query.parseSync("NOT A QUERY"), 63 | Error 64 | ); 65 | }); 66 | }); 67 | 68 | describe("Async parsing", () => { 69 | it("should return a promise resolving to same result", async () => { 70 | const testQuery = "select * from john;"; 71 | const resPromise = query.parse(testQuery); 72 | const res = await resPromise; 73 | 74 | assert.ok(resPromise instanceof Promise); 75 | assert.deepEqual(res, query.parseSync(testQuery)); 76 | }); 77 | 78 | it("should reject on bogus queries", async () => { 79 | await assert.rejects( 80 | query.parse("NOT A QUERY"), 81 | (err) => { 82 | assert.ok(err instanceof Error); 83 | assert.match(err.message, /NOT/); 84 | return true; 85 | } 86 | ); 87 | }); 88 | }); 89 | }); 90 | -------------------------------------------------------------------------------- /versions/17/test/parsing.test.js: -------------------------------------------------------------------------------- 1 | const { describe, it, before } = require('node:test'); 2 | const assert = require('node:assert/strict'); 3 | const query = require("../"); 4 | 5 | function removeLocationProperties(obj) { 6 | if (typeof obj !== 'object' || obj === null) { 7 | return obj; 8 | } 9 | 10 | if (Array.isArray(obj)) { 11 | return obj.map(item => removeLocationProperties(item)); 12 | } 13 | 14 | const result = {}; 15 | for (const key in obj) { 16 | if (obj.hasOwnProperty(key)) { 17 | if (key === 'location' || key === 'stmt_len' || key === 'stmt_location') { 18 | continue; // Skip location-related properties 19 | } 20 | result[key] = removeLocationProperties(obj[key]); 21 | } 22 | } 23 | return result; 24 | } 25 | 26 | describe("Query Parsing", () => { 27 | before(async () => { 28 | await query.parse("SELECT 1"); 29 | }); 30 | 31 | describe("Sync Parsing", () => { 32 | it("should return a single-item parse result for common queries", () => { 33 | const queries = ["select 1", "select null", "select ''", "select a, b"]; 34 | const results = queries.map(query.parseSync); 35 | results.forEach((res) => { 36 | assert.equal(res.stmts.length, 1); 37 | }); 38 | 39 | const selectedDatas = results.map( 40 | (it) => it.stmts[0].stmt.SelectStmt.targetList 41 | ); 42 | 43 | assert.equal(selectedDatas[0][0].ResTarget.val.A_Const.ival.ival, 1); 44 | assert.equal(selectedDatas[1][0].ResTarget.val.A_Const.isnull, true); 45 | assert.equal(selectedDatas[2][0].ResTarget.val.A_Const.sval.sval, ""); 46 | assert.equal(selectedDatas[3].length, 2); 47 | }); 48 | 49 | it("should support parsing multiple queries", () => { 50 | const res = query.parseSync("select 1; select null;"); 51 | assert.deepEqual( 52 | res.stmts.map(removeLocationProperties), 53 | [ 54 | ...query.parseSync("select 1;").stmts.map(removeLocationProperties), 55 | ...query.parseSync("select null;").stmts.map(removeLocationProperties), 56 | ] 57 | ); 58 | }); 59 | 60 | it("should not parse a bogus query", () => { 61 | assert.throws( 62 | () => query.parseSync("NOT A QUERY"), 63 | Error 64 | ); 65 | }); 66 | }); 67 | 68 | describe("Async parsing", () => { 69 | it("should return a promise resolving to same result", async () => { 70 | const testQuery = "select * from john;"; 71 | const resPromise = query.parse(testQuery); 72 | const res = await resPromise; 73 | 74 | assert.ok(resPromise instanceof Promise); 75 | assert.deepEqual(res, query.parseSync(testQuery)); 76 | }); 77 | 78 | it("should reject on bogus queries", async () => { 79 | await assert.rejects( 80 | query.parse("NOT A QUERY"), 81 | (err) => { 82 | assert.ok(err instanceof Error); 83 | assert.match(err.message, /NOT/); 84 | return true; 85 | } 86 | ); 87 | }); 88 | }); 89 | }); 90 | -------------------------------------------------------------------------------- /full/Makefile: -------------------------------------------------------------------------------- 1 | WASM_OUT_DIR := wasm 2 | WASM_OUT_NAME := libpg-query 3 | WASM_MODULE_NAME := PgQueryModule 4 | LIBPG_QUERY_REPO := https://github.com/pganalyze/libpg_query.git 5 | LIBPG_QUERY_TAG := 17-6.1.0 6 | 7 | CACHE_DIR := .cache 8 | 9 | OS ?= $(shell uname -s) 10 | ARCH ?= $(shell uname -m) 11 | 12 | ifdef EMSCRIPTEN 13 | PLATFORM := emscripten 14 | else ifeq ($(OS),Darwin) 15 | PLATFORM := darwin 16 | else ifeq ($(OS),Linux) 17 | PLATFORM := linux 18 | else 19 | $(error Unsupported platform: $(OS)) 20 | endif 21 | 22 | ifdef EMSCRIPTEN 23 | ARCH := wasm 24 | endif 25 | 26 | PLATFORM_ARCH := $(PLATFORM)-$(ARCH) 27 | SRC_FILES := src/wasm_wrapper.c 28 | LIBPG_QUERY_DIR := $(CACHE_DIR)/$(PLATFORM_ARCH)/libpg_query/$(LIBPG_QUERY_TAG) 29 | LIBPG_QUERY_ARCHIVE := $(LIBPG_QUERY_DIR)/libpg_query.a 30 | LIBPG_QUERY_HEADER := $(LIBPG_QUERY_DIR)/pg_query.h 31 | CXXFLAGS := -O3 32 | 33 | ifdef EMSCRIPTEN 34 | OUT_FILES := $(foreach EXT,.js .wasm,$(WASM_OUT_DIR)/$(WASM_OUT_NAME)$(EXT)) 35 | else 36 | $(error Native builds are no longer supported. Use EMSCRIPTEN=1 for WASM builds only.) 37 | endif 38 | 39 | # Clone libpg_query source (lives in CACHE_DIR) 40 | $(LIBPG_QUERY_DIR): 41 | mkdir -p $(CACHE_DIR) 42 | git clone -b $(LIBPG_QUERY_TAG) --single-branch $(LIBPG_QUERY_REPO) $(LIBPG_QUERY_DIR) 43 | 44 | $(LIBPG_QUERY_HEADER): $(LIBPG_QUERY_DIR) 45 | 46 | # Build libpg_query 47 | $(LIBPG_QUERY_ARCHIVE): $(LIBPG_QUERY_DIR) 48 | cd $(LIBPG_QUERY_DIR); $(MAKE) build 49 | 50 | # Build libpg-query-node WASM module 51 | $(OUT_FILES): $(LIBPG_QUERY_ARCHIVE) $(LIBPG_QUERY_HEADER) $(SRC_FILES) 52 | ifdef EMSCRIPTEN 53 | mkdir -p $(WASM_OUT_DIR) 54 | $(CC) \ 55 | -v \ 56 | $(CXXFLAGS) \ 57 | -I$(LIBPG_QUERY_DIR) \ 58 | -I$(LIBPG_QUERY_DIR)/vendor \ 59 | -L$(LIBPG_QUERY_DIR) \ 60 | -sEXPORTED_FUNCTIONS="['_malloc','_free','_wasm_parse_query','_wasm_parse_query_protobuf','_wasm_get_protobuf_len','_wasm_deparse_protobuf','_wasm_parse_plpgsql','_wasm_fingerprint','_wasm_normalize_query','_wasm_scan','_wasm_parse_query_detailed','_wasm_free_detailed_result','_wasm_free_string','_wasm_parse_query_raw','_wasm_free_parse_result']" \ 61 | -sEXPORTED_RUNTIME_METHODS="['lengthBytesUTF8','stringToUTF8','UTF8ToString','getValue','HEAPU8','HEAPU32']" \ 62 | -sEXPORT_NAME="$(WASM_MODULE_NAME)" \ 63 | -sENVIRONMENT="web,node,worker" \ 64 | -sASSERTIONS=0 \ 65 | -sSINGLE_FILE=0 \ 66 | -sMODULARIZE=1 \ 67 | -sEXPORT_ES6=0 \ 68 | -sALLOW_MEMORY_GROWTH=1 \ 69 | -sINITIAL_MEMORY=134217728 \ 70 | -sMAXIMUM_MEMORY=1073741824 \ 71 | -sSTACK_SIZE=33554432 \ 72 | -lpg_query \ 73 | -o $@ \ 74 | $(SRC_FILES) 75 | else 76 | $(error Native builds are no longer supported. Use EMSCRIPTEN=1 for WASM builds only.) 77 | endif 78 | 79 | # Commands 80 | build: $(OUT_FILES) 81 | 82 | build-cache: $(LIBPG_QUERY_ARCHIVE) $(LIBPG_QUERY_HEADER) 83 | 84 | rebuild: clean build 85 | 86 | rebuild-cache: clean-cache build-cache 87 | 88 | clean: 89 | -@ rm -r $(OUT_FILES) > /dev/null 2>&1 90 | 91 | clean-cache: 92 | -@ rm -rf $(LIBPG_QUERY_DIR) 93 | 94 | .PHONY: build build-cache rebuild rebuild-cache clean clean-cache 95 | -------------------------------------------------------------------------------- /versions/14/Makefile: -------------------------------------------------------------------------------- 1 | # DO NOT MODIFY MANUALLY — this is generated from the templates dir 2 | # 3 | # To make changes, edit the files in the templates/ directory and run: 4 | # npm run copy:templates 5 | 6 | WASM_OUT_DIR := wasm 7 | WASM_OUT_NAME := libpg-query 8 | WASM_MODULE_NAME := PgQueryModule 9 | LIBPG_QUERY_REPO := https://github.com/pganalyze/libpg_query.git 10 | LIBPG_QUERY_TAG := 14-3.0.0 11 | 12 | CACHE_DIR := .cache 13 | 14 | OS ?= $(shell uname -s) 15 | ARCH ?= $(shell uname -m) 16 | 17 | ifdef EMSCRIPTEN 18 | PLATFORM := emscripten 19 | else ifeq ($(OS),Darwin) 20 | PLATFORM := darwin 21 | else ifeq ($(OS),Linux) 22 | PLATFORM := linux 23 | else 24 | $(error Unsupported platform: $(OS)) 25 | endif 26 | 27 | ifdef EMSCRIPTEN 28 | ARCH := wasm 29 | endif 30 | 31 | PLATFORM_ARCH := $(PLATFORM)-$(ARCH) 32 | SRC_FILES := src/wasm_wrapper.c 33 | LIBPG_QUERY_DIR := $(CACHE_DIR)/$(PLATFORM_ARCH)/libpg_query/$(LIBPG_QUERY_TAG) 34 | LIBPG_QUERY_ARCHIVE := $(LIBPG_QUERY_DIR)/libpg_query.a 35 | LIBPG_QUERY_HEADER := $(LIBPG_QUERY_DIR)/pg_query.h 36 | CXXFLAGS := -O3 -flto 37 | 38 | ifdef EMSCRIPTEN 39 | OUT_FILES := $(foreach EXT,.js .wasm,$(WASM_OUT_DIR)/$(WASM_OUT_NAME)$(EXT)) 40 | else 41 | $(error Native builds are no longer supported. Use EMSCRIPTEN=1 for WASM builds only.) 42 | endif 43 | 44 | # Clone libpg_query source (lives in CACHE_DIR) 45 | $(LIBPG_QUERY_DIR): 46 | mkdir -p $(CACHE_DIR) 47 | git clone -b $(LIBPG_QUERY_TAG) --single-branch $(LIBPG_QUERY_REPO) $(LIBPG_QUERY_DIR) 48 | 49 | $(LIBPG_QUERY_HEADER): $(LIBPG_QUERY_DIR) 50 | 51 | # Build libpg_query 52 | $(LIBPG_QUERY_ARCHIVE): $(LIBPG_QUERY_DIR) 53 | cd $(LIBPG_QUERY_DIR); $(MAKE) build 54 | 55 | # Build libpg-query-node WASM module 56 | $(OUT_FILES): $(LIBPG_QUERY_ARCHIVE) $(LIBPG_QUERY_HEADER) $(SRC_FILES) 57 | ifdef EMSCRIPTEN 58 | mkdir -p $(WASM_OUT_DIR) 59 | $(CC) \ 60 | -v \ 61 | $(CXXFLAGS) \ 62 | -I$(LIBPG_QUERY_DIR) \ 63 | -I$(LIBPG_QUERY_DIR)/vendor \ 64 | -L$(LIBPG_QUERY_DIR) \ 65 | -sEXPORTED_FUNCTIONS="['_malloc','_free','_wasm_parse_query_raw','_wasm_free_parse_result']" \ 66 | -sEXPORTED_RUNTIME_METHODS="['lengthBytesUTF8','stringToUTF8','getValue','UTF8ToString','HEAPU8','HEAPU32']" \ 67 | -sEXPORT_NAME="$(WASM_MODULE_NAME)" \ 68 | -sENVIRONMENT="web,node,worker" \ 69 | -sASSERTIONS=0 \ 70 | -sSINGLE_FILE=0 \ 71 | -sMODULARIZE=1 \ 72 | -sEXPORT_ES6=0 \ 73 | -sALLOW_MEMORY_GROWTH=1 \ 74 | -sINITIAL_MEMORY=134217728 \ 75 | -sMAXIMUM_MEMORY=1073741824 \ 76 | -sSTACK_SIZE=33554432 \ 77 | -lpg_query \ 78 | -o $@ \ 79 | $(SRC_FILES) 80 | else 81 | $(error Native builds are no longer supported. Use EMSCRIPTEN=1 for WASM builds only.) 82 | endif 83 | 84 | # Commands 85 | build: $(OUT_FILES) 86 | 87 | build-cache: $(LIBPG_QUERY_ARCHIVE) $(LIBPG_QUERY_HEADER) 88 | 89 | rebuild: clean build 90 | 91 | rebuild-cache: clean-cache build-cache 92 | 93 | clean: 94 | -@ rm -r $(OUT_FILES) > /dev/null 2>&1 95 | 96 | clean-cache: 97 | -@ rm -rf $(LIBPG_QUERY_DIR) 98 | 99 | .PHONY: build build-cache rebuild rebuild-cache clean clean-cache 100 | -------------------------------------------------------------------------------- /versions/16/Makefile: -------------------------------------------------------------------------------- 1 | # DO NOT MODIFY MANUALLY — this is generated from the templates dir 2 | # 3 | # To make changes, edit the files in the templates/ directory and run: 4 | # npm run copy:templates 5 | 6 | WASM_OUT_DIR := wasm 7 | WASM_OUT_NAME := libpg-query 8 | WASM_MODULE_NAME := PgQueryModule 9 | LIBPG_QUERY_REPO := https://github.com/pganalyze/libpg_query.git 10 | LIBPG_QUERY_TAG := 16-5.2.0 11 | 12 | CACHE_DIR := .cache 13 | 14 | OS ?= $(shell uname -s) 15 | ARCH ?= $(shell uname -m) 16 | 17 | ifdef EMSCRIPTEN 18 | PLATFORM := emscripten 19 | else ifeq ($(OS),Darwin) 20 | PLATFORM := darwin 21 | else ifeq ($(OS),Linux) 22 | PLATFORM := linux 23 | else 24 | $(error Unsupported platform: $(OS)) 25 | endif 26 | 27 | ifdef EMSCRIPTEN 28 | ARCH := wasm 29 | endif 30 | 31 | PLATFORM_ARCH := $(PLATFORM)-$(ARCH) 32 | SRC_FILES := src/wasm_wrapper.c 33 | LIBPG_QUERY_DIR := $(CACHE_DIR)/$(PLATFORM_ARCH)/libpg_query/$(LIBPG_QUERY_TAG) 34 | LIBPG_QUERY_ARCHIVE := $(LIBPG_QUERY_DIR)/libpg_query.a 35 | LIBPG_QUERY_HEADER := $(LIBPG_QUERY_DIR)/pg_query.h 36 | CXXFLAGS := -O3 -flto 37 | 38 | ifdef EMSCRIPTEN 39 | OUT_FILES := $(foreach EXT,.js .wasm,$(WASM_OUT_DIR)/$(WASM_OUT_NAME)$(EXT)) 40 | else 41 | $(error Native builds are no longer supported. Use EMSCRIPTEN=1 for WASM builds only.) 42 | endif 43 | 44 | # Clone libpg_query source (lives in CACHE_DIR) 45 | $(LIBPG_QUERY_DIR): 46 | mkdir -p $(CACHE_DIR) 47 | git clone -b $(LIBPG_QUERY_TAG) --single-branch $(LIBPG_QUERY_REPO) $(LIBPG_QUERY_DIR) 48 | 49 | $(LIBPG_QUERY_HEADER): $(LIBPG_QUERY_DIR) 50 | 51 | # Build libpg_query 52 | $(LIBPG_QUERY_ARCHIVE): $(LIBPG_QUERY_DIR) 53 | cd $(LIBPG_QUERY_DIR); $(MAKE) build 54 | 55 | # Build libpg-query-node WASM module 56 | $(OUT_FILES): $(LIBPG_QUERY_ARCHIVE) $(LIBPG_QUERY_HEADER) $(SRC_FILES) 57 | ifdef EMSCRIPTEN 58 | mkdir -p $(WASM_OUT_DIR) 59 | $(CC) \ 60 | -v \ 61 | $(CXXFLAGS) \ 62 | -I$(LIBPG_QUERY_DIR) \ 63 | -I$(LIBPG_QUERY_DIR)/vendor \ 64 | -L$(LIBPG_QUERY_DIR) \ 65 | -sEXPORTED_FUNCTIONS="['_malloc','_free','_wasm_parse_query_raw','_wasm_free_parse_result']" \ 66 | -sEXPORTED_RUNTIME_METHODS="['lengthBytesUTF8','stringToUTF8','getValue','UTF8ToString','HEAPU8','HEAPU32']" \ 67 | -sEXPORT_NAME="$(WASM_MODULE_NAME)" \ 68 | -sENVIRONMENT="web,node,worker" \ 69 | -sASSERTIONS=0 \ 70 | -sSINGLE_FILE=0 \ 71 | -sMODULARIZE=1 \ 72 | -sEXPORT_ES6=0 \ 73 | -sALLOW_MEMORY_GROWTH=1 \ 74 | -sINITIAL_MEMORY=134217728 \ 75 | -sMAXIMUM_MEMORY=1073741824 \ 76 | -sSTACK_SIZE=33554432 \ 77 | -lpg_query \ 78 | -o $@ \ 79 | $(SRC_FILES) 80 | else 81 | $(error Native builds are no longer supported. Use EMSCRIPTEN=1 for WASM builds only.) 82 | endif 83 | 84 | # Commands 85 | build: $(OUT_FILES) 86 | 87 | build-cache: $(LIBPG_QUERY_ARCHIVE) $(LIBPG_QUERY_HEADER) 88 | 89 | rebuild: clean build 90 | 91 | rebuild-cache: clean-cache build-cache 92 | 93 | clean: 94 | -@ rm -r $(OUT_FILES) > /dev/null 2>&1 95 | 96 | clean-cache: 97 | -@ rm -rf $(LIBPG_QUERY_DIR) 98 | 99 | .PHONY: build build-cache rebuild rebuild-cache clean clean-cache 100 | -------------------------------------------------------------------------------- /versions/17/Makefile: -------------------------------------------------------------------------------- 1 | # DO NOT MODIFY MANUALLY — this is generated from the templates dir 2 | # 3 | # To make changes, edit the files in the templates/ directory and run: 4 | # npm run copy:templates 5 | 6 | WASM_OUT_DIR := wasm 7 | WASM_OUT_NAME := libpg-query 8 | WASM_MODULE_NAME := PgQueryModule 9 | LIBPG_QUERY_REPO := https://github.com/pganalyze/libpg_query.git 10 | LIBPG_QUERY_TAG := 17-6.1.0 11 | 12 | CACHE_DIR := .cache 13 | 14 | OS ?= $(shell uname -s) 15 | ARCH ?= $(shell uname -m) 16 | 17 | ifdef EMSCRIPTEN 18 | PLATFORM := emscripten 19 | else ifeq ($(OS),Darwin) 20 | PLATFORM := darwin 21 | else ifeq ($(OS),Linux) 22 | PLATFORM := linux 23 | else 24 | $(error Unsupported platform: $(OS)) 25 | endif 26 | 27 | ifdef EMSCRIPTEN 28 | ARCH := wasm 29 | endif 30 | 31 | PLATFORM_ARCH := $(PLATFORM)-$(ARCH) 32 | SRC_FILES := src/wasm_wrapper.c 33 | LIBPG_QUERY_DIR := $(CACHE_DIR)/$(PLATFORM_ARCH)/libpg_query/$(LIBPG_QUERY_TAG) 34 | LIBPG_QUERY_ARCHIVE := $(LIBPG_QUERY_DIR)/libpg_query.a 35 | LIBPG_QUERY_HEADER := $(LIBPG_QUERY_DIR)/pg_query.h 36 | CXXFLAGS := -O3 -flto 37 | 38 | ifdef EMSCRIPTEN 39 | OUT_FILES := $(foreach EXT,.js .wasm,$(WASM_OUT_DIR)/$(WASM_OUT_NAME)$(EXT)) 40 | else 41 | $(error Native builds are no longer supported. Use EMSCRIPTEN=1 for WASM builds only.) 42 | endif 43 | 44 | # Clone libpg_query source (lives in CACHE_DIR) 45 | $(LIBPG_QUERY_DIR): 46 | mkdir -p $(CACHE_DIR) 47 | git clone -b $(LIBPG_QUERY_TAG) --single-branch $(LIBPG_QUERY_REPO) $(LIBPG_QUERY_DIR) 48 | 49 | $(LIBPG_QUERY_HEADER): $(LIBPG_QUERY_DIR) 50 | 51 | # Build libpg_query 52 | $(LIBPG_QUERY_ARCHIVE): $(LIBPG_QUERY_DIR) 53 | cd $(LIBPG_QUERY_DIR); $(MAKE) build 54 | 55 | # Build libpg-query-node WASM module 56 | $(OUT_FILES): $(LIBPG_QUERY_ARCHIVE) $(LIBPG_QUERY_HEADER) $(SRC_FILES) 57 | ifdef EMSCRIPTEN 58 | mkdir -p $(WASM_OUT_DIR) 59 | $(CC) \ 60 | -v \ 61 | $(CXXFLAGS) \ 62 | -I$(LIBPG_QUERY_DIR) \ 63 | -I$(LIBPG_QUERY_DIR)/vendor \ 64 | -L$(LIBPG_QUERY_DIR) \ 65 | -sEXPORTED_FUNCTIONS="['_malloc','_free','_wasm_parse_query_raw','_wasm_free_parse_result']" \ 66 | -sEXPORTED_RUNTIME_METHODS="['lengthBytesUTF8','stringToUTF8','getValue','UTF8ToString','HEAPU8','HEAPU32']" \ 67 | -sEXPORT_NAME="$(WASM_MODULE_NAME)" \ 68 | -sENVIRONMENT="web,node,worker" \ 69 | -sASSERTIONS=0 \ 70 | -sSINGLE_FILE=0 \ 71 | -sMODULARIZE=1 \ 72 | -sEXPORT_ES6=0 \ 73 | -sALLOW_MEMORY_GROWTH=1 \ 74 | -sINITIAL_MEMORY=134217728 \ 75 | -sMAXIMUM_MEMORY=1073741824 \ 76 | -sSTACK_SIZE=33554432 \ 77 | -lpg_query \ 78 | -o $@ \ 79 | $(SRC_FILES) 80 | else 81 | $(error Native builds are no longer supported. Use EMSCRIPTEN=1 for WASM builds only.) 82 | endif 83 | 84 | # Commands 85 | build: $(OUT_FILES) 86 | 87 | build-cache: $(LIBPG_QUERY_ARCHIVE) $(LIBPG_QUERY_HEADER) 88 | 89 | rebuild: clean build 90 | 91 | rebuild-cache: clean-cache build-cache 92 | 93 | clean: 94 | -@ rm -r $(OUT_FILES) > /dev/null 2>&1 95 | 96 | clean-cache: 97 | -@ rm -rf $(LIBPG_QUERY_DIR) 98 | 99 | .PHONY: build build-cache rebuild rebuild-cache clean clean-cache 100 | -------------------------------------------------------------------------------- /templates/Makefile.template: -------------------------------------------------------------------------------- 1 | WASM_OUT_DIR := wasm 2 | WASM_OUT_NAME := libpg-query 3 | WASM_MODULE_NAME := PgQueryModule 4 | LIBPG_QUERY_REPO := https://github.com/pganalyze/libpg_query.git 5 | LIBPG_QUERY_TAG := {{VERSION_TAG}} 6 | 7 | CACHE_DIR := .cache 8 | 9 | OS ?= $(shell uname -s) 10 | ARCH ?= $(shell uname -m) 11 | 12 | ifdef EMSCRIPTEN 13 | PLATFORM := emscripten 14 | else ifeq ($(OS),Darwin) 15 | PLATFORM := darwin 16 | else ifeq ($(OS),Linux) 17 | PLATFORM := linux 18 | else 19 | $(error Unsupported platform: $(OS)) 20 | endif 21 | 22 | ifdef EMSCRIPTEN 23 | ARCH := wasm 24 | endif 25 | 26 | PLATFORM_ARCH := $(PLATFORM)-$(ARCH) 27 | SRC_FILES := src/wasm_wrapper.c 28 | LIBPG_QUERY_DIR := $(CACHE_DIR)/$(PLATFORM_ARCH)/libpg_query/$(LIBPG_QUERY_TAG) 29 | LIBPG_QUERY_ARCHIVE := $(LIBPG_QUERY_DIR)/libpg_query.a 30 | LIBPG_QUERY_HEADER := $(LIBPG_QUERY_DIR)/pg_query.h 31 | CXXFLAGS := -O3 -flto 32 | 33 | ifdef EMSCRIPTEN 34 | OUT_FILES := $(foreach EXT,.js .wasm,$(WASM_OUT_DIR)/$(WASM_OUT_NAME)$(EXT)) 35 | else 36 | $(error Native builds are no longer supported. Use EMSCRIPTEN=1 for WASM builds only.) 37 | endif 38 | 39 | # Clone libpg_query source (lives in CACHE_DIR) 40 | $(LIBPG_QUERY_DIR): 41 | mkdir -p $(CACHE_DIR) 42 | git clone -b $(LIBPG_QUERY_TAG) --single-branch $(LIBPG_QUERY_REPO) $(LIBPG_QUERY_DIR) 43 | {{#USE_EMSCRIPTEN_PATCH}} 44 | ifdef EMSCRIPTEN 45 | cd $(LIBPG_QUERY_DIR); patch -p1 < $(shell pwd)/patches/emscripten_disable_spinlocks.patch 46 | endif 47 | {{/USE_EMSCRIPTEN_PATCH}} 48 | 49 | $(LIBPG_QUERY_HEADER): $(LIBPG_QUERY_DIR) 50 | 51 | # Build libpg_query 52 | $(LIBPG_QUERY_ARCHIVE): $(LIBPG_QUERY_DIR) 53 | cd $(LIBPG_QUERY_DIR); $(MAKE) build 54 | 55 | # Build libpg-query-node WASM module 56 | $(OUT_FILES): $(LIBPG_QUERY_ARCHIVE) $(LIBPG_QUERY_HEADER) $(SRC_FILES) 57 | ifdef EMSCRIPTEN 58 | mkdir -p $(WASM_OUT_DIR) 59 | $(CC) \ 60 | -v \ 61 | $(CXXFLAGS) \ 62 | -I$(LIBPG_QUERY_DIR) \ 63 | -I$(LIBPG_QUERY_DIR)/vendor \ 64 | -L$(LIBPG_QUERY_DIR) \ 65 | -sEXPORTED_FUNCTIONS="['_malloc','_free','_wasm_parse_query_raw','_wasm_free_parse_result']" \ 66 | -sEXPORTED_RUNTIME_METHODS="['lengthBytesUTF8','stringToUTF8','getValue','UTF8ToString','HEAPU8','HEAPU32']" \ 67 | -sEXPORT_NAME="$(WASM_MODULE_NAME)" \ 68 | -sENVIRONMENT="web,node,worker" \ 69 | -sASSERTIONS=0 \ 70 | -sSINGLE_FILE=0 \ 71 | -sMODULARIZE=1 \ 72 | -sEXPORT_ES6=0 \ 73 | -sALLOW_MEMORY_GROWTH=1 \ 74 | -sINITIAL_MEMORY=134217728 \ 75 | -sMAXIMUM_MEMORY=1073741824 \ 76 | -sSTACK_SIZE=33554432 \ 77 | -lpg_query \ 78 | -o $@ \ 79 | $(SRC_FILES) 80 | else 81 | $(error Native builds are no longer supported. Use EMSCRIPTEN=1 for WASM builds only.) 82 | endif 83 | 84 | # Commands 85 | build: $(OUT_FILES) 86 | 87 | build-cache: $(LIBPG_QUERY_ARCHIVE) $(LIBPG_QUERY_HEADER) 88 | 89 | rebuild: clean build 90 | 91 | rebuild-cache: clean-cache build-cache 92 | 93 | clean: 94 | -@ rm -r $(OUT_FILES) > /dev/null 2>&1 95 | 96 | clean-cache: 97 | -@ rm -rf $(LIBPG_QUERY_DIR) 98 | 99 | .PHONY: build build-cache rebuild rebuild-cache clean clean-cache 100 | -------------------------------------------------------------------------------- /versions/15/Makefile: -------------------------------------------------------------------------------- 1 | # DO NOT MODIFY MANUALLY — this is generated from the templates dir 2 | # 3 | # To make changes, edit the files in the templates/ directory and run: 4 | # npm run copy:templates 5 | 6 | WASM_OUT_DIR := wasm 7 | WASM_OUT_NAME := libpg-query 8 | WASM_MODULE_NAME := PgQueryModule 9 | # LIBPG_QUERY_REPO := https://github.com/pganalyze/libpg_query.git 10 | # LIBPG_QUERY_TAG := 15-4.2.4 11 | LIBPG_QUERY_REPO := https://github.com/constructive-io/libpg_query.git 12 | LIBPG_QUERY_TAG := fix/negative-int-pg15 13 | 14 | CACHE_DIR := .cache 15 | 16 | OS ?= $(shell uname -s) 17 | ARCH ?= $(shell uname -m) 18 | 19 | ifdef EMSCRIPTEN 20 | PLATFORM := emscripten 21 | else ifeq ($(OS),Darwin) 22 | PLATFORM := darwin 23 | else ifeq ($(OS),Linux) 24 | PLATFORM := linux 25 | else 26 | $(error Unsupported platform: $(OS)) 27 | endif 28 | 29 | ifdef EMSCRIPTEN 30 | ARCH := wasm 31 | endif 32 | 33 | PLATFORM_ARCH := $(PLATFORM)-$(ARCH) 34 | SRC_FILES := src/wasm_wrapper.c 35 | LIBPG_QUERY_DIR := $(CACHE_DIR)/$(PLATFORM_ARCH)/libpg_query/$(LIBPG_QUERY_TAG) 36 | LIBPG_QUERY_ARCHIVE := $(LIBPG_QUERY_DIR)/libpg_query.a 37 | LIBPG_QUERY_HEADER := $(LIBPG_QUERY_DIR)/pg_query.h 38 | CXXFLAGS := -O3 -flto 39 | 40 | ifdef EMSCRIPTEN 41 | OUT_FILES := $(foreach EXT,.js .wasm,$(WASM_OUT_DIR)/$(WASM_OUT_NAME)$(EXT)) 42 | else 43 | $(error Native builds are no longer supported. Use EMSCRIPTEN=1 for WASM builds only.) 44 | endif 45 | 46 | # Clone libpg_query source (lives in CACHE_DIR) 47 | $(LIBPG_QUERY_DIR): 48 | mkdir -p $(CACHE_DIR) 49 | git clone -b $(LIBPG_QUERY_TAG) --single-branch $(LIBPG_QUERY_REPO) $(LIBPG_QUERY_DIR) 50 | 51 | $(LIBPG_QUERY_HEADER): $(LIBPG_QUERY_DIR) 52 | 53 | # Build libpg_query 54 | $(LIBPG_QUERY_ARCHIVE): $(LIBPG_QUERY_DIR) 55 | cd $(LIBPG_QUERY_DIR); $(MAKE) build 56 | 57 | # Build libpg-query-node WASM module 58 | $(OUT_FILES): $(LIBPG_QUERY_ARCHIVE) $(LIBPG_QUERY_HEADER) $(SRC_FILES) 59 | ifdef EMSCRIPTEN 60 | mkdir -p $(WASM_OUT_DIR) 61 | $(CC) \ 62 | -v \ 63 | $(CXXFLAGS) \ 64 | -I$(LIBPG_QUERY_DIR) \ 65 | -I$(LIBPG_QUERY_DIR)/vendor \ 66 | -L$(LIBPG_QUERY_DIR) \ 67 | -sEXPORTED_FUNCTIONS="['_malloc','_free','_wasm_parse_query_raw','_wasm_free_parse_result']" \ 68 | -sEXPORTED_RUNTIME_METHODS="['lengthBytesUTF8','stringToUTF8','getValue','UTF8ToString','HEAPU8','HEAPU32']" \ 69 | -sEXPORT_NAME="$(WASM_MODULE_NAME)" \ 70 | -sENVIRONMENT="web,node,worker" \ 71 | -sASSERTIONS=0 \ 72 | -sSINGLE_FILE=0 \ 73 | -sMODULARIZE=1 \ 74 | -sEXPORT_ES6=0 \ 75 | -sALLOW_MEMORY_GROWTH=1 \ 76 | -sINITIAL_MEMORY=134217728 \ 77 | -sMAXIMUM_MEMORY=1073741824 \ 78 | -sSTACK_SIZE=33554432 \ 79 | -lpg_query \ 80 | -o $@ \ 81 | $(SRC_FILES) 82 | else 83 | $(error Native builds are no longer supported. Use EMSCRIPTEN=1 for WASM builds only.) 84 | endif 85 | 86 | # Commands 87 | build: $(OUT_FILES) 88 | 89 | build-cache: $(LIBPG_QUERY_ARCHIVE) $(LIBPG_QUERY_HEADER) 90 | 91 | rebuild: clean build 92 | 93 | rebuild-cache: clean-cache build-cache 94 | 95 | clean: 96 | -@ rm -r $(OUT_FILES) > /dev/null 2>&1 97 | 98 | clean-cache: 99 | -@ rm -rf $(LIBPG_QUERY_DIR) 100 | 101 | .PHONY: build build-cache rebuild rebuild-cache clean clean-cache 102 | -------------------------------------------------------------------------------- /versions/13/Makefile: -------------------------------------------------------------------------------- 1 | # DO NOT MODIFY MANUALLY — this is generated from the templates dir 2 | # 3 | # To make changes, edit the files in the templates/ directory and run: 4 | # npm run copy:templates 5 | 6 | WASM_OUT_DIR := wasm 7 | WASM_OUT_NAME := libpg-query 8 | WASM_MODULE_NAME := PgQueryModule 9 | LIBPG_QUERY_REPO := https://github.com/pganalyze/libpg_query.git 10 | LIBPG_QUERY_TAG := 13-2.2.0 11 | 12 | CACHE_DIR := .cache 13 | 14 | OS ?= $(shell uname -s) 15 | ARCH ?= $(shell uname -m) 16 | 17 | ifdef EMSCRIPTEN 18 | PLATFORM := emscripten 19 | else ifeq ($(OS),Darwin) 20 | PLATFORM := darwin 21 | else ifeq ($(OS),Linux) 22 | PLATFORM := linux 23 | else 24 | $(error Unsupported platform: $(OS)) 25 | endif 26 | 27 | ifdef EMSCRIPTEN 28 | ARCH := wasm 29 | endif 30 | 31 | PLATFORM_ARCH := $(PLATFORM)-$(ARCH) 32 | SRC_FILES := src/wasm_wrapper.c 33 | LIBPG_QUERY_DIR := $(CACHE_DIR)/$(PLATFORM_ARCH)/libpg_query/$(LIBPG_QUERY_TAG) 34 | LIBPG_QUERY_ARCHIVE := $(LIBPG_QUERY_DIR)/libpg_query.a 35 | LIBPG_QUERY_HEADER := $(LIBPG_QUERY_DIR)/pg_query.h 36 | CXXFLAGS := -O3 -flto 37 | 38 | ifdef EMSCRIPTEN 39 | OUT_FILES := $(foreach EXT,.js .wasm,$(WASM_OUT_DIR)/$(WASM_OUT_NAME)$(EXT)) 40 | else 41 | $(error Native builds are no longer supported. Use EMSCRIPTEN=1 for WASM builds only.) 42 | endif 43 | 44 | # Clone libpg_query source (lives in CACHE_DIR) 45 | $(LIBPG_QUERY_DIR): 46 | mkdir -p $(CACHE_DIR) 47 | git clone -b $(LIBPG_QUERY_TAG) --single-branch $(LIBPG_QUERY_REPO) $(LIBPG_QUERY_DIR) 48 | ifdef EMSCRIPTEN 49 | cd $(LIBPG_QUERY_DIR); patch -p1 < $(shell pwd)/patches/emscripten_disable_spinlocks.patch 50 | endif 51 | 52 | $(LIBPG_QUERY_HEADER): $(LIBPG_QUERY_DIR) 53 | 54 | # Build libpg_query 55 | $(LIBPG_QUERY_ARCHIVE): $(LIBPG_QUERY_DIR) 56 | cd $(LIBPG_QUERY_DIR); $(MAKE) build 57 | 58 | # Build libpg-query-node WASM module 59 | $(OUT_FILES): $(LIBPG_QUERY_ARCHIVE) $(LIBPG_QUERY_HEADER) $(SRC_FILES) 60 | ifdef EMSCRIPTEN 61 | mkdir -p $(WASM_OUT_DIR) 62 | $(CC) \ 63 | -v \ 64 | $(CXXFLAGS) \ 65 | -I$(LIBPG_QUERY_DIR) \ 66 | -I$(LIBPG_QUERY_DIR)/vendor \ 67 | -L$(LIBPG_QUERY_DIR) \ 68 | -sEXPORTED_FUNCTIONS="['_malloc','_free','_wasm_parse_query_raw','_wasm_free_parse_result']" \ 69 | -sEXPORTED_RUNTIME_METHODS="['lengthBytesUTF8','stringToUTF8','getValue','UTF8ToString','HEAPU8','HEAPU32']" \ 70 | -sEXPORT_NAME="$(WASM_MODULE_NAME)" \ 71 | -sENVIRONMENT="web,node,worker" \ 72 | -sASSERTIONS=0 \ 73 | -sSINGLE_FILE=0 \ 74 | -sMODULARIZE=1 \ 75 | -sEXPORT_ES6=0 \ 76 | -sALLOW_MEMORY_GROWTH=1 \ 77 | -sINITIAL_MEMORY=134217728 \ 78 | -sMAXIMUM_MEMORY=1073741824 \ 79 | -sSTACK_SIZE=33554432 \ 80 | -lpg_query \ 81 | -o $@ \ 82 | $(SRC_FILES) 83 | else 84 | $(error Native builds are no longer supported. Use EMSCRIPTEN=1 for WASM builds only.) 85 | endif 86 | 87 | # Commands 88 | build: $(OUT_FILES) 89 | 90 | build-cache: $(LIBPG_QUERY_ARCHIVE) $(LIBPG_QUERY_HEADER) 91 | 92 | rebuild: clean build 93 | 94 | rebuild-cache: clean-cache build-cache 95 | 96 | clean: 97 | -@ rm -r $(OUT_FILES) > /dev/null 2>&1 98 | 99 | clean-cache: 100 | -@ rm -rf $(LIBPG_QUERY_DIR) 101 | 102 | .PHONY: build build-cache rebuild rebuild-cache clean clean-cache 103 | -------------------------------------------------------------------------------- /parser/test/errors.test.js: -------------------------------------------------------------------------------- 1 | const { describe, it } = require('node:test'); 2 | const assert = require('node:assert/strict'); 3 | const { Parser } = require('../wasm/index.cjs'); 4 | 5 | describe('Parser Error Handling', () => { 6 | describe('Error propagation across versions', () => { 7 | const versions = [13, 14, 15, 16, 17]; 8 | const invalidQuery = 'SELECT * FROM users WHERE id = @'; 9 | 10 | for (const version of versions) { 11 | it(`should handle parse errors in PostgreSQL v${version}`, async () => { 12 | const parser = new Parser({version}); 13 | 14 | // Test async parse 15 | await assert.rejects( 16 | async () => await parser.parse(invalidQuery), 17 | (error) => { 18 | assert.ok(error instanceof Error); 19 | assert.ok(error.message.includes('syntax error')); 20 | // Check that sqlDetails are preserved 21 | assert.ok('sqlDetails' in error); 22 | assert.ok(error.sqlDetails.cursorPosition >= 0); 23 | return true; 24 | } 25 | ); 26 | 27 | // Load parser for sync test 28 | await parser.loadParser(); 29 | 30 | // Test sync parse 31 | assert.throws( 32 | () => parser.parseSync(invalidQuery), 33 | (error) => { 34 | assert.ok(error instanceof Error); 35 | assert.ok(error.message.includes('syntax error')); 36 | // Check that sqlDetails are preserved 37 | assert.ok('sqlDetails' in error); 38 | assert.ok(error.sqlDetails.cursorPosition >= 0); 39 | return true; 40 | } 41 | ); 42 | }); 43 | } 44 | }); 45 | 46 | describe('Error details preservation', () => { 47 | it('should preserve error details from underlying parser', async () => { 48 | const parser = new Parser({ version: 17 }); 49 | await parser.loadParser(); 50 | 51 | try { 52 | parser.parseSync('SELECT * FROM users WHERE id = @'); 53 | assert.fail('Expected error'); 54 | } catch (error) { 55 | // Check that the error is preserved as-is 56 | assert.ok(error.message.includes('syntax error')); 57 | assert.ok('sqlDetails' in error); 58 | assert.equal(error.sqlDetails.cursorPosition, 32); 59 | assert.equal(error.sqlDetails.fileName, 'scan.l'); 60 | assert.equal(error.sqlDetails.functionName, 'scanner_yyerror'); 61 | } 62 | }); 63 | }); 64 | 65 | describe('Invalid version handling', () => { 66 | it('should throw error for unsupported version', () => { 67 | assert.throws( 68 | () => new Parser({ version: 12 }), 69 | { 70 | message: 'Unsupported PostgreSQL version: 12. Supported versions are 13, 14, 15, 16, 17.' 71 | } 72 | ); 73 | }); 74 | }); 75 | 76 | describe('Parser not loaded error', () => { 77 | it('should throw error when using parseSync without loading', () => { 78 | const parser = new Parser({ version: 17 }); 79 | 80 | assert.throws( 81 | () => parser.parseSync('SELECT 1'), 82 | { 83 | message: 'Parser not loaded. Call loadParser() first or use parse() for automatic loading.' 84 | } 85 | ); 86 | }); 87 | }); 88 | }); -------------------------------------------------------------------------------- /scripts/fetch-protos.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | const fs = require('fs'); 4 | const path = require('path'); 5 | const https = require('https'); 6 | 7 | // Read all version packages and extract x-publish metadata 8 | function getVersionMappings() { 9 | const versionsDir = path.join(__dirname, '..', 'versions'); 10 | const mappings = []; 11 | 12 | for (const version of ['13', '14', '15', '16', '17']) { 13 | const packagePath = path.join(versionsDir, version, 'package.json'); 14 | if (fs.existsSync(packagePath)) { 15 | const pkg = JSON.parse(fs.readFileSync(packagePath, 'utf8')); 16 | if (pkg['x-publish']) { 17 | mappings.push({ 18 | pgVersion: pkg['x-publish'].pgVersion, 19 | packageVersion: pkg.version, 20 | distTag: pkg['x-publish'].distTag, 21 | libpgQueryTag: pkg['x-publish'].libpgQueryTag 22 | }); 23 | } 24 | } 25 | } 26 | 27 | return mappings; 28 | } 29 | 30 | // Download file from URL 31 | function downloadFile(url, dest) { 32 | return new Promise((resolve, reject) => { 33 | const file = fs.createWriteStream(dest); 34 | console.log('Downloading', url, 'to', dest); 35 | https.get(url, (response) => { 36 | if (response.statusCode === 200) { 37 | response.pipe(file); 38 | file.on('finish', () => { 39 | file.close(); 40 | resolve(); 41 | }); 42 | } else { 43 | reject(new Error(`HTTP ${response.statusCode}: ${response.statusMessage}`)); 44 | } 45 | }).on('error', (err) => { 46 | reject(err); 47 | }); 48 | }); 49 | } 50 | 51 | // Main function 52 | async function fetchProtos() { 53 | const mappings = getVersionMappings(); 54 | const protosDir = path.join(__dirname, '..', 'protos'); 55 | 56 | // Create protos directory if it doesn't exist 57 | if (!fs.existsSync(protosDir)) { 58 | fs.mkdirSync(protosDir, { recursive: true }); 59 | } 60 | 61 | console.log('Fetching protobuf files for all versions...\n'); 62 | 63 | for (const mapping of mappings) { 64 | const { pgVersion, libpgQueryTag } = mapping; 65 | const versionDir = path.join(protosDir, pgVersion); 66 | 67 | // Create version directory 68 | if (!fs.existsSync(versionDir)) { 69 | fs.mkdirSync(versionDir, { recursive: true }); 70 | } 71 | 72 | // Use the libpgQueryTag from the Makefile 73 | const url = `https://raw.githubusercontent.com/pganalyze/libpg_query/refs/tags/${libpgQueryTag}/protobuf/pg_query.proto`; 74 | const destPath = path.join(versionDir, 'pg_query.proto'); 75 | 76 | console.log(`Fetching protobuf for PostgreSQL ${pgVersion} with tag ${libpgQueryTag}...`); 77 | 78 | try { 79 | await downloadFile(url, destPath); 80 | console.log(`✅ Successfully downloaded protobuf for PostgreSQL ${pgVersion}`); 81 | console.log(` Source: ${url}`); 82 | console.log(` Saved to: ${destPath}\n`); 83 | } catch (error) { 84 | console.log(`❌ Failed to fetch protobuf for PostgreSQL ${pgVersion}: ${error.message}\n`); 85 | } 86 | } 87 | 88 | console.log('Protobuf fetch completed!'); 89 | } 90 | 91 | // Run the script 92 | if (require.main === module) { 93 | fetchProtos().catch(console.error); 94 | } 95 | 96 | module.exports = { fetchProtos, getVersionMappings }; -------------------------------------------------------------------------------- /scripts/prepare-enums.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | const fs = require('fs'); 4 | const path = require('path'); 5 | 6 | /** 7 | * Script to prepare enums packages for publishing by modifying their dist/package.json 8 | * to use the correct publishing name and dist-tag from x-publish metadata 9 | */ 10 | 11 | function preparePackageForPublish(packageDir) { 12 | const packageJsonPath = path.join(packageDir, 'package.json'); 13 | const distPackageJsonPath = path.join(packageDir, 'dist', 'package.json'); 14 | 15 | if (!fs.existsSync(packageJsonPath)) { 16 | console.error(`❌ Package.json not found: ${packageJsonPath}`); 17 | return false; 18 | } 19 | 20 | if (!fs.existsSync(distPackageJsonPath)) { 21 | console.error(`❌ Dist package.json not found: ${distPackageJsonPath}`); 22 | return false; 23 | } 24 | 25 | try { 26 | const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8')); 27 | const distPackageJson = JSON.parse(fs.readFileSync(distPackageJsonPath, 'utf8')); 28 | 29 | if (!packageJson['x-publish']) { 30 | console.error(`❌ No x-publish metadata found in ${packageDir}`); 31 | return false; 32 | } 33 | 34 | const { publishName, distTag } = packageJson['x-publish']; 35 | 36 | if (!publishName) { 37 | console.error(`❌ No publishName found in x-publish metadata for ${packageDir}`); 38 | return false; 39 | } 40 | 41 | // Modify the dist package.json 42 | distPackageJson.name = publishName; 43 | 44 | // Add dist-tag to publishConfig if specified 45 | if (distTag) { 46 | if (!distPackageJson.publishConfig) { 47 | distPackageJson.publishConfig = {}; 48 | } 49 | distPackageJson.publishConfig.tag = distTag; 50 | } 51 | 52 | // Remove x-publish metadata from the dist version 53 | delete distPackageJson['x-publish']; 54 | 55 | // Write the modified package.json back to dist 56 | fs.writeFileSync(distPackageJsonPath, JSON.stringify(distPackageJson, null, 2) + '\n'); 57 | 58 | console.log(`✅ Prepared ${packageDir} for publishing as ${publishName}${distTag ? ` with tag ${distTag}` : ''}`); 59 | return true; 60 | 61 | } catch (error) { 62 | console.error(`❌ Error preparing ${packageDir}: ${error.message}`); 63 | return false; 64 | } 65 | } 66 | 67 | function main() { 68 | const enumsDir = path.join(__dirname, '..', 'enums'); 69 | 70 | if (!fs.existsSync(enumsDir)) { 71 | console.error('❌ Enums directory not found'); 72 | process.exit(1); 73 | } 74 | 75 | const enumsPackages = fs.readdirSync(enumsDir) 76 | .filter(dir => fs.statSync(path.join(enumsDir, dir)).isDirectory()) 77 | .sort(); 78 | 79 | console.log(`📦 Found ${enumsPackages.length} enums packages: ${enumsPackages.join(', ')}\n`); 80 | 81 | let successCount = 0; 82 | 83 | for (const packageName of enumsPackages) { 84 | const packagePath = path.join(enumsDir, packageName); 85 | console.log(`🔧 Preparing enums/${packageName}...`); 86 | 87 | if (preparePackageForPublish(packagePath)) { 88 | successCount++; 89 | } 90 | console.log(''); 91 | } 92 | 93 | console.log('=================================================='); 94 | console.log(`Prepare Summary:`); 95 | console.log(`✅ Successful: ${successCount}`); 96 | console.log(`❌ Failed: ${enumsPackages.length - successCount}`); 97 | console.log(`📦 Total packages: ${enumsPackages.length}`); 98 | 99 | if (successCount < enumsPackages.length) { 100 | process.exit(1); 101 | } 102 | } 103 | 104 | if (require.main === module) { 105 | main(); 106 | } 107 | 108 | module.exports = { preparePackageForPublish }; -------------------------------------------------------------------------------- /scripts/prepare-types.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | const fs = require('fs'); 4 | const path = require('path'); 5 | 6 | /** 7 | * Script to prepare types packages for publishing by modifying their dist/package.json 8 | * to use the correct publishing name and dist-tag from x-publish metadata 9 | */ 10 | 11 | function preparePackageForPublish(packageDir) { 12 | const packageJsonPath = path.join(packageDir, 'package.json'); 13 | const distPackageJsonPath = path.join(packageDir, 'dist', 'package.json'); 14 | 15 | if (!fs.existsSync(packageJsonPath)) { 16 | console.error(`❌ Package.json not found: ${packageJsonPath}`); 17 | return false; 18 | } 19 | 20 | if (!fs.existsSync(distPackageJsonPath)) { 21 | console.error(`❌ Dist package.json not found: ${distPackageJsonPath}`); 22 | return false; 23 | } 24 | 25 | try { 26 | const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8')); 27 | const distPackageJson = JSON.parse(fs.readFileSync(distPackageJsonPath, 'utf8')); 28 | 29 | if (!packageJson['x-publish']) { 30 | console.error(`❌ No x-publish metadata found in ${packageDir}`); 31 | return false; 32 | } 33 | 34 | const { publishName, distTag } = packageJson['x-publish']; 35 | 36 | if (!publishName) { 37 | console.error(`❌ No publishName found in x-publish metadata for ${packageDir}`); 38 | return false; 39 | } 40 | 41 | // Modify the dist package.json 42 | distPackageJson.name = publishName; 43 | 44 | // Add dist-tag to publishConfig if specified 45 | if (distTag) { 46 | if (!distPackageJson.publishConfig) { 47 | distPackageJson.publishConfig = {}; 48 | } 49 | distPackageJson.publishConfig.tag = distTag; 50 | } 51 | 52 | // Remove x-publish metadata from the dist version 53 | delete distPackageJson['x-publish']; 54 | 55 | // Write the modified package.json back to dist 56 | fs.writeFileSync(distPackageJsonPath, JSON.stringify(distPackageJson, null, 2) + '\n'); 57 | 58 | console.log(`✅ Prepared ${packageDir} for publishing as ${publishName}${distTag ? ` with tag ${distTag}` : ''}`); 59 | return true; 60 | 61 | } catch (error) { 62 | console.error(`❌ Error preparing ${packageDir}: ${error.message}`); 63 | return false; 64 | } 65 | } 66 | 67 | function main() { 68 | const typesDir = path.join(__dirname, '..', 'types'); 69 | 70 | if (!fs.existsSync(typesDir)) { 71 | console.error('❌ Types directory not found'); 72 | process.exit(1); 73 | } 74 | 75 | const typesPackages = fs.readdirSync(typesDir) 76 | .filter(dir => fs.statSync(path.join(typesDir, dir)).isDirectory()) 77 | .sort(); 78 | 79 | console.log(`📦 Found ${typesPackages.length} types packages: ${typesPackages.join(', ')}\n`); 80 | 81 | let successCount = 0; 82 | 83 | for (const packageName of typesPackages) { 84 | const packagePath = path.join(typesDir, packageName); 85 | console.log(`🔧 Preparing types/${packageName}...`); 86 | 87 | if (preparePackageForPublish(packagePath)) { 88 | successCount++; 89 | } 90 | console.log(''); 91 | } 92 | 93 | console.log('=================================================='); 94 | console.log(`Prepare Summary:`); 95 | console.log(`✅ Successful: ${successCount}`); 96 | console.log(`❌ Failed: ${typesPackages.length - successCount}`); 97 | console.log(`📦 Total packages: ${typesPackages.length}`); 98 | 99 | if (successCount < typesPackages.length) { 100 | process.exit(1); 101 | } 102 | } 103 | 104 | if (require.main === module) { 105 | main(); 106 | } 107 | 108 | module.exports = { preparePackageForPublish }; -------------------------------------------------------------------------------- /parser/test/parsing.test.js: -------------------------------------------------------------------------------- 1 | const { describe, it, before } = require('node:test'); 2 | const assert = require('node:assert/strict'); 3 | const { Parser } = require('../wasm/index.cjs'); 4 | 5 | describe('Parser', () => { 6 | describe('Dynamic API', () => { 7 | it('should parse SQL with default version', async () => { 8 | const parser = new Parser(); 9 | const result = await parser.parse('SELECT 1+1 as sum'); 10 | assert.ok(result); 11 | assert.ok(result.stmts); 12 | assert.equal(result.stmts.length, 1); 13 | }); 14 | 15 | it('should parse SQL with specific version', async () => { 16 | // Get available versions from the Parser class 17 | const parser = new Parser(); 18 | const defaultVersion = parser.version; 19 | 20 | // Test with a different version if available 21 | const testVersion = defaultVersion === 17 ? 16 : 15; 22 | try { 23 | const versionParser = new Parser({ version: testVersion }); 24 | const result = await versionParser.parse('SELECT 1+1 as sum'); 25 | assert.equal(versionParser.version, testVersion); 26 | assert.ok(result); 27 | } catch (e) { 28 | // Version might not be available in this build 29 | console.log(`Version ${testVersion} not available in this build`); 30 | } 31 | }); 32 | 33 | it('should handle parse errors', async () => { 34 | const parser = new Parser(); 35 | try { 36 | await parser.parse('INVALID SQL'); 37 | assert.fail('Should have thrown an error'); 38 | } catch (error) { 39 | assert.ok(error); 40 | assert.ok(error.message.includes('syntax error')); 41 | } 42 | }); 43 | 44 | it('should work with Parser class', async () => { 45 | const parser = new Parser(); 46 | const result = await parser.parse('SELECT * FROM users'); 47 | assert.ok(result); 48 | assert.ok(result.stmts); 49 | }); 50 | 51 | it('should validate version in constructor', () => { 52 | // Test invalid version 53 | assert.throws(() => { 54 | new Parser({ version: 99 }); 55 | }, /Unsupported PostgreSQL version/); 56 | }); 57 | 58 | it('should support parseSync after initial parse', async () => { 59 | const parser = new Parser(); 60 | 61 | // First parse to initialize 62 | await parser.parse('SELECT 1'); 63 | 64 | // Now parseSync should work 65 | const result = parser.parseSync('SELECT 2+2 as sum'); 66 | assert.ok(result); 67 | assert.ok(result.stmts); 68 | assert.equal(result.stmts.length, 1); 69 | }); 70 | }); 71 | 72 | describe('Version-specific imports', () => { 73 | // Dynamically test available version imports 74 | const versions = [13, 14, 15, 16, 17]; 75 | 76 | for (const version of versions) { 77 | it(`should parse with v${version} if available`, async () => { 78 | try { 79 | const versionModule = require(`../wasm/v${version}.cjs`); 80 | await versionModule.loadModule(); 81 | const result = await versionModule.parse('SELECT 1'); 82 | assert.ok(result); 83 | assert.equal(result.stmts.length, 1); 84 | } catch (e) { 85 | // Version not available in this build 86 | console.log(`Version ${version} not available in this build`); 87 | } 88 | }); 89 | } 90 | }); 91 | }); 92 | 93 | describe('Issue Test - INSERT with multiple VALUES', () => { 94 | const testSQL = "INSERT INTO logtable (message) VALUES ('Init'), ('Reboot'), ('ERROR'), ('Warning'), ('info');"; 95 | const versions = [13, 14, 15, 16, 17]; 96 | 97 | for (const version of versions) { 98 | it(`should parse with PostgreSQL v${version} without throwing`, async () => { 99 | try { 100 | const versionModule = require(`../wasm/v${version}.cjs`); 101 | await versionModule.loadModule(); 102 | const result = await versionModule.parse(testSQL); 103 | assert.ok(result); // Just verify we got a result 104 | } catch (e) { 105 | if (e.code === 'MODULE_NOT_FOUND') { 106 | console.log(`Version ${version} not available in this build`); 107 | } else { 108 | throw e; 109 | } 110 | } 111 | }); 112 | } 113 | }); -------------------------------------------------------------------------------- /scripts/update-versions-types.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | const fs = require('fs'); 4 | const path = require('path'); 5 | const { execSync } = require('child_process'); 6 | 7 | console.log('🔄 Updating @pgsql/types versions in versions/* packages...\n'); 8 | 9 | // Fetch dist-tags for @pgsql/types from npm 10 | console.log('📡 Fetching latest @pgsql/types versions from npm dist-tags...'); 11 | let distTags; 12 | try { 13 | const npmOutput = execSync('npm view @pgsql/types dist-tags --json', { encoding: 'utf8' }); 14 | distTags = JSON.parse(npmOutput); 15 | } catch (error) { 16 | console.error('❌ Failed to fetch npm data:', error.message); 17 | process.exit(1); 18 | } 19 | 20 | // Extract versions for PostgreSQL 13-17 21 | const typeVersions = {}; 22 | for (let pgVersion = 13; pgVersion <= 17; pgVersion++) { 23 | const tag = `pg${pgVersion}`; 24 | if (distTags[tag]) { 25 | typeVersions[pgVersion.toString()] = distTags[tag]; 26 | } 27 | } 28 | 29 | console.log('\n📦 Found latest versions from npm:'); 30 | Object.entries(typeVersions).sort(([a], [b]) => parseInt(a) - parseInt(b)).forEach(([major, version]) => { 31 | console.log(` PostgreSQL ${major} → @pgsql/types@${version}`); 32 | }); 33 | console.log(); 34 | 35 | // Get all version directories 36 | const versionsDir = path.join(__dirname, '..', 'versions'); 37 | const versionDirs = fs.readdirSync(versionsDir) 38 | .filter(dir => /^\d+$/.test(dir)) 39 | .sort((a, b) => parseInt(a) - parseInt(b)); 40 | 41 | let updatedCount = 0; 42 | 43 | versionDirs.forEach(version => { 44 | const packageJsonPath = path.join(versionsDir, version, 'package.json'); 45 | 46 | if (!fs.existsSync(packageJsonPath)) { 47 | console.log(`⚠️ No package.json found for version ${version}`); 48 | return; 49 | } 50 | 51 | const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8')); 52 | const targetTypeVersion = typeVersions[version]; 53 | 54 | if (!targetTypeVersion) { 55 | console.log(`⚠️ No type version mapping found for PostgreSQL ${version}`); 56 | return; 57 | } 58 | 59 | const currentTypeVersion = packageJson.dependencies?.['@pgsql/types']; 60 | const expectedTypeVersion = `^${targetTypeVersion}`; 61 | 62 | if (currentTypeVersion === expectedTypeVersion) { 63 | console.log(`✅ Version ${version}: @pgsql/types already up to date (${currentTypeVersion})`); 64 | return; 65 | } 66 | 67 | // Update the dependency 68 | if (!packageJson.dependencies) { 69 | packageJson.dependencies = {}; 70 | } 71 | 72 | packageJson.dependencies['@pgsql/types'] = expectedTypeVersion; 73 | 74 | // Write back the updated package.json 75 | fs.writeFileSync( 76 | packageJsonPath, 77 | JSON.stringify(packageJson, null, 2) + '\n', 78 | 'utf8' 79 | ); 80 | 81 | console.log(`📦 Version ${version}: Updated @pgsql/types from ${currentTypeVersion || 'none'} to ${expectedTypeVersion}`); 82 | updatedCount++; 83 | }); 84 | 85 | // Also update the full package (which uses PostgreSQL 17) 86 | console.log('\n📦 Checking full package...'); 87 | const fullPackageJsonPath = path.join(__dirname, '..', 'full', 'package.json'); 88 | 89 | if (fs.existsSync(fullPackageJsonPath)) { 90 | const fullPackageJson = JSON.parse(fs.readFileSync(fullPackageJsonPath, 'utf8')); 91 | const targetTypeVersion = typeVersions['17']; // Full package uses PG 17 92 | 93 | if (targetTypeVersion) { 94 | const currentTypeVersion = fullPackageJson.dependencies?.['@pgsql/types']; 95 | const expectedTypeVersion = `^${targetTypeVersion}`; 96 | 97 | if (currentTypeVersion === expectedTypeVersion) { 98 | console.log(`✅ Full package: @pgsql/types already up to date (${currentTypeVersion})`); 99 | } else { 100 | // Update the dependency 101 | if (!fullPackageJson.dependencies) { 102 | fullPackageJson.dependencies = {}; 103 | } 104 | 105 | fullPackageJson.dependencies['@pgsql/types'] = expectedTypeVersion; 106 | 107 | // Write back the updated package.json 108 | fs.writeFileSync( 109 | fullPackageJsonPath, 110 | JSON.stringify(fullPackageJson, null, 2) + '\n', 111 | 'utf8' 112 | ); 113 | 114 | console.log(`📦 Full package: Updated @pgsql/types from ${currentTypeVersion || 'none'} to ${expectedTypeVersion}`); 115 | updatedCount++; 116 | } 117 | } 118 | } 119 | 120 | console.log(`\n✨ Updated ${updatedCount} package(s)`); 121 | 122 | if (updatedCount > 0) { 123 | console.log('\n💡 Next steps:'); 124 | console.log(' 1. Run "pnpm install" to update lockfile'); 125 | console.log(' 2. Test the changes'); 126 | console.log(' 3. Commit the updates'); 127 | } -------------------------------------------------------------------------------- /scripts/copy-templates.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | const fs = require('fs'); 4 | const path = require('path'); 5 | const glob = require('glob'); 6 | 7 | const HEADER = `/** 8 | * DO NOT MODIFY MANUALLY — this is generated from the templates dir 9 | * 10 | * To make changes, edit the files in the templates/ directory and run: 11 | * npm run copy:templates 12 | */ 13 | 14 | `; 15 | 16 | const MAKEFILE_HEADER = `# DO NOT MODIFY MANUALLY — this is generated from the templates dir 17 | # 18 | # To make changes, edit the files in the templates/ directory and run: 19 | # npm run copy:templates 20 | 21 | `; 22 | 23 | // Load version configurations from package.json files 24 | function loadVersionConfigs() { 25 | const configs = {}; 26 | const packageFiles = glob.sync('versions/*/package.json'); 27 | 28 | console.log(`Found ${packageFiles.length} package.json files\n`); 29 | 30 | packageFiles.forEach(packageFile => { 31 | try { 32 | const packageData = JSON.parse(fs.readFileSync(packageFile, 'utf8')); 33 | const version = packageData['x-publish']?.pgVersion; 34 | const libpgQueryTag = packageData['x-publish']?.libpgQueryTag; 35 | 36 | if (version && libpgQueryTag) { 37 | configs[version] = { 38 | tag: libpgQueryTag, 39 | hasEmscriptenPatch: version === '13' // Only version 13 needs the patch 40 | }; 41 | console.log(` Version ${version}: tag ${libpgQueryTag}`); 42 | } else { 43 | console.warn(` Warning: Missing x-publish data in ${packageFile}`); 44 | } 45 | } catch (error) { 46 | console.error(` Error reading ${packageFile}: ${error.message}`); 47 | } 48 | }); 49 | 50 | console.log(''); // Empty line for readability 51 | return configs; 52 | } 53 | 54 | // Load configurations 55 | const VERSION_CONFIGS = loadVersionConfigs(); 56 | 57 | // Files to copy from templates 58 | const TEMPLATE_FILES = [ 59 | { src: 'LICENSE', dest: 'LICENSE', header: false }, 60 | { src: 'wasm_wrapper.c', dest: 'src/wasm_wrapper.c', header: HEADER }, 61 | { src: 'libpg-query.d.ts', dest: 'src/libpg-query.d.ts', header: HEADER }, 62 | { src: 'index.ts', dest: 'src/index.ts', header: HEADER } 63 | ]; 64 | 65 | function copyTemplates() { 66 | const templatesDir = path.join(__dirname, '..', 'templates'); 67 | const versionsDir = path.join(__dirname, '..', 'versions'); 68 | 69 | // Process each version 70 | for (const [version, config] of Object.entries(VERSION_CONFIGS)) { 71 | const versionDir = path.join(versionsDir, version); 72 | console.log(`\nProcessing version ${version}...`); 73 | 74 | // Copy template files 75 | for (const file of TEMPLATE_FILES) { 76 | const srcPath = path.join(templatesDir, file.src); 77 | const destPath = path.join(versionDir, file.dest); 78 | 79 | // Ensure destination directory exists 80 | const destDir = path.dirname(destPath); 81 | if (!fs.existsSync(destDir)) { 82 | fs.mkdirSync(destDir, { recursive: true }); 83 | } 84 | 85 | // Read template content 86 | let content = fs.readFileSync(srcPath, 'utf8'); 87 | 88 | // Add header if specified 89 | if (file.header) { 90 | content = file.header + content; 91 | } 92 | 93 | // Write to destination 94 | fs.writeFileSync(destPath, content); 95 | console.log(` ✓ Copied ${file.src} to ${file.dest}`); 96 | } 97 | 98 | // Process Makefile template 99 | const makefileTemplate = fs.readFileSync(path.join(templatesDir, 'Makefile.template'), 'utf8'); 100 | let makefileContent = makefileTemplate.replace(/{{VERSION_TAG}}/g, config.tag); 101 | 102 | // Handle the USE_EMSCRIPTEN_PATCH placeholder 103 | if (config.hasEmscriptenPatch) { 104 | // For version 13, keep the patch block (remove only the placeholders) 105 | makefileContent = makefileContent.replace( 106 | /{{#USE_EMSCRIPTEN_PATCH}}\n?/g, 107 | '' 108 | ); 109 | makefileContent = makefileContent.replace( 110 | /{{\/USE_EMSCRIPTEN_PATCH}}\n?/g, 111 | '' 112 | ); 113 | } else { 114 | // For other versions, remove the entire block including placeholders 115 | makefileContent = makefileContent.replace( 116 | /{{#USE_EMSCRIPTEN_PATCH}}[\s\S]*?{{\/USE_EMSCRIPTEN_PATCH}}\n?/g, 117 | '' 118 | ); 119 | } 120 | 121 | // Write Makefile with header 122 | fs.writeFileSync(path.join(versionDir, 'Makefile'), MAKEFILE_HEADER + makefileContent); 123 | console.log(` ✓ Generated Makefile with tag ${config.tag}`); 124 | } 125 | 126 | console.log('\n✅ Template copying completed!'); 127 | } 128 | 129 | // Run the script 130 | copyTemplates(); -------------------------------------------------------------------------------- /versions/17/README_ERROR_HANDLING.md: -------------------------------------------------------------------------------- 1 | # Enhanced Error Handling in libpg-query-node v17 2 | 3 | ## Overview 4 | 5 | Version 17 includes enhanced error handling that provides detailed information about SQL parsing errors, including exact error positions, source file information, and visual error indicators. 6 | 7 | ## Error Details 8 | 9 | When a parsing error occurs, the error object now includes a `sqlDetails` property with the following information: 10 | 11 | ```typescript 12 | interface SqlErrorDetails { 13 | message: string; // Full error message 14 | cursorPosition: number; // 0-based position in the query 15 | fileName?: string; // Source file (e.g., 'scan.l', 'gram.y') 16 | functionName?: string; // Internal function name 17 | lineNumber?: number; // Line number in source file 18 | context?: string; // Additional context 19 | } 20 | ``` 21 | 22 | ## Basic Usage 23 | 24 | ```javascript 25 | const { parseSync, loadModule } = require('@libpg-query/v17'); 26 | 27 | await loadModule(); 28 | 29 | try { 30 | const result = parseSync("SELECT * FROM users WHERE id = 'unclosed"); 31 | } catch (error) { 32 | if (error.sqlDetails) { 33 | console.log('Error:', error.message); 34 | console.log('Position:', error.sqlDetails.cursorPosition); 35 | console.log('Source:', error.sqlDetails.fileName); 36 | } 37 | } 38 | ``` 39 | 40 | ## Error Formatting Helper 41 | 42 | The library includes a built-in `formatSqlError()` function for consistent error formatting: 43 | 44 | ```javascript 45 | const { parseSync, loadModule, formatSqlError } = require('@libpg-query/v17'); 46 | 47 | await loadModule(); 48 | 49 | const query = "SELECT * FROM users WHERE id = 'unclosed"; 50 | 51 | try { 52 | parseSync(query); 53 | } catch (error) { 54 | console.log(formatSqlError(error, query)); 55 | } 56 | ``` 57 | 58 | Output: 59 | ``` 60 | Error: unterminated quoted string at or near "'unclosed" 61 | Position: 31 62 | Source: file: scan.l, function: scanner_yyerror, line: 1262 63 | SELECT * FROM users WHERE id = 'unclosed 64 | ^ 65 | ``` 66 | 67 | ## Formatting Options 68 | 69 | The `formatSqlError()` function accepts options to customize the output: 70 | 71 | ```typescript 72 | interface SqlErrorFormatOptions { 73 | showPosition?: boolean; // Show the error position marker (default: true) 74 | showQuery?: boolean; // Show the query text (default: true) 75 | color?: boolean; // Use ANSI colors (default: false) 76 | maxQueryLength?: number; // Max query length to display (default: no limit) 77 | } 78 | ``` 79 | 80 | ### Examples 81 | 82 | #### With Colors (for terminal output) 83 | ```javascript 84 | console.log(formatSqlError(error, query, { color: true })); 85 | ``` 86 | 87 | #### Without Position Marker 88 | ```javascript 89 | console.log(formatSqlError(error, query, { showPosition: false })); 90 | ``` 91 | 92 | #### With Query Truncation (for long queries) 93 | ```javascript 94 | console.log(formatSqlError(error, longQuery, { maxQueryLength: 80 })); 95 | ``` 96 | 97 | ## Type Guard 98 | 99 | Use the `hasSqlDetails()` function to check if an error has SQL details: 100 | 101 | ```javascript 102 | const { hasSqlDetails } = require('@libpg-query/v17'); 103 | 104 | try { 105 | parseSync(query); 106 | } catch (error) { 107 | if (hasSqlDetails(error)) { 108 | // TypeScript knows error has sqlDetails property 109 | console.log('Error at position:', error.sqlDetails.cursorPosition); 110 | } 111 | } 112 | ``` 113 | 114 | ## Error Types 115 | 116 | Errors are classified by their source file: 117 | - **Lexer errors** (`scan.l`): Token recognition errors (invalid characters, unterminated strings) 118 | - **Parser errors** (`gram.y`): Grammar violations (syntax errors, missing keywords) 119 | 120 | ## Examples of Common Errors 121 | 122 | ### Unterminated String 123 | ```sql 124 | SELECT * FROM users WHERE name = 'unclosed 125 | ``` 126 | Error: `unterminated quoted string at or near "'unclosed"` 127 | 128 | ### Invalid Character 129 | ```sql 130 | SELECT * FROM users WHERE id = @ 131 | ``` 132 | Error: `syntax error at end of input` 133 | 134 | ### Reserved Keyword 135 | ```sql 136 | SELECT * FROM table 137 | ``` 138 | Error: `syntax error at or near "table"` (use quotes: `"table"`) 139 | 140 | ### Missing Keyword 141 | ```sql 142 | SELECT * WHERE id = 1 143 | ``` 144 | Error: `syntax error at or near "WHERE"` 145 | 146 | ## Backward Compatibility 147 | 148 | The enhanced error handling is fully backward compatible: 149 | - Existing code that catches errors will continue to work 150 | - The `sqlDetails` property is added without modifying the base Error object 151 | - All existing error properties and methods remain unchanged 152 | 153 | ## Migration Guide 154 | 155 | To take advantage of the new error handling: 156 | 157 | 1. **Check for sqlDetails**: 158 | ```javascript 159 | if (error.sqlDetails) { 160 | // Use enhanced error information 161 | } 162 | ``` 163 | 164 | 2. **Use the formatting helper**: 165 | ```javascript 166 | console.log(formatSqlError(error, query)); 167 | ``` 168 | 169 | 3. **Type-safe access** (TypeScript): 170 | ```typescript 171 | if (hasSqlDetails(error)) { 172 | // error.sqlDetails is now typed 173 | } 174 | ``` -------------------------------------------------------------------------------- /enums/13/README.md: -------------------------------------------------------------------------------- 1 | # @pgsql/enums 2 | 3 |

4 | 5 |

6 | 7 |

8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 |

16 | 17 | `@pgsql/enums` is a TypeScript library providing enum definitions for PostgreSQL AST nodes, primarily used in conjunction with [`pgsql-parser`](https://github.com/constructive-io/pgsql-parser). It offers a comprehensive and type-safe way to work with PostgreSQL enum values in query parsing and AST manipulation. 18 | 19 | 20 | ## Installation 21 | 22 | Install the package via npm: 23 | 24 | ```bash 25 | npm install @pgsql/enums 26 | ``` 27 | 28 | ## Usage 29 | 30 | Here's a simple example showing how to work with enums, converting between enum names and their numeric values: 31 | 32 | ```ts 33 | import { ObjectType } from '@pgsql/enums'; 34 | 35 | // Get the numeric value of an enum 36 | const tableValue = ObjectType.OBJECT_TABLE; 37 | console.log(tableValue); // 41 38 | 39 | // Convert from value back to enum name 40 | const enumName = ObjectType[41]; 41 | console.log(enumName); // "OBJECT_TABLE" 42 | 43 | // Use in comparisons 44 | if (someNode.objectType === ObjectType.OBJECT_TABLE) { 45 | console.log("This is a table object"); 46 | } 47 | ``` 48 | 49 | ## Versions 50 | 51 | Our latest is built with PostgreSQL 17 enum definitions. 52 | 53 | | PG Major Version | libpg_query | npm dist-tag 54 | |--------------------------|-------------|---------| 55 | | 17 | 17-6.1.0 | [`pg17`](https://www.npmjs.com/package/@pgsql/enums/v/latest) 56 | | 16 | 16-5.2.0 | [`pg16`](https://www.npmjs.com/package/@pgsql/enums/v/pg16) 57 | | 15 | 15-4.2.4 | [`pg15`](https://www.npmjs.com/package/@pgsql/enums/v/pg15) 58 | | 14 | 14-3.0.0 | [`pg14`](https://www.npmjs.com/package/@pgsql/enums/v/pg14) 59 | | 13 | 13-2.2.0 | [`pg13`](https://www.npmjs.com/package/@pgsql/enums/v/pg13) 60 | 61 | ## Related 62 | 63 | * [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. 64 | * [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`. 65 | * [@pgsql/parser](https://www.npmjs.com/package/@pgsql/parser): Multi-version PostgreSQL parser with dynamic version selection at runtime, supporting PostgreSQL 15, 16, and 17 in a single package. 66 | * [@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. 67 | * [@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. 68 | * [@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. 69 | * [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. 70 | * [libpg-query](https://github.com/constructive-io/libpg-query-node): The real PostgreSQL parser exposed for Node.js, used primarily in `pgsql-parser` for parsing and deparsing SQL queries. 71 | 72 | ## Credits 73 | 74 | **🛠 Built by the [Constructive](https://constructive.io) team — creators of modular Postgres tooling for secure, composable backends. If you like our work, contribute on [GitHub](https://github.com/constructive-io).** 75 | 76 | 77 | ## Disclaimer 78 | 79 | AS DESCRIBED IN THE LICENSES, THE SOFTWARE IS PROVIDED "AS IS", AT YOUR OWN RISK, AND WITHOUT WARRANTIES OF ANY KIND. 80 | 81 | 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. -------------------------------------------------------------------------------- /enums/14/README.md: -------------------------------------------------------------------------------- 1 | # @pgsql/enums 2 | 3 |

4 | 5 |

6 | 7 |

8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 |

16 | 17 | `@pgsql/enums` is a TypeScript library providing enum definitions for PostgreSQL AST nodes, primarily used in conjunction with [`pgsql-parser`](https://github.com/constructive-io/pgsql-parser). It offers a comprehensive and type-safe way to work with PostgreSQL enum values in query parsing and AST manipulation. 18 | 19 | 20 | ## Installation 21 | 22 | Install the package via npm: 23 | 24 | ```bash 25 | npm install @pgsql/enums 26 | ``` 27 | 28 | ## Usage 29 | 30 | Here's a simple example showing how to work with enums, converting between enum names and their numeric values: 31 | 32 | ```ts 33 | import { ObjectType } from '@pgsql/enums'; 34 | 35 | // Get the numeric value of an enum 36 | const tableValue = ObjectType.OBJECT_TABLE; 37 | console.log(tableValue); // 41 38 | 39 | // Convert from value back to enum name 40 | const enumName = ObjectType[41]; 41 | console.log(enumName); // "OBJECT_TABLE" 42 | 43 | // Use in comparisons 44 | if (someNode.objectType === ObjectType.OBJECT_TABLE) { 45 | console.log("This is a table object"); 46 | } 47 | ``` 48 | 49 | ## Versions 50 | 51 | Our latest is built with PostgreSQL 17 enum definitions. 52 | 53 | | PG Major Version | libpg_query | npm dist-tag 54 | |--------------------------|-------------|---------| 55 | | 17 | 17-6.1.0 | [`pg17`](https://www.npmjs.com/package/@pgsql/enums/v/latest) 56 | | 16 | 16-5.2.0 | [`pg16`](https://www.npmjs.com/package/@pgsql/enums/v/pg16) 57 | | 15 | 15-4.2.4 | [`pg15`](https://www.npmjs.com/package/@pgsql/enums/v/pg15) 58 | | 14 | 14-3.0.0 | [`pg14`](https://www.npmjs.com/package/@pgsql/enums/v/pg14) 59 | | 13 | 13-2.2.0 | [`pg13`](https://www.npmjs.com/package/@pgsql/enums/v/pg13) 60 | 61 | ## Related 62 | 63 | * [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. 64 | * [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`. 65 | * [@pgsql/parser](https://www.npmjs.com/package/@pgsql/parser): Multi-version PostgreSQL parser with dynamic version selection at runtime, supporting PostgreSQL 15, 16, and 17 in a single package. 66 | * [@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. 67 | * [@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. 68 | * [@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. 69 | * [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. 70 | * [libpg-query](https://github.com/constructive-io/libpg-query-node): The real PostgreSQL parser exposed for Node.js, used primarily in `pgsql-parser` for parsing and deparsing SQL queries. 71 | 72 | ## Credits 73 | 74 | **🛠 Built by the [Constructive](https://constructive.io) team — creators of modular Postgres tooling for secure, composable backends. If you like our work, contribute on [GitHub](https://github.com/constructive-io).** 75 | 76 | 77 | ## Disclaimer 78 | 79 | AS DESCRIBED IN THE LICENSES, THE SOFTWARE IS PROVIDED "AS IS", AT YOUR OWN RISK, AND WITHOUT WARRANTIES OF ANY KIND. 80 | 81 | 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. --------------------------------------------------------------------------------