diff --git a/README.md b/README.md index 280b103..3f720be 100644 --- a/README.md +++ b/README.md @@ -41,7 +41,7 @@ - 🌳 **Database Explorer** — Browse tables, views, functions, types, FDWs - 🛠️ **Object Operations** — CRUD, scripts, VACUUM, ANALYZE, REINDEX - 🌍 **Foreign Data Wrappers** — Manage foreign servers, user mappings & tables -- 🤖 **AI-Powered** — GitHub Copilot, OpenAI, Anthropic, Gemini +- 🤖 **AI-Powered** — Generate, Optimize, Explain & Analyze (OpenAI, Anthropic, Gemini) - 📤 **Export Data** — Export results to CSV, JSON, or Excel --- @@ -135,16 +135,31 @@ yape/ PgStudio integrates advanced AI capabilities directly into your workflow, but keeps **YOU** in control. -### Chat to Query (Natural Language → SQL) -Describe what you need in plain English, and PgStudio will generate the SQL for you. -- **Context-Aware**: The AI understands your table schemas and columns. -- **Smart Suggestions**: Ask for "top selling products" and it knows to join `orders` and `products`. +### 🪄 Generate Query (Natural Language → SQL) +Describe what you need in plain English (e.g., "Show me top 10 users by order count"), and PgStudio will generate the SQL for you using your schema context. +- **Command Palette**: `AI: Generate Query` +- **Context-Aware**: The AI understands your table schemas, columns, and relationships. + +### ⚡ Performance Optimization +Click the **Optimize** button on any successful query result. +- **Explain Scripts**: Generates `EXPLAIN ANALYZE` commands for deeper profiling. +- **Static Analysis**: Suggests missing indexes, query rewrites, or schema improvements. + +### 📊 Data Analysis +Click the **Analyze Data** button in result tables. +- **Clean Workflow**: Automatically exports data to a temporary CSV and attaches it to the chat. +- **Actionable Insights**: AI summarizes patterns, trends, and outliers in your result sets. + +### ✨ Error Handling (Explain & Fix) +When a query fails, get instant help directly in the error cell. +- **Explain Error**: Translates cryptic Postgres errors into plain English. +- **Fix Query**: Suggests corrected SQL to resolve the error. ### 🛡️ Safe Execution Model (Notebook-First) We believe AI should assist, not take over. **No query is ever executed automatically.** -1. **Ask**: You ask a question in the side panel. -2. **Review**: The AI generates SQL code. -3. **Insert**: You click "Open in Notebook" to place the code into a cell. +1. **Ask/Trigger**: You use one of the AI features. +2. **Review**: The AI generates SQL or suggestions in the chat. +3. **Insert**: You click "Open in Notebook" to place code into a cell. 4. **Execute**: You review the code and click "Run" when you are ready. --- @@ -277,3 +292,84 @@ npx ovsx publish Also on [Open VSX](https://open-vsx.org/extension/ric-v/postgres-explorer) + +--- + +## ???? Troubleshooting + +### Connection Issues + +#### SSL Connection Failures +**Problem**: `SSL connection failed` or `certificate verify failed` + +**Solutions**: +- Disable SSL (development only): Set SSL Mode to `disable` +- Use `prefer` mode (tries SSL, falls back to non-SSL) +- Provide CA certificate: SSL Mode `verify-ca` + CA Certificate path + +#### Connection Timeout +**Problem**: `Connection timeout` or `ETIMEDOUT` + +**Solutions**: +- Increase connection timeout in settings +- Check firewall rules +- Verify PostgreSQL `pg_hba.conf` allows remote connections +- Ensure PostgreSQL is listening on correct interface + +#### SSH Tunnel Issues +**Problem**: `SSH tunnel failed to establish` + +**Solutions**: +- Verify SSH credentials and host +- Test SSH connection manually: `ssh user@host -p port` +- Check SSH key permissions: `chmod 600 ~/.ssh/id_rsa` +- Ensure SSH server allows port forwarding + +### Performance Issues + +#### Large Result Sets +**Problem**: Querying large tables causes freezes + +**Solution**: Results are automatically limited to 10,000 rows. Use `LIMIT` clause for specific row counts. + +#### Slow Tree View +**Problem**: Database tree takes long to load + +**Solutions**: +- Use search filter to narrow objects +- Collapse unused schemas +- Disable object count badges in settings + +### Common Error Messages + +| Error | Cause | Solution | +|-------|-------|----------| +| `password authentication failed` | Wrong credentials | Verify username/password | +| `database does not exist` | Database name typo | Check database name | +| `permission denied` | Insufficient privileges | Grant SELECT permission | +| `too many connections` | Pool exhausted | Close unused connections | +| `no pg_hba.conf entry` | Access control | Add entry to `pg_hba.conf` | + +--- + +## 🙈 Feature Comparison + +| Feature | PgStudio | pgAdmin | DBeaver | TablePlus | +|---------|----------|---------|---------|-----------| +| **VS Code Integration** | ✅ Native | ❌ | ❌ | ❌ | +| **SQL Notebooks** | ✅ Interactive | ❌ | ❌ | ❌ | +| **AI Assistant** | ✅ Built-in | ❌ | ❌ | ❌ | +| **Real-time Dashboard** | ✅ | ✅ | ⚠️ Limited | ⚠️ Limited | +| **Inline Cell Editing** | ✅ | ✅ | ✅ | ✅ | +| **Export Formats** | CSV, JSON, Excel | CSV, JSON | CSV, JSON, Excel | CSV, JSON, SQL | +| **SSH Tunneling** | ✅ | ✅ | ✅ | ✅ | +| **Foreign Data Wrappers** | ✅ Full | ✅ | ⚠️ Limited | ❌ | +| **License** | MIT (Free) | PostgreSQL (Free) | Apache 2.0 (Free) | Proprietary (Paid) | + +### Unique to PgStudio +- 🤖 AI-powered query generation and optimization +- 📓 Interactive SQL notebooks with persistent state +- 🔄 Infinite scrolling for large result sets (10k rows) +- 🎨 Modern UI integrated into VS Code +- 🚀 Hybrid connection pooling for performance + diff --git a/docs/ARCHITECTURE.md b/docs/ARCHITECTURE.md new file mode 100644 index 0000000..1106eb5 --- /dev/null +++ b/docs/ARCHITECTURE.md @@ -0,0 +1,480 @@ +# PgStudio Architecture + +> **Last Updated**: December 2025 + +This document provides a comprehensive overview of PgStudio's architecture, design decisions, and component interactions. + +--- + +## Table of Contents + +- [System Overview](#system-overview) +- [Component Architecture](#component-architecture) +- [Data Flow](#data-flow) +- [Key Design Decisions](#key-design-decisions) +- [Extension Points](#extension-points) + +--- + +## System Overview + +PgStudio is a VS Code extension that provides comprehensive PostgreSQL database management capabilities. The architecture follows a modular design with clear separation between the Extension Host (Node.js) and Webview Renderers (Browser). + +```mermaid +graph TB + subgraph "VS Code Extension Host" + EXT[Extension Entry Point] + CMD[Commands] + PROV[Providers] + SVC[Services] + end + + subgraph "Webview Renderers" + DASH[Dashboard Panel] + NB[Notebook Renderer] + end + + subgraph "External Systems" + PG[(PostgreSQL Database)] + AI[AI Services
OpenAI/Anthropic/Gemini] + end + + EXT --> CMD + EXT --> PROV + EXT --> SVC + + CMD --> SVC + PROV --> SVC + + SVC --> PG + SVC --> AI + + EXT -.Message Passing.-> DASH + EXT -.Message Passing.-> NB + + DASH -.Postback.-> CMD + NB -.Postback.-> CMD +``` + +--- + +## Component Architecture + +### Extension Host Components + +#### 1. **Extension Entry Point** (`src/extension.ts`) +- Registers commands, providers, and services +- Initializes connection manager and secret storage +- Sets up message passing for webviews +- Manages extension lifecycle + +#### 2. **Commands** (`src/commands/`) +Implements VS Code commands for database operations: + +```mermaid +graph LR + subgraph Commands + CONN[Connection
Management] + TBL[Table
Operations] + VIEW[View
Operations] + FUNC[Function
Operations] + FDW[FDW
Operations] + AI_CMD[AI
Commands] + end + + CONN --> |Uses| CM[ConnectionManager] + TBL --> |Uses| CM + VIEW --> |Uses| CM + FUNC --> |Uses| CM + FDW --> |Uses| CM + AI_CMD --> |Uses| AI_SVC[AIService] +``` + +**Key Command Files**: +- `connections.ts` - Add, edit, delete, test connections +- `tables.ts` - CRUD, VACUUM, ANALYZE, REINDEX, scripts +- `views.ts` - View operations and scripts +- `functions.ts` - Function management +- `fdw.ts` - Foreign Data Wrapper operations +- `ai.ts` - AI-powered query generation and optimization + +#### 3. **Providers** (`src/providers/`) +Implements VS Code provider interfaces: + +- **`DatabaseTreeProvider.ts`** - Tree view for database objects +- **`SqlCompletionProvider.ts`** - SQL autocomplete +- **`NotebookKernel.ts`** - SQL notebook execution kernel +- **`DashboardPanel.ts`** - Real-time monitoring dashboard + +#### 4. **Services** (`src/services/`) +Core business logic and infrastructure: + +```mermaid +graph TB + subgraph Services + CM[ConnectionManager] + SS[SecretStorageService] + SSH[SSHService] + AI[AIService] + HIST[HistoryService] + ERR[ErrorService] + DBO[DbObjectService] + end + + CM --> |Stores passwords| SS + CM --> |Tunnels via| SSH + AI --> |Reads schema| DBO + AI --> |Reads history| HIST + CM --> |Reports errors| ERR +``` + +**Service Responsibilities**: + +| Service | Purpose | +|---------|---------| +| `ConnectionManager` | Hybrid pooling (`pg.Pool` + `pg.Client`), connection lifecycle | +| `SecretStorageService` | Encrypted password storage via VS Code API | +| `SSHService` | SSH tunnel management for remote connections | +| `AIService` | AI provider abstraction (OpenAI, Anthropic, Gemini) | +| `HistoryService` | Query history tracking for AI context | +| `ErrorService` | Centralized error handling and reporting | +| `DbObjectService` | Database schema introspection and caching | + +--- + +### Webview Components + +#### 1. **Dashboard Panel** (`src/panels/DashboardPanel.ts`) +Real-time monitoring interface showing: +- Active connections (`pg_stat_activity`) +- Database size and growth +- Table statistics +- Index health +- Long-running queries + +**Technology**: HTML + CSS + Vanilla JavaScript with Chart.js + +#### 2. **Notebook Renderer** (`src/renderer_v2.ts`) +Renders SQL query results in notebooks with: +- **Infinite Scrolling** (200 rows/chunk via `IntersectionObserver`) +- Interactive table with column resizing +- Inline cell editing (double-click) +- Chart visualization (Chart.js) +- Export to CSV/JSON/Excel +- AI-powered data analysis + +**Modular Structure**: +``` +src/renderer/ +├── components/ +│ └── ui.ts # Reusable UI components (buttons, tabs) +└── features/ + ├── export.ts # Export functionality + └── ai.ts # AI analysis features +``` + +--- + +## Data Flow + +### Query Execution Flow + +```mermaid +sequenceDiagram + participant User + participant Notebook as Notebook Cell + participant Kernel as NotebookKernel + participant CM as ConnectionManager + participant Pool as pg.Pool + participant PG as PostgreSQL + participant Renderer as Notebook Renderer + + User->>Notebook: Execute SQL + Notebook->>Kernel: Execute cell + Kernel->>CM: getSessionClient(config, sessionId) + CM->>Pool: Get/Create pool + Pool->>CM: Return pooled client + CM->>Kernel: Return client + + Kernel->>PG: Execute query + PG->>Kernel: Return result (rows) + + alt Result > 10k rows + Kernel->>Kernel: Truncate to 10k + Kernel->>Kernel: Add warning notice + end + + Kernel->>Renderer: Send result JSON + Renderer->>Renderer: Render first 200 rows + + User->>Renderer: Scroll down + Renderer->>Renderer: Load next 200 rows +``` + +### Connection Pooling Strategy + +PgStudio uses a **hybrid pooling approach**: + +```mermaid +graph TB + subgraph "Connection Manager" + direction TB + API[Public API] + + subgraph "Ephemeral Operations" + POOL[pg.Pool] + PC1[PoolClient 1] + PC2[PoolClient 2] + PCN[PoolClient N] + end + + subgraph "Stateful Sessions" + CLIENT[pg.Client] + SC1[Session Client 1
Notebook A] + SC2[Session Client 2
Notebook B] + end + end + + API -->|getPooledClient| POOL + POOL --> PC1 + POOL --> PC2 + POOL --> PCN + + API -->|getSessionClient| CLIENT + CLIENT --> SC1 + CLIENT --> SC2 + + PC1 -.auto release.-> POOL + PC2 -.auto release.-> POOL + + SC1 -.manual close.-> CLIENT + SC2 -.manual close.-> CLIENT +``` + +**Why Hybrid?** +- **`pg.Pool`** for commands (tree refresh, CRUD operations) - automatic connection reuse +- **`pg.Client`** for notebooks - maintains transaction state across cells + +--- + +## Key Design Decisions + +### 1. **Infinite Scrolling over Virtual Scrolling** + +**Problem**: Rendering 10k+ rows freezes the UI. + +**Solution**: +- Backend truncates results to 10k rows (prevents crashes) +- Frontend renders in 200-row chunks +- `IntersectionObserver` triggers loading on scroll + +**Trade-offs**: +- ✅ Simple implementation +- ✅ Works with existing table structure +- ✅ No complex windowing logic +- ⚠️ All 10k rows in memory (acceptable for max limit) + +### 2. **Hybrid Connection Pooling** + +**Problem**: +- Commands need short-lived connections +- Notebooks need persistent connections (transactions) + +**Solution**: +```typescript +// Ephemeral (auto-released) +const client = await ConnectionManager.getInstance().getPooledClient(config); +try { + await client.query('SELECT ...'); +} finally { + client.release(); // Returns to pool +} + +// Stateful (manual lifecycle) +const client = await ConnectionManager.getInstance() + .getSessionClient(config, notebookUri); +// Client persists across cells +// Closed when notebook closes +``` + +### 3. **AI Context Optimization** + +**Problem**: Sending full schema on every AI request is expensive. + +**Solution**: +- **Schema Caching**: `DbObjectService` caches table/column metadata +- **Selective Context**: Only send relevant tables based on query +- **History Integration**: Include recent queries for better suggestions + +### 4. **Modular Renderer Architecture** + +**Problem**: `renderer_v2.ts` was 144KB monolith. + +**Solution**: +``` +renderer_v2.ts (main) +├── renderer/components/ui.ts # Buttons, tabs, modals +└── renderer/features/ + ├── export.ts # CSV/JSON/Excel export + └── ai.ts # AI analysis integration +``` + +**Benefits**: +- Easier testing +- Clear separation of concerns +- Reusable components + +--- + +## Extension Points + +### Adding a New Command + +1. **Define command** in `package.json`: +```json +{ + "command": "postgres-explorer.myCommand", + "title": "My Command", + "category": "PostgreSQL" +} +``` + +2. **Implement handler** in `src/commands/myCommand.ts`: +```typescript +export async function myCommandHandler(node: TreeNode) { + const client = await ConnectionManager.getInstance() + .getPooledClient(node.connection); + try { + await client.query('...'); + } finally { + client.release(); + } +} +``` + +3. **Register** in `src/extension.ts`: +```typescript +context.subscriptions.push( + vscode.commands.registerCommand( + 'postgres-explorer.myCommand', + myCommandHandler + ) +); +``` + +### Adding a New AI Provider + +Implement the `AIProvider` interface in `src/services/AIService.ts`: + +```typescript +interface AIProvider { + generateQuery(prompt: string, context: SchemaContext): Promise; + optimizeQuery(query: string, context: SchemaContext): Promise; + explainError(error: string, query: string): Promise; +} +``` + +### Extending the Tree View + +Add new node types in `DatabaseTreeProvider.ts`: + +```typescript +class MyCustomNode extends TreeNode { + contextValue = 'myCustomNode'; + + async getChildren(): Promise { + // Return child nodes + } +} +``` + +--- + +## Performance Considerations + +### Connection Pool Sizing + +Default pool configuration: +```typescript +{ + max: 10, // Max connections per pool + idleTimeoutMillis: 30000, + connectionTimeoutMillis: 2000 +} +``` + +### Result Set Limits + +- **Backend**: 10,000 rows (hard limit in `NotebookKernel.ts`) +- **Frontend**: 200 rows/chunk (configurable in `renderer_v2.ts`) + +### Memory Management + +- Pools automatically release idle connections +- Session clients closed on notebook disposal +- Result truncation prevents OOM errors + +--- + +## Security + +### Password Storage + +```mermaid +graph LR + USER[User Input] --> |Plain text| EXT[Extension] + EXT --> |Encrypt| SS[SecretStorage API] + SS --> |Store| KEYCHAIN[OS Keychain] + + KEYCHAIN -.Retrieve.-> SS + SS -.Decrypt.-> EXT + EXT -.Use.-> PG[(PostgreSQL)] +``` + +- Passwords stored via VS Code `SecretStorage` API +- Encrypted by OS keychain (Keychain on macOS, Credential Manager on Windows, libsecret on Linux) +- Never stored in plain text + +### SSH Tunnels + +- Supports SSH key-based authentication +- Tunnels created per connection +- Automatically cleaned up on disconnect + +--- + +## Testing Strategy + +### Unit Tests +- `src/test/unit/` - Service layer tests +- Mock `pg.Pool` and `pg.Client` +- Test connection lifecycle + +### Integration Tests +- Require local PostgreSQL instance +- Test actual query execution +- Verify result rendering + +### Manual Testing +- Use test database with large tables +- Verify infinite scrolling +- Test AI features with real providers + +--- + +## Future Architecture Improvements + +1. **WebSocket for Real-time Updates** - Replace polling in dashboard +2. **Worker Threads for Large Exports** - Offload CSV/Excel generation +3. **Query Result Streaming** - Stream rows instead of loading all at once +4. **Distributed Tracing** - Add telemetry for performance monitoring +5. **Plugin System** - Allow third-party extensions + +--- + +## References + +- [VS Code Extension API](https://code.visualstudio.com/api) +- [node-postgres Documentation](https://node-postgres.com/) +- [Chart.js Documentation](https://www.chartjs.org/) +- [PostgreSQL System Catalogs](https://www.postgresql.org/docs/current/catalogs.html) diff --git a/docs/CONTRIBUTING.md b/docs/CONTRIBUTING.md new file mode 100644 index 0000000..4800a13 --- /dev/null +++ b/docs/CONTRIBUTING.md @@ -0,0 +1,478 @@ +# Contributing to PgStudio + +Thank you for your interest in contributing to PgStudio! This guide will help you get started with development. + +--- + +## Table of Contents + +- [Development Setup](#development-setup) +- [Project Structure](#project-structure) +- [Code Style Guide](#code-style-guide) +- [Testing Guidelines](#testing-guidelines) +- [Pull Request Process](#pull-request-process) +- [Commit Message Format](#commit-message-format) + +--- + +## Development Setup + +### Prerequisites + +- **Node.js** >= 18.x +- **npm** >= 9.x +- **VS Code** >= 1.80.0 +- **PostgreSQL** >= 12.x (for testing) + +### Initial Setup + +```bash +# Clone the repository +git clone https://github.com/dev-asterix/yape.git +cd yape + +# Install dependencies +npm install + +# Compile TypeScript +npm run compile + +# Watch mode for development +npm run watch +``` + +### Running the Extension + +1. Open the project in VS Code +2. Press `F5` to launch Extension Development Host +3. The extension will be loaded in a new VS Code window + +### Project Scripts + +```bash +npm run compile # Compile TypeScript +npm run watch # Watch mode (auto-compile on save) +npm run test # Run unit tests +npm run lint # Run ESLint +npm run esbuild-renderer # Bundle renderer for production +``` + +--- + +## Project Structure + +``` +yape/ +├── src/ +│ ├── extension.ts # Extension entry point +│ ├── commands/ # Command implementations +│ │ ├── connections.ts # Connection management +│ │ ├── tables.ts # Table operations +│ │ ├── views.ts # View operations +│ │ ├── functions.ts # Function operations +│ │ ├── fdw.ts # Foreign Data Wrapper ops +│ │ ├── ai.ts # AI commands +│ │ └── helper.ts # Shared utilities +│ ├── providers/ # VS Code providers +│ │ ├── DatabaseTreeProvider.ts +│ │ ├── SqlCompletionProvider.ts +│ │ ├── NotebookKernel.ts +│ │ └── DashboardPanel.ts +│ ├── services/ # Core services +│ │ ├── ConnectionManager.ts # Connection pooling +│ │ ├── SecretStorageService.ts +│ │ ├── SSHService.ts +│ │ ├── AIService.ts +│ │ ├── HistoryService.ts +│ │ ├── ErrorService.ts +│ │ └── DbObjectService.ts +│ ├── renderer_v2.ts # Notebook renderer +│ ├── renderer/ # Renderer modules +│ │ ├── components/ui.ts +│ │ └── features/ +│ │ ├── export.ts +│ │ └── ai.ts +│ ├── common/ # Shared types +│ │ └── types.ts +│ └── test/ # Tests +│ └── unit/ +├── docs/ # Documentation +├── package.json # Extension manifest +└── tsconfig.json # TypeScript config +``` + +--- + +## Code Style Guide + +### TypeScript Conventions + +#### 1. **Strict Typing** +Always use explicit types. Avoid `any` unless absolutely necessary. + +```typescript +// ✅ Good +async function getTableData( + client: PoolClient, + schema: string, + table: string +): Promise { + return await client.query('SELECT * FROM $1.$2', [schema, table]); +} + +// ❌ Bad +async function getTableData(client: any, schema: any, table: any): Promise { + return await client.query('SELECT * FROM $1.$2', [schema, table]); +} +``` + +#### 2. **Naming Conventions** + +| Type | Convention | Example | +|------|------------|---------| +| Classes | PascalCase | `ConnectionManager` | +| Interfaces | PascalCase with `I` prefix (optional) | `ConnectionConfig` | +| Functions | camelCase | `getPooledClient` | +| Constants | UPPER_SNAKE_CASE | `MAX_ROWS` | +| Private members | camelCase with `_` prefix | `_pools` | + +#### 3. **Async/Await** +Prefer `async/await` over `.then()` chains. + +```typescript +// ✅ Good +async function fetchData() { + try { + const result = await client.query('SELECT ...'); + return result.rows; + } catch (error) { + ErrorService.getInstance().handleError(error); + } +} + +// ❌ Bad +function fetchData() { + return client.query('SELECT ...') + .then(result => result.rows) + .catch(error => ErrorService.getInstance().handleError(error)); +} +``` + +--- + +### Connection Management Best Practices + +#### 1. **Always Use Pooling** + +```typescript +// ✅ Good - Pooled client (auto-released) +const client = await ConnectionManager.getInstance().getPooledClient(config); +try { + await client.query('SELECT ...'); +} finally { + client.release(); // CRITICAL: Always release in finally +} + +// ❌ Bad - Direct client creation +const client = new Client(config); +await client.connect(); +await client.query('SELECT ...'); +await client.end(); // May not execute if error occurs +``` + +#### 2. **Session Clients for Notebooks** + +```typescript +// ✅ Good - Session client for stateful operations +const client = await ConnectionManager.getInstance() + .getSessionClient(config, notebook.uri.toString()); + +// Client persists across cells +// Automatically closed when notebook closes +``` + +#### 3. **Error Handling** + +```typescript +// ✅ Good - Centralized error handling +try { + await client.query('...'); +} catch (error) { + ErrorService.getInstance().handleError(error, { + context: 'Table Operations', + operation: 'INSERT', + table: tableName + }); + throw error; // Re-throw if caller needs to handle +} +``` + +--- + +### SQL Query Patterns + +#### 1. **Parameterized Queries** +Always use parameterized queries to prevent SQL injection. + +```typescript +// ✅ Good +await client.query( + 'SELECT * FROM $1.$2 WHERE id = $3', + [schema, table, id] +); + +// ❌ Bad - SQL injection risk +await client.query( + `SELECT * FROM ${schema}.${table} WHERE id = ${id}` +); +``` + +#### 2. **Identifier Quoting** +Use double quotes for identifiers to handle special characters. + +```typescript +// ✅ Good +const query = `SELECT * FROM "${schema}"."${table}"`; + +// Handles schemas/tables with spaces, uppercase, etc. +``` + +--- + +### Error Handling Patterns + +#### 1. **Service Layer Errors** + +```typescript +export class MyService { + private static instance: MyService; + + public static getInstance(): MyService { + if (!MyService.instance) { + MyService.instance = new MyService(); + } + return MyService.instance; + } + + async performOperation(): Promise { + try { + // Operation logic + } catch (error) { + ErrorService.getInstance().handleError(error, { + context: 'MyService', + operation: 'performOperation' + }); + throw error; + } + } +} +``` + +#### 2. **Command Handler Errors** + +```typescript +export async function myCommandHandler(node: TreeNode) { + try { + const client = await ConnectionManager.getInstance() + .getPooledClient(node.connection); + try { + await client.query('...'); + vscode.window.showInformationMessage('Success!'); + } finally { + client.release(); + } + } catch (error) { + vscode.window.showErrorMessage(`Failed: ${error.message}`); + } +} +``` + +--- + +## Testing Guidelines + +### Unit Tests + +Located in `src/test/unit/`. Use Mocha + Chai. + +```typescript +import { expect } from 'chai'; +import * as sinon from 'sinon'; + +describe('ConnectionManager', () => { + let sandbox: sinon.SinonSandbox; + + beforeEach(() => { + sandbox = sinon.createSandbox(); + }); + + afterEach(() => { + sandbox.restore(); + }); + + it('should create a new pool if one does not exist', async () => { + const manager = ConnectionManager.getInstance(); + const config = { /* ... */ }; + + const poolStub = { + connect: sandbox.stub().resolves({ release: sandbox.stub() }), + on: sandbox.stub(), + end: sandbox.stub().resolves() + }; + + sandbox.stub(require('pg'), 'Pool').returns(poolStub); + + const client = await manager.getPooledClient(config); + + expect(poolStub.connect.calledOnce).to.be.true; + expect(client).to.exist; + }); +}); +``` + +### Integration Tests + +Require a local PostgreSQL instance. Use environment variables for configuration: + +```bash +export PGHOST=localhost +export PGPORT=5432 +export PGUSER=postgres +export PGPASSWORD=postgres +export PGDATABASE=test_db +``` + +--- + +## Pull Request Process + +### 1. **Fork and Branch** + +```bash +# Fork the repository on GitHub +# Clone your fork +git clone https://github.com/YOUR_USERNAME/yape.git + +# Create a feature branch +git checkout -b feature/my-new-feature +``` + +### 2. **Make Changes** + +- Follow the code style guide +- Add tests for new functionality +- Update documentation if needed + +### 3. **Test Your Changes** + +```bash +npm run compile +npm run test +npm run lint +``` + +### 4. **Commit** + +Follow the [commit message format](#commit-message-format). + +### 5. **Push and Create PR** + +```bash +git push origin feature/my-new-feature +``` + +Then create a Pull Request on GitHub with: +- Clear description of changes +- Reference to related issues +- Screenshots/GIFs for UI changes + +### 6. **Code Review** + +- Address reviewer feedback +- Keep commits clean (squash if needed) +- Ensure CI passes + +--- + +## Commit Message Format + +We follow the [Conventional Commits](https://www.conventionalcommits.org/) specification. + +### Format + +``` +(): + + + +