perf(editor): single-pass table name semantic coloring
This commit is contained in:
2 files changed
+18
-13
No files matched your search
@@ -358,6 +358,16 @@ describe("sqlSemanticModel baseline fixtures", () => {
|
|||||||
expect(spans.map((span) => sql.slice(span.start, span.end))).toEqual(["users", "orders", "audit_log", "events"]);
|
expect(spans.map((span) => sql.slice(span.start, span.end))).toEqual(["users", "orders", "audit_log", "events"]);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("keeps table highlighting linear for a 24,000-line Oracle select list", () => {
|
||||||
|
const sql = `SELECT\n${Array.from({ length: 23_997 }, (_, index) => ` t.col_${index} AS alias_${index},`).join("\n")}\n t.final_col\nFROM app.huge_table t`;
|
||||||
|
const startedAt = performance.now();
|
||||||
|
const spans = sqlSemanticTableNameSpans(sql, { databaseType: "oracle" });
|
||||||
|
const elapsedMs = performance.now() - startedAt;
|
||||||
|
|
||||||
|
expect(spans.map((span) => sql.slice(span.start, span.end))).toEqual(["huge_table"]);
|
||||||
|
expect(elapsedMs).toBeLessThan(2_000);
|
||||||
|
});
|
||||||
|
|
||||||
it("highlights mutation targets but ignores strings, comments, and table functions", () => {
|
it("highlights mutation targets but ignores strings, comments, and table functions", () => {
|
||||||
const sql = "UPDATE users SET name = 'FROM fake'; INSERT INTO audit_log(id) VALUES (1); -- FROM ignored\nSELECT * FROM read_csv('events.csv') e";
|
const sql = "UPDATE users SET name = 'FROM fake'; INSERT INTO audit_log(id) VALUES (1); -- FROM ignored\nSELECT * FROM read_csv('events.csv') e";
|
||||||
const spans = sqlSemanticTableNameSpans(sql);
|
const spans = sqlSemanticTableNameSpans(sql);
|
||||||
|
|||||||
@@ -131,18 +131,6 @@ function updateIntroducesMutationTarget(tokens: readonly SqlSemanticToken[], upd
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
function commaContinuesTableList(tokens: readonly SqlSemanticToken[], commaIndex: number): boolean {
|
|
||||||
const comma = tokens[commaIndex];
|
|
||||||
if (comma?.text !== ",") return false;
|
|
||||||
for (let index = commaIndex - 1; index >= 0; index -= 1) {
|
|
||||||
const item = tokens[index];
|
|
||||||
if (!item || item.depth !== comma.depth || item.kind !== "word") continue;
|
|
||||||
if (item.normalized === "from") return true;
|
|
||||||
if (item.normalized === "select" || item.normalized === "join" || TABLE_INTRODUCERS.has(item.normalized) || CLAUSE_BOUNDARIES.has(item.normalized)) return false;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Finds concrete table-name tokens for visual highlighting without consulting
|
* Finds concrete table-name tokens for visual highlighting without consulting
|
||||||
* metadata. Only the final identifier in a qualified name is returned, so
|
* metadata. Only the final identifier in a qualified name is returned, so
|
||||||
@@ -153,11 +141,18 @@ export function sqlSemanticTableNameSpans(sql: string, options: SqlSemanticBuild
|
|||||||
const tokens = significantTokens(tokenizeSqlSemantic(sql, dialect.id));
|
const tokens = significantTokens(tokenizeSqlSemantic(sql, dialect.id));
|
||||||
const spans: SqlSemanticSpan[] = [];
|
const spans: SqlSemanticSpan[] = [];
|
||||||
const seen = new Set<string>();
|
const seen = new Set<string>();
|
||||||
|
const commaContinuesTableListByDepth = new Map<number, boolean>();
|
||||||
|
|
||||||
for (let index = 0; index < tokens.length; index += 1) {
|
for (let index = 0; index < tokens.length; index += 1) {
|
||||||
const item = tokens[index];
|
const item = tokens[index];
|
||||||
|
if (!item) continue;
|
||||||
|
const commaContinuesTableList = item.text === "," && commaContinuesTableListByDepth.get(item.depth) === true;
|
||||||
|
if (item.kind === "word") {
|
||||||
|
if (item.normalized === "from") commaContinuesTableListByDepth.set(item.depth, true);
|
||||||
|
else if (item.normalized === "select" || item.normalized === "join" || TABLE_INTRODUCERS.has(item.normalized) || CLAUSE_BOUNDARIES.has(item.normalized)) commaContinuesTableListByDepth.set(item.depth, false);
|
||||||
|
}
|
||||||
const introduced = item?.kind === "word" && TABLE_INTRODUCERS.has(item.normalized) && (item.normalized !== "update" || updateIntroducesMutationTarget(tokens, index));
|
const introduced = item?.kind === "word" && TABLE_INTRODUCERS.has(item.normalized) && (item.normalized !== "update" || updateIntroducesMutationTarget(tokens, index));
|
||||||
if (!introduced && !commaContinuesTableList(tokens, index)) continue;
|
if (!introduced && !commaContinuesTableList) continue;
|
||||||
|
|
||||||
let target = index + 1;
|
let target = index + 1;
|
||||||
while (TABLE_TARGET_MODIFIERS.has(tokens[target]?.normalized ?? "")) target += 1;
|
while (TABLE_TARGET_MODIFIERS.has(tokens[target]?.normalized ?? "")) target += 1;
|
||||||
|
|||||||
Reference in new issue
Block a user