query-analyzer
Version:
A utility for enhancing Sequelize queries with EXPLAIN options and logging detailed query plans.
366 lines (267 loc) • 8.05 kB
Markdown
# Query Analyzer
A Node.js utility for analyzing Sequelize queries with PostgreSQL EXPLAIN. Provides detailed insights into query performance and logs results to CSV files.
[](https://www.npmjs.com/package/query-analyzer)
[](https://opensource.org/licenses/MIT)
## Features
- ✅ Automatic query interception and analysis
- ✅ Full PostgreSQL EXPLAIN ANALYZE support
- ✅ Production safety controls (enable/disable by environment)
- ✅ Slow query detection with callbacks
- ✅ Structured error handling
- ✅ Daily CSV reports with performance metrics
- ✅ TypeScript support with full type definitions
## Installation
```bash
npm install query-analyzer --save-dev
```
## Quick Start
```typescript
import { enableAnalyzer } from 'query-analyzer';
// Enable only in development
await enableAnalyzer(sequelize, {
environment: 'development'
});
```
That's it! All queries are now analyzed and logged to `analyzer/report-YYYY-MM-DD.csv`
## Compatibility
| Component | Version | Notes |
|-----------|---------|-------|
| **PostgreSQL** | 13-17 | Recommended (all features) |
| | 10-12 | Supported (some features unavailable) |
| **Sequelize** | 6.x | Tested and supported |
| | 7.x | Likely works (untested) |
| **Node.js** | 16-22 | LTS versions |
<details>
<summary>PostgreSQL Feature Support by Version</summary>
| PostgreSQL | Available Options | Missing |
|------------|-------------------|---------|
| 17, 16 | All (ANALYZE, BUFFERS, WAL, TIMING, SUMMARY, SETTINGS, SERIALIZE) | - |
| 15, 14, 13 | All except SERIALIZE | SERIALIZE |
| 12 | All except WAL, SERIALIZE | WAL, SERIALIZE |
| 10, 11 | All except SETTINGS, WAL, SERIALIZE | SETTINGS, WAL, SERIALIZE |
</details>
## Usage
### Development Only (Recommended)
```typescript
import { enableAnalyzer } from 'query-analyzer';
await enableAnalyzer(sequelize, {
environment: 'development'
});
```
### With EXPLAIN Options
```typescript
await enableAnalyzer(sequelize, {
environment: 'development',
verbose: true,
buffers: true,
timing: true,
summary: true
});
```
### Disable in Production
```typescript
await enableAnalyzer(sequelize, {
enabled: process.env.NODE_ENV !== 'production'
});
```
### Slow Query Monitoring
```typescript
import { enableAnalyzer, AnalyzerError } from 'query-analyzer';
await enableAnalyzer(sequelize, {
environment: 'development',
slowQueryThreshold: 500, // ms
onSlowQuery: (payload) => {
console.warn(`⚠️ Slow query: ${payload.actualExecutionTime}ms`);
console.warn(`Query: ${payload.query}`);
},
onError: (error: AnalyzerError) => {
console.error(`Error: ${error.code} - ${error.message}`);
}
});
```
## Configuration Options
```typescript
interface AnalyzerOptions {
// Enable/Disable
enabled?: boolean; // Default: true
environment?: string; // Only enable in specific env
// Monitoring
onError?: (error: AnalyzerError) => void | Promise<void>;
onSlowQuery?: (payload: Payload) => void | Promise<void>;
slowQueryThreshold?: number; // In ms, default: 1000, set to 0 for all queries
// PostgreSQL EXPLAIN Options
verbose?: boolean;
costs?: boolean;
settings?: boolean;
buffers?: boolean;
serialize?: 'NONE' | 'TEXT' | 'BINARY';
wal?: boolean;
timing?: boolean;
summary?: boolean;
}
```
## Output
Results are saved to CSV files in the `analyzer/` directory:
```
analyzer/
└── report-2025-11-10.csv
```
### CSV Columns
| Column | Description |
|--------|-------------|
| `query` | SQL query executed |
| `actualExecutionTime` | Wall-clock time (ms) |
| `queryPlan` | Full EXPLAIN output |
| `planningTime` | PostgreSQL planning time (ms) |
| `executionTime` | PostgreSQL execution time (ms) |
| `startCost` | Estimated startup cost |
| `endCost` | Estimated total cost |
| `params` | Query parameters |
## Error Handling
The package exports structured error classes:
```typescript
import {
AnalyzerError, // Base error class
ExplainError, // EXPLAIN failed
CsvError, // CSV write failed
QueryExecutionError // Query execution failed
} from 'query-analyzer';
```
### Error Properties
- `code`: Error code (e.g., 'EXPLAIN_FAILED')
- `query`: SQL query that caused the error
- `originalError`: Underlying error (if any)
- `timestamp`: When error occurred
- `getFormattedMessage()`: Human-readable message
- `toJSON()`: For logging services
## ⚠️ Production Safety
**Important:** The analyzer runs `EXPLAIN ANALYZE` which **executes queries twice**. Always use environment controls:
```typescript
// ✅ SAFE - Only in development
await enableAnalyzer(sequelize, {
environment: 'development'
});
// ✅ SAFE - Explicit control
await enableAnalyzer(sequelize, {
enabled: process.env.NODE_ENV !== 'production'
});
// ❌ UNSAFE - Always enabled (doubles query time!)
await enableAnalyzer(sequelize);
```
## Examples
### Basic Usage
```typescript
import { Sequelize } from 'sequelize';
import { enableAnalyzer } from 'query-analyzer';
const sequelize = new Sequelize(/* config */);
await enableAnalyzer(sequelize, {
environment: 'development'
});
// All queries are now analyzed automatically
const users = await User.findAll({ where: { active: true } });
```
### With Monitoring Integration
```typescript
import { enableAnalyzer, AnalyzerError } from 'query-analyzer';
await enableAnalyzer(sequelize, {
environment: 'development',
slowQueryThreshold: 1000,
onSlowQuery: async (payload) => {
// Send to monitoring service
await sendMetric('slow_query', {
duration: payload.actualExecutionTime,
query: payload.query,
cost: payload.endCost
});
},
onError: async (error: AnalyzerError) => {
// Send to error tracking
await Sentry.captureException(error.toJSON());
}
});
```
### Environment-Based Configuration
```typescript
const analyzerConfig = {
enabled: process.env.ENABLE_QUERY_ANALYZER === 'true',
environment: process.env.NODE_ENV,
verbose: true,
buffers: true,
timing: true,
slowQueryThreshold: parseInt(process.env.SLOW_QUERY_THRESHOLD || '1000')
};
await enableAnalyzer(sequelize, analyzerConfig);
```
## API Reference
### `enableAnalyzer(sequelize, options)`
Enables query analysis for a Sequelize instance.
**Parameters:**
- `sequelize` (Sequelize): Sequelize instance
- `options` (AnalyzerOptions): Configuration options
**Returns:** `Promise<void>`
**Example:**
```typescript
await enableAnalyzer(sequelize, {
environment: 'development',
verbose: true
});
```
## Development
### Running Tests
```bash
npm test # Run all tests
npm run test:watch # Watch mode
npm run test:coverage # Coverage report
```
### Building
```bash
npm run build
```
### Project Stats
- **Tests:** 68 passing (100%)
- **Type Safety:** Full TypeScript support
- **Security:** 0 vulnerabilities
## Roadmap
### Current Support
- ✅ Sequelize ORM
- ✅ PostgreSQL database
- ✅ Node.js 16-22 LTS
### Future (Based on Demand)
- ⏸️ TypeORM support
- ⏸️ Prisma support
- ⏸️ MySQL/MariaDB support
**Want support for another ORM or database?**
[Open an issue](https://github.com/Sohaib-Abid/query-analyzer/issues) and let us know!
## Contributing
See [CONTRIBUTING.md](./CONTRIBUTING.md) for detailed guidelines.
**Quick contribution checklist:**
1. Fork the repo
2. Create a feature branch
3. Write tests for your changes
4. Ensure all tests pass
5. Submit a Pull Request
## License
MIT © Sohaib Abid
## Links
- **GitHub:** [Sohaib-Abid/query-analyzer](https://github.com/Sohaib-Abid/query-analyzer)
- **npm:** [query-analyzer](https://www.npmjs.com/package/query-analyzer)
- **Issues:** [Report a bug](https://github.com/Sohaib-Abid/query-analyzer/issues)
## Acknowledgments
Built with ❤️ for the Node.js and PostgreSQL community.