mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-01-19 17:22:48 -05:00
More layering and compile strictness (#8973)
* add more folders to strictire compile, add more strict compile options * update ci * wip * add more layering and fix issues * add more strictness * remove unnecessary assertion * add missing checks * fix indentation * remove jsdoc
This commit is contained in:
141
src/sql/workbench/services/query/common/gridDataProvider.ts
Normal file
141
src/sql/workbench/services/query/common/gridDataProvider.ts
Normal file
@@ -0,0 +1,141 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* 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 types from 'vs/base/common/types';
|
||||
import { SaveFormat } from 'sql/workbench/contrib/grid/common/interfaces';
|
||||
|
||||
export interface IGridDataProvider {
|
||||
|
||||
/**
|
||||
* Gets N rows of data
|
||||
* @param rowStart 0-indexed start row to retrieve data from
|
||||
* @param numberOfRows total number of rows of data to retrieve
|
||||
*/
|
||||
getRowData(rowStart: number, numberOfRows: number): Thenable<azdata.QueryExecuteSubsetResult>;
|
||||
|
||||
/**
|
||||
* Sends a copy request to copy data to the clipboard
|
||||
* @param selection The selection range to copy
|
||||
* @param batchId The batch id of the result to copy from
|
||||
* @param resultId The result id of the result to copy from
|
||||
* @param includeHeaders [Optional]: Should column headers be included in the copy selection
|
||||
*/
|
||||
copyResults(selection: Slick.Range[], includeHeaders?: boolean): Promise<void>;
|
||||
|
||||
/**
|
||||
* Gets the EOL terminator to use for this data type.
|
||||
*/
|
||||
getEolString(): string;
|
||||
|
||||
shouldIncludeHeaders(includeHeaders: boolean): boolean;
|
||||
|
||||
shouldRemoveNewLines(): boolean;
|
||||
|
||||
getColumnHeaders(range: Slick.Range): string[] | undefined;
|
||||
|
||||
readonly canSerialize: boolean;
|
||||
|
||||
serializeResults(format: SaveFormat, selection: Slick.Range[]): Thenable<void>;
|
||||
|
||||
}
|
||||
|
||||
export async function getResultsString(provider: IGridDataProvider, selection: Slick.Range[], includeHeaders?: boolean): Promise<string> {
|
||||
let headers: Map<number, string> = new Map(); // Maps a column index -> header
|
||||
let rows: Map<number, Map<number, string>> = new Map(); // Maps row index -> column index -> actual row value
|
||||
const eol = provider.getEolString();
|
||||
|
||||
// create a mapping of the ranges to get promises
|
||||
let tasks: (() => Promise<void>)[] = selection.map((range) => {
|
||||
return async (): Promise<void> => {
|
||||
let startCol = range.fromCell;
|
||||
let startRow = range.fromRow;
|
||||
|
||||
const result = await provider.getRowData(range.fromRow, range.toRow - range.fromRow + 1);
|
||||
// If there was a previous selection separate it with a line break. Currently
|
||||
// when there are multiple selections they are never on the same line
|
||||
let columnHeaders = provider.getColumnHeaders(range);
|
||||
if (columnHeaders !== undefined) {
|
||||
let idx = 0;
|
||||
for (let header of columnHeaders) {
|
||||
headers.set(startCol + idx, header);
|
||||
idx++;
|
||||
}
|
||||
}
|
||||
// Iterate over the rows to paste into the copy string
|
||||
for (let rowIndex: number = 0; rowIndex < result.resultSubset.rows.length; rowIndex++) {
|
||||
let row = result.resultSubset.rows[rowIndex];
|
||||
let cellObjects = row.slice(range.fromCell, (range.toCell + 1));
|
||||
// Remove newlines if requested
|
||||
let cells = provider.shouldRemoveNewLines()
|
||||
? cellObjects.map(x => removeNewLines(x.displayValue))
|
||||
: cellObjects.map(x => x.displayValue);
|
||||
|
||||
let idx = 0;
|
||||
for (let cell of cells) {
|
||||
let map = rows.get(rowIndex + startRow);
|
||||
if (!map) {
|
||||
map = new Map();
|
||||
rows.set(rowIndex + startRow, map);
|
||||
}
|
||||
|
||||
map.set(startCol + idx, cell);
|
||||
idx++;
|
||||
}
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
// Set the tasks gathered above to execute
|
||||
let actionedTasks: Promise<void>[] = tasks.map(t => { return t(); });
|
||||
|
||||
// Make sure all these tasks have executed
|
||||
await Promise.all(actionedTasks);
|
||||
|
||||
const sortResults = (e1: [number, any], e2: [number, any]) => {
|
||||
return e1[0] - e2[0];
|
||||
};
|
||||
headers = new Map([...headers].sort(sortResults));
|
||||
rows = new Map([...rows].sort(sortResults));
|
||||
|
||||
let copyString = '';
|
||||
if (includeHeaders) {
|
||||
copyString = [...headers.values()].join('\t').concat(eol);
|
||||
}
|
||||
|
||||
const rowKeys = [...headers.keys()];
|
||||
for (let rowEntry of rows) {
|
||||
let rowMap = rowEntry[1];
|
||||
for (let rowIdx of rowKeys) {
|
||||
|
||||
let value = rowMap.get(rowIdx);
|
||||
if (value) {
|
||||
copyString = copyString.concat(value);
|
||||
}
|
||||
copyString = copyString.concat('\t');
|
||||
}
|
||||
// Removes the tab seperator from the end of a row
|
||||
copyString = copyString.slice(0, -1 * '\t'.length);
|
||||
copyString = copyString.concat(eol);
|
||||
}
|
||||
// Removes EoL from the end of the result
|
||||
copyString = copyString.slice(0, -1 * eol.length);
|
||||
|
||||
return copyString;
|
||||
}
|
||||
|
||||
|
||||
function removeNewLines(inputString: string): string {
|
||||
// This regex removes all newlines in all OS types
|
||||
// Windows(CRLF): \r\n
|
||||
// Linux(LF)/Modern MacOS: \n
|
||||
// Old MacOs: \r
|
||||
if (types.isUndefinedOrNull(inputString)) {
|
||||
return 'null';
|
||||
}
|
||||
|
||||
let outputString: string = inputString.replace(/(\r\n|\n|\r)/gm, '');
|
||||
return outputString;
|
||||
}
|
||||
Reference in New Issue
Block a user