@sisense/sdk-data 0.14.0 → 0.15.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -339,3 +339,6 @@ export interface Filter extends Element {
339
339
  */
340
340
  filterJaql(): any;
341
341
  }
342
+ export interface CustomFormulaContext {
343
+ [key: string]: Attribute | Measure;
344
+ }
@@ -1,4 +1,4 @@
1
- import { Attribute, Measure, Filter, CalculatedMeasure, BaseMeasure } from '../interfaces.js';
1
+ import { Attribute, Measure, Filter, CalculatedMeasure, BaseMeasure, CustomFormulaContext } from '../interfaces.js';
2
2
  import { ForecastFormulaOptions, TrendFormulaOptions } from '../../interfaces.js';
3
3
  /**
4
4
  * Defines the different numeric operators that can be used with numeric filters
@@ -32,6 +32,66 @@ export declare const RankingSortTypes: {
32
32
  Ascending: string;
33
33
  Descending: string;
34
34
  };
35
+ /**
36
+ * Creates a calculated measure for a [valid custom formula](https://docs.sisense.com/main/SisenseLinux/dashboard-functions-reference.htm).
37
+ *
38
+ * Use square brackets within the `formula` to include dimensions or measures.
39
+ * Each unique dimension or measure included in the `formula` must be defined using a property:value pair in the `context` parameter.
40
+ *
41
+ * You can nest custom formulas by placing one inside the `formula` parameter of another
42
+ *
43
+ *
44
+ * Note: Shared formula must be fetched prior to use (see {@link @sisense/sdk-ui!useGetSharedFormula | useGetSharedFormula}).
45
+ *
46
+ * @example
47
+ * An example of constructing a `customFormula` using dimensions, measures, and nested custom formulas:
48
+ * ```tsx
49
+ * const profitabilityRatio = measures.customFormula(
50
+ * 'Profitability Ratio',
51
+ * '([totalRevenue] - SUM([cost])) / [totalRevenue]',
52
+ * {
53
+ * totalRevenue: measures.sum(DM.Commerce.Revenue),
54
+ * cost: DM.Commerce.Cost,
55
+ * },
56
+ * );
57
+ *
58
+ * const profitabilityRatioRank = measures.customFormula(
59
+ * 'Profitability Ratio Rank',
60
+ * 'RANK([profRatio], "ASC", "1224")',
61
+ * {
62
+ * profRatio: profitabilityRatio,
63
+ * },
64
+ * );
65
+ *
66
+ * return (
67
+ * <Chart
68
+ * dataSet={DM.DataSource}
69
+ * chartType="line"
70
+ * dataOptions={{
71
+ * category: [DM.Commerce.AgeRange],
72
+ * value: [
73
+ * profitabilityRatioRank,
74
+ * {
75
+ * column: measures.sum(DM.Commerce.Revenue, 'Total Revenue'),
76
+ * showOnRightAxis: true,
77
+ * chartType: 'column',
78
+ * },
79
+ * {
80
+ * column: measures.sum(DM.Commerce.Cost, 'Total Cost'),
81
+ * showOnRightAxis: true,
82
+ * chartType: 'column',
83
+ * },
84
+ * ],
85
+ * }}
86
+ * />
87
+ * );
88
+ * ```
89
+ * @param title - Title of the measure to be displayed in legend
90
+ * @param formula - Formula to be used for the measure
91
+ * @param context - Formula context as a map of strings to measures or attributes
92
+ * @returns A calculated measure object that may be used in a chart or a query
93
+ */
94
+ export declare function customFormula(title: string, formula: string, context: CustomFormulaContext): Attribute | Measure;
35
95
  /**
36
96
  * Creates a basic aggregated measure.
37
97
  * This is a base function to build other aggregation functions (e.g., `sum`, `average`, etc)
@@ -1,6 +1,9 @@
1
1
  import { DimensionalBaseMeasure, DimensionalCalculatedMeasure } from './measures.js';
2
- import { AggregationTypes, MetadataTypes } from '../types.js';
2
+ import { AggregationTypes, MetadataTypes, Sort } from '../types.js';
3
3
  import { normalizeName } from '../base.js';
4
+ import { mapValues } from 'lodash';
5
+ import { DimensionalAttribute, DimensionalLevelAttribute } from '../attributes.js';
6
+ import { isDatetime, isNumber } from './../simple-column-types.js';
4
7
  /**
5
8
  * Defines the different numeric operators that can be used with numeric filters
6
9
  *
@@ -70,6 +73,96 @@ function measureFunction(measure, name, func, options) {
70
73
  builder.push(')');
71
74
  return new DimensionalCalculatedMeasure(name, builder.join(''), context);
72
75
  }
76
+ function transformCustomFormulaJaql(jaql) {
77
+ var _a;
78
+ const isFormulaJaql = 'formula' in jaql;
79
+ let sort;
80
+ if (jaql.sort) {
81
+ sort = jaql.sort === 'asc' ? Sort.Ascending : Sort.Descending;
82
+ }
83
+ if (isFormulaJaql) {
84
+ const context = mapValues((_a = jaql.context) !== null && _a !== void 0 ? _a : {}, (jaqlContextValue) => jaqlContextValue ? transformCustomFormulaJaql(jaqlContextValue) : {});
85
+ return new DimensionalCalculatedMeasure(jaql.title, jaql.formula, context, undefined, undefined, sort);
86
+ }
87
+ const hasAggregation = !!jaql.agg;
88
+ const isDatatypeDatetime = isDatetime(jaql.datatype);
89
+ const attributeType = isNumber(jaql.datatype)
90
+ ? MetadataTypes.NumericAttribute
91
+ : MetadataTypes.TextAttribute;
92
+ const attribute = isDatatypeDatetime
93
+ ? new DimensionalLevelAttribute(jaql.title, jaql.dim, DimensionalLevelAttribute.translateJaqlToGranularity(jaql), undefined, undefined, sort)
94
+ : new DimensionalAttribute(jaql.title, jaql.dim, attributeType, undefined, sort);
95
+ if (hasAggregation) {
96
+ return new DimensionalBaseMeasure(jaql.title, attribute, DimensionalBaseMeasure.aggregationFromJAQL(jaql.agg || ''), undefined, undefined, sort);
97
+ }
98
+ return attribute;
99
+ }
100
+ /**
101
+ * Creates a calculated measure for a [valid custom formula](https://docs.sisense.com/main/SisenseLinux/dashboard-functions-reference.htm).
102
+ *
103
+ * Use square brackets within the `formula` to include dimensions or measures.
104
+ * Each unique dimension or measure included in the `formula` must be defined using a property:value pair in the `context` parameter.
105
+ *
106
+ * You can nest custom formulas by placing one inside the `formula` parameter of another
107
+ *
108
+ *
109
+ * Note: Shared formula must be fetched prior to use (see {@link @sisense/sdk-ui!useGetSharedFormula | useGetSharedFormula}).
110
+ *
111
+ * @example
112
+ * An example of constructing a `customFormula` using dimensions, measures, and nested custom formulas:
113
+ * ```tsx
114
+ * const profitabilityRatio = measures.customFormula(
115
+ * 'Profitability Ratio',
116
+ * '([totalRevenue] - SUM([cost])) / [totalRevenue]',
117
+ * {
118
+ * totalRevenue: measures.sum(DM.Commerce.Revenue),
119
+ * cost: DM.Commerce.Cost,
120
+ * },
121
+ * );
122
+ *
123
+ * const profitabilityRatioRank = measures.customFormula(
124
+ * 'Profitability Ratio Rank',
125
+ * 'RANK([profRatio], "ASC", "1224")',
126
+ * {
127
+ * profRatio: profitabilityRatio,
128
+ * },
129
+ * );
130
+ *
131
+ * return (
132
+ * <Chart
133
+ * dataSet={DM.DataSource}
134
+ * chartType="line"
135
+ * dataOptions={{
136
+ * category: [DM.Commerce.AgeRange],
137
+ * value: [
138
+ * profitabilityRatioRank,
139
+ * {
140
+ * column: measures.sum(DM.Commerce.Revenue, 'Total Revenue'),
141
+ * showOnRightAxis: true,
142
+ * chartType: 'column',
143
+ * },
144
+ * {
145
+ * column: measures.sum(DM.Commerce.Cost, 'Total Cost'),
146
+ * showOnRightAxis: true,
147
+ * chartType: 'column',
148
+ * },
149
+ * ],
150
+ * }}
151
+ * />
152
+ * );
153
+ * ```
154
+ * @param title - Title of the measure to be displayed in legend
155
+ * @param formula - Formula to be used for the measure
156
+ * @param context - Formula context as a map of strings to measures or attributes
157
+ * @returns A calculated measure object that may be used in a chart or a query
158
+ */
159
+ export function customFormula(title, formula, context) {
160
+ const newContext = Object.entries(context).reduce((acc, [key, val]) => {
161
+ acc[`[${key}]`] = val.jaql().jaql;
162
+ return acc;
163
+ }, {});
164
+ return transformCustomFormulaJaql({ title, formula, context: newContext });
165
+ }
73
166
  function arithmetic(operand1, operator, operand2, name, withParentheses) {
74
167
  const builder = [];
75
168
  const context = {};
@@ -150,3 +150,55 @@ export declare const DateLevels: {
150
150
  /** @internal */
151
151
  readonly all: string[];
152
152
  };
153
+ export declare enum DataType {
154
+ TEXT = "text",
155
+ NUMERIC = "numeric",
156
+ DATETIME = "datetime"
157
+ }
158
+ export declare enum SortDirection {
159
+ ASC = "asc",
160
+ DESC = "desc"
161
+ }
162
+ export declare type Jaql = BaseJaql | FormulaJaql | FilterJaql;
163
+ export declare type BaseJaql = {
164
+ agg?: string;
165
+ datatype: DataType;
166
+ dim: string;
167
+ table: string;
168
+ column: string;
169
+ title: string;
170
+ level?: 'years' | 'quarters' | 'months' | 'weeks' | 'minutes' | 'days';
171
+ sort?: SortDirection;
172
+ };
173
+ export declare type FormulaID = string;
174
+ export declare type FormulaContext = BaseJaql | FormulaJaql | FilterJaql;
175
+ export declare type FormulaJaql = {
176
+ type?: 'measure';
177
+ sort?: SortDirection;
178
+ title: string;
179
+ formula: string;
180
+ context?: Record<FormulaID, FormulaContext>;
181
+ };
182
+ export declare type BaseFilter = IncludeAllFilter | IncludeMembersFilter | ExcludeMembersFilter;
183
+ export declare type BackgroundFilter = BaseFilter & {
184
+ level?: 'string';
185
+ };
186
+ export declare type IncludeAllFilter = {
187
+ all: true;
188
+ };
189
+ export declare type IncludeMembersFilter = {
190
+ members: string[];
191
+ };
192
+ export declare type ExcludeMembersFilter = {
193
+ exclude: {
194
+ members: string[];
195
+ };
196
+ };
197
+ export declare type TurnOffMembersFilter = ExcludeMembersFilter & {
198
+ turnedOff: boolean;
199
+ };
200
+ export declare type FilterJaql = BaseJaql & {
201
+ filter: BaseFilter & {
202
+ filter?: BackgroundFilter | TurnOffMembersFilter;
203
+ };
204
+ };
@@ -282,3 +282,14 @@ export const DateLevels = {
282
282
  ];
283
283
  },
284
284
  };
285
+ export var DataType;
286
+ (function (DataType) {
287
+ DataType["TEXT"] = "text";
288
+ DataType["NUMERIC"] = "numeric";
289
+ DataType["DATETIME"] = "datetime";
290
+ })(DataType = DataType || (DataType = {}));
291
+ export var SortDirection;
292
+ (function (SortDirection) {
293
+ SortDirection["ASC"] = "asc";
294
+ SortDirection["DESC"] = "desc";
295
+ })(SortDirection = SortDirection || (SortDirection = {}));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sisense/sdk-data",
3
- "version": "0.14.0",
3
+ "version": "0.15.0",
4
4
  "type": "module",
5
5
  "exports": {
6
6
  ".": "./dist/index.js",
@@ -12,8 +12,9 @@
12
12
  "author": "Sisense ",
13
13
  "license": "SEE LICENSE IN LICENSE.md",
14
14
  "dependencies": {
15
- "@sisense/sdk-rest-client": "^0.14.0",
15
+ "@sisense/sdk-rest-client": "^0.15.0",
16
16
  "guid-typescript": "^1.0.9",
17
+ "lodash": "^4.17.21",
17
18
  "numeral": "^2.0.6",
18
19
  "object-hash": "^3.0.0"
19
20
  },
@@ -37,6 +38,7 @@
37
38
  ],
38
39
  "devDependencies": {
39
40
  "@babel/preset-env": "^7.20.2",
41
+ "@types/lodash": "^4.14.201",
40
42
  "@types/numeral": "2.0.2",
41
43
  "@types/object-hash": "^3.0.5",
42
44
  "eslint": "^8.40.0",