Skip to content

Commit 0f350ef

Browse files
authored
feat(vnext): expose session relation completion (#197)
## Summary - expose one framework-independent completion lifecycle through `SqlDocumentSession.complete()` and `onDidChange()` - compose visible CTEs with one bounded catalog page using deterministic ranking, proven shadowing, original-document UTF-16 edits, and closed incomplete reasons - share catalog scheduling/cache/epoch ownership at service scope while keeping request, refresh intent, and terminal-loading lifecycle session-local - make the public completion result extensible with a `kind: "relation"` item discriminant - document the consumer contract and add cold/warm local plus cold/cached catalog benchmarks ## Why The lower catalog scheduler and parser-independent query-site work were not yet usable through the public session. This slice connects those layers without exposing coordinator identities, epochs, timers, or CodeMirror state. It gives adapters a bounded local-first response and an explicit revision event when catalog evidence becomes usable. Catalog scope is treated as a live connection incarnation. Loading, partial, paginated, failed, overloaded, and timed-out evidence remains explicit, so unresolved marimo metadata cannot be mistaken for a complete empty catalog. ## Evidence - 1,989 unit tests pass with one expected failure - changed production files: 98.02% statements, 95.13% branches, 100% functions, 98.23% lines - strict and loose-optional vNext type fixtures pass - source, test, and demo typechecks pass - oxlint and test-integrity checks pass - 10 KiB completion benchmark: cold p99 about 1.5 ms; warm p99 below 0.8 ms - two independent exact-head reviews approved the final lifecycle, API, timer, and consumer semantics <!-- This is an auto-generated description by cubic. --> --- ## Summary by cubic Exposes a session-based, framework-independent relation completion API with deterministic CTE + catalog suggestions and clear change events. Aligns CI bundle budgets for both the core and the worker fixture to match the new relation service. - **New Features** - `SqlDocumentSession.complete(request)` returns `SqlCompletionResult` with `kind: "relation"` items. - `SqlDocumentSession.onDidChange(listener)` emits `SqlSessionChangeEvent` when catalog evidence becomes usable. - Deterministic ranking for local CTEs plus a bounded catalog page; supports cancellation and response budgets. - `createSqlLanguageService({ catalog, completion: { catalogResponseBudgetMs } })` to configure a catalog and timing. - Docs updated in `@marimo-team/codemirror-sql/vnext`; added unit tests and a 10 KiB session completion benchmark. - CI: set core bundle allocation to 48 KiB gzip (180 KiB raw) and raised worker fixture ceiling to 160 KiB gzip (700 KiB raw); updated worker README and capability charter. - **Migration** - Rename `SqlRelationCompletionItem` → `SqlCompletionItem` and `SqlRelationCompletionList` → `SqlCompletionList`. - Update CodeMirror resolver signatures to accept `SqlCompletionItem`. <sup>Written for commit c66cffc. Summary will update on new commits.</sup> <a href="https://cubic.dev/pr/marimo-team/codemirror-sql/pull/197?utm_source=github" target="_blank" rel="noopener noreferrer" data-no-image-dialog="true"><picture><source media="(prefers-color-scheme: dark)" srcset="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"><source media="(prefers-color-scheme: light)" srcset="https://www.cubic.dev/buttons/review-in-cubic-light.svg"><img alt="Review in cubic" src="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"></picture></a> <!-- End of auto-generated description by cubic. -->
1 parent f0f4d5e commit 0f350ef

18 files changed

Lines changed: 4884 additions & 170 deletions

docs/vnext/capability-charter.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -239,6 +239,7 @@ count and estimated retained bytes.
239239

240240
Provisional compressed bundle budgets:
241241

242+
- Framework-independent core with relation completion: 48 KiB
242243
- Core plus CodeMirror adapter, excluding parser and dialect data: 75 KiB
243244
- Each ordinary dialect module: 25 KiB
244245
- Optional `node-sql-parser` chunk: no regression from its recorded baseline

docs/vnext/session-primitives.md

Lines changed: 71 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,10 @@
33
Status: experimental walking skeleton
44
Import: `@marimo-team/codemirror-sql/vnext`
55

6-
This entry point currently provides document ownership, atomic text/context
7-
updates, opaque revisions, dialect registration, and lifecycle management. It
8-
does not yet provide parsing, completion, diagnostics, hover, or navigation.
9-
Those methods will be added only with working vertical slices.
6+
This entry point provides document ownership, atomic text/context updates,
7+
opaque revisions, dialect registration, lifecycle management, and
8+
parser-independent relation completion. Diagnostics, hover, navigation, and
9+
general expression completion are not yet available.
1010

1111
See [source coordinates](./source-coordinates.md) for the shared UTF-16 range
1212
contract and the internal immutable source-snapshot model.
@@ -56,6 +56,73 @@ Use `{ kind: "replace", text }` for full replacement and
5656
also supplies the complete embedded-region set for its resulting text. A
5757
region-only transaction can replace or clear that set without a fake text edit.
5858

59+
## Relation completion
60+
61+
Completion works without a catalog for visible CTEs. A service can also own one
62+
shared asynchronous relation-catalog provider:
63+
64+
```ts
65+
const service = createSqlLanguageService<AppSqlContext>({
66+
catalog: {
67+
id: "app-catalog",
68+
search: async (request, signal) => {
69+
signal.throwIfAborted();
70+
return {
71+
coverage: { kind: "complete" },
72+
epoch: { generation: 0, token: "initial" },
73+
relations: [],
74+
status: "ready",
75+
};
76+
},
77+
},
78+
completion: { catalogResponseBudgetMs: 40 },
79+
dialects: [duckdbDialect()],
80+
});
81+
82+
const session = service.openDocument({
83+
context: {
84+
dialect: "duckdb",
85+
engine: "local",
86+
catalog: { scope: "connection-incarnation:1" },
87+
},
88+
text: "SELECT * FROM ",
89+
});
90+
91+
const subscription = session.onDidChange(({ reason }) => {
92+
if (reason === "catalog" || reason === "catalog-availability") {
93+
// Ask the editor adapter to request completion again.
94+
}
95+
});
96+
97+
const result = await session.complete({
98+
position: 14,
99+
trigger: { kind: "invoked" },
100+
});
101+
102+
if (result.status === "ready" && session.isCurrent(result.revision)) {
103+
for (const item of result.value.items) {
104+
// Apply item.edit in the original document's UTF-16 coordinates.
105+
}
106+
}
107+
108+
subscription.dispose();
109+
session.dispose();
110+
service.dispose();
111+
```
112+
113+
The catalog `scope` identifies a live connection incarnation, not a reusable
114+
display name. Search responses distinguish complete, partial, paginated,
115+
loading, and failed evidence. A ready result can therefore be incomplete; its
116+
closed `issues` explain why, while `sources` reports catalog outcomes without
117+
exposing provider errors or internal epochs.
118+
119+
The interactive catalog wait is bounded from the start of `complete()`. When
120+
the budget expires, the session returns local evidence with a
121+
`catalog-loading` issue and a checked remaining intent lease. Compatible
122+
readiness advances the session revision and emits `catalog-availability`;
123+
higher provider epochs emit `catalog`. Consumers must request completion again
124+
and apply only results whose revision remains current.
125+
59126
## Dialect registration
60127

61128
`duckdbDialect()`, `postgresDialect()`, `bigQueryDialect()`, and

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
"bench:local-relation-site": "vitest bench --run src/vnext/__tests__/local-relation-site.bench.ts",
3232
"bench:parser-adapter": "vitest bench --run src/vnext/__tests__/node-sql-parser-adapter.bench.ts",
3333
"bench:query-site": "vitest bench --run src/vnext/__tests__/query-site.bench.ts",
34+
"bench:session-completion": "vitest bench --run src/vnext/__tests__/session-completion.bench.ts",
3435
"bench:statement-index": "vitest bench --run src/vnext/__tests__/statement-index.bench.ts",
3536
"test:package": "node ./scripts/clean.mjs && tsc && node ./scripts/package-smoke.mjs",
3637
"demo": "vite build",

scripts/worker-placement.mjs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -35,11 +35,11 @@ const PARSER_MARKERS = [
3535
"tableList",
3636
];
3737
const BIGQUERY_GZIP_LIMIT = 50 * 1024;
38-
const CORE_TOTAL_GZIP_LIMIT = 16 * 1024;
39-
const CORE_TOTAL_RAW_LIMIT = 52 * 1024;
38+
const CORE_TOTAL_GZIP_LIMIT = 48 * 1024;
39+
const CORE_TOTAL_RAW_LIMIT = 180 * 1024;
4040
const POSTGRESQL_GZIP_LIMIT = 68 * 1024;
41-
const WORKER_TOTAL_GZIP_LIMIT = 128 * 1024;
42-
const WORKER_TOTAL_RAW_LIMIT = 570 * 1024;
41+
const WORKER_TOTAL_GZIP_LIMIT = 160 * 1024;
42+
const WORKER_TOTAL_RAW_LIMIT = 700 * 1024;
4343
const MIME_TYPES = new Map([
4444
[".css", "text/css; charset=utf-8"],
4545
[".html", "text/html; charset=utf-8"],

0 commit comments

Comments
 (0)