From 20d2256709ddc0920147e748252b5fbf74bda9dc Mon Sep 17 00:00:00 2001
From: Lewis Sanchez <87730006+lewis-sanchez@users.noreply.github.com>
Date: Thu, 9 Jun 2022 16:07:12 -0700
Subject: [PATCH] Adds toggle button to switch between estimated and actual
execution plans (#19629)
* Creates toggle button to switch between estimate and actual query plans
* Renames ID for the toggleActualExecutionPlanModeAction class
* Renames button back to explain
* Creating actual execution plans resembles SSMS
* Adds CTRL/CMD + L shortcut to display estimated execution plans
* Alphabetically organizes telemetry actions
* Adds telemetry when the setting for actual execution plan toggle is used
* Resolves build errors
* Fixes broken unit tests.
* Code review changes
* Removes unnecessary null-coalescing operator.
* Creates placeholder icons for actual execution plans enabled
* Code review changes
* Shortens label names
* Telemetry moved to toggle button
* Telemetry review changes
* Clarifies misleading label
---
...disabled-actual-execution-plan-inverse.svg | 1 +
.../media/disabled-actual-execution-plan.svg | 1 +
.../enabled-actual-execution-plan-inverse.svg | 1 +
.../media/enabled-actual-execution-plan.svg | 1 +
.../base/browser/ui/taskbar/media/icons.css | 18 +++++
.../telemetry/common/telemetryKeys.ts | 17 ++---
.../common/editor/query/queryEditorInput.ts | 14 ++++
.../query/browser/keyboardQueryActions.ts | 21 ++++++
.../query/browser/query.contribution.ts | 12 +++-
.../contrib/query/browser/queryActions.ts | 67 +++++++++++++++++--
.../contrib/query/browser/queryEditor.ts | 9 ++-
.../query/test/browser/queryActions.test.ts | 14 ++++
12 files changed, 159 insertions(+), 17 deletions(-)
create mode 100644 src/sql/base/browser/ui/taskbar/media/disabled-actual-execution-plan-inverse.svg
create mode 100644 src/sql/base/browser/ui/taskbar/media/disabled-actual-execution-plan.svg
create mode 100644 src/sql/base/browser/ui/taskbar/media/enabled-actual-execution-plan-inverse.svg
create mode 100644 src/sql/base/browser/ui/taskbar/media/enabled-actual-execution-plan.svg
diff --git a/src/sql/base/browser/ui/taskbar/media/disabled-actual-execution-plan-inverse.svg b/src/sql/base/browser/ui/taskbar/media/disabled-actual-execution-plan-inverse.svg
new file mode 100644
index 0000000000..1c7c0724d8
--- /dev/null
+++ b/src/sql/base/browser/ui/taskbar/media/disabled-actual-execution-plan-inverse.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/src/sql/base/browser/ui/taskbar/media/disabled-actual-execution-plan.svg b/src/sql/base/browser/ui/taskbar/media/disabled-actual-execution-plan.svg
new file mode 100644
index 0000000000..d1c246bf81
--- /dev/null
+++ b/src/sql/base/browser/ui/taskbar/media/disabled-actual-execution-plan.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/src/sql/base/browser/ui/taskbar/media/enabled-actual-execution-plan-inverse.svg b/src/sql/base/browser/ui/taskbar/media/enabled-actual-execution-plan-inverse.svg
new file mode 100644
index 0000000000..1c7c0724d8
--- /dev/null
+++ b/src/sql/base/browser/ui/taskbar/media/enabled-actual-execution-plan-inverse.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/src/sql/base/browser/ui/taskbar/media/enabled-actual-execution-plan.svg b/src/sql/base/browser/ui/taskbar/media/enabled-actual-execution-plan.svg
new file mode 100644
index 0000000000..d1c246bf81
--- /dev/null
+++ b/src/sql/base/browser/ui/taskbar/media/enabled-actual-execution-plan.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/src/sql/base/browser/ui/taskbar/media/icons.css b/src/sql/base/browser/ui/taskbar/media/icons.css
index 9ebe9573ef..14e2bf69e0 100644
--- a/src/sql/base/browser/ui/taskbar/media/icons.css
+++ b/src/sql/base/browser/ui/taskbar/media/icons.css
@@ -65,6 +65,14 @@
background-image: url('query-plan.svg');
}
+.vs .codicon.disabledActualExecutionPlan {
+ background-image: url('disabled-actual-execution-plan.svg');
+}
+
+.vs .codicon.enabledActualExecutionPlan {
+ background-image: url('enabled-actual-execution-plan.svg');
+}
+
.vs-dark .codicon.estimatedQueryPlan,
.hc-black .codicon.estimatedQueryPlan,
.vs-dark .codicon.actualQueryPlan,
@@ -72,6 +80,16 @@
background-image: url('query-plan-inverse.svg');
}
+.vs-dark .codicon.codicon.disabledActualExecutionPlan,
+.hc-black .codicon.codicon.disabledActualExecutionPlan {
+ background-image: url('disabled-actual-execution-plan-inverse.svg');
+}
+
+.vs-dark .codicon.codicon.enabledActualExecutionPlan,
+.hc-black .codicon.codicon.enabledActualExecutionPlan {
+ background-image: url('enabled-actual-execution-plan-inverse.svg');
+}
+
.vs .codicon.createInsight {
background-image: url('create_insight.svg');
}
diff --git a/src/sql/platform/telemetry/common/telemetryKeys.ts b/src/sql/platform/telemetry/common/telemetryKeys.ts
index 7033e02acb..404afa50f6 100644
--- a/src/sql/platform/telemetry/common/telemetryKeys.ts
+++ b/src/sql/platform/telemetry/common/telemetryKeys.ts
@@ -55,12 +55,16 @@ export const enum TelemetryError {
}
export const enum TelemetryAction {
+ adsCommandExecuted = 'adsCommandExecuted',
AddExecutionPlan = 'AddExecutionPlan',
AddServerGroup = 'AddServerGroup',
- adsCommandExecuted = 'adsCommandExecuted',
+ BackupCreated = 'BackupCreated',
ConnectToServer = 'ConnectToServer',
CustomZoom = 'CustomZoom',
- BackupCreated = 'BackupCreated',
+ CancelQuery = 'CancelQuery',
+ ChartCreated = 'ChartCreated',
+ Click = 'Click',
+ CompareExecutionPlan = 'CompareExecutionPlan',
DashboardNavigated = 'DashboardNavigated',
DatabaseConnected = 'DatabaseConnected',
DatabaseDisconnected = 'DatabaseDisconnected',
@@ -71,10 +75,6 @@ export const enum TelemetryAction {
DeleteAgentProxy = 'DeleteAgentProxy',
DeleteConnection = 'DeleteConnection',
DeleteServerGroup = 'DeleteServerGroup',
- CancelQuery = 'CancelQuery',
- ChartCreated = 'ChartCreated',
- Click = 'Click',
- CompareExecutionPlan = 'CompareExecutionPlan',
FindNode = 'FindNode',
FirewallRuleRequested = 'FirewallRuleCreated',
GenerateScript = 'GenerateScript',
@@ -97,13 +97,14 @@ export const enum TelemetryAction {
RunQuery = 'RunQuery',
RunQueryStatement = 'RunQueryStatement',
RunQueryString = 'RunQueryString',
+ SearchCompleted = 'SearchCompleted',
+ SearchStarted = 'SearchStarted',
ShowChart = 'ShowChart',
StopAgentJob = 'StopAgentJob',
+ ToggleActualExecutionPlan = 'ToggleActualExecutionPlan',
ViewExecutionPlanComparisonProperties = 'ViewExecutionPlanComparisonProperties',
ViewTopOperations = 'ViewTopOperations',
WizardPagesNavigation = 'WizardPagesNavigation',
- SearchStarted = 'SearchStarted',
- SearchCompleted = 'SearchCompleted',
ZoomIn = 'ZoomIn',
ZoomOut = 'ZoomOut',
ZoomToFit = 'ZoomToFIt'
diff --git a/src/sql/workbench/common/editor/query/queryEditorInput.ts b/src/sql/workbench/common/editor/query/queryEditorInput.ts
index 496ef9d0fd..faffa79868 100644
--- a/src/sql/workbench/common/editor/query/queryEditorInput.ts
+++ b/src/sql/workbench/common/editor/query/queryEditorInput.ts
@@ -41,6 +41,7 @@ export interface IQueryEditorStateChange {
executingChange?: boolean;
connectingChange?: boolean;
sqlCmdModeChanged?: boolean;
+ actualExecutionPlanModeChanged?: boolean;
}
export class QueryEditorState extends Disposable {
@@ -49,6 +50,7 @@ export class QueryEditorState extends Disposable {
private _resultsVisible = false;
private _executing = false;
private _connecting = false;
+ private _isActualExecutionPlanMode = false;
private _onChange = this._register(new Emitter());
public onChange = this._onChange.event;
@@ -108,12 +110,24 @@ export class QueryEditorState extends Disposable {
return this._isSqlCmdMode;
}
+ public set isActualExecutionPlanMode(val: boolean) {
+ if (val !== this._isActualExecutionPlanMode) {
+ this._isActualExecutionPlanMode = val;
+ this._onChange.fire({ actualExecutionPlanModeChanged: true });
+ }
+ }
+
+ public get isActualExecutionPlanMode() {
+ return this._isActualExecutionPlanMode;
+ }
+
public setState(newState: QueryEditorState): void {
this.connected = newState.connected;
this.connecting = newState.connecting;
this.resultsVisible = newState.resultsVisible;
this.executing = newState.executing;
this.isSqlCmdMode = newState.isSqlCmdMode;
+ this.isActualExecutionPlanMode = newState.isActualExecutionPlanMode;
}
}
diff --git a/src/sql/workbench/contrib/query/browser/keyboardQueryActions.ts b/src/sql/workbench/contrib/query/browser/keyboardQueryActions.ts
index 0ee40e0a26..62a7391952 100644
--- a/src/sql/workbench/contrib/query/browser/keyboardQueryActions.ts
+++ b/src/sql/workbench/contrib/query/browser/keyboardQueryActions.ts
@@ -206,6 +206,27 @@ export class CopyQueryWithResultsKeyboardAction extends Action {
}
}
+export class EstimatedExecutionPlanKeyboardAction extends Action {
+ public static ID = 'estimatedExecutionPlanKeyboardAction';
+ public static LABEL = nls.localize('estimatedExecutionPlanKeyboardAction', "Display Estimated Execution Plan");
+
+ constructor(
+ id: string,
+ label: string,
+ @IEditorService private _editorService: IEditorService
+ ) {
+ super(id, label);
+ this.enabled = true;
+ }
+
+ public override async run(): Promise {
+ const editor = this._editorService.activeEditorPane;
+ if (editor instanceof QueryEditor) {
+ editor.input.runQuery(editor.getSelection(), { displayEstimatedQueryPlan: true });
+ }
+ }
+}
+
export class RunCurrentQueryWithActualPlanKeyboardAction extends Action {
public static ID = 'runCurrentQueryWithActualPlanKeyboardAction';
public static LABEL = nls.localize('runCurrentQueryWithActualPlanKeyboardAction', "Run Current Query with Actual Plan");
diff --git a/src/sql/workbench/contrib/query/browser/query.contribution.ts b/src/sql/workbench/contrib/query/browser/query.contribution.ts
index e55ddd3716..65631ee974 100644
--- a/src/sql/workbench/contrib/query/browser/query.contribution.ts
+++ b/src/sql/workbench/contrib/query/browser/query.contribution.ts
@@ -19,7 +19,7 @@ import { QueryResultsInput } from 'sql/workbench/common/editor/query/queryResult
import * as queryContext from 'sql/workbench/contrib/query/common/queryContext';
import {
RunQueryKeyboardAction, RunCurrentQueryKeyboardAction, CancelQueryKeyboardAction, RefreshIntellisenseKeyboardAction, ToggleQueryResultsKeyboardAction,
- RunQueryShortcutAction, RunCurrentQueryWithActualPlanKeyboardAction, CopyQueryWithResultsKeyboardAction, FocusOnCurrentQueryKeyboardAction, ParseSyntaxAction, ToggleFocusBetweenQueryEditorAndResultsAction
+ RunQueryShortcutAction, RunCurrentQueryWithActualPlanKeyboardAction, CopyQueryWithResultsKeyboardAction, FocusOnCurrentQueryKeyboardAction, ParseSyntaxAction, ToggleFocusBetweenQueryEditorAndResultsAction, EstimatedExecutionPlanKeyboardAction
} from 'sql/workbench/contrib/query/browser/keyboardQueryActions';
import * as gridActions from 'sql/workbench/contrib/editData/browser/gridActions';
import * as gridCommands from 'sql/workbench/contrib/editData/browser/gridCommands';
@@ -135,6 +135,16 @@ actionRegistry.registerWorkbenchAction(
RunCurrentQueryKeyboardAction.LABEL
);
+actionRegistry.registerWorkbenchAction(
+ SyncActionDescriptor.create(
+ EstimatedExecutionPlanKeyboardAction,
+ EstimatedExecutionPlanKeyboardAction.ID,
+ EstimatedExecutionPlanKeyboardAction.LABEL,
+ { primary: KeyMod.CtrlCmd | KeyCode.KEY_L }
+ ),
+ EstimatedExecutionPlanKeyboardAction.LABEL
+);
+
actionRegistry.registerWorkbenchAction(
SyncActionDescriptor.create(
RunCurrentQueryWithActualPlanKeyboardAction,
diff --git a/src/sql/workbench/contrib/query/browser/queryActions.ts b/src/sql/workbench/contrib/query/browser/queryActions.ts
index b718e3f519..9dfe4a3757 100644
--- a/src/sql/workbench/contrib/query/browser/queryActions.ts
+++ b/src/sql/workbench/contrib/query/browser/queryActions.ts
@@ -5,6 +5,7 @@
import 'vs/css!./media/queryActions';
import * as nls from 'vs/nls';
+import * as TelemetryKeys from 'sql/platform/telemetry/common/telemetryKeys';
import { Action, IAction, IActionRunner } from 'vs/base/common/actions';
import { IDisposable, Disposable } from 'vs/base/common/lifecycle';
import { IContextViewService } from 'vs/platform/contextview/browser/contextView';
@@ -46,6 +47,7 @@ import { getErrorMessage, onUnexpectedError } from 'vs/base/common/errors';
import { IActionViewItem } from 'vs/base/browser/ui/actionbar/actionbar';
import { gen3Version, sqlDataWarehouse } from 'sql/platform/connection/common/constants';
import { Dropdown } from 'sql/base/browser/ui/editableDropdown/browser/dropdown';
+import { IAdsTelemetryService } from 'sql/platform/telemetry/common/telemetry';
/**
* Action class that query-based Actions will extend. This base class automatically handles activating and
@@ -242,9 +244,15 @@ export class RunQueryAction extends QueryTaskbarAction {
if (runCurrentStatement && selection && this.isCursorPosition(selection)) {
editor.input.runQueryStatement(selection);
} else {
- // get the selection again this time with trimming
- selection = editor.getSelection();
- editor.input.runQuery(selection);
+ if (editor.input.state.isActualExecutionPlanMode) {
+ selection = editor.getSelection();
+ editor.input.runQuery(selection, { displayActualQueryPlan: true });
+ }
+ else {
+ // get the selection again this time with trimming
+ selection = editor.getSelection();
+ editor.input.runQuery(selection);
+ }
}
return true;
}
@@ -300,7 +308,7 @@ export class EstimatedQueryPlanAction extends QueryTaskbarAction {
@IConnectionManagementService connectionManagementService: IConnectionManagementService
) {
super(connectionManagementService, editor, EstimatedQueryPlanAction.ID, EstimatedQueryPlanAction.EnabledClass);
- this.label = nls.localize('estimatedQueryPlan', "Explain");
+ this.label = nls.localize('estimatedQueryPlan', "Estimated Plan");
}
public override async run(): Promise {
@@ -323,13 +331,57 @@ export class EstimatedQueryPlanAction extends QueryTaskbarAction {
}
if (this.isConnected(editor)) {
- editor.input.runQuery(editor.getSelection(), {
- displayEstimatedQueryPlan: true
- });
+ editor.input.runQuery(editor.getSelection(), { displayEstimatedQueryPlan: true });
}
}
}
+/**
+ * Action class that toggles the actual execution plan mode for the editor
+ */
+export class ToggleActualExecutionPlanModeAction extends QueryTaskbarAction {
+ public static EnabledClass = 'enabledActualExecutionPlan';
+ public static ID = 'toggleActualExecutionPlanModeAction';
+
+ private _enableActualPlanLabel = nls.localize('enableActualPlanLabel', "Include Actual Plan");
+ private _disableActualPlanLabel = nls.localize('disableActualPlanLabel', "Exclude Actual Plan");
+
+ constructor(
+ editor: QueryEditor,
+ private _isActualPlanMode: boolean,
+ @IQueryManagementService protected readonly queryManagementService: IQueryManagementService,
+ @IConfigurationService protected readonly configurationService: IConfigurationService,
+ @IConnectionManagementService connectionManagementService: IConnectionManagementService,
+ @IAdsTelemetryService private readonly telemetryService: IAdsTelemetryService
+ ) {
+ super(connectionManagementService, editor, ToggleActualExecutionPlanModeAction.ID, ToggleActualExecutionPlanModeAction.EnabledClass);
+ this.updateLabel();
+ }
+
+ public get isActualExecutionPlanMode(): boolean {
+ return this._isActualPlanMode;
+ }
+
+ public set isActualExecutionPlanMode(value: boolean) {
+ this._isActualPlanMode = value;
+ this.updateLabel();
+ }
+
+ private updateLabel(): void {
+ // show option to disable actual plan mode if already enabled
+ this.label = this.isActualExecutionPlanMode ? this._disableActualPlanLabel : this._enableActualPlanLabel;
+ }
+
+ public override async run(): Promise {
+ const toActualPlanState = !this.isActualExecutionPlanMode;
+ this.editor.input.state.isActualExecutionPlanMode = toActualPlanState;
+
+ this.telemetryService.createActionEvent(TelemetryKeys.TelemetryView.ExecutionPlan, TelemetryKeys.TelemetryAction.Click, 'ToggleActualExecutionPlan')
+ .withAdditionalProperties({ actualExecutionPlanMode: this.isActualExecutionPlanMode })
+ .send();
+ }
+}
+
export class ActualQueryPlanAction extends QueryTaskbarAction {
public static EnabledClass = 'actualQueryPlan';
public static ID = 'actualQueryPlanAction';
@@ -522,6 +574,7 @@ export class ToggleSqlCmdModeAction extends QueryTaskbarAction {
private _enablesqlcmdLabel = nls.localize('enablesqlcmdLabel', "Enable SQLCMD");
private _disablesqlcmdLabel = nls.localize('disablesqlcmdLabel', "Disable SQLCMD");
+
constructor(
editor: QueryEditor,
private _isSqlCmdMode: boolean,
diff --git a/src/sql/workbench/contrib/query/browser/queryEditor.ts b/src/sql/workbench/contrib/query/browser/queryEditor.ts
index 2a65df6a0e..84770398cc 100644
--- a/src/sql/workbench/contrib/query/browser/queryEditor.ts
+++ b/src/sql/workbench/contrib/query/browser/queryEditor.ts
@@ -96,6 +96,7 @@ export class QueryEditor extends EditorPane {
private _actualQueryPlanAction: actions.ActualQueryPlanAction;
private _listDatabasesActionItem: actions.ListDatabasesActionItem;
private _toggleSqlcmdMode: actions.ToggleSqlCmdModeAction;
+ private _toggleActualExecutionPlanMode: actions.ToggleActualExecutionPlanModeAction;
private _exportAsNotebookAction: actions.ExportAsNotebookAction;
constructor(
@@ -205,6 +206,7 @@ export class QueryEditor extends EditorPane {
this._estimatedQueryPlanAction = this.instantiationService.createInstance(actions.EstimatedQueryPlanAction, this);
this._actualQueryPlanAction = this.instantiationService.createInstance(actions.ActualQueryPlanAction, this);
this._toggleSqlcmdMode = this.instantiationService.createInstance(actions.ToggleSqlCmdModeAction, this, false);
+ this._toggleActualExecutionPlanMode = this.instantiationService.createInstance(actions.ToggleActualExecutionPlanModeAction, this, false);
this._exportAsNotebookAction = this.instantiationService.createInstance(actions.ExportAsNotebookAction, this);
this.setTaskbarContent();
this._register(this.configurationService.onDidChangeConfiguration(e => {
@@ -241,6 +243,10 @@ export class QueryEditor extends EditorPane {
this._toggleSqlcmdMode.isSqlCmdMode = this.input.state.isSqlCmdMode;
}
+ if (stateChangeEvent.actualExecutionPlanModeChanged) {
+ this._toggleActualExecutionPlanMode.isActualExecutionPlanMode = this.input.state.isActualExecutionPlanMode;
+ }
+
if (stateChangeEvent.connectingChange) {
this._runQueryAction.enabled = !this.input.state.connecting;
this._estimatedQueryPlanAction.enabled = !this.input.state.connecting;
@@ -322,6 +328,7 @@ export class QueryEditor extends EditorPane {
content.push(
{ element: Taskbar.createTaskbarSeparator() },
{ action: this._estimatedQueryPlanAction },
+ { action: this._toggleActualExecutionPlanMode },
{ action: this._toggleSqlcmdMode },
{ action: this._exportAsNotebookAction }
);
@@ -367,7 +374,7 @@ export class QueryEditor extends EditorPane {
this.inputDisposables.clear();
this.inputDisposables.add(this.input.state.onChange(c => this.updateState(c)));
- this.updateState({ connectingChange: true, connectedChange: true, executingChange: true, resultsVisibleChange: true, sqlCmdModeChanged: true });
+ this.updateState({ connectingChange: true, connectedChange: true, executingChange: true, resultsVisibleChange: true, sqlCmdModeChanged: true, actualExecutionPlanModeChanged: true });
const editorViewState = this.loadTextEditorViewState(this.input.resource);
diff --git a/src/sql/workbench/contrib/query/test/browser/queryActions.test.ts b/src/sql/workbench/contrib/query/test/browser/queryActions.test.ts
index 5c1cddf354..31778eb65b 100644
--- a/src/sql/workbench/contrib/query/test/browser/queryActions.test.ts
+++ b/src/sql/workbench/contrib/query/test/browser/queryActions.test.ts
@@ -34,6 +34,7 @@ import { IUntitledTextEditorService } from 'vs/workbench/services/untitled/commo
import { TestStorageService } from 'vs/workbench/test/common/workbenchTestServices';
import { IRange } from 'vs/editor/common/core/range';
import { ServerInfo } from 'azdata';
+import { QueryEditorState } from 'sql/workbench/common/editor/query/queryEditorInput';
suite('SQL QueryAction Tests', () => {
@@ -41,6 +42,7 @@ suite('SQL QueryAction Tests', () => {
let editor: TypeMoq.Mock;
let calledRunQueryOnInput: boolean = undefined;
let testQueryInput: TypeMoq.Mock;
+ let testQueryInputState: TypeMoq.Mock;
let configurationService: TypeMoq.Mock;
let queryModelService: TypeMoq.Mock;
let connectionManagementService: TypeMoq.Mock;
@@ -76,9 +78,13 @@ suite('SQL QueryAction Tests', () => {
const service = accessor.untitledTextEditorService;
let fileInput = workbenchinstantiationService.createInstance(UntitledTextEditorInput, service.create({ associatedResource: URI.parse('file://testUri') }));
// Setup a reusable mock QueryInput
+ testQueryInputState = TypeMoq.Mock.ofType(QueryEditorState, TypeMoq.MockBehavior.Strict);
+ testQueryInputState.setup(x => x.isActualExecutionPlanMode).returns(() => false);
+
testQueryInput = TypeMoq.Mock.ofType(UntitledQueryEditorInput, TypeMoq.MockBehavior.Strict, undefined, fileInput, undefined, connectionManagementService.object, queryModelService.object, configurationService.object);
testQueryInput.setup(x => x.uri).returns(() => testUri);
testQueryInput.setup(x => x.runQuery(undefined)).callback(() => { calledRunQueryOnInput = true; });
+ testQueryInput.setup(x => x.state).returns(() => testQueryInputState.object);
});
test('setClass sets child CSS class correctly', () => {
@@ -184,11 +190,15 @@ suite('SQL QueryAction Tests', () => {
let fileInput = workbenchinstantiationService.createInstance(UntitledTextEditorInput, service.create({ associatedResource: URI.parse('file://testUri') }));
// ... Mock "isSelectionEmpty" in QueryEditor
+ let queryInputState = TypeMoq.Mock.ofType(QueryEditorState, TypeMoq.MockBehavior.Loose);
+ queryInputState.setup(x => x.isActualExecutionPlanMode).returns(() => false);
+
let queryInput = TypeMoq.Mock.ofType(UntitledQueryEditorInput, TypeMoq.MockBehavior.Strict, undefined, fileInput, undefined, connectionManagementService.object, queryModelService.object, configurationService.object);
queryInput.setup(x => x.uri).returns(() => testUri);
queryInput.setup(x => x.runQuery(undefined)).callback(() => {
countCalledRunQuery++;
});
+ queryInput.setup(x => x.state).returns(() => queryInputState.object);
const contextkeyservice = new MockContextKeyService();
// Setup a reusable mock QueryEditor
@@ -234,12 +244,16 @@ suite('SQL QueryAction Tests', () => {
const service = accessor.untitledTextEditorService;
let fileInput = workbenchinstantiationService.createInstance(UntitledTextEditorInput, service.create({ associatedResource: URI.parse('file://testUri') }));
+ let queryInputState = TypeMoq.Mock.ofType(QueryEditorState, TypeMoq.MockBehavior.Loose);
+ queryInputState.setup(x => x.isActualExecutionPlanMode).returns(() => false);
+
let queryInput = TypeMoq.Mock.ofType(UntitledQueryEditorInput, TypeMoq.MockBehavior.Loose, undefined, fileInput, undefined, connectionManagementService.object, queryModelService.object, configurationService.object);
queryInput.setup(x => x.uri).returns(() => testUri);
queryInput.setup(x => x.runQuery(TypeMoq.It.isAny())).callback((selection: IRange) => {
runQuerySelection = selection;
countCalledRunQuery++;
});
+ queryInput.setup(x => x.state).returns(() => queryInputState.object);
queryInput.setup(x => x.runQuery(undefined)).callback((selection: IRange) => {
runQuerySelection = selection;
countCalledRunQuery++;