fix(mongodb): honor current command execution mode (#2702)
This commit is contained in:
parent
18e5df6f5e
commit
d7e2eac307
|
|
@ -1,4 +1,5 @@
|
|||
import * as api from "@/lib/backend/api";
|
||||
import { mongoCommandRangeAtCursor } from "@/lib/sql/sqlStatementRanges";
|
||||
import type { DatabaseType } from "@/types/database";
|
||||
|
||||
export type ExecuteMode = "all" | "current";
|
||||
|
|
@ -52,10 +53,12 @@ export async function resolveExecutableSqlWithBackend(fullSql: string, selectedS
|
|||
const trimmedSelection = selectedSql.trim();
|
||||
if (trimmedSelection) return trimmedSelection;
|
||||
|
||||
// MongoDB uses dedicated per-command gutter actions for "current command";
|
||||
// the main editor execute action keeps its long-standing "run all text"
|
||||
// behavior when nothing is selected.
|
||||
if (options?.databaseType === "mongodb") return fullSql;
|
||||
if (options?.databaseType === "mongodb") {
|
||||
if (options.mode === "current" && options.cursorPos !== undefined) {
|
||||
return mongoCommandRangeAtCursor(fullSql, options.cursorPos)?.sql ?? fullSql;
|
||||
}
|
||||
return fullSql;
|
||||
}
|
||||
|
||||
if (options?.mode === "current" && options.cursorPos !== undefined) {
|
||||
return await api.findStatementAtCursor(fullSql, options.cursorPos, options.databaseType);
|
||||
|
|
|
|||
|
|
@ -409,6 +409,26 @@ export function statementRangeAtCursor(sql: string, cursorPos: number, databaseT
|
|||
return null;
|
||||
}
|
||||
|
||||
export function mongoCommandRangeAtCursor(sql: string, cursorPos: number): SqlTextRange | null {
|
||||
const pos = clampCursor(sql, cursorPos);
|
||||
if (isCursorOnBlankLine(sql, pos)) return null;
|
||||
|
||||
const commands = splitMongoCommandRanges(sql);
|
||||
for (let index = 0; index < commands.length; index += 1) {
|
||||
const command = commands[index];
|
||||
const range = { from: command.from, to: command.to, sql: command.text };
|
||||
|
||||
if (pos >= command.from && pos <= command.to) return range;
|
||||
|
||||
const next = commands[index + 1];
|
||||
if (pos > command.to && (!next || pos < next.from) && isCursorInSameLineDelimiterGap(sql, command.to, pos)) return range;
|
||||
|
||||
if (pos < command.from && sql.slice(pos, command.from).trim() === "" && isCursorOnStatementLine(sql, pos, command)) return range;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
function isCursorInSameLineDelimiterGap(sql: string, previousStatementEnd: number, cursorPos: number): boolean {
|
||||
if (cursorPos <= previousStatementEnd) return false;
|
||||
const between = sql.slice(previousStatementEnd, cursorPos);
|
||||
|
|
@ -1450,7 +1470,7 @@ function isCursorOnBlankLine(sql: string, pos: number): boolean {
|
|||
return sql.slice(lineStart, lineEnd).trim() === "";
|
||||
}
|
||||
|
||||
function isCursorOnStatementLine(sql: string, pos: number, statement: RawStatement): boolean {
|
||||
function isCursorOnStatementLine(sql: string, pos: number, statement: Pick<RawStatement, "from">): boolean {
|
||||
const lineStart = sql.lastIndexOf("\n", pos - 1) + 1;
|
||||
let lineEnd = sql.indexOf("\n", pos);
|
||||
if (lineEnd === -1) lineEnd = sql.length;
|
||||
|
|
|
|||
|
|
@ -13,20 +13,45 @@ beforeEach(() => {
|
|||
apiMock.findStatementAtCursor.mockReset();
|
||||
});
|
||||
|
||||
test("mongodb backend resolution keeps the full text when nothing is selected", async () => {
|
||||
test("mongodb backend resolution uses the current command when configured", async () => {
|
||||
apiMock.findStatementAtCursor.mockResolvedValue("db.users.insertOne({ name: 'ignored' })");
|
||||
|
||||
const fullSql = "db.users.insertOne({ name: 'Ada' });\ndb.users.insertOne({ name: 'Grace' });";
|
||||
const fullSql = 'db.users.find({ name: "Ada" });\ndb.users.find({ name: "Grace" });\ndb.users.find({ name: "Linus" });';
|
||||
const resolved = await resolveExecutableSqlWithBackend(fullSql, "", {
|
||||
mode: "current",
|
||||
cursorPos: fullSql.indexOf("Grace"),
|
||||
databaseType: "mongodb",
|
||||
});
|
||||
|
||||
assert.equal(resolved, 'db.users.find({ name: "Grace" })');
|
||||
assert.equal(apiMock.findStatementAtCursor.mock.calls.length, 0);
|
||||
});
|
||||
|
||||
test("mongodb backend resolution keeps the full text in all mode", async () => {
|
||||
const fullSql = 'db.users.find({ name: "Ada" });\ndb.users.find({ name: "Grace" });';
|
||||
const resolved = await resolveExecutableSqlWithBackend(fullSql, "", {
|
||||
mode: "all",
|
||||
cursorPos: fullSql.indexOf("Grace"),
|
||||
databaseType: "mongodb",
|
||||
});
|
||||
|
||||
assert.equal(resolved, fullSql);
|
||||
assert.equal(apiMock.findStatementAtCursor.mock.calls.length, 0);
|
||||
});
|
||||
|
||||
test("mongodb backend resolution prefers the manual selection", async () => {
|
||||
const fullSql = 'db.users.find({ name: "Ada" });\ndb.users.find({ name: "Grace" });';
|
||||
const selectedSql = 'db.users.find({ name: "Ada" })';
|
||||
const resolved = await resolveExecutableSqlWithBackend(fullSql, selectedSql, {
|
||||
mode: "current",
|
||||
cursorPos: fullSql.indexOf("Grace"),
|
||||
databaseType: "mongodb",
|
||||
});
|
||||
|
||||
assert.equal(resolved, selectedSql);
|
||||
assert.equal(apiMock.findStatementAtCursor.mock.calls.length, 0);
|
||||
});
|
||||
|
||||
test("non-mongodb backend resolution still asks the backend for the current statement", async () => {
|
||||
apiMock.findStatementAtCursor.mockResolvedValue("SELECT 2");
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue