Skip to content

Commit

Permalink
Clarify attribute area sort
Browse files Browse the repository at this point in the history
-  the attribute sort aggregation switches the attribute sort into
   area sort
-  having a 'flag' or 'aggregation' on a newAttributeSort factory seemed
   confusing while I tried to explain this in docs
-  it is more clear if the area sort has separate factory - even if it
   creates the same type.
-  but this way, the intent is cleaner
-  also, the aggregation: boolean was not good. this is indeed a function that may one day support more.
  • Loading branch information
lupko committed Jun 23, 2020
1 parent 881be7c commit e3d400e
Show file tree
Hide file tree
Showing 11 changed files with 155 additions and 46 deletions.
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// (C) 2007-2020 GoodData Corporation
import React, { Component } from "react";
import { PivotTable } from "@gooddata/sdk-ui-pivot";
import { newAttributeSort } from "@gooddata/sdk-model";
import { newAttributeAreaSort } from "@gooddata/sdk-model";

import { LdmExt, Ldm } from "../../ldm";

Expand All @@ -14,7 +14,7 @@ export class PivotTableSortingAggregationExample extends Component {
rows={[LdmExt.LocationState]}
columns={[Ldm.DateQuarter]}
pageSize={20}
sortBy={[newAttributeSort(LdmExt.LocationState, "desc", true)]}
sortBy={[newAttributeAreaSort(LdmExt.LocationState, "desc")]}
/>
</div>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {
IAttributeSortItem,
IMeasureSortItem,
newAttributeLocator,
newAttributeAreaSort,
} from "@gooddata/sdk-model";
import { LdmExt } from "../../ldm";
import { SortDirection } from "@gooddata/gd-bear-client";
Expand Down Expand Up @@ -82,7 +83,7 @@ export const DynamicSortingExample: React.FC = () => {
`The columns (date) are sorted by the sum of the Total Sales stacks in each column in ${getOrderLabel(
dir!,
)} order.`,
sortBy: (dir) => [newAttributeSort(LdmExt.monthDate, dir, true)],
sortBy: (dir) => [newAttributeAreaSort(LdmExt.monthDate, dir)],
},
{
key: "sum-of-stacks",
Expand All @@ -91,7 +92,7 @@ export const DynamicSortingExample: React.FC = () => {
`The stacks (state) are sorted by the sum of the Total Sales stacks across all columns in ${getOrderLabel(
dir!,
)} order.`,
sortBy: (dir) => [newAttributeSort(LdmExt.LocationState, dir, true)],
sortBy: (dir) => [newAttributeAreaSort(LdmExt.LocationState, dir)],
},
{
key: "state-element",
Expand Down
10 changes: 8 additions & 2 deletions libs/sdk-model/api/sdk-model.api.md
Original file line number Diff line number Diff line change
Expand Up @@ -305,7 +305,7 @@ export function defWithSorting(definition: IExecutionDefinition, sorts: ISortIte
export type DimensionGenerator = (def: IExecutionDefinition) => IDimension[];

// @public
export type DimensionItem = Identifier | ITotal;
export type DimensionItem = Identifier | IAttribute | ITotal;

// @public
export function dimensionSetTotals(dim: IDimension, totals?: ITotal[]): IDimension;
Expand Down Expand Up @@ -1022,6 +1022,9 @@ export function isArithmeticMeasureDefinition(obj: any): obj is IArithmeticMeasu
// @public
export function isAttribute(obj: any): obj is IAttribute;

// @public
export function isAttributeAreaSort(obj: any): obj is IAttributeSortItem;

// @public
export function isAttributeElementsByRef(obj: any): obj is IAttributeElementsByRef;

Expand Down Expand Up @@ -1387,6 +1390,9 @@ export function newArithmeticMeasure(measuresOrIds: ReadonlyArray<MeasureOrLocal
// @public
export function newAttribute(displayFormRefOrId: ObjRef | Identifier, modifications?: AttributeModifications): IAttribute;

// @public
export function newAttributeAreaSort(attributeOrId: IAttribute | string, sortDirection?: SortDirection, aggregation?: "sum"): IAttributeSortItem;

// @public
export const newAttributeDisplayFormMetadataObject: (ref: ObjRef, modifications?: BuilderModifications<AttributeDisplayFormMetadataObjectBuilder>) => IAttributeDisplayFormMetadataObject;

Expand All @@ -1397,7 +1403,7 @@ export function newAttributeLocator(attributeOrId: IAttribute | string, element:
export const newAttributeMetadataObject: (ref: ObjRef, modifications?: BuilderModifications<AttributeMetadataObjectBuilder>) => IAttributeMetadataObject;

// @public
export function newAttributeSort(attributeOrId: IAttribute | string, sortDirection?: SortDirection, aggregation?: boolean): IAttributeSortItem;
export function newAttributeSort(attributeOrId: IAttribute | string, sortDirection?: SortDirection): IAttributeSortItem;

// @public
export function newBucket(localId: string, ...content: Array<IAttributeOrMeasure | ITotal | undefined>): IBucket;
Expand Down
46 changes: 35 additions & 11 deletions libs/sdk-model/src/execution/base/sort.ts
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,15 @@ export function isAttributeSort(obj: any): obj is IAttributeSortItem {
return !isEmpty(obj) && (obj as IAttributeSortItem).attributeSortItem !== undefined;
}

/**
* Type guard checking whether an object is an attribute area sort item.
*
* @public
*/
export function isAttributeAreaSort(obj: any): obj is IAttributeSortItem {
return isAttributeSort(obj) && obj.attributeSortItem.aggregation !== undefined;
}

/**
* Type guard checking whether an object is a measure sort item.
*
Expand Down Expand Up @@ -206,33 +215,48 @@ export function sortEntityIds(sort: ISortItem): SortEntityIds {
*
* @param attributeOrId - attribute to sort by
* @param sortDirection - asc or desc, defaults to "asc"
* @param aggregation - TODO
* @returns always new item
* @public
*/
export function newAttributeSort(
attributeOrId: IAttribute | string,
sortDirection: SortDirection = "asc",
aggregation: boolean = false,
): IAttributeSortItem {
invariant(attributeOrId, "attribute to create sort for must be defined");

const id: string = attributeLocalId(attributeOrId);

if (!aggregation) {
return {
attributeSortItem: {
attributeIdentifier: id,
direction: sortDirection,
},
};
}
return {
attributeSortItem: {
attributeIdentifier: id,
direction: sortDirection,
},
};
}

/**
* Creates a new attribute area sort - sorting the result by aggregated measure values belonging to each
* attribute value included in the result.
*
* @param attributeOrId - attribute to sort by
* @param sortDirection - sorting direction
* @param aggregation - area sort aggregation function. only "sum" is supported at the moment.
* @public
*/
export function newAttributeAreaSort(
attributeOrId: IAttribute | string,
sortDirection: SortDirection = "asc",
aggregation: "sum" = "sum",
): IAttributeSortItem {
invariant(attributeOrId, "attribute to create sort for must be defined");

const id: string = attributeLocalId(attributeOrId);

return {
attributeSortItem: {
attributeIdentifier: id,
direction: sortDirection,
aggregation: "sum",
aggregation,
},
};
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,55 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`newAttributeAreaSort should create asc area sort by default 1`] = `
Object {
"attributeSortItem": Object {
"aggregation": "sum",
"attributeIdentifier": "a_label.account.id",
"direction": "asc",
},
}
`;

exports[`newAttributeAreaSort should create asc area sort for attribute 1`] = `
Object {
"attributeSortItem": Object {
"aggregation": "sum",
"attributeIdentifier": "localId1",
"direction": "asc",
},
}
`;

exports[`newAttributeAreaSort should create asc area sort for attribute object 1`] = `
Object {
"attributeSortItem": Object {
"aggregation": "sum",
"attributeIdentifier": "a_label.account.id",
"direction": "asc",
},
}
`;

exports[`newAttributeAreaSort should create desc area sort for attribute 1`] = `
Object {
"attributeSortItem": Object {
"aggregation": "sum",
"attributeIdentifier": "localId1",
"direction": "desc",
},
}
`;

exports[`newAttributeAreaSort should create desc area sort for attribute object 1`] = `
Object {
"attributeSortItem": Object {
"aggregation": "sum",
"attributeIdentifier": "a_label.account.id",
"direction": "desc",
},
}
`;

exports[`newAttributeLocator should create locator for attr 1`] = `
Object {
"attributeLocatorItem": Object {
Expand Down Expand Up @@ -63,16 +113,6 @@ Object {
}
`;

exports[`newAttributeSort should create sort with aggregation 1`] = `
Object {
"attributeSortItem": Object {
"aggregation": "sum",
"attributeIdentifier": "a_label.account.id",
"direction": "asc",
},
}
`;

exports[`newMeasureSort should create asc sort by default 1`] = `
Object {
"measureSortItem": Object {
Expand Down
42 changes: 32 additions & 10 deletions libs/sdk-model/src/execution/base/tests/sort.test.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
// (C) 2019 GoodData Corporation
// (C) 2019-2020 GoodData Corporation

import {
IAttributeSortItem,
IMeasureSortItem,
newAttributeAreaSort,
newAttributeLocator,
newAttributeSort,
newMeasureSort,
Expand Down Expand Up @@ -39,17 +40,16 @@ describe("sortEntityIds", () => {
});

describe("newAttributeSort", () => {
const Scenarios: Array<[string, any, any, any]> = [
["create asc sort by default", Account.Default, undefined, undefined],
["create asc sort for attribute object", Account.Default, "asc", undefined],
["create desc sort for attribute object", Account.Default, "desc", undefined],
["create asc sort for attribute", "localId1", "asc", undefined],
["create desc sort for attribute", "localId1", "desc", undefined],
["create sort with aggregation", Account.Default, "asc", true],
const Scenarios: Array<[string, any, any]> = [
["create asc sort by default", Account.Default, undefined],
["create asc sort for attribute object", Account.Default, "asc"],
["create desc sort for attribute object", Account.Default, "desc"],
["create asc sort for attribute", "localId1", "asc"],
["create desc sort for attribute", "localId1", "desc"],
];

it.each(Scenarios)("should %s", (_desc, attrArg, sortArg, aggArg) => {
expect(newAttributeSort(attrArg, sortArg, aggArg)).toMatchSnapshot();
it.each(Scenarios)("should %s", (_desc, attrArg, sortArg) => {
expect(newAttributeSort(attrArg, sortArg)).toMatchSnapshot();
});

it("should throw if attribute input is undefined", () => {
Expand All @@ -61,6 +61,28 @@ describe("newAttributeSort", () => {
});
});

describe("newAttributeAreaSort", () => {
const Scenarios: Array<[string, any, any]> = [
["create asc area sort by default", Account.Default, undefined],
["create asc area sort for attribute object", Account.Default, "asc"],
["create desc area sort for attribute object", Account.Default, "desc"],
["create asc area sort for attribute", "localId1", "asc"],
["create desc area sort for attribute", "localId1", "desc"],
];

it.each(Scenarios)("should %s", (_desc, attrArg, sortArg) => {
expect(newAttributeAreaSort(attrArg, sortArg)).toMatchSnapshot();
});

it("should throw if attribute input is undefined", () => {
expect(() => newAttributeAreaSort(undefined as any, "asc")).toThrowError(InvariantError);
});

it("should throw if attribute input is null", () => {
expect(() => newAttributeAreaSort(undefined as any, "asc")).toThrowError(InvariantError);
});
});

describe("newMeasureSort", () => {
const Scenarios: Array<[string, any, any, any]> = [
["create asc sort by default", Won, undefined, undefined],
Expand Down
6 changes: 6 additions & 0 deletions libs/sdk-model/src/execution/objectFactoryNotation/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import {
IAttributeSortItem,
IMeasureSortItem,
IMeasureLocatorItem,
isAttributeAreaSort,
} from "../base/sort";
import {
IFilter,
Expand Down Expand Up @@ -149,6 +150,9 @@ const convertMeasure: Converter<IMeasure> = ({ measure }) => {
throw new Error("Unknown measure type");
};

const convertAttributeAreaSortItem: Converter<IAttributeSortItem> = ({ attributeSortItem }) =>
`newAttributeAreaSort("${attributeSortItem.attributeIdentifier}", "${attributeSortItem.direction}", "${attributeSortItem.aggregation}")`;

const convertAttributeSortItem: Converter<IAttributeSortItem> = ({ attributeSortItem }) =>
`newAttributeSort("${attributeSortItem.attributeIdentifier}", "${
attributeSortItem.direction
Expand Down Expand Up @@ -218,6 +222,8 @@ export const factoryNotationFor = (data: any): string => {
return convertAttribute(data);
} else if (isMeasure(data)) {
return convertMeasure(data);
} else if (isAttributeAreaSort(data)) {
return convertAttributeAreaSortItem(data);
} else if (isAttributeSort(data)) {
return convertAttributeSortItem(data);
} else if (isMeasureSort(data)) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,14 @@
// (C) 2019 GoodData Corporation
// (C) 2019-2020 GoodData Corporation
import { factoryNotationFor } from "../index";
import { IAttribute } from "../../attribute";
import { newAttribute } from "../../attribute/factory";
import { IAttributeSortItem, IMeasureSortItem, newAttributeSort, newMeasureSort } from "../../base/sort";
import {
IAttributeSortItem,
IMeasureSortItem,
newAttributeAreaSort,
newAttributeSort,
newMeasureSort,
} from "../../base/sort";
import {
IAbsoluteDateFilter,
IMeasureValueFilter,
Expand Down Expand Up @@ -41,6 +47,7 @@ const factories = {
newMeasureValueFilter,

newAttributeSort,
newAttributeAreaSort,
newMeasureSort,
};

Expand Down Expand Up @@ -317,7 +324,7 @@ describe("factoryNotationFor", () => {
const actual = factoryNotationFor(input);
testModelNotation(actual, input);
});
it("should handle attribute sort item with aggregation", () => {
it("should handle attribute area sort item", () => {
const input: IAttributeSortItem = {
attributeSortItem: {
attributeIdentifier: "foo",
Expand Down
2 changes: 2 additions & 0 deletions libs/sdk-model/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -77,8 +77,10 @@ export {
isAttributeLocator,
isMeasureSort,
isAttributeSort,
isAttributeAreaSort,
newMeasureSort,
newAttributeSort,
newAttributeAreaSort,
newAttributeLocator,
SortEntityIds,
sortEntityIds,
Expand Down
2 changes: 1 addition & 1 deletion libs/sdk-ui-charts/src/charts/treemap/Treemap.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ function getDefaultTreemapSort(buckets: IBucket[]): ISortItem[] {
const measures = bucketsMeasures(buckets);

return [
newAttributeSort(viewAttribute, "asc", false),
newAttributeSort(viewAttribute, "asc"),
...measures.map((measure) => newMeasureSort(measure, "desc")),
];
}
Expand Down
Loading

0 comments on commit e3d400e

Please sign in to comment.