Add option for using generic SQL queries to filter EditData rows via a query editor pane. (#1329)

This commit is contained in:
Cory Rivera
2018-05-14 12:27:55 -07:00
committed by GitHub
parent 6b549696c5
commit 89c48bbe75
27 changed files with 1075 additions and 293 deletions

View File

@@ -33,6 +33,8 @@ import { QueryPlanEditor } from 'sql/parts/queryPlan/queryPlanEditor';
import { QueryPlanInput } from 'sql/parts/queryPlan/queryPlanInput';
import * as Constants from 'sql/parts/query/common/constants';
import { localize } from 'vs/nls';
import { EditDataResultsEditor } from 'sql/parts/editData/editor/editDataResultsEditor';
import { EditDataResultsInput } from 'sql/parts/editData/common/editDataResultsInput';
const gridCommandsWeightBonus = 100; // give our commands a little bit more weight over other default list/tree commands
@@ -81,6 +83,16 @@ const editDataEditorDescriptor = new EditorDescriptor(
Registry.as<IEditorRegistry>(EditorExtensions.Editors)
.registerEditor(editDataEditorDescriptor, [new SyncDescriptor(EditDataInput)]);
// Editor
const editDataResultsEditorDescriptor = new EditorDescriptor(
EditDataResultsEditor,
EditDataResultsEditor.ID,
'EditDataResults'
);
Registry.as<IEditorRegistry>(EditorExtensions.Editors)
.registerEditor(editDataResultsEditorDescriptor, [new SyncDescriptor(EditDataResultsInput)]);
let actionRegistry = <IWorkbenchActionRegistry>Registry.as(Extensions.WorkbenchActions);
// Query Actions

View File

@@ -30,7 +30,7 @@ export interface IQueryEditorService {
newQueryPlanEditor(xmlShowPlan: string): Promise<any>;
// Creates new edit data session
newEditDataEditor(schemaName: string, tableName: string): Promise<IConnectableInput>;
newEditDataEditor(schemaName: string, tableName: string, queryString: string): Promise<IConnectableInput>;
// Clears any QueryEditor data for the given URI held by this service
onQueryInputClosed(uri: string): void;

View File

@@ -43,7 +43,7 @@ export interface IQueryManagementService {
onEditSessionReady(ownerUri: string, success: boolean, message: string): void;
// Edit Data Functions
initializeEdit(ownerUri: string, schemaName: string, objectName: string, objectType: string, rowLimit: number): Thenable<void>;
initializeEdit(ownerUri: string, schemaName: string, objectName: string, objectType: string, rowLimit: number, queryString: string): Thenable<void>;
disposeEdit(ownerUri: string): Thenable<void>;
updateCell(ownerUri: string, rowId: number, columnId: number, newValue: string): Thenable<sqlops.EditUpdateCellResult>;
commitEdit(ownerUri): Thenable<void>;
@@ -68,7 +68,7 @@ export interface IQueryRequestHandler {
saveResults(requestParams: sqlops.SaveResultsRequestParams): Thenable<sqlops.SaveResultRequestResult>;
// Edit Data actions
initializeEdit(ownerUri: string, schemaName: string, objectName: string, objectType: string, rowLimit: number): Thenable<void>;
initializeEdit(ownerUri: string, schemaName: string, objectName: string, objectType: string, rowLimit: number, queryString: string): Thenable<void>;
disposeEdit(ownerUri: string): Thenable<void>;
updateCell(ownerUri: string, rowId: number, columnId: number, newValue: string): Thenable<sqlops.EditUpdateCellResult>;
commitEdit(ownerUri): Thenable<void>;
@@ -244,9 +244,9 @@ export class QueryManagementService implements IQueryManagementService {
}
// Edit Data Functions
public initializeEdit(ownerUri: string, schemaName: string, objectName: string, objectType: string, rowLimit: number): Thenable<void> {
public initializeEdit(ownerUri: string, schemaName: string, objectName: string, objectType: string, rowLimit: number, queryString: string): Thenable<void> {
return this._runAction(ownerUri, (runner) => {
return runner.initializeEdit(ownerUri, schemaName, objectName, objectType, rowLimit);
return runner.initializeEdit(ownerUri, schemaName, objectName, objectType, rowLimit, queryString);
});
}

View File

@@ -19,6 +19,7 @@ import { IQueryModelService } from 'sql/parts/query/execution/queryModel';
import * as WorkbenchUtils from 'sql/workbench/common/sqlWorkbenchUtils';
import * as Constants from 'sql/parts/query/common/constants';
import * as ConnectionConstants from 'sql/parts/connection/common/constants';
import { EditDataEditor } from 'sql/parts/editData/editor/editDataEditor';
const singleQuote = '\'';
@@ -98,8 +99,8 @@ export class RunQueryKeyboardAction extends Action {
public run(): TPromise<void> {
let editor = this._editorService.getActiveEditor();
if (editor && editor instanceof QueryEditor) {
let queryEditor: QueryEditor = editor;
if (editor && (editor instanceof QueryEditor || editor instanceof EditDataEditor)) {
let queryEditor: QueryEditor | EditDataEditor = editor;
queryEditor.runQuery();
}
return TPromise.as(null);
@@ -174,8 +175,8 @@ export class CancelQueryKeyboardAction extends Action {
public run(): TPromise<void> {
let editor = this._editorService.getActiveEditor();
if (editor && editor instanceof QueryEditor) {
let queryEditor: QueryEditor = editor;
if (editor && (editor instanceof QueryEditor || editor instanceof EditDataEditor)) {
let queryEditor: QueryEditor | EditDataEditor = editor;
queryEditor.cancelQuery();
}
return TPromise.as(null);

View File

@@ -57,7 +57,7 @@ export interface IQueryModelService {
// Edit Data Functions
initializeEdit(ownerUri: string, schemaName: string, objectName: string, objectType: string, rowLimit: number): void;
initializeEdit(ownerUri: string, schemaName: string, objectName: string, objectType: string, rowLimit: number, queryString: string): void;
disposeEdit(ownerUri: string): Thenable<void>;
updateCell(ownerUri: string, rowId: number, columnId: number, newValue: string): Thenable<EditUpdateCellResult>;
commitEdit(ownerUri): Thenable<void>;

View File

@@ -352,7 +352,7 @@ export class QueryModelService implements IQueryModelService {
}
// EDIT DATA METHODS /////////////////////////////////////////////////////
initializeEdit(ownerUri: string, schemaName: string, objectName: string, objectType: string, rowLimit: number): void {
initializeEdit(ownerUri: string, schemaName: string, objectName: string, objectType: string, rowLimit: number, queryString: string): void {
// Reuse existing query runner if it exists
let queryRunner: QueryRunner;
let info: QueryInfo;
@@ -368,6 +368,8 @@ export class QueryModelService implements IQueryModelService {
queryRunner = existingRunner;
} else {
info = new QueryInfo();
// We do not have a query runner for this editor, so create a new one
// and map it to the results uri
queryRunner = this._instantiationService.createInstance(QueryRunner, ownerUri, ownerUri);
@@ -376,15 +378,21 @@ export class QueryModelService implements IQueryModelService {
});
queryRunner.addListener(QREvents.BATCH_START, batch => {
let link = undefined;
let messageText = LocalizedConstants.runQueryBatchStartMessage;
if (batch.selection) {
link = {
text: strings.format(LocalizedConstants.runQueryBatchStartLine, batch.selection.startLine + 1),
uri: ''
};
if (info.selectionSnippet) {
// This indicates it's a query string. Do not include line information since it'll be inaccurate, but show some of the
// executed query text
messageText = nls.localize('runQueryStringBatchStartMessage', 'Started executing query "{0}"', info.selectionSnippet);
} else {
link = {
text: strings.format(LocalizedConstants.runQueryBatchStartLine, batch.selection.startLine + 1)
};
}
}
let message = {
message: LocalizedConstants.runQueryBatchStartMessage,
batchId: undefined,
message: messageText,
batchId: batch.id,
isError: false,
time: new Date().toLocaleTimeString(),
link: link
@@ -407,13 +415,20 @@ export class QueryModelService implements IQueryModelService {
this._fireQueryEvent(e.ownerUri, 'editSessionReady');
});
info = new QueryInfo();
info.queryRunner = queryRunner;
info.dataService = this._instantiationService.createInstance(DataService, ownerUri);
this._queryInfoMap.set(ownerUri, info);
}
queryRunner.initializeEdit(ownerUri, schemaName, objectName, objectType, rowLimit);
if (queryString) {
if (queryString.length < selectionSnippetMaxLen) {
info.selectionSnippet = queryString;
} else {
info.selectionSnippet = queryString.substring(0, selectionSnippetMaxLen - 3) + '...';
}
}
queryRunner.initializeEdit(ownerUri, schemaName, objectName, objectType, rowLimit, queryString);
}
public cancelInitializeEdit(input: QueryRunner | string): void {

View File

@@ -300,13 +300,13 @@ export default class QueryRunner {
/*
* Handle a session ready event for Edit Data
*/
public initializeEdit(ownerUri: string, schemaName: string, objectName: string, objectType: string, rowLimit: number): Thenable<void> {
public initializeEdit(ownerUri: string, schemaName: string, objectName: string, objectType: string, rowLimit: number, queryString: string): Thenable<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).then(result => {
return this._queryManagementService.initializeEdit(ownerUri, schemaName, objectName, objectType, rowLimit, queryString).then(result => {
// The query has started, so lets fire up the result pane
this._eventEmitter.emit(EventType.START);
this._queryManagementService.registerRunner(this, ownerUri);

View File

@@ -29,6 +29,7 @@ import paths = require('vs/base/common/paths');
import { isLinux } from 'vs/base/common/platform';
import { Schemas } from 'vs/base/common/network';
import { INotificationService } from 'vs/platform/notification/common/notification';
import { EditDataResultsInput } from 'sql/parts/editData/common/editDataResultsInput';
const fs = require('fs');
@@ -120,7 +121,7 @@ export class QueryEditorService implements IQueryEditorService {
/**
* Creates new edit data session
*/
public newEditDataEditor(schemaName: string, tableName: string): Promise<IConnectableInput> {
public newEditDataEditor(schemaName: string, tableName: string, sqlContent: string): Promise<IConnectableInput> {
return new Promise<IConnectableInput>((resolve, reject) => {
try {
@@ -129,8 +130,17 @@ export class QueryEditorService implements IQueryEditorService {
let filePath = this.createEditDataFileName(objectName);
let docUri: URI = URI.from({ scheme: Schemas.untitled, path: filePath });
// Create a sql document pane with accoutrements
const fileInput = this._untitledEditorService.createOrGet(docUri, 'sql');
fileInput.resolve().then(m => {
if (sqlContent) {
m.textEditorModel.setValue(sqlContent);
}
});
// Create an EditDataInput for editing
let editDataInput: EditDataInput = this._instantiationService.createInstance(EditDataInput, docUri, schemaName, tableName);
const resultsInput: EditDataResultsInput = this._instantiationService.createInstance(EditDataResultsInput, docUri.toString());
let editDataInput: EditDataInput = this._instantiationService.createInstance(EditDataInput, docUri, schemaName, tableName, fileInput, sqlContent, resultsInput);
this._editorService.openEditor(editDataInput, { pinned: true })
.then((editor) => {
@@ -212,7 +222,7 @@ export class QueryEditorService implements IQueryEditorService {
}
let uri: URI = QueryEditorService._getEditorChangeUri(editor.input, changingToSql);
if(uri.scheme === Schemas.untitled && editor.input instanceof QueryInput)
if(uri.scheme === Schemas.untitled && (editor.input instanceof QueryInput || editor.input instanceof EditDataInput))
{
QueryEditorService.notificationService.notify({
severity: Severity.Error,
@@ -299,10 +309,8 @@ export class QueryEditorService implements IQueryEditorService {
filePath = editDataFileName(counter);
}
// TODO: check if this document name already exists in any open documents tabs
let fileNames: string[] = [];
this._editorGroupService.getStacksModel().groups.map(group => group.getEditors().map(editor => fileNames.push(editor.getName())));
while (fileNames.find(x => x.toUpperCase() === filePath.toUpperCase())) {
let untitledEditors = this._untitledEditorService.getAll();
while (untitledEditors.find(x => x.getName().toUpperCase() === filePath.toUpperCase())) {
counter++;
filePath = editDataFileName(counter);
}