@kysera/debug 0.7.2 → 0.7.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -24,26 +24,28 @@ bun add @kysera/debug
24
24
  - **Performance Metrics** - Collect and analyze query performance data
25
25
  - **Slow Query Detection** - Identify and alert on slow database queries
26
26
  - **SQL Formatting** - Format and highlight SQL for better readability
27
- - **Query Profiling** - Detailed performance analysis with statistics
28
- - **Circular Buffer** - Memory-efficient metrics storage with automatic cleanup
27
+ - **Query Profiling** - Detailed performance analysis with statistics using O(1) index-based metrics
28
+ - **Circular Buffer** - O(1) memory-efficient metrics storage with automatic cleanup (ring buffer implementation)
29
29
  - **Zero Dependencies** - Only depends on `@kysera/core` and peer-depends on `kysely`
30
30
 
31
31
  ## Quick Start
32
32
 
33
33
  ```typescript
34
- import { Kysely } from 'kysely';
35
- import { withDebug } from '@kysera/debug';
34
+ import { Kysely } from 'kysely'
35
+ import { withDebug } from '@kysera/debug'
36
36
 
37
37
  // Wrap your database with debug capabilities
38
- const db = new Kysely<Database>({ /* config */ });
39
- const debugDb = withDebug(db);
38
+ const db = new Kysely<Database>({
39
+ /* config */
40
+ })
41
+ const debugDb = withDebug(db)
40
42
 
41
43
  // Execute queries - they're automatically logged and timed
42
- await debugDb.selectFrom('users').selectAll().execute();
44
+ await debugDb.selectFrom('users').selectAll().execute()
43
45
 
44
46
  // Get collected metrics
45
- const metrics = debugDb.getMetrics();
46
- console.log(`Executed ${metrics.length} queries`);
47
+ const metrics = debugDb.getMetrics()
48
+ console.log(`Executed ${metrics.length} queries`)
47
49
  ```
48
50
 
49
51
  ## API Documentation
@@ -53,10 +55,7 @@ console.log(`Executed ${metrics.length} queries`);
53
55
  Wraps a Kysely database instance with debug capabilities, adding query logging, metrics collection, and slow query detection.
54
56
 
55
57
  ```typescript
56
- function withDebug<DB>(
57
- db: Kysely<DB>,
58
- options?: DebugOptions
59
- ): DebugDatabase<DB>
58
+ function withDebug<DB>(db: Kysely<DB>, options?: DebugOptions): DebugDatabase<DB>
60
59
  ```
61
60
 
62
61
  #### Parameters
@@ -71,7 +70,7 @@ function withDebug<DB>(
71
70
  #### Example
72
71
 
73
72
  ```typescript
74
- import { withDebug } from '@kysera/debug';
73
+ import { withDebug } from '@kysera/debug'
75
74
 
76
75
  const debugDb = withDebug(db, {
77
76
  logQuery: true,
@@ -79,9 +78,9 @@ const debugDb = withDebug(db, {
79
78
  slowQueryThreshold: 100,
80
79
  maxMetrics: 1000,
81
80
  onSlowQuery: (sql, duration) => {
82
- console.warn(`Slow query detected: ${duration}ms`);
83
- },
84
- });
81
+ console.warn(`Slow query detected: ${duration}ms`)
82
+ }
83
+ })
85
84
  ```
86
85
 
87
86
  ### DebugOptions
@@ -94,37 +93,37 @@ interface DebugOptions {
94
93
  * Log query SQL.
95
94
  * @default true
96
95
  */
97
- logQuery?: boolean;
96
+ logQuery?: boolean
98
97
 
99
98
  /**
100
99
  * Log query parameters.
101
100
  * @default false
102
101
  */
103
- logParams?: boolean;
102
+ logParams?: boolean
104
103
 
105
104
  /**
106
105
  * Duration threshold (ms) to consider a query slow.
107
106
  * @default 100
108
107
  */
109
- slowQueryThreshold?: number;
108
+ slowQueryThreshold?: number
110
109
 
111
110
  /**
112
111
  * Callback for slow queries.
113
112
  */
114
- onSlowQuery?: (sql: string, duration: number) => void;
113
+ onSlowQuery?: (sql: string, duration: number) => void
115
114
 
116
115
  /**
117
116
  * Logger for debug messages.
118
117
  * @default consoleLogger
119
118
  */
120
- logger?: KyseraLogger;
119
+ logger?: KyseraLogger
121
120
 
122
121
  /**
123
122
  * Maximum number of metrics to keep in memory.
124
123
  * When limit is reached, oldest metrics are removed (circular buffer).
125
124
  * @default 1000
126
125
  */
127
- maxMetrics?: number;
126
+ maxMetrics?: number
128
127
  }
129
128
  ```
130
129
 
@@ -135,10 +134,10 @@ Extended database interface with debug capabilities.
135
134
  ```typescript
136
135
  interface DebugDatabase<DB> extends Kysely<DB> {
137
136
  /** Get all collected query metrics */
138
- getMetrics(): QueryMetrics[];
137
+ getMetrics(): QueryMetrics[]
139
138
 
140
139
  /** Clear all collected metrics */
141
- clearMetrics(): void;
140
+ clearMetrics(): void
142
141
  }
143
142
  ```
144
143
 
@@ -149,9 +148,11 @@ interface DebugDatabase<DB> extends Kysely<DB> {
149
148
  Returns all collected query metrics.
150
149
 
151
150
  ```typescript
152
- const metrics = debugDb.getMetrics();
153
- console.log(`Total queries: ${metrics.length}`);
154
- console.log(`Average duration: ${metrics.reduce((sum, m) => sum + m.duration, 0) / metrics.length}ms`);
151
+ const metrics = debugDb.getMetrics()
152
+ console.log(`Total queries: ${metrics.length}`)
153
+ console.log(
154
+ `Average duration: ${metrics.reduce((sum, m) => sum + m.duration, 0) / metrics.length}ms`
155
+ )
155
156
  ```
156
157
 
157
158
  ##### clearMetrics()
@@ -159,7 +160,7 @@ console.log(`Average duration: ${metrics.reduce((sum, m) => sum + m.duration, 0)
159
160
  Clears all collected metrics from memory.
160
161
 
161
162
  ```typescript
162
- debugDb.clearMetrics();
163
+ debugDb.clearMetrics()
163
164
  ```
164
165
 
165
166
  ### QueryMetrics
@@ -169,16 +170,16 @@ Query performance metrics data.
169
170
  ```typescript
170
171
  interface QueryMetrics {
171
172
  /** SQL query string */
172
- sql: string;
173
+ sql: string
173
174
 
174
175
  /** Query parameters */
175
- params?: unknown[];
176
+ params?: unknown[]
176
177
 
177
178
  /** Query execution duration in milliseconds */
178
- duration: number;
179
+ duration: number
179
180
 
180
181
  /** Timestamp when query was executed */
181
- timestamp: number;
182
+ timestamp: number
182
183
  }
183
184
  ```
184
185
 
@@ -186,57 +187,59 @@ interface QueryMetrics {
186
187
 
187
188
  Advanced query profiler for collecting and analyzing query performance with detailed statistics.
188
189
 
190
+ **Implementation:** Uses O(1) index-based circular buffer for efficient metrics tracking with minimal memory overhead.
191
+
189
192
  ```typescript
190
193
  class QueryProfiler {
191
- constructor(options?: ProfilerOptions);
194
+ constructor(options?: ProfilerOptions)
192
195
 
193
196
  /** Record a query metric */
194
- record(metric: QueryMetrics): void;
197
+ record(metric: QueryMetrics): void
195
198
 
196
- /** Get profiling summary */
197
- getSummary(): ProfilerSummary;
199
+ /** Get profiling summary (O(1) using index-based metrics) */
200
+ getSummary(): ProfilerSummary
198
201
 
199
202
  /** Get the slowest N queries */
200
- getSlowestQueries(count: number): QueryMetrics[];
203
+ getSlowestQueries(count: number): QueryMetrics[]
201
204
 
202
205
  /** Get queries slower than a threshold */
203
- getSlowQueries(thresholdMs: number): QueryMetrics[];
206
+ getSlowQueries(thresholdMs: number): QueryMetrics[]
204
207
 
205
208
  /** Clear all recorded queries */
206
- clear(): void;
209
+ clear(): void
207
210
 
208
211
  /** Get the number of recorded queries */
209
- get count(): number;
212
+ get count(): number
210
213
  }
211
214
  ```
212
215
 
213
216
  #### Example
214
217
 
215
218
  ```typescript
216
- import { QueryProfiler } from '@kysera/debug';
219
+ import { QueryProfiler } from '@kysera/debug'
217
220
 
218
- const profiler = new QueryProfiler({ maxQueries: 500 });
221
+ const profiler = new QueryProfiler({ maxQueries: 500 })
219
222
 
220
223
  // Record queries manually
221
224
  profiler.record({
222
225
  sql: 'SELECT * FROM users WHERE id = $1',
223
226
  params: [123],
224
227
  duration: 10.5,
225
- timestamp: Date.now(),
226
- });
228
+ timestamp: Date.now()
229
+ })
227
230
 
228
231
  // Get summary
229
- const summary = profiler.getSummary();
230
- console.log(`Total queries: ${summary.totalQueries}`);
231
- console.log(`Average duration: ${summary.averageDuration.toFixed(2)}ms`);
232
- console.log(`Slowest query: ${summary.slowestQuery?.duration.toFixed(2)}ms`);
232
+ const summary = profiler.getSummary()
233
+ console.log(`Total queries: ${summary.totalQueries}`)
234
+ console.log(`Average duration: ${summary.averageDuration.toFixed(2)}ms`)
235
+ console.log(`Slowest query: ${summary.slowestQuery?.duration.toFixed(2)}ms`)
233
236
 
234
237
  // Get slow queries
235
- const slowQueries = profiler.getSlowQueries(50);
236
- console.log(`Queries slower than 50ms: ${slowQueries.length}`);
238
+ const slowQueries = profiler.getSlowQueries(50)
239
+ console.log(`Queries slower than 50ms: ${slowQueries.length}`)
237
240
 
238
241
  // Get top 10 slowest
239
- const top10 = profiler.getSlowestQueries(10);
242
+ const top10 = profiler.getSlowestQueries(10)
240
243
  ```
241
244
 
242
245
  ### ProfilerOptions
@@ -249,7 +252,7 @@ interface ProfilerOptions {
249
252
  * Maximum number of queries to keep in memory.
250
253
  * @default 1000
251
254
  */
252
- maxQueries?: number;
255
+ maxQueries?: number
253
256
  }
254
257
  ```
255
258
 
@@ -260,22 +263,22 @@ Summary statistics from the query profiler.
260
263
  ```typescript
261
264
  interface ProfilerSummary {
262
265
  /** Total number of recorded queries */
263
- totalQueries: number;
266
+ totalQueries: number
264
267
 
265
268
  /** Sum of all query durations */
266
- totalDuration: number;
269
+ totalDuration: number
267
270
 
268
271
  /** Average query duration */
269
- averageDuration: number;
272
+ averageDuration: number
270
273
 
271
274
  /** Slowest recorded query */
272
- slowestQuery: QueryMetrics | null;
275
+ slowestQuery: QueryMetrics | null
273
276
 
274
277
  /** Fastest recorded query */
275
- fastestQuery: QueryMetrics | null;
278
+ fastestQuery: QueryMetrics | null
276
279
 
277
280
  /** All recorded queries */
278
- queries: QueryMetrics[];
281
+ queries: QueryMetrics[]
279
282
  }
280
283
  ```
281
284
 
@@ -292,10 +295,10 @@ function formatSQL(sql: string): string
292
295
  **Example:**
293
296
 
294
297
  ```typescript
295
- import { formatSQL } from '@kysera/debug';
298
+ import { formatSQL } from '@kysera/debug'
296
299
 
297
- const sql = 'SELECT id, name FROM users WHERE active = true ORDER BY name';
298
- console.log(formatSQL(sql));
300
+ const sql = 'SELECT id, name FROM users WHERE active = true ORDER BY name'
301
+ console.log(formatSQL(sql))
299
302
  // Output:
300
303
  // SELECT id, name
301
304
  // FROM users
@@ -312,16 +315,17 @@ function formatSQLPretty(sql: string, indentSize?: number): string
312
315
  ```
313
316
 
314
317
  **Parameters:**
318
+
315
319
  - `sql` - SQL string to format
316
320
  - `indentSize` - Number of spaces for indentation (default: 2)
317
321
 
318
322
  **Example:**
319
323
 
320
324
  ```typescript
321
- import { formatSQLPretty } from '@kysera/debug';
325
+ import { formatSQLPretty } from '@kysera/debug'
322
326
 
323
- const sql = 'SELECT * FROM users WHERE id IN (SELECT user_id FROM orders WHERE total > 100)';
324
- console.log(formatSQLPretty(sql));
327
+ const sql = 'SELECT * FROM users WHERE id IN (SELECT user_id FROM orders WHERE total > 100)'
328
+ console.log(formatSQLPretty(sql))
325
329
  // Output with proper indentation for subqueries
326
330
  ```
327
331
 
@@ -336,14 +340,14 @@ function minifySQL(sql: string): string
336
340
  **Example:**
337
341
 
338
342
  ```typescript
339
- import { minifySQL } from '@kysera/debug';
343
+ import { minifySQL } from '@kysera/debug'
340
344
 
341
345
  const sql = `
342
346
  SELECT id, name
343
347
  FROM users
344
348
  WHERE active = true
345
- `;
346
- console.log(minifySQL(sql));
349
+ `
350
+ console.log(minifySQL(sql))
347
351
  // Output: SELECT id, name FROM users WHERE active = true
348
352
  ```
349
353
 
@@ -358,9 +362,9 @@ function highlightSQL(sql: string): string
358
362
  **Example:**
359
363
 
360
364
  ```typescript
361
- import { highlightSQL } from '@kysera/debug';
365
+ import { highlightSQL } from '@kysera/debug'
362
366
 
363
- console.log(highlightSQL('SELECT * FROM users WHERE active = true'));
367
+ console.log(highlightSQL('SELECT * FROM users WHERE active = true'))
364
368
  // Keywords will be highlighted in blue in terminal
365
369
  ```
366
370
 
@@ -369,21 +373,19 @@ console.log(highlightSQL('SELECT * FROM users WHERE active = true'));
369
373
  ### Basic Query Logging
370
374
 
371
375
  ```typescript
372
- import { Kysely } from 'kysely';
373
- import { withDebug } from '@kysera/debug';
376
+ import { Kysely } from 'kysely'
377
+ import { withDebug } from '@kysera/debug'
374
378
 
375
- const db = new Kysely<Database>({ /* config */ });
379
+ const db = new Kysely<Database>({
380
+ /* config */
381
+ })
376
382
  const debugDb = withDebug(db, {
377
383
  logQuery: true,
378
- logParams: false,
379
- });
384
+ logParams: false
385
+ })
380
386
 
381
387
  // Queries are automatically logged
382
- await debugDb
383
- .selectFrom('users')
384
- .where('active', '=', true)
385
- .selectAll()
386
- .execute();
388
+ await debugDb.selectFrom('users').where('active', '=', true).selectAll().execute()
387
389
  // Console output:
388
390
  // [SQL] SELECT * FROM "users" WHERE "active" = $1
389
391
  // [Duration] 12.34ms
@@ -392,129 +394,127 @@ await debugDb
392
394
  ### Detecting Slow Queries
393
395
 
394
396
  ```typescript
395
- import { withDebug } from '@kysera/debug';
397
+ import { withDebug } from '@kysera/debug'
396
398
 
397
399
  const debugDb = withDebug(db, {
398
400
  slowQueryThreshold: 50, // 50ms threshold
399
401
  onSlowQuery: (sql, duration) => {
400
402
  // Send to monitoring service
401
- monitoring.recordSlowQuery({ sql, duration });
403
+ monitoring.recordSlowQuery({ sql, duration })
402
404
 
403
405
  // Log to error tracking
404
- logger.warn(`Slow query detected: ${duration.toFixed(2)}ms`, { sql });
405
- },
406
- });
406
+ logger.warn(`Slow query detected: ${duration.toFixed(2)}ms`, { sql })
407
+ }
408
+ })
407
409
 
408
410
  // If query takes > 50ms, callback is triggered
409
- await debugDb.selectFrom('users').selectAll().execute();
411
+ await debugDb.selectFrom('users').selectAll().execute()
410
412
  ```
411
413
 
412
414
  ### Collecting and Analyzing Metrics
413
415
 
414
416
  ```typescript
415
- import { withDebug, formatSQL } from '@kysera/debug';
417
+ import { withDebug, formatSQL } from '@kysera/debug'
416
418
 
417
419
  const debugDb = withDebug(db, {
418
- maxMetrics: 500, // Keep last 500 queries
419
- });
420
+ maxMetrics: 500 // Keep last 500 queries
421
+ })
420
422
 
421
423
  // Execute some queries
422
- await debugDb.selectFrom('users').selectAll().execute();
423
- await debugDb.selectFrom('posts').selectAll().execute();
424
+ await debugDb.selectFrom('users').selectAll().execute()
425
+ await debugDb.selectFrom('posts').selectAll().execute()
424
426
 
425
427
  // Analyze metrics
426
- const metrics = debugDb.getMetrics();
427
- const totalDuration = metrics.reduce((sum, m) => sum + m.duration, 0);
428
- const avgDuration = totalDuration / metrics.length;
428
+ const metrics = debugDb.getMetrics()
429
+ const totalDuration = metrics.reduce((sum, m) => sum + m.duration, 0)
430
+ const avgDuration = totalDuration / metrics.length
429
431
 
430
- console.log(`Total queries: ${metrics.length}`);
431
- console.log(`Average duration: ${avgDuration.toFixed(2)}ms`);
432
+ console.log(`Total queries: ${metrics.length}`)
433
+ console.log(`Average duration: ${avgDuration.toFixed(2)}ms`)
432
434
 
433
435
  // Find slowest query
434
- const slowest = metrics.reduce((max, m) =>
435
- m.duration > max.duration ? m : max
436
- );
437
- console.log('Slowest query:');
438
- console.log(formatSQL(slowest.sql));
439
- console.log(`Duration: ${slowest.duration.toFixed(2)}ms`);
436
+ const slowest = metrics.reduce((max, m) => (m.duration > max.duration ? m : max))
437
+ console.log('Slowest query:')
438
+ console.log(formatSQL(slowest.sql))
439
+ console.log(`Duration: ${slowest.duration.toFixed(2)}ms`)
440
440
  ```
441
441
 
442
442
  ### Advanced Profiling
443
443
 
444
444
  ```typescript
445
- import { QueryProfiler } from '@kysera/debug';
445
+ import { QueryProfiler } from '@kysera/debug'
446
446
 
447
- const profiler = new QueryProfiler({ maxQueries: 1000 });
447
+ const profiler = new QueryProfiler({ maxQueries: 1000 })
448
448
 
449
449
  // Record queries from debug database
450
- const debugDb = withDebug(db);
450
+ const debugDb = withDebug(db)
451
451
  // ... execute queries ...
452
452
 
453
- const metrics = debugDb.getMetrics();
454
- metrics.forEach(m => profiler.record(m));
453
+ const metrics = debugDb.getMetrics()
454
+ metrics.forEach(m => profiler.record(m))
455
455
 
456
456
  // Get comprehensive summary
457
- const summary = profiler.getSummary();
458
- console.log('Query Performance Summary:');
459
- console.log(` Total Queries: ${summary.totalQueries}`);
460
- console.log(` Total Time: ${summary.totalDuration.toFixed(2)}ms`);
461
- console.log(` Average: ${summary.averageDuration.toFixed(2)}ms`);
462
- console.log(` Slowest: ${summary.slowestQuery?.duration.toFixed(2)}ms`);
463
- console.log(` Fastest: ${summary.fastestQuery?.duration.toFixed(2)}ms`);
457
+ const summary = profiler.getSummary()
458
+ console.log('Query Performance Summary:')
459
+ console.log(` Total Queries: ${summary.totalQueries}`)
460
+ console.log(` Total Time: ${summary.totalDuration.toFixed(2)}ms`)
461
+ console.log(` Average: ${summary.averageDuration.toFixed(2)}ms`)
462
+ console.log(` Slowest: ${summary.slowestQuery?.duration.toFixed(2)}ms`)
463
+ console.log(` Fastest: ${summary.fastestQuery?.duration.toFixed(2)}ms`)
464
464
 
465
465
  // Analyze slow queries
466
- const slowQueries = profiler.getSlowQueries(100);
466
+ const slowQueries = profiler.getSlowQueries(100)
467
467
  if (slowQueries.length > 0) {
468
- console.log(`\nFound ${slowQueries.length} queries slower than 100ms:`);
468
+ console.log(`\nFound ${slowQueries.length} queries slower than 100ms:`)
469
469
  slowQueries.forEach(q => {
470
- console.log(` ${q.duration.toFixed(2)}ms: ${q.sql.substring(0, 80)}...`);
471
- });
470
+ console.log(` ${q.duration.toFixed(2)}ms: ${q.sql.substring(0, 80)}...`)
471
+ })
472
472
  }
473
473
 
474
474
  // Get top 5 slowest
475
- const top5 = profiler.getSlowestQueries(5);
476
- console.log('\nTop 5 Slowest Queries:');
475
+ const top5 = profiler.getSlowestQueries(5)
476
+ console.log('\nTop 5 Slowest Queries:')
477
477
  top5.forEach((q, i) => {
478
- console.log(`${i + 1}. ${q.duration.toFixed(2)}ms`);
479
- console.log(formatSQL(q.sql));
480
- console.log('');
481
- });
478
+ console.log(`${i + 1}. ${q.duration.toFixed(2)}ms`)
479
+ console.log(formatSQL(q.sql))
480
+ console.log('')
481
+ })
482
482
  ```
483
483
 
484
484
  ### Custom Logger Integration
485
485
 
486
486
  ```typescript
487
- import { withDebug } from '@kysera/debug';
488
- import type { KyseraLogger } from '@kysera/core';
487
+ import { withDebug } from '@kysera/debug'
488
+ import type { KyseraLogger } from '@kysera/core'
489
489
 
490
490
  // Custom logger implementation
491
491
  const customLogger: KyseraLogger = {
492
492
  debug: (message: string) => {
493
493
  // Send to logging service
494
- loggingService.debug('db-query', message);
494
+ loggingService.debug('db-query', message)
495
495
  },
496
496
  info: (message: string) => {
497
- loggingService.info('db-query', message);
497
+ loggingService.info('db-query', message)
498
498
  },
499
499
  warn: (message: string) => {
500
- loggingService.warn('db-query', message);
500
+ loggingService.warn('db-query', message)
501
501
  },
502
502
  error: (message: string) => {
503
- loggingService.error('db-query', message);
504
- },
505
- };
503
+ loggingService.error('db-query', message)
504
+ }
505
+ }
506
506
 
507
507
  const debugDb = withDebug(db, {
508
508
  logger: customLogger,
509
509
  logQuery: true,
510
- logParams: true,
511
- });
510
+ logParams: true
511
+ })
512
512
  ```
513
513
 
514
514
  ### Production Monitoring
515
515
 
516
516
  ```typescript
517
- import { withDebug } from '@kysera/debug';
517
+ import { withDebug } from '@kysera/debug'
518
518
 
519
519
  const debugDb = withDebug(db, {
520
520
  logQuery: false, // Don't log in production
@@ -525,51 +525,52 @@ const debugDb = withDebug(db, {
525
525
  apm.recordTransaction({
526
526
  type: 'db.query',
527
527
  duration,
528
- metadata: { sql },
529
- });
528
+ metadata: { sql }
529
+ })
530
530
 
531
531
  // Alert if extremely slow
532
532
  if (duration > 1000) {
533
533
  alerting.critical('Database query exceeded 1 second', {
534
534
  sql,
535
- duration,
536
- });
535
+ duration
536
+ })
537
537
  }
538
- },
539
- });
538
+ }
539
+ })
540
540
 
541
541
  // Periodic metrics reporting
542
542
  setInterval(() => {
543
- const metrics = debugDb.getMetrics();
543
+ const metrics = debugDb.getMetrics()
544
544
  if (metrics.length > 0) {
545
- const avgDuration = metrics.reduce((sum, m) => sum + m.duration, 0) / metrics.length;
545
+ const avgDuration = metrics.reduce((sum, m) => sum + m.duration, 0) / metrics.length
546
546
 
547
- monitoring.gauge('db.query.avg_duration', avgDuration);
548
- monitoring.gauge('db.query.count', metrics.length);
547
+ monitoring.gauge('db.query.avg_duration', avgDuration)
548
+ monitoring.gauge('db.query.count', metrics.length)
549
549
 
550
- debugDb.clearMetrics(); // Reset for next interval
550
+ debugDb.clearMetrics() // Reset for next interval
551
551
  }
552
- }, 60000); // Every minute
552
+ }, 60000) // Every minute
553
553
  ```
554
554
 
555
555
  ### Formatting SQL for Display
556
556
 
557
557
  ```typescript
558
- import { formatSQL, formatSQLPretty, highlightSQL } from '@kysera/debug';
558
+ import { formatSQL, formatSQLPretty, highlightSQL } from '@kysera/debug'
559
559
 
560
- const sql = 'SELECT u.id, u.name, COUNT(p.id) as post_count FROM users u LEFT JOIN posts p ON u.id = p.user_id WHERE u.active = true GROUP BY u.id, u.name ORDER BY post_count DESC';
560
+ const sql =
561
+ 'SELECT u.id, u.name, COUNT(p.id) as post_count FROM users u LEFT JOIN posts p ON u.id = p.user_id WHERE u.active = true GROUP BY u.id, u.name ORDER BY post_count DESC'
561
562
 
562
563
  // Basic formatting
563
- console.log('Basic Format:');
564
- console.log(formatSQL(sql));
564
+ console.log('Basic Format:')
565
+ console.log(formatSQL(sql))
565
566
 
566
567
  // Pretty formatting with indentation
567
- console.log('\nPretty Format:');
568
- console.log(formatSQLPretty(sql));
568
+ console.log('\nPretty Format:')
569
+ console.log(formatSQLPretty(sql))
569
570
 
570
571
  // Highlighted for terminal
571
- console.log('\nHighlighted:');
572
- console.log(highlightSQL(formatSQL(sql)));
572
+ console.log('\nHighlighted:')
573
+ console.log(highlightSQL(formatSQL(sql)))
573
574
  ```
574
575
 
575
576
  ## TypeScript Support
@@ -582,40 +583,41 @@ import type {
582
583
  DebugOptions,
583
584
  DebugDatabase,
584
585
  ProfilerSummary,
585
- ProfilerOptions,
586
- } from '@kysera/debug';
586
+ ProfilerOptions
587
+ } from '@kysera/debug'
587
588
 
588
589
  // Type-safe debug options
589
590
  const options: DebugOptions = {
590
591
  logQuery: true,
591
592
  slowQueryThreshold: 100,
592
593
  onSlowQuery: (sql: string, duration: number) => {
593
- console.warn(`Slow: ${sql} (${duration}ms)`);
594
- },
595
- };
594
+ console.warn(`Slow: ${sql} (${duration}ms)`)
595
+ }
596
+ }
596
597
 
597
598
  // Type-safe database
598
599
  interface Database {
599
- users: { id: number; name: string };
600
+ users: { id: number; name: string }
600
601
  }
601
602
 
602
- const debugDb: DebugDatabase<Database> = withDebug(db, options);
603
+ const debugDb: DebugDatabase<Database> = withDebug(db, options)
603
604
  ```
604
605
 
605
606
  ## Performance Considerations
606
607
 
607
608
  ### Memory Management
608
609
 
609
- The debug plugin uses a circular buffer to manage memory efficiently:
610
+ The debug plugin uses an O(1) circular buffer (ring buffer) to manage memory efficiently:
610
611
 
611
612
  - Default limit: 1000 metrics
612
- - Oldest metrics automatically removed when limit reached
613
+ - Oldest metrics automatically removed when limit reached (O(1) operation)
613
614
  - Configure via `maxMetrics` option
615
+ - Index-based metrics tracking for constant-time summary calculations
614
616
 
615
617
  ```typescript
616
618
  const debugDb = withDebug(db, {
617
- maxMetrics: 500, // Keep only last 500 queries
618
- });
619
+ maxMetrics: 500 // Keep only last 500 queries
620
+ })
619
621
  ```
620
622
 
621
623
  ### Production Usage
@@ -623,29 +625,31 @@ const debugDb = withDebug(db, {
623
625
  For production environments:
624
626
 
625
627
  1. **Disable verbose logging:**
628
+
626
629
  ```typescript
627
630
  const debugDb = withDebug(db, {
628
631
  logQuery: false,
629
- logParams: false,
630
- });
632
+ logParams: false
633
+ })
631
634
  ```
632
635
 
633
636
  2. **Use slow query detection only:**
637
+
634
638
  ```typescript
635
639
  const debugDb = withDebug(db, {
636
640
  logQuery: false,
637
641
  slowQueryThreshold: 500,
638
642
  onSlowQuery: (sql, duration) => {
639
- monitoring.recordSlowQuery({ sql, duration });
640
- },
641
- });
643
+ monitoring.recordSlowQuery({ sql, duration })
644
+ }
645
+ })
642
646
  ```
643
647
 
644
648
  3. **Limit metrics collection:**
645
649
  ```typescript
646
650
  const debugDb = withDebug(db, {
647
- maxMetrics: 100, // Smaller buffer for production
648
- });
651
+ maxMetrics: 100 // Smaller buffer for production
652
+ })
649
653
  ```
650
654
 
651
655
  ## Runtime Compatibility