Skip to content
Open
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
*--------------------------------------------------------------------------------------------*/

import * as vscode from "vscode";
import { SqlMoveToSchema as loc } from "../constants/locConstants";
import { SqlMoveToSchema as loc, msgYes } from "../constants/locConstants";
Comment thread
ssreerama marked this conversation as resolved.
import { cmdMoveToSchema } from "../constants/constants";
import SqlToolsServerClient from "./serviceclient";
import {
Expand Down Expand Up @@ -187,6 +187,18 @@ export class SqlMoveToSchemaProvider implements vscode.CodeActionProvider {
return;
}

// Warn if an object with the same name already exists in the target schema.
if (response.warningMessage) {
Comment thread
ssreerama marked this conversation as resolved.
Outdated
const choice = await vscode.window.showWarningMessage(
response.warningMessage,
{ modal: true },
Comment thread
ssreerama marked this conversation as resolved.
msgYes,
);
Comment thread
ssreerama marked this conversation as resolved.
if (choice !== msgYes) {
return; // user declined — do nothing silently
}
Comment thread
ssreerama marked this conversation as resolved.
}
Comment thread
ssreerama marked this conversation as resolved.

const changes = response.changes as Record<string, SqlSymbolRenameTextEdit[]>;
const label = loc.previewLabel(targetSchema);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import {
SqlSymbolRenameRequest,
SqlSymbolRenameTextEdit,
} from "../models/contracts/languageService";
import { SqlSymbolRename as loc } from "../constants/locConstants";
import { SqlSymbolRename as loc, msgYes } from "../constants/locConstants";
Comment thread
ssreerama marked this conversation as resolved.

/** Escapes a string for safe use inside an XML attribute value (e.g. an Include path). */
function escapeXmlAttribute(value: string): string {
Expand Down Expand Up @@ -152,6 +152,18 @@ export class SqlSymbolRenameProvider implements vscode.RenameProvider {
throw new Error(loc.renameOnlyInProjectFiles);
}

// Name collision — ask the user before proceeding.
Comment thread
ssreerama marked this conversation as resolved.
Outdated
if (response.warningMessage) {
Comment thread
ssreerama marked this conversation as resolved.
Outdated
const choice = await vscode.window.showWarningMessage(
response.warningMessage,
{ modal: true },
msgYes,
);
Comment thread
ssreerama marked this conversation as resolved.
if (choice !== msgYes) {
return new vscode.WorkspaceEdit(); // user declined — apply nothing silently
}
Comment thread
ssreerama marked this conversation as resolved.
}
Comment thread
ssreerama marked this conversation as resolved.

const workspaceEdit = new vscode.WorkspaceEdit();

if (!response.changes || Object.keys(response.changes).length === 0) {
Expand Down
2 changes: 2 additions & 0 deletions extensions/mssql/src/models/contracts/languageService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,7 @@ export interface SqlSymbolRenameResponse {
*/
refactorLogContent: string | null;
newName: string;
warningMessage?: string | null;
}
Comment thread
ssreerama marked this conversation as resolved.

export namespace SqlSymbolRenameRequest {
Expand Down Expand Up @@ -204,6 +205,7 @@ export interface SqlMoveToSchemaResponse {
*/
refactorLogContent: string | null;
targetSchema: string;
warningMessage?: string | null;
}
Comment thread
ssreerama marked this conversation as resolved.

export namespace SqlMoveToSchemaRequest {
Expand Down
130 changes: 130 additions & 0 deletions extensions/mssql/test/unit/sqlSymbolRenameProvider.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -349,6 +349,77 @@ suite("SqlSymbolRenameProvider Tests", () => {
}),
);
});

test("returns empty WorkspaceEdit when STS returns warningMessage and user cancels", async () => {
const projUri = vscode.Uri.file(defaultProjFile);
findFilesStub.resolves([projUri]);
const fileUri = vscode.Uri.file(defaultSqlFile).toString();
sendRequestStub.withArgs(SqlSymbolRenameRequest.type).resolves({
changes: {
[fileUri]: [
{
range: {
start: { line: 0, character: 0 },
end: { line: 0, character: 7 },
},
newText: "Orders",
},
],
},
newName: "Orders",
warningMessage:
"A schema object with the name [Orders] already exists. Would you like to continue?",
});
sandbox.stub(vscode.window, "showWarningMessage").resolves(undefined); // user dismissed/cancelled

const doc = makeDocument(sandbox);
const edit = await provider.provideRenameEdits(
doc,
new vscode.Position(0, 0),
"Orders",
token,
);

expect(edit).to.be.instanceOf(vscode.WorkspaceEdit);
expect(edit!.entries()).to.have.length(0); // empty — no changes applied
});

test("applies edits when STS returns warningMessage and user confirms", async () => {
const projUri = vscode.Uri.file(defaultProjFile);
findFilesStub.resolves([projUri]);
const fileUri = vscode.Uri.file(defaultSqlFile).toString();
sendRequestStub.withArgs(SqlSymbolRenameRequest.type).resolves({
changes: {
[fileUri]: [
{
range: {
start: { line: 0, character: 0 },
end: { line: 0, character: 7 },
},
newText: "Orders",
},
],
},
newName: "Orders",
warningMessage:
"A schema object with the name [Orders] already exists. Would you like to continue?",
});
sandbox
.stub(vscode.window, "showWarningMessage")
.resolves("Yes" as vscode.MessageItem & string);

Comment thread
ssreerama marked this conversation as resolved.
Comment thread
ssreerama marked this conversation as resolved.
const doc = makeDocument(sandbox);
const edit = await provider.provideRenameEdits(
doc,
new vscode.Position(0, 0),
"Orders",
token,
);

expect(edit).to.be.instanceOf(vscode.WorkspaceEdit);
expect(edit!.entries()).to.have.length(1); // edits applied
expect(edit!.entries()[0][0].toString()).to.equal(fileUri);
});
});

// -------------------------------------------------------------------------
Expand Down Expand Up @@ -736,6 +807,65 @@ suite("SqlMoveToSchemaProvider Tests", () => {
moveLoc.applyEditFailed,
);
});

test("does not call applyEdit when warningMessage is returned and user dismisses", async () => {
const fileUri = vscode.Uri.file(defaultSqlFile).toString();
sendRequestStub
.withArgs(ListProjectSchemasRequest.type)
.resolves({ schemas: ["hr"] });
sendRequestStub.withArgs(SqlMoveToSchemaRequest.type).resolves({
changes: {
[fileUri]: [
{
range: {
start: { line: 0, character: 7 },
end: { line: 0, character: 14 },
},
newText: "[hr].[MyTable]",
},
],
},
warningMessage:
"A schema object with the name [hr].[MyTable] already exists. Would you like to continue?",
});
messageBoxes.showWarningMessage.resolves(undefined); // user dismissed

const doc = makeMoveDocument(sandbox, { lineText: "SELECT MyTable" });
await provider.runMoveToSchema(doc, new vscode.Position(0, 7));

expect(applyEditStub).to.not.have.been.called;
});

test("calls applyEdit when warningMessage is returned and user confirms Yes", async () => {
const fileUri = vscode.Uri.file(defaultSqlFile).toString();
sendRequestStub
.withArgs(ListProjectSchemasRequest.type)
.resolves({ schemas: ["hr"] });
sendRequestStub.withArgs(SqlMoveToSchemaRequest.type).resolves({
changes: {
[fileUri]: [
{
range: {
start: { line: 0, character: 7 },
end: { line: 0, character: 14 },
},
newText: "[hr].[MyTable]",
},
],
},
warningMessage:
"A schema object with the name [hr].[MyTable] already exists. Would you like to continue?",
});
messageBoxes.showWarningMessage.resolves("Yes" as vscode.MessageItem & string);
Comment thread
ssreerama marked this conversation as resolved.

Comment thread
ssreerama marked this conversation as resolved.
const doc = makeMoveDocument(sandbox, { lineText: "SELECT MyTable" });
await provider.runMoveToSchema(doc, new vscode.Position(0, 7));

expect(applyEditStub).to.have.been.calledWith(
sinon.match.instanceOf(vscode.WorkspaceEdit),
sinon.match({ isRefactoring: true }),
);
});
});
});
});
Loading