feat: FROM-aware autocompletion — alias/scope resolution + debounced column loading (#84)#146
Merged
Merged
Conversation
…column loading (#84) Column completion now fires while typing, driven by the statement's FROM/JOIN clause, without expanding a table in the sidebar first. - src/core/from-scope.js (new, pure, 100%): fromScopeAt(text, pos[, toks]) → {db, table, alias}[] for the caret's statement, reusing the SQL tokenizer so strings/comments/`;` can't fool it; pendingColumnLoads(scope, schema) diffs the in-scope tables against the loaded schema. - src/core/completions.js: rankCompletions resolves `ctx.parent` through the FROM-scope aliases (`e.` → events) and scopes/boosts unqualified columns to the statement's tables; absent scope keeps today's global behavior. completionContext/openBacktickStart accept a shared token list so the completion path lexes the caret prefix once. - src/editor/codemirror-adapter.js: the completion source attaches the scope; a debounced idle tick (300ms, off the keystroke path) prefetches unloaded FROM columns via the existing app.loadColumns ('loading' sentinel dedupes, per-connection cache) and refreshes an open dropdown — guarded against a destroy-between-tick-and-resolve race with the file's `view === v` idiom. Acceptance criteria covered; from-scope.js + completions.js at 100/100/100/100. Unit tests (real CM6 under happy-dom) + a cross-engine e2e for alias completion. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01GyLqZGyUkm7mP6WhZCkodj
…etions-84 # Conflicts: # CHANGELOG.md
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.
What & why
Implements #84 — schema-aware, FROM-driven autocompletion on the CM6 editor (#21). Column completion previously almost never fired: columns were only fetched when a table was expanded in the sidebar, aliases didn't resolve, and unqualified columns competed against every loaded table globally.
Now completion is FROM-aware and columns load while you type:
src/core/from-scope.js(new, pure, 100%) —fromScopeAt(text, pos[, toks])resolves the caret's statement into its base tables ({db, table, alias}[]), reusing the SQL tokenizer so aFROM/;inside a string or comment can't fool it. Handlesdb.table,table alias,table AS alias, comma joins,JOIN; skipsARRAY JOIN, table functions, and FROM-position subqueries.pendingColumnLoads(scope, schema)diffs the in-scope tables against the loaded schema.src/core/completions.js—rankCompletionsresolvesctx.parentthrough the FROM-scope aliases (e.→events) and scopes/boosts unqualified columns to the statement's tables (an unrelated loaded table's columns are no longer suggested). With no scope in view it degrades to today's global pool, so existing behavior is unchanged.completionContext/openBacktickStartnow accept a shared token list so the completion path lexes the caret prefix once, not twice.src/editor/codemirror-adapter.js— the completion source attaches the scope; a debounced idle tick (300 ms, never on the keystroke path) prefetches unloaded FROM columns via the existingapp.loadColumns(the'loading'sentinel dedupes; per-connection cache) and refreshes an open dropdown when they arrive — guarded against a destroy-between-tick-and-resolve race with this file'sview === vidiom.No
src/ui/app.jschange (the adapter reusesapp.actions.loadColumns/app.state.schema/app.completions). No new runtime dependency —startCompletion/completionStatuscome from the already-bundled@codemirror/autocomplete.Acceptance (all met)
FROM db.table(unexpanded) offers that table's columns, unqualified, scoped to the statement ✅e.afterFROM events e(and… AS e) offersevents' columns ✅db.table./table.qualification still works ✅npm testgreen at the per-file gate (from-scope.js+completions.jsat 100%) ✅Testing
npm test— 1386 pass;from-scope.jsandcompletions.jsat 100/100/100/100.npm run build— succeeds.npm run test:e2e(chromium + webkit) — all editor specs pass, including a new cross-engine test assertinge.→eventscolumns with out-of-scope suppression. (Firefox skipped — known sandboxEPERMin this environment.)/code-review --high(correctness + cleanup fan-out): fixed a NUL-byte-in-dedup-key issue, removed a double-tokenization on the completion path, dropped a dead token field, and closed the async-after-destroy refresh race.Checklist
npm testpasses (the per-file coverage gate is non-negotiable)npm run buildsucceeds (single-filedist/sql.html)src/core/, network insrc/net/(injected fetch), DOM insrc/ui// editor behind theEditorPortseamCHANGELOG.md([Unreleased]) updatedCloses #84
🤖 Generated with Claude Code