mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-03-25 22:30:29 -04:00
Alanren/profiler filter (#3760)
* profiler filter * add test cases * perf improvement with bulk insert * update dependency version and address comments
This commit is contained in:
100
src/sqltest/base/browser/ui/table/tableDataView.test.ts
Normal file
100
src/sqltest/base/browser/ui/table/tableDataView.test.ts
Normal file
@@ -0,0 +1,100 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
'use strict';
|
||||
|
||||
import * as assert from 'assert';
|
||||
import { TableDataView } from 'sql/base/browser/ui/table/tableDataView';
|
||||
|
||||
suite('TableDataView Tests', () => {
|
||||
test('Data can be filtered and filter can be cleared', () => {
|
||||
const rowCount = 10;
|
||||
const columnCount = 5;
|
||||
const originalData = populateData(rowCount, columnCount);
|
||||
|
||||
let filteredRowCount = 5;
|
||||
const obj = new TableDataView(originalData, undefined, undefined, (data: any[]) => {
|
||||
return populateData(filteredRowCount, columnCount);
|
||||
});
|
||||
|
||||
let rowCountEventInvokeCount = 0;
|
||||
let filterStateChangeEventInvokeCount = 0;
|
||||
let rowCountEventParameter;
|
||||
obj.onRowCountChange((count) => {
|
||||
rowCountEventInvokeCount++;
|
||||
rowCountEventParameter = count;
|
||||
});
|
||||
|
||||
obj.onFilterStateChange(() => {
|
||||
filterStateChangeEventInvokeCount++;
|
||||
});
|
||||
|
||||
let verify = (expectedRowCountChangeInvokeCount: number,
|
||||
expectedDataLength: number,
|
||||
expectedNonFilteredDataLength: number,
|
||||
expectedFilterStateChangeInvokeCount: number,
|
||||
stepName: string,
|
||||
verifyRowCountEventParameter: boolean = true) => {
|
||||
assert.equal(rowCountEventInvokeCount, expectedRowCountChangeInvokeCount, 'RowCountChange event count - ' + stepName);
|
||||
if (verifyRowCountEventParameter) {
|
||||
assert.equal(rowCountEventParameter, expectedDataLength, 'Row count passed by RowCountChange event - ' + stepName);
|
||||
}
|
||||
assert.equal(obj.getLength(), expectedDataLength, 'Data length - ' + stepName);
|
||||
assert.equal(obj.getLengthNonFiltered(), expectedNonFilteredDataLength, 'Length for all data - ' + stepName);
|
||||
assert.equal(filterStateChangeEventInvokeCount, expectedFilterStateChangeInvokeCount, 'FilterStateChange event count - ' + stepName);
|
||||
};
|
||||
|
||||
verify(0, rowCount, rowCount, 0, 'after initialization', false);
|
||||
|
||||
obj.filter();
|
||||
|
||||
verify(0, filteredRowCount, rowCount, 1, 'after filtering', false);
|
||||
|
||||
const additionalRowCount = 20;
|
||||
const additionalData = populateData(additionalRowCount, columnCount);
|
||||
obj.push(additionalData);
|
||||
|
||||
verify(1, filteredRowCount * 2, rowCount + additionalRowCount, 1, 'after adding more data');
|
||||
|
||||
obj.clearFilter();
|
||||
|
||||
verify(1, rowCount + additionalRowCount, rowCount + additionalRowCount, 2, 'after clearing filter', false);
|
||||
|
||||
//From this point on, nothing matches the filter criteria
|
||||
filteredRowCount = 0;
|
||||
|
||||
obj.filter();
|
||||
verify(1, 0, rowCount + additionalRowCount, 3, 'after 2nd filtering', false);
|
||||
|
||||
obj.push(additionalData);
|
||||
verify(2, 0, rowCount + additionalRowCount + additionalRowCount, 3, 'after 2nd adding more data');
|
||||
|
||||
obj.clearFilter();
|
||||
verify(2, rowCount + additionalRowCount + additionalRowCount, rowCount + additionalRowCount + additionalRowCount, 4, 'after 2nd clearing filter', false);
|
||||
|
||||
obj.clearFilter();
|
||||
verify(2, rowCount + additionalRowCount + additionalRowCount, rowCount + additionalRowCount + additionalRowCount, 4, 'calling clearFilter() multiple times', false);
|
||||
});
|
||||
});
|
||||
|
||||
function populateData(row: number, column: number): any[] {
|
||||
let data = [];
|
||||
for (let i: number = 0; i < row; i++) {
|
||||
let row = {};
|
||||
for (let j: number = 0; j < column; j++) {
|
||||
row[getColumnName(j)] = getCellValue(i, j);
|
||||
}
|
||||
data.push(row);
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
function getColumnName(index: number): string {
|
||||
return `column${index}`;
|
||||
}
|
||||
|
||||
function getCellValue(row: number, column: number): string {
|
||||
return `row ${row} column ${column}`;
|
||||
}
|
||||
122
src/sqltest/parts/profiler/service/profilerFilter.test.ts
Normal file
122
src/sqltest/parts/profiler/service/profilerFilter.test.ts
Normal file
@@ -0,0 +1,122 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
'use strict';
|
||||
|
||||
import * as assert from 'assert';
|
||||
import { FilterData } from 'sql/parts/profiler/service/profilerFilter';
|
||||
import { ProfilerFilterClauseOperator, ProfilerFilter } from 'sql/parts/profiler/service/interfaces';
|
||||
|
||||
const property1 = 'property1';
|
||||
const property2 = 'property2';
|
||||
|
||||
suite('Profiler filter data tests', () => {
|
||||
test('number type filter data test', () => {
|
||||
let filter: ProfilerFilter = { clauses: [] };
|
||||
let entry1: TestData = { property1: '-1', property2: '0' };
|
||||
let entry2: TestData = { property1: '0', property2: '10' };
|
||||
let entry3: TestData = { property1: '10.0', property2: '-1' };
|
||||
|
||||
let data: TestData[] = [entry1, entry2, entry3];
|
||||
|
||||
filter.clauses = [{ field: property1, operator: ProfilerFilterClauseOperator.Equals, value: '10' }];
|
||||
filterAndVerify(filter, data, [entry3], 'Equals operator');
|
||||
|
||||
filter.clauses = [{ field: property1, operator: ProfilerFilterClauseOperator.NotEquals, value: '-1' }];
|
||||
filterAndVerify(filter, data, [entry2, entry3], 'NotEquals operator');
|
||||
|
||||
filter.clauses = [{ field: property1, operator: ProfilerFilterClauseOperator.GreaterThan, value: '2' }];
|
||||
filterAndVerify(filter, data, [entry3], 'GreaterThan operator');
|
||||
|
||||
filter.clauses = [{ field: property1, operator: ProfilerFilterClauseOperator.GreaterThanOrEquals, value: '0' }];
|
||||
filterAndVerify(filter, data, [entry2, entry3], 'GreaterThanOrEquals operator');
|
||||
|
||||
filter.clauses = [{ field: property1, operator: ProfilerFilterClauseOperator.LessThan, value: '0' }];
|
||||
filterAndVerify(filter, data, [entry1], 'LessThan operator');
|
||||
|
||||
filter.clauses = [{ field: property1, operator: ProfilerFilterClauseOperator.LessThanOrEquals, value: '0' }];
|
||||
filterAndVerify(filter, data, [entry1, entry2], 'LessThanOrEquals operator');
|
||||
|
||||
filter.clauses = [{ field: property1, operator: ProfilerFilterClauseOperator.LessThanOrEquals, value: '-2' }];
|
||||
filterAndVerify(filter, data, [], 'Empty result set');
|
||||
|
||||
filter.clauses = [{ field: property1, operator: ProfilerFilterClauseOperator.LessThanOrEquals, value: '10' }];
|
||||
filterAndVerify(filter, data, data, 'All matches');
|
||||
|
||||
filter.clauses = [{ field: property1, operator: ProfilerFilterClauseOperator.LessThanOrEquals, value: '0' },
|
||||
{ field: property2, operator: ProfilerFilterClauseOperator.LessThan, value: '10' }];
|
||||
filterAndVerify(filter, data, [entry1], 'Multiple clauses');
|
||||
});
|
||||
|
||||
test('date type filter data test', () => {
|
||||
let filter: ProfilerFilter = { clauses: [] };
|
||||
let entry1: TestData = { property1: '2019-01-02T19:00:00.000Z', property2: '' };
|
||||
let entry2: TestData = { property1: '2019-01-03T10:00:00.000Z', property2: '' };
|
||||
let entry3: TestData = { property1: '2019-01-04T10:00:00.000Z', property2: '' };
|
||||
|
||||
let data: TestData[] = [entry1, entry2, entry3];
|
||||
|
||||
filter.clauses = [{ field: property1, operator: ProfilerFilterClauseOperator.Equals, value: '2019-01-02T19:00:00Z' }];
|
||||
filterAndVerify(filter, data, [entry1], 'Equals operator');
|
||||
|
||||
filter.clauses = [{ field: property1, operator: ProfilerFilterClauseOperator.NotEquals, value: '2019-01-03T10:00:00Z' }];
|
||||
filterAndVerify(filter, data, [entry1, entry3], 'NotEquals operator');
|
||||
|
||||
filter.clauses = [{ field: property1, operator: ProfilerFilterClauseOperator.GreaterThan, value: '2019-01-01T00:00:00Z' }];
|
||||
filterAndVerify(filter, data, [entry1, entry2, entry3], 'GreaterThan operator');
|
||||
|
||||
filter.clauses = [{ field: property1, operator: ProfilerFilterClauseOperator.GreaterThanOrEquals, value: '2019-01-03T10:00:00.000Z' }];
|
||||
filterAndVerify(filter, data, [entry2, entry3], 'GreaterThanOrEquals operator');
|
||||
|
||||
filter.clauses = [{ field: property1, operator: ProfilerFilterClauseOperator.LessThan, value: '2019-01-03T10:00:00.000Z' }];
|
||||
filterAndVerify(filter, data, [entry1], 'LessThan operator');
|
||||
|
||||
filter.clauses = [{ field: property1, operator: ProfilerFilterClauseOperator.LessThanOrEquals, value: '2019-01-03T10:00:00Z' }];
|
||||
filterAndVerify(filter, data, [entry1, entry2], 'LessThanOrEquals operator');
|
||||
});
|
||||
|
||||
test('string type filter data test', () => {
|
||||
let filter: ProfilerFilter = { clauses: [] };
|
||||
let entry1: TestData = { property1: '', property2: '' };
|
||||
let entry2: TestData = { property1: 'test string', property2: '' };
|
||||
let entry3: TestData = { property1: 'new string', property2: '' };
|
||||
|
||||
let data: TestData[] = [entry1, entry2, entry3];
|
||||
|
||||
filter.clauses = [{ field: property1, operator: ProfilerFilterClauseOperator.IsNull, value: '' }];
|
||||
filterAndVerify(filter, data, [entry1], 'IsNull operator');
|
||||
|
||||
filter.clauses = [{ field: property1, operator: ProfilerFilterClauseOperator.IsNotNull, value: '' }];
|
||||
filterAndVerify(filter, data, [entry2, entry3], 'IsNotNull operator');
|
||||
|
||||
filter.clauses = [{ field: property1, operator: ProfilerFilterClauseOperator.Contains, value: 'sTRing' }];
|
||||
filterAndVerify(filter, data, [entry2, entry3], 'Contains operator');
|
||||
|
||||
filter.clauses = [{ field: property1, operator: ProfilerFilterClauseOperator.NotContains, value: 'string' }];
|
||||
filterAndVerify(filter, data, [entry1], 'NotContains operator');
|
||||
|
||||
filter.clauses = [{ field: property1, operator: ProfilerFilterClauseOperator.StartsWith, value: 'tEst' }];
|
||||
filterAndVerify(filter, data, [entry2], 'StartsWith operator');
|
||||
|
||||
filter.clauses = [{ field: property1, operator: ProfilerFilterClauseOperator.NotStartsWith, value: 'Test' }];
|
||||
filterAndVerify(filter, data, [entry1, entry3], 'NotStartsWith operator');
|
||||
});
|
||||
});
|
||||
|
||||
function filterAndVerify(filter: ProfilerFilter, data: TestData[], expectedResult: TestData[], stepName: string) {
|
||||
let actualResult = FilterData(filter, data);
|
||||
assert.equal(actualResult.length, expectedResult.length, `length check for ${stepName}`);
|
||||
for (let i = 0; i < actualResult.length; i++) {
|
||||
let actual = actualResult[i];
|
||||
let expected = expectedResult[i];
|
||||
assert(actual.property1 === expected.property1 && actual.property2 === expected.property2, `array content check for ${stepName}`);
|
||||
}
|
||||
}
|
||||
|
||||
interface TestData {
|
||||
property1: string;
|
||||
property2: string;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user