pgsql-parser-testing

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

PGSQL Parser Testing

PGSQL Parser 测试

Testing workflow for the pgsql-parser repository. This skill is scoped specifically to the
constructive-io/pgsql-parser
monorepo.
pgsql-parser仓库的测试工作流,本技能专门适用于
constructive-io/pgsql-parser
monorepo。

When to Apply

适用场景

Use this skill when:
  • Working in the pgsql-parser repository
  • Fixing deparser or parser issues
  • Running parser/deparser tests
  • Validating SQL round-trip correctness
  • Adding new SQL syntax support
在以下场景中使用本技能:
  • 在pgsql-parser仓库中开展开发工作
  • 修复反解析器或解析器问题
  • 运行解析器/反解析器测试
  • 验证SQL往返转换的正确性
  • 新增SQL语法支持

Repository Structure

仓库结构

pgsql-parser/
  packages/
    parser/           # SQL parser (libpg_query bindings)
    deparser/         # SQL deparser (AST to SQL)
    plpgsql-parser/   # PL/pgSQL parser
    plpgsql-deparser/ # PL/pgSQL deparser
    types/            # TypeScript type definitions
    utils/            # Utility functions
    traverse/         # AST traversal utilities
    transform/        # AST transformation utilities
pgsql-parser/
  packages/
    parser/           # SQL parser (libpg_query bindings)
    deparser/         # SQL deparser (AST to SQL)
    plpgsql-parser/   # PL/pgSQL parser
    plpgsql-deparser/ # PL/pgSQL deparser
    types/            # TypeScript type definitions
    utils/            # Utility functions
    traverse/         # AST traversal utilities
    transform/        # AST transformation utilities

Testing Strategy

测试策略

The pgsql-parser uses AST-level equality for correctness, not string equality:
parse(sql1) → ast1 → deparse(ast1) → sql2 → parse(sql2) → ast2
While
sql2 !== sql1
textually, a correct round-trip means
ast1 === ast2
.
pgsql-parser使用AST层级的相等性判断正确性,而非字符串相等性:
parse(sql1) → ast1 → deparse(ast1) → sql2 → parse(sql2) → ast2
虽然文本层面
sql2 !== sql1
,但只要
ast1 === ast2
就说明往返转换是正确的。

Key Principle

核心原则

Exact SQL string equality is not required. The focus is on comparing resulting ASTs. Use
expectAstMatch
(deparser) or
expectPGParse
(ast package) to validate correctness.
不要求SQL字符串完全相等,重点是对比生成的AST是否一致。可以使用
expectAstMatch
(反解析器)或
expectPGParse
(ast包)验证正确性。

Development Workflow

开发工作流

Initial Setup

初始配置

bash
pnpm install
pnpm build
bash
pnpm install
pnpm build

Running Tests

运行测试

Run all tests:
bash
pnpm test
Run tests for a specific package:
bash
cd packages/deparser
pnpm test
Watch mode for rapid iteration:
bash
cd packages/deparser
pnpm test:watch
Run a specific test:
bash
pnpm test --testNamePattern="specific-test-name"
运行所有测试:
bash
pnpm test
运行指定包的测试:
bash
cd packages/deparser
pnpm test
开启监听模式实现快速迭代:
bash
cd packages/deparser
pnpm test:watch
运行单个指定测试:
bash
pnpm test --testNamePattern="specific-test-name"

Fixing Deparser Issues

修复反解析器问题

Systematic Approach

系统化方法

  1. One test at a time: Focus on individual failing tests
    bash
    pnpm test --testNamePattern="specific-test"
  2. Always check for regressions: After each fix, run full test suite
    bash
    pnpm test
  3. Build before testing: Always rebuild after code changes
    bash
    pnpm build && pnpm test
  4. Clean commits: Stage files explicitly
    bash
    git add packages/deparser/src/specific-file.ts
  1. 单次只处理一个测试:聚焦单个失败的测试用例
    bash
    pnpm test --testNamePattern="specific-test"
  2. 始终检查回归问题:每次修复完成后运行完整测试套件
    bash
    pnpm test
  3. 测试前先构建:代码修改后务必重新构建
    bash
    pnpm build && pnpm test
  4. 干净提交:显式暂存修改的文件
    bash
    git add packages/deparser/src/specific-file.ts

Workflow Loop

工作流循环

Make changes → pnpm build → pnpm test --testNamePattern="target" → pnpm test (full) → commit
修改代码 → pnpm build → pnpm test --testNamePattern="目标测试名" → 运行全量pnpm test → 提交

Test Utilities

测试工具

Deparser Tests

反解析器测试

Location:
packages/deparser/test-utils/index.ts
typescript
import { expectAstMatch } from '../test-utils';

it('deparses SELECT correctly', () => {
  expectAstMatch('SELECT * FROM users');
});
位置:
packages/deparser/test-utils/index.ts
typescript
import { expectAstMatch } from '../test-utils';

it('deparses SELECT correctly', () => {
  expectAstMatch('SELECT * FROM users');
});

AST Package Tests

AST包测试

Location:
packages/ast/test/utils/index.ts
Uses database deparser for validation:
typescript
import { expectPGParse } from '../test/utils';

it('round-trips through database deparser', async () => {
  await expectPGParse('SELECT * FROM users WHERE id = 1');
});
Note: AST tests require the database to have
deparser.expressions_array
function available.
位置:
packages/ast/test/utils/index.ts
使用数据库反解析器做验证:
typescript
import { expectPGParse } from '../test/utils';

it('round-trips through database deparser', async () => {
  await expectPGParse('SELECT * FROM users WHERE id = 1');
});
注意:AST测试要求数据库中存在
deparser.expressions_array
函数。

Common Commands

常用命令

CommandDescription
pnpm build
Build all packages
pnpm test
Run all tests
pnpm test:watch
Run tests in watch mode
pnpm lint
Run linter
pnpm clean
Clean build artifacts
命令描述
pnpm build
构建所有包
pnpm test
运行所有测试
pnpm test:watch
以监听模式运行测试
pnpm lint
运行代码检查
pnpm clean
清理构建产物

Package-Specific Testing

特定包测试

Parser Package

Parser包

Tests libpg_query bindings and SQL parsing:
bash
cd packages/parser
pnpm test
测试libpg_query绑定和SQL解析能力:
bash
cd packages/parser
pnpm test

Deparser Package

Deparser包

Tests AST-to-SQL conversion:
bash
cd packages/deparser
pnpm test
测试AST转SQL的转换能力:
bash
cd packages/deparser
pnpm test

PL/pgSQL Packages

PL/pgSQL相关包

Tests PL/pgSQL parsing and deparsing:
bash
cd packages/plpgsql-parser
pnpm test

cd packages/plpgsql-deparser
pnpm test
测试PL/pgSQL的解析和反解析能力:
bash
cd packages/plpgsql-parser
pnpm test

cd packages/plpgsql-deparser
pnpm test

Debugging Tips

调试技巧

  1. Use isolated debug scripts for complex issues (don't commit them)
  2. Check the AST structure when tests fail:
    typescript
    import { parse } from 'pgsql-parser';
    console.log(JSON.stringify(parse('SELECT 1'), null, 2));
  3. Compare ASTs visually to understand differences:
    typescript
    const ast1 = parse(sql1);
    const ast2 = parse(deparse(ast1));
    console.log('Original:', JSON.stringify(ast1, null, 2));
    console.log('Round-trip:', JSON.stringify(ast2, null, 2));
  1. 复杂问题可以使用独立的调试脚本(不要提交这些脚本)
  2. 测试失败时检查AST结构:
    typescript
    import { parse } from 'pgsql-parser';
    console.log(JSON.stringify(parse('SELECT 1'), null, 2));
  3. 可视化对比AST来理解差异:
    typescript
    const ast1 = parse(sql1);
    const ast2 = parse(deparse(ast1));
    console.log('原始AST:', JSON.stringify(ast1, null, 2));
    console.log('往返转换后AST:', JSON.stringify(ast2, null, 2));

Troubleshooting

问题排查

IssueSolution
Tests fail after changesRun
pnpm build
before
pnpm test
Type errorsCheck
packages/types
for type definitions
Shared code changesRebuild dependent packages
Snapshot mismatchesReview changes, update with
pnpm test -u
if correct
问题解决方案
修改代码后测试失败运行
pnpm test
前先执行
pnpm build
类型错误检查
packages/types
中的类型定义
公共代码修改重新构建依赖该公共代码的包
快照不匹配核查修改内容,确认正确后执行
pnpm test -u
更新快照

Important Notes

注意事项

  • Changes to
    types
    or
    utils
    packages may require rebuilding dependent packages
  • Each package can be developed and tested independently
  • The project uses Lerna for monorepo management
  • Always verify no regressions before committing
  • 修改
    types
    utils
    包可能需要重新构建依赖它们的其他包
  • 每个包都可以独立开发和测试
  • 项目使用Lerna进行monorepo管理
  • 提交前务必确认没有引入回归问题

References

参考资料

  • Deparser testing docs:
    packages/deparser/TESTING.md
  • Quoting rules:
    packages/deparser/QUOTING-RULES.md
  • Deparser usage:
    packages/deparser/DEPARSER_USAGE.md
  • PL/pgSQL deparser:
    packages/plpgsql-deparser/AGENTS.md
  • 反解析器测试文档:
    packages/deparser/TESTING.md
  • 引号规则:
    packages/deparser/QUOTING-RULES.md
  • 反解析器使用说明:
    packages/deparser/DEPARSER_USAGE.md
  • PL/pgSQL反解析器:
    packages/plpgsql-deparser/AGENTS.md