|
1 | 1 | import assert from 'node:assert/strict' |
| 2 | +import { EventEmitter } from 'node:events' |
2 | 3 | import test from 'node:test' |
| 4 | +import type { Knex } from 'knex' |
3 | 5 | import { createFakeKnex } from '../test/helpers/fake-knex.ts' |
4 | 6 | import { createTracer } from './tracer.ts' |
5 | 7 | import type { QueryStartEvent, TracerQueryEndEvent, TracerQueryErrorEvent } from './types.ts' |
@@ -104,3 +106,82 @@ test('createTracer ignores tracer errors by default', () => { |
104 | 106 | knex.emit('query-response', [], { __knexQueryUid: 'query-1' }) |
105 | 107 | }) |
106 | 108 | }) |
| 109 | + |
| 110 | +test('createTracer supports queries without knex ids', () => { |
| 111 | + const knex = createFakeKnex() |
| 112 | + const query = { sql: 'select ?', bindings: [1] } |
| 113 | + const startEvents: QueryStartEvent[] = [] |
| 114 | + const endEvents: TracerQueryEndEvent[] = [] |
| 115 | + |
| 116 | + createTracer(knex, { |
| 117 | + onStart(event) { |
| 118 | + startEvents.push(event) |
| 119 | + }, |
| 120 | + onEnd(event) { |
| 121 | + endEvents.push(event) |
| 122 | + }, |
| 123 | + }) |
| 124 | + |
| 125 | + knex.emit('query', query) |
| 126 | + knex.emit('query-response', [], query) |
| 127 | + |
| 128 | + assert.equal(startEvents.length, 1) |
| 129 | + assert.equal(startEvents[0].queryId, 'anonymous:1') |
| 130 | + assert.equal(endEvents.length, 1) |
| 131 | + assert.equal(endEvents[0].queryId, 'anonymous:1') |
| 132 | +}) |
| 133 | + |
| 134 | +test('createTracer normalizes non-object query payloads', () => { |
| 135 | + const knex = createFakeKnex() |
| 136 | + const startEvents: QueryStartEvent[] = [] |
| 137 | + |
| 138 | + createTracer(knex, { |
| 139 | + onStart(event) { |
| 140 | + startEvents.push(event) |
| 141 | + }, |
| 142 | + }) |
| 143 | + |
| 144 | + knex.emit('query', 'select 1') |
| 145 | + |
| 146 | + assert.equal(startEvents.length, 1) |
| 147 | + assert.equal(startEvents[0].queryId, 'anonymous:1') |
| 148 | + assert.equal(startEvents[0].sql, '') |
| 149 | +}) |
| 150 | + |
| 151 | +test('createTracer swallows tracer error handler failures', () => { |
| 152 | + const knex = createFakeKnex() |
| 153 | + |
| 154 | + createTracer(knex, { |
| 155 | + onEnd() { |
| 156 | + throw new Error('logger failed') |
| 157 | + }, |
| 158 | + onTracerError() { |
| 159 | + throw new Error('tracer failed') |
| 160 | + }, |
| 161 | + }) |
| 162 | + |
| 163 | + assert.doesNotThrow(() => { |
| 164 | + knex.emit('query', { __knexQueryUid: 'query-1', sql: 'select 1' }) |
| 165 | + knex.emit('query-response', [], { __knexQueryUid: 'query-1' }) |
| 166 | + }) |
| 167 | +}) |
| 168 | + |
| 169 | +test('createTracer disposes with removeListener when off is unavailable', () => { |
| 170 | + const emitter = new EventEmitter() |
| 171 | + const knex = { |
| 172 | + emit: emitter.emit.bind(emitter), |
| 173 | + on: emitter.on.bind(emitter), |
| 174 | + removeListener: emitter.removeListener.bind(emitter), |
| 175 | + } as unknown as Knex & Pick<EventEmitter, 'emit'> |
| 176 | + const startEvents: QueryStartEvent[] = [] |
| 177 | + const tracer = createTracer(knex, { |
| 178 | + onStart(event) { |
| 179 | + startEvents.push(event) |
| 180 | + }, |
| 181 | + }) |
| 182 | + |
| 183 | + tracer.dispose() |
| 184 | + knex.emit('query', { __knexQueryUid: 'query-1', sql: 'select 1' }) |
| 185 | + |
| 186 | + assert.equal(startEvents.length, 0) |
| 187 | +}) |
0 commit comments