Combined SQL + PL/pgSQL parser with hydrated ASTs and transform API.
⚠️ Experimental: This package is currently experimental. If you're looking for just SQL parsing, seepgsql-parser. For body-only PL/pgSQL deparsing, seeplpgsql-deparser.
This package provides a unified API for heterogeneous parsing and deparsing of SQL scripts containing PL/pgSQL functions. It handles the full pipeline: parsing SQL + PL/pgSQL together, transforming ASTs, and deparsing back to complete SQL.
Use this package when you need to:
- Parse and deparse complete
CREATE FUNCTIONstatements with PL/pgSQL bodies - Transform both SQL and embedded PL/pgSQL expressions (e.g., rename schemas)
- Round-trip SQL through parse → modify → deparse
Key features:
- Auto-detects
CREATE FUNCTIONstatements withLANGUAGE plpgsql - Hydrates PL/pgSQL function bodies into structured ASTs
- Automatic
RETURNstatement handling based on function return type - Transform API for parse → modify → deparse workflows
- Re-exports underlying primitives for power users
npm install plpgsql-parserimport { parse, transform, deparseSync, loadModule } from 'plpgsql-parser';
// Initialize the WASM module
await loadModule();
// Parse SQL with PL/pgSQL functions - auto-detects and hydrates
const result = parse(`
CREATE FUNCTION my_func(p_id int)
RETURNS void
LANGUAGE plpgsql
AS $$
BEGIN
RAISE NOTICE 'Hello %', p_id;
END;
$$;
`);
console.log(result.functions.length); // 1
console.log(result.functions[0].plpgsql.hydrated); // Hydrated AST
// Transform API for parse -> modify -> deparse pipeline
const output = transformSync(sql, (ctx) => {
// Modify the function name
ctx.functions[0].stmt.funcname[0].String.sval = 'renamed_func';
});
// Deparse back to SQL
const sql = deparseSync(result, { pretty: true });Parses SQL and auto-detects PL/pgSQL functions, hydrating their bodies.
Options:
hydrate(default:true) - Whether to hydrate PL/pgSQL function bodies
Returns a ParsedScript with:
sql- The raw SQL parse resultitems- Array of parsed items (statements and functions)functions- Array of detected PL/pgSQL functions with hydrated ASTs
Async transform pipeline: parse -> modify -> deparse.
Sync version of transform.
Converts a parsed script back to SQL.
Options:
pretty(default:true) - Whether to pretty-print the output
The package provides a visitor pattern for traversing PL/pgSQL ASTs, similar to @pgsql/traverse but designed for PL/pgSQL node types.
Walks the tree of PL/pgSQL AST nodes using a visitor pattern.
import { parse, walk, loadModule } from 'plpgsql-parser';
import type { PLpgSQLVisitor } from 'plpgsql-parser';
await loadModule();
const parsed = parse(`
CREATE FUNCTION get_user(p_id int)
RETURNS text
LANGUAGE plpgsql
AS $$
BEGIN
RETURN (SELECT name FROM users WHERE id = p_id);
END;
$$;
`);
// Visit PL/pgSQL nodes
const visitor: PLpgSQLVisitor = {
PLpgSQL_stmt_block: (path) => {
console.log('Found block at path:', path.path);
},
PLpgSQL_stmt_return: (path) => {
console.log('Found return statement');
},
};
walk(parsed.functions[0].plpgsql.hydrated, visitor);Options:
walkSqlExpressions(default:true) - Whether to recurse into hydrated SQL expressionssqlVisitor- SQL visitor to use when walking hydrated SQL expressions (from@pgsql/traverse)
Convenience function that walks both SQL statements and PL/pgSQL function bodies.
import { parse, walkParsedScript, loadModule } from 'plpgsql-parser';
await loadModule();
const parsed = parse(`
CREATE TABLE users (id int);
CREATE FUNCTION get_user(p_id int) RETURNS text LANGUAGE plpgsql AS $$
BEGIN
RETURN (SELECT name FROM users WHERE id = p_id);
END;
$$;
`);
walkParsedScript(
parsed,
// PL/pgSQL visitor
{
PLpgSQL_stmt_return: (path) => {
console.log('PL/pgSQL return statement');
},
},
// SQL visitor (optional) - visits both top-level SQL and embedded SQL in functions
{
CreateStmt: (path) => {
console.log('CREATE TABLE statement');
},
RangeVar: (path) => {
console.log('Table reference:', path.node.relname);
},
}
);The path object passed to visitor functions:
class PLpgSQLNodePath<TTag extends string = string> {
tag: TTag; // Node type (e.g., 'PLpgSQL_stmt_block')
node: any; // The actual node data
parent: PLpgSQLNodePath | null; // Parent path
keyPath: readonly (string | number)[]; // Full path array
get path(): (string | number)[]; // Copy of keyPath
get key(): string | number; // Last element of path
}For power users, the package re-exports underlying primitives:
parseSql- SQL parser from@libpg-query/parserparsePlpgsqlBody- PL/pgSQL parser from@libpg-query/parserdeparseSql- SQL deparser frompgsql-deparserdeparsePlpgsqlBody- PL/pgSQL deparser fromplpgsql-deparserhydratePlpgsqlAst- Hydration utility fromplpgsql-deparserdehydratePlpgsqlAst- Dehydration utility fromplpgsql-deparser
MIT