Added back fix for duplicate edits (#23003)

This commit is contained in:
Alex Ma
2023-05-11 17:56:42 -07:00
committed by GitHub
parent 01bcdf9c01
commit 142a3aaf7c
7 changed files with 259 additions and 71 deletions

View File

@@ -533,12 +533,34 @@ export class ConnectionManagementService extends Disposable implements IConnecti
return this.connectWithOptions(connection, uri, options, callbacks);
}
private duplicateEditErrorMessage(connection: interfaces.IConnectionProfile): void {
let groupNameBase = ConnectionProfile.displayIdSeparator + 'groupName' + ConnectionProfile.displayNameValueSeparator;
let connectionOptionsKey = ConnectionProfile.getDisplayOptionsKey(connection.getOptionsKey());
// Must get connection group name here as it may not always be initialized.
let connectionGroupName = (connection.groupFullName !== undefined && connection.groupFullName !== '' && connection.groupFullName !== '/') ?
(groupNameBase + connection.groupFullName) : (groupNameBase + '<default>');
this._logService.error(`Profile edit for '${connection.id}' matches an existing profile with data: '${connectionOptionsKey}'`);
throw new Error(nls.localize('connection.duplicateEditErrorMessage', 'Cannot save profile, the selected connection matches an existing profile with the same server info in the same group: \n\n {0}{1}', connectionOptionsKey, connectionGroupName));
}
private async connectWithOptions(connection: interfaces.IConnectionProfile, uri: string, options?: IConnectionCompletionOptions, callbacks?: IConnectionCallbacks): Promise<IConnectionResult> {
connection.options['groupId'] = connection.groupId;
connection.options['databaseDisplayName'] = connection.databaseName;
let isEdit = options?.params?.isEditConnection ?? false;
let matcher: interfaces.ProfileMatcher;
if (isEdit) {
matcher = (a: interfaces.IConnectionProfile, b: interfaces.IConnectionProfile) => a.id === options.params.oldProfileId;
//Check to make sure the edits are not identical to another connection.
let result = await this._connectionStore.isDuplicateEdit(connection, matcher);
if (result) {
this.duplicateEditErrorMessage(connection);
}
}
if (!uri) {
uri = Utils.generateUri(connection);
}
@@ -586,10 +608,6 @@ export class ConnectionManagementService extends Disposable implements IConnecti
callbacks.onConnectSuccess(options.params, connectionResult.connectionProfile);
}
if (options.saveTheConnection || isEdit) {
let matcher: interfaces.ProfileMatcher;
if (isEdit) {
matcher = (a: interfaces.IConnectionProfile, b: interfaces.IConnectionProfile) => a.id === options.params.oldProfileId;
}
await this.saveToSettings(uri, connection, matcher).then(value => {
this._onAddConnectionProfile.fire(connection);

View File

@@ -1013,6 +1013,11 @@ suite('SQL ConnectionManagementService tests', () => {
showFirewallRuleOnError: true
};
connectionStore.setup(x => x.isDuplicateEdit(TypeMoq.It.isAny(), TypeMoq.It.isAny())).returns(() => {
//In a real scenario this would be false as it would match the first instance and not find a duplicate.
return Promise.resolve(false);
});
await connect(uri1, options, true, profile);
let newProfile = Object.assign({}, connectionProfile);
newProfile.connectionName = newname;
@@ -1047,6 +1052,9 @@ suite('SQL ConnectionManagementService tests', () => {
showFirewallRuleOnError: true
};
// In an actual edit situation, the profile options would be different for different URIs, as a placeholder, we check the test uris instead here.
connectionStore.setup(x => x.isDuplicateEdit(TypeMoq.It.isAny(), TypeMoq.It.isAny())).returns(() => Promise.resolve(uri1 === uri2));
await connect(uri1, options, true, profile);
options.params.isEditConnection = true;
await connect(uri2, options, true, profile);
@@ -1055,6 +1063,47 @@ suite('SQL ConnectionManagementService tests', () => {
assert.strictEqual(uri1info.connectionProfile.id, uri2info.connectionProfile.id);
});
test('Edit Connection - Connecting with an already connected profile via edit should throw an error', async () => {
let uri1 = 'test_uri1';
let profile = Object.assign({}, connectionProfile);
profile.id = '0451';
let options: IConnectionCompletionOptions = {
params: {
connectionType: ConnectionType.editor,
input: {
onConnectSuccess: undefined,
onConnectReject: undefined,
onConnectStart: undefined,
onDisconnect: undefined,
onConnectCanceled: undefined,
uri: uri1
},
queryRange: undefined,
runQueryOnCompletion: RunQueryOnConnectionMode.none,
isEditConnection: true
},
saveTheConnection: true,
showDashboard: false,
showConnectionDialogOnError: true,
showFirewallRuleOnError: true
};
let originalProfileKey = '';
connectionStore.setup(x => x.isDuplicateEdit(TypeMoq.It.isAny(), TypeMoq.It.isAny())).returns((inputProfile, matcher) => {
let newProfile = ConnectionProfile.fromIConnectionProfile(new TestCapabilitiesService(), inputProfile);
let result = newProfile.getOptionsKey() === originalProfileKey;
return Promise.resolve(result)
});
await connect(uri1, options, true, profile);
let originalProfile = ConnectionProfile.fromIConnectionProfile(new TestCapabilitiesService(), connectionProfile);
originalProfileKey = originalProfile.getOptionsKey();
let newProfile = Object.assign({}, connectionProfile);
options.params.isEditConnection = true;
await assert.rejects(async () => await connect(uri1, options, true, newProfile));
});
test('failed firewall rule should open the firewall rule dialog', async () => {
handleFirewallRuleResult.canHandleFirewallRule = true;