mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-02-19 11:01:38 -05:00
Compare commits
29 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5b3b97f4a3 | ||
|
|
6d25299eef | ||
|
|
26fe9932f2 | ||
|
|
2acd37a1b1 | ||
|
|
85786b48c3 | ||
|
|
acd6257bae | ||
|
|
f007d707b6 | ||
|
|
b118b4bc7a | ||
|
|
f3edece70b | ||
|
|
4de376c357 | ||
|
|
0753b63ad0 | ||
|
|
0523190fbb | ||
|
|
de994972db | ||
|
|
3b06473c49 | ||
|
|
bb75143282 | ||
|
|
3857f11dc9 | ||
|
|
0918d93a18 | ||
|
|
25d96d041e | ||
|
|
0dc88501cf | ||
|
|
bac7eccbaf | ||
|
|
585d609ebb | ||
|
|
168385b6f1 | ||
|
|
eb4612100d | ||
|
|
d89ce8f9ec | ||
|
|
d84dd31491 | ||
|
|
b6632547a2 | ||
|
|
79669f073c | ||
|
|
e078e3bc48 | ||
|
|
72d035be98 |
@@ -114,14 +114,14 @@ steps:
|
|||||||
APP_NAME="`ls $APP_ROOT | head -n 1`"
|
APP_NAME="`ls $APP_ROOT | head -n 1`"
|
||||||
yarn smoketest --build "$APP_ROOT/$APP_NAME" --screenshots "$(build.artifactstagingdirectory)/smokeshots"
|
yarn smoketest --build "$APP_ROOT/$APP_NAME" --screenshots "$(build.artifactstagingdirectory)/smokeshots"
|
||||||
displayName: Run smoke tests (Electron)
|
displayName: Run smoke tests (Electron)
|
||||||
condition: and(succeeded(), eq(variables['VSCODE_STEP_ON_IT'], 'false'))
|
condition: and(succeeded(), eq(variables['RUN_TESTS'], 'true'))
|
||||||
|
|
||||||
- script: |
|
# - script: |
|
||||||
set -e
|
# set -e
|
||||||
VSCODE_REMOTE_SERVER_PATH="$(agent.builddirectory)/azuredatastudio-reh-web-darwin" \
|
# VSCODE_REMOTE_SERVER_PATH="$(agent.builddirectory)/azuredatastudio-reh-web-darwin" \
|
||||||
yarn smoketest --web --headless --screenshots "$(build.artifactstagingdirectory)/smokeshots"
|
# yarn smoketest --web --headless --screenshots "$(build.artifactstagingdirectory)/smokeshots"
|
||||||
displayName: Run smoke tests (Browser)
|
# displayName: Run smoke tests (Browser)
|
||||||
condition: and(succeeded(), eq(variables['VSCODE_STEP_ON_IT'], 'false'))
|
# condition: and(succeeded(), eq(variables['RUN_TESTS'], 'true'))
|
||||||
|
|
||||||
- script: |
|
- script: |
|
||||||
set -e
|
set -e
|
||||||
|
|||||||
@@ -16,12 +16,10 @@ steps:
|
|||||||
- task: NodeTool@0
|
- task: NodeTool@0
|
||||||
inputs:
|
inputs:
|
||||||
versionSpec: "10.15.1"
|
versionSpec: "10.15.1"
|
||||||
condition: and(succeeded(), ne(variables['CacheRestored-Compilation'], 'true'))
|
|
||||||
|
|
||||||
- task: geeklearningio.gl-vsts-tasks-yarn.yarn-installer-task.YarnInstaller@3
|
- task: geeklearningio.gl-vsts-tasks-yarn.yarn-installer-task.YarnInstaller@3
|
||||||
inputs:
|
inputs:
|
||||||
versionSpec: "1.x"
|
versionSpec: "1.x"
|
||||||
condition: and(succeeded(), ne(variables['CacheRestored-Compilation'], 'true'))
|
|
||||||
|
|
||||||
- task: AzureKeyVault@1
|
- task: AzureKeyVault@1
|
||||||
displayName: 'Azure Key Vault: Get Secrets'
|
displayName: 'Azure Key Vault: Get Secrets'
|
||||||
@@ -56,26 +54,25 @@ steps:
|
|||||||
keyfile: 'build/.cachesalt, .yarnrc, remote/.yarnrc, **/yarn.lock, !**/node_modules/**/yarn.lock, !**/.*/**/yarn.lock, !samples/**/yarn.lock'
|
keyfile: 'build/.cachesalt, .yarnrc, remote/.yarnrc, **/yarn.lock, !**/node_modules/**/yarn.lock, !**/.*/**/yarn.lock, !samples/**/yarn.lock'
|
||||||
targetfolder: '**/node_modules, !**/node_modules/**/node_modules, !samples/**/node_modules'
|
targetfolder: '**/node_modules, !**/node_modules/**/node_modules, !samples/**/node_modules'
|
||||||
vstsFeed: 'BuildCache'
|
vstsFeed: 'BuildCache'
|
||||||
condition: and(succeeded(), ne(variables['CacheRestored-Compilation'], 'true'))
|
|
||||||
|
|
||||||
- script: |
|
- script: |
|
||||||
set -e
|
set -e
|
||||||
CHILD_CONCURRENCY=1 yarn --frozen-lockfile
|
CHILD_CONCURRENCY=1 yarn --frozen-lockfile
|
||||||
displayName: Install dependencies
|
displayName: Install dependencies
|
||||||
condition: and(succeeded(), ne(variables['CacheRestored-Compilation'], 'true'), ne(variables['CacheRestored'], 'true'))
|
condition: and(succeeded(), ne(variables['CacheRestored'], 'true'))
|
||||||
|
|
||||||
- task: 1ESLighthouseEng.PipelineArtifactCaching.SaveCacheV1.SaveCache@1
|
- task: 1ESLighthouseEng.PipelineArtifactCaching.SaveCacheV1.SaveCache@1
|
||||||
inputs:
|
inputs:
|
||||||
keyfile: 'build/.cachesalt, .yarnrc, remote/.yarnrc, **/yarn.lock, !**/node_modules/**/yarn.lock, !**/.*/**/yarn.lock, !samples/**/yarn.lock'
|
keyfile: 'build/.cachesalt, .yarnrc, remote/.yarnrc, **/yarn.lock, !**/node_modules/**/yarn.lock, !**/.*/**/yarn.lock, !samples/**/yarn.lock'
|
||||||
targetfolder: '**/node_modules, !**/node_modules/**/node_modules, !samples/**/node_modules'
|
targetfolder: '**/node_modules, !**/node_modules/**/node_modules, !samples/**/node_modules'
|
||||||
vstsFeed: 'BuildCache'
|
vstsFeed: 'BuildCache'
|
||||||
condition: and(succeeded(), ne(variables['CacheRestored-Compilation'], 'true'), ne(variables['CacheRestored'], 'true'))
|
condition: and(succeeded(), ne(variables['CacheRestored'], 'true'))
|
||||||
|
|
||||||
- script: |
|
- script: |
|
||||||
set -e
|
set -e
|
||||||
yarn postinstall
|
yarn postinstall
|
||||||
displayName: Run postinstall scripts
|
displayName: Run postinstall scripts
|
||||||
condition: and(succeeded(), ne(variables['CacheRestored-Compilation'], 'true'), eq(variables['CacheRestored'], 'true'))
|
condition: and(succeeded(), eq(variables['CacheRestored'], 'true'))
|
||||||
|
|
||||||
# Mixin must run before optimize, because the CSS loader will
|
# Mixin must run before optimize, because the CSS loader will
|
||||||
# inline small SVGs
|
# inline small SVGs
|
||||||
@@ -113,7 +110,6 @@ steps:
|
|||||||
|
|
||||||
node build/azure-pipelines/common/copyArtifacts.js
|
node build/azure-pipelines/common/copyArtifacts.js
|
||||||
displayName: Write Version Information
|
displayName: Write Version Information
|
||||||
condition: and(succeeded(), ne(variables['CacheRestored-Compilation'], 'true'))
|
|
||||||
|
|
||||||
- task: PublishBuildArtifacts@1
|
- task: PublishBuildArtifacts@1
|
||||||
displayName: 'Publish Artifact: drop'
|
displayName: 'Publish Artifact: drop'
|
||||||
|
|||||||
@@ -3,7 +3,6 @@
|
|||||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||||
*--------------------------------------------------------------------------------------------*/
|
*--------------------------------------------------------------------------------------------*/
|
||||||
|
|
||||||
import { WorkspaceConfiguration, ConfigurationTarget } from 'vscode';
|
|
||||||
import { Account } from 'azdata';
|
import { Account } from 'azdata';
|
||||||
|
|
||||||
import { azureResource } from '../azure-resource';
|
import { azureResource } from '../azure-resource';
|
||||||
@@ -53,25 +52,8 @@ export class AzureResourceSubscriptionFilterService implements IAzureResourceSub
|
|||||||
for (const accountId in selectedSubscriptionsCache) {
|
for (const accountId in selectedSubscriptionsCache) {
|
||||||
filters.push(...selectedSubscriptionsCache[accountId].map((subcription) => `${accountId}/${subcription.id}/${subcription.name}`));
|
filters.push(...selectedSubscriptionsCache[accountId].map((subcription) => `${accountId}/${subcription.id}/${subcription.name}`));
|
||||||
}
|
}
|
||||||
|
|
||||||
const resourceFilterConfig = this._config.inspect<string[]>(AzureResourceSubscriptionFilterService.filterConfigName);
|
|
||||||
let configTarget = ConfigurationTarget.Global;
|
|
||||||
if (resourceFilterConfig) {
|
|
||||||
if (resourceFilterConfig.workspaceFolderValue) {
|
|
||||||
configTarget = ConfigurationTarget.WorkspaceFolder;
|
|
||||||
} else if (resourceFilterConfig.workspaceValue) {
|
|
||||||
configTarget = ConfigurationTarget.Workspace;
|
|
||||||
} else if (resourceFilterConfig.globalValue) {
|
|
||||||
configTarget = ConfigurationTarget.Global;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
await this._config.update(AzureResourceSubscriptionFilterService.filterConfigName, filters, configTarget);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private _config: WorkspaceConfiguration = undefined;
|
|
||||||
private _cacheService: IAzureResourceCacheService = undefined;
|
private _cacheService: IAzureResourceCacheService = undefined;
|
||||||
private _cacheKey: string = undefined;
|
private _cacheKey: string = undefined;
|
||||||
|
|
||||||
private static readonly filterConfigName = 'azure.resource.config.filter';
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
import * as nls from 'vscode-nls';
|
import * as nls from 'vscode-nls';
|
||||||
const localize = nls.loadMessageBundle();
|
const localize = nls.loadMessageBundle();
|
||||||
|
|
||||||
import { ExtensionContext, workspace, window, Disposable, commands, OutputChannel } from 'vscode'; // {{SQL CARBON EDIT}} - remove unused imports
|
import { ExtensionContext, workspace, window, Disposable, commands, OutputChannel, Uri } from 'vscode';
|
||||||
import { findGit, Git, IGit } from './git';
|
import { findGit, Git, IGit } from './git';
|
||||||
import { Model } from './model';
|
import { Model } from './model';
|
||||||
import { CommandCenter } from './commands';
|
import { CommandCenter } from './commands';
|
||||||
@@ -78,7 +78,7 @@ async function createModel(context: ExtensionContext, outputChannel: OutputChann
|
|||||||
new GitTimelineProvider(model)
|
new GitTimelineProvider(model)
|
||||||
);
|
);
|
||||||
|
|
||||||
await checkGitVersion(info);
|
// await checkGitVersion(info); {{SQL CARBON EDIT}} Don't check git version
|
||||||
|
|
||||||
return model;
|
return model;
|
||||||
}
|
}
|
||||||
@@ -180,13 +180,8 @@ export async function activate(context: ExtensionContext): Promise<GitExtension>
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
async function checkGitVersion(_info: IGit): Promise<void> { // {{SQL CARBON EDIT}} - Rename info to _info to prevent error due to unused variable
|
// @ts-expect-error
|
||||||
return; /* {{SQL CARBON EDIT}} return immediately
|
async function checkGitVersion(info: IGit): Promise<void> {
|
||||||
|
|
||||||
/*const config = workspace.getConfiguration('git');
|
|
||||||
const shouldIgnore = config.get<boolean>('ignoreLegacyWarning') === true;
|
|
||||||
|
|
||||||
|
|
||||||
const config = workspace.getConfiguration('git');
|
const config = workspace.getConfiguration('git');
|
||||||
const shouldIgnore = config.get<boolean>('ignoreLegacyWarning') === true;
|
const shouldIgnore = config.get<boolean>('ignoreLegacyWarning') === true;
|
||||||
|
|
||||||
@@ -211,5 +206,5 @@ async function checkGitVersion(_info: IGit): Promise<void> { // {{SQL CARBON EDI
|
|||||||
commands.executeCommand('vscode.open', Uri.parse('https://git-scm.com/'));
|
commands.executeCommand('vscode.open', Uri.parse('https://git-scm.com/'));
|
||||||
} else if (choice === neverShowAgain) {
|
} else if (choice === neverShowAgain) {
|
||||||
await config.update('ignoreLegacyWarning', true, true);
|
await config.update('ignoreLegacyWarning', true, true);
|
||||||
}*/
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,13 +28,11 @@
|
|||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/chai": "3.4.34",
|
"@types/chai": "3.4.34",
|
||||||
"@types/node": "^10.14.8",
|
"@types/node": "^10.14.8",
|
||||||
|
"azure-keyvault": "^3.0.4",
|
||||||
"chai": "3.5.0",
|
"chai": "3.5.0",
|
||||||
"mocha-junit-reporter": "^1.17.0",
|
"mocha-junit-reporter": "^1.17.0",
|
||||||
"mocha-multi-reporters": "^1.1.7",
|
"mocha-multi-reporters": "^1.1.7",
|
||||||
|
"ms-rest-azure": "^2.6.0",
|
||||||
"vscode": "1.1.5"
|
"vscode": "1.1.5"
|
||||||
},
|
|
||||||
"dependencies": {
|
|
||||||
"azure-keyvault": "^3.0.4",
|
|
||||||
"ms-rest-azure": "^2.6.0"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -478,17 +478,7 @@
|
|||||||
{
|
{
|
||||||
"displayName": "%databasesListProperties.name%",
|
"displayName": "%databasesListProperties.name%",
|
||||||
"value": "name",
|
"value": "name",
|
||||||
"widthWeight": 60
|
"widthWeight": 100
|
||||||
},
|
|
||||||
{
|
|
||||||
"displayName": "%databasesListProperties.status%",
|
|
||||||
"value": "state",
|
|
||||||
"widthWeight": 20
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"displayName": "%databasesListProperties.size%",
|
|
||||||
"value": "sizeInMB",
|
|
||||||
"widthWeight": 20
|
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@@ -1099,7 +1089,7 @@
|
|||||||
"figures": "^2.0.0",
|
"figures": "^2.0.0",
|
||||||
"find-remove": "1.2.1",
|
"find-remove": "1.2.1",
|
||||||
"request": "^2.88.0",
|
"request": "^2.88.0",
|
||||||
"request-promise": "^4.2.2",
|
"request-light": "^0.3.0",
|
||||||
"service-downloader": "0.2.1",
|
"service-downloader": "0.2.1",
|
||||||
"stream-meter": "^1.0.4",
|
"stream-meter": "^1.0.4",
|
||||||
"through2": "^3.0.1",
|
"through2": "^3.0.1",
|
||||||
@@ -1113,7 +1103,6 @@
|
|||||||
"@types/chai": "^4.2.11",
|
"@types/chai": "^4.2.11",
|
||||||
"@types/mocha": "^7.0.2",
|
"@types/mocha": "^7.0.2",
|
||||||
"@types/request": "^2.48.2",
|
"@types/request": "^2.48.2",
|
||||||
"@types/request-promise": "^4.1.44",
|
|
||||||
"@types/stream-meter": "^0.0.22",
|
"@types/stream-meter": "^0.0.22",
|
||||||
"@types/through2": "^2.0.34",
|
"@types/through2": "^2.0.34",
|
||||||
"chai": "^4.2.0",
|
"chai": "^4.2.0",
|
||||||
|
|||||||
@@ -37,15 +37,14 @@ export class SparkJobSubmissionModel {
|
|||||||
constructor(
|
constructor(
|
||||||
private readonly _sqlClusterConnection: SqlClusterConnection,
|
private readonly _sqlClusterConnection: SqlClusterConnection,
|
||||||
private readonly _dialog: azdata.window.Dialog,
|
private readonly _dialog: azdata.window.Dialog,
|
||||||
private readonly _appContext: AppContext,
|
private readonly _appContext: AppContext) {
|
||||||
requestService?: typeof import('request-promise')) {
|
|
||||||
|
|
||||||
if (!this._sqlClusterConnection || !this._dialog || !this._appContext) {
|
if (!this._sqlClusterConnection || !this._dialog || !this._appContext) {
|
||||||
throw new Error(localize('sparkJobSubmission.SparkJobSubmissionModelInitializeError',
|
throw new Error(localize('sparkJobSubmission.SparkJobSubmissionModelInitializeError',
|
||||||
"Parameters for SparkJobSubmissionModel is illegal"));
|
"Parameters for SparkJobSubmissionModel is illegal"));
|
||||||
}
|
}
|
||||||
|
|
||||||
this._dialogService = new SparkJobSubmissionService(requestService);
|
this._dialogService = new SparkJobSubmissionService();
|
||||||
this._guidForClusterFolder = utils.generateGuid();
|
this._guidForClusterFolder = utils.generateGuid();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -10,21 +10,9 @@ import * as constants from '../../../constants';
|
|||||||
import { SqlClusterConnection } from '../../../objectExplorerNodeProvider/connection';
|
import { SqlClusterConnection } from '../../../objectExplorerNodeProvider/connection';
|
||||||
import * as utils from '../../../utils';
|
import * as utils from '../../../utils';
|
||||||
import * as auth from '../../../util/auth';
|
import * as auth from '../../../util/auth';
|
||||||
import { Options } from 'request-promise';
|
import * as request from 'request-light';
|
||||||
|
|
||||||
export class SparkJobSubmissionService {
|
export class SparkJobSubmissionService {
|
||||||
private _requestPromise: typeof import('request-promise');
|
|
||||||
|
|
||||||
constructor(
|
|
||||||
requestService?: typeof import('request-promise')) {
|
|
||||||
if (requestService) {
|
|
||||||
// this is to fake the request service for test.
|
|
||||||
this._requestPromise = requestService;
|
|
||||||
} else {
|
|
||||||
this._requestPromise = require('request-promise');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public async submitBatchJob(submissionArgs: SparkJobSubmissionInput): Promise<string> {
|
public async submitBatchJob(submissionArgs: SparkJobSubmissionInput): Promise<string> {
|
||||||
try {
|
try {
|
||||||
let livyUrl: string = `https://${submissionArgs.host}:${submissionArgs.port}${submissionArgs.livyPath}/`;
|
let livyUrl: string = `https://${submissionArgs.host}:${submissionArgs.port}${submissionArgs.livyPath}/`;
|
||||||
@@ -32,12 +20,11 @@ export class SparkJobSubmissionService {
|
|||||||
// Get correct authentication headers
|
// Get correct authentication headers
|
||||||
let headers = await this.getAuthenticationHeaders(submissionArgs);
|
let headers = await this.getAuthenticationHeaders(submissionArgs);
|
||||||
|
|
||||||
let options: Options = {
|
let options: request.XHROptions = {
|
||||||
uri: livyUrl,
|
url: livyUrl,
|
||||||
method: 'POST',
|
type: 'POST',
|
||||||
json: true,
|
strictSSL: !auth.getIgnoreSslVerificationConfigSetting(),
|
||||||
rejectUnauthorized: !auth.getIgnoreSslVerificationConfigSetting(),
|
data: {
|
||||||
body: {
|
|
||||||
file: submissionArgs.sparkFile,
|
file: submissionArgs.sparkFile,
|
||||||
proxyUser: submissionArgs.user,
|
proxyUser: submissionArgs.user,
|
||||||
className: submissionArgs.mainClass,
|
className: submissionArgs.mainClass,
|
||||||
@@ -51,7 +38,7 @@ export class SparkJobSubmissionService {
|
|||||||
if (submissionArgs.jobArguments && submissionArgs.jobArguments.trim()) {
|
if (submissionArgs.jobArguments && submissionArgs.jobArguments.trim()) {
|
||||||
let argsList = submissionArgs.jobArguments.split(' ');
|
let argsList = submissionArgs.jobArguments.split(' ');
|
||||||
if (argsList.length > 0) {
|
if (argsList.length > 0) {
|
||||||
options.body['args'] = argsList;
|
options.data['args'] = argsList;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -59,7 +46,7 @@ export class SparkJobSubmissionService {
|
|||||||
if (submissionArgs.jarFileList && submissionArgs.jarFileList.trim()) {
|
if (submissionArgs.jarFileList && submissionArgs.jarFileList.trim()) {
|
||||||
let jarList = submissionArgs.jarFileList.split(';');
|
let jarList = submissionArgs.jarFileList.split(';');
|
||||||
if (jarList.length > 0) {
|
if (jarList.length > 0) {
|
||||||
options.body['jars'] = jarList;
|
options.data['jars'] = jarList;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -67,7 +54,7 @@ export class SparkJobSubmissionService {
|
|||||||
if (submissionArgs.pyFileList && submissionArgs.pyFileList.trim()) {
|
if (submissionArgs.pyFileList && submissionArgs.pyFileList.trim()) {
|
||||||
let pyList = submissionArgs.pyFileList.split(';');
|
let pyList = submissionArgs.pyFileList.split(';');
|
||||||
if (pyList.length > 0) {
|
if (pyList.length > 0) {
|
||||||
options.body['pyFiles'] = pyList;
|
options.data['pyFiles'] = pyList;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -75,11 +62,17 @@ export class SparkJobSubmissionService {
|
|||||||
if (submissionArgs.otherFileList && submissionArgs.otherFileList.trim()) {
|
if (submissionArgs.otherFileList && submissionArgs.otherFileList.trim()) {
|
||||||
let otherList = submissionArgs.otherFileList.split(';');
|
let otherList = submissionArgs.otherFileList.split(';');
|
||||||
if (otherList.length > 0) {
|
if (otherList.length > 0) {
|
||||||
options.body['files'] = otherList;
|
options.data['files'] = otherList;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const response = await this._requestPromise(options);
|
options.data = JSON.stringify(options.data);
|
||||||
|
|
||||||
|
// Note this is currently required to be called each time since request-light is overwriting
|
||||||
|
// the setting passed in through the options. If/when that gets fixed this can be removed
|
||||||
|
request.configure(null, !auth.getIgnoreSslVerificationConfigSetting());
|
||||||
|
|
||||||
|
const response = JSON.parse((await request.xhr(options)).responseText);
|
||||||
if (response && utils.isValidNumber(response.id)) {
|
if (response && utils.isValidNumber(response.id)) {
|
||||||
return response.id;
|
return response.id;
|
||||||
}
|
}
|
||||||
@@ -108,16 +101,19 @@ export class SparkJobSubmissionService {
|
|||||||
let livyUrl = `https://${submissionArgs.host}:${submissionArgs.port}${submissionArgs.livyPath}/${livyBatchId}/log`;
|
let livyUrl = `https://${submissionArgs.host}:${submissionArgs.port}${submissionArgs.livyPath}/${livyBatchId}/log`;
|
||||||
let headers = await this.getAuthenticationHeaders(submissionArgs);
|
let headers = await this.getAuthenticationHeaders(submissionArgs);
|
||||||
|
|
||||||
let options = {
|
let options: request.XHROptions = {
|
||||||
uri: livyUrl,
|
url: livyUrl,
|
||||||
method: 'GET',
|
type: 'GET',
|
||||||
json: true,
|
strictSSL: !auth.getIgnoreSslVerificationConfigSetting(),
|
||||||
rejectUnauthorized: !auth.getIgnoreSslVerificationConfigSetting(),
|
|
||||||
// authentication headers
|
// authentication headers
|
||||||
headers: headers
|
headers: headers
|
||||||
};
|
};
|
||||||
|
|
||||||
const response = await this._requestPromise(options);
|
// Note this is currently required to be called each time since request-light is overwriting
|
||||||
|
// the setting passed in through the options. If/when that gets fixed this can be removed
|
||||||
|
request.configure(null, !auth.getIgnoreSslVerificationConfigSetting());
|
||||||
|
|
||||||
|
const response = JSON.parse((await request.xhr(options)).responseText);
|
||||||
if (response && response.log) {
|
if (response && response.log) {
|
||||||
return this.extractYarnAppIdFromLog(response.log);
|
return this.extractYarnAppIdFromLog(response.log);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,11 +2,6 @@
|
|||||||
# yarn lockfile v1
|
# yarn lockfile v1
|
||||||
|
|
||||||
|
|
||||||
"@types/bluebird@*":
|
|
||||||
version "3.5.30"
|
|
||||||
resolved "https://registry.yarnpkg.com/@types/bluebird/-/bluebird-3.5.30.tgz#ee034a0eeea8b84ed868b1aa60d690b08a6cfbc5"
|
|
||||||
integrity sha512-8LhzvcjIoqoi1TghEkRMkbbmM+jhHnBokPGkJWjclMK+Ks0MxEBow3/p2/iFTZ+OIbJHQDSfpgdZEb+af3gfVw==
|
|
||||||
|
|
||||||
"@types/bytes@^3.0.0":
|
"@types/bytes@^3.0.0":
|
||||||
version "3.1.0"
|
version "3.1.0"
|
||||||
resolved "https://registry.yarnpkg.com/@types/bytes/-/bytes-3.1.0.tgz#835a3e4aea3b4d7604aca216a78de372bff3ecc3"
|
resolved "https://registry.yarnpkg.com/@types/bytes/-/bytes-3.1.0.tgz#835a3e4aea3b4d7604aca216a78de372bff3ecc3"
|
||||||
@@ -32,15 +27,7 @@
|
|||||||
resolved "https://registry.yarnpkg.com/@types/node/-/node-13.11.1.tgz#49a2a83df9d26daacead30d0ccc8762b128d53c7"
|
resolved "https://registry.yarnpkg.com/@types/node/-/node-13.11.1.tgz#49a2a83df9d26daacead30d0ccc8762b128d53c7"
|
||||||
integrity sha512-eWQGP3qtxwL8FGneRrC5DwrJLGN4/dH1clNTuLfN81HCrxVtxRjygDTUoZJ5ASlDEeo0ppYFQjQIlXhtXpOn6g==
|
integrity sha512-eWQGP3qtxwL8FGneRrC5DwrJLGN4/dH1clNTuLfN81HCrxVtxRjygDTUoZJ5ASlDEeo0ppYFQjQIlXhtXpOn6g==
|
||||||
|
|
||||||
"@types/request-promise@^4.1.44":
|
"@types/request@^2.48.2":
|
||||||
version "4.1.46"
|
|
||||||
resolved "https://registry.yarnpkg.com/@types/request-promise/-/request-promise-4.1.46.tgz#37df6efae984316dfbfbbe8fcda37f3ba52822f2"
|
|
||||||
integrity sha512-3Thpj2Va5m0ji3spaCk8YKrjkZyZc6RqUVOphA0n/Xet66AW/AiOAs5vfXhQIL5NmkaO7Jnun7Nl9NEjJ2zBaw==
|
|
||||||
dependencies:
|
|
||||||
"@types/bluebird" "*"
|
|
||||||
"@types/request" "*"
|
|
||||||
|
|
||||||
"@types/request@*", "@types/request@^2.48.2":
|
|
||||||
version "2.48.4"
|
version "2.48.4"
|
||||||
resolved "https://registry.yarnpkg.com/@types/request/-/request-2.48.4.tgz#df3d43d7b9ed3550feaa1286c6eabf0738e6cf7e"
|
resolved "https://registry.yarnpkg.com/@types/request/-/request-2.48.4.tgz#df3d43d7b9ed3550feaa1286c6eabf0738e6cf7e"
|
||||||
integrity sha512-W1t1MTKYR8PxICH+A4HgEIPuAC3sbljoEVfyZbeFJJDbr30guDspJri2XOaM2E+Un7ZjrihaDi7cf6fPa2tbgw==
|
integrity sha512-W1t1MTKYR8PxICH+A4HgEIPuAC3sbljoEVfyZbeFJJDbr30guDspJri2XOaM2E+Un7ZjrihaDi7cf6fPa2tbgw==
|
||||||
@@ -257,11 +244,6 @@ binary-extensions@^2.0.0:
|
|||||||
resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.0.0.tgz#23c0df14f6a88077f5f986c0d167ec03c3d5537c"
|
resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.0.0.tgz#23c0df14f6a88077f5f986c0d167ec03c3d5537c"
|
||||||
integrity sha512-Phlt0plgpIIBOGTT/ehfFnbNlfsDEiqmzE2KRXoX1bLIlir4X/MR+zSyBEkL05ffWgnRSf/DXv+WrUAVr93/ow==
|
integrity sha512-Phlt0plgpIIBOGTT/ehfFnbNlfsDEiqmzE2KRXoX1bLIlir4X/MR+zSyBEkL05ffWgnRSf/DXv+WrUAVr93/ow==
|
||||||
|
|
||||||
bluebird@^3.5.0:
|
|
||||||
version "3.7.2"
|
|
||||||
resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.7.2.tgz#9f229c15be272454ffa973ace0dbee79a1b0c36f"
|
|
||||||
integrity sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==
|
|
||||||
|
|
||||||
brace-expansion@^1.1.7:
|
brace-expansion@^1.1.7:
|
||||||
version "1.1.11"
|
version "1.1.11"
|
||||||
resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd"
|
resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd"
|
||||||
@@ -893,7 +875,7 @@ http-signature@~1.2.0:
|
|||||||
jsprim "^1.2.2"
|
jsprim "^1.2.2"
|
||||||
sshpk "^1.7.0"
|
sshpk "^1.7.0"
|
||||||
|
|
||||||
https-proxy-agent@^2.2.3:
|
https-proxy-agent@^2.2.3, https-proxy-agent@^2.2.4:
|
||||||
version "2.2.4"
|
version "2.2.4"
|
||||||
resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-2.2.4.tgz#4ee7a737abd92678a293d9b34a1af4d0d08c787b"
|
resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-2.2.4.tgz#4ee7a737abd92678a293d9b34a1af4d0d08c787b"
|
||||||
integrity sha512-OmvfoQ53WLjtA9HeYP9RNrWMJzzAz1JGaSFr1nijg0PVR1JaD/xbJq1mdEIIlxGpXp9eSe/O2LgU9DJmTPd0Eg==
|
integrity sha512-OmvfoQ53WLjtA9HeYP9RNrWMJzzAz1JGaSFr1nijg0PVR1JaD/xbJq1mdEIIlxGpXp9eSe/O2LgU9DJmTPd0Eg==
|
||||||
@@ -1493,22 +1475,14 @@ remap-istanbul@^0.11.1:
|
|||||||
source-map "^0.6.1"
|
source-map "^0.6.1"
|
||||||
through2 "2.0.1"
|
through2 "2.0.1"
|
||||||
|
|
||||||
request-promise-core@1.1.3:
|
request-light@^0.3.0:
|
||||||
version "1.1.3"
|
version "0.3.0"
|
||||||
resolved "https://registry.yarnpkg.com/request-promise-core/-/request-promise-core-1.1.3.tgz#e9a3c081b51380dfea677336061fea879a829ee9"
|
resolved "https://registry.yarnpkg.com/request-light/-/request-light-0.3.0.tgz#04daa783e7f0a70392328dda4b546f3e27845f2d"
|
||||||
integrity sha512-QIs2+ArIGQVp5ZYbWD5ZLCY29D5CfWizP8eWnm8FoGD1TX61veauETVQbrV60662V0oFBkrDOuaBI8XgtuyYAQ==
|
integrity sha512-xlVlZVT0ZvCT+c3zm3SjeFCzchoQxsUUmx5fkal0I6RIDJK+lmb1UYyKJ7WM4dTfnzHP4ElWwAf8Dli8c0/tVA==
|
||||||
dependencies:
|
dependencies:
|
||||||
lodash "^4.17.15"
|
http-proxy-agent "^2.1.0"
|
||||||
|
https-proxy-agent "^2.2.4"
|
||||||
request-promise@^4.2.2:
|
vscode-nls "^4.1.1"
|
||||||
version "4.2.5"
|
|
||||||
resolved "https://registry.yarnpkg.com/request-promise/-/request-promise-4.2.5.tgz#186222c59ae512f3497dfe4d75a9c8461bd0053c"
|
|
||||||
integrity sha512-ZgnepCykFdmpq86fKGwqntyTiUrHycALuGggpyCZwMvGaZWgxW6yagT0FHkgo5LzYvOaCNvxYwWYIjevSH1EDg==
|
|
||||||
dependencies:
|
|
||||||
bluebird "^3.5.0"
|
|
||||||
request-promise-core "1.1.3"
|
|
||||||
stealthy-require "^1.1.1"
|
|
||||||
tough-cookie "^2.3.3"
|
|
||||||
|
|
||||||
request@^2.88.0:
|
request@^2.88.0:
|
||||||
version "2.88.2"
|
version "2.88.2"
|
||||||
@@ -1642,11 +1616,6 @@ sshpk@^1.7.0:
|
|||||||
safer-buffer "^2.0.2"
|
safer-buffer "^2.0.2"
|
||||||
tweetnacl "~0.14.0"
|
tweetnacl "~0.14.0"
|
||||||
|
|
||||||
stealthy-require@^1.1.1:
|
|
||||||
version "1.1.1"
|
|
||||||
resolved "https://registry.yarnpkg.com/stealthy-require/-/stealthy-require-1.1.1.tgz#35b09875b4ff49f26a777e509b3090a3226bf24b"
|
|
||||||
integrity sha1-NbCYdbT/SfJqd35QmzCQoyJr8ks=
|
|
||||||
|
|
||||||
stream-meter@^1.0.4:
|
stream-meter@^1.0.4:
|
||||||
version "1.0.4"
|
version "1.0.4"
|
||||||
resolved "https://registry.yarnpkg.com/stream-meter/-/stream-meter-1.0.4.tgz#52af95aa5ea760a2491716704dbff90f73afdd1d"
|
resolved "https://registry.yarnpkg.com/stream-meter/-/stream-meter-1.0.4.tgz#52af95aa5ea760a2491716704dbff90f73afdd1d"
|
||||||
@@ -1812,14 +1781,6 @@ to-regex-range@^5.0.1:
|
|||||||
dependencies:
|
dependencies:
|
||||||
is-number "^7.0.0"
|
is-number "^7.0.0"
|
||||||
|
|
||||||
tough-cookie@^2.3.3, tough-cookie@~2.5.0:
|
|
||||||
version "2.5.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.5.0.tgz#cd9fb2a0aa1d5a12b473bd9fb96fa3dcff65ade2"
|
|
||||||
integrity sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==
|
|
||||||
dependencies:
|
|
||||||
psl "^1.1.28"
|
|
||||||
punycode "^2.1.1"
|
|
||||||
|
|
||||||
tough-cookie@^3.0.1:
|
tough-cookie@^3.0.1:
|
||||||
version "3.0.1"
|
version "3.0.1"
|
||||||
resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-3.0.1.tgz#9df4f57e739c26930a018184887f4adb7dca73b2"
|
resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-3.0.1.tgz#9df4f57e739c26930a018184887f4adb7dca73b2"
|
||||||
@@ -1829,6 +1790,14 @@ tough-cookie@^3.0.1:
|
|||||||
psl "^1.1.28"
|
psl "^1.1.28"
|
||||||
punycode "^2.1.1"
|
punycode "^2.1.1"
|
||||||
|
|
||||||
|
tough-cookie@~2.5.0:
|
||||||
|
version "2.5.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.5.0.tgz#cd9fb2a0aa1d5a12b473bd9fb96fa3dcff65ade2"
|
||||||
|
integrity sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==
|
||||||
|
dependencies:
|
||||||
|
psl "^1.1.28"
|
||||||
|
punycode "^2.1.1"
|
||||||
|
|
||||||
tunnel-agent@^0.6.0:
|
tunnel-agent@^0.6.0:
|
||||||
version "0.6.0"
|
version "0.6.0"
|
||||||
resolved "https://registry.yarnpkg.com/tunnel-agent/-/tunnel-agent-0.6.0.tgz#27a5dea06b36b04a0a9966774b290868f0fc40fd"
|
resolved "https://registry.yarnpkg.com/tunnel-agent/-/tunnel-agent-0.6.0.tgz#27a5dea06b36b04a0a9966774b290868f0fc40fd"
|
||||||
@@ -1928,7 +1897,7 @@ vscode-languageserver-types@3.14.0:
|
|||||||
resolved "https://registry.yarnpkg.com/vscode-languageserver-types/-/vscode-languageserver-types-3.14.0.tgz#d3b5952246d30e5241592b6dde8280e03942e743"
|
resolved "https://registry.yarnpkg.com/vscode-languageserver-types/-/vscode-languageserver-types-3.14.0.tgz#d3b5952246d30e5241592b6dde8280e03942e743"
|
||||||
integrity sha512-lTmS6AlAlMHOvPQemVwo3CezxBp0sNB95KNPkqp3Nxd5VFEnuG1ByM0zlRWos0zjO3ZWtkvhal0COgiV1xIA4A==
|
integrity sha512-lTmS6AlAlMHOvPQemVwo3CezxBp0sNB95KNPkqp3Nxd5VFEnuG1ByM0zlRWos0zjO3ZWtkvhal0COgiV1xIA4A==
|
||||||
|
|
||||||
vscode-nls@^4.0.0:
|
vscode-nls@^4.0.0, vscode-nls@^4.1.1:
|
||||||
version "4.1.2"
|
version "4.1.2"
|
||||||
resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-4.1.2.tgz#ca8bf8bb82a0987b32801f9fddfdd2fb9fd3c167"
|
resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-4.1.2.tgz#ca8bf8bb82a0987b32801f9fddfdd2fb9fd3c167"
|
||||||
integrity sha512-7bOHxPsfyuCqmP+hZXscLhiHwe7CSuFE4hyhbs22xPIhQ4jv99FcR4eBzfYYVLP356HNFpdvz63FFb/xw6T4Iw==
|
integrity sha512-7bOHxPsfyuCqmP+hZXscLhiHwe7CSuFE4hyhbs22xPIhQ4jv99FcR4eBzfYYVLP356HNFpdvz63FFb/xw6T4Iw==
|
||||||
|
|||||||
@@ -114,6 +114,7 @@ export class BookTreeViewProvider implements vscode.TreeDataProvider<BookTreeIte
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (showPreview) {
|
if (showPreview) {
|
||||||
|
this._bookViewer.reveal(this.currentBook.bookItems[0], { expand: vscode.TreeItemCollapsibleState.Expanded, focus: true, select: true });
|
||||||
await this.showPreviewFile(urlToOpen);
|
await this.showPreviewFile(urlToOpen);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -134,6 +134,7 @@ export class ConfigurePathPage extends BasePage {
|
|||||||
checked: !useExistingPython
|
checked: !useExistingPython
|
||||||
}).component();
|
}).component();
|
||||||
this.newInstallButton.onDidClick(() => {
|
this.newInstallButton.onDidClick(() => {
|
||||||
|
this.existingInstallButton.checked = false;
|
||||||
this.updatePythonPathsDropdown(false)
|
this.updatePythonPathsDropdown(false)
|
||||||
.catch(err => {
|
.catch(err => {
|
||||||
this.instance.showErrorMessage(utils.getErrorMessage(err));
|
this.instance.showErrorMessage(utils.getErrorMessage(err));
|
||||||
@@ -147,6 +148,7 @@ export class ConfigurePathPage extends BasePage {
|
|||||||
checked: useExistingPython
|
checked: useExistingPython
|
||||||
}).component();
|
}).component();
|
||||||
this.existingInstallButton.onDidClick(() => {
|
this.existingInstallButton.onDidClick(() => {
|
||||||
|
this.newInstallButton.checked = false;
|
||||||
this.updatePythonPathsDropdown(true)
|
this.updatePythonPathsDropdown(true)
|
||||||
.catch(err => {
|
.catch(err => {
|
||||||
this.instance.showErrorMessage(utils.getErrorMessage(err));
|
this.instance.showErrorMessage(utils.getErrorMessage(err));
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
"If you want to provide a fix or improvement, please create a pull request against the original repository.",
|
"If you want to provide a fix or improvement, please create a pull request against the original repository.",
|
||||||
"Once accepted there, we are happy to receive an update request."
|
"Once accepted there, we are happy to receive an update request."
|
||||||
],
|
],
|
||||||
"version": "https://github.com/Microsoft/vscode-mssql/commit/a542fe96780e6b274adb281810d419a512fb5bb4",
|
"version": "https://github.com/Microsoft/vscode-mssql/commit/a79741f76fd33bd137a8c28172c9750b978309b6",
|
||||||
"name": "SQL",
|
"name": "SQL",
|
||||||
"scopeName": "source.sql",
|
"scopeName": "source.sql",
|
||||||
"patterns": [
|
"patterns": [
|
||||||
@@ -404,7 +404,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"comment": "this is faster than the next begin/end rule since sub-pattern will match till end-of-line and SQL files tend to have very long lines.",
|
"comment": "this is faster than the next begin/end rule since sub-pattern will match till end-of-line and SQL files tend to have very long lines.",
|
||||||
"match": "(N)?(')(?:[^'\\\\]|\\\\.)*(')",
|
"match": "(N)?(')[^']*(')",
|
||||||
"name": "string.quoted.single.sql"
|
"name": "string.quoted.single.sql"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -437,7 +437,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"comment": "this is faster than the next begin/end rule since sub-pattern will match till end-of-line and SQL files tend to have very long lines.",
|
"comment": "this is faster than the next begin/end rule since sub-pattern will match till end-of-line and SQL files tend to have very long lines.",
|
||||||
"match": "(`)(?:[^`\\\\]|\\\\.)*(`)",
|
"match": "(`)[^`\\\\]*(`)",
|
||||||
"name": "string.quoted.other.backtick.sql"
|
"name": "string.quoted.other.backtick.sql"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -470,7 +470,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"comment": "this is faster than the next begin/end rule since sub-pattern will match till end-of-line and SQL files tend to have very long lines.",
|
"comment": "this is faster than the next begin/end rule since sub-pattern will match till end-of-line and SQL files tend to have very long lines.",
|
||||||
"match": "(\")(?:[^\"#\\\\]|\\\\.)*(\")",
|
"match": "(\")[^\"#]*(\")",
|
||||||
"name": "string.quoted.double.sql"
|
"name": "string.quoted.double.sql"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "azuredatastudio",
|
"name": "azuredatastudio",
|
||||||
"version": "1.18.0",
|
"version": "1.18.1",
|
||||||
"distro": "1a99144c4c1f884810b37cdc9be608372e99d168",
|
"distro": "a04ebf32a5868f2bc7a4eed0716a42564d2a7896",
|
||||||
"author": {
|
"author": {
|
||||||
"name": "Microsoft Corporation"
|
"name": "Microsoft Corporation"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -69,7 +69,7 @@
|
|||||||
"builtInExtensions": [
|
"builtInExtensions": [
|
||||||
{
|
{
|
||||||
"name": "Microsoft.sqlservernotebook",
|
"name": "Microsoft.sqlservernotebook",
|
||||||
"version": "0.3.6",
|
"version": "0.3.7",
|
||||||
"repo": "https://github.com/Microsoft/azuredatastudio"
|
"repo": "https://github.com/Microsoft/azuredatastudio"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -12,28 +12,6 @@ import { IConnectionProfile } from 'sql/platform/connection/common/interfaces';
|
|||||||
import { ConnectionManagementInfo } from 'sql/platform/connection/common/connectionManagementInfo';
|
import { ConnectionManagementInfo } from 'sql/platform/connection/common/connectionManagementInfo';
|
||||||
import { ConnectionProviderProperties } from 'sql/platform/capabilities/common/capabilitiesService';
|
import { ConnectionProviderProperties } from 'sql/platform/capabilities/common/capabilitiesService';
|
||||||
|
|
||||||
/**
|
|
||||||
* A range in the editor. This interface is suitable for serialization.
|
|
||||||
*/
|
|
||||||
export interface IRange {
|
|
||||||
/**
|
|
||||||
* Line number on which the range starts (starts at 1).
|
|
||||||
*/
|
|
||||||
readonly startLineNumber: number;
|
|
||||||
/**
|
|
||||||
* Column on which the range starts in line `startLineNumber` (starts at 1).
|
|
||||||
*/
|
|
||||||
readonly startColumn: number;
|
|
||||||
/**
|
|
||||||
* Line number on which the range ends.
|
|
||||||
*/
|
|
||||||
readonly endLineNumber: number;
|
|
||||||
/**
|
|
||||||
* Column on which the range ends in line `endLineNumber`.
|
|
||||||
*/
|
|
||||||
readonly endColumn: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Options for the actions that could happen after connecting is complete
|
* Options for the actions that could happen after connecting is complete
|
||||||
*/
|
*/
|
||||||
@@ -324,10 +302,11 @@ export interface INewConnectionParams {
|
|||||||
connectionType: ConnectionType;
|
connectionType: ConnectionType;
|
||||||
input?: IConnectableInput;
|
input?: IConnectableInput;
|
||||||
runQueryOnCompletion?: RunQueryOnConnectionMode;
|
runQueryOnCompletion?: RunQueryOnConnectionMode;
|
||||||
queryRange?: IRange;
|
querySelection?: azdata.ISelectionData;
|
||||||
showDashboard?: boolean;
|
showDashboard?: boolean;
|
||||||
providers?: string[];
|
providers?: string[];
|
||||||
isEditConnection?: boolean;
|
isEditConnection?: boolean;
|
||||||
|
oldProfileId?: string; // used for edit connection
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IConnectableInput {
|
export interface IConnectableInput {
|
||||||
|
|||||||
@@ -324,6 +324,8 @@ export class ExtHostDataProtocol extends ExtHostDataProtocolShape {
|
|||||||
if (this.uriTransformer) {
|
if (this.uriTransformer) {
|
||||||
batchInfo.ownerUri = URI.from(this.uriTransformer.transformOutgoing(URI.parse(batchInfo.ownerUri))).toString(true);
|
batchInfo.ownerUri = URI.from(this.uriTransformer.transformOutgoing(URI.parse(batchInfo.ownerUri))).toString(true);
|
||||||
}
|
}
|
||||||
|
this.messageRunner.cancel(); // clear batch messages before saying we completed the batch
|
||||||
|
this.sendMessages();
|
||||||
this._proxy.$onBatchComplete(handle, batchInfo);
|
this._proxy.$onBatchComplete(handle, batchInfo);
|
||||||
}
|
}
|
||||||
$onResultSetAvailable(handle: number, resultSetInfo: azdata.QueryExecuteResultSetNotificationParams): void {
|
$onResultSetAvailable(handle: number, resultSetInfo: azdata.QueryExecuteResultSetNotificationParams): void {
|
||||||
|
|||||||
@@ -14,6 +14,8 @@ import * as azdata from 'azdata';
|
|||||||
import { SafeHtml, DomSanitizer } from '@angular/platform-browser';
|
import { SafeHtml, DomSanitizer } from '@angular/platform-browser';
|
||||||
import { TitledComponent } from 'sql/workbench/browser/modelComponents/titledComponent';
|
import { TitledComponent } from 'sql/workbench/browser/modelComponents/titledComponent';
|
||||||
import { IComponentDescriptor, IComponent, IModelStore } from 'sql/platform/dashboard/browser/interfaces';
|
import { IComponentDescriptor, IComponent, IModelStore } from 'sql/platform/dashboard/browser/interfaces';
|
||||||
|
import { registerThemingParticipant, IColorTheme, ICssStyleCollector } from 'vs/platform/theme/common/themeService';
|
||||||
|
import { textLinkForeground, textLinkActiveForeground } from 'vs/platform/theme/common/colorRegistry';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'modelview-text',
|
selector: 'modelview-text',
|
||||||
@@ -99,3 +101,24 @@ export default class TextComponent extends TitledComponent implements IComponent
|
|||||||
return this.requiredIndicator || !!this.description;
|
return this.requiredIndicator || !!this.description;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
registerThemingParticipant((theme: IColorTheme, collector: ICssStyleCollector) => {
|
||||||
|
const linkForeground = theme.getColor(textLinkForeground);
|
||||||
|
if (linkForeground) {
|
||||||
|
collector.addRule(`
|
||||||
|
a.modelview-text-link:link,
|
||||||
|
a.modelview-text-link:visited {
|
||||||
|
color: ${linkForeground};
|
||||||
|
}
|
||||||
|
`);
|
||||||
|
}
|
||||||
|
|
||||||
|
const activeForeground = theme.getColor(textLinkActiveForeground);
|
||||||
|
if (activeForeground) {
|
||||||
|
collector.addRule(`
|
||||||
|
a.modelview-text-link:hover {
|
||||||
|
color: ${activeForeground};
|
||||||
|
}
|
||||||
|
`);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|||||||
@@ -534,7 +534,7 @@ export class TreeView extends Disposable implements ITreeView {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
getActionsContext: () => (<TreeViewItemHandleArg>{ $treeViewId: this.id, $treeItemHandle: node.handle }),
|
getActionsContext: () => (<TreeViewItemHandleArg>{ $treeViewId: this.id, $treeItemHandle: node.handle, $treeItem: node }),
|
||||||
|
|
||||||
actionRunner
|
actionRunner
|
||||||
});
|
});
|
||||||
@@ -860,11 +860,10 @@ class TreeRenderer extends Disposable implements ITreeRenderer<ITreeItem, FuzzyS
|
|||||||
templateData.icon.title = title ? title : '';
|
templateData.icon.title = title ? title : '';
|
||||||
|
|
||||||
if (iconUrl || sqlIcon) {
|
if (iconUrl || sqlIcon) {
|
||||||
|
templateData.icon.className = 'custom-view-tree-node-item-icon';
|
||||||
DOM.toggleClass(templateData.icon, sqlIcon, !!sqlIcon); // tracked change
|
DOM.toggleClass(templateData.icon, sqlIcon, !!sqlIcon); // tracked change
|
||||||
DOM.toggleClass(templateData.icon, 'icon', !!sqlIcon);
|
DOM.toggleClass(templateData.icon, 'icon', !!sqlIcon);
|
||||||
templateData.icon.className = 'custom-view-tree-node-item-icon';
|
|
||||||
templateData.icon.style.backgroundImage = iconUrl ? DOM.asCSSUrl(iconUrl) : '';
|
templateData.icon.style.backgroundImage = iconUrl ? DOM.asCSSUrl(iconUrl) : '';
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
let iconClass: string | undefined;
|
let iconClass: string | undefined;
|
||||||
if (node.themeIcon && !this.isFileKindThemeIcon(node.themeIcon)) {
|
if (node.themeIcon && !this.isFileKindThemeIcon(node.themeIcon)) {
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ const targetDatabaseEngineEditionMap = {
|
|||||||
5: 'SqlAzureDatabaseEdition',
|
5: 'SqlAzureDatabaseEdition',
|
||||||
6: 'SqlDatawarehouseEdition',
|
6: 'SqlDatawarehouseEdition',
|
||||||
7: 'SqlServerStretchEdition',
|
7: 'SqlServerStretchEdition',
|
||||||
11: 'SqlServerSqlOnDemandEdition',
|
11: 'SqlServerOnDemandEdition',
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -14,9 +14,8 @@ import { IConnectionManagementService, IConnectableInput, INewConnectionParams,
|
|||||||
import { QueryResultsInput } from 'sql/workbench/common/editor/query/queryResultsInput';
|
import { QueryResultsInput } from 'sql/workbench/common/editor/query/queryResultsInput';
|
||||||
import { IQueryModelService } from 'sql/workbench/services/query/common/queryModel';
|
import { IQueryModelService } from 'sql/workbench/services/query/common/queryModel';
|
||||||
|
|
||||||
import { ExecutionPlanOptions } from 'azdata';
|
import { ISelectionData, ExecutionPlanOptions } from 'azdata';
|
||||||
import { startsWith } from 'vs/base/common/strings';
|
import { startsWith } from 'vs/base/common/strings';
|
||||||
import { IRange } from 'vs/editor/common/core/range';
|
|
||||||
|
|
||||||
const MAX_SIZE = 13;
|
const MAX_SIZE = 13;
|
||||||
|
|
||||||
@@ -230,13 +229,13 @@ export abstract class QueryEditorInput extends EditorInput implements IConnectab
|
|||||||
}
|
}
|
||||||
|
|
||||||
// State update funtions
|
// State update funtions
|
||||||
public runQuery(range?: IRange, executePlanOptions?: ExecutionPlanOptions): void {
|
public runQuery(selection?: ISelectionData, executePlanOptions?: ExecutionPlanOptions): void {
|
||||||
this.queryModelService.runQuery(this.uri, range, executePlanOptions);
|
this.queryModelService.runQuery(this.uri, selection, executePlanOptions);
|
||||||
this.state.executing = true;
|
this.state.executing = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public runQueryStatement(range?: IRange): void {
|
public runQueryStatement(selection?: ISelectionData): void {
|
||||||
this.queryModelService.runQueryStatement(this.uri, range);
|
this.queryModelService.runQueryStatement(this.uri, selection);
|
||||||
this.state.executing = true;
|
this.state.executing = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -270,15 +269,15 @@ export abstract class QueryEditorInput extends EditorInput implements IConnectab
|
|||||||
|
|
||||||
let isRunningQuery = this.queryModelService.isRunningQuery(this.uri);
|
let isRunningQuery = this.queryModelService.isRunningQuery(this.uri);
|
||||||
if (!isRunningQuery && params && params.runQueryOnCompletion) {
|
if (!isRunningQuery && params && params.runQueryOnCompletion) {
|
||||||
let range: IRange | undefined = params ? params.queryRange : undefined;
|
let selection: ISelectionData | undefined = params ? params.querySelection : undefined;
|
||||||
if (params.runQueryOnCompletion === RunQueryOnConnectionMode.executeCurrentQuery) {
|
if (params.runQueryOnCompletion === RunQueryOnConnectionMode.executeCurrentQuery) {
|
||||||
this.runQueryStatement(range);
|
this.runQueryStatement(selection);
|
||||||
} else if (params.runQueryOnCompletion === RunQueryOnConnectionMode.executeQuery) {
|
} else if (params.runQueryOnCompletion === RunQueryOnConnectionMode.executeQuery) {
|
||||||
this.runQuery(range);
|
this.runQuery(selection);
|
||||||
} else if (params.runQueryOnCompletion === RunQueryOnConnectionMode.estimatedQueryPlan) {
|
} else if (params.runQueryOnCompletion === RunQueryOnConnectionMode.estimatedQueryPlan) {
|
||||||
this.runQuery(range, { displayEstimatedQueryPlan: true });
|
this.runQuery(selection, { displayEstimatedQueryPlan: true });
|
||||||
} else if (params.runQueryOnCompletion === RunQueryOnConnectionMode.actualQueryPlan) {
|
} else if (params.runQueryOnCompletion === RunQueryOnConnectionMode.actualQueryPlan) {
|
||||||
this.runQuery(range, { displayActualQueryPlan: true });
|
this.runQuery(selection, { displayActualQueryPlan: true });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
this._onDidChangeLabel.fire();
|
this._onDidChangeLabel.fire();
|
||||||
|
|||||||
@@ -8,7 +8,6 @@ import 'vs/css!./media/chartView';
|
|||||||
import { IPanelView } from 'sql/base/browser/ui/panel/panel';
|
import { IPanelView } from 'sql/base/browser/ui/panel/panel';
|
||||||
import { Insight } from './insight';
|
import { Insight } from './insight';
|
||||||
import QueryRunner from 'sql/workbench/services/query/common/queryRunner';
|
import QueryRunner from 'sql/workbench/services/query/common/queryRunner';
|
||||||
import { ICellValue } from 'sql/workbench/services/query/common/query';
|
|
||||||
import { ChartOptions, IChartOption, ControlType } from './chartOptions';
|
import { ChartOptions, IChartOption, ControlType } from './chartOptions';
|
||||||
import { Extensions, IInsightRegistry, IInsightData } from 'sql/platform/dashboard/browser/insightRegistry';
|
import { Extensions, IInsightRegistry, IInsightData } from 'sql/platform/dashboard/browser/insightRegistry';
|
||||||
import { Registry } from 'vs/platform/registry/common/platform';
|
import { Registry } from 'vs/platform/registry/common/platform';
|
||||||
@@ -29,6 +28,7 @@ import { ChartState } from 'sql/workbench/common/editor/query/chartState';
|
|||||||
import * as nls from 'vs/nls';
|
import * as nls from 'vs/nls';
|
||||||
import { find } from 'vs/base/common/arrays';
|
import { find } from 'vs/base/common/arrays';
|
||||||
import { INotificationService } from 'vs/platform/notification/common/notification';
|
import { INotificationService } from 'vs/platform/notification/common/notification';
|
||||||
|
import { DbCellValue } from 'azdata';
|
||||||
import { Event, Emitter } from 'vs/base/common/event';
|
import { Event, Emitter } from 'vs/base/common/event';
|
||||||
|
|
||||||
const insightRegistry = Registry.as<IInsightRegistry>(Extensions.InsightContribution);
|
const insightRegistry = Registry.as<IInsightRegistry>(Extensions.InsightContribution);
|
||||||
@@ -213,7 +213,7 @@ export class ChartView extends Disposable implements IPanelView {
|
|||||||
this.shouldGraph();
|
this.shouldGraph();
|
||||||
}
|
}
|
||||||
|
|
||||||
public setData(rows: ICellValue[][], columns: string[]): void {
|
public setData(rows: DbCellValue[][], columns: string[]): void {
|
||||||
if (!rows) {
|
if (!rows) {
|
||||||
this._data = { columns: [], rows: [] };
|
this._data = { columns: [], rows: [] };
|
||||||
this._notificationService.error(nls.localize('charting.failedToGetRows', "Failed to get rows for the dataset to chart."));
|
this._notificationService.error(nls.localize('charting.failedToGetRows', "Failed to get rows for the dataset to chart."));
|
||||||
@@ -238,7 +238,7 @@ export class ChartView extends Disposable implements IPanelView {
|
|||||||
let summary = batch.resultSetSummaries[this._currentData.resultId];
|
let summary = batch.resultSetSummaries[this._currentData.resultId];
|
||||||
if (summary) {
|
if (summary) {
|
||||||
this._queryRunner.getQueryRows(0, summary.rowCount, this._currentData.batchId, this._currentData.resultId).then(d => {
|
this._queryRunner.getQueryRows(0, summary.rowCount, this._currentData.batchId, this._currentData.resultId).then(d => {
|
||||||
let rows = d.rows;
|
let rows = d.resultSubset.rows;
|
||||||
let columns = summary.columnInfo.map(c => c.columnName);
|
let columns = summary.columnInfo.map(c => c.columnName);
|
||||||
this.setData(rows, columns);
|
this.setData(rows, columns);
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -132,6 +132,7 @@ export class DashboardWidgetWrapper extends AngularDisposable implements OnInit
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (this._actions && this.toggleMore) {
|
if (this._actions && this.toggleMore) {
|
||||||
|
this._actionbar.context = { target: this._actionbarRef.nativeElement };
|
||||||
this._actionbar.push(this.instantiationService.createInstance(ToggleMoreWidgetAction, this._actions as Array<IAction>, this._component.actionsContext), { icon: true, label: false });
|
this._actionbar.push(this.instantiationService.createInstance(ToggleMoreWidgetAction, this._actions as Array<IAction>, this._component.actionsContext), { icon: true, label: false });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,6 +7,10 @@ import { ChangeDetectorRef, Component, ElementRef, forwardRef, Inject, OnInit, V
|
|||||||
import { Router } from '@angular/router';
|
import { Router } from '@angular/router';
|
||||||
import { DatabaseInfo } from 'azdata';
|
import { DatabaseInfo } from 'azdata';
|
||||||
import { subscriptionToDisposable } from 'sql/base/browser/lifecycle';
|
import { subscriptionToDisposable } from 'sql/base/browser/lifecycle';
|
||||||
|
import { ICapabilitiesService } from 'sql/platform/capabilities/common/capabilitiesService';
|
||||||
|
import { IConnectionManagementService } from 'sql/platform/connection/common/connectionManagement';
|
||||||
|
import { ConnectionProfile } from 'sql/platform/connection/common/connectionProfile';
|
||||||
|
import { DatabaseEngineEdition } from 'sql/workbench/api/common/sqlExtHostTypes';
|
||||||
import { DashboardWidget, IDashboardWidget, WidgetConfig, WIDGET_CONFIG } from 'sql/workbench/contrib/dashboard/browser/core/dashboardWidget';
|
import { DashboardWidget, IDashboardWidget, WidgetConfig, WIDGET_CONFIG } from 'sql/workbench/contrib/dashboard/browser/core/dashboardWidget';
|
||||||
import { ConnectionProfilePropertyName, ExplorerTable } from 'sql/workbench/contrib/dashboard/browser/widgets/explorer/explorerTable';
|
import { ConnectionProfilePropertyName, ExplorerTable } from 'sql/workbench/contrib/dashboard/browser/widgets/explorer/explorerTable';
|
||||||
import { NameProperty } from 'sql/workbench/contrib/dashboard/browser/widgets/explorer/explorerView';
|
import { NameProperty } from 'sql/workbench/contrib/dashboard/browser/widgets/explorer/explorerView';
|
||||||
@@ -51,6 +55,8 @@ export class ExplorerWidget extends DashboardWidget implements IDashboardWidget,
|
|||||||
@Inject(IMenuService) private readonly menuService: IMenuService,
|
@Inject(IMenuService) private readonly menuService: IMenuService,
|
||||||
@Inject(IContextKeyService) private readonly contextKeyService: IContextKeyService,
|
@Inject(IContextKeyService) private readonly contextKeyService: IContextKeyService,
|
||||||
@Inject(IEditorProgressService) private readonly progressService: IEditorProgressService,
|
@Inject(IEditorProgressService) private readonly progressService: IEditorProgressService,
|
||||||
|
@Inject(IConnectionManagementService) private readonly connectionManagementService: IConnectionManagementService,
|
||||||
|
@Inject(ICapabilitiesService) private readonly capabilitiesService: ICapabilitiesService,
|
||||||
@Inject(forwardRef(() => ChangeDetectorRef)) changeRef: ChangeDetectorRef
|
@Inject(forwardRef(() => ChangeDetectorRef)) changeRef: ChangeDetectorRef
|
||||||
) {
|
) {
|
||||||
super(changeRef);
|
super(changeRef);
|
||||||
@@ -95,7 +101,6 @@ export class ExplorerWidget extends DashboardWidget implements IDashboardWidget,
|
|||||||
this._register(subscriptionToDisposable(this._bootstrap.metadataService.metadata.subscribe(
|
this._register(subscriptionToDisposable(this._bootstrap.metadataService.metadata.subscribe(
|
||||||
data => {
|
data => {
|
||||||
if (data) {
|
if (data) {
|
||||||
|
|
||||||
const objectData = ObjectMetadataWrapper.createFromObjectMetadata(data.objectMetadata);
|
const objectData = ObjectMetadataWrapper.createFromObjectMetadata(data.objectMetadata);
|
||||||
objectData.sort(ObjectMetadataWrapper.sort);
|
objectData.sort(ObjectMetadataWrapper.sort);
|
||||||
this.updateTable(objectData);
|
this.updateTable(objectData);
|
||||||
@@ -106,34 +111,55 @@ export class ExplorerWidget extends DashboardWidget implements IDashboardWidget,
|
|||||||
}
|
}
|
||||||
)));
|
)));
|
||||||
} else {
|
} else {
|
||||||
this._register(subscriptionToDisposable(this._bootstrap.metadataService.databases.subscribe(
|
// TODO: remove this ADS side workaround for SQL On-Demand and handle it in SQL Tools Service
|
||||||
data => {
|
if (this._bootstrap.connectionManagementService.connectionInfo.serverInfo.engineEditionId === DatabaseEngineEdition.SqlOnDemand) {
|
||||||
// Handle the case where there is no metadata service
|
this.connectionManagementService.listDatabases(this._bootstrap.connectionManagementService.connectionInfo.ownerUri).then(
|
||||||
data = data || [];
|
result => {
|
||||||
if (isStringArray(data)) {
|
// Sort the databases: system databases first and then the sorted list of other databases
|
||||||
data = data.map(item => {
|
const sysDatabases = ['master', 'model', 'msdb', 'tempdb'];
|
||||||
const dbInfo: DatabaseInfo = { options: {} };
|
const databaseNames = result.databaseNames.filter(db => sysDatabases.indexOf(db) !== -1).
|
||||||
dbInfo.options[NameProperty] = item;
|
concat(result.databaseNames.filter(db => sysDatabases.indexOf(db) === -1).sort());
|
||||||
return dbInfo;
|
this.handleServerContextResults(databaseNames);
|
||||||
});
|
},
|
||||||
|
error => {
|
||||||
|
this.showErrorMessage(nls.localize('dashboard.explorer.databaseError', "Unable to load databases"));
|
||||||
}
|
}
|
||||||
|
);
|
||||||
const currentProfile = this._bootstrap.connectionManagementService.connectionInfo.connectionProfile;
|
}
|
||||||
this.updateTable(data.map(d => {
|
else {
|
||||||
const item = assign({}, d.options);
|
this._register(subscriptionToDisposable(this._bootstrap.metadataService.databases.subscribe(
|
||||||
const profile = currentProfile.toIConnectionProfile();
|
data => {
|
||||||
profile.databaseName = d.options[NameProperty];
|
this.handleServerContextResults(data);
|
||||||
item[ConnectionProfilePropertyName] = profile;
|
},
|
||||||
return item;
|
error => {
|
||||||
}));
|
this.showErrorMessage(nls.localize('dashboard.explorer.databaseError', "Unable to load databases"));
|
||||||
},
|
}
|
||||||
error => {
|
)));
|
||||||
this.showErrorMessage(nls.localize('dashboard.explorer.databaseError', "Unable to load databases"));
|
}
|
||||||
}
|
|
||||||
)));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private handleServerContextResults(data: string[] | DatabaseInfo[]): void {
|
||||||
|
// Handle the case where there is no metadata service
|
||||||
|
data = data || [];
|
||||||
|
if (isStringArray(data)) {
|
||||||
|
data = data.map(item => {
|
||||||
|
const dbInfo: DatabaseInfo = { options: {} };
|
||||||
|
dbInfo.options[NameProperty] = item;
|
||||||
|
return dbInfo;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const currentProfile = this._bootstrap.connectionManagementService.connectionInfo.connectionProfile;
|
||||||
|
this.updateTable(data.map(d => {
|
||||||
|
const item = assign({}, d.options);
|
||||||
|
const profile = new ConnectionProfile(this.capabilitiesService, currentProfile);
|
||||||
|
profile.databaseName = d.options[NameProperty];
|
||||||
|
item[ConnectionProfilePropertyName] = profile;
|
||||||
|
return item;
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
private updateTable(data: Slick.SlickData[]) {
|
private updateTable(data: Slick.SlickData[]) {
|
||||||
this._table.setData(data);
|
this._table.setData(data);
|
||||||
this.setLoadingStatus(false);
|
this.setLoadingStatus(false);
|
||||||
|
|||||||
@@ -17,3 +17,13 @@ explorer-widget .list-row {
|
|||||||
.explorer-widget .slick-cell {
|
.explorer-widget .slick-cell {
|
||||||
border-right-style: none;
|
border-right-style: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The widget could be put into container with class name "grid" and inherit colors unexpectedly,
|
||||||
|
* using this selector to force the cell to use the colors from parent elements
|
||||||
|
*/
|
||||||
|
.grid .explorer-widget .slick-cell {
|
||||||
|
color: inherit;
|
||||||
|
background-color: inherit;
|
||||||
|
border-color: inherit;
|
||||||
|
}
|
||||||
|
|||||||
@@ -42,6 +42,7 @@ export class NotebookEditorModel extends EditorModel {
|
|||||||
private _notebookTextFileModel: NotebookTextFileModel;
|
private _notebookTextFileModel: NotebookTextFileModel;
|
||||||
private readonly _onDidChangeDirty: Emitter<void> = this._register(new Emitter<void>());
|
private readonly _onDidChangeDirty: Emitter<void> = this._register(new Emitter<void>());
|
||||||
private _lastEditFullReplacement: boolean;
|
private _lastEditFullReplacement: boolean;
|
||||||
|
private _isFirstKernelChange: boolean = true;
|
||||||
constructor(public readonly notebookUri: URI,
|
constructor(public readonly notebookUri: URI,
|
||||||
private textEditorModel: ITextFileEditorModel | IUntitledTextEditorModel | ResourceEditorModel,
|
private textEditorModel: ITextFileEditorModel | IUntitledTextEditorModel | ResourceEditorModel,
|
||||||
@INotebookService private notebookService: INotebookService,
|
@INotebookService private notebookService: INotebookService,
|
||||||
@@ -110,6 +111,10 @@ export class NotebookEditorModel extends EditorModel {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public updateModel(contentChange?: NotebookContentChange, type?: NotebookChangeType): void {
|
public updateModel(contentChange?: NotebookContentChange, type?: NotebookChangeType): void {
|
||||||
|
if (type === NotebookChangeType.KernelChanged && this._isFirstKernelChange) {
|
||||||
|
this._isFirstKernelChange = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
this._lastEditFullReplacement = false;
|
this._lastEditFullReplacement = false;
|
||||||
if (contentChange && contentChange.changeType === NotebookChangeType.Saved) {
|
if (contentChange && contentChange.changeType === NotebookChangeType.Saved) {
|
||||||
// We send the saved events out, so ignore. Otherwise we double-count this as a change
|
// We send the saved events out, so ignore. Otherwise we double-count this as a change
|
||||||
|
|||||||
@@ -238,10 +238,10 @@ export class NotebookComponent extends AngularDisposable implements OnInit, OnDe
|
|||||||
private async doLoad(): Promise<void> {
|
private async doLoad(): Promise<void> {
|
||||||
try {
|
try {
|
||||||
await this.createModelAndLoadContents();
|
await this.createModelAndLoadContents();
|
||||||
await this.setNotebookManager();
|
|
||||||
await this.loadModel();
|
|
||||||
this._modelReadyDeferred.resolve(this._model);
|
this._modelReadyDeferred.resolve(this._model);
|
||||||
this.notebookService.addNotebookEditor(this);
|
this.notebookService.addNotebookEditor(this);
|
||||||
|
await this.setNotebookManager();
|
||||||
|
await this.loadModel();
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
if (error) {
|
if (error) {
|
||||||
// Offer to create a file from the error if we have a file not found and the name is valid
|
// Offer to create a file from the error if we have a file not found and the name is valid
|
||||||
|
|||||||
@@ -14,7 +14,6 @@ import { IConfigurationService } from 'vs/platform/configuration/common/configur
|
|||||||
import { IDataResource } from 'sql/workbench/services/notebook/browser/sql/sqlSessionManager';
|
import { IDataResource } from 'sql/workbench/services/notebook/browser/sql/sqlSessionManager';
|
||||||
import { ITextResourcePropertiesService } from 'vs/editor/common/services/textResourceConfigurationService';
|
import { ITextResourcePropertiesService } from 'vs/editor/common/services/textResourceConfigurationService';
|
||||||
import { getEolString, shouldIncludeHeaders, shouldRemoveNewLines } from 'sql/workbench/services/query/common/queryRunner';
|
import { getEolString, shouldIncludeHeaders, shouldRemoveNewLines } from 'sql/workbench/services/query/common/queryRunner';
|
||||||
import { ICellValue, ResultSetSummary, ResultSetSubset } from 'sql/workbench/services/query/common/query';
|
|
||||||
import { INotificationService } from 'vs/platform/notification/common/notification';
|
import { INotificationService } from 'vs/platform/notification/common/notification';
|
||||||
import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService';
|
import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService';
|
||||||
import { attachTableStyler } from 'sql/platform/theme/common/styler';
|
import { attachTableStyler } from 'sql/platform/theme/common/styler';
|
||||||
@@ -216,7 +215,7 @@ class DataResourceTable extends GridTableBase<any> {
|
|||||||
gridDataProvider.getRowData(0, rowCount).then(result => {
|
gridDataProvider.getRowData(0, rowCount).then(result => {
|
||||||
let range = new Slick.Range(0, 0, rowCount - 1, columnCount - 1);
|
let range = new Slick.Range(0, 0, rowCount - 1, columnCount - 1);
|
||||||
let columns = gridDataProvider.getColumnHeaders(range);
|
let columns = gridDataProvider.getColumnHeaders(range);
|
||||||
this._chart.setData(result.rows, columns);
|
this._chart.setData(result.resultSubset.rows, columns);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -227,9 +226,9 @@ class DataResourceTable extends GridTableBase<any> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class DataResourceDataProvider implements IGridDataProvider {
|
class DataResourceDataProvider implements IGridDataProvider {
|
||||||
private rows: ICellValue[][];
|
private rows: azdata.DbCellValue[][];
|
||||||
constructor(source: IDataResource,
|
constructor(source: IDataResource,
|
||||||
private resultSet: ResultSetSummary,
|
private resultSet: azdata.ResultSetSummary,
|
||||||
private documentUri: string,
|
private documentUri: string,
|
||||||
@INotificationService private _notificationService: INotificationService,
|
@INotificationService private _notificationService: INotificationService,
|
||||||
@IClipboardService private _clipboardService: IClipboardService,
|
@IClipboardService private _clipboardService: IClipboardService,
|
||||||
@@ -257,14 +256,17 @@ class DataResourceDataProvider implements IGridDataProvider {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
getRowData(rowStart: number, numberOfRows: number): Thenable<ResultSetSubset> {
|
getRowData(rowStart: number, numberOfRows: number): Thenable<azdata.QueryExecuteSubsetResult> {
|
||||||
let rowEnd = rowStart + numberOfRows;
|
let rowEnd = rowStart + numberOfRows;
|
||||||
if (rowEnd > this.rows.length) {
|
if (rowEnd > this.rows.length) {
|
||||||
rowEnd = this.rows.length;
|
rowEnd = this.rows.length;
|
||||||
}
|
}
|
||||||
let resultSubset: ResultSetSubset = {
|
let resultSubset: azdata.QueryExecuteSubsetResult = {
|
||||||
rowCount: rowEnd - rowStart,
|
message: undefined,
|
||||||
rows: this.rows.slice(rowStart, rowEnd)
|
resultSubset: {
|
||||||
|
rowCount: rowEnd - rowStart,
|
||||||
|
rows: this.rows.slice(rowStart, rowEnd)
|
||||||
|
}
|
||||||
};
|
};
|
||||||
return Promise.resolve(resultSubset);
|
return Promise.resolve(resultSubset);
|
||||||
}
|
}
|
||||||
@@ -324,7 +326,7 @@ class DataResourceDataProvider implements IGridDataProvider {
|
|||||||
maxRow = singleSelection.toRow + 1;
|
maxRow = singleSelection.toRow + 1;
|
||||||
columns = columns.slice(singleSelection.fromCell, singleSelection.toCell + 1);
|
columns = columns.slice(singleSelection.fromCell, singleSelection.toCell + 1);
|
||||||
}
|
}
|
||||||
let getRows: ((index: number, rowCount: number) => ICellValue[][]) = (index, rowCount) => {
|
let getRows: ((index: number, rowCount: number) => azdata.DbCellValue[][]) = (index, rowCount) => {
|
||||||
// Offset for selections by adding the selection startRow to the index
|
// Offset for selections by adding the selection startRow to the index
|
||||||
index = index + minRow;
|
index = index + minRow;
|
||||||
if (rowLength === 0 || index < 0 || index >= maxRow) {
|
if (rowLength === 0 || index < 0 || index >= maxRow) {
|
||||||
|
|||||||
@@ -7,7 +7,6 @@ import 'vs/css!./media/gridPanel';
|
|||||||
|
|
||||||
import { attachTableStyler } from 'sql/platform/theme/common/styler';
|
import { attachTableStyler } from 'sql/platform/theme/common/styler';
|
||||||
import QueryRunner, { QueryGridDataProvider } from 'sql/workbench/services/query/common/queryRunner';
|
import QueryRunner, { QueryGridDataProvider } from 'sql/workbench/services/query/common/queryRunner';
|
||||||
import { ResultSetSummary, IColumn } from 'sql/workbench/services/query/common/query';
|
|
||||||
import { VirtualizedCollection, AsyncDataProvider } from 'sql/base/browser/ui/table/asyncDataView';
|
import { VirtualizedCollection, AsyncDataProvider } from 'sql/base/browser/ui/table/asyncDataView';
|
||||||
import { Table } from 'sql/base/browser/ui/table/table';
|
import { Table } from 'sql/base/browser/ui/table/table';
|
||||||
import { ScrollableSplitView, IView } from 'sql/base/browser/ui/scrollableSplitview/scrollableSplitview';
|
import { ScrollableSplitView, IView } from 'sql/base/browser/ui/scrollableSplitview/scrollableSplitview';
|
||||||
@@ -22,6 +21,8 @@ import { CopyKeybind } from 'sql/base/browser/ui/table/plugins/copyKeybind.plugi
|
|||||||
import { AdditionalKeyBindings } from 'sql/base/browser/ui/table/plugins/additionalKeyBindings.plugin';
|
import { AdditionalKeyBindings } from 'sql/base/browser/ui/table/plugins/additionalKeyBindings.plugin';
|
||||||
import { ITableStyles, ITableMouseEvent } from 'sql/base/browser/ui/table/interfaces';
|
import { ITableStyles, ITableMouseEvent } from 'sql/base/browser/ui/table/interfaces';
|
||||||
|
|
||||||
|
import * as azdata from 'azdata';
|
||||||
|
|
||||||
import { IContextMenuService } from 'vs/platform/contextview/browser/contextView';
|
import { IContextMenuService } from 'vs/platform/contextview/browser/contextView';
|
||||||
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||||
import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
|
import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
|
||||||
@@ -122,7 +123,7 @@ export class GridPanel extends Disposable {
|
|||||||
}
|
}
|
||||||
this.reset();
|
this.reset();
|
||||||
}));
|
}));
|
||||||
this.addResultSet(this.runner.batchSets.reduce<ResultSetSummary[]>((p, e) => {
|
this.addResultSet(this.runner.batchSets.reduce<azdata.ResultSetSummary[]>((p, e) => {
|
||||||
if (this.configurationService.getValue<boolean>('sql.results.streaming')) {
|
if (this.configurationService.getValue<boolean>('sql.results.streaming')) {
|
||||||
p = p.concat(e.resultSetSummaries);
|
p = p.concat(e.resultSetSummaries);
|
||||||
} else {
|
} else {
|
||||||
@@ -140,8 +141,8 @@ export class GridPanel extends Disposable {
|
|||||||
this.splitView.setScrollPosition(this.state.scrollPosition);
|
this.splitView.setScrollPosition(this.state.scrollPosition);
|
||||||
}
|
}
|
||||||
|
|
||||||
private onResultSet(resultSet: ResultSetSummary | ResultSetSummary[]) {
|
private onResultSet(resultSet: azdata.ResultSetSummary | azdata.ResultSetSummary[]) {
|
||||||
let resultsToAdd: ResultSetSummary[];
|
let resultsToAdd: azdata.ResultSetSummary[];
|
||||||
if (!Array.isArray(resultSet)) {
|
if (!Array.isArray(resultSet)) {
|
||||||
resultsToAdd = [resultSet];
|
resultsToAdd = [resultSet];
|
||||||
} else {
|
} else {
|
||||||
@@ -169,8 +170,8 @@ export class GridPanel extends Disposable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private updateResultSet(resultSet: ResultSetSummary | ResultSetSummary[]) {
|
private updateResultSet(resultSet: azdata.ResultSetSummary | azdata.ResultSetSummary[]) {
|
||||||
let resultsToUpdate: ResultSetSummary[];
|
let resultsToUpdate: azdata.ResultSetSummary[];
|
||||||
if (!Array.isArray(resultSet)) {
|
if (!Array.isArray(resultSet)) {
|
||||||
resultsToUpdate = [resultSet];
|
resultsToUpdate = [resultSet];
|
||||||
} else {
|
} else {
|
||||||
@@ -202,7 +203,7 @@ export class GridPanel extends Disposable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private addResultSet(resultSet: ResultSetSummary[]) {
|
private addResultSet(resultSet: azdata.ResultSetSummary[]) {
|
||||||
let tables: GridTable<any>[] = [];
|
let tables: GridTable<any>[] = [];
|
||||||
|
|
||||||
for (let set of resultSet) {
|
for (let set of resultSet) {
|
||||||
@@ -315,7 +316,7 @@ export class GridPanel extends Disposable {
|
|||||||
|
|
||||||
export interface IDataSet {
|
export interface IDataSet {
|
||||||
rowCount: number;
|
rowCount: number;
|
||||||
columnInfo: IColumn[];
|
columnInfo: azdata.IDbColumn[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export abstract class GridTableBase<T> extends Disposable implements IView {
|
export abstract class GridTableBase<T> extends Disposable implements IView {
|
||||||
@@ -362,7 +363,7 @@ export abstract class GridTableBase<T> extends Disposable implements IView {
|
|||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
state: GridTableState,
|
state: GridTableState,
|
||||||
protected _resultSet: ResultSetSummary,
|
protected _resultSet: azdata.ResultSetSummary,
|
||||||
protected contextMenuService: IContextMenuService,
|
protected contextMenuService: IContextMenuService,
|
||||||
protected instantiationService: IInstantiationService,
|
protected instantiationService: IInstantiationService,
|
||||||
protected editorService: IEditorService,
|
protected editorService: IEditorService,
|
||||||
@@ -393,7 +394,7 @@ export abstract class GridTableBase<T> extends Disposable implements IView {
|
|||||||
|
|
||||||
abstract get gridDataProvider(): IGridDataProvider;
|
abstract get gridDataProvider(): IGridDataProvider;
|
||||||
|
|
||||||
public get resultSet(): ResultSetSummary {
|
public get resultSet(): azdata.ResultSetSummary {
|
||||||
return this._resultSet;
|
return this._resultSet;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -586,7 +587,7 @@ export abstract class GridTableBase<T> extends Disposable implements IView {
|
|||||||
// handle if a showplan link was clicked
|
// handle if a showplan link was clicked
|
||||||
if (column && (column.isXml || column.isJson)) {
|
if (column && (column.isXml || column.isJson)) {
|
||||||
this.gridDataProvider.getRowData(event.cell.row, 1).then(async d => {
|
this.gridDataProvider.getRowData(event.cell.row, 1).then(async d => {
|
||||||
let value = d.rows[0][event.cell.cell - 1];
|
let value = d.resultSubset.rows[0][event.cell.cell - 1];
|
||||||
let content = value.displayValue;
|
let content = value.displayValue;
|
||||||
|
|
||||||
const input = this.untitledEditorService.create({ mode: column.isXml ? 'xml' : 'json', initialValue: content });
|
const input = this.untitledEditorService.create({ mode: column.isXml ? 'xml' : 'json', initialValue: content });
|
||||||
@@ -597,7 +598,7 @@ export abstract class GridTableBase<T> extends Disposable implements IView {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public updateResult(resultSet: ResultSetSummary) {
|
public updateResult(resultSet: azdata.ResultSetSummary) {
|
||||||
this._resultSet = resultSet;
|
this._resultSet = resultSet;
|
||||||
if (this.table && this.visible) {
|
if (this.table && this.visible) {
|
||||||
this.dataProvider.length = resultSet.rowCount;
|
this.dataProvider.length = resultSet.rowCount;
|
||||||
@@ -654,10 +655,10 @@ export abstract class GridTableBase<T> extends Disposable implements IView {
|
|||||||
|
|
||||||
private loadData(offset: number, count: number): Thenable<T[]> {
|
private loadData(offset: number, count: number): Thenable<T[]> {
|
||||||
return this.gridDataProvider.getRowData(offset, count).then(response => {
|
return this.gridDataProvider.getRowData(offset, count).then(response => {
|
||||||
if (!response) {
|
if (!response.resultSubset) {
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
return response.rows.map(r => {
|
return response.resultSubset.rows.map(r => {
|
||||||
let dataWithSchema = {};
|
let dataWithSchema = {};
|
||||||
// skip the first column since its a number column
|
// skip the first column since its a number column
|
||||||
for (let i = 1; i < this.columns.length; i++) {
|
for (let i = 1; i < this.columns.length; i++) {
|
||||||
@@ -755,7 +756,7 @@ class GridTable<T> extends GridTableBase<T> {
|
|||||||
private _gridDataProvider: IGridDataProvider;
|
private _gridDataProvider: IGridDataProvider;
|
||||||
constructor(
|
constructor(
|
||||||
private _runner: QueryRunner,
|
private _runner: QueryRunner,
|
||||||
resultSet: ResultSetSummary,
|
resultSet: azdata.ResultSetSummary,
|
||||||
state: GridTableState,
|
state: GridTableState,
|
||||||
@IContextMenuService contextMenuService: IContextMenuService,
|
@IContextMenuService contextMenuService: IContextMenuService,
|
||||||
@IInstantiationService instantiationService: IInstantiationService,
|
@IInstantiationService instantiationService: IInstantiationService,
|
||||||
|
|||||||
@@ -4,15 +4,16 @@
|
|||||||
*--------------------------------------------------------------------------------------------*/
|
*--------------------------------------------------------------------------------------------*/
|
||||||
|
|
||||||
import 'vs/css!./media/messagePanel';
|
import 'vs/css!./media/messagePanel';
|
||||||
import QueryRunner from 'sql/workbench/services/query/common/queryRunner';
|
import QueryRunner, { IQueryMessage } from 'sql/workbench/services/query/common/queryRunner';
|
||||||
import { IQueryMessage } from 'sql/workbench/services/query/common/query';
|
|
||||||
|
import { ISelectionData } from 'azdata';
|
||||||
|
|
||||||
import { ITreeRenderer, IDataSource, ITreeNode, ITreeContextMenuEvent } from 'vs/base/browser/ui/tree/tree';
|
import { ITreeRenderer, IDataSource, ITreeNode, ITreeContextMenuEvent } from 'vs/base/browser/ui/tree/tree';
|
||||||
import { generateUuid } from 'vs/base/common/uuid';
|
import { generateUuid } from 'vs/base/common/uuid';
|
||||||
import { attachListStyler } from 'vs/platform/theme/common/styler';
|
import { attachListStyler } from 'vs/platform/theme/common/styler';
|
||||||
import { IThemeService, IColorTheme } from 'vs/platform/theme/common/themeService';
|
import { IThemeService, IColorTheme } from 'vs/platform/theme/common/themeService';
|
||||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||||
import { WorkbenchDataTree } from 'vs/platform/list/browser/listService';
|
import { WorkbenchDataTree, horizontalScrollingKey } from 'vs/platform/list/browser/listService';
|
||||||
import { isArray, isString } from 'vs/base/common/types';
|
import { isArray, isString } from 'vs/base/common/types';
|
||||||
import { Disposable, DisposableStore, dispose } from 'vs/base/common/lifecycle';
|
import { Disposable, DisposableStore, dispose } from 'vs/base/common/lifecycle';
|
||||||
import { $, Dimension, createStyleSheet, addStandardDisposableGenericMouseDownListner } from 'vs/base/browser/dom';
|
import { $, Dimension, createStyleSheet, addStandardDisposableGenericMouseDownListner } from 'vs/base/browser/dom';
|
||||||
@@ -31,7 +32,7 @@ import { ICodeEditor } from 'vs/editor/browser/editorBrowser';
|
|||||||
import { QueryEditor } from 'sql/workbench/contrib/query/browser/queryEditor';
|
import { QueryEditor } from 'sql/workbench/contrib/query/browser/queryEditor';
|
||||||
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
|
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
|
||||||
import { IDataTreeViewState } from 'vs/base/browser/ui/tree/dataTree';
|
import { IDataTreeViewState } from 'vs/base/browser/ui/tree/dataTree';
|
||||||
import { IRange } from 'vs/editor/common/core/range';
|
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||||
|
|
||||||
export interface IResultMessageIntern {
|
export interface IResultMessageIntern {
|
||||||
id?: string;
|
id?: string;
|
||||||
@@ -39,7 +40,8 @@ export interface IResultMessageIntern {
|
|||||||
isError: boolean;
|
isError: boolean;
|
||||||
time?: string | Date;
|
time?: string | Date;
|
||||||
message: string;
|
message: string;
|
||||||
range?: IRange;
|
selection?: ISelectionData;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IMessagePanelMessage {
|
export interface IMessagePanelMessage {
|
||||||
@@ -48,7 +50,7 @@ export interface IMessagePanelMessage {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export interface IMessagePanelBatchMessage extends IMessagePanelMessage {
|
export interface IMessagePanelBatchMessage extends IMessagePanelMessage {
|
||||||
range: IRange;
|
selection: ISelectionData;
|
||||||
time: string;
|
time: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -101,9 +103,11 @@ export class MessagePanel extends Disposable {
|
|||||||
@IThemeService private readonly themeService: IThemeService,
|
@IThemeService private readonly themeService: IThemeService,
|
||||||
@IContextMenuService private readonly contextMenuService: IContextMenuService,
|
@IContextMenuService private readonly contextMenuService: IContextMenuService,
|
||||||
@IClipboardService private readonly clipboardService: IClipboardService,
|
@IClipboardService private readonly clipboardService: IClipboardService,
|
||||||
@ITextResourcePropertiesService private readonly textResourcePropertiesService: ITextResourcePropertiesService
|
@ITextResourcePropertiesService private readonly textResourcePropertiesService: ITextResourcePropertiesService,
|
||||||
|
@IConfigurationService private configurationService: IConfigurationService
|
||||||
) {
|
) {
|
||||||
super();
|
super();
|
||||||
|
const horizontalScrollEnabled = this.configurationService.getValue(horizontalScrollingKey) || false;
|
||||||
this.tree = <WorkbenchDataTree<Model, IResultMessageIntern, FuzzyScore>>instantiationService.createInstance(
|
this.tree = <WorkbenchDataTree<Model, IResultMessageIntern, FuzzyScore>>instantiationService.createInstance(
|
||||||
WorkbenchDataTree,
|
WorkbenchDataTree,
|
||||||
'MessagePanel',
|
'MessagePanel',
|
||||||
@@ -119,7 +123,7 @@ export class MessagePanel extends Disposable {
|
|||||||
accessibilityProvider: new AccessibilityProvider(),
|
accessibilityProvider: new AccessibilityProvider(),
|
||||||
mouseSupport: false,
|
mouseSupport: false,
|
||||||
setRowLineHeight: false,
|
setRowLineHeight: false,
|
||||||
supportDynamicHeights: true,
|
supportDynamicHeights: !horizontalScrollEnabled,
|
||||||
identityProvider: new IdentityProvider()
|
identityProvider: new IdentityProvider()
|
||||||
});
|
});
|
||||||
this._register(this.tree.onContextMenu(e => this.onContextMenu(e)));
|
this._register(this.tree.onContextMenu(e => this.onContextMenu(e)));
|
||||||
@@ -210,7 +214,7 @@ export class MessagePanel extends Disposable {
|
|||||||
const errorColor = theme.getColor(resultsErrorColor);
|
const errorColor = theme.getColor(resultsErrorColor);
|
||||||
const content: string[] = [];
|
const content: string[] = [];
|
||||||
if (errorColor) {
|
if (errorColor) {
|
||||||
content.push(`.message-tree .monaco-tree-rows .error-message { color: ${errorColor}; }`);
|
content.push(`.message-tree .monaco-list-rows .error-message { color: ${errorColor}; }`);
|
||||||
}
|
}
|
||||||
|
|
||||||
const newStyles = content.join('\n');
|
const newStyles = content.join('\n');
|
||||||
@@ -266,7 +270,7 @@ class MessagePanelDelegate extends CachedListVirtualDelegate<IResultMessageInter
|
|||||||
getTemplateId(element: IResultMessageIntern): string {
|
getTemplateId(element: IResultMessageIntern): string {
|
||||||
if (element instanceof Model) {
|
if (element instanceof Model) {
|
||||||
return TemplateIds.MODEL;
|
return TemplateIds.MODEL;
|
||||||
} else if (element.range) {
|
} else if (element.selection) {
|
||||||
return TemplateIds.BATCH;
|
return TemplateIds.BATCH;
|
||||||
} else if (element.isError) {
|
} else if (element.isError) {
|
||||||
return TemplateIds.ERROR;
|
return TemplateIds.ERROR;
|
||||||
@@ -321,13 +325,14 @@ class BatchMessageRenderer implements ITreeRenderer<IResultMessageIntern, void,
|
|||||||
}
|
}
|
||||||
templateData.timeStamp.innerText = (node.element.time as Date).toLocaleTimeString();
|
templateData.timeStamp.innerText = (node.element.time as Date).toLocaleTimeString();
|
||||||
templateData.message.innerText = node.element.message;
|
templateData.message.innerText = node.element.message;
|
||||||
if (node.element.range) {
|
if (node.element.selection) {
|
||||||
|
const selection = { endColumn: node.element.selection.endColumn + 1, endLineNumber: node.element.selection.endLine + 1, startColumn: node.element.selection.startColumn + 1, startLineNumber: node.element.selection.startLine + 1 };
|
||||||
templateData.disposable.add(addStandardDisposableGenericMouseDownListner(templateData.message, () => {
|
templateData.disposable.add(addStandardDisposableGenericMouseDownListner(templateData.message, () => {
|
||||||
let editor = this.editorService.activeEditorPane as QueryEditor;
|
let editor = this.editorService.activeEditorPane as QueryEditor;
|
||||||
const codeEditor = <ICodeEditor>editor.getControl();
|
const codeEditor = <ICodeEditor>editor.getControl();
|
||||||
codeEditor.focus();
|
codeEditor.focus();
|
||||||
codeEditor.setSelection(node.element.range);
|
codeEditor.setSelection(selection);
|
||||||
codeEditor.revealRangeInCenterIfOutsideViewport(node.element.range);
|
codeEditor.revealRangeInCenterIfOutsideViewport(selection);
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ import { INotificationService } from 'vs/platform/notification/common/notificati
|
|||||||
import Severity from 'vs/base/common/severity';
|
import Severity from 'vs/base/common/severity';
|
||||||
import { append, $ } from 'vs/base/browser/dom';
|
import { append, $ } from 'vs/base/browser/dom';
|
||||||
|
|
||||||
import { QueryExecutionOptions } from 'azdata';
|
import { ISelectionData, QueryExecutionOptions } from 'azdata';
|
||||||
import {
|
import {
|
||||||
IConnectionManagementService,
|
IConnectionManagementService,
|
||||||
IConnectionParams,
|
IConnectionParams,
|
||||||
@@ -43,7 +43,6 @@ import { ICapabilitiesService } from 'sql/platform/capabilities/common/capabilit
|
|||||||
import { ConnectionProfile } from 'sql/platform/connection/common/connectionProfile';
|
import { ConnectionProfile } from 'sql/platform/connection/common/connectionProfile';
|
||||||
import { IQueryManagementService } from 'sql/workbench/services/query/common/queryManagement';
|
import { IQueryManagementService } from 'sql/workbench/services/query/common/queryManagement';
|
||||||
import { ILogService } from 'vs/platform/log/common/log';
|
import { ILogService } from 'vs/platform/log/common/log';
|
||||||
import { IRange } from 'vs/editor/common/core/range';
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Action class that query-based Actions will extend. This base class automatically handles activating and
|
* Action class that query-based Actions will extend. This base class automatically handles activating and
|
||||||
@@ -102,12 +101,12 @@ export abstract class QueryTaskbarAction extends Action {
|
|||||||
* Connects the given editor to it's current URI.
|
* Connects the given editor to it's current URI.
|
||||||
* Public for testing only.
|
* Public for testing only.
|
||||||
*/
|
*/
|
||||||
protected connectEditor(editor: QueryEditor, runQueryOnCompletion?: RunQueryOnConnectionMode, range?: IRange): void {
|
protected connectEditor(editor: QueryEditor, runQueryOnCompletion?: RunQueryOnConnectionMode, selection?: ISelectionData): void {
|
||||||
let params: INewConnectionParams = {
|
let params: INewConnectionParams = {
|
||||||
input: editor.input,
|
input: editor.input,
|
||||||
connectionType: ConnectionType.editor,
|
connectionType: ConnectionType.editor,
|
||||||
runQueryOnCompletion: runQueryOnCompletion ? runQueryOnCompletion : RunQueryOnConnectionMode.none,
|
runQueryOnCompletion: runQueryOnCompletion ? runQueryOnCompletion : RunQueryOnConnectionMode.none,
|
||||||
queryRange: range
|
querySelection: selection
|
||||||
};
|
};
|
||||||
this.connectionManagementService.showConnectionDialog(params);
|
this.connectionManagementService.showConnectionDialog(params);
|
||||||
}
|
}
|
||||||
@@ -242,8 +241,8 @@ export class RunQueryAction extends QueryTaskbarAction {
|
|||||||
if (this.isConnected(editor)) {
|
if (this.isConnected(editor)) {
|
||||||
// if the selection isn't empty then execute the selection
|
// if the selection isn't empty then execute the selection
|
||||||
// otherwise, either run the statement or the script depending on parameter
|
// otherwise, either run the statement or the script depending on parameter
|
||||||
let selection = editor.getSelection();
|
let selection: ISelectionData = editor.getSelection(false);
|
||||||
if (runCurrentStatement && selection) {
|
if (runCurrentStatement && selection && this.isCursorPosition(selection)) {
|
||||||
editor.input.runQueryStatement(selection);
|
editor.input.runQueryStatement(selection);
|
||||||
} else {
|
} else {
|
||||||
// get the selection again this time with trimming
|
// get the selection again this time with trimming
|
||||||
@@ -252,6 +251,11 @@ export class RunQueryAction extends QueryTaskbarAction {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected isCursorPosition(selection: ISelectionData) {
|
||||||
|
return selection.startLine === selection.endLine
|
||||||
|
&& selection.startColumn === selection.endColumn;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ import { IEditorGroup, IEditorGroupsService } from 'vs/workbench/services/editor
|
|||||||
import { SplitView, Sizing } from 'vs/base/browser/ui/splitview/splitview';
|
import { SplitView, Sizing } from 'vs/base/browser/ui/splitview/splitview';
|
||||||
import { Event } from 'vs/base/common/event';
|
import { Event } from 'vs/base/common/event';
|
||||||
import { DisposableStore } from 'vs/base/common/lifecycle';
|
import { DisposableStore } from 'vs/base/common/lifecycle';
|
||||||
|
import { ISelectionData } from 'azdata';
|
||||||
import { IActionViewItem, IAction } from 'vs/base/common/actions';
|
import { IActionViewItem, IAction } from 'vs/base/common/actions';
|
||||||
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||||
import { BaseTextEditor } from 'vs/workbench/browser/parts/editor/textEditor';
|
import { BaseTextEditor } from 'vs/workbench/browser/parts/editor/textEditor';
|
||||||
@@ -35,7 +36,6 @@ import { QueryResultsEditor } from 'sql/workbench/contrib/query/browser/queryRes
|
|||||||
import * as queryContext from 'sql/workbench/contrib/query/common/queryContext';
|
import * as queryContext from 'sql/workbench/contrib/query/common/queryContext';
|
||||||
import { Taskbar, ITaskbarContent } from 'sql/base/browser/ui/taskbar/taskbar';
|
import { Taskbar, ITaskbarContent } from 'sql/base/browser/ui/taskbar/taskbar';
|
||||||
import * as actions from 'sql/workbench/contrib/query/browser/queryActions';
|
import * as actions from 'sql/workbench/contrib/query/browser/queryActions';
|
||||||
import { IRange } from 'vs/editor/common/core/range';
|
|
||||||
|
|
||||||
const QUERY_EDITOR_VIEW_STATE_PREFERENCE_KEY = 'queryEditorViewState';
|
const QUERY_EDITOR_VIEW_STATE_PREFERENCE_KEY = 'queryEditorViewState';
|
||||||
|
|
||||||
@@ -499,7 +499,7 @@ export class QueryEditor extends BaseEditor {
|
|||||||
* Returns the underlying SQL editor's text selection in a 0-indexed format. Returns undefined if there
|
* Returns the underlying SQL editor's text selection in a 0-indexed format. Returns undefined if there
|
||||||
* is no selected text.
|
* is no selected text.
|
||||||
*/
|
*/
|
||||||
public getSelection(checkIfRange: boolean = true): IRange {
|
public getSelection(checkIfRange: boolean = true): ISelectionData {
|
||||||
if (this.currentTextEditor && this.currentTextEditor.getControl()) {
|
if (this.currentTextEditor && this.currentTextEditor.getControl()) {
|
||||||
let vscodeSelection = this.currentTextEditor.getControl().getSelection();
|
let vscodeSelection = this.currentTextEditor.getControl().getSelection();
|
||||||
|
|
||||||
@@ -508,7 +508,13 @@ export class QueryEditor extends BaseEditor {
|
|||||||
!(vscodeSelection.getStartPosition().lineNumber === vscodeSelection.getEndPosition().lineNumber &&
|
!(vscodeSelection.getStartPosition().lineNumber === vscodeSelection.getEndPosition().lineNumber &&
|
||||||
vscodeSelection.getStartPosition().column === vscodeSelection.getEndPosition().column);
|
vscodeSelection.getStartPosition().column === vscodeSelection.getEndPosition().column);
|
||||||
if (!checkIfRange || isRange) {
|
if (!checkIfRange || isRange) {
|
||||||
return vscodeSelection;
|
let sqlToolsServiceSelection: ISelectionData = {
|
||||||
|
startLine: vscodeSelection.getStartPosition().lineNumber - 1,
|
||||||
|
startColumn: vscodeSelection.getStartPosition().column - 1,
|
||||||
|
endLine: vscodeSelection.getEndPosition().lineNumber - 1,
|
||||||
|
endColumn: vscodeSelection.getEndPosition().column - 1,
|
||||||
|
};
|
||||||
|
return sqlToolsServiceSelection;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -516,7 +522,7 @@ export class QueryEditor extends BaseEditor {
|
|||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
public getAllSelection(): IRange {
|
public getAllSelection(): ISelectionData {
|
||||||
if (this.currentTextEditor && this.currentTextEditor.getControl()) {
|
if (this.currentTextEditor && this.currentTextEditor.getControl()) {
|
||||||
let control = this.currentTextEditor.getControl();
|
let control = this.currentTextEditor.getControl();
|
||||||
let codeEditor: ICodeEditor = <ICodeEditor>control;
|
let codeEditor: ICodeEditor = <ICodeEditor>control;
|
||||||
@@ -524,12 +530,13 @@ export class QueryEditor extends BaseEditor {
|
|||||||
let model = codeEditor.getModel();
|
let model = codeEditor.getModel();
|
||||||
let totalLines = model.getLineCount();
|
let totalLines = model.getLineCount();
|
||||||
let endColumn = model.getLineMaxColumn(totalLines);
|
let endColumn = model.getLineMaxColumn(totalLines);
|
||||||
return {
|
let selection: ISelectionData = {
|
||||||
startLineNumber: 1,
|
startLine: 0,
|
||||||
startColumn: 1,
|
startColumn: 0,
|
||||||
endLineNumber: totalLines,
|
endLine: totalLines - 1,
|
||||||
endColumn: endColumn,
|
endColumn: endColumn - 1,
|
||||||
};
|
};
|
||||||
|
return selection;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return undefined;
|
return undefined;
|
||||||
|
|||||||
@@ -5,6 +5,8 @@
|
|||||||
|
|
||||||
import { Emitter, Event } from 'vs/base/common/event';
|
import { Emitter, Event } from 'vs/base/common/event';
|
||||||
|
|
||||||
|
import { ISelectionData } from 'azdata';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
IConnectionParams,
|
IConnectionParams,
|
||||||
INewConnectionParams,
|
INewConnectionParams,
|
||||||
@@ -32,7 +34,6 @@ import { TestConfigurationService } from 'vs/platform/configuration/test/common/
|
|||||||
import { UntitledTextEditorInput } from 'vs/workbench/services/untitled/common/untitledTextEditorInput';
|
import { UntitledTextEditorInput } from 'vs/workbench/services/untitled/common/untitledTextEditorInput';
|
||||||
import { IUntitledTextEditorService } from 'vs/workbench/services/untitled/common/untitledTextEditorService';
|
import { IUntitledTextEditorService } from 'vs/workbench/services/untitled/common/untitledTextEditorService';
|
||||||
import { TestStorageService } from 'vs/workbench/test/common/workbenchTestServices';
|
import { TestStorageService } from 'vs/workbench/test/common/workbenchTestServices';
|
||||||
import { IRange } from 'vs/editor/common/core/range';
|
|
||||||
|
|
||||||
suite('SQL QueryAction Tests', () => {
|
suite('SQL QueryAction Tests', () => {
|
||||||
|
|
||||||
@@ -221,9 +222,9 @@ suite('SQL QueryAction Tests', () => {
|
|||||||
let countCalledShowDialog: number = 0;
|
let countCalledShowDialog: number = 0;
|
||||||
let countCalledRunQuery: number = 0;
|
let countCalledRunQuery: number = 0;
|
||||||
let showDialogConnectionParams: INewConnectionParams = undefined;
|
let showDialogConnectionParams: INewConnectionParams = undefined;
|
||||||
let runQuerySelection: IRange = undefined;
|
let runQuerySelection: ISelectionData = undefined;
|
||||||
let selectionToReturnInGetSelection: IRange = undefined;
|
let selectionToReturnInGetSelection: ISelectionData = undefined;
|
||||||
let predefinedSelection: IRange = { startLineNumber: 1, startColumn: 2, endLineNumber: 3, endColumn: 4 };
|
let predefinedSelection: ISelectionData = { startLine: 1, startColumn: 2, endLine: 3, endColumn: 4 };
|
||||||
|
|
||||||
// ... Mock "getSelection" in QueryEditor
|
// ... Mock "getSelection" in QueryEditor
|
||||||
const workbenchinstantiationService = workbenchInstantiationService();
|
const workbenchinstantiationService = workbenchInstantiationService();
|
||||||
@@ -233,11 +234,11 @@ suite('SQL QueryAction Tests', () => {
|
|||||||
|
|
||||||
let queryInput = TypeMoq.Mock.ofType(UntitledQueryEditorInput, TypeMoq.MockBehavior.Loose, undefined, fileInput, undefined, connectionManagementService.object, queryModelService.object, configurationService.object);
|
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.uri).returns(() => testUri);
|
||||||
queryInput.setup(x => x.runQuery(TypeMoq.It.isAny())).callback((selection: IRange) => {
|
queryInput.setup(x => x.runQuery(TypeMoq.It.isAny())).callback((selection: ISelectionData) => {
|
||||||
runQuerySelection = selection;
|
runQuerySelection = selection;
|
||||||
countCalledRunQuery++;
|
countCalledRunQuery++;
|
||||||
});
|
});
|
||||||
queryInput.setup(x => x.runQuery(undefined)).callback((selection: IRange) => {
|
queryInput.setup(x => x.runQuery(undefined)).callback((selection: ISelectionData) => {
|
||||||
runQuerySelection = selection;
|
runQuerySelection = selection;
|
||||||
countCalledRunQuery++;
|
countCalledRunQuery++;
|
||||||
});
|
});
|
||||||
@@ -276,7 +277,7 @@ suite('SQL QueryAction Tests', () => {
|
|||||||
assert.equal(countCalledShowDialog, 1, 'run should call showDialog');
|
assert.equal(countCalledShowDialog, 1, 'run should call showDialog');
|
||||||
assert.equal(countCalledRunQuery, 0, 'run should not call runQuery');
|
assert.equal(countCalledRunQuery, 0, 'run should not call runQuery');
|
||||||
assert.equal(showDialogConnectionParams.connectionType, ConnectionType.editor, 'connectionType should be queryEditor');
|
assert.equal(showDialogConnectionParams.connectionType, ConnectionType.editor, 'connectionType should be queryEditor');
|
||||||
assert.equal(showDialogConnectionParams.queryRange, undefined, 'querySelection should be undefined');
|
assert.equal(showDialogConnectionParams.querySelection, undefined, 'querySelection should be undefined');
|
||||||
|
|
||||||
////// If I call run on RunQueryAction while disconnected and with a defined selection
|
////// If I call run on RunQueryAction while disconnected and with a defined selection
|
||||||
isConnected = false;
|
isConnected = false;
|
||||||
@@ -287,11 +288,11 @@ suite('SQL QueryAction Tests', () => {
|
|||||||
assert.equal(countCalledShowDialog, 2, 'run should call showDialog again');
|
assert.equal(countCalledShowDialog, 2, 'run should call showDialog again');
|
||||||
assert.equal(countCalledRunQuery, 0, 'run should not call runQuery');
|
assert.equal(countCalledRunQuery, 0, 'run should not call runQuery');
|
||||||
assert.equal(showDialogConnectionParams.connectionType, ConnectionType.editor, 'connectionType should be queryEditor');
|
assert.equal(showDialogConnectionParams.connectionType, ConnectionType.editor, 'connectionType should be queryEditor');
|
||||||
assert.notEqual(showDialogConnectionParams.queryRange, undefined, 'There should not be an undefined selection in runQuery');
|
assert.notEqual(showDialogConnectionParams.querySelection, undefined, 'There should not be an undefined selection in runQuery');
|
||||||
assert.equal(showDialogConnectionParams.queryRange.startLineNumber, selectionToReturnInGetSelection.startLineNumber, 'startLine should match');
|
assert.equal(showDialogConnectionParams.querySelection.startLine, selectionToReturnInGetSelection.startLine, 'startLine should match');
|
||||||
assert.equal(showDialogConnectionParams.queryRange.startColumn, selectionToReturnInGetSelection.startColumn, 'startColumn should match');
|
assert.equal(showDialogConnectionParams.querySelection.startColumn, selectionToReturnInGetSelection.startColumn, 'startColumn should match');
|
||||||
assert.equal(showDialogConnectionParams.queryRange.endLineNumber, selectionToReturnInGetSelection.endLineNumber, 'endLine should match');
|
assert.equal(showDialogConnectionParams.querySelection.endLine, selectionToReturnInGetSelection.endLine, 'endLine should match');
|
||||||
assert.equal(showDialogConnectionParams.queryRange.endColumn, selectionToReturnInGetSelection.endColumn, 'endColumn should match');
|
assert.equal(showDialogConnectionParams.querySelection.endColumn, selectionToReturnInGetSelection.endColumn, 'endColumn should match');
|
||||||
|
|
||||||
////// If I call run on RunQueryAction while connected and with an undefined selection
|
////// If I call run on RunQueryAction while connected and with an undefined selection
|
||||||
isConnected = true;
|
isConnected = true;
|
||||||
@@ -312,9 +313,9 @@ suite('SQL QueryAction Tests', () => {
|
|||||||
assert.equal(countCalledShowDialog, 2, 'run should not call showDialog');
|
assert.equal(countCalledShowDialog, 2, 'run should not call showDialog');
|
||||||
assert.equal(countCalledRunQuery, 2, 'run should call runQuery again');
|
assert.equal(countCalledRunQuery, 2, 'run should call runQuery again');
|
||||||
assert.notEqual(runQuerySelection, undefined, 'There should not be an undefined selection in runQuery');
|
assert.notEqual(runQuerySelection, undefined, 'There should not be an undefined selection in runQuery');
|
||||||
assert.equal(runQuerySelection.startLineNumber, selectionToReturnInGetSelection.startLineNumber, 'startLine should match');
|
assert.equal(runQuerySelection.startLine, selectionToReturnInGetSelection.startLine, 'startLine should match');
|
||||||
assert.equal(runQuerySelection.startColumn, selectionToReturnInGetSelection.startColumn, 'startColumn should match');
|
assert.equal(runQuerySelection.startColumn, selectionToReturnInGetSelection.startColumn, 'startColumn should match');
|
||||||
assert.equal(runQuerySelection.endLineNumber, selectionToReturnInGetSelection.endLineNumber, 'endLine should match');
|
assert.equal(runQuerySelection.endLine, selectionToReturnInGetSelection.endLine, 'endLine should match');
|
||||||
assert.equal(runQuerySelection.endColumn, selectionToReturnInGetSelection.endColumn, 'endColumn should match');
|
assert.equal(runQuerySelection.endColumn, selectionToReturnInGetSelection.endColumn, 'endColumn should match');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ MenuRegistry.appendMenuItem(MenuId.DataExplorerContext, {
|
|||||||
id: commands.SCRIPT_AS_CREATE_COMMAND_ID,
|
id: commands.SCRIPT_AS_CREATE_COMMAND_ID,
|
||||||
title: localize('scriptAsCreate', "Script as Create")
|
title: localize('scriptAsCreate', "Script as Create")
|
||||||
},
|
},
|
||||||
when: ContextKeyExpr.and(MssqlNodeContext.CanScriptAsCreateOrDelete, MssqlNodeContext.EngineEdition.notEqualsTo(DatabaseEngineEdition.SqlOnDemand.toString()))
|
when: MssqlNodeContext.CanScriptAsCreateOrDelete
|
||||||
});
|
});
|
||||||
|
|
||||||
// Script as Delete
|
// Script as Delete
|
||||||
@@ -115,10 +115,10 @@ MenuRegistry.appendMenuItem(MenuId.ObjectExplorerItemContext, {
|
|||||||
title: localize('scriptCreate', "Script as Create")
|
title: localize('scriptCreate', "Script as Create")
|
||||||
},
|
},
|
||||||
when: ContextKeyExpr.or(
|
when: ContextKeyExpr.or(
|
||||||
ContextKeyExpr.and(TreeNodeContextKey.NodeType.isEqualTo('Table'), MssqlNodeContext.EngineEdition.notEqualsTo(DatabaseEngineEdition.SqlOnDemand.toString())),
|
TreeNodeContextKey.NodeType.isEqualTo('Table'),
|
||||||
ContextKeyExpr.and(TreeNodeContextKey.NodeType.isEqualTo('View'), MssqlNodeContext.EngineEdition.notEqualsTo(DatabaseEngineEdition.SqlOnDemand.toString())),
|
TreeNodeContextKey.NodeType.isEqualTo('View'),
|
||||||
ContextKeyExpr.and(TreeNodeContextKey.NodeType.isEqualTo('Schema'), MssqlNodeContext.EngineEdition.notEqualsTo(DatabaseEngineEdition.SqlOnDemand.toString())),
|
TreeNodeContextKey.NodeType.isEqualTo('Schema'),
|
||||||
ContextKeyExpr.and(TreeNodeContextKey.NodeType.isEqualTo('User'), MssqlNodeContext.EngineEdition.notEqualsTo(DatabaseEngineEdition.SqlOnDemand.toString())),
|
TreeNodeContextKey.NodeType.isEqualTo('User'),
|
||||||
TreeNodeContextKey.NodeType.isEqualTo('UserDefinedTableType'),
|
TreeNodeContextKey.NodeType.isEqualTo('UserDefinedTableType'),
|
||||||
TreeNodeContextKey.NodeType.isEqualTo('StoredProcedure'),
|
TreeNodeContextKey.NodeType.isEqualTo('StoredProcedure'),
|
||||||
TreeNodeContextKey.NodeType.isEqualTo('AggregateFunction'),
|
TreeNodeContextKey.NodeType.isEqualTo('AggregateFunction'),
|
||||||
@@ -296,7 +296,6 @@ MenuRegistry.appendMenuItem(MenuId.ExplorerWidgetContext, {
|
|||||||
id: commands.ExplorerScriptCreateAction.ID,
|
id: commands.ExplorerScriptCreateAction.ID,
|
||||||
title: commands.ExplorerScriptCreateAction.LABEL
|
title: commands.ExplorerScriptCreateAction.LABEL
|
||||||
},
|
},
|
||||||
when: MssqlNodeContext.EngineEdition.notEqualsTo(DatabaseEngineEdition.SqlOnDemand.toString()),
|
|
||||||
order: 2
|
order: 2
|
||||||
});
|
});
|
||||||
//#endregion
|
//#endregion
|
||||||
|
|||||||
@@ -166,6 +166,10 @@ export class ConnectionDialogService implements IConnectionDialogService {
|
|||||||
}
|
}
|
||||||
profile = result.connection;
|
profile = result.connection;
|
||||||
|
|
||||||
|
if (params.oldProfileId && params.isEditConnection) {
|
||||||
|
profile.id = params.oldProfileId;
|
||||||
|
}
|
||||||
|
|
||||||
profile.serverName = trim(profile.serverName);
|
profile.serverName = trim(profile.serverName);
|
||||||
|
|
||||||
// append the port to the server name for SQL Server connections
|
// append the port to the server name for SQL Server connections
|
||||||
|
|||||||
@@ -235,7 +235,8 @@ export class ConnectionManagementService extends Disposable implements IConnecti
|
|||||||
}
|
}
|
||||||
let params = {
|
let params = {
|
||||||
connectionType: ConnectionType.default,
|
connectionType: ConnectionType.default,
|
||||||
isEditConnection: true
|
isEditConnection: true,
|
||||||
|
oldProfileId: model.id
|
||||||
};
|
};
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|||||||
@@ -349,7 +349,7 @@ suite('SQL ConnectionManagementService tests', () => {
|
|||||||
onConnectCanceled: undefined,
|
onConnectCanceled: undefined,
|
||||||
uri: uri
|
uri: uri
|
||||||
},
|
},
|
||||||
queryRange: undefined,
|
querySelection: undefined,
|
||||||
runQueryOnCompletion: RunQueryOnConnectionMode.none
|
runQueryOnCompletion: RunQueryOnConnectionMode.none
|
||||||
},
|
},
|
||||||
saveTheConnection: true,
|
saveTheConnection: true,
|
||||||
@@ -456,7 +456,7 @@ suite('SQL ConnectionManagementService tests', () => {
|
|||||||
onConnectCanceled: undefined,
|
onConnectCanceled: undefined,
|
||||||
uri: uri1,
|
uri: uri1,
|
||||||
},
|
},
|
||||||
queryRange: undefined,
|
querySelection: undefined,
|
||||||
runQueryOnCompletion: RunQueryOnConnectionMode.none,
|
runQueryOnCompletion: RunQueryOnConnectionMode.none,
|
||||||
isEditConnection: false
|
isEditConnection: false
|
||||||
},
|
},
|
||||||
@@ -494,7 +494,7 @@ suite('SQL ConnectionManagementService tests', () => {
|
|||||||
onConnectCanceled: undefined,
|
onConnectCanceled: undefined,
|
||||||
uri: uri1
|
uri: uri1
|
||||||
},
|
},
|
||||||
queryRange: undefined,
|
querySelection: undefined,
|
||||||
runQueryOnCompletion: RunQueryOnConnectionMode.none,
|
runQueryOnCompletion: RunQueryOnConnectionMode.none,
|
||||||
isEditConnection: false
|
isEditConnection: false
|
||||||
},
|
},
|
||||||
@@ -705,7 +705,7 @@ suite('SQL ConnectionManagementService tests', () => {
|
|||||||
onConnectCanceled: undefined,
|
onConnectCanceled: undefined,
|
||||||
uri: uri
|
uri: uri
|
||||||
},
|
},
|
||||||
queryRange: undefined,
|
querySelection: undefined,
|
||||||
runQueryOnCompletion: RunQueryOnConnectionMode.none
|
runQueryOnCompletion: RunQueryOnConnectionMode.none
|
||||||
},
|
},
|
||||||
saveTheConnection: true,
|
saveTheConnection: true,
|
||||||
|
|||||||
@@ -1,123 +0,0 @@
|
|||||||
/*---------------------------------------------------------------------------------------------
|
|
||||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
||||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
|
||||||
*--------------------------------------------------------------------------------------------*/
|
|
||||||
|
|
||||||
import * as azdata from 'azdata';
|
|
||||||
import * as nls from 'vs/nls';
|
|
||||||
|
|
||||||
import QueryRunner from 'sql/workbench/services/query/common/queryRunner';
|
|
||||||
import Severity from 'vs/base/common/severity';
|
|
||||||
import { INotificationService } from 'vs/platform/notification/common/notification';
|
|
||||||
import { IQueryManagementService } from 'sql/workbench/services/query/common/queryManagement';
|
|
||||||
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
|
||||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
|
||||||
import { ITextResourcePropertiesService } from 'vs/editor/common/services/textResourceConfigurationService';
|
|
||||||
import { ILogService } from 'vs/platform/log/common/log';
|
|
||||||
import { Emitter } from 'vs/base/common/event';
|
|
||||||
|
|
||||||
export interface IEditSessionReadyEvent {
|
|
||||||
ownerUri: string;
|
|
||||||
success: boolean;
|
|
||||||
message: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export default class EditQueryRunner extends QueryRunner {
|
|
||||||
|
|
||||||
private readonly _onEditSessionReady = this._register(new Emitter<IEditSessionReadyEvent>());
|
|
||||||
public readonly onEditSessionReady = this._onEditSessionReady.event;
|
|
||||||
|
|
||||||
constructor(
|
|
||||||
public uri: string,
|
|
||||||
@INotificationService private readonly notificationService: INotificationService,
|
|
||||||
@IQueryManagementService queryManagementService: IQueryManagementService,
|
|
||||||
@IConfigurationService configurationService: IConfigurationService,
|
|
||||||
@IInstantiationService instantiationService: IInstantiationService,
|
|
||||||
@ITextResourcePropertiesService textResourcePropertiesService: ITextResourcePropertiesService,
|
|
||||||
@ILogService logService: ILogService
|
|
||||||
) {
|
|
||||||
super(uri, queryManagementService, configurationService, instantiationService, textResourcePropertiesService, logService);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Handle a session ready event for Edit Data
|
|
||||||
*/
|
|
||||||
public async 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
|
|
||||||
|
|
||||||
try {
|
|
||||||
await this.queryManagementService.initializeEdit(ownerUri, schemaName, objectName, objectType, rowLimit, queryString);
|
|
||||||
// The query has started, so lets fire up the result pane
|
|
||||||
this._onQueryStart.fire();
|
|
||||||
this.queryManagementService.registerRunner(this, ownerUri);
|
|
||||||
} catch (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 async getEditRows(rowStart: number, numberOfRows: number): Promise<azdata.EditSubsetResult> {
|
|
||||||
let rowData: azdata.EditSubsetParams = {
|
|
||||||
ownerUri: this.uri,
|
|
||||||
rowCount: numberOfRows,
|
|
||||||
rowStartIndex: rowStart
|
|
||||||
};
|
|
||||||
|
|
||||||
const result = await this.queryManagementService.getEditRows(rowData);
|
|
||||||
if (!result.hasOwnProperty('rowCount')) {
|
|
||||||
let error = `Nothing returned from subset query`;
|
|
||||||
this.notificationService.notify({
|
|
||||||
severity: Severity.Error,
|
|
||||||
message: error
|
|
||||||
});
|
|
||||||
throw new Error(error);
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -6,11 +6,12 @@
|
|||||||
import { IConnectionManagementService } from 'sql/platform/connection/common/connectionManagement';
|
import { IConnectionManagementService } from 'sql/platform/connection/common/connectionManagement';
|
||||||
import { IConnectionProfile } from 'sql/platform/connection/common/interfaces';
|
import { IConnectionProfile } from 'sql/platform/connection/common/interfaces';
|
||||||
import QueryRunner from 'sql/workbench/services/query/common/queryRunner';
|
import QueryRunner from 'sql/workbench/services/query/common/queryRunner';
|
||||||
import { IColumn, ICellValue, ResultSetSubset } from 'sql/workbench/services/query/common/query';
|
|
||||||
import * as Utils from 'sql/platform/connection/common/utils';
|
import * as Utils from 'sql/platform/connection/common/utils';
|
||||||
import { IErrorMessageService } from 'sql/platform/errorMessage/common/errorMessageService';
|
import { IErrorMessageService } from 'sql/platform/errorMessage/common/errorMessageService';
|
||||||
import { resolveQueryFilePath } from '../common/insightsUtils';
|
import { resolveQueryFilePath } from '../common/insightsUtils';
|
||||||
|
|
||||||
|
import { DbCellValue, IDbColumn, QueryExecuteSubsetResult } from 'azdata';
|
||||||
|
|
||||||
import Severity from 'vs/base/common/severity';
|
import Severity from 'vs/base/common/severity';
|
||||||
import * as types from 'vs/base/common/types';
|
import * as types from 'vs/base/common/types';
|
||||||
import * as nls from 'vs/nls';
|
import * as nls from 'vs/nls';
|
||||||
@@ -26,8 +27,8 @@ export class InsightsDialogController {
|
|||||||
private _queryRunner: QueryRunner;
|
private _queryRunner: QueryRunner;
|
||||||
private _connectionProfile: IConnectionProfile;
|
private _connectionProfile: IConnectionProfile;
|
||||||
private _connectionUri: string;
|
private _connectionUri: string;
|
||||||
private _columns: IColumn[];
|
private _columns: IDbColumn[];
|
||||||
private _rows: ICellValue[][];
|
private _rows: DbCellValue[][];
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private readonly _model: IInsightsDialogModel,
|
private readonly _model: IInsightsDialogModel,
|
||||||
@@ -159,13 +160,13 @@ export class InsightsDialogController {
|
|||||||
) {
|
) {
|
||||||
let resultset = batch.resultSetSummaries[0];
|
let resultset = batch.resultSetSummaries[0];
|
||||||
this._columns = resultset.columnInfo;
|
this._columns = resultset.columnInfo;
|
||||||
let rows: ResultSetSubset;
|
let rows: QueryExecuteSubsetResult;
|
||||||
try {
|
try {
|
||||||
rows = await this._queryRunner.getQueryRows(0, resultset.rowCount, batch.id, resultset.id);
|
rows = await this._queryRunner.getQueryRows(0, resultset.rowCount, batch.id, resultset.id);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
return Promise.reject(e);
|
return Promise.reject(e);
|
||||||
}
|
}
|
||||||
this._rows = rows.rows;
|
this._rows = rows.resultSubset.rows;
|
||||||
this.updateModel();
|
this.updateModel();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,13 +4,13 @@
|
|||||||
*--------------------------------------------------------------------------------------------*/
|
*--------------------------------------------------------------------------------------------*/
|
||||||
|
|
||||||
import { InsightsDialogController } from 'sql/workbench/services/insights/browser/insightsDialogController';
|
import { InsightsDialogController } from 'sql/workbench/services/insights/browser/insightsDialogController';
|
||||||
import QueryRunner from 'sql/workbench/services/query/common/queryRunner';
|
import QueryRunner, { IQueryMessage } from 'sql/workbench/services/query/common/queryRunner';
|
||||||
import { IQueryMessage, BatchSummary, IColumn, ResultSetSubset } from 'sql/workbench/services/query/common/query';
|
|
||||||
import { ConnectionManagementService } from 'sql/workbench/services/connection/browser/connectionManagementService';
|
import { ConnectionManagementService } from 'sql/workbench/services/connection/browser/connectionManagementService';
|
||||||
import { IConnectionProfile } from 'sql/platform/connection/common/interfaces';
|
import { IConnectionProfile } from 'sql/platform/connection/common/interfaces';
|
||||||
|
|
||||||
import { InstantiationService } from 'vs/platform/instantiation/common/instantiationService';
|
import { InstantiationService } from 'vs/platform/instantiation/common/instantiationService';
|
||||||
|
|
||||||
|
import * as azdata from 'azdata';
|
||||||
import { equal } from 'assert';
|
import { equal } from 'assert';
|
||||||
import { Mock, MockBehavior, It } from 'typemoq';
|
import { Mock, MockBehavior, It } from 'typemoq';
|
||||||
import { Emitter } from 'vs/base/common/event';
|
import { Emitter } from 'vs/base/common/event';
|
||||||
@@ -114,12 +114,12 @@ function getPrimedQueryRunner(data: string[][], columns: string[]): IPrimedQuery
|
|||||||
querymock.setup(x => x.onQueryEnd).returns(x => emitter.event);
|
querymock.setup(x => x.onQueryEnd).returns(x => emitter.event);
|
||||||
querymock.setup(x => x.onMessage).returns(x => new Emitter<[IQueryMessage]>().event);
|
querymock.setup(x => x.onMessage).returns(x => new Emitter<[IQueryMessage]>().event);
|
||||||
querymock.setup(x => x.batchSets).returns(x => {
|
querymock.setup(x => x.batchSets).returns(x => {
|
||||||
return <Array<BatchSummary>>[
|
return <Array<azdata.BatchSummary>>[
|
||||||
{
|
{
|
||||||
id: 0,
|
id: 0,
|
||||||
resultSetSummaries: [
|
resultSetSummaries: [
|
||||||
{
|
{
|
||||||
columnInfo: <Array<IColumn>>columns.map(c => { return { columnName: c }; }),
|
columnInfo: <Array<azdata.IDbColumn>>columns.map(c => { return { columnName: c }; }),
|
||||||
id: 0,
|
id: 0,
|
||||||
rowCount: data.length
|
rowCount: data.length
|
||||||
}
|
}
|
||||||
@@ -129,9 +129,11 @@ function getPrimedQueryRunner(data: string[][], columns: string[]): IPrimedQuery
|
|||||||
});
|
});
|
||||||
|
|
||||||
querymock.setup(x => x.getQueryRows(It.isAnyNumber(), It.isAnyNumber(), It.isAnyNumber(), It.isAnyNumber()))
|
querymock.setup(x => x.getQueryRows(It.isAnyNumber(), It.isAnyNumber(), It.isAnyNumber(), It.isAnyNumber()))
|
||||||
.returns(x => Promise.resolve(<ResultSetSubset>{
|
.returns(x => Promise.resolve(<azdata.QueryExecuteSubsetResult>{
|
||||||
rowCount: data.length,
|
resultSubset: <azdata.ResultSetSubset>{
|
||||||
rows: data.map(r => r.map(c => { return { displayValue: c }; }))
|
rowCount: data.length,
|
||||||
|
rows: data.map(r => r.map(c => { return { displayValue: c }; }))
|
||||||
|
}
|
||||||
}));
|
}));
|
||||||
|
|
||||||
querymock.setup(x => x.runQuery(It.isAnyString())).returns(x => Promise.resolve());
|
querymock.setup(x => x.runQuery(It.isAnyString())).returns(x => Promise.resolve());
|
||||||
|
|||||||
@@ -3,10 +3,9 @@
|
|||||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||||
*--------------------------------------------------------------------------------------------*/
|
*--------------------------------------------------------------------------------------------*/
|
||||||
|
|
||||||
import { nb, IResultMessage } from 'azdata';
|
import { nb, QueryExecuteSubsetResult, IDbColumn, BatchSummary, IResultMessage, ResultSetSummary } from 'azdata';
|
||||||
import { localize } from 'vs/nls';
|
import { localize } from 'vs/nls';
|
||||||
import QueryRunner from 'sql/workbench/services/query/common/queryRunner';
|
import QueryRunner from 'sql/workbench/services/query/common/queryRunner';
|
||||||
import { BatchSummary, ResultSetSummary, IColumn, ResultSetSubset } from 'sql/workbench/services/query/common/query';
|
|
||||||
import { IConnectionManagementService } from 'sql/platform/connection/common/connectionManagement';
|
import { IConnectionManagementService } from 'sql/platform/connection/common/connectionManagement';
|
||||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||||
import Severity from 'vs/base/common/severity';
|
import Severity from 'vs/base/common/severity';
|
||||||
@@ -344,7 +343,7 @@ class SqlKernel extends Disposable implements nb.IKernel {
|
|||||||
this._register(queryRunner.onMessage(messages => {
|
this._register(queryRunner.onMessage(messages => {
|
||||||
// TODO handle showing a messages output (should be updated with all messages, only changing 1 output in total)
|
// TODO handle showing a messages output (should be updated with all messages, only changing 1 output in total)
|
||||||
for (const message of messages) {
|
for (const message of messages) {
|
||||||
if (this._future && isUndefinedOrNull(message.range)) {
|
if (this._future && isUndefinedOrNull(message.selection)) {
|
||||||
this._future.handleMessage(message);
|
this._future.handleMessage(message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -384,7 +383,7 @@ export class SQLFuture extends Disposable implements FutureInternal {
|
|||||||
private doneDeferred = new Deferred<nb.IShellMessage>();
|
private doneDeferred = new Deferred<nb.IShellMessage>();
|
||||||
private configuredMaxRows: number = MAX_ROWS;
|
private configuredMaxRows: number = MAX_ROWS;
|
||||||
private _outputAddedPromises: Promise<void>[] = [];
|
private _outputAddedPromises: Promise<void>[] = [];
|
||||||
private _querySubsetResultMap: Map<number, ResultSetSubset> = new Map<number, ResultSetSubset>();
|
private _querySubsetResultMap: Map<number, QueryExecuteSubsetResult> = new Map<number, QueryExecuteSubsetResult>();
|
||||||
private _errorOccurred: boolean = false;
|
private _errorOccurred: boolean = false;
|
||||||
private _stopOnError: boolean = true;
|
private _stopOnError: boolean = true;
|
||||||
constructor(
|
constructor(
|
||||||
@@ -509,11 +508,11 @@ export class SQLFuture extends Disposable implements FutureInternal {
|
|||||||
this._querySubsetResultMap.set(resultSet.id, result);
|
this._querySubsetResultMap.set(resultSet.id, result);
|
||||||
deferred.resolve();
|
deferred.resolve();
|
||||||
}, (err) => {
|
}, (err) => {
|
||||||
this._querySubsetResultMap.set(resultSet.id, { rowCount: 0, rows: [] });
|
this._querySubsetResultMap.set(resultSet.id, { message: '', resultSubset: { rowCount: 0, rows: [] } });
|
||||||
deferred.reject(err);
|
deferred.reject(err);
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
this._querySubsetResultMap.set(resultSet.id, { rowCount: 0, rows: [] });
|
this._querySubsetResultMap.set(resultSet.id, { message: '', resultSubset: { rowCount: 0, rows: [] } });
|
||||||
deferred.resolve();
|
deferred.resolve();
|
||||||
}
|
}
|
||||||
return deferred;
|
return deferred;
|
||||||
@@ -526,7 +525,7 @@ export class SQLFuture extends Disposable implements FutureInternal {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private sendIOPubMessage(subsetResult: ResultSetSubset, resultSet: ResultSetSummary): void {
|
private sendIOPubMessage(subsetResult: QueryExecuteSubsetResult, resultSet: ResultSetSummary): void {
|
||||||
let msg: nb.IIOPubMessage = {
|
let msg: nb.IIOPubMessage = {
|
||||||
channel: 'iopub',
|
channel: 'iopub',
|
||||||
type: 'iopub',
|
type: 'iopub',
|
||||||
@@ -561,7 +560,7 @@ export class SQLFuture extends Disposable implements FutureInternal {
|
|||||||
// no-op
|
// no-op
|
||||||
}
|
}
|
||||||
|
|
||||||
private convertToDataResource(columns: IColumn[], subsetResult: ResultSetSubset): IDataResource {
|
private convertToDataResource(columns: IDbColumn[], subsetResult: QueryExecuteSubsetResult): IDataResource {
|
||||||
let columnsResources: IDataResourceSchema[] = [];
|
let columnsResources: IDataResourceSchema[] = [];
|
||||||
columns.forEach(column => {
|
columns.forEach(column => {
|
||||||
columnsResources.push({ name: escape(column.columnName) });
|
columnsResources.push({ name: escape(column.columnName) });
|
||||||
@@ -570,7 +569,7 @@ export class SQLFuture extends Disposable implements FutureInternal {
|
|||||||
columnsFields.fields = columnsResources;
|
columnsFields.fields = columnsResources;
|
||||||
return {
|
return {
|
||||||
schema: columnsFields,
|
schema: columnsFields,
|
||||||
data: subsetResult.rows.map(row => {
|
data: subsetResult.resultSubset.rows.map(row => {
|
||||||
let rowObject: { [key: string]: any; } = {};
|
let rowObject: { [key: string]: any; } = {};
|
||||||
row.forEach((val, index) => {
|
row.forEach((val, index) => {
|
||||||
rowObject[index] = val.displayValue;
|
rowObject[index] = val.displayValue;
|
||||||
@@ -580,9 +579,9 @@ export class SQLFuture extends Disposable implements FutureInternal {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
private convertToHtmlTable(columns: IColumn[], d: ResultSetSubset): string[] {
|
private convertToHtmlTable(columns: IDbColumn[], d: QueryExecuteSubsetResult): string[] {
|
||||||
// Adding 3 for <table>, column title rows, </table>
|
// Adding 3 for <table>, column title rows, </table>
|
||||||
let htmlStringArr: string[] = new Array(d.rowCount + 3);
|
let htmlStringArr: string[] = new Array(d.resultSubset.rowCount + 3);
|
||||||
htmlStringArr[0] = '<table>';
|
htmlStringArr[0] = '<table>';
|
||||||
if (columns.length > 0) {
|
if (columns.length > 0) {
|
||||||
let columnHeaders = '<tr>';
|
let columnHeaders = '<tr>';
|
||||||
@@ -593,7 +592,7 @@ export class SQLFuture extends Disposable implements FutureInternal {
|
|||||||
htmlStringArr[1] = columnHeaders;
|
htmlStringArr[1] = columnHeaders;
|
||||||
}
|
}
|
||||||
let i = 2;
|
let i = 2;
|
||||||
for (const row of d.rows) {
|
for (const row of d.resultSubset.rows) {
|
||||||
let rowData = '<tr>';
|
let rowData = '<tr>';
|
||||||
for (let columnIndex = 0; columnIndex < columns.length; columnIndex++) {
|
for (let columnIndex = 0; columnIndex < columns.length; columnIndex++) {
|
||||||
rowData += `<td>${escape(row[columnIndex].displayValue)}</td>`;
|
rowData += `<td>${escape(row[columnIndex].displayValue)}</td>`;
|
||||||
|
|||||||
@@ -3,9 +3,9 @@
|
|||||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||||
*--------------------------------------------------------------------------------------------*/
|
*--------------------------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
import * as azdata from 'azdata';
|
||||||
import * as types from 'vs/base/common/types';
|
import * as types from 'vs/base/common/types';
|
||||||
import { SaveFormat } from 'sql/workbench/services/query/common/resultSerializer';
|
import { SaveFormat } from 'sql/workbench/services/query/common/resultSerializer';
|
||||||
import { ResultSetSubset } from 'sql/workbench/services/query/common/query';
|
|
||||||
|
|
||||||
export interface IGridDataProvider {
|
export interface IGridDataProvider {
|
||||||
|
|
||||||
@@ -14,7 +14,7 @@ export interface IGridDataProvider {
|
|||||||
* @param rowStart 0-indexed start row to retrieve data from
|
* @param rowStart 0-indexed start row to retrieve data from
|
||||||
* @param numberOfRows total number of rows of data to retrieve
|
* @param numberOfRows total number of rows of data to retrieve
|
||||||
*/
|
*/
|
||||||
getRowData(rowStart: number, numberOfRows: number): Thenable<ResultSetSubset>;
|
getRowData(rowStart: number, numberOfRows: number): Thenable<azdata.QueryExecuteSubsetResult>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sends a copy request to copy data to the clipboard
|
* Sends a copy request to copy data to the clipboard
|
||||||
@@ -65,8 +65,8 @@ export async function getResultsString(provider: IGridDataProvider, selection: S
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Iterate over the rows to paste into the copy string
|
// Iterate over the rows to paste into the copy string
|
||||||
for (let rowIndex: number = 0; rowIndex < result.rows.length; rowIndex++) {
|
for (let rowIndex: number = 0; rowIndex < result.resultSubset.rows.length; rowIndex++) {
|
||||||
let row = result.rows[rowIndex];
|
let row = result.resultSubset.rows[rowIndex];
|
||||||
let cellObjects = row.slice(range.fromCell, (range.toCell + 1));
|
let cellObjects = row.slice(range.fromCell, (range.toCell + 1));
|
||||||
// Remove newlines if requested
|
// Remove newlines if requested
|
||||||
let cells = provider.shouldRemoveNewLines()
|
let cells = provider.shouldRemoveNewLines()
|
||||||
|
|||||||
@@ -1,69 +0,0 @@
|
|||||||
/*---------------------------------------------------------------------------------------------
|
|
||||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
||||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
|
||||||
*--------------------------------------------------------------------------------------------*/
|
|
||||||
|
|
||||||
import { IRange } from 'vs/editor/common/core/range';
|
|
||||||
|
|
||||||
export interface IColumn {
|
|
||||||
columnName: string;
|
|
||||||
isXml?: boolean;
|
|
||||||
isJson?: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface ResultSetSummary {
|
|
||||||
id: number;
|
|
||||||
batchId: number;
|
|
||||||
rowCount: number;
|
|
||||||
columnInfo: IColumn[];
|
|
||||||
complete: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface BatchStartSummary {
|
|
||||||
id: number;
|
|
||||||
executionStart: string;
|
|
||||||
range?: IRange;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface BatchSummary extends BatchStartSummary {
|
|
||||||
hasError: boolean;
|
|
||||||
resultSetSummaries: ResultSetSummary[];
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface CompleteBatchSummary extends BatchSummary {
|
|
||||||
executionElapsed: string;
|
|
||||||
executionEnd: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface IQueryMessage {
|
|
||||||
batchId?: number;
|
|
||||||
isError: boolean;
|
|
||||||
time?: string;
|
|
||||||
message: string;
|
|
||||||
range?: IRange;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface IResultMessage {
|
|
||||||
batchId?: number;
|
|
||||||
isError: boolean;
|
|
||||||
time?: string;
|
|
||||||
message: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface QueryExecuteSubsetParams {
|
|
||||||
ownerUri: string;
|
|
||||||
batchIndex: number;
|
|
||||||
resultSetIndex: number;
|
|
||||||
rowsStartIndex: number;
|
|
||||||
rowsCount: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface ResultSetSubset {
|
|
||||||
rowCount: number;
|
|
||||||
rows: ICellValue[][];
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface ICellValue {
|
|
||||||
displayValue: string;
|
|
||||||
isNull?: boolean;
|
|
||||||
}
|
|
||||||
@@ -13,24 +13,11 @@ import { Event, Emitter } from 'vs/base/common/event';
|
|||||||
import { keys } from 'vs/base/common/map';
|
import { keys } from 'vs/base/common/map';
|
||||||
import { assign } from 'vs/base/common/objects';
|
import { assign } from 'vs/base/common/objects';
|
||||||
import { IAdsTelemetryService, ITelemetryEventProperties } from 'sql/platform/telemetry/common/telemetry';
|
import { IAdsTelemetryService, ITelemetryEventProperties } from 'sql/platform/telemetry/common/telemetry';
|
||||||
import EditQueryRunner from 'sql/workbench/services/editData/common/editQueryRunner';
|
|
||||||
import { IRange, Range } from 'vs/editor/common/core/range';
|
|
||||||
import { ResultSetSubset } from 'sql/workbench/services/query/common/query';
|
|
||||||
import { isUndefined } from 'vs/base/common/types';
|
|
||||||
|
|
||||||
export const SERVICE_ID = 'queryManagementService';
|
export const SERVICE_ID = 'queryManagementService';
|
||||||
|
|
||||||
export const IQueryManagementService = createDecorator<IQueryManagementService>(SERVICE_ID);
|
export const IQueryManagementService = createDecorator<IQueryManagementService>(SERVICE_ID);
|
||||||
|
|
||||||
export interface QueryCancelResult {
|
|
||||||
messages: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface ExecutionPlanOptions {
|
|
||||||
displayEstimatedQueryPlan?: boolean;
|
|
||||||
displayActualQueryPlan?: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface IQueryManagementService {
|
export interface IQueryManagementService {
|
||||||
_serviceBrand: undefined;
|
_serviceBrand: undefined;
|
||||||
|
|
||||||
@@ -41,13 +28,13 @@ export interface IQueryManagementService {
|
|||||||
getRegisteredProviders(): string[];
|
getRegisteredProviders(): string[];
|
||||||
registerRunner(runner: QueryRunner, uri: string): void;
|
registerRunner(runner: QueryRunner, uri: string): void;
|
||||||
|
|
||||||
cancelQuery(ownerUri: string): Promise<QueryCancelResult>;
|
cancelQuery(ownerUri: string): Promise<azdata.QueryCancelResult>;
|
||||||
runQuery(ownerUri: string, range: IRange, runOptions?: ExecutionPlanOptions): Promise<void>;
|
runQuery(ownerUri: string, selection: azdata.ISelectionData, runOptions?: azdata.ExecutionPlanOptions): Promise<void>;
|
||||||
runQueryStatement(ownerUri: string, line: number, column: number): Promise<void>;
|
runQueryStatement(ownerUri: string, line: number, column: number): Promise<void>;
|
||||||
runQueryString(ownerUri: string, queryString: string): Promise<void>;
|
runQueryString(ownerUri: string, queryString: string): Promise<void>;
|
||||||
runQueryAndReturn(ownerUri: string, queryString: string): Promise<azdata.SimpleExecuteResult>;
|
runQueryAndReturn(ownerUri: string, queryString: string): Promise<azdata.SimpleExecuteResult>;
|
||||||
parseSyntax(ownerUri: string, query: string): Promise<azdata.SyntaxParseResult>;
|
parseSyntax(ownerUri: string, query: string): Promise<azdata.SyntaxParseResult>;
|
||||||
getQueryRows(rowData: azdata.QueryExecuteSubsetParams): Promise<ResultSetSubset>;
|
getQueryRows(rowData: azdata.QueryExecuteSubsetParams): Promise<azdata.QueryExecuteSubsetResult>;
|
||||||
disposeQuery(ownerUri: string): Promise<void>;
|
disposeQuery(ownerUri: string): Promise<void>;
|
||||||
saveResults(requestParams: azdata.SaveResultsRequestParams): Promise<azdata.SaveResultRequestResult>;
|
saveResults(requestParams: azdata.SaveResultsRequestParams): Promise<azdata.SaveResultRequestResult>;
|
||||||
setQueryExecutionOptions(uri: string, options: azdata.QueryExecutionOptions): Promise<void>;
|
setQueryExecutionOptions(uri: string, options: azdata.QueryExecutionOptions): Promise<void>;
|
||||||
@@ -80,7 +67,7 @@ export interface IQueryManagementService {
|
|||||||
*/
|
*/
|
||||||
export interface IQueryRequestHandler {
|
export interface IQueryRequestHandler {
|
||||||
cancelQuery(ownerUri: string): Promise<azdata.QueryCancelResult>;
|
cancelQuery(ownerUri: string): Promise<azdata.QueryCancelResult>;
|
||||||
runQuery(ownerUri: string, selection: azdata.ISelectionData, runOptions?: ExecutionPlanOptions): Promise<void>;
|
runQuery(ownerUri: string, selection: azdata.ISelectionData, runOptions?: azdata.ExecutionPlanOptions): Promise<void>;
|
||||||
runQueryStatement(ownerUri: string, line: number, column: number): Promise<void>;
|
runQueryStatement(ownerUri: string, line: number, column: number): Promise<void>;
|
||||||
runQueryString(ownerUri: string, queryString: string): Promise<void>;
|
runQueryString(ownerUri: string, queryString: string): Promise<void>;
|
||||||
runQueryAndReturn(ownerUri: string, queryString: string): Promise<azdata.SimpleExecuteResult>;
|
runQueryAndReturn(ownerUri: string, queryString: string): Promise<azdata.SimpleExecuteResult>;
|
||||||
@@ -142,7 +129,7 @@ export class QueryManagementService implements IQueryManagementService {
|
|||||||
// Handles logic to run the given handlerCallback at the appropriate time. If the given runner is
|
// Handles logic to run the given handlerCallback at the appropriate time. If the given runner is
|
||||||
// undefined, the handlerCallback is put on the _handlerCallbackQueue to be run once the runner is set
|
// undefined, the handlerCallback is put on the _handlerCallbackQueue to be run once the runner is set
|
||||||
// public for testing only
|
// public for testing only
|
||||||
private enqueueOrRun(handlerCallback: (runnerParam: QueryRunner) => void, runner?: QueryRunner): void {
|
private enqueueOrRun(handlerCallback: (runnerParam: QueryRunner) => void, runner: QueryRunner): void {
|
||||||
if (runner === undefined) {
|
if (runner === undefined) {
|
||||||
this._handlerCallbackQueue.push(handlerCallback);
|
this._handlerCallbackQueue.push(handlerCallback);
|
||||||
} else {
|
} else {
|
||||||
@@ -150,9 +137,9 @@ export class QueryManagementService implements IQueryManagementService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private _notify(ownerUri: string, sendNotification: (runner: QueryRunner | EditQueryRunner) => void): void {
|
private _notify(ownerUri: string, sendNotification: (runner: QueryRunner) => void): void {
|
||||||
let runner = this._queryRunners.get(ownerUri);
|
let runner = this._queryRunners.get(ownerUri);
|
||||||
this.enqueueOrRun(sendNotification, runner);
|
this.enqueueOrRun(sendNotification, runner!);
|
||||||
}
|
}
|
||||||
|
|
||||||
public addQueryRequestHandler(queryType: string, handler: IQueryRequestHandler): IDisposable {
|
public addQueryRequestHandler(queryType: string, handler: IQueryRequestHandler): IDisposable {
|
||||||
@@ -178,7 +165,7 @@ export class QueryManagementService implements IQueryManagementService {
|
|||||||
return Array.from(keys(this._requestHandlers));
|
return Array.from(keys(this._requestHandlers));
|
||||||
}
|
}
|
||||||
|
|
||||||
private addTelemetry(eventName: string, ownerUri: string, runOptions?: ExecutionPlanOptions): void {
|
private addTelemetry(eventName: string, ownerUri: string, runOptions?: azdata.ExecutionPlanOptions): void {
|
||||||
const providerId: string = this._connectionService.getProviderIdFromUri(ownerUri);
|
const providerId: string = this._connectionService.getProviderIdFromUri(ownerUri);
|
||||||
const data: ITelemetryEventProperties = {
|
const data: ITelemetryEventProperties = {
|
||||||
provider: providerId,
|
provider: providerId,
|
||||||
@@ -210,59 +197,51 @@ export class QueryManagementService implements IQueryManagementService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public cancelQuery(ownerUri: string): Promise<QueryCancelResult> {
|
public cancelQuery(ownerUri: string): Promise<azdata.QueryCancelResult> {
|
||||||
this.addTelemetry(TelemetryKeys.CancelQuery, ownerUri);
|
this.addTelemetry(TelemetryKeys.CancelQuery, ownerUri);
|
||||||
return this._runAction(ownerUri, (runner) => {
|
return this._runAction(ownerUri, (runner) => {
|
||||||
return runner.cancelQuery(ownerUri);
|
return runner.cancelQuery(ownerUri);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
public runQuery(ownerUri: string, selection: azdata.ISelectionData, runOptions?: azdata.ExecutionPlanOptions): Promise<void> {
|
||||||
public runQuery(ownerUri: string, range?: IRange, runOptions?: ExecutionPlanOptions): Promise<void> {
|
|
||||||
this.addTelemetry(TelemetryKeys.RunQuery, ownerUri, runOptions);
|
this.addTelemetry(TelemetryKeys.RunQuery, ownerUri, runOptions);
|
||||||
return this._runAction(ownerUri, (runner) => {
|
return this._runAction(ownerUri, (runner) => {
|
||||||
return runner.runQuery(ownerUri, rangeToSelectionData(range), runOptions);
|
return runner.runQuery(ownerUri, selection, runOptions);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public runQueryStatement(ownerUri: string, line: number, column: number): Promise<void> {
|
public runQueryStatement(ownerUri: string, line: number, column: number): Promise<void> {
|
||||||
this.addTelemetry(TelemetryKeys.RunQueryStatement, ownerUri);
|
this.addTelemetry(TelemetryKeys.RunQueryStatement, ownerUri);
|
||||||
return this._runAction(ownerUri, (runner) => {
|
return this._runAction(ownerUri, (runner) => {
|
||||||
return runner.runQueryStatement(ownerUri, line - 1, column - 1); // we are taking in a vscode IRange which is 1 indexed, but our api expected a 0 index
|
return runner.runQueryStatement(ownerUri, line, column);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public runQueryString(ownerUri: string, queryString: string): Promise<void> {
|
public runQueryString(ownerUri: string, queryString: string): Promise<void> {
|
||||||
this.addTelemetry(TelemetryKeys.RunQueryString, ownerUri);
|
this.addTelemetry(TelemetryKeys.RunQueryString, ownerUri);
|
||||||
return this._runAction(ownerUri, (runner) => {
|
return this._runAction(ownerUri, (runner) => {
|
||||||
return runner.runQueryString(ownerUri, queryString);
|
return runner.runQueryString(ownerUri, queryString);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public runQueryAndReturn(ownerUri: string, queryString: string): Promise<azdata.SimpleExecuteResult> {
|
public runQueryAndReturn(ownerUri: string, queryString: string): Promise<azdata.SimpleExecuteResult> {
|
||||||
return this._runAction(ownerUri, (runner) => {
|
return this._runAction(ownerUri, (runner) => {
|
||||||
return runner.runQueryAndReturn(ownerUri, queryString);
|
return runner.runQueryAndReturn(ownerUri, queryString);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public parseSyntax(ownerUri: string, query: string): Promise<azdata.SyntaxParseResult> {
|
public parseSyntax(ownerUri: string, query: string): Promise<azdata.SyntaxParseResult> {
|
||||||
return this._runAction(ownerUri, (runner) => {
|
return this._runAction(ownerUri, (runner) => {
|
||||||
return runner.parseSyntax(ownerUri, query);
|
return runner.parseSyntax(ownerUri, query);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
public getQueryRows(rowData: azdata.QueryExecuteSubsetParams): Promise<azdata.QueryExecuteSubsetResult> {
|
||||||
public async getQueryRows(rowData: azdata.QueryExecuteSubsetParams): Promise<ResultSetSubset> {
|
|
||||||
return this._runAction(rowData.ownerUri, (runner) => {
|
return this._runAction(rowData.ownerUri, (runner) => {
|
||||||
return runner.getQueryRows(rowData).then(r => r.resultSubset);
|
return runner.getQueryRows(rowData);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public disposeQuery(ownerUri: string): Promise<void> {
|
public disposeQuery(ownerUri: string): Promise<void> {
|
||||||
this._queryRunners.delete(ownerUri);
|
this._queryRunners.delete(ownerUri);
|
||||||
return this._runAction(ownerUri, (runner) => {
|
return this._runAction(ownerUri, (runner) => {
|
||||||
return runner.disposeQuery(ownerUri);
|
return runner.disposeQuery(ownerUri);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public setQueryExecutionOptions(ownerUri: string, options: azdata.QueryExecutionOptions): Promise<void> {
|
public setQueryExecutionOptions(ownerUri: string, options: azdata.QueryExecutionOptions): Promise<void> {
|
||||||
return this._runAction(ownerUri, (runner) => {
|
return this._runAction(ownerUri, (runner) => {
|
||||||
return runner.setQueryExecutionOptions(ownerUri, options);
|
return runner.setQueryExecutionOptions(ownerUri, options);
|
||||||
@@ -277,38 +256,37 @@ export class QueryManagementService implements IQueryManagementService {
|
|||||||
|
|
||||||
public onQueryComplete(result: azdata.QueryExecuteCompleteNotificationResult): void {
|
public onQueryComplete(result: azdata.QueryExecuteCompleteNotificationResult): void {
|
||||||
this._notify(result.ownerUri, (runner: QueryRunner) => {
|
this._notify(result.ownerUri, (runner: QueryRunner) => {
|
||||||
runner.handleQueryComplete(result.batchSummaries.map(s => ({ ...s, range: selectionDataToRange(s.selection) })));
|
runner.handleQueryComplete(result);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public onBatchStart(batchInfo: azdata.QueryExecuteBatchNotificationParams): void {
|
public onBatchStart(batchInfo: azdata.QueryExecuteBatchNotificationParams): void {
|
||||||
this._notify(batchInfo.ownerUri, (runner: QueryRunner) => {
|
this._notify(batchInfo.ownerUri, (runner: QueryRunner) => {
|
||||||
runner.handleBatchStart({ ...batchInfo.batchSummary, range: selectionDataToRange(batchInfo.batchSummary.selection) });
|
runner.handleBatchStart(batchInfo);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public onBatchComplete(batchInfo: azdata.QueryExecuteBatchNotificationParams): void {
|
public onBatchComplete(batchInfo: azdata.QueryExecuteBatchNotificationParams): void {
|
||||||
this._notify(batchInfo.ownerUri, (runner: QueryRunner) => {
|
this._notify(batchInfo.ownerUri, (runner: QueryRunner) => {
|
||||||
runner.handleBatchComplete({ range: selectionDataToRange(batchInfo.batchSummary.selection), ...batchInfo.batchSummary });
|
runner.handleBatchComplete(batchInfo);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public onResultSetAvailable(resultSetInfo: azdata.QueryExecuteResultSetNotificationParams): void {
|
public onResultSetAvailable(resultSetInfo: azdata.QueryExecuteResultSetNotificationParams): void {
|
||||||
this._notify(resultSetInfo.ownerUri, (runner: QueryRunner) => {
|
this._notify(resultSetInfo.ownerUri, (runner: QueryRunner) => {
|
||||||
runner.handleResultSetAvailable(resultSetInfo.resultSetSummary);
|
runner.handleResultSetAvailable(resultSetInfo);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public onResultSetUpdated(resultSetInfo: azdata.QueryExecuteResultSetNotificationParams): void {
|
public onResultSetUpdated(resultSetInfo: azdata.QueryExecuteResultSetNotificationParams): void {
|
||||||
this._notify(resultSetInfo.ownerUri, (runner: QueryRunner) => {
|
this._notify(resultSetInfo.ownerUri, (runner: QueryRunner) => {
|
||||||
runner.handleResultSetUpdated(resultSetInfo.resultSetSummary);
|
runner.handleResultSetUpdated(resultSetInfo);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public onMessage(messagesMap: Map<string, azdata.QueryExecuteMessageParams[]>): void {
|
public onMessage(messagesMap: Map<string, azdata.QueryExecuteMessageParams[]>): void {
|
||||||
for (const [uri, messages] of messagesMap) {
|
for (const [uri, messages] of messagesMap) {
|
||||||
this._notify(uri, (runner: QueryRunner) => {
|
this._notify(uri, (runner: QueryRunner) => {
|
||||||
runner.handleMessage(messages.map(m => m.message));
|
runner.handleMessage(messages);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -321,8 +299,8 @@ export class QueryManagementService implements IQueryManagementService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public onEditSessionReady(ownerUri: string, success: boolean, message: string): void {
|
public onEditSessionReady(ownerUri: string, success: boolean, message: string): void {
|
||||||
this._notify(ownerUri, runner => {
|
this._notify(ownerUri, (runner: QueryRunner) => {
|
||||||
(runner as EditQueryRunner).handleEditSessionReady(ownerUri, success, message);
|
runner.handleEditSessionReady(ownerUri, success, message);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -374,11 +352,3 @@ export class QueryManagementService implements IQueryManagementService {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function selectionDataToRange(selection?: azdata.ISelectionData): IRange | undefined {
|
|
||||||
return isUndefined(selection) ? undefined : new Range(selection.startLine + 1, selection.startColumn + 1, selection.endLine + 1, selection.endColumn + 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
function rangeToSelectionData(range?: IRange): azdata.ISelectionData | undefined {
|
|
||||||
return isUndefined(range) ? undefined : { startLine: range.startLineNumber - 1, startColumn: range.startColumn - 1, endLine: range.endLineNumber - 1, endColumn: range.endColumn - 1 };
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -3,12 +3,13 @@
|
|||||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||||
*--------------------------------------------------------------------------------------------*/
|
*--------------------------------------------------------------------------------------------*/
|
||||||
|
|
||||||
import QueryRunner from 'sql/workbench/services/query/common/queryRunner';
|
import QueryRunner, { IQueryMessage } from 'sql/workbench/services/query/common/queryRunner';
|
||||||
import { IQueryMessage, ResultSetSubset } from 'sql/workbench/services/query/common/query';
|
|
||||||
import { DataService } from 'sql/workbench/services/query/common/dataService';
|
import { DataService } from 'sql/workbench/services/query/common/dataService';
|
||||||
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
|
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
|
||||||
import { Event } from 'vs/base/common/event';
|
import { Event } from 'vs/base/common/event';
|
||||||
import {
|
import {
|
||||||
|
ISelectionData,
|
||||||
|
ResultSetSubset,
|
||||||
EditUpdateCellResult,
|
EditUpdateCellResult,
|
||||||
EditSessionReadyParams,
|
EditSessionReadyParams,
|
||||||
EditSubsetResult,
|
EditSubsetResult,
|
||||||
@@ -18,7 +19,6 @@ import {
|
|||||||
queryeditor
|
queryeditor
|
||||||
} from 'azdata';
|
} from 'azdata';
|
||||||
import { QueryInfo } from 'sql/workbench/services/query/common/queryModelService';
|
import { QueryInfo } from 'sql/workbench/services/query/common/queryModelService';
|
||||||
import { IRange } from 'vs/editor/common/core/range';
|
|
||||||
|
|
||||||
export const SERVICE_ID = 'queryModelService';
|
export const SERVICE_ID = 'queryModelService';
|
||||||
|
|
||||||
@@ -31,7 +31,7 @@ export interface IQueryPlanInfo {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export interface IQueryInfo {
|
export interface IQueryInfo {
|
||||||
range: IRange[];
|
selection: ISelectionData[];
|
||||||
messages: IQueryMessage[];
|
messages: IQueryMessage[];
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -51,8 +51,8 @@ export interface IQueryModelService {
|
|||||||
getQueryRunner(uri: string): QueryRunner | undefined;
|
getQueryRunner(uri: string): QueryRunner | undefined;
|
||||||
|
|
||||||
getQueryRows(uri: string, rowStart: number, numberOfRows: number, batchId: number, resultId: number): Promise<ResultSetSubset | undefined>;
|
getQueryRows(uri: string, rowStart: number, numberOfRows: number, batchId: number, resultId: number): Promise<ResultSetSubset | undefined>;
|
||||||
runQuery(uri: string, range: IRange | undefined, runOptions?: ExecutionPlanOptions): void;
|
runQuery(uri: string, selection: ISelectionData | undefined, runOptions?: ExecutionPlanOptions): void;
|
||||||
runQueryStatement(uri: string, range: IRange | undefined): void;
|
runQueryStatement(uri: string, selection: ISelectionData | undefined): void;
|
||||||
runQueryString(uri: string, selection: string | undefined): void;
|
runQueryString(uri: string, selection: string | undefined): void;
|
||||||
cancelQuery(input: QueryRunner | string): void;
|
cancelQuery(input: QueryRunner | string): void;
|
||||||
disposeQuery(uri: string): void;
|
disposeQuery(uri: string): void;
|
||||||
|
|||||||
@@ -5,7 +5,6 @@
|
|||||||
|
|
||||||
import * as GridContentEvents from 'sql/workbench/services/query/common/gridContentEvents';
|
import * as GridContentEvents from 'sql/workbench/services/query/common/gridContentEvents';
|
||||||
import QueryRunner from 'sql/workbench/services/query/common/queryRunner';
|
import QueryRunner from 'sql/workbench/services/query/common/queryRunner';
|
||||||
import { ResultSetSubset } from 'sql/workbench/services/query/common/query';
|
|
||||||
import { DataService } from 'sql/workbench/services/query/common/dataService';
|
import { DataService } from 'sql/workbench/services/query/common/dataService';
|
||||||
import { IQueryModelService, IQueryEvent } from 'sql/workbench/services/query/common/queryModel';
|
import { IQueryModelService, IQueryEvent } from 'sql/workbench/services/query/common/queryModel';
|
||||||
|
|
||||||
@@ -18,8 +17,6 @@ import * as strings from 'vs/base/common/strings';
|
|||||||
import * as types from 'vs/base/common/types';
|
import * as types from 'vs/base/common/types';
|
||||||
import { INotificationService } from 'vs/platform/notification/common/notification';
|
import { INotificationService } from 'vs/platform/notification/common/notification';
|
||||||
import Severity from 'vs/base/common/severity';
|
import Severity from 'vs/base/common/severity';
|
||||||
import EditQueryRunner from 'sql/workbench/services/editData/common/editQueryRunner';
|
|
||||||
import { IRange } from 'vs/editor/common/core/range';
|
|
||||||
|
|
||||||
const selectionSnippetMaxLen = 100;
|
const selectionSnippetMaxLen = 100;
|
||||||
|
|
||||||
@@ -32,10 +29,10 @@ export interface QueryEvent {
|
|||||||
* Holds information about the state of a query runner
|
* Holds information about the state of a query runner
|
||||||
*/
|
*/
|
||||||
export class QueryInfo {
|
export class QueryInfo {
|
||||||
public queryRunner?: EditQueryRunner;
|
public queryRunner?: QueryRunner;
|
||||||
public dataService?: DataService;
|
public dataService?: DataService;
|
||||||
public queryEventQueue?: QueryEvent[];
|
public queryEventQueue?: QueryEvent[];
|
||||||
public range?: Array<IRange>;
|
public selection?: Array<azdata.ISelectionData>;
|
||||||
public selectionSnippet?: string;
|
public selectionSnippet?: string;
|
||||||
|
|
||||||
// Notes if the angular components have obtained the DataService. If not, all messages sent
|
// Notes if the angular components have obtained the DataService. If not, all messages sent
|
||||||
@@ -45,7 +42,7 @@ export class QueryInfo {
|
|||||||
constructor() {
|
constructor() {
|
||||||
this.dataServiceReady = false;
|
this.dataServiceReady = false;
|
||||||
this.queryEventQueue = [];
|
this.queryEventQueue = [];
|
||||||
this.range = [];
|
this.selection = [];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -131,10 +128,10 @@ export class QueryModelService implements IQueryModelService {
|
|||||||
/**
|
/**
|
||||||
* Get more data rows from the current resultSets from the service layer
|
* Get more data rows from the current resultSets from the service layer
|
||||||
*/
|
*/
|
||||||
public getQueryRows(uri: string, rowStart: number, numberOfRows: number, batchId: number, resultId: number): Promise<ResultSetSubset | undefined> {
|
public getQueryRows(uri: string, rowStart: number, numberOfRows: number, batchId: number, resultId: number): Promise<azdata.ResultSetSubset | undefined> {
|
||||||
if (this._queryInfoMap.has(uri)) {
|
if (this._queryInfoMap.has(uri)) {
|
||||||
return this._getQueryInfo(uri)!.queryRunner!.getQueryRows(rowStart, numberOfRows, batchId, resultId).then(results => {
|
return this._getQueryInfo(uri)!.queryRunner!.getQueryRows(rowStart, numberOfRows, batchId, resultId).then(results => {
|
||||||
return results;
|
return results.resultSubset;
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
return Promise.resolve(undefined);
|
return Promise.resolve(undefined);
|
||||||
@@ -173,15 +170,15 @@ export class QueryModelService implements IQueryModelService {
|
|||||||
/**
|
/**
|
||||||
* Run a query for the given URI with the given text selection
|
* Run a query for the given URI with the given text selection
|
||||||
*/
|
*/
|
||||||
public async runQuery(uri: string, range: IRange, runOptions?: azdata.ExecutionPlanOptions): Promise<void> {
|
public async runQuery(uri: string, selection: azdata.ISelectionData, runOptions?: azdata.ExecutionPlanOptions): Promise<void> {
|
||||||
return this.doRunQuery(uri, range, false, runOptions);
|
return this.doRunQuery(uri, selection, false, runOptions);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Run the current SQL statement for the given URI
|
* Run the current SQL statement for the given URI
|
||||||
*/
|
*/
|
||||||
public async runQueryStatement(uri: string, range: IRange): Promise<void> {
|
public async runQueryStatement(uri: string, selection: azdata.ISelectionData): Promise<void> {
|
||||||
return this.doRunQuery(uri, range, true);
|
return this.doRunQuery(uri, selection, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -194,7 +191,7 @@ export class QueryModelService implements IQueryModelService {
|
|||||||
/**
|
/**
|
||||||
* Run Query implementation
|
* Run Query implementation
|
||||||
*/
|
*/
|
||||||
private async doRunQuery(uri: string, range: IRange | string,
|
private async doRunQuery(uri: string, selection: azdata.ISelectionData | string,
|
||||||
runCurrentStatement: boolean, runOptions?: azdata.ExecutionPlanOptions): Promise<void> {
|
runCurrentStatement: boolean, runOptions?: azdata.ExecutionPlanOptions): Promise<void> {
|
||||||
// Reuse existing query runner if it exists
|
// Reuse existing query runner if it exists
|
||||||
let queryRunner: QueryRunner | undefined;
|
let queryRunner: QueryRunner | undefined;
|
||||||
@@ -211,7 +208,7 @@ export class QueryModelService implements IQueryModelService {
|
|||||||
|
|
||||||
// If the query is not in progress, we can reuse the query runner
|
// If the query is not in progress, we can reuse the query runner
|
||||||
queryRunner = existingRunner!;
|
queryRunner = existingRunner!;
|
||||||
info.range = [];
|
info.selection = [];
|
||||||
info.selectionSnippet = undefined;
|
info.selectionSnippet = undefined;
|
||||||
} else {
|
} else {
|
||||||
// We do not have a query runner for this editor, so create a new one
|
// We do not have a query runner for this editor, so create a new one
|
||||||
@@ -220,23 +217,23 @@ export class QueryModelService implements IQueryModelService {
|
|||||||
queryRunner = info.queryRunner!;
|
queryRunner = info.queryRunner!;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (types.isString(range)) {
|
if (types.isString(selection)) {
|
||||||
// Run the query string in this case
|
// Run the query string in this case
|
||||||
if (range.length < selectionSnippetMaxLen) {
|
if (selection.length < selectionSnippetMaxLen) {
|
||||||
info.selectionSnippet = range;
|
info.selectionSnippet = selection;
|
||||||
} else {
|
} else {
|
||||||
info.selectionSnippet = range.substring(0, selectionSnippetMaxLen - 3) + '...';
|
info.selectionSnippet = selection.substring(0, selectionSnippetMaxLen - 3) + '...';
|
||||||
}
|
}
|
||||||
return queryRunner.runQuery(range, runOptions);
|
return queryRunner.runQuery(selection, runOptions);
|
||||||
} else if (runCurrentStatement) {
|
} else if (runCurrentStatement) {
|
||||||
return queryRunner.runQueryStatement(range);
|
return queryRunner.runQueryStatement(selection);
|
||||||
} else {
|
} else {
|
||||||
return queryRunner.runQuery(range, runOptions);
|
return queryRunner.runQuery(selection, runOptions);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private initQueryRunner(uri: string): QueryInfo {
|
private initQueryRunner(uri: string): QueryInfo {
|
||||||
let queryRunner = this._instantiationService.createInstance(EditQueryRunner, uri);
|
let queryRunner = this._instantiationService.createInstance(QueryRunner, uri);
|
||||||
let info = new QueryInfo();
|
let info = new QueryInfo();
|
||||||
queryRunner.onResultSet(e => {
|
queryRunner.onResultSet(e => {
|
||||||
this._fireQueryEvent(uri, 'resultSet', e);
|
this._fireQueryEvent(uri, 'resultSet', e);
|
||||||
@@ -244,14 +241,14 @@ export class QueryModelService implements IQueryModelService {
|
|||||||
queryRunner.onBatchStart(b => {
|
queryRunner.onBatchStart(b => {
|
||||||
let link = undefined;
|
let link = undefined;
|
||||||
let messageText = nls.localize('runQueryBatchStartMessage', "Started executing query at ");
|
let messageText = nls.localize('runQueryBatchStartMessage', "Started executing query at ");
|
||||||
if (b.range) {
|
if (b.selection) {
|
||||||
if (info.selectionSnippet) {
|
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
|
// 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
|
// executed query text
|
||||||
messageText = nls.localize('runQueryStringBatchStartMessage', "Started executing query \"{0}\"", info.selectionSnippet);
|
messageText = nls.localize('runQueryStringBatchStartMessage', "Started executing query \"{0}\"", info.selectionSnippet);
|
||||||
} else {
|
} else {
|
||||||
link = {
|
link = {
|
||||||
text: strings.format(nls.localize('runQueryBatchStartLine', "Line {0}"), b.range.startLineNumber)
|
text: strings.format(nls.localize('runQueryBatchStartLine', "Line {0}"), b.selection.startLine + 1)
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -263,7 +260,7 @@ export class QueryModelService implements IQueryModelService {
|
|||||||
link: link
|
link: link
|
||||||
};
|
};
|
||||||
this._fireQueryEvent(uri, 'message', message);
|
this._fireQueryEvent(uri, 'message', message);
|
||||||
info.range!.push(b.range);
|
info.selection!.push(this._validateSelection(b.selection));
|
||||||
});
|
});
|
||||||
queryRunner.onMessage(m => {
|
queryRunner.onMessage(m => {
|
||||||
this._fireQueryEvent(uri, 'message', m);
|
this._fireQueryEvent(uri, 'message', m);
|
||||||
@@ -277,7 +274,7 @@ export class QueryModelService implements IQueryModelService {
|
|||||||
uri: uri,
|
uri: uri,
|
||||||
queryInfo:
|
queryInfo:
|
||||||
{
|
{
|
||||||
range: info.range!,
|
selection: info.selection!,
|
||||||
messages: info.queryRunner!.messages
|
messages: info.queryRunner!.messages
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -295,7 +292,7 @@ export class QueryModelService implements IQueryModelService {
|
|||||||
uri: uri,
|
uri: uri,
|
||||||
queryInfo:
|
queryInfo:
|
||||||
{
|
{
|
||||||
range: info.range!,
|
selection: info.selection!,
|
||||||
messages: info.queryRunner!.messages
|
messages: info.queryRunner!.messages
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -311,7 +308,7 @@ export class QueryModelService implements IQueryModelService {
|
|||||||
uri: uri,
|
uri: uri,
|
||||||
queryInfo:
|
queryInfo:
|
||||||
{
|
{
|
||||||
range: info.range!,
|
selection: info.selection!,
|
||||||
messages: info.queryRunner!.messages
|
messages: info.queryRunner!.messages
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -327,7 +324,7 @@ export class QueryModelService implements IQueryModelService {
|
|||||||
uri: planInfo.fileUri,
|
uri: planInfo.fileUri,
|
||||||
queryInfo:
|
queryInfo:
|
||||||
{
|
{
|
||||||
range: info.range!,
|
selection: info.selection!,
|
||||||
messages: info.queryRunner!.messages
|
messages: info.queryRunner!.messages
|
||||||
},
|
},
|
||||||
params: planInfo
|
params: planInfo
|
||||||
@@ -341,7 +338,7 @@ export class QueryModelService implements IQueryModelService {
|
|||||||
uri: uri,
|
uri: uri,
|
||||||
queryInfo:
|
queryInfo:
|
||||||
{
|
{
|
||||||
range: info.range!,
|
selection: info.selection!,
|
||||||
messages: info.queryRunner!.messages
|
messages: info.queryRunner!.messages
|
||||||
},
|
},
|
||||||
params: resultSetInfo
|
params: resultSetInfo
|
||||||
@@ -402,12 +399,12 @@ export class QueryModelService implements IQueryModelService {
|
|||||||
// EDIT DATA METHODS /////////////////////////////////////////////////////
|
// EDIT DATA METHODS /////////////////////////////////////////////////////
|
||||||
async initializeEdit(ownerUri: string, schemaName: string, objectName: string, objectType: string, rowLimit: number, queryString: string): Promise<void> {
|
async initializeEdit(ownerUri: string, schemaName: string, objectName: string, objectType: string, rowLimit: number, queryString: string): Promise<void> {
|
||||||
// Reuse existing query runner if it exists
|
// Reuse existing query runner if it exists
|
||||||
let queryRunner: EditQueryRunner;
|
let queryRunner: QueryRunner;
|
||||||
let info: QueryInfo;
|
let info: QueryInfo;
|
||||||
|
|
||||||
if (this._queryInfoMap.has(ownerUri)) {
|
if (this._queryInfoMap.has(ownerUri)) {
|
||||||
info = this._getQueryInfo(ownerUri)!;
|
info = this._getQueryInfo(ownerUri)!;
|
||||||
let existingRunner = info.queryRunner!;
|
let existingRunner: QueryRunner = info.queryRunner!;
|
||||||
|
|
||||||
// If the initialization is already in progress
|
// If the initialization is already in progress
|
||||||
if (existingRunner.isExecuting) {
|
if (existingRunner.isExecuting) {
|
||||||
@@ -420,7 +417,7 @@ export class QueryModelService implements IQueryModelService {
|
|||||||
|
|
||||||
// We do not have a query runner for this editor, so create a new one
|
// We do not have a query runner for this editor, so create a new one
|
||||||
// and map it to the results uri
|
// and map it to the results uri
|
||||||
queryRunner = this._instantiationService.createInstance(EditQueryRunner, ownerUri);
|
queryRunner = this._instantiationService.createInstance(QueryRunner, ownerUri);
|
||||||
const resultSetEventType = 'resultSet';
|
const resultSetEventType = 'resultSet';
|
||||||
queryRunner.onResultSet(resultSet => {
|
queryRunner.onResultSet(resultSet => {
|
||||||
this._fireQueryEvent(ownerUri, resultSetEventType, resultSet);
|
this._fireQueryEvent(ownerUri, resultSetEventType, resultSet);
|
||||||
@@ -431,14 +428,14 @@ export class QueryModelService implements IQueryModelService {
|
|||||||
queryRunner.onBatchStart(batch => {
|
queryRunner.onBatchStart(batch => {
|
||||||
let link = undefined;
|
let link = undefined;
|
||||||
let messageText = nls.localize('runQueryBatchStartMessage', "Started executing query at ");
|
let messageText = nls.localize('runQueryBatchStartMessage', "Started executing query at ");
|
||||||
if (batch.range) {
|
if (batch.selection) {
|
||||||
if (info.selectionSnippet) {
|
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
|
// 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
|
// executed query text
|
||||||
messageText = nls.localize('runQueryStringBatchStartMessage', "Started executing query \"{0}\"", info.selectionSnippet);
|
messageText = nls.localize('runQueryStringBatchStartMessage', "Started executing query \"{0}\"", info.selectionSnippet);
|
||||||
} else {
|
} else {
|
||||||
link = {
|
link = {
|
||||||
text: strings.format(nls.localize('runQueryBatchStartLine', "Line {0}"), batch.range.startLineNumber)
|
text: strings.format(nls.localize('runQueryBatchStartLine', "Line {0}"), batch.selection.startLine + 1)
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -462,7 +459,7 @@ export class QueryModelService implements IQueryModelService {
|
|||||||
uri: ownerUri,
|
uri: ownerUri,
|
||||||
queryInfo:
|
queryInfo:
|
||||||
{
|
{
|
||||||
range: info.range!,
|
selection: info.selection!,
|
||||||
messages: info.queryRunner!.messages
|
messages: info.queryRunner!.messages
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
@@ -479,7 +476,7 @@ export class QueryModelService implements IQueryModelService {
|
|||||||
uri: ownerUri,
|
uri: ownerUri,
|
||||||
queryInfo:
|
queryInfo:
|
||||||
{
|
{
|
||||||
range: info.range!,
|
selection: info.selection!,
|
||||||
messages: info.queryRunner!.messages
|
messages: info.queryRunner!.messages
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
@@ -599,8 +596,8 @@ export class QueryModelService implements IQueryModelService {
|
|||||||
|
|
||||||
// PRIVATE METHODS //////////////////////////////////////////////////////
|
// PRIVATE METHODS //////////////////////////////////////////////////////
|
||||||
|
|
||||||
private internalGetQueryRunner(ownerUri: string): EditQueryRunner | undefined {
|
private internalGetQueryRunner(ownerUri: string): QueryRunner | undefined {
|
||||||
let queryRunner: EditQueryRunner | undefined;
|
let queryRunner: QueryRunner | undefined;
|
||||||
if (this._queryInfoMap.has(ownerUri)) {
|
if (this._queryInfoMap.has(ownerUri)) {
|
||||||
let existingRunner = this._getQueryInfo(ownerUri)!.queryRunner!;
|
let existingRunner = this._getQueryInfo(ownerUri)!.queryRunner!;
|
||||||
// If the query is not already executing then set it up
|
// If the query is not already executing then set it up
|
||||||
@@ -651,4 +648,17 @@ export class QueryModelService implements IQueryModelService {
|
|||||||
public _getQueryInfo(uri: string): QueryInfo | undefined {
|
public _getQueryInfo(uri: string): QueryInfo | undefined {
|
||||||
return this._queryInfoMap.get(uri);
|
return this._queryInfoMap.get(uri);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO remove this funciton and its usages when #821 in vscode-mssql is fixed and
|
||||||
|
// the SqlToolsService version is updated in this repo - coquagli 4/19/2017
|
||||||
|
private _validateSelection(selection: azdata.ISelectionData): azdata.ISelectionData {
|
||||||
|
if (!selection) {
|
||||||
|
selection = <azdata.ISelectionData>{};
|
||||||
|
}
|
||||||
|
selection.endColumn = selection ? Math.max(0, selection.endColumn) : 0;
|
||||||
|
selection.endLine = selection ? Math.max(0, selection.endLine) : 0;
|
||||||
|
selection.startColumn = selection ? Math.max(0, selection.startColumn) : 0;
|
||||||
|
selection.startLine = selection ? Math.max(0, selection.startLine) : 0;
|
||||||
|
return selection;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,12 +3,15 @@
|
|||||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||||
*--------------------------------------------------------------------------------------------*/
|
*--------------------------------------------------------------------------------------------*/
|
||||||
|
|
||||||
import { IQueryManagementService, QueryCancelResult, ExecutionPlanOptions } from 'sql/workbench/services/query/common/queryManagement';
|
import * as azdata from 'azdata';
|
||||||
|
|
||||||
|
import { IQueryManagementService } from 'sql/workbench/services/query/common/queryManagement';
|
||||||
import * as Utils from 'sql/platform/connection/common/utils';
|
import * as Utils from 'sql/platform/connection/common/utils';
|
||||||
import { Deferred } from 'sql/base/common/promise';
|
import { Deferred } from 'sql/base/common/promise';
|
||||||
import { IQueryPlanInfo } from 'sql/workbench/services/query/common/queryModel';
|
import { IQueryPlanInfo } from 'sql/workbench/services/query/common/queryModel';
|
||||||
import { ResultSerializer, SaveFormat } from 'sql/workbench/services/query/common/resultSerializer';
|
import { ResultSerializer, SaveFormat } from 'sql/workbench/services/query/common/resultSerializer';
|
||||||
|
|
||||||
|
import Severity from 'vs/base/common/severity';
|
||||||
import * as nls from 'vs/nls';
|
import * as nls from 'vs/nls';
|
||||||
import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService';
|
import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService';
|
||||||
import * as types from 'vs/base/common/types';
|
import * as types from 'vs/base/common/types';
|
||||||
@@ -24,8 +27,20 @@ import { IGridDataProvider, getResultsString } from 'sql/workbench/services/quer
|
|||||||
import { getErrorMessage } from 'vs/base/common/errors';
|
import { getErrorMessage } from 'vs/base/common/errors';
|
||||||
import { ILogService } from 'vs/platform/log/common/log';
|
import { ILogService } from 'vs/platform/log/common/log';
|
||||||
import { find } from 'vs/base/common/arrays';
|
import { find } from 'vs/base/common/arrays';
|
||||||
import { IRange, Range } from 'vs/editor/common/core/range';
|
|
||||||
import { BatchSummary, IQueryMessage, ResultSetSummary, QueryExecuteSubsetParams, CompleteBatchSummary, IResultMessage, ResultSetSubset, BatchStartSummary } from './query';
|
export interface IEditSessionReadyEvent {
|
||||||
|
ownerUri: string;
|
||||||
|
success: boolean;
|
||||||
|
message: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface IQueryMessage {
|
||||||
|
batchId?: number;
|
||||||
|
isError: boolean;
|
||||||
|
time?: string;
|
||||||
|
message: string;
|
||||||
|
selection?: azdata.ISelectionData;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Query Runner class which handles running a query, reports the results to the content manager,
|
* Query Runner class which handles running a query, reports the results to the content manager,
|
||||||
@@ -35,10 +50,10 @@ export default class QueryRunner extends Disposable {
|
|||||||
// MEMBER VARIABLES ////////////////////////////////////////////////////
|
// MEMBER VARIABLES ////////////////////////////////////////////////////
|
||||||
private _resultLineOffset?: number;
|
private _resultLineOffset?: number;
|
||||||
private _resultColumnOffset?: number;
|
private _resultColumnOffset?: number;
|
||||||
protected _totalElapsedMilliseconds: number = 0;
|
private _totalElapsedMilliseconds: number = 0;
|
||||||
protected _isExecuting: boolean = false;
|
private _isExecuting: boolean = false;
|
||||||
private _hasCompleted: boolean = false;
|
private _hasCompleted: boolean = false;
|
||||||
private _batchSets: BatchSummary[] = [];
|
private _batchSets: azdata.BatchSummary[] = [];
|
||||||
private _messages: IQueryMessage[] = [];
|
private _messages: IQueryMessage[] = [];
|
||||||
private registered = false;
|
private registered = false;
|
||||||
|
|
||||||
@@ -50,28 +65,31 @@ export default class QueryRunner extends Disposable {
|
|||||||
private _onMessage = this._register(new Emitter<IQueryMessage[]>());
|
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
|
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 readonly _onResultSet = this._register(new Emitter<ResultSetSummary>());
|
private _onResultSet = this._register(new Emitter<azdata.ResultSetSummary>());
|
||||||
public readonly onResultSet = this._onResultSet.event;
|
public readonly onResultSet = this._onResultSet.event;
|
||||||
|
|
||||||
private readonly _onResultSetUpdate = this._register(new Emitter<ResultSetSummary>());
|
private _onResultSetUpdate = this._register(new Emitter<azdata.ResultSetSummary>());
|
||||||
public readonly onResultSetUpdate = this._onResultSetUpdate.event;
|
public readonly onResultSetUpdate = this._onResultSetUpdate.event;
|
||||||
|
|
||||||
protected readonly _onQueryStart = this._register(new Emitter<void>());
|
private _onQueryStart = this._register(new Emitter<void>());
|
||||||
public readonly onQueryStart: Event<void> = this._onQueryStart.event;
|
public readonly onQueryStart: Event<void> = this._onQueryStart.event;
|
||||||
|
|
||||||
private readonly _onQueryEnd = this._register(new Emitter<string>());
|
private _onQueryEnd = this._register(new Emitter<string>());
|
||||||
public get onQueryEnd(): Event<string> { return this._onQueryEnd.event; }
|
public get onQueryEnd(): Event<string> { return this._onQueryEnd.event; }
|
||||||
|
|
||||||
private readonly _onBatchStart = this._register(new Emitter<BatchStartSummary>());
|
private _onBatchStart = this._register(new Emitter<azdata.BatchSummary>());
|
||||||
public readonly onBatchStart: Event<BatchStartSummary> = this._onBatchStart.event;
|
public readonly onBatchStart: Event<azdata.BatchSummary> = this._onBatchStart.event;
|
||||||
|
|
||||||
private readonly _onBatchEnd = this._register(new Emitter<CompleteBatchSummary>());
|
private _onBatchEnd = this._register(new Emitter<azdata.BatchSummary>());
|
||||||
public readonly onBatchEnd: Event<CompleteBatchSummary> = this._onBatchEnd.event;
|
public readonly onBatchEnd: Event<azdata.BatchSummary> = this._onBatchEnd.event;
|
||||||
|
|
||||||
private readonly _onQueryPlanAvailable = this._register(new Emitter<IQueryPlanInfo>());
|
private _onEditSessionReady = this._register(new Emitter<IEditSessionReadyEvent>());
|
||||||
|
public readonly onEditSessionReady = this._onEditSessionReady.event;
|
||||||
|
|
||||||
|
private _onQueryPlanAvailable = this._register(new Emitter<IQueryPlanInfo>());
|
||||||
public readonly onQueryPlanAvailable = this._onQueryPlanAvailable.event;
|
public readonly onQueryPlanAvailable = this._onQueryPlanAvailable.event;
|
||||||
|
|
||||||
private readonly _onVisualize = this._register(new Emitter<ResultSetSummary>());
|
private _onVisualize = this._register(new Emitter<azdata.ResultSetSummary>());
|
||||||
public readonly onVisualize = this._onVisualize.event;
|
public readonly onVisualize = this._onVisualize.event;
|
||||||
|
|
||||||
private _queryStartTime?: Date;
|
private _queryStartTime?: Date;
|
||||||
@@ -86,11 +104,12 @@ export default class QueryRunner extends Disposable {
|
|||||||
// CONSTRUCTOR /////////////////////////////////////////////////////////
|
// CONSTRUCTOR /////////////////////////////////////////////////////////
|
||||||
constructor(
|
constructor(
|
||||||
public uri: string,
|
public uri: string,
|
||||||
@IQueryManagementService protected readonly queryManagementService: IQueryManagementService,
|
@IQueryManagementService private _queryManagementService: IQueryManagementService,
|
||||||
@IConfigurationService private readonly configurationService: IConfigurationService,
|
@INotificationService private _notificationService: INotificationService,
|
||||||
@IInstantiationService private readonly instantiationService: IInstantiationService,
|
@IConfigurationService private _configurationService: IConfigurationService,
|
||||||
@ITextResourcePropertiesService private readonly textResourcePropertiesService: ITextResourcePropertiesService,
|
@IInstantiationService private instantiationService: IInstantiationService,
|
||||||
@ILogService private readonly logService: ILogService
|
@ITextResourcePropertiesService private _textResourcePropertiesService: ITextResourcePropertiesService,
|
||||||
|
@ILogService private _logService: ILogService
|
||||||
) {
|
) {
|
||||||
super();
|
super();
|
||||||
}
|
}
|
||||||
@@ -106,7 +125,7 @@ export default class QueryRunner extends Disposable {
|
|||||||
/**
|
/**
|
||||||
* For public use only, for private use, directly access the member
|
* For public use only, for private use, directly access the member
|
||||||
*/
|
*/
|
||||||
public get batchSets(): BatchSummary[] {
|
public get batchSets(): azdata.BatchSummary[] {
|
||||||
return this._batchSets.slice(0);
|
return this._batchSets.slice(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -122,22 +141,22 @@ export default class QueryRunner extends Disposable {
|
|||||||
/**
|
/**
|
||||||
* Cancels the running query, if there is one
|
* Cancels the running query, if there is one
|
||||||
*/
|
*/
|
||||||
public cancelQuery(): Promise<QueryCancelResult> {
|
public cancelQuery(): Promise<azdata.QueryCancelResult> {
|
||||||
return this.queryManagementService.cancelQuery(this.uri);
|
return this._queryManagementService.cancelQuery(this.uri);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Runs the query with the provided query
|
* Runs the query with the provided query
|
||||||
* @param input Query string to execute
|
* @param input Query string to execute
|
||||||
*/
|
*/
|
||||||
public runQuery(input: string, runOptions?: ExecutionPlanOptions): Promise<void>;
|
public runQuery(input: string, runOptions?: azdata.ExecutionPlanOptions): Promise<void>;
|
||||||
/**
|
/**
|
||||||
* Runs the query by pulling the query from the document using the provided selection data
|
* Runs the query by pulling the query from the document using the provided selection data
|
||||||
* @param input selection data
|
* @param input selection data
|
||||||
*/
|
*/
|
||||||
public runQuery(input: IRange | undefined, runOptions?: ExecutionPlanOptions): Promise<void>;
|
public runQuery(input: azdata.ISelectionData, runOptions?: azdata.ExecutionPlanOptions): Promise<void>;
|
||||||
public runQuery(input: string | IRange | undefined, runOptions?: ExecutionPlanOptions): Promise<void> {
|
public runQuery(input: string | azdata.ISelectionData, runOptions?: azdata.ExecutionPlanOptions): Promise<void> {
|
||||||
if (types.isString(input) || types.isUndefined(input)) {
|
if (types.isString(input)) {
|
||||||
return this.doRunQuery(input, false, runOptions);
|
return this.doRunQuery(input, false, runOptions);
|
||||||
} else {
|
} else {
|
||||||
return this.doRunQuery(input, false, runOptions);
|
return this.doRunQuery(input, false, runOptions);
|
||||||
@@ -148,7 +167,7 @@ export default class QueryRunner extends Disposable {
|
|||||||
* Runs the current SQL statement by pulling the query from the document using the provided selection data
|
* Runs the current SQL statement by pulling the query from the document using the provided selection data
|
||||||
* @param input selection data
|
* @param input selection data
|
||||||
*/
|
*/
|
||||||
public runQueryStatement(input: IRange): Promise<void> {
|
public runQueryStatement(input: azdata.ISelectionData): Promise<void> {
|
||||||
return this.doRunQuery(input, true);
|
return this.doRunQuery(input, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -156,9 +175,9 @@ export default class QueryRunner extends Disposable {
|
|||||||
* Implementation that runs the query with the provided query
|
* Implementation that runs the query with the provided query
|
||||||
* @param input Query string to execute
|
* @param input Query string to execute
|
||||||
*/
|
*/
|
||||||
private doRunQuery(input: string, runCurrentStatement: boolean, runOptions?: ExecutionPlanOptions): Promise<void>;
|
private doRunQuery(input: string, runCurrentStatement: boolean, runOptions?: azdata.ExecutionPlanOptions): Promise<void>;
|
||||||
private doRunQuery(input: IRange | undefined, runCurrentStatement: boolean, runOptions?: ExecutionPlanOptions): Promise<void>;
|
private doRunQuery(input: azdata.ISelectionData, runCurrentStatement: boolean, runOptions?: azdata.ExecutionPlanOptions): Promise<void>;
|
||||||
private doRunQuery(input: string | IRange | undefined, runCurrentStatement: boolean, runOptions?: ExecutionPlanOptions): Promise<void> {
|
private doRunQuery(input: string | azdata.ISelectionData, runCurrentStatement: boolean, runOptions?: azdata.ExecutionPlanOptions): Promise<void> {
|
||||||
if (this.isExecuting) {
|
if (this.isExecuting) {
|
||||||
return Promise.resolve();
|
return Promise.resolve();
|
||||||
}
|
}
|
||||||
@@ -168,9 +187,9 @@ export default class QueryRunner extends Disposable {
|
|||||||
this._queryStartTime = undefined;
|
this._queryStartTime = undefined;
|
||||||
this._queryEndTime = undefined;
|
this._queryEndTime = undefined;
|
||||||
this._messages = [];
|
this._messages = [];
|
||||||
if (isRangeOrUndefined(input)) {
|
if (isSelectionOrUndefined(input)) {
|
||||||
// Update internal state to show that we're executing the query
|
// Update internal state to show that we're executing the query
|
||||||
this._resultLineOffset = input ? input.startLineNumber : 0;
|
this._resultLineOffset = input ? input.startLine : 0;
|
||||||
this._resultColumnOffset = input ? input.startColumn : 0;
|
this._resultColumnOffset = input ? input.startColumn : 0;
|
||||||
this._isExecuting = true;
|
this._isExecuting = true;
|
||||||
this._totalElapsedMilliseconds = 0;
|
this._totalElapsedMilliseconds = 0;
|
||||||
@@ -180,8 +199,8 @@ export default class QueryRunner extends Disposable {
|
|||||||
|
|
||||||
// Send the request to execute the query
|
// Send the request to execute the query
|
||||||
return runCurrentStatement
|
return runCurrentStatement
|
||||||
? this.queryManagementService.runQueryStatement(this.uri, input.startLineNumber, input.startColumn).then(() => this.handleSuccessRunQueryResult(), e => this.handleFailureRunQueryResult(e))
|
? 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.runQuery(this.uri, input, runOptions).then(() => this.handleSuccessRunQueryResult(), e => this.handleFailureRunQueryResult(e));
|
||||||
} else {
|
} else {
|
||||||
// Update internal state to show that we're executing the query
|
// Update internal state to show that we're executing the query
|
||||||
this._isExecuting = true;
|
this._isExecuting = true;
|
||||||
@@ -189,7 +208,7 @@ export default class QueryRunner extends Disposable {
|
|||||||
|
|
||||||
this._onQueryStart.fire();
|
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));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -199,39 +218,45 @@ export default class QueryRunner extends Disposable {
|
|||||||
// The query has started, so lets fire up the result pane
|
// The query has started, so lets fire up the result pane
|
||||||
if (!this.registered) {
|
if (!this.registered) {
|
||||||
this.registered = true;
|
this.registered = true;
|
||||||
this.queryManagementService.registerRunner(this, this.uri);
|
this._queryManagementService.registerRunner(this, this.uri);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private handleFailureRunQueryResult(error: any) {
|
private handleFailureRunQueryResult(error: any) {
|
||||||
// Attempting to launch the query failed, show the error message
|
// 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) {
|
if (error instanceof Error) {
|
||||||
error = error.message;
|
error = error.message;
|
||||||
}
|
}
|
||||||
let message = nls.localize('query.ExecutionFailedError', "Execution failed due to an unexpected error: {0}\t{1}", eol, error);
|
let message = nls.localize('query.ExecutionFailedError', "Execution failed due to an unexpected error: {0}\t{1}", eol, error);
|
||||||
this.handleMessage([{
|
this.handleMessage([<azdata.QueryExecuteMessageParams>{
|
||||||
isError: true,
|
ownerUri: this.uri,
|
||||||
message: message
|
message: {
|
||||||
|
isError: true,
|
||||||
|
message: message
|
||||||
|
}
|
||||||
}]);
|
}]);
|
||||||
this.handleQueryComplete();
|
this.handleQueryComplete(<azdata.QueryExecuteCompleteNotificationResult>{ ownerUri: this.uri });
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handle a QueryComplete from the service layer
|
* Handle a QueryComplete from the service layer
|
||||||
*/
|
*/
|
||||||
public handleQueryComplete(batchSummaries?: CompleteBatchSummary[]): void {
|
public handleQueryComplete(result: azdata.QueryExecuteCompleteNotificationResult): void {
|
||||||
// this also isn't exact but its the best we can do
|
// this also isn't exact but its the best we can do
|
||||||
this._queryEndTime = new Date();
|
this._queryEndTime = new Date();
|
||||||
|
|
||||||
// Store the batch sets we got back as a source of "truth"
|
// Store the batch sets we got back as a source of "truth"
|
||||||
this._isExecuting = false;
|
this._isExecuting = false;
|
||||||
this._hasCompleted = true;
|
this._hasCompleted = true;
|
||||||
this._batchSets = batchSummaries ? batchSummaries : [];
|
this._batchSets = result.batchSummaries ? result.batchSummaries : [];
|
||||||
|
|
||||||
this._batchSets.map(batch => {
|
this._batchSets.map(batch => {
|
||||||
if (batch.range) {
|
if (batch.selection) {
|
||||||
batch.range = new Range(batch.range.startLineNumber + this._resultLineOffset, batch.range.startColumn + this._resultColumnOffset, batch.range.endLineNumber + this._resultLineOffset, batch.range.endColumn + this._resultColumnOffset);
|
batch.selection.startLine += this._resultLineOffset!;
|
||||||
|
batch.selection.startColumn += this._resultColumnOffset!;
|
||||||
|
batch.selection.endLine += this._resultLineOffset!;
|
||||||
|
batch.selection.endColumn += this._resultColumnOffset!;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -252,20 +277,28 @@ export default class QueryRunner extends Disposable {
|
|||||||
/**
|
/**
|
||||||
* Handle a BatchStart from the service layer
|
* Handle a BatchStart from the service layer
|
||||||
*/
|
*/
|
||||||
public handleBatchStart(batch: BatchStartSummary): void {
|
public handleBatchStart(result: azdata.QueryExecuteBatchNotificationParams): void {
|
||||||
|
let batch = result.batchSummary;
|
||||||
|
|
||||||
// Recalculate the start and end lines, relative to the result line offset
|
// Recalculate the start and end lines, relative to the result line offset
|
||||||
if (batch.range) {
|
if (batch.selection) {
|
||||||
batch.range = new Range(batch.range.startLineNumber + this._resultLineOffset, batch.range.startColumn + this._resultColumnOffset, batch.range.endLineNumber + this._resultLineOffset, batch.range.endColumn + this._resultColumnOffset);
|
batch.selection.startLine += this._resultLineOffset!;
|
||||||
|
batch.selection.startColumn += this._resultColumnOffset!;
|
||||||
|
batch.selection.endLine += this._resultLineOffset!;
|
||||||
|
batch.selection.endColumn += this._resultColumnOffset!;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Store the batch
|
// Set the result sets as an empty array so that as result sets complete we can add to the list
|
||||||
this._batchSets[batch.id] = { ...batch, resultSetSummaries: [], hasError: false };
|
batch.resultSetSummaries = [];
|
||||||
|
|
||||||
let message: IQueryMessage = {
|
// Store the batch
|
||||||
|
this._batchSets[batch.id] = batch;
|
||||||
|
|
||||||
|
let message = {
|
||||||
// account for index by 1
|
// account for index by 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),
|
message: nls.localize('query.message.startQuery', "Started executing query at Line {0}", batch.selection.startLine + 1),
|
||||||
time: batch.executionStart,
|
time: batch.executionStart,
|
||||||
range: batch.range,
|
selection: batch.selection,
|
||||||
isError: false
|
isError: false
|
||||||
};
|
};
|
||||||
this._messages.push(message);
|
this._messages.push(message);
|
||||||
@@ -276,7 +309,9 @@ export default class QueryRunner extends Disposable {
|
|||||||
/**
|
/**
|
||||||
* Handle a BatchComplete from the service layer
|
* Handle a BatchComplete from the service layer
|
||||||
*/
|
*/
|
||||||
public handleBatchComplete(batch: CompleteBatchSummary): void {
|
public handleBatchComplete(result: azdata.QueryExecuteBatchNotificationParams): void {
|
||||||
|
let batch: azdata.BatchSummary = result.batchSummary;
|
||||||
|
|
||||||
// Store the batch again to get the rest of the data
|
// Store the batch again to get the rest of the data
|
||||||
this._batchSets[batch.id] = batch;
|
this._batchSets[batch.id] = batch;
|
||||||
let executionTime = <number>(Utils.parseTimeString(batch.executionElapsed) || 0);
|
let executionTime = <number>(Utils.parseTimeString(batch.executionElapsed) || 0);
|
||||||
@@ -292,18 +327,19 @@ export default class QueryRunner extends Disposable {
|
|||||||
/**
|
/**
|
||||||
* Handle a ResultSetComplete from the service layer
|
* Handle a ResultSetComplete from the service layer
|
||||||
*/
|
*/
|
||||||
public handleResultSetAvailable(resultSet?: ResultSetSummary): void {
|
public handleResultSetAvailable(result: azdata.QueryExecuteResultSetNotificationParams): void {
|
||||||
if (resultSet) {
|
if (result && result.resultSetSummary) {
|
||||||
let batchSet: BatchSummary;
|
let resultSet = result.resultSetSummary;
|
||||||
|
let batchSet: azdata.BatchSummary;
|
||||||
if (!resultSet.batchId) {
|
if (!resultSet.batchId) {
|
||||||
// Missing the batchId or processing batchId==0. In this case, default to always using the first batch in the list
|
// 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
|
// or create one in the case the DMP extension didn't obey the contract perfectly
|
||||||
if (this._batchSets.length > 0) {
|
if (this._batchSets.length > 0) {
|
||||||
batchSet = this._batchSets[0];
|
batchSet = this._batchSets[0];
|
||||||
} else {
|
} else {
|
||||||
batchSet = <BatchSummary>{
|
batchSet = <azdata.BatchSummary><unknown>{
|
||||||
id: 0,
|
id: 0,
|
||||||
range: undefined,
|
selection: undefined,
|
||||||
hasError: false,
|
hasError: false,
|
||||||
resultSetSummaries: []
|
resultSetSummaries: []
|
||||||
};
|
};
|
||||||
@@ -314,15 +350,15 @@ export default class QueryRunner extends Disposable {
|
|||||||
}
|
}
|
||||||
// handle getting queryPlanxml if we need too
|
// 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
|
// check if this result has show plan, this needs work, it won't work for any other provider
|
||||||
let hasShowPlan = !!find(resultSet.columnInfo, e => e.columnName === 'Microsoft SQL Server 2005 XML Showplan');
|
let hasShowPlan = !!find(result.resultSetSummary.columnInfo, e => e.columnName === 'Microsoft SQL Server 2005 XML Showplan');
|
||||||
if (hasShowPlan && resultSet.rowCount > 0) {
|
if (hasShowPlan) {
|
||||||
this._isQueryPlan = true;
|
this._isQueryPlan = true;
|
||||||
|
|
||||||
this.getQueryRows(0, 1, resultSet.batchId, resultSet.id).then(e => {
|
this.getQueryRows(0, 1, result.resultSetSummary.batchId, result.resultSetSummary.id).then(e => {
|
||||||
if (e.rows) {
|
if (e.resultSubset.rows) {
|
||||||
this._planXml.resolve(e.rows[0][0].displayValue);
|
this._planXml.resolve(e.resultSubset.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
|
// we will just ignore the set if we already have it
|
||||||
// ideally this should never happen
|
// ideally this should never happen
|
||||||
@@ -334,30 +370,31 @@ export default class QueryRunner extends Disposable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public handleResultSetUpdated(resultSet?: ResultSetSummary): void {
|
public handleResultSetUpdated(result: azdata.QueryExecuteResultSetNotificationParams): void {
|
||||||
if (resultSet) {
|
if (result && result.resultSetSummary) {
|
||||||
let batchSet: BatchSummary;
|
let resultSet = result.resultSetSummary;
|
||||||
|
let batchSet: azdata.BatchSummary;
|
||||||
batchSet = this._batchSets[resultSet.batchId];
|
batchSet = this._batchSets[resultSet.batchId];
|
||||||
// handle getting queryPlanxml if we need too
|
// 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
|
// check if this result has show plan, this needs work, it won't work for any other provider
|
||||||
let hasShowPlan = !!resultSet.columnInfo.find(e => e.columnName === 'Microsoft SQL Server 2005 XML Showplan');
|
let hasShowPlan = !!find(result.resultSetSummary.columnInfo, e => e.columnName === 'Microsoft SQL Server 2005 XML Showplan');
|
||||||
if (hasShowPlan) {
|
if (hasShowPlan) {
|
||||||
this._isQueryPlan = true;
|
this._isQueryPlan = true;
|
||||||
this.getQueryRows(0, 1, resultSet.batchId, resultSet.id).then(e => {
|
this.getQueryRows(0, 1, result.resultSetSummary.batchId, result.resultSetSummary.id).then(e => {
|
||||||
|
|
||||||
if (e.rows) {
|
if (e.resultSubset.rows) {
|
||||||
let planXmlString = e.rows[0][0].displayValue;
|
let planXmlString = e.resultSubset.rows[0][0].displayValue;
|
||||||
this._planXml.resolve(e.rows[0][0].displayValue);
|
this._planXml.resolve(e.resultSubset.rows[0][0].displayValue);
|
||||||
// fire query plan available event if execution is completed
|
// fire query plan available event if execution is completed
|
||||||
if (resultSet.complete) {
|
if (result.resultSetSummary.complete) {
|
||||||
this._onQueryPlanAvailable.fire({
|
this._onQueryPlanAvailable.fire({
|
||||||
providerId: mssqlProviderName,
|
providerId: mssqlProviderName,
|
||||||
fileUri: this.uri,
|
fileUri: result.ownerUri,
|
||||||
planXml: planXmlString
|
planXml: planXmlString
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}).catch((e) => this.logService.error(e));
|
}).catch((e) => this._logService.error(e));
|
||||||
}
|
}
|
||||||
if (batchSet) {
|
if (batchSet) {
|
||||||
// Store the result set in the batch and emit that a result set has completed
|
// Store the result set in the batch and emit that a result set has completed
|
||||||
@@ -370,7 +407,8 @@ export default class QueryRunner extends Disposable {
|
|||||||
/**
|
/**
|
||||||
* Handle a Mssage from the service layer
|
* Handle a Mssage from the service layer
|
||||||
*/
|
*/
|
||||||
public handleMessage(messages: IResultMessage[]): void {
|
public handleMessage(messagesObj: azdata.QueryExecuteMessageParams[]): void {
|
||||||
|
const messages = messagesObj.map(m => m.message);
|
||||||
this._messages.push(...messages);
|
this._messages.push(...messages);
|
||||||
|
|
||||||
// Send the message to the results pane
|
// Send the message to the results pane
|
||||||
@@ -380,8 +418,8 @@ export default class QueryRunner extends Disposable {
|
|||||||
/**
|
/**
|
||||||
* Get more data rows from the current resultSets from the service layer
|
* Get more data rows from the current resultSets from the service layer
|
||||||
*/
|
*/
|
||||||
public getQueryRows(rowStart: number, numberOfRows: number, batchIndex: number, resultSetIndex: number): Promise<ResultSetSubset> {
|
public getQueryRows(rowStart: number, numberOfRows: number, batchIndex: number, resultSetIndex: number): Promise<azdata.QueryExecuteSubsetResult> {
|
||||||
let rowData: QueryExecuteSubsetParams = <QueryExecuteSubsetParams>{
|
let rowData: azdata.QueryExecuteSubsetParams = <azdata.QueryExecuteSubsetParams>{
|
||||||
ownerUri: this.uri,
|
ownerUri: this.uri,
|
||||||
resultSetIndex: resultSetIndex,
|
resultSetIndex: resultSetIndex,
|
||||||
rowsCount: numberOfRows,
|
rowsCount: numberOfRows,
|
||||||
@@ -389,7 +427,7 @@ export default class QueryRunner extends Disposable {
|
|||||||
batchIndex: batchIndex
|
batchIndex: batchIndex
|
||||||
};
|
};
|
||||||
|
|
||||||
return this.queryManagementService.getQueryRows(rowData).then(r => r, error => {
|
return this._queryManagementService.getQueryRows(rowData).then(r => r, error => {
|
||||||
// this._notificationService.notify({
|
// this._notificationService.notify({
|
||||||
// severity: Severity.Error,
|
// severity: Severity.Error,
|
||||||
// message: nls.localize('query.gettingRowsFailedError', 'Something went wrong getting more rows: {0}', error)
|
// message: nls.localize('query.gettingRowsFailedError', 'Something went wrong getting more rows: {0}', error)
|
||||||
@@ -398,11 +436,104 @@ 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
|
* Disposes the Query from the service client
|
||||||
*/
|
*/
|
||||||
public async disposeQuery(): Promise<void> {
|
public async disposeQuery(): Promise<void> {
|
||||||
await this.queryManagementService.disposeQuery(this.uri);
|
await this._queryManagementService.disposeQuery(this.uri);
|
||||||
this.dispose();
|
this.dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -430,7 +561,7 @@ export default class QueryRunner extends Disposable {
|
|||||||
|
|
||||||
public getColumnHeaders(batchId: number, resultId: number, range: Slick.Range): string[] | undefined {
|
public getColumnHeaders(batchId: number, resultId: number, range: Slick.Range): string[] | undefined {
|
||||||
let headers: string[] | undefined = undefined;
|
let headers: string[] | undefined = undefined;
|
||||||
let batchSummary: BatchSummary = this._batchSets[batchId];
|
let batchSummary: azdata.BatchSummary = this._batchSets[batchId];
|
||||||
if (batchSummary !== undefined) {
|
if (batchSummary !== undefined) {
|
||||||
let resultSetSummary = batchSummary.resultSetSummaries[resultId];
|
let resultSetSummary = batchSummary.resultSetSummaries[resultId];
|
||||||
headers = resultSetSummary.columnInfo.slice(range.fromCell, range.toCell + 1).map((info, i) => {
|
headers = resultSetSummary.columnInfo.slice(range.fromCell, range.toCell + 1).map((info, i) => {
|
||||||
@@ -442,7 +573,7 @@ export default class QueryRunner extends Disposable {
|
|||||||
|
|
||||||
private sendBatchTimeMessage(batchId: number, executionTime: string): void {
|
private sendBatchTimeMessage(batchId: number, executionTime: string): void {
|
||||||
// get config copyRemoveNewLine option from vscode config
|
// 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) {
|
if (showBatchTime) {
|
||||||
let message: IQueryMessage = {
|
let message: IQueryMessage = {
|
||||||
batchId: batchId,
|
batchId: batchId,
|
||||||
@@ -465,7 +596,7 @@ export default class QueryRunner extends Disposable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public notifyVisualizeRequested(batchId: number, resultSetId: number): void {
|
public notifyVisualizeRequested(batchId: number, resultSetId: number): void {
|
||||||
let result: ResultSetSummary = {
|
let result: azdata.ResultSetSummary = {
|
||||||
batchId: batchId,
|
batchId: batchId,
|
||||||
id: resultSetId,
|
id: resultSetId,
|
||||||
columnInfo: this.batchSets[batchId].resultSetSummaries[resultSetId].columnInfo,
|
columnInfo: this.batchSets[batchId].resultSetSummaries[resultSetId].columnInfo,
|
||||||
@@ -489,7 +620,7 @@ export class QueryGridDataProvider implements IGridDataProvider {
|
|||||||
) {
|
) {
|
||||||
}
|
}
|
||||||
|
|
||||||
getRowData(rowStart: number, numberOfRows: number): Promise<ResultSetSubset> {
|
getRowData(rowStart: number, numberOfRows: number): Promise<azdata.QueryExecuteSubsetResult> {
|
||||||
return this.queryRunner.getQueryRows(rowStart, numberOfRows, this.batchId, this.resultSetId);
|
return this.queryRunner.getQueryRows(rowStart, numberOfRows, this.batchId, this.resultSetId);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -548,6 +679,6 @@ export function shouldRemoveNewLines(configurationService: IConfigurationService
|
|||||||
return !!removeNewLines;
|
return !!removeNewLines;
|
||||||
}
|
}
|
||||||
|
|
||||||
function isRangeOrUndefined(input: string | IRange | undefined): input is IRange | undefined {
|
function isSelectionOrUndefined(input: string | azdata.ISelectionData | undefined): input is azdata.ISelectionData | undefined {
|
||||||
return Range.isIRange(input) || types.isUndefinedOrNull(input);
|
return types.isObject(input) || types.isUndefinedOrNull(input);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,229 +0,0 @@
|
|||||||
/*---------------------------------------------------------------------------------------------
|
|
||||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
||||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
|
||||||
*--------------------------------------------------------------------------------------------*/
|
|
||||||
|
|
||||||
import * as assert from 'assert';
|
|
||||||
import * as sinon from 'sinon';
|
|
||||||
import QueryRunner from 'sql/workbench/services/query/common/queryRunner';
|
|
||||||
import { BatchSummary, ResultSetSummary, IResultMessage, ResultSetSubset, CompleteBatchSummary } from 'sql/workbench/services/query/common/query';
|
|
||||||
import { URI } from 'vs/base/common/uri';
|
|
||||||
import { workbenchInstantiationService } from 'sql/workbench/test/workbenchTestServices';
|
|
||||||
import { TestInstantiationService } from 'vs/platform/instantiation/test/common/instantiationServiceMock';
|
|
||||||
import { IQueryManagementService } from 'sql/workbench/services/query/common/queryManagement';
|
|
||||||
import { Event } from 'vs/base/common/event';
|
|
||||||
import { range } from 'vs/base/common/arrays';
|
|
||||||
|
|
||||||
suite('Query Runner', () => {
|
|
||||||
test('does execute a standard selection query workflow', async () => {
|
|
||||||
const instantiationService = workbenchInstantiationService();
|
|
||||||
const uri = URI.parse('test:uri').toString();
|
|
||||||
const runner = instantiationService.createInstance(QueryRunner, uri);
|
|
||||||
const runQueryStub = sinon.stub().returns(Promise.resolve());
|
|
||||||
(instantiationService as TestInstantiationService).stub(IQueryManagementService, 'runQuery', runQueryStub);
|
|
||||||
assert(!runner.isExecuting);
|
|
||||||
assert(!runner.hasCompleted);
|
|
||||||
// start query
|
|
||||||
const queryStartPromise = Event.toPromise(runner.onQueryStart);
|
|
||||||
const rangeSelection = { endColumn: 1, endLineNumber: 1, startColumn: 1, startLineNumber: 1 };
|
|
||||||
await runner.runQuery(rangeSelection);
|
|
||||||
assert(runQueryStub.calledOnce);
|
|
||||||
assert(runQueryStub.calledWithExactly(uri, rangeSelection, undefined));
|
|
||||||
await queryStartPromise;
|
|
||||||
assert(runner.queryStartTime instanceof Date);
|
|
||||||
assert(runner.isExecuting);
|
|
||||||
assert(!runner.hasCompleted);
|
|
||||||
// start batch
|
|
||||||
const batch: BatchSummary = { id: 0, hasError: false, range: rangeSelection, resultSetSummaries: [], executionStart: '' };
|
|
||||||
const returnBatch = await trigger(batch, arg => runner.handleBatchStart(arg), runner.onBatchStart);
|
|
||||||
assert.deepEqual(returnBatch, batch);
|
|
||||||
// we expect the query runner to create a message sense we sent a selection
|
|
||||||
assert(runner.messages.length === 1);
|
|
||||||
// start result set
|
|
||||||
const result1: ResultSetSummary = { batchId: 0, id: 0, complete: false, rowCount: 0, columnInfo: [{ columnName: 'column' }] };
|
|
||||||
const returnResult = await trigger(result1, arg => runner.handleResultSetAvailable(arg), runner.onResultSet);
|
|
||||||
assert.deepEqual(returnResult, result1);
|
|
||||||
assert.deepEqual(runner.batchSets[0].resultSetSummaries[0], result1);
|
|
||||||
// update result set
|
|
||||||
const result1Update: ResultSetSummary = { batchId: 0, id: 0, complete: true, rowCount: 100, columnInfo: [{ columnName: 'column' }] };
|
|
||||||
const returnResultUpdate = await trigger(result1Update, arg => runner.handleResultSetUpdated(arg), runner.onResultSetUpdate);
|
|
||||||
assert.deepEqual(returnResultUpdate, result1Update);
|
|
||||||
assert.deepEqual(runner.batchSets[0].resultSetSummaries[0], result1Update);
|
|
||||||
// post message
|
|
||||||
const message: IResultMessage = { message: 'some message', isError: false, batchId: 0 };
|
|
||||||
const messageReturn = await trigger([message], arg => runner.handleMessage(arg), runner.onMessage);
|
|
||||||
assert.deepEqual(messageReturn[0], message);
|
|
||||||
assert.deepEqual(runner.messages[1], message);
|
|
||||||
// get query rows
|
|
||||||
const rowResults: ResultSetSubset = { rowCount: 100, rows: range(100).map(r => range(1).map(c => ({ displayValue: `${r}${c}` }))) };
|
|
||||||
const getRowStub = sinon.stub().returns(Promise.resolve(rowResults));
|
|
||||||
(instantiationService as TestInstantiationService).stub(IQueryManagementService, 'getQueryRows', getRowStub);
|
|
||||||
const resultReturn = await runner.getQueryRows(0, 100, 0, 0);
|
|
||||||
assert(getRowStub.calledWithExactly({ ownerUri: uri, batchIndex: 0, resultSetIndex: 0, rowsStartIndex: 0, rowsCount: 100 }));
|
|
||||||
assert.deepStrictEqual(resultReturn, rowResults);
|
|
||||||
// batch complete
|
|
||||||
const batchComplete: CompleteBatchSummary = { ...batch, executionEnd: 'endstring', executionElapsed: 'elapsedstring' };
|
|
||||||
const batchCompleteReturn = await trigger(batchComplete, arg => runner.handleBatchComplete(arg), runner.onBatchEnd);
|
|
||||||
assert.deepStrictEqual(batchCompleteReturn, batchComplete);
|
|
||||||
// query complete
|
|
||||||
await trigger([batchComplete], arg => runner.handleQueryComplete(arg), runner.onQueryEnd);
|
|
||||||
assert(!runner.isExecuting);
|
|
||||||
assert(runner.hasCompleted);
|
|
||||||
await runner.disposeQuery();
|
|
||||||
});
|
|
||||||
|
|
||||||
test('does handle inital query failure', async () => {
|
|
||||||
const instantiationService = workbenchInstantiationService();
|
|
||||||
const uri = URI.parse('test:uri').toString();
|
|
||||||
const runner = instantiationService.createInstance(QueryRunner, uri);
|
|
||||||
const runQueryStub = sinon.stub().returns(Promise.reject(new Error('some error')));
|
|
||||||
(instantiationService as TestInstantiationService).stub(IQueryManagementService, 'runQuery', runQueryStub);
|
|
||||||
assert(!runner.isExecuting);
|
|
||||||
assert(!runner.hasCompleted);
|
|
||||||
// start query
|
|
||||||
const queryCompletePromise = Event.toPromise(runner.onQueryEnd);
|
|
||||||
const rangeSelection = { endColumn: 1, endLineNumber: 1, startColumn: 1, startLineNumber: 1 };
|
|
||||||
await runner.runQuery(rangeSelection);
|
|
||||||
await queryCompletePromise;
|
|
||||||
assert(runQueryStub.calledOnce);
|
|
||||||
assert(runQueryStub.calledWithExactly(uri, rangeSelection, undefined));
|
|
||||||
assert(runner.messages.length === 2);
|
|
||||||
assert(runner.messages[0].message.includes('some error'));
|
|
||||||
assert(runner.messages[0].isError);
|
|
||||||
});
|
|
||||||
|
|
||||||
test('does handle cancel query', async () => {
|
|
||||||
const instantiationService = workbenchInstantiationService();
|
|
||||||
const uri = URI.parse('test:uri').toString();
|
|
||||||
const runner = instantiationService.createInstance(QueryRunner, uri);
|
|
||||||
assert(!runner.isExecuting);
|
|
||||||
// start query
|
|
||||||
const rangeSelection = { endColumn: 1, endLineNumber: 1, startColumn: 1, startLineNumber: 1 };
|
|
||||||
await runner.runQuery(rangeSelection);
|
|
||||||
assert(runner.isExecuting);
|
|
||||||
// cancel query
|
|
||||||
const cancelQueryStub = sinon.stub().returns(Promise.resolve());
|
|
||||||
(instantiationService as TestInstantiationService).stub(IQueryManagementService, 'cancelQuery', cancelQueryStub);
|
|
||||||
await runner.cancelQuery();
|
|
||||||
assert(cancelQueryStub.calledOnce);
|
|
||||||
await trigger([], () => runner.handleQueryComplete(), runner.onQueryEnd);
|
|
||||||
assert(!runner.isExecuting);
|
|
||||||
});
|
|
||||||
|
|
||||||
test('does handle query plan in inital data set', async () => {
|
|
||||||
const instantiationService = workbenchInstantiationService();
|
|
||||||
const uri = URI.parse('test:uri').toString();
|
|
||||||
const runner = instantiationService.createInstance(QueryRunner, uri);
|
|
||||||
const runQueryStub = sinon.stub().returns(Promise.resolve());
|
|
||||||
(instantiationService as TestInstantiationService).stub(IQueryManagementService, 'runQuery', runQueryStub);
|
|
||||||
await runner.runQuery(undefined, { displayEstimatedQueryPlan: true });
|
|
||||||
assert(runQueryStub.calledOnce);
|
|
||||||
assert(runQueryStub.calledWithExactly(uri, undefined, { displayEstimatedQueryPlan: true }));
|
|
||||||
const xmlPlan = 'xml plan';
|
|
||||||
const getRowsStub = sinon.stub().returns(Promise.resolve({ rowCount: 1, rows: [[{ displayValue: xmlPlan }]] } as ResultSetSubset));
|
|
||||||
(instantiationService as TestInstantiationService).stub(IQueryManagementService, 'getQueryRows', getRowsStub);
|
|
||||||
runner.handleBatchStart({ id: 0, executionStart: '' });
|
|
||||||
runner.handleResultSetAvailable({ id: 0, batchId: 0, complete: true, rowCount: 1, columnInfo: [{ columnName: 'Microsoft SQL Server 2005 XML Showplan' }] });
|
|
||||||
const plan = await runner.planXml;
|
|
||||||
assert(getRowsStub.calledOnce);
|
|
||||||
assert.equal(plan, xmlPlan);
|
|
||||||
assert(runner.isQueryPlan);
|
|
||||||
});
|
|
||||||
|
|
||||||
test('does handle query plan in update', async () => {
|
|
||||||
const instantiationService = workbenchInstantiationService();
|
|
||||||
const uri = URI.parse('test:uri').toString();
|
|
||||||
const runner = instantiationService.createInstance(QueryRunner, uri);
|
|
||||||
const runQueryStub = sinon.stub().returns(Promise.resolve());
|
|
||||||
(instantiationService as TestInstantiationService).stub(IQueryManagementService, 'runQuery', runQueryStub);
|
|
||||||
await runner.runQuery(undefined, { displayEstimatedQueryPlan: true });
|
|
||||||
assert(runQueryStub.calledOnce);
|
|
||||||
assert(runQueryStub.calledWithExactly(uri, undefined, { displayEstimatedQueryPlan: true }));
|
|
||||||
runner.handleBatchStart({ id: 0, executionStart: '' });
|
|
||||||
runner.handleResultSetAvailable({ id: 0, batchId: 0, complete: false, rowCount: 0, columnInfo: [{ columnName: 'Microsoft SQL Server 2005 XML Showplan' }] });
|
|
||||||
const xmlPlan = 'xml plan';
|
|
||||||
const getRowsStub = sinon.stub().returns(Promise.resolve({ rowCount: 1, rows: [[{ displayValue: xmlPlan }]] } as ResultSetSubset));
|
|
||||||
(instantiationService as TestInstantiationService).stub(IQueryManagementService, 'getQueryRows', getRowsStub);
|
|
||||||
runner.handleResultSetUpdated({ id: 0, batchId: 0, complete: true, rowCount: 1, columnInfo: [{ columnName: 'Microsoft SQL Server 2005 XML Showplan' }] });
|
|
||||||
const plan = await runner.planXml;
|
|
||||||
assert(getRowsStub.calledOnce);
|
|
||||||
assert.equal(plan, xmlPlan);
|
|
||||||
assert(runner.isQueryPlan);
|
|
||||||
});
|
|
||||||
|
|
||||||
test('does run query string', async () => {
|
|
||||||
const instantiationService = workbenchInstantiationService();
|
|
||||||
const uri = URI.parse('test:uri').toString();
|
|
||||||
const runner = instantiationService.createInstance(QueryRunner, uri);
|
|
||||||
const runQueryStringStub = sinon.stub().returns(Promise.resolve());
|
|
||||||
(instantiationService as TestInstantiationService).stub(IQueryManagementService, 'runQueryString', runQueryStringStub);
|
|
||||||
assert(!runner.isExecuting);
|
|
||||||
assert(!runner.hasCompleted);
|
|
||||||
// start query
|
|
||||||
await runner.runQuery('some query');
|
|
||||||
assert(runQueryStringStub.calledOnce);
|
|
||||||
assert(runQueryStringStub.calledWithExactly(uri, 'some query'));
|
|
||||||
assert(runner.isExecuting);
|
|
||||||
});
|
|
||||||
|
|
||||||
test('does handle run query string error', async () => {
|
|
||||||
const instantiationService = workbenchInstantiationService();
|
|
||||||
const uri = URI.parse('test:uri').toString();
|
|
||||||
const runner = instantiationService.createInstance(QueryRunner, uri);
|
|
||||||
const runQueryStringStub = sinon.stub().returns(Promise.reject(new Error('some error')));
|
|
||||||
(instantiationService as TestInstantiationService).stub(IQueryManagementService, 'runQueryString', runQueryStringStub);
|
|
||||||
assert(!runner.isExecuting);
|
|
||||||
assert(!runner.hasCompleted);
|
|
||||||
// start query
|
|
||||||
const queryCompletePromise = Event.toPromise(runner.onQueryEnd);
|
|
||||||
await runner.runQuery('some query');
|
|
||||||
await queryCompletePromise;
|
|
||||||
assert(runQueryStringStub.calledOnce);
|
|
||||||
assert(runQueryStringStub.calledWithExactly(uri, 'some query'));
|
|
||||||
assert(runner.messages.length === 2);
|
|
||||||
assert(runner.messages[0].message.includes('some error'));
|
|
||||||
assert(runner.messages[0].isError);
|
|
||||||
});
|
|
||||||
|
|
||||||
test('does run query statement', async () => {
|
|
||||||
const instantiationService = workbenchInstantiationService();
|
|
||||||
const uri = URI.parse('test:uri').toString();
|
|
||||||
const runner = instantiationService.createInstance(QueryRunner, uri);
|
|
||||||
const runQueryStatementStub = sinon.stub().returns(Promise.resolve());
|
|
||||||
(instantiationService as TestInstantiationService).stub(IQueryManagementService, 'runQueryStatement', runQueryStatementStub);
|
|
||||||
assert(!runner.isExecuting);
|
|
||||||
assert(!runner.hasCompleted);
|
|
||||||
// start query
|
|
||||||
const rangeSelection = { endColumn: 1, endLineNumber: 1, startColumn: 1, startLineNumber: 1 };
|
|
||||||
await runner.runQueryStatement(rangeSelection);
|
|
||||||
assert(runQueryStatementStub.calledOnce);
|
|
||||||
assert(runQueryStatementStub.calledWithExactly(uri, rangeSelection.startLineNumber, rangeSelection.startColumn));
|
|
||||||
assert(runner.isExecuting);
|
|
||||||
});
|
|
||||||
|
|
||||||
test('does handle run query statement error', async () => {
|
|
||||||
const instantiationService = workbenchInstantiationService();
|
|
||||||
const uri = URI.parse('test:uri').toString();
|
|
||||||
const runner = instantiationService.createInstance(QueryRunner, uri);
|
|
||||||
const runQueryStatementStub = sinon.stub().returns(Promise.reject(new Error('some error')));
|
|
||||||
(instantiationService as TestInstantiationService).stub(IQueryManagementService, 'runQueryStatement', runQueryStatementStub);
|
|
||||||
assert(!runner.isExecuting);
|
|
||||||
assert(!runner.hasCompleted);
|
|
||||||
// start query
|
|
||||||
const queryCompletePromise = Event.toPromise(runner.onQueryEnd);
|
|
||||||
const rangeSelection = { endColumn: 1, endLineNumber: 1, startColumn: 1, startLineNumber: 1 };
|
|
||||||
await runner.runQueryStatement(rangeSelection);
|
|
||||||
await queryCompletePromise;
|
|
||||||
assert(runQueryStatementStub.calledOnce);
|
|
||||||
assert(runQueryStatementStub.calledWithExactly(uri, rangeSelection.startLineNumber, rangeSelection.startColumn));
|
|
||||||
assert(runner.messages.length === 2);
|
|
||||||
assert(runner.messages[0].message.includes('some error'));
|
|
||||||
assert(runner.messages[0].isError);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
function trigger<T, V = T>(arg: T, func: (arg: T) => void, event: Event<V>): Promise<V> {
|
|
||||||
const promise = Event.toPromise(event);
|
|
||||||
func(arg);
|
|
||||||
return promise;
|
|
||||||
}
|
|
||||||
@@ -1,108 +0,0 @@
|
|||||||
/*---------------------------------------------------------------------------------------------
|
|
||||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
||||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
|
||||||
*--------------------------------------------------------------------------------------------*/
|
|
||||||
|
|
||||||
import { IQueryManagementService, IQueryRequestHandler, ExecutionPlanOptions } from 'sql/workbench/services/query/common/queryManagement';
|
|
||||||
import { Event } from 'vs/base/common/event';
|
|
||||||
import { IDisposable } from 'vs/base/common/lifecycle';
|
|
||||||
import QueryRunner from 'sql/workbench/services/query/common/queryRunner';
|
|
||||||
import * as azdata from 'azdata';
|
|
||||||
import { IRange } from 'vs/editor/common/core/range';
|
|
||||||
import { ResultSetSubset } from 'sql/workbench/services/query/common/query';
|
|
||||||
|
|
||||||
export class TestQueryManagementService implements IQueryManagementService {
|
|
||||||
_serviceBrand: undefined;
|
|
||||||
onHandlerAdded: Event<string>;
|
|
||||||
addQueryRequestHandler(queryType: string, runner: IQueryRequestHandler): IDisposable {
|
|
||||||
throw new Error('Method not implemented.');
|
|
||||||
}
|
|
||||||
isProviderRegistered(providerId: string): boolean {
|
|
||||||
throw new Error('Method not implemented.');
|
|
||||||
}
|
|
||||||
getRegisteredProviders(): string[] {
|
|
||||||
throw new Error('Method not implemented.');
|
|
||||||
}
|
|
||||||
registerRunner(runner: QueryRunner, uri: string): void {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
async cancelQuery(ownerUri: string): Promise<azdata.QueryCancelResult> {
|
|
||||||
return { messages: undefined };
|
|
||||||
}
|
|
||||||
async runQuery(ownerUri: string, range: IRange, runOptions?: ExecutionPlanOptions): Promise<void> {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
runQueryStatement(ownerUri: string, line: number, column: number): Promise<void> {
|
|
||||||
throw new Error('Method not implemented.');
|
|
||||||
}
|
|
||||||
runQueryString(ownerUri: string, queryString: string): Promise<void> {
|
|
||||||
throw new Error('Method not implemented.');
|
|
||||||
}
|
|
||||||
runQueryAndReturn(ownerUri: string, queryString: string): Promise<azdata.SimpleExecuteResult> {
|
|
||||||
throw new Error('Method not implemented.');
|
|
||||||
}
|
|
||||||
parseSyntax(ownerUri: string, query: string): Promise<azdata.SyntaxParseResult> {
|
|
||||||
throw new Error('Method not implemented.');
|
|
||||||
}
|
|
||||||
getQueryRows(rowData: azdata.QueryExecuteSubsetParams): Promise<ResultSetSubset> {
|
|
||||||
throw new Error('Method not implemented.');
|
|
||||||
}
|
|
||||||
async disposeQuery(ownerUri: string): Promise<void> {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
saveResults(requestParams: azdata.SaveResultsRequestParams): Promise<azdata.SaveResultRequestResult> {
|
|
||||||
throw new Error('Method not implemented.');
|
|
||||||
}
|
|
||||||
setQueryExecutionOptions(uri: string, options: azdata.QueryExecutionOptions): Promise<void> {
|
|
||||||
throw new Error('Method not implemented.');
|
|
||||||
}
|
|
||||||
onQueryComplete(result: azdata.QueryExecuteCompleteNotificationResult): void {
|
|
||||||
throw new Error('Method not implemented.');
|
|
||||||
}
|
|
||||||
onBatchStart(batchInfo: azdata.QueryExecuteBatchNotificationParams): void {
|
|
||||||
throw new Error('Method not implemented.');
|
|
||||||
}
|
|
||||||
onBatchComplete(batchInfo: azdata.QueryExecuteBatchNotificationParams): void {
|
|
||||||
throw new Error('Method not implemented.');
|
|
||||||
}
|
|
||||||
onResultSetAvailable(resultSetInfo: azdata.QueryExecuteResultSetNotificationParams): void {
|
|
||||||
throw new Error('Method not implemented.');
|
|
||||||
}
|
|
||||||
onResultSetUpdated(resultSetInfo: azdata.QueryExecuteResultSetNotificationParams): void {
|
|
||||||
throw new Error('Method not implemented.');
|
|
||||||
}
|
|
||||||
onMessage(message: Map<string, azdata.QueryExecuteMessageParams[]>): void {
|
|
||||||
throw new Error('Method not implemented.');
|
|
||||||
}
|
|
||||||
onEditSessionReady(ownerUri: string, success: boolean, message: string): void {
|
|
||||||
throw new Error('Method not implemented.');
|
|
||||||
}
|
|
||||||
initializeEdit(ownerUri: string, schemaName: string, objectName: string, objectType: string, rowLimit: number, queryString: string): Promise<void> {
|
|
||||||
throw new Error('Method not implemented.');
|
|
||||||
}
|
|
||||||
disposeEdit(ownerUri: string): Promise<void> {
|
|
||||||
throw new Error('Method not implemented.');
|
|
||||||
}
|
|
||||||
updateCell(ownerUri: string, rowId: number, columnId: number, newValue: string): Promise<azdata.EditUpdateCellResult> {
|
|
||||||
throw new Error('Method not implemented.');
|
|
||||||
}
|
|
||||||
commitEdit(ownerUri: string): Promise<void> {
|
|
||||||
throw new Error('Method not implemented.');
|
|
||||||
}
|
|
||||||
createRow(ownerUri: string): Promise<azdata.EditCreateRowResult> {
|
|
||||||
throw new Error('Method not implemented.');
|
|
||||||
}
|
|
||||||
deleteRow(ownerUri: string, rowId: number): Promise<void> {
|
|
||||||
throw new Error('Method not implemented.');
|
|
||||||
}
|
|
||||||
revertCell(ownerUri: string, rowId: number, columnId: number): Promise<azdata.EditRevertCellResult> {
|
|
||||||
throw new Error('Method not implemented.');
|
|
||||||
}
|
|
||||||
revertRow(ownerUri: string, rowId: number): Promise<void> {
|
|
||||||
throw new Error('Method not implemented.');
|
|
||||||
}
|
|
||||||
getEditRows(rowData: azdata.EditSubsetParams): Promise<azdata.EditSubsetResult> {
|
|
||||||
throw new Error('Method not implemented.');
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -9,7 +9,6 @@ import * as azdata from 'azdata';
|
|||||||
import { Event } from 'vs/base/common/event';
|
import { Event } from 'vs/base/common/event';
|
||||||
import { QueryInfo } from 'sql/workbench/services/query/common/queryModelService';
|
import { QueryInfo } from 'sql/workbench/services/query/common/queryModelService';
|
||||||
import { DataService } from 'sql/workbench/services/query/common/dataService';
|
import { DataService } from 'sql/workbench/services/query/common/dataService';
|
||||||
import { IRange } from 'vs/editor/common/core/range';
|
|
||||||
|
|
||||||
export class TestQueryModelService implements IQueryModelService {
|
export class TestQueryModelService implements IQueryModelService {
|
||||||
_serviceBrand: any;
|
_serviceBrand: any;
|
||||||
@@ -26,10 +25,10 @@ export class TestQueryModelService implements IQueryModelService {
|
|||||||
getQueryRows(uri: string, rowStart: number, numberOfRows: number, batchId: number, resultId: number): Promise<azdata.ResultSetSubset> {
|
getQueryRows(uri: string, rowStart: number, numberOfRows: number, batchId: number, resultId: number): Promise<azdata.ResultSetSubset> {
|
||||||
throw new Error('Method not implemented.');
|
throw new Error('Method not implemented.');
|
||||||
}
|
}
|
||||||
runQuery(uri: string, range: IRange, runOptions?: azdata.ExecutionPlanOptions): void {
|
runQuery(uri: string, selection: azdata.ISelectionData, runOptions?: azdata.ExecutionPlanOptions): void {
|
||||||
throw new Error('Method not implemented.');
|
throw new Error('Method not implemented.');
|
||||||
}
|
}
|
||||||
runQueryStatement(uri: string, range: IRange): void {
|
runQueryStatement(uri: string, selection: azdata.ISelectionData): void {
|
||||||
throw new Error('Method not implemented.');
|
throw new Error('Method not implemented.');
|
||||||
}
|
}
|
||||||
runQueryString(uri: string, selection: string) {
|
runQueryString(uri: string, selection: string) {
|
||||||
|
|||||||
@@ -52,12 +52,12 @@ export class QueryHistoryService extends Disposable implements IQueryHistoryServ
|
|||||||
const uri: URI = URI.parse(e.uri);
|
const uri: URI = URI.parse(e.uri);
|
||||||
// VS Range is 1 based so offset values by 1. The endLine we get back from SqlToolsService is incremented
|
// VS Range is 1 based so offset values by 1. The endLine we get back from SqlToolsService is incremented
|
||||||
// by 1 from the original input range sent in as well so take that into account and don't modify
|
// by 1 from the original input range sent in as well so take that into account and don't modify
|
||||||
const text: string = e.queryInfo.range && e.queryInfo.range.length > 0 ?
|
const text: string = e.queryInfo.selection && e.queryInfo.selection.length > 0 ?
|
||||||
_modelService.getModel(uri).getValueInRange(new Range(
|
_modelService.getModel(uri).getValueInRange(new Range(
|
||||||
e.queryInfo.range[0].startLineNumber,
|
e.queryInfo.selection[0].startLine + 1,
|
||||||
e.queryInfo.range[0].startColumn,
|
e.queryInfo.selection[0].startColumn + 1,
|
||||||
e.queryInfo.range[0].endLineNumber,
|
e.queryInfo.selection[0].endLine,
|
||||||
e.queryInfo.range[0].endColumn)) :
|
e.queryInfo.selection[0].endColumn + 1)) :
|
||||||
// If no specific selection get the entire text
|
// If no specific selection get the entire text
|
||||||
_modelService.getModel(uri).getValue();
|
_modelService.getModel(uri).getValue();
|
||||||
|
|
||||||
|
|||||||
@@ -12,8 +12,6 @@ import { TestObjectExplorerService } from 'sql/workbench/services/objectExplorer
|
|||||||
import { IObjectExplorerService } from 'sql/workbench/services/objectExplorer/browser/objectExplorerService';
|
import { IObjectExplorerService } from 'sql/workbench/services/objectExplorer/browser/objectExplorerService';
|
||||||
import { IQueryEditorService } from 'sql/workbench/services/queryEditor/common/queryEditorService';
|
import { IQueryEditorService } from 'sql/workbench/services/queryEditor/common/queryEditorService';
|
||||||
import { TestQueryEditorService } from 'sql/workbench/services/queryEditor/test/common/testQueryEditorService';
|
import { TestQueryEditorService } from 'sql/workbench/services/queryEditor/test/common/testQueryEditorService';
|
||||||
import { IQueryManagementService } from 'sql/workbench/services/query/common/queryManagement';
|
|
||||||
import { TestQueryManagementService } from 'sql/workbench/services/query/test/common/testQueryManagementService';
|
|
||||||
|
|
||||||
export function workbenchInstantiationService(): ITestInstantiationService {
|
export function workbenchInstantiationService(): ITestInstantiationService {
|
||||||
const instantiationService = vsworkbenchInstantiationService();
|
const instantiationService = vsworkbenchInstantiationService();
|
||||||
@@ -21,6 +19,5 @@ export function workbenchInstantiationService(): ITestInstantiationService {
|
|||||||
instantiationService.stub(IConnectionManagementService, new TestConnectionManagementService());
|
instantiationService.stub(IConnectionManagementService, new TestConnectionManagementService());
|
||||||
instantiationService.stub(IQueryModelService, new TestQueryModelService());
|
instantiationService.stub(IQueryModelService, new TestQueryModelService());
|
||||||
instantiationService.stub(IObjectExplorerService, new TestObjectExplorerService());
|
instantiationService.stub(IObjectExplorerService, new TestObjectExplorerService());
|
||||||
instantiationService.stub(IQueryManagementService, new TestQueryManagementService());
|
|
||||||
return instantiationService;
|
return instantiationService;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -658,7 +658,6 @@ abstract class ResourceNavigator<T> extends Disposable {
|
|||||||
onDidChangeFocus: Event<{ browserEvent?: UIEvent }>,
|
onDidChangeFocus: Event<{ browserEvent?: UIEvent }>,
|
||||||
onDidChangeSelection: Event<{ browserEvent?: UIEvent }>,
|
onDidChangeSelection: Event<{ browserEvent?: UIEvent }>,
|
||||||
onDidOpen: Event<{ browserEvent?: UIEvent }>,
|
onDidOpen: Event<{ browserEvent?: UIEvent }>,
|
||||||
readonly openOnSingleClick?: boolean
|
|
||||||
},
|
},
|
||||||
options?: IResourceNavigatorOptions
|
options?: IResourceNavigatorOptions
|
||||||
) {
|
) {
|
||||||
@@ -712,7 +711,7 @@ abstract class ResourceNavigator<T> extends Disposable {
|
|||||||
!!(<SelectionKeyboardEvent>browserEvent).preserveFocus :
|
!!(<SelectionKeyboardEvent>browserEvent).preserveFocus :
|
||||||
!isDoubleClick;
|
!isDoubleClick;
|
||||||
|
|
||||||
if (this.treeOrList.openOnSingleClick || isDoubleClick || isKeyboardEvent) {
|
if (this.options.openOnSingleClick || isDoubleClick || isKeyboardEvent) {
|
||||||
const sideBySide = browserEvent instanceof MouseEvent && (browserEvent.ctrlKey || browserEvent.metaKey || browserEvent.altKey);
|
const sideBySide = browserEvent instanceof MouseEvent && (browserEvent.ctrlKey || browserEvent.metaKey || browserEvent.altKey);
|
||||||
this.open(preserveFocus, isDoubleClick || isMiddleClick, sideBySide, browserEvent);
|
this.open(preserveFocus, isDoubleClick || isMiddleClick, sideBySide, browserEvent);
|
||||||
}
|
}
|
||||||
@@ -739,8 +738,8 @@ export class ListResourceNavigator<T> extends ResourceNavigator<number> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export class TreeResourceNavigator<T, TFilterData> extends ResourceNavigator<T> {
|
export class TreeResourceNavigator<T, TFilterData> extends ResourceNavigator<T> {
|
||||||
constructor(tree: WorkbenchObjectTree<T, TFilterData> | WorkbenchCompressibleObjectTree<T, TFilterData> | WorkbenchDataTree<any, T, TFilterData> | WorkbenchAsyncDataTree<any, T, TFilterData> | WorkbenchCompressibleAsyncDataTree<any, T, TFilterData>, options: IResourceNavigatorOptions = {}) {
|
constructor(tree: WorkbenchObjectTree<T, TFilterData> | WorkbenchCompressibleObjectTree<T, TFilterData> | WorkbenchDataTree<any, T, TFilterData> | WorkbenchAsyncDataTree<any, T, TFilterData> | WorkbenchCompressibleAsyncDataTree<any, T, TFilterData>, options?: IResourceNavigatorOptions) {
|
||||||
super(tree, options);
|
super(tree, { openOnSingleClick: tree.openOnSingleClick, ...(options || {}) });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -125,7 +125,7 @@ export class MainThreadTextEditors implements MainThreadTextEditorsShape {
|
|||||||
// preserve pre 1.38 behaviour to not make group active when preserveFocus: true
|
// preserve pre 1.38 behaviour to not make group active when preserveFocus: true
|
||||||
// but make sure to restore the editor to fix https://github.com/microsoft/vscode/issues/79633
|
// but make sure to restore the editor to fix https://github.com/microsoft/vscode/issues/79633
|
||||||
activation: options.preserveFocus ? EditorActivation.RESTORE : undefined,
|
activation: options.preserveFocus ? EditorActivation.RESTORE : undefined,
|
||||||
ignoreOverrides: true
|
ignoreOverrides: uri?.fsPath?.toLowerCase().endsWith('ipynb') || uri?.fsPath?.toLowerCase().endsWith('sql') ? false : true // {{SQL CARBON EDIT}}
|
||||||
};
|
};
|
||||||
|
|
||||||
const input: IResourceEditorInput = {
|
const input: IResourceEditorInput = {
|
||||||
|
|||||||
@@ -84,6 +84,7 @@ export class ExtensionRecommendationsService extends Disposable implements IExte
|
|||||||
this.dynamicWorkspaceRecommendations = instantiationService.createInstance(DynamicWorkspaceRecommendations, isExtensionAllowedToBeRecommended);
|
this.dynamicWorkspaceRecommendations = instantiationService.createInstance(DynamicWorkspaceRecommendations, isExtensionAllowedToBeRecommended);
|
||||||
this.keymapRecommendations = instantiationService.createInstance(KeymapRecommendations, isExtensionAllowedToBeRecommended);
|
this.keymapRecommendations = instantiationService.createInstance(KeymapRecommendations, isExtensionAllowedToBeRecommended);
|
||||||
this.staticRecommendations = instantiationService.createInstance(StaticRecommendations, isExtensionAllowedToBeRecommended); // {{SQL CARBON EDIT}} add ours
|
this.staticRecommendations = instantiationService.createInstance(StaticRecommendations, isExtensionAllowedToBeRecommended); // {{SQL CARBON EDIT}} add ours
|
||||||
|
this.scenarioRecommendations = instantiationService.createInstance(ScenarioRecommendations, isExtensionAllowedToBeRecommended); // {{SQL CARBON EDIT}} add ours
|
||||||
|
|
||||||
if (!this.isEnabled()) {
|
if (!this.isEnabled()) {
|
||||||
this.sessionSeed = 0;
|
this.sessionSeed = 0;
|
||||||
@@ -99,6 +100,7 @@ export class ExtensionRecommendationsService extends Disposable implements IExte
|
|||||||
this.experimentalRecommendations.activate();
|
this.experimentalRecommendations.activate();
|
||||||
this.keymapRecommendations.activate();
|
this.keymapRecommendations.activate();
|
||||||
this.staticRecommendations.activate(); // {{SQL CARBON EDIT}} add ours
|
this.staticRecommendations.activate(); // {{SQL CARBON EDIT}} add ours
|
||||||
|
this.scenarioRecommendations.activate(); // {{SQL CARBON EDIT}} add ours
|
||||||
if (!this.configurationService.getValue<boolean>(ShowRecommendationsOnlyOnDemandKey)) {
|
if (!this.configurationService.getValue<boolean>(ShowRecommendationsOnlyOnDemandKey)) {
|
||||||
lifecycleService.when(LifecyclePhase.Eventually).then(() => this.activateProactiveRecommendations());
|
lifecycleService.when(LifecyclePhase.Eventually).then(() => this.activateProactiveRecommendations());
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3043,7 +3043,7 @@ export class InstallVSIXAction extends Action {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const requireReload = !(extension.local && this.extensionService.canAddExtension(toExtensionDescription(extension.local)));
|
const requireReload = !(extension.local && this.extensionService.canAddExtension(toExtensionDescription(extension.local)));
|
||||||
const message = requireReload ? localize('InstallVSIXAction.successReload', "Please reload Visual Studio Code to complete installing the extension {0}.", extension.displayName || extension.name)
|
const message = requireReload ? localize('InstallVSIXAction.successReload', "Please reload Azure Data Studio to complete installing the extension {0}.", extension.displayName || extension.name) // {{SQL CARBON EDIT}}
|
||||||
: localize('InstallVSIXAction.success', "Completed installing the extension {0}.", extension.displayName || extension.name);
|
: localize('InstallVSIXAction.success', "Completed installing the extension {0}.", extension.displayName || extension.name);
|
||||||
const actions = requireReload ? [{
|
const actions = requireReload ? [{
|
||||||
label: localize('InstallVSIXAction.reloadNow', "Reload Now"),
|
label: localize('InstallVSIXAction.reloadNow', "Reload Now"),
|
||||||
|
|||||||
@@ -230,55 +230,61 @@ export class FileBasedRecommendations extends ExtensionRecommendations {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private async promptRecommendedExtensionForFileExtension(fileExtension: string, installed: ILocalExtension[]): Promise<void> {
|
private async promptRecommendedExtensionForFileExtension(fileExtension: string, installed: ILocalExtension[]): Promise<void> {
|
||||||
const fileExtensionSuggestionIgnoreList = <string[]>JSON.parse(this.storageService.get('extensionsAssistant/fileExtensionsSuggestionIgnore', StorageScope.GLOBAL, '[]'));
|
// {{SQL CARBON EDIT}} - Turn off file extension-based extensions until we have a scenario that requires this. The queryGallery isn't working correctly in ADS now.
|
||||||
if (fileExtensionSuggestionIgnoreList.indexOf(fileExtension) > -1) {
|
let enableRecommendation: boolean = false;
|
||||||
|
if (!enableRecommendation) {
|
||||||
return;
|
return;
|
||||||
}
|
} else {
|
||||||
|
const fileExtensionSuggestionIgnoreList = <string[]>JSON.parse(this.storageService.get('extensionsAssistant/fileExtensionsSuggestionIgnore', StorageScope.GLOBAL, '[]'));
|
||||||
const text = `ext:${fileExtension}`;
|
if (fileExtensionSuggestionIgnoreList.indexOf(fileExtension) > -1) {
|
||||||
const pager = await this.extensionsWorkbenchService.queryGallery({ text, pageSize: 100 }, CancellationToken.None);
|
return;
|
||||||
if (pager.firstPage.length === 0) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const installedExtensionsIds = installed.reduce((result, i) => { result.add(i.identifier.id.toLowerCase()); return result; }, new Set<string>());
|
|
||||||
if (pager.firstPage.some(e => installedExtensionsIds.has(e.identifier.id.toLowerCase()))) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.notificationService.prompt(
|
|
||||||
Severity.Info,
|
|
||||||
localize('showLanguageExtensions', "The Marketplace has extensions that can help with '.{0}' files", fileExtension),
|
|
||||||
[{
|
|
||||||
label: searchMarketplace,
|
|
||||||
run: () => {
|
|
||||||
this.telemetryService.publicLog2<{ userReaction: string, fileExtension: string }, FileExtensionSuggestionClassification>('fileExtensionSuggestion:popup', { userReaction: 'ok', fileExtension });
|
|
||||||
this.viewletService.openViewlet('workbench.view.extensions', true)
|
|
||||||
.then(viewlet => viewlet?.getViewPaneContainer() as IExtensionsViewPaneContainer)
|
|
||||||
.then(viewlet => {
|
|
||||||
viewlet.search(`ext:${fileExtension}`);
|
|
||||||
viewlet.focus();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}, {
|
|
||||||
label: localize('dontShowAgainExtension', "Don't Show Again for '.{0}' files", fileExtension),
|
|
||||||
run: () => {
|
|
||||||
fileExtensionSuggestionIgnoreList.push(fileExtension);
|
|
||||||
this.storageService.store(
|
|
||||||
'extensionsAssistant/fileExtensionsSuggestionIgnore',
|
|
||||||
JSON.stringify(fileExtensionSuggestionIgnoreList),
|
|
||||||
StorageScope.GLOBAL
|
|
||||||
);
|
|
||||||
this.telemetryService.publicLog2<{ userReaction: string, fileExtension: string }, FileExtensionSuggestionClassification>('fileExtensionSuggestion:popup', { userReaction: 'neverShowAgain', fileExtension });
|
|
||||||
}
|
|
||||||
}],
|
|
||||||
{
|
|
||||||
sticky: true,
|
|
||||||
onCancel: () => {
|
|
||||||
this.telemetryService.publicLog2<{ userReaction: string, fileExtension: string }, FileExtensionSuggestionClassification>('fileExtensionSuggestion:popup', { userReaction: 'cancelled', fileExtension });
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
);
|
|
||||||
|
const text = `ext:${fileExtension}`;
|
||||||
|
const pager = await this.extensionsWorkbenchService.queryGallery({ text, pageSize: 100 }, CancellationToken.None);
|
||||||
|
if (pager.firstPage.length === 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const installedExtensionsIds = installed.reduce((result, i) => { result.add(i.identifier.id.toLowerCase()); return result; }, new Set<string>());
|
||||||
|
if (pager.firstPage.some(e => installedExtensionsIds.has(e.identifier.id.toLowerCase()))) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.notificationService.prompt(
|
||||||
|
Severity.Info,
|
||||||
|
localize('showLanguageExtensions', "The Marketplace has extensions that can help with '.{0}' files", fileExtension),
|
||||||
|
[{
|
||||||
|
label: searchMarketplace,
|
||||||
|
run: () => {
|
||||||
|
this.telemetryService.publicLog2<{ userReaction: string, fileExtension: string }, FileExtensionSuggestionClassification>('fileExtensionSuggestion:popup', { userReaction: 'ok', fileExtension });
|
||||||
|
this.viewletService.openViewlet('workbench.view.extensions', true)
|
||||||
|
.then(viewlet => viewlet?.getViewPaneContainer() as IExtensionsViewPaneContainer)
|
||||||
|
.then(viewlet => {
|
||||||
|
viewlet.search(`ext:${fileExtension}`);
|
||||||
|
viewlet.focus();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
label: localize('dontShowAgainExtension', "Don't Show Again for '.{0}' files", fileExtension),
|
||||||
|
run: () => {
|
||||||
|
fileExtensionSuggestionIgnoreList.push(fileExtension);
|
||||||
|
this.storageService.store(
|
||||||
|
'extensionsAssistant/fileExtensionsSuggestionIgnore',
|
||||||
|
JSON.stringify(fileExtensionSuggestionIgnoreList),
|
||||||
|
StorageScope.GLOBAL
|
||||||
|
);
|
||||||
|
this.telemetryService.publicLog2<{ userReaction: string, fileExtension: string }, FileExtensionSuggestionClassification>('fileExtensionSuggestion:popup', { userReaction: 'neverShowAgain', fileExtension });
|
||||||
|
}
|
||||||
|
}],
|
||||||
|
{
|
||||||
|
sticky: true,
|
||||||
|
onCancel: () => {
|
||||||
|
this.telemetryService.publicLog2<{ userReaction: string, fileExtension: string }, FileExtensionSuggestionClassification>('fileExtensionSuggestion:popup', { userReaction: 'cancelled', fileExtension });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private filterInstalled(recommendationsToSuggest: string[], installed: ILocalExtension[]): string[] {
|
private filterInstalled(recommendationsToSuggest: string[], installed: ILocalExtension[]): string[] {
|
||||||
|
|||||||
Reference in New Issue
Block a user