mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-01-16 09:35:36 -05:00
Support Save As CSV/JSON/Excel/XML from Notebooks (#6627)
Updated existing serialization code so it actually supports serialization. Still needs work to replace the saveAs function when a QueryProvider doesn't support save as, but want to handle in separate PR. Removed separate MainThread/ExtHostSerializationProvider code as the DataProtocol code is the right place to put this code Plumbed support through the gridOutputComponent to use the new serialize method in the serialization provider Refactored the resultSerializer so majority of code can be shared between both implementations (for example file save dialog -> save -> show file on completion) * Update to latest SQLToolsService release
This commit is contained in:
@@ -19,5 +19,4 @@ import './mainThreadNotebookDocumentsAndEditors';
|
||||
import './mainThreadObjectExplorer';
|
||||
import './mainThreadQueryEditor';
|
||||
import './mainThreadResourceProvider';
|
||||
import './mainThreadSerializationProvider';
|
||||
import './mainThreadTasks';
|
||||
|
||||
@@ -134,11 +134,11 @@ export class MainThreadDataProtocol implements MainThreadDataProtocolShape {
|
||||
return self._proxy.$disposeQuery(handle, ownerUri);
|
||||
},
|
||||
saveResults(requestParams: azdata.SaveResultsRequestParams): Thenable<azdata.SaveResultRequestResult> {
|
||||
let serializationProvider = self._serializationService.getSerializationFeatureMetadataProvider(requestParams.ownerUri);
|
||||
if (serializationProvider && serializationProvider.enabled) {
|
||||
let saveResultsFeatureInfo = self._serializationService.getSaveResultsFeatureMetadataProvider(requestParams.ownerUri);
|
||||
if (saveResultsFeatureInfo && saveResultsFeatureInfo.enabled) {
|
||||
return self._proxy.$saveResults(handle, requestParams);
|
||||
}
|
||||
else if (serializationProvider && !serializationProvider.enabled) {
|
||||
else if (saveResultsFeatureInfo && !saveResultsFeatureInfo.enabled) {
|
||||
return self._serializationService.disabledSaveAs();
|
||||
}
|
||||
else {
|
||||
@@ -499,6 +499,20 @@ export class MainThreadDataProtocol implements MainThreadDataProtocolShape {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
public $registerSerializationProvider(providerId: string, handle: number): Promise<any> {
|
||||
const self = this;
|
||||
this._serializationService.registerProvider(providerId, <azdata.SerializationProvider>{
|
||||
startSerialization(requestParams: azdata.SerializeDataStartRequestParams): Thenable<azdata.SerializeDataResult> {
|
||||
return self._proxy.$startSerialization(handle, requestParams);
|
||||
},
|
||||
continueSerialization(requestParams: azdata.SerializeDataContinueRequestParams): Thenable<azdata.SerializeDataResult> {
|
||||
return self._proxy.$continueSerialization(handle, requestParams);
|
||||
},
|
||||
});
|
||||
|
||||
return undefined;
|
||||
}
|
||||
|
||||
// Connection Management handlers
|
||||
public $onConnectionComplete(handle: number, connectionInfoSummary: azdata.ConnectionInfoSummary): void {
|
||||
this._connectionManagementService.onConnectionComplete(handle, connectionInfoSummary);
|
||||
|
||||
@@ -1,59 +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 { IDisposable, dispose } from 'vs/base/common/lifecycle';
|
||||
import {
|
||||
SqlExtHostContext, ExtHostSerializationProviderShape,
|
||||
MainThreadSerializationProviderShape, SqlMainContext
|
||||
} from 'sql/workbench/api/common/sqlExtHost.protocol';
|
||||
import { ISerializationService } from 'sql/platform/serialization/common/serializationService';
|
||||
import * as azdata from 'azdata';
|
||||
import { IExtHostContext } from 'vs/workbench/api/common/extHost.protocol';
|
||||
import { extHostNamedCustomer } from 'vs/workbench/api/common/extHostCustomers';
|
||||
|
||||
@extHostNamedCustomer(SqlMainContext.MainThreadSerializationProvider)
|
||||
export class MainThreadSerializationProvider implements MainThreadSerializationProviderShape {
|
||||
|
||||
private _proxy: ExtHostSerializationProviderShape;
|
||||
|
||||
private _toDispose: IDisposable[];
|
||||
|
||||
private _registrations: { [handle: number]: IDisposable; } = Object.create(null);
|
||||
|
||||
constructor(
|
||||
extHostContext: IExtHostContext,
|
||||
@ISerializationService private serializationService: ISerializationService
|
||||
|
||||
) {
|
||||
if (extHostContext) {
|
||||
this._proxy = extHostContext.getProxy(SqlExtHostContext.ExtHostSerializationProvider);
|
||||
}
|
||||
}
|
||||
|
||||
public dispose(): void {
|
||||
this._toDispose = dispose(this._toDispose);
|
||||
}
|
||||
|
||||
public $registerSerializationProvider(handle: number): Promise<any> {
|
||||
let self = this;
|
||||
|
||||
this._registrations[handle] = this.serializationService.addEventListener(handle, {
|
||||
onSaveAs(saveFormat: string, savePath: string, results: string, appendToFile: boolean): Thenable<azdata.SaveResultRequestResult> {
|
||||
return self._proxy.$saveAs(saveFormat, savePath, results, appendToFile);
|
||||
}
|
||||
});
|
||||
|
||||
return undefined;
|
||||
}
|
||||
|
||||
public $unregisterSerializationProvider(handle: number): Promise<any> {
|
||||
let registration = this._registrations[handle];
|
||||
if (registration) {
|
||||
registration.dispose();
|
||||
delete this._registrations[handle];
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
@@ -181,6 +181,12 @@ export class ExtHostDataProtocol extends ExtHostDataProtocolShape {
|
||||
return rt;
|
||||
}
|
||||
|
||||
$registerSerializationProvider(provider: azdata.SerializationProvider): vscode.Disposable {
|
||||
let rt = this.registerProvider(provider, DataProviderType.QueryProvider);
|
||||
this._proxy.$registerSerializationProvider(provider.providerId, provider.handle);
|
||||
return rt;
|
||||
}
|
||||
|
||||
// Capabilities Discovery handlers
|
||||
$getServerCapabilities(handle: number, client: azdata.DataProtocolClientCapabilities): Thenable<azdata.DataProtocolServerCapabilities> {
|
||||
return this._resolveProvider<azdata.CapabilitiesProvider>(handle).getServerCapabilities(client);
|
||||
@@ -750,4 +756,13 @@ export class ExtHostDataProtocol extends ExtHostDataProtocolShape {
|
||||
public $onJobDataUpdated(handle: Number): void {
|
||||
this._proxy.$onJobDataUpdated(handle);
|
||||
}
|
||||
|
||||
// Serialization methods
|
||||
public $startSerialization(handle: number, requestParams: azdata.SerializeDataStartRequestParams): Thenable<azdata.SerializeDataResult> {
|
||||
return this._resolveProvider<azdata.SerializationProvider>(handle).startSerialization(requestParams);
|
||||
}
|
||||
|
||||
public $continueSerialization(handle: number, requestParams: azdata.SerializeDataContinueRequestParams): Thenable<azdata.SerializeDataResult> {
|
||||
return this._resolveProvider<azdata.SerializationProvider>(handle).continueSerialization(requestParams);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,71 +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 { IMainContext } from 'vs/workbench/api/common/extHost.protocol';
|
||||
import { SqlMainContext, MainThreadSerializationProviderShape, ExtHostSerializationProviderShape } from 'sql/workbench/api/common/sqlExtHost.protocol';
|
||||
import * as vscode from 'vscode';
|
||||
import * as azdata from 'azdata';
|
||||
import { Disposable } from 'vs/workbench/api/common/extHostTypes';
|
||||
|
||||
class SerializationAdapter {
|
||||
private _provider: azdata.SerializationProvider;
|
||||
|
||||
constructor(provider: azdata.SerializationProvider) {
|
||||
this._provider = provider;
|
||||
}
|
||||
|
||||
public saveAs(saveFormat: string, savePath: string, results: string, appendToFile: boolean): Thenable<azdata.SaveResultRequestResult> {
|
||||
return this._provider.saveAs(saveFormat, savePath, results, appendToFile);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
type Adapter = SerializationAdapter;
|
||||
|
||||
export class ExtHostSerializationProvider extends ExtHostSerializationProviderShape {
|
||||
|
||||
private _proxy: MainThreadSerializationProviderShape;
|
||||
|
||||
private static _handlePool: number = 0;
|
||||
private _adapter: { [handle: number]: Adapter } = Object.create(null);
|
||||
|
||||
private _createDisposable(handle: number): Disposable {
|
||||
return new Disposable(() => {
|
||||
delete this._adapter[handle];
|
||||
this._proxy.$unregisterSerializationProvider(handle);
|
||||
});
|
||||
}
|
||||
|
||||
private _nextHandle(): number {
|
||||
return ExtHostSerializationProvider._handlePool++;
|
||||
}
|
||||
|
||||
private _withAdapter<A, R>(handle: number, ctor: { new(...args: any[]): A }, callback: (adapter: A) => Thenable<R>): Thenable<R> {
|
||||
let adapter = this._adapter[handle];
|
||||
if (!(adapter instanceof ctor)) {
|
||||
return Promise.reject(new Error('no adapter found'));
|
||||
}
|
||||
return callback(<any>adapter);
|
||||
}
|
||||
|
||||
constructor(
|
||||
mainContext: IMainContext
|
||||
) {
|
||||
super();
|
||||
this._proxy = mainContext.getProxy(SqlMainContext.MainThreadSerializationProvider);
|
||||
}
|
||||
|
||||
public $registerSerializationProvider(provider: azdata.SerializationProvider): vscode.Disposable {
|
||||
provider.handle = this._nextHandle();
|
||||
this._adapter[provider.handle] = new SerializationAdapter(provider);
|
||||
this._proxy.$registerSerializationProvider(provider.handle);
|
||||
return this._createDisposable(provider.handle);
|
||||
}
|
||||
|
||||
public $saveAs(saveFormat: string, savePath: string, results: string, appendToFile: boolean): Thenable<azdata.SaveResultRequestResult> {
|
||||
return this._withAdapter(0, SerializationAdapter, adapter => adapter.saveAs(saveFormat, savePath, results, appendToFile));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -504,6 +504,15 @@ export abstract class ExtHostDataProtocolShape {
|
||||
*/
|
||||
$schemaCompareCancel(handle: number, operationId: string): Thenable<azdata.ResultStatus> { throw ni(); }
|
||||
|
||||
/**
|
||||
* Serialization start request
|
||||
*/
|
||||
$startSerialization(handle: number, requestParams: azdata.SerializeDataStartRequestParams): Thenable<azdata.SerializeDataResult> { throw ni(); }
|
||||
|
||||
/**
|
||||
* Serialization continuation request
|
||||
*/
|
||||
$continueSerialization(handle: number, requestParams: azdata.SerializeDataContinueRequestParams): Thenable<azdata.SerializeDataResult> { throw ni(); }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -533,13 +542,6 @@ export abstract class ExtHostCredentialManagementShape {
|
||||
$deleteCredential(credentialId: string): Thenable<boolean> { throw ni(); }
|
||||
}
|
||||
|
||||
/**
|
||||
* Serialization provider extension host class.
|
||||
*/
|
||||
export abstract class ExtHostSerializationProviderShape {
|
||||
$saveAs(saveFormat: string, savePath: string, results: string, appendToFile: boolean): Thenable<azdata.SaveResultRequestResult> { throw ni(); }
|
||||
}
|
||||
|
||||
export interface MainThreadAccountManagementShape extends IDisposable {
|
||||
$registerAccountProvider(providerMetadata: azdata.AccountProviderMetadata, handle: number): Thenable<any>;
|
||||
$unregisterAccountProvider(handle: number): Thenable<any>;
|
||||
@@ -575,6 +577,7 @@ export interface MainThreadDataProtocolShape extends IDisposable {
|
||||
$registerAgentServicesProvider(providerId: string, handle: number): Promise<any>;
|
||||
$registerDacFxServicesProvider(providerId: string, handle: number): Promise<any>;
|
||||
$registerSchemaCompareServicesProvider(providerId: string, handle: number): Promise<any>;
|
||||
$registerSerializationProvider(providerId: string, handle: number): Promise<any>;
|
||||
$unregisterProvider(handle: number): Promise<any>;
|
||||
$onConnectionComplete(handle: number, connectionInfoSummary: azdata.ConnectionInfoSummary): void;
|
||||
$onIntelliSenseCacheComplete(handle: number, connectionUri: string): void;
|
||||
@@ -625,11 +628,6 @@ export interface MainThreadCredentialManagementShape extends IDisposable {
|
||||
$unregisterCredentialProvider(handle: number): Promise<any>;
|
||||
}
|
||||
|
||||
export interface MainThreadSerializationProviderShape extends IDisposable {
|
||||
$registerSerializationProvider(handle: number): Promise<any>;
|
||||
$unregisterSerializationProvider(handle: number): Promise<any>;
|
||||
}
|
||||
|
||||
function ni() { return new Error('Not implemented'); }
|
||||
|
||||
// --- proxy identifiers
|
||||
@@ -642,7 +640,6 @@ export const SqlMainContext = {
|
||||
MainThreadDataProtocol: createMainId<MainThreadDataProtocolShape>('MainThreadDataProtocol'),
|
||||
MainThreadObjectExplorer: createMainId<MainThreadObjectExplorerShape>('MainThreadObjectExplorer'),
|
||||
MainThreadBackgroundTaskManagement: createMainId<MainThreadBackgroundTaskManagementShape>('MainThreadBackgroundTaskManagement'),
|
||||
MainThreadSerializationProvider: createMainId<MainThreadSerializationProviderShape>('MainThreadSerializationProvider'),
|
||||
MainThreadResourceProvider: createMainId<MainThreadResourceProviderShape>('MainThreadResourceProvider'),
|
||||
MainThreadModalDialog: createMainId<MainThreadModalDialogShape>('MainThreadModalDialog'),
|
||||
MainThreadTasks: createMainId<MainThreadTasksShape>('MainThreadTasks'),
|
||||
@@ -662,7 +659,6 @@ export const SqlExtHostContext = {
|
||||
ExtHostCredentialManagement: createExtId<ExtHostCredentialManagementShape>('ExtHostCredentialManagement'),
|
||||
ExtHostDataProtocol: createExtId<ExtHostDataProtocolShape>('ExtHostDataProtocol'),
|
||||
ExtHostObjectExplorer: createExtId<ExtHostObjectExplorerShape>('ExtHostObjectExplorer'),
|
||||
ExtHostSerializationProvider: createExtId<ExtHostSerializationProviderShape>('ExtHostSerializationProvider'),
|
||||
ExtHostResourceProvider: createExtId<ExtHostResourceProviderShape>('ExtHostResourceProvider'),
|
||||
ExtHostModalDialogs: createExtId<ExtHostModalDialogsShape>('ExtHostModalDialogs'),
|
||||
ExtHostTasks: createExtId<ExtHostTasksShape>('ExtHostTasks'),
|
||||
|
||||
@@ -328,7 +328,8 @@ export enum DataProviderType {
|
||||
DacFxServicesProvider = 'DacFxServicesProvider',
|
||||
SchemaCompareServicesProvider = 'SchemaCompareServicesProvider',
|
||||
ObjectExplorerNodeProvider = 'ObjectExplorerNodeProvider',
|
||||
IconProvider = 'IconProvider'
|
||||
IconProvider = 'IconProvider',
|
||||
SerializationProvider = 'SerializationProvider'
|
||||
}
|
||||
|
||||
export enum DeclarativeDataType {
|
||||
@@ -686,4 +687,4 @@ export enum NotebookChangeKind {
|
||||
MetadataUpdated = 1,
|
||||
Save = 2,
|
||||
CellExecuted = 3
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,7 +9,6 @@ import 'sql/workbench/api/browser/mainThreadCredentialManagement';
|
||||
import 'sql/workbench/api/browser/mainThreadDataProtocol';
|
||||
import 'sql/workbench/api/browser/mainThreadObjectExplorer';
|
||||
import 'sql/workbench/api/browser/mainThreadBackgroundTaskManagement';
|
||||
import 'sql/workbench/api/browser/mainThreadSerializationProvider';
|
||||
import 'sql/workbench/api/browser/mainThreadResourceProvider';
|
||||
import 'sql/workbench/api/browser/mainThreadTasks';
|
||||
import 'sql/workbench/api/browser/mainThreadDashboard';
|
||||
|
||||
@@ -15,7 +15,6 @@ import { SqlExtHostContext } from 'sql/workbench/api/common/sqlExtHost.protocol'
|
||||
import { ExtHostAccountManagement } from 'sql/workbench/api/common/extHostAccountManagement';
|
||||
import { ExtHostCredentialManagement } from 'sql/workbench/api/common/extHostCredentialManagement';
|
||||
import { ExtHostDataProtocol } from 'sql/workbench/api/common/extHostDataProtocol';
|
||||
import { ExtHostSerializationProvider } from 'sql/workbench/api/common/extHostSerializationProvider';
|
||||
import { ExtHostResourceProvider } from 'sql/workbench/api/common/extHostResourceProvider';
|
||||
import * as sqlExtHostTypes from 'sql/workbench/api/common/sqlExtHostTypes';
|
||||
import { ExtHostModalDialogs } from 'sql/workbench/api/common/extHostModalDialog';
|
||||
@@ -71,7 +70,6 @@ export function createApiFactory(
|
||||
const extHostCredentialManagement = rpcProtocol.set(SqlExtHostContext.ExtHostCredentialManagement, new ExtHostCredentialManagement(rpcProtocol));
|
||||
const extHostDataProvider = rpcProtocol.set(SqlExtHostContext.ExtHostDataProtocol, new ExtHostDataProtocol(rpcProtocol, uriTransformer));
|
||||
const extHostObjectExplorer = rpcProtocol.set(SqlExtHostContext.ExtHostObjectExplorer, new ExtHostObjectExplorer(rpcProtocol));
|
||||
const extHostSerializationProvider = rpcProtocol.set(SqlExtHostContext.ExtHostSerializationProvider, new ExtHostSerializationProvider(rpcProtocol));
|
||||
const extHostResourceProvider = rpcProtocol.set(SqlExtHostContext.ExtHostResourceProvider, new ExtHostResourceProvider(rpcProtocol));
|
||||
const extHostModalDialogs = rpcProtocol.set(SqlExtHostContext.ExtHostModalDialogs, new ExtHostModalDialogs(rpcProtocol));
|
||||
const extHostTasks = rpcProtocol.set(SqlExtHostContext.ExtHostTasks, new ExtHostTasks(rpcProtocol, logService));
|
||||
@@ -188,14 +186,7 @@ export function createApiFactory(
|
||||
}
|
||||
};
|
||||
|
||||
// namespace: serialization
|
||||
const serialization: typeof azdata.serialization = {
|
||||
registerProvider(provider: azdata.SerializationProvider): vscode.Disposable {
|
||||
return extHostSerializationProvider.$registerSerializationProvider(provider);
|
||||
},
|
||||
};
|
||||
|
||||
// namespace: serialization
|
||||
// namespace: resources
|
||||
const resources: typeof azdata.resources = {
|
||||
registerResourceProvider(providerMetadata: azdata.ResourceProviderMetadata, provider: azdata.ResourceProvider): vscode.Disposable {
|
||||
return extHostResourceProvider.$registerResourceProvider(providerMetadata, provider);
|
||||
@@ -369,6 +360,10 @@ export function createApiFactory(
|
||||
return extHostDataProvider.$registerSchemaCompareServiceProvider(provider);
|
||||
};
|
||||
|
||||
let registerSerializationProvider = (provider: azdata.SerializationProvider): vscode.Disposable => {
|
||||
return extHostDataProvider.$registerSerializationProvider(provider);
|
||||
};
|
||||
|
||||
// namespace: dataprotocol
|
||||
const dataprotocol: typeof azdata.dataprotocol = {
|
||||
registerBackupProvider,
|
||||
@@ -388,6 +383,7 @@ export function createApiFactory(
|
||||
registerCapabilitiesServiceProvider,
|
||||
registerDacFxServicesProvider,
|
||||
registerSchemaCompareServicesProvider,
|
||||
registerSerializationProvider,
|
||||
onDidChangeLanguageFlavor(listener: (e: azdata.DidChangeLanguageFlavorParams) => any, thisArgs?: any, disposables?: extHostTypes.Disposable[]) {
|
||||
return extHostDataProvider.onDidChangeLanguageFlavor(listener, thisArgs, disposables);
|
||||
},
|
||||
@@ -516,7 +512,6 @@ export function createApiFactory(
|
||||
credentials,
|
||||
objectexplorer: objectExplorer,
|
||||
resources,
|
||||
serialization,
|
||||
dataprotocol,
|
||||
DataProviderType: sqlExtHostTypes.DataProviderType,
|
||||
DeclarativeDataType: sqlExtHostTypes.DeclarativeDataType,
|
||||
@@ -630,7 +625,9 @@ export function createApiFactory(
|
||||
// namespace: serialization
|
||||
const serialization: typeof sqlops.serialization = {
|
||||
registerProvider(provider: sqlops.SerializationProvider): vscode.Disposable {
|
||||
return extHostSerializationProvider.$registerSerializationProvider(provider);
|
||||
// No-op this to avoid breaks in existing applications. Tested on Github - no examples,
|
||||
// but I think it's safer to avoid breaking this
|
||||
return undefined;
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user