Merge pull request #28 from Microsoft/add_support_for_basic_filter_with_values_as_array_of_tuples
Add support for basic filter with values as array of tuples
This commit is contained in:
Коммит
0de0170131
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "powerbi-models",
|
"name": "powerbi-models",
|
||||||
"version": "0.10.2",
|
"version": "0.10.3",
|
||||||
"description": "Contains JavaScript & TypeScript object models for Microsoft Power BI JavaScript SDK. For each model there is a TypeScript interface, a json schema definitions, and a validation function to ensure and object is valid.",
|
"description": "Contains JavaScript & TypeScript object models for Microsoft Power BI JavaScript SDK. For each model there is a TypeScript interface, a json schema definitions, and a validation function to ensure and object is valid.",
|
||||||
"main": "dist/models.js",
|
"main": "dist/models.js",
|
||||||
"typings": "dist/models.d.ts",
|
"typings": "dist/models.d.ts",
|
||||||
|
|
|
@ -126,6 +126,10 @@ export interface IFilterColumnTarget extends IBaseFilterTarget {
|
||||||
column: string;
|
column: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface IFilterKeyColumnsTarget extends IFilterColumnTarget {
|
||||||
|
keys: string[];
|
||||||
|
}
|
||||||
|
|
||||||
export interface IFilterHierarchyTarget extends IBaseFilterTarget {
|
export interface IFilterHierarchyTarget extends IBaseFilterTarget {
|
||||||
hierarchy: string;
|
hierarchy: string;
|
||||||
hierarchyLevel: string;
|
hierarchyLevel: string;
|
||||||
|
@ -147,6 +151,11 @@ export interface IBasicFilter extends IFilter {
|
||||||
values: (string | number | boolean)[];
|
values: (string | number | boolean)[];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface IBasicFilterWithKeys extends IBasicFilter {
|
||||||
|
target: IFilterKeyColumnsTarget;
|
||||||
|
keyValues: (string | number | boolean)[][];
|
||||||
|
}
|
||||||
|
|
||||||
export type BasicFilterOperators = "In" | "NotIn" | "All";
|
export type BasicFilterOperators = "In" | "NotIn" | "All";
|
||||||
export type AdvancedFilterLogicalOperators = "And" | "Or";
|
export type AdvancedFilterLogicalOperators = "And" | "Or";
|
||||||
export type AdvancedFilterConditionOperators = "None" | "LessThan" | "LessThanOrEqual" | "GreaterThan" | "GreaterThanOrEqual" | "Contains" | "DoesNotContain" | "StartsWith" | "DoesNotStartWith" | "Is" | "IsNot" | "IsBlank" | "IsNotBlank";
|
export type AdvancedFilterConditionOperators = "None" | "LessThan" | "LessThanOrEqual" | "GreaterThan" | "GreaterThanOrEqual" | "Contains" | "DoesNotContain" | "StartsWith" | "DoesNotStartWith" | "Is" | "IsNot" | "IsBlank" | "IsNotBlank";
|
||||||
|
@ -167,6 +176,14 @@ export enum FilterType {
|
||||||
Unknown
|
Unknown
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function isFilterKeyColumnsTarget(target: IFilterTarget): boolean {
|
||||||
|
return isColumn(target) && !!(<IFilterKeyColumnsTarget>target).keys;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function isBasicFilterWithKeys(filter: IFilter): boolean {
|
||||||
|
return getFilterType(filter) === FilterType.Basic && !!(<IBasicFilterWithKeys>filter).keyValues;
|
||||||
|
}
|
||||||
|
|
||||||
export function getFilterType(filter: IFilter): FilterType {
|
export function getFilterType(filter: IFilter): FilterType {
|
||||||
const basicFilter = filter as IBasicFilter;
|
const basicFilter = filter as IBasicFilter;
|
||||||
const advancedFilter = filter as IAdvancedFilter;
|
const advancedFilter = filter as IAdvancedFilter;
|
||||||
|
@ -222,6 +239,7 @@ export class BasicFilter extends Filter {
|
||||||
static schemaUrl: string = "http://powerbi.com/product/schema#basic";
|
static schemaUrl: string = "http://powerbi.com/product/schema#basic";
|
||||||
operator: BasicFilterOperators;
|
operator: BasicFilterOperators;
|
||||||
values: (string | number | boolean)[];
|
values: (string | number | boolean)[];
|
||||||
|
keyValues: (string | number | boolean)[][];
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
target: IFilterTarget,
|
target: IFilterTarget,
|
||||||
|
@ -233,7 +251,7 @@ export class BasicFilter extends Filter {
|
||||||
this.schemaUrl = BasicFilter.schemaUrl;
|
this.schemaUrl = BasicFilter.schemaUrl;
|
||||||
|
|
||||||
if (values.length === 0 && operator !== "All") {
|
if (values.length === 0 && operator !== "All") {
|
||||||
throw new Error(`values must be a non-empty array unless your operator is "All". You passed: ${values}`);
|
throw new Error(`values must be a non-empty array unless your operator is "All".`);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -259,6 +277,47 @@ export class BasicFilter extends Filter {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export class BasicFilterWithKeys extends BasicFilter {
|
||||||
|
keyValues: (string | number | boolean)[][];
|
||||||
|
target: IFilterKeyColumnsTarget;
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
target: IFilterKeyColumnsTarget,
|
||||||
|
operator: BasicFilterOperators,
|
||||||
|
values: ((string | number | boolean) | (string | number | boolean)[]),
|
||||||
|
keyValues: (string | number | boolean)[][]
|
||||||
|
) {
|
||||||
|
super(target, operator, values);
|
||||||
|
this.keyValues = keyValues;
|
||||||
|
this.target = target;
|
||||||
|
let numberOfKeys = target.keys ? target.keys.length : 0;
|
||||||
|
|
||||||
|
if (numberOfKeys > 0 && !keyValues) {
|
||||||
|
throw new Error(`You shold pass the values to be filtered for each key. You passed: no values and ${numberOfKeys} keys`);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (numberOfKeys === 0 && keyValues && keyValues.length > 0) {
|
||||||
|
throw new Error(`You passed key values but your target object doesn't contain the keys to be filtered`);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (let i = 0 ; i < this.keyValues.length ; i++) {
|
||||||
|
if (this.keyValues[i] ) {
|
||||||
|
let lengthOfArray = this.keyValues[i].length;
|
||||||
|
if (lengthOfArray !== numberOfKeys) {
|
||||||
|
throw new Error(`Each tuple of key values should contain a value for each of the keys. You passed: ${lengthOfArray} values and ${numberOfKeys} keys`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
toJSON(): IBasicFilter {
|
||||||
|
const filter = <IBasicFilterWithKeys>super.toJSON();
|
||||||
|
filter.keyValues = this.keyValues;
|
||||||
|
return filter;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export class AdvancedFilter extends Filter {
|
export class AdvancedFilter extends Filter {
|
||||||
static schemaUrl: string = "http://powerbi.com/product/schema#advanced";
|
static schemaUrl: string = "http://powerbi.com/product/schema#advanced";
|
||||||
|
|
||||||
|
|
|
@ -512,6 +512,30 @@ describe("Unit | Filters", function () {
|
||||||
expect(basicFilter.values).toEqual(values);
|
expect(basicFilter.values).toEqual(values);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("should accept values as an array of tuples", function () {
|
||||||
|
// Arrange
|
||||||
|
const values = [1, 2];
|
||||||
|
const keyValues = [[1, 2], [3,4]];
|
||||||
|
|
||||||
|
// Act
|
||||||
|
const basicFilter = new models.BasicFilterWithKeys({ table: "t", column: "c" , keys: ["1", "2"]}, "In", values, keyValues);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
expect(basicFilter.values).toEqual(values);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should throw an exception when values are an array of tuples, but tuples length is different than keys length", function () {
|
||||||
|
// Arrange
|
||||||
|
const values = [1, 2];
|
||||||
|
const keyValues = [[1, 2], [3,4]];
|
||||||
|
|
||||||
|
// Act
|
||||||
|
const attemptToCreateFilter = () => {
|
||||||
|
return new models.BasicFilterWithKeys({ table: "t", column: "c" , keys: ["1"]}, "In", values, keyValues);
|
||||||
|
};
|
||||||
|
expect(attemptToCreateFilter).toThrowError();
|
||||||
|
});
|
||||||
|
|
||||||
it("should return valid json format when toJSON is called", function () {
|
it("should return valid json format when toJSON is called", function () {
|
||||||
// Arrange
|
// Arrange
|
||||||
const expectedFilter: models.IBasicFilter = {
|
const expectedFilter: models.IBasicFilter = {
|
||||||
|
@ -679,11 +703,12 @@ describe("Unit | Filters", function () {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('determine filter type', function () {
|
describe('determine types', function () {
|
||||||
it('getFilterType should return type of filter given a filter object', function () {
|
it('getFilterType should return type of filter given a filter object', function () {
|
||||||
// Arrange
|
// Arrange
|
||||||
const testData = {
|
const testData = {
|
||||||
basicFilter: new models.BasicFilter({ table: "a", column: "b" }, "In", ["x", "y"]),
|
basicFilter: new models.BasicFilter({ table: "a", column: "b" }, "In", ["x", "y"]),
|
||||||
|
basicFilterWithKeys: new models.BasicFilterWithKeys({ table: "a", column: "b", keys: ["1", "2"] }, "In", ["x1", 1], [["x1", 1], ["y2",2]]),
|
||||||
advancedFilter: new models.AdvancedFilter({ table: "a", column: "b" }, "And",
|
advancedFilter: new models.AdvancedFilter({ table: "a", column: "b" }, "And",
|
||||||
{ operator: "Contains", value: "x" },
|
{ operator: "Contains", value: "x" },
|
||||||
{ operator: "Contains", value: "x" }
|
{ operator: "Contains", value: "x" }
|
||||||
|
@ -695,8 +720,31 @@ describe("Unit | Filters", function () {
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
expect(models.getFilterType(testData.basicFilter.toJSON())).toBe(models.FilterType.Basic);
|
expect(models.getFilterType(testData.basicFilter.toJSON())).toBe(models.FilterType.Basic);
|
||||||
|
expect(models.getFilterType(testData.basicFilterWithKeys.toJSON())).toBe(models.FilterType.Basic);
|
||||||
expect(models.getFilterType(testData.advancedFilter.toJSON())).toBe(models.FilterType.Advanced);
|
expect(models.getFilterType(testData.advancedFilter.toJSON())).toBe(models.FilterType.Advanced);
|
||||||
expect(models.getFilterType(testData.nonFilter)).toBe(models.FilterType.Unknown);
|
expect(models.getFilterType(testData.nonFilter)).toBe(models.FilterType.Unknown);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('isFilterKeyColumnsTarget should return the correct response', function () {
|
||||||
|
// Arrange
|
||||||
|
let filterKeyColumnsTarget = { table: "a", column: "b", keys: ["key1"] };
|
||||||
|
let filterColumnTarget = { table: "a", column: "b"};
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
expect(models.isFilterKeyColumnsTarget(filterKeyColumnsTarget)).toBeTruthy();
|
||||||
|
expect(models.isFilterKeyColumnsTarget(filterColumnTarget)).toBeFalsy();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('isBasicFilterWithKeys should return the correct response', function () {
|
||||||
|
// Arrange
|
||||||
|
const testData = {
|
||||||
|
basicFilter: new models.BasicFilter({ table: "a", column: "b" }, "In", ["x", "y"]),
|
||||||
|
basicFilterWithKeys: new models.BasicFilterWithKeys({ table: "a", column: "b", keys: ["1", "2"] }, "In", ["x1", 1], [["x1", 1], ["y2",2]]),
|
||||||
|
};
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
expect(models.isBasicFilterWithKeys(testData.basicFilter.toJSON())).toBeFalsy();
|
||||||
|
expect(models.isBasicFilterWithKeys(testData.basicFilterWithKeys.toJSON())).toBeTruthy();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
Загрузка…
Ссылка в новой задаче