97 lines
3.5 KiB
TypeScript
97 lines
3.5 KiB
TypeScript
import { strict as assert } from "node:assert";
|
|
import { test } from "vitest";
|
|
import { buildSqlParserErrorDiagnostic, buildSqlSemanticDiagnostics, areSqlSemanticDiagnosticsEqual, shouldRunSqlSemanticDiagnostics } from "../../apps/desktop/src/lib/sqlSemanticDiagnostics.ts";
|
|
import type { SqlReferenceAnalysis } from "../../apps/desktop/src/types/database.ts";
|
|
|
|
const span = (startColumn: number, endColumn: number) => ({
|
|
start_line: 1,
|
|
start_column: startColumn,
|
|
end_line: 1,
|
|
end_column: endColumn,
|
|
});
|
|
|
|
test("flags missing qualified columns against the referenced table", () => {
|
|
const analysis: SqlReferenceAnalysis = {
|
|
tables: [{ name: "users", alias: "u", span: span(23, 27) }],
|
|
columns: [
|
|
{ name: "missing", qualifier: "u", span: span(10, 16) },
|
|
{ name: "id", qualifier: "u", span: span(34, 35) },
|
|
],
|
|
};
|
|
|
|
const diagnostics = buildSqlSemanticDiagnostics(analysis, {
|
|
tables: [{ name: "users", type: "table" }],
|
|
columnsByTable: new Map([["users", [{ name: "id", table: "users" }]]]),
|
|
});
|
|
|
|
assert.deepEqual(
|
|
diagnostics.map((diagnostic) => diagnostic.message),
|
|
["Unknown column u.missing"],
|
|
);
|
|
});
|
|
|
|
test("does not flag unqualified columns when multiple tables make ownership ambiguous", () => {
|
|
const analysis: SqlReferenceAnalysis = {
|
|
tables: [
|
|
{ name: "users", alias: "u", span: span(25, 29) },
|
|
{ name: "orders", alias: "o", span: span(35, 40) },
|
|
],
|
|
columns: [{ name: "id", span: span(8, 9) }],
|
|
};
|
|
|
|
const diagnostics = buildSqlSemanticDiagnostics(analysis, {
|
|
tables: [
|
|
{ name: "users", type: "table" },
|
|
{ name: "orders", type: "table" },
|
|
],
|
|
columnsByTable: new Map(),
|
|
});
|
|
|
|
assert.deepEqual(diagnostics, []);
|
|
});
|
|
|
|
test("builds a syntax diagnostic from parser errors with line and column", () => {
|
|
const diagnostic = buildSqlParserErrorDiagnostic("Expected: end of statement, found: FOM at Line: 1, Column: 10", "SELECT * FOM");
|
|
|
|
assert.equal(diagnostic?.message, "Expected: end of statement, found: FOM at Line: 1, Column: 10");
|
|
assert.deepEqual(diagnostic?.span, span(10, 12));
|
|
});
|
|
|
|
test("compares diagnostics by severity message and span", () => {
|
|
const diagnostics = [
|
|
{
|
|
message: "Unknown column u.missing",
|
|
severity: "warning" as const,
|
|
span: span(10, 16),
|
|
},
|
|
];
|
|
|
|
assert.equal(
|
|
areSqlSemanticDiagnosticsEqual(
|
|
diagnostics,
|
|
diagnostics.map((item) => ({ ...item })),
|
|
),
|
|
true,
|
|
);
|
|
assert.equal(areSqlSemanticDiagnosticsEqual(diagnostics, [{ ...diagnostics[0], message: "Unknown column u.name" }]), false);
|
|
});
|
|
|
|
test("defers diagnostics while the cursor is in table completion context", () => {
|
|
assert.equal(shouldRunSqlSemanticDiagnostics("select * from ", "select * from ".length), false);
|
|
assert.equal(shouldRunSqlSemanticDiagnostics("select * from us", "select * from us".length), false);
|
|
assert.equal(shouldRunSqlSemanticDiagnostics("select u.", "select u.".length), false);
|
|
assert.equal(shouldRunSqlSemanticDiagnostics("select * from users where missing = 1", 42), true);
|
|
});
|
|
|
|
test("skips diagnostics for MongoDB connections", () => {
|
|
assert.equal(shouldRunSqlSemanticDiagnostics("db.my_collection.find({})", 0, { databaseType: "mongodb" }), false);
|
|
});
|
|
|
|
test("skips diagnostics for Elasticsearch connections", () => {
|
|
assert.equal(shouldRunSqlSemanticDiagnostics("db.my_collection.find({})", 0, { databaseType: "elasticsearch" }), false);
|
|
});
|
|
|
|
test("still runs diagnostics for SQL connections", () => {
|
|
assert.equal(shouldRunSqlSemanticDiagnostics("SELECT * FROM users WHERE id = 1", 42, { databaseType: "mysql" }), true);
|
|
});
|