From 95ea053523240978334ead94b783d268356ff082 Mon Sep 17 00:00:00 2001 From: Noa Nutkevitch Date: Sun, 27 Aug 2017 11:06:37 +0000 Subject: [PATCH] Merged PR 23006: Add more filter types --- package.json | 2 +- src/models.ts | 217 ++++++++++++++++++-- src/schemas/advancedFilter.json | 8 +- src/schemas/basicFilter.json | 8 +- src/schemas/filter.json | 12 ++ src/schemas/includeExcludeFilter.json | 49 +++++ src/schemas/notSupportedFilter.json | 45 +++++ src/schemas/relativeDateFilter.json | 60 ++++++ src/schemas/reportLoadConfiguration.json | 3 + src/schemas/topNFilter.json | 46 +++++ test/models.spec.ts | 241 +++++++++++++++++++++-- 11 files changed, 658 insertions(+), 33 deletions(-) create mode 100644 src/schemas/includeExcludeFilter.json create mode 100644 src/schemas/notSupportedFilter.json create mode 100644 src/schemas/relativeDateFilter.json create mode 100644 src/schemas/topNFilter.json diff --git a/package.json b/package.json index e65ffda..bac5d5e 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "powerbi-models", - "version": "0.11.4", + "version": "0.11.5", "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", "typings": "dist/models.d.ts", diff --git a/src/models.ts b/src/models.ts index 0658afb..51a9c31 100644 --- a/src/models.ts +++ b/src/models.ts @@ -2,6 +2,10 @@ declare var require: Function; /* tslint:disable:no-var-requires */ export const advancedFilterSchema = require('./schemas/advancedFilter.json'); +export const includeExcludeFilterSchema = require('./schemas/includeExcludeFilter.json'); +export const notSupportedFilterSchema = require('./schemas/notSupportedFilter.json'); +export const relativeDateFilterSchema = require('./schemas/relativeDateFilter.json'); +export const topNFilterSchema = require('./schemas/topNFilter.json'); export const filterSchema = require('./schemas/filter.json'); export const extensionSchema = require('./schemas/extension.json'); export const extensionItemSchema = require('./schemas/extensionItem.json'); @@ -141,8 +145,6 @@ export interface ISettings { export const validateSettings = validate(settingsSchema, { schemas: { - basicFilter: basicFilterSchema, - advancedFilter: advancedFilterSchema, customLayout: customLayoutSchema, pageSize: pageSizeSchema, extension: extensionSchema, @@ -175,7 +177,7 @@ export interface IReportLoadConfiguration { id: string; settings?: ISettings; pageName?: string; - filters?: (IBasicFilter | IAdvancedFilter)[]; + filters?: ReportLevelFilters[]; permissions?: Permissions; viewMode?: ViewMode; tokenType?: TokenType; @@ -186,6 +188,7 @@ export const validateReportLoad = validate(loadSchema, { settings: settingsSchema, basicFilter: basicFilterSchema, advancedFilter: advancedFilterSchema, + relativeDateFilter: relativeDateFilterSchema, customLayout: customLayoutSchema, pageSize: pageSizeSchema, extension: extensionSchema, @@ -249,7 +252,11 @@ export const validatePage = validate(pageSchema); export const validateFilter = validate(filterSchema, { schemas: { basicFilter: basicFilterSchema, - advancedFilter: advancedFilterSchema + advancedFilter: advancedFilterSchema, + notSupportedFilter: notSupportedFilterSchema, + topNFilter: topNFilterSchema, + relativeDateFilter: relativeDateFilterSchema, + includeExcludeFilter: includeExcludeFilterSchema } }); @@ -279,16 +286,41 @@ export interface IFilterHierarchyTarget extends IBaseFilterTarget { aggregationFunction?: string; } +export interface INotSupportedFilterTarget extends IBaseFilterTarget {} + export interface IFilterMeasureTarget extends IBaseFilterTarget { measure: string; } export declare type IFilterKeyTarget = (IFilterKeyColumnsTarget | IFilterKeyHierarchyTarget); -export declare type IFilterTarget = (IFilterColumnTarget | IFilterHierarchyTarget | IFilterMeasureTarget); +export declare type IFilterTarget = (IFilterColumnTarget | IFilterHierarchyTarget | IFilterMeasureTarget | INotSupportedFilterTarget); export interface IFilter { - $schema: string; - target: IFilterTarget; + $schema: string; + target: IFilterTarget; + filterType: FilterType; +} + +export interface INotSupportedFilter extends IFilter { + message: string; + notSupportedTypeName: string; +} + +export interface IIncludeExcludeFilter extends IFilter { + values: (string | number | boolean)[]; + isExclude: boolean; +} + +export interface ITopNFilter extends IFilter { + operator: TopNFilterOperators; + itemCount: number; +} + +export interface IRelativeDateFilter extends IFilter { + operator: RelativeDateOperators; + timeUnitsCount: number; + timeUnitType: RelativeDateFilterTimeUnit; + includeToday: boolean; } export interface IBasicFilter extends IFilter { @@ -301,10 +333,30 @@ export interface IBasicFilterWithKeys extends IBasicFilter { keyValues: (string | number | boolean)[][]; } +export type ReportLevelFilters = IBasicFilter | IAdvancedFilter | IRelativeDateFilter; +export type PageLevelFilters = IBasicFilter | IAdvancedFilter | IRelativeDateFilter; +export type VisualFilterTypes = IBasicFilter | IAdvancedFilter | IRelativeDateFilter | ITopNFilter | IIncludeExcludeFilter; +export type TopNFilterOperators = "Top" | "Bottom"; export type BasicFilterOperators = "In" | "NotIn" | "All"; export type AdvancedFilterLogicalOperators = "And" | "Or"; export type AdvancedFilterConditionOperators = "None" | "LessThan" | "LessThanOrEqual" | "GreaterThan" | "GreaterThanOrEqual" | "Contains" | "DoesNotContain" | "StartsWith" | "DoesNotStartWith" | "Is" | "IsNot" | "IsBlank" | "IsNotBlank"; +export function validateReportLevelFilters(filer: IFilter): IError { + let error: IError; + if (validate(basicFilterSchema)(filer) && validate(advancedFilterSchema)(filer) && validate(relativeDateFilterSchema)(filer)) { + error = { message: "One of the filters is not a report level filter" }; + } + return error; +} + +export function validatePageLevelFilters(filer: IFilter): IError { + let error: IError; + if (validate(basicFilterSchema)(filer) && validate(advancedFilterSchema)(filer) && validate(relativeDateFilterSchema)(filer)) { + error = { message: "One of the filters is not a page level filter" }; + } + return error; +} + export interface IAdvancedFilterCondition { value: (string | number | boolean); operator: AdvancedFilterConditionOperators; @@ -316,9 +368,28 @@ export interface IAdvancedFilter extends IFilter { } export enum FilterType { - Advanced, - Basic, - Unknown + Advanced = 0, + Basic = 1, + Unknown = 2, + IncludeExclude = 3, + RelativeDate = 4, + TopN = 5, +} + +export enum RelativeDateFilterTimeUnit { + Days = 0, + Weeks = 1, + CalendarWeeks = 2, + Months = 3, + CalendarMonths = 4, + Years = 5, + CalendarYears = 6, +} + +export enum RelativeDateOperators { + InLast = 0, + InThis = 1, + InNext = 2, } export function isFilterKeyColumnsTarget(target: IFilterTarget): boolean { @@ -330,6 +401,10 @@ export function isBasicFilterWithKeys(filter: IFilter): boolean { } export function getFilterType(filter: IFilter): FilterType { + if(filter.filterType) { + return filter.filterType; + } + const basicFilter = filter as IBasicFilter; const advancedFilter = filter as IAdvancedFilter; @@ -364,22 +439,134 @@ export abstract class Filter { static schema: string; protected static schemaUrl: string; target: IFilterTarget; + filterType: FilterType; protected schemaUrl: string; constructor( - target: IFilterTarget + target: IFilterTarget, + filterType: FilterType ) { this.target = target; + this.filterType = filterType; } toJSON(): IFilter { return { $schema: this.schemaUrl, - target: this.target + target: this.target, + filterType: this.filterType }; }; } +export class NotSupportedFilter extends Filter { + static schemaUrl: string = "http://powerbi.com/product/schema#notSupported"; + message: string; + notSupportedTypeName: string; + + constructor( + target: IFilterTarget, + message: string, + notSupportedTypeName: string) { + super(target, FilterType.Unknown); + this.message = message; + this.notSupportedTypeName = notSupportedTypeName; + this.schemaUrl = NotSupportedFilter.schemaUrl; + } + + toJSON(): INotSupportedFilter { + const filter = super.toJSON(); + + filter.message = this.message; + filter.notSupportedTypeName = this.notSupportedTypeName; + + return filter; + } +} + +export class IncludeExcludeFilter extends Filter { + static schemaUrl: string = "http://powerbi.com/product/schema#includeExclude"; + values: (string | number | boolean)[]; + isExclude: boolean; + + constructor( + target: IFilterTarget, + isExclude: boolean, + values: (string | number | boolean)[]) { + super(target, FilterType.IncludeExclude); + this.values = values; + this.isExclude = isExclude; + this.schemaUrl = IncludeExcludeFilter.schemaUrl; + } + + toJSON(): IIncludeExcludeFilter { + const filter = super.toJSON(); + + filter.isExclude = this.isExclude; + filter.values = this.values; + + return filter; + } +} + +export class TopNFilter extends Filter { + static schemaUrl: string = "http://powerbi.com/product/schema#topN"; + operator: TopNFilterOperators; + itemCount: number; + + constructor( + target: IFilterTarget, + operator: TopNFilterOperators, + itemCount: number) { + super(target, FilterType.TopN); + this.operator = operator; + this.itemCount = itemCount; + this.schemaUrl = TopNFilter.schemaUrl; + } + + toJSON(): ITopNFilter { + const filter = super.toJSON(); + + filter.operator = this.operator; + filter.itemCount = this.itemCount; + + return filter; + } +} + +export class RelativeDateFilter extends Filter { + static schemaUrl: string = "http://powerbi.com/product/schema#relativeDate"; + operator: RelativeDateOperators; + timeUnitsCount: number; + timeUnitType: RelativeDateFilterTimeUnit; + includeToday: boolean; + + constructor( + target: IFilterTarget, + operator: RelativeDateOperators, + timeUnitsCount: number, + timeUnitType: RelativeDateFilterTimeUnit, + includeToday: boolean) { + super(target, FilterType.RelativeDate); + this.operator = operator; + this.timeUnitsCount = timeUnitsCount; + this.timeUnitType = timeUnitType; + this.includeToday = includeToday; + this.schemaUrl = RelativeDateFilter.schemaUrl; + } + + toJSON(): IRelativeDateFilter { + const filter = super.toJSON(); + + filter.operator = this.operator; + filter.timeUnitsCount = this.timeUnitsCount; + filter.timeUnitType = this.timeUnitType; + filter.includeToday = this.includeToday; + + return filter; + } +} + export class BasicFilter extends Filter { static schemaUrl: string = "http://powerbi.com/product/schema#basic"; operator: BasicFilterOperators; @@ -391,7 +578,7 @@ export class BasicFilter extends Filter { operator: BasicFilterOperators, ...values: ((string | number | boolean) | (string | number | boolean)[])[] ) { - super(target); + super(target, FilterType.Basic); this.operator = operator; this.schemaUrl = BasicFilter.schemaUrl; @@ -474,7 +661,7 @@ export class AdvancedFilter extends Filter { logicalOperator: AdvancedFilterLogicalOperators, ...conditions: (IAdvancedFilterCondition | IAdvancedFilterCondition[])[] ) { - super(target); + super(target, FilterType.Advanced); this.schemaUrl = AdvancedFilter.schemaUrl; // Guard statements @@ -549,7 +736,7 @@ export interface ISelection { report: IReport; dataPoints: IIdentityValue[]; regions: IIdentityValue[]; - filters: (IBasicFilter | IAdvancedFilter)[]; + filters: IFilter[]; } export enum Permissions { diff --git a/src/schemas/advancedFilter.json b/src/schemas/advancedFilter.json index b1f254b..a92960f 100644 --- a/src/schemas/advancedFilter.json +++ b/src/schemas/advancedFilter.json @@ -75,7 +75,13 @@ "operator" ] } - } + }, + "filterType": { + "type": "number", + "enum": [0], + "default": 0, + "invalidMessage": "filterType property is invalid" + } }, "required": [ "target", diff --git a/src/schemas/basicFilter.json b/src/schemas/basicFilter.json index 480b229..1585646 100644 --- a/src/schemas/basicFilter.json +++ b/src/schemas/basicFilter.json @@ -33,7 +33,13 @@ "items": { "type": ["string", "boolean", "number"] } - } + }, + "filterType": { + "type": "number", + "enum": [1], + "default": 1, + "invalidMessage": "filterType property is invalid" + } }, "required": [ "target", diff --git a/src/schemas/filter.json b/src/schemas/filter.json index aab744d..9e822bf 100644 --- a/src/schemas/filter.json +++ b/src/schemas/filter.json @@ -6,6 +6,18 @@ }, { "$ref": "#advancedFilter" + }, + { + "$ref": "#includeExcludeFilter" + }, + { + "$ref": "#notSupportedFilter" + }, + { + "$ref": "#relativeDateFilter" + }, + { + "$ref": "#topNFilter" } ], "invalidMessage": "filter is invalid" diff --git a/src/schemas/includeExcludeFilter.json b/src/schemas/includeExcludeFilter.json new file mode 100644 index 0000000..bb0b1e4 --- /dev/null +++ b/src/schemas/includeExcludeFilter.json @@ -0,0 +1,49 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "type": "object", + "properties": { + "target": { + "type": "object", + "properties": { + "table": { + "type": "string" + }, + "column": { + "type": "string" + }, + "hierarchy": { + "type": "string" + }, + "hierarchyLevel": { + "type": "string" + }, + "measure": { + "type": "string" + } + }, + "required": [ + "table" + ] + }, + "isExclude": { + "type": "boolean" + }, + "values": { + "type": "array", + "items": { + "type": ["string", "boolean", "number"] + }, + "filterType": { + "type": "number", + "enum": [3], + "default": 3, + "invalidMessage": "filterType property is invalid" + } + } + }, + "required": [ + "target", + "isExclude", + "values" + ] +} \ No newline at end of file diff --git a/src/schemas/notSupportedFilter.json b/src/schemas/notSupportedFilter.json new file mode 100644 index 0000000..7bd8308 --- /dev/null +++ b/src/schemas/notSupportedFilter.json @@ -0,0 +1,45 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "type": "object", + "properties": { + "target": { + "type": "object", + "properties": { + "table": { + "type": "string" + }, + "column": { + "type": "string" + }, + "hierarchy": { + "type": "string" + }, + "hierarchyLevel": { + "type": "string" + }, + "measure": { + "type": "string" + } + }, + "required": [ + "table" + ] + }, + "message": { + "type": "string" + }, + "notSupportedTypeName": { + "type": "string" + }, + "filterType": { + "type": "number", + "enum": [2], + "default": 2, + "invalidMessage": "filterType property is invalid" + } + }, + "required": [ + "message", + "notSupportedTypeName" + ] +} \ No newline at end of file diff --git a/src/schemas/relativeDateFilter.json b/src/schemas/relativeDateFilter.json new file mode 100644 index 0000000..06887d1 --- /dev/null +++ b/src/schemas/relativeDateFilter.json @@ -0,0 +1,60 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "type": "object", + "properties": { + "target": { + "type": "object", + "properties": { + "table": { + "type": "string" + }, + "column": { + "type": "string" + }, + "hierarchy": { + "type": "string" + }, + "hierarchyLevel": { + "type": "string" + }, + "measure": { + "type": "string" + } + }, + "required": [ + "table" + ] + }, + "operator": { + "type": "number", + "enum": [0, 1, 2], + "default": 0, + "invalidMessage": "operator property is invalid" + }, + "timeUnitsCount": { + "type": "number" + }, + "timeUnitType": { + "type": "number", + "enum": [0, 1, 2, 3, 4, 5, 6], + "default": 0, + "invalidMessage": "timeUnitType property is invalid" + }, + "includeToday": { + "type": "boolean" + }, + "filterType": { + "type": "number", + "enum": [4], + "default": 4, + "invalidMessage": "filterType property is invalid" + } + }, + "required": [ + "target", + "operator", + "timeUnitsCount", + "timeUnitType", + "includeToday" + ] +} \ No newline at end of file diff --git a/src/schemas/reportLoadConfiguration.json b/src/schemas/reportLoadConfiguration.json index 3da3bce..7d0f6e0 100644 --- a/src/schemas/reportLoadConfiguration.json +++ b/src/schemas/reportLoadConfiguration.json @@ -35,6 +35,9 @@ }, { "$ref": "#advancedFilter" + }, + { + "$ref": "#relativeDateFilter" } ] }, diff --git a/src/schemas/topNFilter.json b/src/schemas/topNFilter.json new file mode 100644 index 0000000..061c82a --- /dev/null +++ b/src/schemas/topNFilter.json @@ -0,0 +1,46 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "type": "object", + "properties": { + "target": { + "type": "object", + "properties": { + "table": { + "type": "string" + }, + "column": { + "type": "string" + }, + "hierarchy": { + "type": "string" + }, + "hierarchyLevel": { + "type": "string" + }, + "measure": { + "type": "string" + } + }, + "required": [ + "table" + ] + }, + "operator": { + "type": "string" + }, + "itemCount": { + "type": "number" + }, + "filterType": { + "type": "number", + "enum": [5], + "default": 5, + "invalidMessage": "filterType property is invalid" + } + }, + "required": [ + "target", + "operator", + "itemCount" + ] +} \ No newline at end of file diff --git a/test/models.spec.ts b/test/models.spec.ts index 606f816..a26ec35 100644 --- a/test/models.spec.ts +++ b/test/models.spec.ts @@ -95,7 +95,7 @@ describe('Unit | Models', function () { expect(errors).toBeUndefined(); }); - it(`should return errors with one containing message '${filtersInvalidMessage}' if filters is not a valid array of basicFilter or advancedFilter`, function () { + it(`should return errors with one containing message '${filtersInvalidMessage}' if filters is not a valid array of IFilter`, function () { // Arrange const testData = { load: { @@ -112,7 +112,7 @@ describe('Unit | Models', function () { testForExpectedMessage(errors, filtersInvalidMessage); }); - it(`should return errors if filters is array, but item is not a valid basicFilter or advancedFilter`, function () { + it(`should return errors if filters is array, but item is not a valid IFilter`, function () { // Arrange const testData = { load: { @@ -133,7 +133,7 @@ describe('Unit | Models', function () { // TODO: Need to fix reportLoadConfiguration.json schema so that this fails. // Currently this validates without errors, but the second object should be rejected since it is not a valid filter. - xit(`should return errors if filters is array, but not all items are valid basicFilter or advancedFilter`, function () { + xit(`should return errors if filters is array, but not all items are valid IFIlter`, function () { // Arrange const testData = { load: { @@ -154,14 +154,16 @@ describe('Unit | Models', function () { expect(errors.length).toBeGreaterThan(0); }); - it(`should return undefined if filters is valid array of basicFilter or advancedFilter`, function () { + it(`should return undefined if filters is valid array of IFIlter`, function () { // Arrange const testData = { load: { id: 'fakeId', accessToken: 'fakeAccessToken', filters: [ - new models.BasicFilter({ table: "fakeTable", column: "fakeColumn" }, "In", ["A"]).toJSON() + new models.BasicFilter({ table: "fakeTable", column: "fakeColumn" }, "In", ["A"]).toJSON(), + new models.RelativeDateFilter({ table: "fakeTable", column: "fakeColumn" }, + models.RelativeDateOperators.InLast, 3, models.RelativeDateFilterTimeUnit.CalendarMonths, true).toJSON() ] } }; @@ -690,7 +692,8 @@ describe('Unit | Models', function () { "a", 100, false - ] + ], + filterType: models.FilterType.Basic }; // Act const filter = new models.BasicFilter( @@ -711,7 +714,8 @@ describe('Unit | Models', function () { column: "b" }, operator: "All", - values: [] + values: [], + filterType: models.FilterType.Basic }; // Act @@ -724,6 +728,102 @@ describe('Unit | Models', function () { expect(models.validateFilter(filter.toJSON())).toBeUndefined(); }); + it("should return undefined if object is valid relativeDate filter schema", function () { + // Arrange + const expectedFilter: models.IRelativeDateFilter = { + $schema: "http://powerbi.com/product/schema#relativeDate", + target: { + table: "a", + column: "b" + }, + operator: models.RelativeDateOperators.InLast, + timeUnitsCount: 11, + timeUnitType: models.RelativeDateFilterTimeUnit.Years, + includeToday: false, + filterType: models.FilterType.RelativeDate + }; + + // Act + const filter = new models.RelativeDateFilter( + expectedFilter.target, + expectedFilter.operator, + expectedFilter.timeUnitsCount, + expectedFilter.timeUnitType, + expectedFilter.includeToday); + + // Assert + expect(models.validateFilter(filter.toJSON())).toBeUndefined(); + }); + + it("should return undefined if object is valid topN filter schema", function () { + // Arrange + const expectedFilter: models.ITopNFilter = { + $schema: "http://powerbi.com/product/schema#topN", + target: { + table: "a", + column: "b" + }, + operator: "Top", + itemCount: 2, + filterType: models.FilterType.TopN + }; + + // Act + const filter = new models.TopNFilter( + expectedFilter.target, + expectedFilter.operator, + expectedFilter.itemCount); + + // Assert + expect(models.validateFilter(filter.toJSON())).toBeUndefined(); + }); + + it("should return undefined if object is valid notSupported filter schema", function () { + // Arrange + const expectedFilter: models.INotSupportedFilter = { + $schema: "http://powerbi.com/product/schema#notSupported", + target: { + table: "a", + column: "b" + }, + message: "not supported", + notSupportedTypeName: "not supported type", + filterType: models.FilterType.Unknown + }; + + // Act + const filter = new models.NotSupportedFilter( + expectedFilter.target, + expectedFilter.message, + expectedFilter.notSupportedTypeName); + + // Assert + expect(models.validateFilter(filter.toJSON())).toBeUndefined(); + }); + + it("should return undefined if object is valid include/exclude filter schema", function () { + // Arrange + const expectedFilter: models.IIncludeExcludeFilter = { + $schema: "http://powerbi.com/product/schema#includeExclude", + target: { + table: "a", + column: "b" + }, + values: [1,2], + isExclude: true, + filterType: models.FilterType.IncludeExclude + }; + + // Act + const filter = new models.IncludeExcludeFilter( + expectedFilter.target, + expectedFilter.isExclude, + expectedFilter.values); + + // Assert + expect(models.validateFilter(filter.toJSON())).toBeUndefined(); + }); + it("should return undefined if object is valid advanced filter schema", function () { // Arrange const expectedFilter: models.IAdvancedFilter = { @@ -746,7 +846,8 @@ describe('Unit | Models', function () { value: 1, operator: "Is" } - ] + ], + filterType: models.FilterType.Advanced }; const filter = new models.AdvancedFilter( @@ -928,7 +1029,8 @@ describe("Unit | Filters", function () { 1, 2, 3 - ] + ], + filterType: models.FilterType.Basic }; // Act @@ -954,7 +1056,8 @@ describe("Unit | Filters", function () { "a", 100, false - ] + ], + filterType: models.FilterType.Basic }; // Act @@ -1039,7 +1142,8 @@ describe("Unit | Filters", function () { value: "b", operator: "LessThan" } - ] + ], + filterType: models.FilterType.Advanced }; // Act @@ -1070,7 +1174,8 @@ describe("Unit | Filters", function () { value: "v2", operator: "Contains" } - ] + ], + filterType: models.FilterType.Advanced }; // Act @@ -1082,8 +1187,109 @@ describe("Unit | Filters", function () { }); }); + describe("RelativeDateFilter", function () { + it("should output the correct json when toJSON is called", function () { + // Arrange + const expectedFilter: models.IRelativeDateFilter = { + $schema: "http://powerbi.com/product/schema#relativeDate", + target: { + table: "a", + column: "b" + }, + filterType: models.FilterType.RelativeDate, + operator: models.RelativeDateOperators.InLast, + timeUnitsCount: 11, + timeUnitType: models.RelativeDateFilterTimeUnit.Years, + includeToday: false, + }; + + // Act + const filter = new models.RelativeDateFilter( + expectedFilter.target, + expectedFilter.operator, + expectedFilter.timeUnitsCount, + expectedFilter.timeUnitType, + expectedFilter.includeToday); + + // Assert + expect(filter.toJSON()).toEqual(expectedFilter); + }); + }); + + describe("notSupportedFilterFilter", function () { + it("should output the correct json when toJSON is called", function () { + // Arrange + const expectedFilter: models.INotSupportedFilter = { + $schema: "http://powerbi.com/product/schema#notSupported", + target: null, + filterType: models.FilterType.Unknown, + message: 'filter is not supported', + notSupportedTypeName: 'new filter name' + }; + + // Act + const filter = new models.NotSupportedFilter( + expectedFilter.target, + expectedFilter.message, + expectedFilter.notSupportedTypeName); + + // Assert + expect(filter.toJSON()).toEqual(expectedFilter); + }); + }); + + describe("topNFilter", function () { + it("should output the correct json when toJSON is called", function () { + // Arrange + const expectedFilter: models.ITopNFilter = { + $schema: "http://powerbi.com/product/schema#topN", + target: { + table: "a", + column: "b", + }, + filterType: models.FilterType.TopN, + operator: "Top", + itemCount: 3, + }; + + // Act + const filter = new models.TopNFilter( + expectedFilter.target, + expectedFilter.operator, + expectedFilter.itemCount); + + // Assert + expect(filter.toJSON()).toEqual(expectedFilter); + }); + }); + + describe("includeExcludeFilter", function () { + it("should output the correct json when toJSON is called", function () { + // Arrange + const expectedFilter: models.IIncludeExcludeFilter = { + $schema: "http://powerbi.com/product/schema#includeExclude", + target: { + table: "a", + column: "b" + }, + filterType: models.FilterType.IncludeExclude, + isExclude: false, + values: [1,2,3], + }; + + // Act + const filter = new models.IncludeExcludeFilter( + expectedFilter.target, + expectedFilter.isExclude, + expectedFilter.values); + + // Assert + expect(filter.toJSON()).toEqual(expectedFilter); + }); + }); + describe('determine types', function () { - it('getFilterType should return type of filter given a filter object', function () { + it('filter object should be constructed with the correct filterType', function () { // Arrange const testData = { basicFilter: new models.BasicFilter({ table: "a", column: "b" }, "In", ["x", "y"]), @@ -1093,7 +1299,10 @@ describe("Unit | Filters", function () { { operator: "Contains", value: "x" }, { operator: "Contains", value: "x" } ), - nonFilter: {} + relativeDateFilter: new models.RelativeDateFilter({ table: "a", column: "b" }, models.RelativeDateOperators.InLast, + 3, models.RelativeDateFilterTimeUnit.CalendarMonths, true), + topNFilter: new models.TopNFilter({ table: "a", column: "b" }, "Top", 4), + includeExclude: new models.IncludeExcludeFilter({ table: "a", column: "b" }, true, [1,2]) }; // Act @@ -1103,7 +1312,9 @@ describe("Unit | Filters", function () { expect(models.getFilterType(testData.basicFilterWithKeysOnColumn.toJSON())).toBe(models.FilterType.Basic); expect(models.getFilterType(testData.basicFilterWithKeysOnHierarchy.toJSON())).toBe(models.FilterType.Basic); expect(models.getFilterType(testData.advancedFilter.toJSON())).toBe(models.FilterType.Advanced); - expect(models.getFilterType(testData.nonFilter)).toBe(models.FilterType.Unknown); + expect(models.getFilterType(testData.relativeDateFilter.toJSON())).toBe(models.FilterType.RelativeDate); + expect(models.getFilterType(testData.topNFilter.toJSON())).toBe(models.FilterType.TopN); + expect(models.getFilterType(testData.includeExclude.toJSON())).toBe(models.FilterType.IncludeExclude); }); it('isFilterKeyColumnsTarget should return the correct response', function () {