Strict null on some query and connection (#7300)

* wip

* make connection work with strict-nulls

* change comments

* fix tests; remove unneeded type forcing

* address feedback

* adjust the logic of query editor

* clean up typing
This commit is contained in:
Anthony Dresser
2019-10-21 15:50:12 -07:00
committed by GitHub
parent 6a375fdd8c
commit 06e86e57e7
22 changed files with 367 additions and 369 deletions

View File

@@ -97,71 +97,71 @@ export class MainThreadDataProtocol extends Disposable implements MainThreadData
public $registerQueryProvider(providerId: string, handle: number): Promise<any> {
const self = this;
this._queryManagementService.addQueryRequestHandler(providerId, {
cancelQuery(ownerUri: string): Thenable<azdata.QueryCancelResult> {
return self._proxy.$cancelQuery(handle, ownerUri);
cancelQuery(ownerUri: string): Promise<azdata.QueryCancelResult> {
return Promise.resolve(self._proxy.$cancelQuery(handle, ownerUri));
},
runQuery(ownerUri: string, selection: azdata.ISelectionData, runOptions?: azdata.ExecutionPlanOptions): Thenable<void> {
return self._proxy.$runQuery(handle, ownerUri, selection, runOptions);
runQuery(ownerUri: string, selection: azdata.ISelectionData, runOptions?: azdata.ExecutionPlanOptions): Promise<void> {
return Promise.resolve(self._proxy.$runQuery(handle, ownerUri, selection, runOptions));
},
runQueryStatement(ownerUri: string, line: number, column: number): Thenable<void> {
return self._proxy.$runQueryStatement(handle, ownerUri, line, column);
runQueryStatement(ownerUri: string, line: number, column: number): Promise<void> {
return Promise.resolve(self._proxy.$runQueryStatement(handle, ownerUri, line, column));
},
runQueryString(ownerUri: string, queryString: string): Thenable<void> {
return self._proxy.$runQueryString(handle, ownerUri, queryString);
runQueryString(ownerUri: string, queryString: string): Promise<void> {
return Promise.resolve(self._proxy.$runQueryString(handle, ownerUri, queryString));
},
runQueryAndReturn(ownerUri: string, queryString: string): Thenable<azdata.SimpleExecuteResult> {
return self._proxy.$runQueryAndReturn(handle, ownerUri, queryString);
runQueryAndReturn(ownerUri: string, queryString: string): Promise<azdata.SimpleExecuteResult> {
return Promise.resolve(self._proxy.$runQueryAndReturn(handle, ownerUri, queryString));
},
parseSyntax(ownerUri: string, query: string): Thenable<azdata.SyntaxParseResult> {
return self._proxy.$parseSyntax(handle, ownerUri, query);
parseSyntax(ownerUri: string, query: string): Promise<azdata.SyntaxParseResult> {
return Promise.resolve(self._proxy.$parseSyntax(handle, ownerUri, query));
},
getQueryRows(rowData: azdata.QueryExecuteSubsetParams): Thenable<azdata.QueryExecuteSubsetResult> {
return self._proxy.$getQueryRows(handle, rowData);
getQueryRows(rowData: azdata.QueryExecuteSubsetParams): Promise<azdata.QueryExecuteSubsetResult> {
return Promise.resolve(self._proxy.$getQueryRows(handle, rowData));
},
setQueryExecutionOptions(ownerUri: string, options: azdata.QueryExecutionOptions): Thenable<void> {
return self._proxy.$setQueryExecutionOptions(handle, ownerUri, options);
setQueryExecutionOptions(ownerUri: string, options: azdata.QueryExecutionOptions): Promise<void> {
return Promise.resolve(self._proxy.$setQueryExecutionOptions(handle, ownerUri, options));
},
disposeQuery(ownerUri: string): Thenable<void> {
return self._proxy.$disposeQuery(handle, ownerUri);
disposeQuery(ownerUri: string): Promise<void> {
return Promise.resolve(self._proxy.$disposeQuery(handle, ownerUri));
},
saveResults(requestParams: azdata.SaveResultsRequestParams): Thenable<azdata.SaveResultRequestResult> {
saveResults(requestParams: azdata.SaveResultsRequestParams): Promise<azdata.SaveResultRequestResult> {
let saveResultsFeatureInfo = self._serializationService.getSaveResultsFeatureMetadataProvider(requestParams.ownerUri);
if (saveResultsFeatureInfo && saveResultsFeatureInfo.enabled) {
return self._proxy.$saveResults(handle, requestParams);
return Promise.resolve(self._proxy.$saveResults(handle, requestParams));
}
else if (saveResultsFeatureInfo && !saveResultsFeatureInfo.enabled) {
return self._serializationService.disabledSaveAs();
return Promise.resolve(self._serializationService.disabledSaveAs());
}
else {
return self._serializationService.saveAs(requestParams.resultFormat, requestParams.filePath, undefined, true);
return Promise.resolve(self._serializationService.saveAs(requestParams.resultFormat, requestParams.filePath, undefined, true));
}
},
initializeEdit(ownerUri: string, schemaName: string, objectName: string, objectType: string, rowLimit: number, queryString: string): Thenable<void> {
return self._proxy.$initializeEdit(handle, ownerUri, schemaName, objectName, objectType, rowLimit, queryString);
initializeEdit(ownerUri: string, schemaName: string, objectName: string, objectType: string, rowLimit: number, queryString: string): Promise<void> {
return Promise.resolve(self._proxy.$initializeEdit(handle, ownerUri, schemaName, objectName, objectType, rowLimit, queryString));
},
updateCell(ownerUri: string, rowId: number, columnId: number, newValue: string): Thenable<azdata.EditUpdateCellResult> {
return self._proxy.$updateCell(handle, ownerUri, rowId, columnId, newValue);
updateCell(ownerUri: string, rowId: number, columnId: number, newValue: string): Promise<azdata.EditUpdateCellResult> {
return Promise.resolve(self._proxy.$updateCell(handle, ownerUri, rowId, columnId, newValue));
},
commitEdit(ownerUri): Thenable<void> {
return self._proxy.$commitEdit(handle, ownerUri);
commitEdit(ownerUri): Promise<void> {
return Promise.resolve(self._proxy.$commitEdit(handle, ownerUri));
},
createRow(ownerUri: string): Thenable<azdata.EditCreateRowResult> {
return self._proxy.$createRow(handle, ownerUri);
createRow(ownerUri: string): Promise<azdata.EditCreateRowResult> {
return Promise.resolve(self._proxy.$createRow(handle, ownerUri));
},
deleteRow(ownerUri: string, rowId: number): Thenable<void> {
return self._proxy.$deleteRow(handle, ownerUri, rowId);
deleteRow(ownerUri: string, rowId: number): Promise<void> {
return Promise.resolve(self._proxy.$deleteRow(handle, ownerUri, rowId));
},
disposeEdit(ownerUri: string): Thenable<void> {
return self._proxy.$disposeEdit(handle, ownerUri);
disposeEdit(ownerUri: string): Promise<void> {
return Promise.resolve(self._proxy.$disposeEdit(handle, ownerUri));
},
revertCell(ownerUri: string, rowId: number, columnId: number): Thenable<azdata.EditRevertCellResult> {
return self._proxy.$revertCell(handle, ownerUri, rowId, columnId);
revertCell(ownerUri: string, rowId: number, columnId: number): Promise<azdata.EditRevertCellResult> {
return Promise.resolve(self._proxy.$revertCell(handle, ownerUri, rowId, columnId));
},
revertRow(ownerUri: string, rowId: number): Thenable<void> {
return self._proxy.$revertRow(handle, ownerUri, rowId);
revertRow(ownerUri: string, rowId: number): Promise<void> {
return Promise.resolve(self._proxy.$revertRow(handle, ownerUri, rowId));
},
getEditRows(rowData: azdata.EditSubsetParams): Thenable<azdata.EditSubsetResult> {
return self._proxy.$getEditRows(handle, rowData);
getEditRows(rowData: azdata.EditSubsetParams): Promise<azdata.EditSubsetResult> {
return Promise.resolve(self._proxy.$getEditRows(handle, rowData));
}
});

View File

@@ -207,31 +207,29 @@ export class EditDataComponent extends GridParentComponent implements OnInit, On
// Setup a function for generating a promise to lookup result subsets
this.loadDataFunction = (offset: number, count: number): Promise<{}[]> => {
return new Promise<{}[]>((resolve, reject) => {
self.dataService.getEditRows(offset, count).subscribe(result => {
let gridData = result.subset.map(r => {
let dataWithSchema = {};
// skip the first column since its a number column
for (let i = 1; i < this.dataSet.columnDefinitions.length; i++) {
dataWithSchema[this.dataSet.columnDefinitions[i].field] = {
displayValue: r.cells[i - 1].displayValue,
ariaLabel: escape(r.cells[i - 1].displayValue),
isNull: r.cells[i - 1].isNull
};
}
return dataWithSchema;
});
// should add null row?
if (offset + count > this.dataSet.totalRows - 1) {
gridData.push(this.dataSet.columnDefinitions.reduce((p, c) => {
p[c.field] = 'NULL';
return p;
}, {}));
return self.dataService.getEditRows(offset, count).then(result => {
let gridData = result.subset.map(r => {
let dataWithSchema = {};
// skip the first column since its a number column
for (let i = 1; i < this.dataSet.columnDefinitions.length; i++) {
dataWithSchema[this.dataSet.columnDefinitions[i].field] = {
displayValue: r.cells[i - 1].displayValue,
ariaLabel: escape(r.cells[i - 1].displayValue),
isNull: r.cells[i - 1].isNull
};
}
resolve(gridData);
return dataWithSchema;
});
// should add null row?
if (offset + count > this.dataSet.totalRows - 1) {
gridData.push(this.dataSet.columnDefinitions.reduce((p, c) => {
p[c.field] = 'NULL';
return p;
}, {}));
}
return gridData;
});
};
}

View File

@@ -40,13 +40,8 @@ export class DataService {
* @param rowStart The row to start retrieving from (inclusive)
* @param numberOfRows The maximum number of rows to return
*/
getEditRows(rowStart: number, numberOfRows: number): Observable<EditSubsetResult> {
const self = this;
return Observable.create(function (observer: Observer<EditSubsetResult>) {
self._queryModel.getEditRows(self._uri, rowStart, numberOfRows).then(results => {
observer.next(results);
});
});
getEditRows(rowStart: number, numberOfRows: number): Promise<EditSubsetResult | undefined> {
return this._queryModel.getEditRows(this._uri, rowStart, numberOfRows);
}
updateCell(rowId: number, columnId: number, newValue: string): Thenable<EditUpdateCellResult> {

View File

@@ -30,7 +30,7 @@ export class GridTableState extends Disposable {
/* The top row of the current scroll */
public scrollPositionY = 0;
public scrollPositionX = 0;
public columnSizes: number[] = undefined;
public columnSizes?: number[] = undefined;
public selection: Slick.Range[];
public activeCell: Slick.Cell;

View File

@@ -276,12 +276,12 @@ export class QueryInput extends EditorInput implements IEncodingSupport, IConnec
}
// State update funtions
public runQuery(selection: ISelectionData, executePlanOptions?: ExecutionPlanOptions): void {
public runQuery(selection?: ISelectionData, executePlanOptions?: ExecutionPlanOptions): void {
this._queryModelService.runQuery(this.uri, selection, this, executePlanOptions);
this.state.executing = true;
}
public runQueryStatement(selection: ISelectionData): void {
public runQueryStatement(selection?: ISelectionData): void {
this._queryModelService.runQueryStatement(this.uri, selection, this);
this.state.executing = true;
}
@@ -316,7 +316,7 @@ export class QueryInput extends EditorInput implements IEncodingSupport, IConnec
let isRunningQuery = this._queryModelService.isRunningQuery(this.uri);
if (!isRunningQuery && params && params.runQueryOnCompletion) {
let selection: ISelectionData = params ? params.querySelection : undefined;
let selection: ISelectionData | undefined = params ? params.querySelection : undefined;
if (params.runQueryOnCompletion === RunQueryOnConnectionMode.executeCurrentQuery) {
this.runQueryStatement(selection);
} else if (params.runQueryOnCompletion === RunQueryOnConnectionMode.executeQuery) {
@@ -361,6 +361,6 @@ export class QueryInput extends EditorInput implements IEncodingSupport, IConnec
}
public get isSharedSession(): boolean {
return this.uri && this.uri.startsWith('vsls:');
return !!(this.uri && this.uri.startsWith('vsls:'));
}
}

View File

@@ -42,9 +42,9 @@ export class ResultsViewState {
*/
export class QueryResultsInput extends EditorInput {
private _state = new ResultsViewState();
private _state?= new ResultsViewState();
public get state(): ResultsViewState {
public get state(): ResultsViewState | undefined {
return this._state;
}
@@ -53,7 +53,7 @@ export class QueryResultsInput extends EditorInput {
}
close() {
this.state.dispose();
this.state!.dispose();
this._state = undefined;
super.close();
}

View File

@@ -67,12 +67,12 @@ export class ResultSerializer {
/**
* Handle save request by getting filename from user and sending request to service
*/
public saveResults(uri: string, saveRequest: ISaveRequest): Thenable<void> {
public saveResults(uri: string, saveRequest: ISaveRequest): Promise<void> {
const self = this;
return this.promptForFilepath(saveRequest.format, uri).then(filePath => {
if (filePath) {
if (!path.isAbsolute(filePath)) {
filePath = resolveFilePath(uri, filePath, this.rootPath);
filePath = resolveFilePath(uri, filePath, this.rootPath)!;
}
let saveResultsParams = this.getParameters(uri, filePath, saveRequest.batchIndex, saveRequest.resultSetNumber, saveRequest.format, saveRequest.selection ? saveRequest.selection[0] : undefined);
let sendRequest = () => this.sendSaveRequestToService(saveResultsParams);
@@ -98,9 +98,9 @@ export class ResultSerializer {
return this.promptForFilepath(format, uri).then(filePath => {
if (filePath) {
if (!path.isAbsolute(filePath)) {
filePath = resolveFilePath(uri, filePath, this.rootPath);
filePath = resolveFilePath(uri, filePath, this.rootPath)!;
}
return self.doSave(filePath, format, () => sendRequest(filePath));
return self.doSave(filePath, format, () => sendRequest(filePath!));
}
return Promise.resolve();
});
@@ -117,10 +117,10 @@ export class ResultSerializer {
private get outputChannel(): IOutputChannel {
this.ensureOutputChannelExists();
return this._outputService.getChannel(ConnectionConstants.outputChannelName);
return this._outputService.getChannel(ConnectionConstants.outputChannelName)!;
}
private get rootPath(): string {
private get rootPath(): string | undefined {
return getRootPath(this._contextService);
}
@@ -129,7 +129,7 @@ export class ResultSerializer {
}
private promptForFilepath(format: SaveFormat, resourceUri: string): Thenable<string | undefined> {
private promptForFilepath(format: SaveFormat, resourceUri: string): Promise<string | undefined> {
let filepathPlaceHolder = prevSavePath ? path.dirname(prevSavePath) : resolveCurrentDirectory(resourceUri, this.rootPath);
if (filepathPlaceHolder) {
filepathPlaceHolder = path.join(filepathPlaceHolder, this.getResultsDefaultFilename(format));
@@ -171,7 +171,7 @@ export class ResultSerializer {
private getResultsFileExtension(format: SaveFormat): FileFilter[] {
let fileFilters = new Array<FileFilter>();
let fileFilter: { extensions: string[]; name: string } = { extensions: undefined, name: undefined };
let fileFilter: { extensions: string[]; name: string } = Object.create(null);
switch (format) {
case SaveFormat.CSV:
@@ -211,7 +211,7 @@ export class ResultSerializer {
} else if (format === SaveFormat.XML) {
saveResultsParams = this.getConfigForXml();
}
return saveResultsParams;
return saveResultsParams!; // this could be unsafe
}
@@ -280,7 +280,7 @@ export class ResultSerializer {
}
private getParameters(uri: string, filePath: string, batchIndex: number, resultSetNo: number, format: string, selection: Slick.Range): SaveResultsRequestParams {
private getParameters(uri: string, filePath: string, batchIndex: number, resultSetNo: number, format: string, selection?: Slick.Range): SaveResultsRequestParams {
let saveResultsParams = this.getBasicSaveParameters(format);
saveResultsParams.filePath = filePath;
saveResultsParams.ownerUri = uri;
@@ -298,8 +298,8 @@ export class ResultSerializer {
/**
* Check if a range of cells were selected.
*/
private isSelected(selection: Slick.Range): boolean {
return (selection && !((selection.fromCell === selection.toCell) && (selection.fromRow === selection.toRow)));
private isSelected(selection?: Slick.Range): selection is Slick.Range {
return !!(selection && !((selection.fromCell === selection.toCell) && (selection.fromRow === selection.toRow)));
}