feat(vba): resolve the table or query named by DLookup and friends - #285
Merged
Merged
Conversation
The eight Access domain aggregates — DLookup, DCount, DSum, DMax, DMin, DAvg, DFirst and DLast — take the domain they read as their SECOND argument: a table name or a saved query name. None of them was modelled, so a procedure whose only data access is a DLookup came through the graph as a procedure that touches no data at all. Decisions taken: - REUSE, not a second resolver. The name gate and the emit path are the ones #253 built for saved-query names (`looksLikeSavedQueryName` and `emitSavedQueryReference`), so a domain name is answered by exactly the same "is this a query?" rule, emits the same `dao-query` reference tagged `vba-query-name`, and is bound by the same `matchVbaQueryName` resolver — which still DECLINES on a miss rather than fabricating a table placeholder. The issue asked for this explicitly. - The scan lives in `vba/sql-wrapper.ts` rather than a new file. All it adds over #253 is a call shape; a module of its own would have needed a rule-table entry to buy nothing. - Argument 2 is found by WALKING the argument list, not by splitting on commas. Two ordinary spellings break a naive split — a comma inside the criteria literal (`"Id In (1,2)"`) and a comma inside a nested call (`"Id=" & Nz(x, 0)`) — and both would have silently shifted the domain to the wrong argument. - Only a lone string literal is read. A variable or an expression in argument 2 names something only the runtime knows, so it is skipped in silence. A domain spelled as a full SQL statement is likewise dropped by the verb gate: silent beats wrong. - A file that declares its own procedure by one of these names is left alone. The call keeps resolving to that user code through the ordinary call-site scan, and no domain reference is invented on top of it. The regex anchors on the opening paren, so a helper named `DLookupSeguro` was never a candidate in the first place. Corpus measurement (00_EXPEDIENTES, 00_GESTION_RIESGOS, HPS_SOLICITUDES, 462 files): the probe's JSON output is BYTE-IDENTICAL with and without the change. These functions have zero uses there, exactly as the issue said, so node and edge counts are unchanged and nothing new was matched. Closes #255 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019gmKKUq1ng5ESk6Qhxu77d
This was referenced Sep 2, 2026
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.
The eight Access domain aggregates —
DLookup,DCount,DSum,DMax,DMin,DAvg,DFirst,DLast— take the domain they read as their second argument: a table name or a saved query name. None was modelled, so a procedure whose only data access is aDLookupcame through the graph as a procedure that touches no data at all.What changed
src/extraction/vba/sql-wrapper.ts— argument-list walk for the eight domain functions, emitting through the existing feat(vba): resolve saved query names to their query node #253 path.__tests__/extraction-vba-domain-functions.test.ts— 29 tests.CHANGELOG.md— one bullet under[Unreleased]→### New Features, ends(#255).Reuse, not a second resolver
The issue said it outright: "reuse that resolver, do not write a second one." The name gate and emit path are #253's (
looksLikeSavedQueryName,emitSavedQueryReference), so a domain name is answered by the same "is this a query?" rule, emits the samedao-queryreference taggedvba-query-name, and is bound by the samematchVbaQueryName— which still declines on a miss rather than fabricating a table placeholder.Argument 2 is found by walking, not by splitting
Splitting the argument list on commas is the obvious implementation and it is wrong. Two ordinary spellings break it, and both would have silently shifted the domain to the wrong argument:
DLookup("N", "T", "Id In (1,2)")DLookup("N", "T", "Id=" & Nz(x, 0))Both are covered by fixtures.
Corpus measurement — the point here is that nothing moved
Run over
00_EXPEDIENTES,00_GESTION_RIESGOSandHPS_SOLICITUDES, after the change:vba-sql-tablevba-closes-formdao-queryvba-row-source-dynamicByte-identical to the pre-change run. The issue predicted zero uses of these functions in this corpus, and that is confirmed: no new reference appears, and no existing count moved. A change here would have meant the argument walk was matching something it should not — for a feature ranked in the last wave precisely because it is unused locally, "nothing moved" is the result you want.
Behaviour is proven by the 29 fixtures, not by corpus counts.
Verification
npx tsc --noEmit— clean.Not verified
The full local suite was not run to completion:
npx vitest runon this machine dies withFatal process out of memory, an environment limit unrelated to this change (it reproduces on file sets this PR does not touch). CI runs the full suite on Ubuntu and Windows.Closes #255
🤖 Generated with Claude Code
https://claude.ai/code/session_019gmKKUq1ng5ESk6Qhxu77d