mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-01-20 17:22:51 -05:00
Query Runner Tests (#10252)
* rework some code and write an inital test * fix strict * add more to standard test * add to existing workflow test * fix tests * simplify the code * add more tests * remove bad import * fix compile * fix timestampiong
This commit is contained in:
@@ -3,15 +3,12 @@
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as azdata from 'azdata';
|
||||
|
||||
import { IQueryManagementService } from 'sql/workbench/services/query/common/queryManagement';
|
||||
import { IQueryManagementService, QueryCancelResult, ExecutionPlanOptions } from 'sql/workbench/services/query/common/queryManagement';
|
||||
import * as Utils from 'sql/platform/connection/common/utils';
|
||||
import { Deferred } from 'sql/base/common/promise';
|
||||
import { IQueryPlanInfo } from 'sql/workbench/services/query/common/queryModel';
|
||||
import { ResultSerializer, SaveFormat } from 'sql/workbench/services/query/common/resultSerializer';
|
||||
|
||||
import Severity from 'vs/base/common/severity';
|
||||
import * as nls from 'vs/nls';
|
||||
import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService';
|
||||
import * as types from 'vs/base/common/types';
|
||||
@@ -27,20 +24,8 @@ import { IGridDataProvider, getResultsString } from 'sql/workbench/services/quer
|
||||
import { getErrorMessage } from 'vs/base/common/errors';
|
||||
import { ILogService } from 'vs/platform/log/common/log';
|
||||
import { find } from 'vs/base/common/arrays';
|
||||
|
||||
export interface IEditSessionReadyEvent {
|
||||
ownerUri: string;
|
||||
success: boolean;
|
||||
message: string;
|
||||
}
|
||||
|
||||
export interface IQueryMessage {
|
||||
batchId?: number;
|
||||
isError: boolean;
|
||||
time?: string;
|
||||
message: string;
|
||||
selection?: azdata.ISelectionData;
|
||||
}
|
||||
import { IRange, Range } from 'vs/editor/common/core/range';
|
||||
import { BatchSummary, IQueryMessage, ResultSetSummary, QueryExecuteSubsetParams, CompleteBatchSummary, IResultMessage, ResultSetSubset, BatchStartSummary } from './query';
|
||||
|
||||
/*
|
||||
* Query Runner class which handles running a query, reports the results to the content manager,
|
||||
@@ -50,10 +35,10 @@ export default class QueryRunner extends Disposable {
|
||||
// MEMBER VARIABLES ////////////////////////////////////////////////////
|
||||
private _resultLineOffset?: number;
|
||||
private _resultColumnOffset?: number;
|
||||
private _totalElapsedMilliseconds: number = 0;
|
||||
private _isExecuting: boolean = false;
|
||||
protected _totalElapsedMilliseconds: number = 0;
|
||||
protected _isExecuting: boolean = false;
|
||||
private _hasCompleted: boolean = false;
|
||||
private _batchSets: azdata.BatchSummary[] = [];
|
||||
private _batchSets: BatchSummary[] = [];
|
||||
private _messages: IQueryMessage[] = [];
|
||||
private registered = false;
|
||||
|
||||
@@ -65,31 +50,28 @@ export default class QueryRunner extends Disposable {
|
||||
private _onMessage = this._register(new Emitter<IQueryMessage[]>());
|
||||
public get onMessage(): Event<IQueryMessage[]> { return this._onMessage.event; } // this is the only way typemoq can moq this... needs investigation @todo anthonydresser 5/2/2019
|
||||
|
||||
private _onResultSet = this._register(new Emitter<azdata.ResultSetSummary>());
|
||||
private readonly _onResultSet = this._register(new Emitter<ResultSetSummary>());
|
||||
public readonly onResultSet = this._onResultSet.event;
|
||||
|
||||
private _onResultSetUpdate = this._register(new Emitter<azdata.ResultSetSummary>());
|
||||
private readonly _onResultSetUpdate = this._register(new Emitter<ResultSetSummary>());
|
||||
public readonly onResultSetUpdate = this._onResultSetUpdate.event;
|
||||
|
||||
private _onQueryStart = this._register(new Emitter<void>());
|
||||
protected readonly _onQueryStart = this._register(new Emitter<void>());
|
||||
public readonly onQueryStart: Event<void> = this._onQueryStart.event;
|
||||
|
||||
private _onQueryEnd = this._register(new Emitter<string>());
|
||||
private readonly _onQueryEnd = this._register(new Emitter<string>());
|
||||
public get onQueryEnd(): Event<string> { return this._onQueryEnd.event; }
|
||||
|
||||
private _onBatchStart = this._register(new Emitter<azdata.BatchSummary>());
|
||||
public readonly onBatchStart: Event<azdata.BatchSummary> = this._onBatchStart.event;
|
||||
private readonly _onBatchStart = this._register(new Emitter<BatchStartSummary>());
|
||||
public readonly onBatchStart: Event<BatchStartSummary> = this._onBatchStart.event;
|
||||
|
||||
private _onBatchEnd = this._register(new Emitter<azdata.BatchSummary>());
|
||||
public readonly onBatchEnd: Event<azdata.BatchSummary> = this._onBatchEnd.event;
|
||||
private readonly _onBatchEnd = this._register(new Emitter<CompleteBatchSummary>());
|
||||
public readonly onBatchEnd: Event<CompleteBatchSummary> = this._onBatchEnd.event;
|
||||
|
||||
private _onEditSessionReady = this._register(new Emitter<IEditSessionReadyEvent>());
|
||||
public readonly onEditSessionReady = this._onEditSessionReady.event;
|
||||
|
||||
private _onQueryPlanAvailable = this._register(new Emitter<IQueryPlanInfo>());
|
||||
private readonly _onQueryPlanAvailable = this._register(new Emitter<IQueryPlanInfo>());
|
||||
public readonly onQueryPlanAvailable = this._onQueryPlanAvailable.event;
|
||||
|
||||
private _onVisualize = this._register(new Emitter<azdata.ResultSetSummary>());
|
||||
private readonly _onVisualize = this._register(new Emitter<ResultSetSummary>());
|
||||
public readonly onVisualize = this._onVisualize.event;
|
||||
|
||||
private _queryStartTime?: Date;
|
||||
@@ -104,12 +86,11 @@ export default class QueryRunner extends Disposable {
|
||||
// CONSTRUCTOR /////////////////////////////////////////////////////////
|
||||
constructor(
|
||||
public uri: string,
|
||||
@IQueryManagementService private _queryManagementService: IQueryManagementService,
|
||||
@INotificationService private _notificationService: INotificationService,
|
||||
@IConfigurationService private _configurationService: IConfigurationService,
|
||||
@IInstantiationService private instantiationService: IInstantiationService,
|
||||
@ITextResourcePropertiesService private _textResourcePropertiesService: ITextResourcePropertiesService,
|
||||
@ILogService private _logService: ILogService
|
||||
@IQueryManagementService protected readonly queryManagementService: IQueryManagementService,
|
||||
@IConfigurationService private readonly configurationService: IConfigurationService,
|
||||
@IInstantiationService private readonly instantiationService: IInstantiationService,
|
||||
@ITextResourcePropertiesService private readonly textResourcePropertiesService: ITextResourcePropertiesService,
|
||||
@ILogService private readonly logService: ILogService
|
||||
) {
|
||||
super();
|
||||
}
|
||||
@@ -125,7 +106,7 @@ export default class QueryRunner extends Disposable {
|
||||
/**
|
||||
* For public use only, for private use, directly access the member
|
||||
*/
|
||||
public get batchSets(): azdata.BatchSummary[] {
|
||||
public get batchSets(): BatchSummary[] {
|
||||
return this._batchSets.slice(0);
|
||||
}
|
||||
|
||||
@@ -141,22 +122,22 @@ export default class QueryRunner extends Disposable {
|
||||
/**
|
||||
* Cancels the running query, if there is one
|
||||
*/
|
||||
public cancelQuery(): Promise<azdata.QueryCancelResult> {
|
||||
return this._queryManagementService.cancelQuery(this.uri);
|
||||
public cancelQuery(): Promise<QueryCancelResult> {
|
||||
return this.queryManagementService.cancelQuery(this.uri);
|
||||
}
|
||||
|
||||
/**
|
||||
* Runs the query with the provided query
|
||||
* @param input Query string to execute
|
||||
*/
|
||||
public runQuery(input: string, runOptions?: azdata.ExecutionPlanOptions): Promise<void>;
|
||||
public runQuery(input: string, runOptions?: ExecutionPlanOptions): Promise<void>;
|
||||
/**
|
||||
* Runs the query by pulling the query from the document using the provided selection data
|
||||
* @param input selection data
|
||||
*/
|
||||
public runQuery(input: azdata.ISelectionData, runOptions?: azdata.ExecutionPlanOptions): Promise<void>;
|
||||
public runQuery(input: string | azdata.ISelectionData, runOptions?: azdata.ExecutionPlanOptions): Promise<void> {
|
||||
if (types.isString(input)) {
|
||||
public runQuery(input: IRange | undefined, runOptions?: ExecutionPlanOptions): Promise<void>;
|
||||
public runQuery(input: string | IRange | undefined, runOptions?: ExecutionPlanOptions): Promise<void> {
|
||||
if (types.isString(input) || types.isUndefined(input)) {
|
||||
return this.doRunQuery(input, false, runOptions);
|
||||
} else {
|
||||
return this.doRunQuery(input, false, runOptions);
|
||||
@@ -167,7 +148,7 @@ export default class QueryRunner extends Disposable {
|
||||
* Runs the current SQL statement by pulling the query from the document using the provided selection data
|
||||
* @param input selection data
|
||||
*/
|
||||
public runQueryStatement(input: azdata.ISelectionData): Promise<void> {
|
||||
public runQueryStatement(input: IRange): Promise<void> {
|
||||
return this.doRunQuery(input, true);
|
||||
}
|
||||
|
||||
@@ -175,9 +156,9 @@ export default class QueryRunner extends Disposable {
|
||||
* Implementation that runs the query with the provided query
|
||||
* @param input Query string to execute
|
||||
*/
|
||||
private doRunQuery(input: string, runCurrentStatement: boolean, runOptions?: azdata.ExecutionPlanOptions): Promise<void>;
|
||||
private doRunQuery(input: azdata.ISelectionData, runCurrentStatement: boolean, runOptions?: azdata.ExecutionPlanOptions): Promise<void>;
|
||||
private doRunQuery(input: string | azdata.ISelectionData, runCurrentStatement: boolean, runOptions?: azdata.ExecutionPlanOptions): Promise<void> {
|
||||
private doRunQuery(input: string, runCurrentStatement: boolean, runOptions?: ExecutionPlanOptions): Promise<void>;
|
||||
private doRunQuery(input: IRange | undefined, runCurrentStatement: boolean, runOptions?: ExecutionPlanOptions): Promise<void>;
|
||||
private doRunQuery(input: string | IRange | undefined, runCurrentStatement: boolean, runOptions?: ExecutionPlanOptions): Promise<void> {
|
||||
if (this.isExecuting) {
|
||||
return Promise.resolve();
|
||||
}
|
||||
@@ -187,9 +168,9 @@ export default class QueryRunner extends Disposable {
|
||||
this._queryStartTime = undefined;
|
||||
this._queryEndTime = undefined;
|
||||
this._messages = [];
|
||||
if (isSelectionOrUndefined(input)) {
|
||||
if (isRangeOrUndefined(input)) {
|
||||
// Update internal state to show that we're executing the query
|
||||
this._resultLineOffset = input ? input.startLine : 0;
|
||||
this._resultLineOffset = input ? input.startLineNumber : 0;
|
||||
this._resultColumnOffset = input ? input.startColumn : 0;
|
||||
this._isExecuting = true;
|
||||
this._totalElapsedMilliseconds = 0;
|
||||
@@ -199,8 +180,8 @@ export default class QueryRunner extends Disposable {
|
||||
|
||||
// Send the request to execute the query
|
||||
return runCurrentStatement
|
||||
? this._queryManagementService.runQueryStatement(this.uri, input.startLine, input.startColumn).then(() => this.handleSuccessRunQueryResult(), e => this.handleFailureRunQueryResult(e))
|
||||
: this._queryManagementService.runQuery(this.uri, input, runOptions).then(() => this.handleSuccessRunQueryResult(), e => this.handleFailureRunQueryResult(e));
|
||||
? this.queryManagementService.runQueryStatement(this.uri, input.startLineNumber, input.startColumn).then(() => this.handleSuccessRunQueryResult(), e => this.handleFailureRunQueryResult(e))
|
||||
: this.queryManagementService.runQuery(this.uri, input, runOptions).then(() => this.handleSuccessRunQueryResult(), e => this.handleFailureRunQueryResult(e));
|
||||
} else {
|
||||
// Update internal state to show that we're executing the query
|
||||
this._isExecuting = true;
|
||||
@@ -208,7 +189,7 @@ export default class QueryRunner extends Disposable {
|
||||
|
||||
this._onQueryStart.fire();
|
||||
|
||||
return this._queryManagementService.runQueryString(this.uri, input).then(() => this.handleSuccessRunQueryResult(), e => this.handleFailureRunQueryResult(e));
|
||||
return this.queryManagementService.runQueryString(this.uri, input).then(() => this.handleSuccessRunQueryResult(), e => this.handleFailureRunQueryResult(e));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -218,45 +199,39 @@ export default class QueryRunner extends Disposable {
|
||||
// The query has started, so lets fire up the result pane
|
||||
if (!this.registered) {
|
||||
this.registered = true;
|
||||
this._queryManagementService.registerRunner(this, this.uri);
|
||||
this.queryManagementService.registerRunner(this, this.uri);
|
||||
}
|
||||
}
|
||||
|
||||
private handleFailureRunQueryResult(error: any) {
|
||||
// Attempting to launch the query failed, show the error message
|
||||
const eol = getEolString(this._textResourcePropertiesService, this.uri);
|
||||
const eol = getEolString(this.textResourcePropertiesService, this.uri);
|
||||
if (error instanceof Error) {
|
||||
error = error.message;
|
||||
}
|
||||
let message = nls.localize('query.ExecutionFailedError', "Execution failed due to an unexpected error: {0}\t{1}", eol, error);
|
||||
this.handleMessage([<azdata.QueryExecuteMessageParams>{
|
||||
ownerUri: this.uri,
|
||||
message: {
|
||||
isError: true,
|
||||
message: message
|
||||
}
|
||||
this.handleMessage([{
|
||||
isError: true,
|
||||
message: message
|
||||
}]);
|
||||
this.handleQueryComplete(<azdata.QueryExecuteCompleteNotificationResult>{ ownerUri: this.uri });
|
||||
this.handleQueryComplete();
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle a QueryComplete from the service layer
|
||||
*/
|
||||
public handleQueryComplete(result: azdata.QueryExecuteCompleteNotificationResult): void {
|
||||
public handleQueryComplete(batchSummaries?: CompleteBatchSummary[]): void {
|
||||
// this also isn't exact but its the best we can do
|
||||
this._queryEndTime = new Date();
|
||||
|
||||
// Store the batch sets we got back as a source of "truth"
|
||||
this._isExecuting = false;
|
||||
this._hasCompleted = true;
|
||||
this._batchSets = result.batchSummaries ? result.batchSummaries : [];
|
||||
this._batchSets = batchSummaries ? batchSummaries : [];
|
||||
|
||||
this._batchSets.map(batch => {
|
||||
if (batch.selection) {
|
||||
batch.selection.startLine += this._resultLineOffset!;
|
||||
batch.selection.startColumn += this._resultColumnOffset!;
|
||||
batch.selection.endLine += this._resultLineOffset!;
|
||||
batch.selection.endColumn += this._resultColumnOffset!;
|
||||
if (batch.range) {
|
||||
batch.range = new Range(batch.range.startLineNumber + this._resultLineOffset, batch.range.startColumn + this._resultColumnOffset, batch.range.endLineNumber + this._resultLineOffset, batch.range.endColumn + this._resultColumnOffset);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -277,28 +252,20 @@ export default class QueryRunner extends Disposable {
|
||||
/**
|
||||
* Handle a BatchStart from the service layer
|
||||
*/
|
||||
public handleBatchStart(result: azdata.QueryExecuteBatchNotificationParams): void {
|
||||
let batch = result.batchSummary;
|
||||
|
||||
public handleBatchStart(batch: BatchStartSummary): void {
|
||||
// Recalculate the start and end lines, relative to the result line offset
|
||||
if (batch.selection) {
|
||||
batch.selection.startLine += this._resultLineOffset!;
|
||||
batch.selection.startColumn += this._resultColumnOffset!;
|
||||
batch.selection.endLine += this._resultLineOffset!;
|
||||
batch.selection.endColumn += this._resultColumnOffset!;
|
||||
if (batch.range) {
|
||||
batch.range = new Range(batch.range.startLineNumber + this._resultLineOffset, batch.range.startColumn + this._resultColumnOffset, batch.range.endLineNumber + this._resultLineOffset, batch.range.endColumn + this._resultColumnOffset);
|
||||
}
|
||||
|
||||
// Set the result sets as an empty array so that as result sets complete we can add to the list
|
||||
batch.resultSetSummaries = [];
|
||||
|
||||
// Store the batch
|
||||
this._batchSets[batch.id] = batch;
|
||||
this._batchSets[batch.id] = { ...batch, resultSetSummaries: [], hasError: false };
|
||||
|
||||
let message = {
|
||||
let message: IQueryMessage = {
|
||||
// account for index by 1
|
||||
message: nls.localize('query.message.startQuery', "Started executing query at Line {0}", batch.selection.startLine + 1),
|
||||
message: batch.range ? nls.localize('query.message.startQueryWithRange', "Started executing query at Line {0}", batch.range.startLineNumber) : nls.localize('query.message.startQuery', "Started executing batch {0}", batch.id),
|
||||
time: batch.executionStart,
|
||||
selection: batch.selection,
|
||||
range: batch.range,
|
||||
isError: false
|
||||
};
|
||||
this._messages.push(message);
|
||||
@@ -309,9 +276,7 @@ export default class QueryRunner extends Disposable {
|
||||
/**
|
||||
* Handle a BatchComplete from the service layer
|
||||
*/
|
||||
public handleBatchComplete(result: azdata.QueryExecuteBatchNotificationParams): void {
|
||||
let batch: azdata.BatchSummary = result.batchSummary;
|
||||
|
||||
public handleBatchComplete(batch: CompleteBatchSummary): void {
|
||||
// Store the batch again to get the rest of the data
|
||||
this._batchSets[batch.id] = batch;
|
||||
let executionTime = <number>(Utils.parseTimeString(batch.executionElapsed) || 0);
|
||||
@@ -327,19 +292,18 @@ export default class QueryRunner extends Disposable {
|
||||
/**
|
||||
* Handle a ResultSetComplete from the service layer
|
||||
*/
|
||||
public handleResultSetAvailable(result: azdata.QueryExecuteResultSetNotificationParams): void {
|
||||
if (result && result.resultSetSummary) {
|
||||
let resultSet = result.resultSetSummary;
|
||||
let batchSet: azdata.BatchSummary;
|
||||
public handleResultSetAvailable(resultSet?: ResultSetSummary): void {
|
||||
if (resultSet) {
|
||||
let batchSet: BatchSummary;
|
||||
if (!resultSet.batchId) {
|
||||
// Missing the batchId or processing batchId==0. In this case, default to always using the first batch in the list
|
||||
// or create one in the case the DMP extension didn't obey the contract perfectly
|
||||
if (this._batchSets.length > 0) {
|
||||
batchSet = this._batchSets[0];
|
||||
} else {
|
||||
batchSet = <azdata.BatchSummary><unknown>{
|
||||
batchSet = <BatchSummary>{
|
||||
id: 0,
|
||||
selection: undefined,
|
||||
range: undefined,
|
||||
hasError: false,
|
||||
resultSetSummaries: []
|
||||
};
|
||||
@@ -350,15 +314,15 @@ export default class QueryRunner extends Disposable {
|
||||
}
|
||||
// handle getting queryPlanxml if we need too
|
||||
// check if this result has show plan, this needs work, it won't work for any other provider
|
||||
let hasShowPlan = !!find(result.resultSetSummary.columnInfo, e => e.columnName === 'Microsoft SQL Server 2005 XML Showplan');
|
||||
if (hasShowPlan) {
|
||||
let hasShowPlan = !!find(resultSet.columnInfo, e => e.columnName === 'Microsoft SQL Server 2005 XML Showplan');
|
||||
if (hasShowPlan && resultSet.rowCount > 0) {
|
||||
this._isQueryPlan = true;
|
||||
|
||||
this.getQueryRows(0, 1, result.resultSetSummary.batchId, result.resultSetSummary.id).then(e => {
|
||||
if (e.resultSubset.rows) {
|
||||
this._planXml.resolve(e.resultSubset.rows[0][0].displayValue);
|
||||
this.getQueryRows(0, 1, resultSet.batchId, resultSet.id).then(e => {
|
||||
if (e.rows) {
|
||||
this._planXml.resolve(e.rows[0][0].displayValue);
|
||||
}
|
||||
}).catch((e) => this._logService.error(e));
|
||||
}).catch((e) => this.logService.error(e));
|
||||
}
|
||||
// we will just ignore the set if we already have it
|
||||
// ideally this should never happen
|
||||
@@ -370,31 +334,30 @@ export default class QueryRunner extends Disposable {
|
||||
}
|
||||
}
|
||||
|
||||
public handleResultSetUpdated(result: azdata.QueryExecuteResultSetNotificationParams): void {
|
||||
if (result && result.resultSetSummary) {
|
||||
let resultSet = result.resultSetSummary;
|
||||
let batchSet: azdata.BatchSummary;
|
||||
public handleResultSetUpdated(resultSet?: ResultSetSummary): void {
|
||||
if (resultSet) {
|
||||
let batchSet: BatchSummary;
|
||||
batchSet = this._batchSets[resultSet.batchId];
|
||||
// handle getting queryPlanxml if we need too
|
||||
// check if this result has show plan, this needs work, it won't work for any other provider
|
||||
let hasShowPlan = !!find(result.resultSetSummary.columnInfo, e => e.columnName === 'Microsoft SQL Server 2005 XML Showplan');
|
||||
let hasShowPlan = !!resultSet.columnInfo.find(e => e.columnName === 'Microsoft SQL Server 2005 XML Showplan');
|
||||
if (hasShowPlan) {
|
||||
this._isQueryPlan = true;
|
||||
this.getQueryRows(0, 1, result.resultSetSummary.batchId, result.resultSetSummary.id).then(e => {
|
||||
this.getQueryRows(0, 1, resultSet.batchId, resultSet.id).then(e => {
|
||||
|
||||
if (e.resultSubset.rows) {
|
||||
let planXmlString = e.resultSubset.rows[0][0].displayValue;
|
||||
this._planXml.resolve(e.resultSubset.rows[0][0].displayValue);
|
||||
if (e.rows) {
|
||||
let planXmlString = e.rows[0][0].displayValue;
|
||||
this._planXml.resolve(e.rows[0][0].displayValue);
|
||||
// fire query plan available event if execution is completed
|
||||
if (result.resultSetSummary.complete) {
|
||||
if (resultSet.complete) {
|
||||
this._onQueryPlanAvailable.fire({
|
||||
providerId: mssqlProviderName,
|
||||
fileUri: result.ownerUri,
|
||||
fileUri: this.uri,
|
||||
planXml: planXmlString
|
||||
});
|
||||
}
|
||||
}
|
||||
}).catch((e) => this._logService.error(e));
|
||||
}).catch((e) => this.logService.error(e));
|
||||
}
|
||||
if (batchSet) {
|
||||
// Store the result set in the batch and emit that a result set has completed
|
||||
@@ -407,8 +370,7 @@ export default class QueryRunner extends Disposable {
|
||||
/**
|
||||
* Handle a Mssage from the service layer
|
||||
*/
|
||||
public handleMessage(messagesObj: azdata.QueryExecuteMessageParams[]): void {
|
||||
const messages = messagesObj.map(m => m.message);
|
||||
public handleMessage(messages: IResultMessage[]): void {
|
||||
this._messages.push(...messages);
|
||||
|
||||
// Send the message to the results pane
|
||||
@@ -418,8 +380,8 @@ export default class QueryRunner extends Disposable {
|
||||
/**
|
||||
* Get more data rows from the current resultSets from the service layer
|
||||
*/
|
||||
public getQueryRows(rowStart: number, numberOfRows: number, batchIndex: number, resultSetIndex: number): Promise<azdata.QueryExecuteSubsetResult> {
|
||||
let rowData: azdata.QueryExecuteSubsetParams = <azdata.QueryExecuteSubsetParams>{
|
||||
public getQueryRows(rowStart: number, numberOfRows: number, batchIndex: number, resultSetIndex: number): Promise<ResultSetSubset> {
|
||||
let rowData: QueryExecuteSubsetParams = <QueryExecuteSubsetParams>{
|
||||
ownerUri: this.uri,
|
||||
resultSetIndex: resultSetIndex,
|
||||
rowsCount: numberOfRows,
|
||||
@@ -427,7 +389,7 @@ export default class QueryRunner extends Disposable {
|
||||
batchIndex: batchIndex
|
||||
};
|
||||
|
||||
return this._queryManagementService.getQueryRows(rowData).then(r => r, error => {
|
||||
return this.queryManagementService.getQueryRows(rowData).then(r => r, error => {
|
||||
// this._notificationService.notify({
|
||||
// severity: Severity.Error,
|
||||
// message: nls.localize('query.gettingRowsFailedError', 'Something went wrong getting more rows: {0}', error)
|
||||
@@ -436,104 +398,11 @@ export default class QueryRunner extends Disposable {
|
||||
});
|
||||
}
|
||||
|
||||
/*
|
||||
* Handle a session ready event for Edit Data
|
||||
*/
|
||||
public initializeEdit(ownerUri: string, schemaName: string, objectName: string, objectType: string, rowLimit: number, queryString: string): Promise<void> {
|
||||
// Update internal state to show that we're executing the query
|
||||
this._isExecuting = true;
|
||||
this._totalElapsedMilliseconds = 0;
|
||||
// TODO issue #228 add statusview callbacks here
|
||||
|
||||
return this._queryManagementService.initializeEdit(ownerUri, schemaName, objectName, objectType, rowLimit, queryString).then(result => {
|
||||
// The query has started, so lets fire up the result pane
|
||||
this._onQueryStart.fire();
|
||||
this._queryManagementService.registerRunner(this, ownerUri);
|
||||
}, error => {
|
||||
// Attempting to launch the query failed, show the error message
|
||||
|
||||
// TODO issue #228 add statusview callbacks here
|
||||
this._isExecuting = false;
|
||||
this._notificationService.error(nls.localize('query.initEditExecutionFailed', "Initialize edit data session failed: ") + error);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves a number of rows from an edit session
|
||||
* @param rowStart The index of the row to start returning (inclusive)
|
||||
* @param numberOfRows The number of rows to return
|
||||
*/
|
||||
public getEditRows(rowStart: number, numberOfRows: number): Promise<azdata.EditSubsetResult> {
|
||||
const self = this;
|
||||
let rowData: azdata.EditSubsetParams = {
|
||||
ownerUri: this.uri,
|
||||
rowCount: numberOfRows,
|
||||
rowStartIndex: rowStart
|
||||
};
|
||||
|
||||
return new Promise<azdata.EditSubsetResult>((resolve, reject) => {
|
||||
self._queryManagementService.getEditRows(rowData).then(result => {
|
||||
if (!result.hasOwnProperty('rowCount')) {
|
||||
let error = `Nothing returned from subset query`;
|
||||
self._notificationService.notify({
|
||||
severity: Severity.Error,
|
||||
message: error
|
||||
});
|
||||
reject(error);
|
||||
}
|
||||
resolve(result);
|
||||
}, error => {
|
||||
// let errorMessage = nls.localize('query.moreRowsFailedError', "Something went wrong getting more rows:");
|
||||
// self._notificationService.notify({
|
||||
// severity: Severity.Error,
|
||||
// message: `${errorMessage} ${error}`
|
||||
// });
|
||||
reject(error);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
public handleEditSessionReady(ownerUri: string, success: boolean, message: string): void {
|
||||
this._onEditSessionReady.fire({ ownerUri, success, message });
|
||||
}
|
||||
|
||||
public updateCell(ownerUri: string, rowId: number, columnId: number, newValue: string): Promise<azdata.EditUpdateCellResult> {
|
||||
return this._queryManagementService.updateCell(ownerUri, rowId, columnId, newValue);
|
||||
}
|
||||
|
||||
public commitEdit(ownerUri: string): Promise<void> {
|
||||
return this._queryManagementService.commitEdit(ownerUri);
|
||||
}
|
||||
|
||||
public createRow(ownerUri: string): Promise<azdata.EditCreateRowResult> {
|
||||
return this._queryManagementService.createRow(ownerUri).then(result => {
|
||||
return result;
|
||||
});
|
||||
}
|
||||
|
||||
public deleteRow(ownerUri: string, rowId: number): Promise<void> {
|
||||
return this._queryManagementService.deleteRow(ownerUri, rowId);
|
||||
}
|
||||
|
||||
public revertCell(ownerUri: string, rowId: number, columnId: number): Promise<azdata.EditRevertCellResult> {
|
||||
return this._queryManagementService.revertCell(ownerUri, rowId, columnId).then(result => {
|
||||
return result;
|
||||
});
|
||||
}
|
||||
|
||||
public revertRow(ownerUri: string, rowId: number): Promise<void> {
|
||||
return this._queryManagementService.revertRow(ownerUri, rowId);
|
||||
}
|
||||
|
||||
public disposeEdit(ownerUri: string): Promise<void> {
|
||||
return this._queryManagementService.disposeEdit(ownerUri);
|
||||
}
|
||||
|
||||
/**
|
||||
* Disposes the Query from the service client
|
||||
*/
|
||||
public async disposeQuery(): Promise<void> {
|
||||
await this._queryManagementService.disposeQuery(this.uri);
|
||||
await this.queryManagementService.disposeQuery(this.uri);
|
||||
this.dispose();
|
||||
}
|
||||
|
||||
@@ -561,7 +430,7 @@ export default class QueryRunner extends Disposable {
|
||||
|
||||
public getColumnHeaders(batchId: number, resultId: number, range: Slick.Range): string[] | undefined {
|
||||
let headers: string[] | undefined = undefined;
|
||||
let batchSummary: azdata.BatchSummary = this._batchSets[batchId];
|
||||
let batchSummary: BatchSummary = this._batchSets[batchId];
|
||||
if (batchSummary !== undefined) {
|
||||
let resultSetSummary = batchSummary.resultSetSummaries[resultId];
|
||||
headers = resultSetSummary.columnInfo.slice(range.fromCell, range.toCell + 1).map((info, i) => {
|
||||
@@ -573,7 +442,7 @@ export default class QueryRunner extends Disposable {
|
||||
|
||||
private sendBatchTimeMessage(batchId: number, executionTime: string): void {
|
||||
// get config copyRemoveNewLine option from vscode config
|
||||
let showBatchTime = this._configurationService.getValue<boolean>('sql.showBatchTime');
|
||||
let showBatchTime = this.configurationService.getValue<boolean>('sql.showBatchTime');
|
||||
if (showBatchTime) {
|
||||
let message: IQueryMessage = {
|
||||
batchId: batchId,
|
||||
@@ -596,7 +465,7 @@ export default class QueryRunner extends Disposable {
|
||||
}
|
||||
|
||||
public notifyVisualizeRequested(batchId: number, resultSetId: number): void {
|
||||
let result: azdata.ResultSetSummary = {
|
||||
let result: ResultSetSummary = {
|
||||
batchId: batchId,
|
||||
id: resultSetId,
|
||||
columnInfo: this.batchSets[batchId].resultSetSummaries[resultSetId].columnInfo,
|
||||
@@ -620,7 +489,7 @@ export class QueryGridDataProvider implements IGridDataProvider {
|
||||
) {
|
||||
}
|
||||
|
||||
getRowData(rowStart: number, numberOfRows: number): Promise<azdata.QueryExecuteSubsetResult> {
|
||||
getRowData(rowStart: number, numberOfRows: number): Promise<ResultSetSubset> {
|
||||
return this.queryRunner.getQueryRows(rowStart, numberOfRows, this.batchId, this.resultSetId);
|
||||
}
|
||||
|
||||
@@ -679,6 +548,6 @@ export function shouldRemoveNewLines(configurationService: IConfigurationService
|
||||
return !!removeNewLines;
|
||||
}
|
||||
|
||||
function isSelectionOrUndefined(input: string | azdata.ISelectionData | undefined): input is azdata.ISelectionData | undefined {
|
||||
return types.isObject(input) || types.isUndefinedOrNull(input);
|
||||
function isRangeOrUndefined(input: string | IRange | undefined): input is IRange | undefined {
|
||||
return Range.isIRange(input) || types.isUndefinedOrNull(input);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user