@pgsql/traverse
PostgreSQL AST traversal utilities for pgsql-parser. This package provides a visitor pattern for traversing PostgreSQL Abstract Syntax Tree (AST) nodes, similar to Babel's traverse functionality but specifically designed for PostgreSQL AST structures.
Installation
npm install @pgsql/traverse
Usage
Walk API (Recommended)
The walk function provides improved traversal with NodePath context and early return support:
import { walk, NodePath } from '@pgsql/traverse';
import type { Walker, Visitor } from '@pgsql/traverse';
const walker: Walker = (path: NodePath) => {
console.log(`Visiting ${path.tag} at path:`, path.path);
if (path.tag === 'SelectStmt') {
return false;
}
};
walk(ast, walker);
const visitor: Visitor = {
SelectStmt: (path) => {
console.log('SELECT statement:', path.node);
},
RangeVar: (path) => {
console.log('Table:', path.node.relname);
console.log('Path to table:', path.path);
console.log('Parent node:', path.parent?.tag);
}
};
walk(ast, visitor);
NodePath Class
The NodePath class provides rich context information:
class NodePath<TTag extends NodeTag = NodeTag> {
tag: TTag;
node: Node[TTag];
parent: NodePath | null;
keyPath: readonly (string | number)[];
get path(): (string | number)[];
get key(): string | number;
}
Runtime Schema Integration
The new implementation uses PostgreSQL's runtime schema to precisely determine which fields contain Node types that need traversal, eliminating guesswork and improving accuracy.
Visit API
The original visit function is still available for backward compatibility:
import { visit } from '@pgsql/traverse';
const visitor = {
SelectStmt: (node, ctx) => {
console.log('Found SELECT statement:', node);
console.log('Path:', ctx.path);
},
RangeVar: (node, ctx) => {
console.log('Found table reference:', node.relname);
}
};
const ast = ;
visit(ast, visitor);
Working with ParseResult
import { walk } from '@pgsql/traverse';
const visitor = {
ParseResult: (path) => {
console.log('Parse result version:', path.node.version);
console.log('Number of statements:', path.node.stmts.length);
},
SelectStmt: (path) => {
console.log('SELECT statement found');
}
};
walk(parseResult, visitor);
Using Visitor Context
The visitor context provides information about the current traversal state:
const visitor = {
RangeVar: (path) => {
console.log('Table name:', path.node.relname);
console.log('Path to this node:', path.path);
console.log('Parent node:', path.parent?.tag);
console.log('Key in parent:', path.key);
}
};
Collecting Information During Traversal
import { visit } from '@pgsql/traverse';
import type { Visitor } from '@pgsql/traverse';
const tableNames: string[] = [];
const columnRefs: string[] = [];
const visitor: Visitor = {
RangeVar: (node) => {
if (node.relname) {
tableNames.push(node.relname);
}
},
ColumnRef: (node) => {
if (node.fields) {
node.fields.forEach(field => {
if (field.String?.sval) {
columnRefs.push(field.String.sval);
}
});
}
}
};
visit(ast, visitor);
console.log('Tables referenced:', tableNames);
console.log('Columns referenced:', columnRefs);
API
walk(root, callback, parent?, keyPath?)
Walks the tree of PostgreSQL AST nodes using runtime schema for precise traversal.
Parameters:
root: The AST node to traverse
callback: A walker function or visitor object
parent?: Optional parent NodePath (for internal use)
keyPath?: Optional key path array (for internal use)
Example:
walk(ast, {
SelectStmt: (path) => {
},
RangeVar: (path) => {
}
});
visit(node, visitor, ctx?) (Legacy)
Recursively visits a PostgreSQL AST node, calling any matching visitor functions. Maintained for backward compatibility.
Parameters:
node: The AST node to traverse
visitor: An object with visitor functions for different node types
ctx?: Optional initial visitor context
Types
Visitor
An object type where keys are node type names and values are walker functions:
type Visitor = {
[TTag in NodeTag]?: Walker<NodePath<TTag>>;
};
Walker
A function that receives a NodePath and can return false to skip children:
type Walker<TNodePath extends NodePath = NodePath> = (
path: TNodePath,
) => boolean | void;
NodePath
A class that encapsulates node traversal context:
class NodePath<TTag extends NodeTag = NodeTag> {
tag: TTag;
node: Node[TTag];
parent: NodePath | null;
keyPath: readonly (string | number)[];
get path(): (string | number)[];
get key(): string | number;
}
VisitorContext (Legacy)
Context information provided to legacy visitor functions:
type VisitorContext = {
path: (string | number)[];
parent: any;
key: string | number;
};
NodeTag
Union type of all PostgreSQL AST node type names:
type NodeTag = keyof Node;
Supported Node Types
This package works with all PostgreSQL AST node types defined in @pgsql/types, including:
ParseResult - Root parse result from libpg-query
SelectStmt - SELECT statements
InsertStmt - INSERT statements
UpdateStmt - UPDATE statements
DeleteStmt - DELETE statements
RangeVar - Table references
ColumnRef - Column references
A_Expr - Expressions
A_Const - Constants
- And many more...
Integration with pgsql-parser
This package is designed to work seamlessly with the pgsql-parser ecosystem:
import { parse } from 'pgsql-parser';
import { visit } from '@pgsql/traverse';
const sql = 'SELECT name, email FROM users WHERE age > 18';
const ast = await parse(sql);
const visitor = {
RangeVar: (node) => {
console.log('Table:', node.relname);
},
ColumnRef: (node) => {
console.log('Column:', node.fields?.[0]?.String?.sval);
}
};
visit(ast, visitor);
🛠 Built by the Constructive team — creators of modular Postgres tooling for secure, composable backends. If you like our work, contribute on GitHub.
Related
- pgsql-parser: The real PostgreSQL parser for Node.js, providing symmetric parsing and deparsing of SQL statements with actual PostgreSQL parser integration.
- pgsql-deparser: A streamlined tool designed for converting PostgreSQL ASTs back into SQL queries, focusing solely on deparser functionality to complement
pgsql-parser.
- @pgsql/parser: Multi-version PostgreSQL parser with dynamic version selection at runtime, supporting PostgreSQL 15, 16, and 17 in a single package.
- @pgsql/types: Offers TypeScript type definitions for PostgreSQL AST nodes, facilitating type-safe construction, analysis, and manipulation of ASTs.
- @pgsql/enums: Provides TypeScript enum definitions for PostgreSQL constants, enabling type-safe usage of PostgreSQL enums and constants in your applications.
- @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.
- @pgsql/traverse: PostgreSQL AST traversal utilities for pgsql-parser, providing a visitor pattern for traversing PostgreSQL Abstract Syntax Tree nodes, similar to Babel's traverse functionality but specifically designed for PostgreSQL AST structures.
- pg-proto-parser: A TypeScript tool that parses PostgreSQL Protocol Buffers definitions to generate TypeScript interfaces, utility functions, and JSON mappings for enums.
- libpg-query: The real PostgreSQL parser exposed for Node.js, used primarily in
pgsql-parser for parsing and deparsing SQL queries.
Disclaimer
AS DESCRIBED IN THE LICENSES, THE SOFTWARE IS PROVIDED "AS IS", AT YOUR OWN RISK, AND WITHOUT WARRANTIES OF ANY KIND.
No developer or entity involved in creating Software will be liable for any claims or damages whatsoever associated with your use, inability to use, or your interaction with other users of the Software code or Software CLI, including any direct, indirect, incidental, special, exemplary, punitive or consequential damages, or loss of profits, cryptocurrencies, tokens, or anything else of value.