fix(fastify): per-query file tag, withRequestContext signature, and a first-party Fastify plugin#16
Merged
Merged
Conversation
The build-time caller was stored in a WeakMap keyed by the drizzle session, which is shared across every query on a `drizzle()` instance. Two queries built before either executed collided on that single entry: the first to reach `prepareQuery` emitted both call sites joined and deleted the entry, the second emitted no `file` tag at all. This dropped/mis-attributed the tag under any real concurrency (two in-flight requests, `Promise.all`). `then -> execute -> _prepare -> session.prepareQuery` runs synchronously, so instead tag each built query object with its own caller and publish it only for that synchronous window. Concurrent queries can't interleave inside it, so each reads exactly its own caller — and it's robust to building and awaiting queries in different orders, which an ordered queue would not be. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…llbacks `next: () => Promise<unknown>` rejected Fastify's `done: (err?: Error) => void` (and Express's `next`) with TS2345, since `void` isn't assignable to `Promise<unknown>`. `next` is only handed to `als.run`, whose return value is ignored, so widen it to `() => unknown`. Also corrects the JSDoc, which said the context carries "route and controller" — it's `route` plus optional `method`/`controller` and arbitrary keys. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
… docs Wiring sqlcommenter into Fastify by hand has two silent pitfalls: a plain `register()` encapsulates the `onRequest` hook so it never applies to routes in the parent scope (no tags, no error), and wrapping the route handler misses queries issued in earlier `onRequest`/`preHandler` hooks (e.g. an auth plugin's session lookup). Add `@query-doctor/sqlcommenter-<driver>/fastify` exporting `sqlcommenterFastify`: a global `onRequest` hook (via the `skip-override` symbol, so no extra dependency) using `request.routeOptions.url` + `request.method`, with an optional `context` callback for extra fields. Rewrite the Fastify README section to recommend the plugin and, for the manual path, document the `fastify-plugin` + `onRequest` + registration-ordering requirements and the `routerPath` -> `routeOptions.url` change for Fastify v5. Adds `fastify` as an optional peer dependency (and a dev dependency for tests). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- @query-doctor/sqlcommenter-drizzle: 0.3.0 -> 0.4.0 (file-tag fix + /fastify) - @query-doctor/sqlcommenter-mikroorm: 0.2.0 -> 0.3.0 (/fastify) - @query-doctor/sqlcommenter-typeorm: 0.2.0 -> 0.3.0 (/fastify) Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Addresses the three issues reported in the Fastify + drizzle-orm/postgres-js dogfooding feedback (Site#3434). The investigation showed two of them are shared with the
mikroorm/typeormpackages, so those are fixed too.1.
filetag clobbered / dropped under concurrency (drizzle) — bugThe build-time caller was stored in a
WeakMapkeyed by the drizzle session, which adrizzle()instance shares across every query. Two queries built before either executed collided on that one entry: the first to reachprepareQueryemitted both call sites joined (fileA;fileB) and deleted the entry; the second emitted nofiletag. This breaks under any real concurrency (two in-flight HTTP requests,Promise.all).Fix:
then → execute → _prepare → session.prepareQueryruns synchronously, so each built query object is tagged with its own caller, published into a module variable only for that synchronous window. Concurrent queries can't interleave inside it, and it's robust to building/awaiting in different orders (an ordered queue would not be).2.
withRequestContext's signature rejected Fastify'sdone— DXnext: () => Promise<unknown>failedtsc(TS2345) when passed Fastify'sdone: (err?: Error) => void(and Express'snext). Widened to() => unknown(nextis only handed toals.run, return ignored). Also corrected the JSDoc wording.3. Fastify integration docs + first-party plugin — DX
Two silent pitfalls when wiring by hand: a plain
register()encapsulates theonRequesthook (applies to nothing, no error), and wrapping the handler misses queries in earlieronRequest/preHandlerhooks.@query-doctor/sqlcommenter-<driver>/fastify→sqlcommenterFastify: a globalonRequesthook (via theskip-overridesymbol — no extra dependency) usingrequest.routeOptions.url+request.method, with an optionalcontextcallback.fastifyadded as an optional peer dependency.fastify-plugin+onRequest+ ordering requirements androuterPath→routeOptions.url(Fastify v5).Verification
Promise.all+ out-of-order build/await. New regression tests fail on the old code, pass on the new.tscconfirms the new form compiles and the old one fails with the exact reportedTS2345.onRequest/preHandler) and handler queries all getroute/method/file; a plain encapsulatedregisteris silently untagged (negative control). The manualfastify-pluginpath was also validated end-to-end.Notes
/fastifyentry; drizzle also the bug fix). Happy to add.package-lock.jsonchanges are only thefastifydevDep tree (nofastify-plugin— that's user-installed, referenced only in the manual README example).🤖 Generated with Claude Code