@sisense/sdk-data 1.27.1 → 1.29.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.
- package/dist/cjs/dimensional-model/attributes.d.ts +2 -2
- package/dist/cjs/dimensional-model/attributes.js +7 -7
- package/dist/cjs/dimensional-model/base.d.ts +7 -1
- package/dist/cjs/dimensional-model/base.js +2 -1
- package/dist/cjs/dimensional-model/filters/factory.d.ts +23 -0
- package/dist/cjs/dimensional-model/filters/factory.js +28 -1
- package/dist/cjs/dimensional-model/filters/filter-config-utils.d.ts +4 -0
- package/dist/cjs/dimensional-model/filters/filter-config-utils.js +5 -2
- package/dist/cjs/dimensional-model/filters/filter-relations.d.ts +187 -0
- package/dist/cjs/dimensional-model/filters/filter-relations.js +532 -0
- package/dist/cjs/dimensional-model/filters/filters.d.ts +3 -3
- package/dist/cjs/dimensional-model/filters/filters.js +7 -8
- package/dist/cjs/dimensional-model/filters/helpers.d.ts +112 -0
- package/dist/cjs/dimensional-model/filters/helpers.js +178 -0
- package/dist/cjs/dimensional-model/filters/index.d.ts +2 -0
- package/dist/cjs/dimensional-model/filters/index.js +18 -0
- package/dist/cjs/dimensional-model/filters/utils/attribute-measure-util.d.ts +1 -35
- package/dist/cjs/dimensional-model/filters/utils/attribute-measure-util.js +37 -101
- package/dist/cjs/dimensional-model/interfaces.d.ts +2 -0
- package/dist/cjs/dimensional-model/measures/factory.js +1 -32
- package/dist/cjs/dimensional-model/measures/measures.d.ts +3 -3
- package/dist/cjs/dimensional-model/measures/measures.js +10 -9
- package/dist/cjs/index.d.ts +1 -1
- package/dist/cjs/index.js +1 -1
- package/dist/cjs/interfaces.d.ts +2 -2
- package/dist/cjs/utils.d.ts +74 -2
- package/dist/cjs/utils.js +138 -3
- package/dist/dimensional-model/attributes.d.ts +2 -2
- package/dist/dimensional-model/attributes.js +7 -7
- package/dist/dimensional-model/base.d.ts +7 -1
- package/dist/dimensional-model/base.js +2 -1
- package/dist/dimensional-model/filters/factory.d.ts +23 -0
- package/dist/dimensional-model/filters/factory.js +27 -1
- package/dist/dimensional-model/filters/filter-config-utils.d.ts +4 -0
- package/dist/dimensional-model/filters/filter-config-utils.js +5 -2
- package/dist/dimensional-model/filters/filter-relations.d.ts +187 -0
- package/dist/dimensional-model/filters/filter-relations.js +507 -0
- package/dist/dimensional-model/filters/filters.d.ts +3 -3
- package/dist/dimensional-model/filters/filters.js +7 -8
- package/dist/dimensional-model/filters/helpers.d.ts +112 -0
- package/dist/dimensional-model/filters/helpers.js +169 -0
- package/dist/dimensional-model/filters/index.d.ts +2 -0
- package/dist/dimensional-model/filters/index.js +2 -0
- package/dist/dimensional-model/filters/utils/attribute-measure-util.d.ts +1 -35
- package/dist/dimensional-model/filters/utils/attribute-measure-util.js +36 -74
- package/dist/dimensional-model/interfaces.d.ts +2 -0
- package/dist/dimensional-model/measures/factory.js +2 -30
- package/dist/dimensional-model/measures/measures.d.ts +3 -3
- package/dist/dimensional-model/measures/measures.js +10 -9
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/interfaces.d.ts +2 -2
- package/dist/tsconfig.prod.cjs.tsbuildinfo +1 -1
- package/dist/utils.d.ts +74 -2
- package/dist/utils.js +133 -2
- package/package.json +4 -3
- package/dist/cjs/dimensional-model/filter-relations.d.ts +0 -9
- package/dist/cjs/dimensional-model/filter-relations.js +0 -18
- package/dist/dimensional-model/filter-relations.d.ts +0 -9
- package/dist/dimensional-model/filter-relations.js +0 -14
|
@@ -0,0 +1,532 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.convertFilterRelationsModelToJaql = exports.getFilterRelationsFromJaql = exports.mergeFilters = exports.getFilterCompareId = exports.isOperatorDescriptionNode = exports.isAttributeDescriptionNode = exports.isCloseBracketDescriptionNode = exports.isOpenBracketDescriptionNode = exports.UnknownRelationsNodeError = exports.findFilterByGuid = exports.filterRelationRulesToFilterRelationsModel = exports.isRelationsRule = exports.isRelationsRuleIdNode = exports.convertFilterRelationsModelToRelationRules = exports.getRelationsWithReplacedFilter = exports.calculateNewRelations = exports.isTrivialSingleNodeRelations = exports.combineFiltersAndRelations = exports.getFiltersArray = exports.splitFiltersAndRelations = exports.mergeFiltersOrFilterRelations = exports.isFilterRelations = void 0;
|
|
4
|
+
/* eslint-disable @typescript-eslint/default-param-last */
|
|
5
|
+
const index_js_1 = require("../../index.js");
|
|
6
|
+
const lodash_es_1 = require("lodash-es");
|
|
7
|
+
const translatable_error_js_1 = require("../../translation/translatable-error.js");
|
|
8
|
+
/**
|
|
9
|
+
* Type guard for checking if the provided filters are FilterRelations.
|
|
10
|
+
*
|
|
11
|
+
* @param filters - The filters to check.
|
|
12
|
+
* @returns `true` if the filters are FilterRelations, `false` otherwise.
|
|
13
|
+
* @group Filter Utilities
|
|
14
|
+
*/
|
|
15
|
+
function isFilterRelations(filters) {
|
|
16
|
+
return (!!filters &&
|
|
17
|
+
'operator' in filters &&
|
|
18
|
+
(filters.operator === 'AND' || filters.operator === 'OR') &&
|
|
19
|
+
!!filters.right &&
|
|
20
|
+
!!filters.left);
|
|
21
|
+
}
|
|
22
|
+
exports.isFilterRelations = isFilterRelations;
|
|
23
|
+
/**
|
|
24
|
+
* Merges source filters with target filters and recalculates relations.
|
|
25
|
+
*
|
|
26
|
+
* @param sourceFilters - The source filters or filter relations to merge.
|
|
27
|
+
* @param targetFilters - The target filters or filter relations to merge with.
|
|
28
|
+
* @returns Updated source filters merged with target filters. If the source filters are FilterRelations, the relations are recalculated.
|
|
29
|
+
* @internal
|
|
30
|
+
*/
|
|
31
|
+
function mergeFiltersOrFilterRelations(sourceFilters = [], targetFilters = []) {
|
|
32
|
+
if (!isFilterRelations(sourceFilters) && !isFilterRelations(targetFilters)) {
|
|
33
|
+
return mergeFilters(sourceFilters, targetFilters);
|
|
34
|
+
}
|
|
35
|
+
const { filters: pureSourceFilters, relations: sourceRelations } = splitFiltersAndRelations(sourceFilters);
|
|
36
|
+
const pureTargetFilters = getFiltersArray(targetFilters);
|
|
37
|
+
const mergedFilters = mergeFilters(pureSourceFilters, pureTargetFilters);
|
|
38
|
+
const mergedRelations = calculateNewRelations(pureSourceFilters, sourceRelations, mergedFilters);
|
|
39
|
+
return combineFiltersAndRelations(mergedFilters, mergedRelations);
|
|
40
|
+
}
|
|
41
|
+
exports.mergeFiltersOrFilterRelations = mergeFiltersOrFilterRelations;
|
|
42
|
+
/**
|
|
43
|
+
* Splits filters or filter relations into filters and relations rules.
|
|
44
|
+
* @internal
|
|
45
|
+
*/
|
|
46
|
+
function splitFiltersAndRelations(filtersOrFilterRelations) {
|
|
47
|
+
if (!filtersOrFilterRelations) {
|
|
48
|
+
return { filters: [], relations: null };
|
|
49
|
+
}
|
|
50
|
+
if ((0, lodash_es_1.isArray)(filtersOrFilterRelations)) {
|
|
51
|
+
return { filters: filtersOrFilterRelations, relations: null };
|
|
52
|
+
}
|
|
53
|
+
const filtersSet = new Set();
|
|
54
|
+
function traverse(node) {
|
|
55
|
+
if (isFilterNode(node)) {
|
|
56
|
+
filtersSet.add(node);
|
|
57
|
+
return { instanceid: node.config.guid };
|
|
58
|
+
}
|
|
59
|
+
if (isFilterRelations(node)) {
|
|
60
|
+
const left = traverse(node.left);
|
|
61
|
+
const right = traverse(node.right);
|
|
62
|
+
return { left, right, operator: node.operator };
|
|
63
|
+
}
|
|
64
|
+
throw new UnknownRelationsNodeError();
|
|
65
|
+
}
|
|
66
|
+
const relations = traverse(filtersOrFilterRelations);
|
|
67
|
+
return {
|
|
68
|
+
filters: Array.from(filtersSet),
|
|
69
|
+
relations,
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
exports.splitFiltersAndRelations = splitFiltersAndRelations;
|
|
73
|
+
/**
|
|
74
|
+
* Returns pure filters array from the given filters or filter relations.
|
|
75
|
+
* @internal
|
|
76
|
+
*/
|
|
77
|
+
function getFiltersArray(filtersOrFilterRelations) {
|
|
78
|
+
if (!filtersOrFilterRelations) {
|
|
79
|
+
return [];
|
|
80
|
+
}
|
|
81
|
+
return splitFiltersAndRelations(filtersOrFilterRelations).filters;
|
|
82
|
+
}
|
|
83
|
+
exports.getFiltersArray = getFiltersArray;
|
|
84
|
+
/**
|
|
85
|
+
* Combines filters and relations into a single FilterRelations object.
|
|
86
|
+
* If the relations are empty or relations are trivial (single node), the filters are returned as is.
|
|
87
|
+
* @internal
|
|
88
|
+
*/
|
|
89
|
+
function combineFiltersAndRelations(filters, relations) {
|
|
90
|
+
if (!relations || isTrivialSingleNodeRelations(relations)) {
|
|
91
|
+
return filters;
|
|
92
|
+
}
|
|
93
|
+
const resultRelations = traverse(relations);
|
|
94
|
+
return isFilterNode(resultRelations) ? [resultRelations] : resultRelations;
|
|
95
|
+
function traverse(node) {
|
|
96
|
+
if (isRelationsRuleIdNode(node)) {
|
|
97
|
+
return filters.find((filter) => filter.config.guid === node.instanceid);
|
|
98
|
+
}
|
|
99
|
+
if (isRelationsRule(node)) {
|
|
100
|
+
return {
|
|
101
|
+
left: traverse(node.left),
|
|
102
|
+
right: traverse(node.right),
|
|
103
|
+
operator: node.operator,
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
throw new UnknownRelationsNodeError();
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
exports.combineFiltersAndRelations = combineFiltersAndRelations;
|
|
110
|
+
/** Type guard for checking if a node is a single relations node (trivial case when relations are needless).
|
|
111
|
+
* @internal
|
|
112
|
+
*/
|
|
113
|
+
function isTrivialSingleNodeRelations(relations) {
|
|
114
|
+
return !!relations && 'instanceid' in relations;
|
|
115
|
+
}
|
|
116
|
+
exports.isTrivialSingleNodeRelations = isTrivialSingleNodeRelations;
|
|
117
|
+
/**
|
|
118
|
+
* Calculates new relations based on the changes in filters.
|
|
119
|
+
* @internal
|
|
120
|
+
*/
|
|
121
|
+
function calculateNewRelations(prevFilters, prevRelations, newFilters) {
|
|
122
|
+
// If there are no previous relations - no need to recalculate them
|
|
123
|
+
if (prevRelations === null) {
|
|
124
|
+
return null;
|
|
125
|
+
}
|
|
126
|
+
const performedActions = diffFilters(prevFilters, newFilters);
|
|
127
|
+
if (performedActions.length === 0) {
|
|
128
|
+
return prevRelations;
|
|
129
|
+
}
|
|
130
|
+
return performedActions.reduce((relations, action) => {
|
|
131
|
+
switch (action.type) {
|
|
132
|
+
case 'add':
|
|
133
|
+
return addFilterToRelations(action.payload, relations);
|
|
134
|
+
case 'remove':
|
|
135
|
+
return removeFilterFromRelations(action.payload, relations);
|
|
136
|
+
}
|
|
137
|
+
}, prevRelations);
|
|
138
|
+
}
|
|
139
|
+
exports.calculateNewRelations = calculateNewRelations;
|
|
140
|
+
/**
|
|
141
|
+
* Compares two filters and determines if they are equal in terms of relations.
|
|
142
|
+
*/
|
|
143
|
+
function areFiltersEqualForRelations(filter1, filter2) {
|
|
144
|
+
return filter1.config.guid === filter2.config.guid;
|
|
145
|
+
}
|
|
146
|
+
/**
|
|
147
|
+
* Replaces a filter in the relations tree with a new filter.
|
|
148
|
+
* @internal
|
|
149
|
+
*/
|
|
150
|
+
function getRelationsWithReplacedFilter(relations, filterToReplace, newFilter) {
|
|
151
|
+
if (!relations) {
|
|
152
|
+
return null;
|
|
153
|
+
}
|
|
154
|
+
const replacedRelations = traverse(relations);
|
|
155
|
+
return replacedRelations;
|
|
156
|
+
function traverse(node) {
|
|
157
|
+
if (isRelationsRuleIdNode(node)) {
|
|
158
|
+
return node.instanceid === filterToReplace.config.guid
|
|
159
|
+
? { instanceid: newFilter.config.guid }
|
|
160
|
+
: node;
|
|
161
|
+
}
|
|
162
|
+
if (isRelationsRule(node)) {
|
|
163
|
+
return {
|
|
164
|
+
left: traverse(node.left),
|
|
165
|
+
right: traverse(node.right),
|
|
166
|
+
operator: node.operator,
|
|
167
|
+
};
|
|
168
|
+
}
|
|
169
|
+
throw new UnknownRelationsNodeError();
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
exports.getRelationsWithReplacedFilter = getRelationsWithReplacedFilter;
|
|
173
|
+
/**
|
|
174
|
+
* Compares two arrays of Filter objects and determines the actions needed
|
|
175
|
+
* to transform prevFilters into newFilters.
|
|
176
|
+
*
|
|
177
|
+
* @param prevFilters - The original array of filters.
|
|
178
|
+
* @param newFilters - The updated array of filters.
|
|
179
|
+
* @param isEqualFilters - A function to determine if two filters are equal.
|
|
180
|
+
* @returns An array of FilterAction objects representing the changes.
|
|
181
|
+
*/
|
|
182
|
+
function diffFilters(prevFilters, newFilters) {
|
|
183
|
+
const actions = [];
|
|
184
|
+
// Clone the arrays to avoid mutating the original data
|
|
185
|
+
const prevFiltersCopy = [...prevFilters];
|
|
186
|
+
const newFiltersCopy = [...newFilters];
|
|
187
|
+
// Determine removals
|
|
188
|
+
prevFiltersCopy.forEach((prevFilter) => {
|
|
189
|
+
const existsInNew = newFiltersCopy.some((newFilter) => areFiltersEqualForRelations(prevFilter, newFilter));
|
|
190
|
+
if (!existsInNew) {
|
|
191
|
+
actions.push({ type: 'remove', payload: prevFilter });
|
|
192
|
+
}
|
|
193
|
+
});
|
|
194
|
+
// Determine additions
|
|
195
|
+
newFiltersCopy.forEach((newFilter) => {
|
|
196
|
+
const existsInPrev = prevFiltersCopy.some((prevFilter) => areFiltersEqualForRelations(newFilter, prevFilter));
|
|
197
|
+
if (!existsInPrev) {
|
|
198
|
+
actions.push({ type: 'add', payload: newFilter });
|
|
199
|
+
}
|
|
200
|
+
});
|
|
201
|
+
return actions;
|
|
202
|
+
}
|
|
203
|
+
/**
|
|
204
|
+
* Adds a filter to root of relations tree as a new node connected with AND operator.
|
|
205
|
+
* If the relations tree is empty, the filter is added as the root node.
|
|
206
|
+
*/
|
|
207
|
+
function addFilterToRelations(filter, relations) {
|
|
208
|
+
if (!relations) {
|
|
209
|
+
return { instanceid: filter.config.guid };
|
|
210
|
+
}
|
|
211
|
+
return {
|
|
212
|
+
left: relations,
|
|
213
|
+
right: { instanceid: filter.config.guid },
|
|
214
|
+
operator: 'AND',
|
|
215
|
+
};
|
|
216
|
+
}
|
|
217
|
+
/**
|
|
218
|
+
* Removes a filter from the relations tree.
|
|
219
|
+
* If the filter is not found, the relations tree is returned as is.
|
|
220
|
+
*/
|
|
221
|
+
function removeFilterFromRelations(filter, relations) {
|
|
222
|
+
if (!relations) {
|
|
223
|
+
return null;
|
|
224
|
+
}
|
|
225
|
+
if (isTrivialSingleNodeRelations(relations)) {
|
|
226
|
+
return relations.instanceid === filter.config.guid ? null : relations;
|
|
227
|
+
}
|
|
228
|
+
const leftAfterRemoval = removeFilterFromRelations(filter, relations.left);
|
|
229
|
+
const rightAfterRemoval = removeFilterFromRelations(filter, relations.right);
|
|
230
|
+
if (leftAfterRemoval === null && !!rightAfterRemoval) {
|
|
231
|
+
return rightAfterRemoval;
|
|
232
|
+
}
|
|
233
|
+
if (rightAfterRemoval === null && !!leftAfterRemoval) {
|
|
234
|
+
return leftAfterRemoval;
|
|
235
|
+
}
|
|
236
|
+
if (leftAfterRemoval === null && rightAfterRemoval === null) {
|
|
237
|
+
return null;
|
|
238
|
+
}
|
|
239
|
+
return {
|
|
240
|
+
left: leftAfterRemoval,
|
|
241
|
+
right: rightAfterRemoval,
|
|
242
|
+
operator: relations.operator,
|
|
243
|
+
};
|
|
244
|
+
}
|
|
245
|
+
/**
|
|
246
|
+
* Converts filter relations model from Fusion to internal CSDK filter relations rules.
|
|
247
|
+
* @internal
|
|
248
|
+
*/
|
|
249
|
+
function convertFilterRelationsModelToRelationRules(filterRelationsModel, filters) {
|
|
250
|
+
if (!filterRelationsModel) {
|
|
251
|
+
return null;
|
|
252
|
+
}
|
|
253
|
+
function traverse(node) {
|
|
254
|
+
if (isModelIdNode(node)) {
|
|
255
|
+
return { instanceid: node.instanceId };
|
|
256
|
+
}
|
|
257
|
+
if (isModelBracketNode(node)) {
|
|
258
|
+
return traverse(node.value);
|
|
259
|
+
}
|
|
260
|
+
if (isModelRelationNode(node)) {
|
|
261
|
+
const newNode = {
|
|
262
|
+
operator: node.operator,
|
|
263
|
+
left: traverse(node.left),
|
|
264
|
+
right: traverse(node.right),
|
|
265
|
+
};
|
|
266
|
+
return newNode;
|
|
267
|
+
}
|
|
268
|
+
if (isModelCascadeNode(node)) {
|
|
269
|
+
// CSDK filter relations model work with cascading filters as with a single node.
|
|
270
|
+
const cascadingFilterForThisCascade = filters.find((filter) => {
|
|
271
|
+
if (!(0, index_js_1.isCascadingFilter)(filter)) {
|
|
272
|
+
return false;
|
|
273
|
+
}
|
|
274
|
+
const levelIds = filter.filters.map((f) => f.config.guid);
|
|
275
|
+
return node.levels.every((levelFilter) => levelIds.includes(levelFilter.instanceId));
|
|
276
|
+
});
|
|
277
|
+
if (cascadingFilterForThisCascade) {
|
|
278
|
+
return { instanceid: cascadingFilterForThisCascade.config.guid };
|
|
279
|
+
}
|
|
280
|
+
throw new Error('Broken filter relations model. Cascading filter not found.');
|
|
281
|
+
}
|
|
282
|
+
throw new Error('Broken filter relations model. Unknown node type.');
|
|
283
|
+
}
|
|
284
|
+
return traverse(filterRelationsModel);
|
|
285
|
+
}
|
|
286
|
+
exports.convertFilterRelationsModelToRelationRules = convertFilterRelationsModelToRelationRules;
|
|
287
|
+
function isModelIdNode(node) {
|
|
288
|
+
return 'instanceId' in node;
|
|
289
|
+
}
|
|
290
|
+
function isModelBracketNode(node) {
|
|
291
|
+
return 'value' in node;
|
|
292
|
+
}
|
|
293
|
+
function isModelRelationNode(node) {
|
|
294
|
+
return 'operator' in node;
|
|
295
|
+
}
|
|
296
|
+
function isModelCascadeNode(node) {
|
|
297
|
+
return 'levels' in node && (0, lodash_es_1.isArray)(node.levels);
|
|
298
|
+
}
|
|
299
|
+
/**
|
|
300
|
+
* @internal
|
|
301
|
+
*/
|
|
302
|
+
function isRelationsRuleIdNode(node) {
|
|
303
|
+
return 'instanceid' in node;
|
|
304
|
+
}
|
|
305
|
+
exports.isRelationsRuleIdNode = isRelationsRuleIdNode;
|
|
306
|
+
/**
|
|
307
|
+
* @internal
|
|
308
|
+
*/
|
|
309
|
+
function isRelationsRule(node) {
|
|
310
|
+
return 'operator' in node;
|
|
311
|
+
}
|
|
312
|
+
exports.isRelationsRule = isRelationsRule;
|
|
313
|
+
function isFilterNode(node) {
|
|
314
|
+
return 'config' in node && 'guid' in node.config;
|
|
315
|
+
}
|
|
316
|
+
/**
|
|
317
|
+
* Converts internal CSDK filter relations rules to filter relations model for Fusion.
|
|
318
|
+
* @internal
|
|
319
|
+
*/
|
|
320
|
+
function filterRelationRulesToFilterRelationsModel(filterRelationRules, filters) {
|
|
321
|
+
if (!filterRelationRules) {
|
|
322
|
+
return undefined;
|
|
323
|
+
}
|
|
324
|
+
function traverse(node) {
|
|
325
|
+
if (isRelationsRuleIdNode(node)) {
|
|
326
|
+
// Check if this instanceid corresponds to a cascading filter
|
|
327
|
+
const filter = filters.find((f) => f.config.guid === node.instanceid);
|
|
328
|
+
if (filter && (0, index_js_1.isCascadingFilter)(filter)) {
|
|
329
|
+
// Build a CascadingIdentifier node
|
|
330
|
+
const levels = filter.filters.map((levelFilter) => ({
|
|
331
|
+
type: 'Identifier',
|
|
332
|
+
instanceId: levelFilter.config.guid,
|
|
333
|
+
}));
|
|
334
|
+
return {
|
|
335
|
+
type: 'CascadingIdentifier',
|
|
336
|
+
levels,
|
|
337
|
+
};
|
|
338
|
+
}
|
|
339
|
+
else {
|
|
340
|
+
// Build an Identifier node
|
|
341
|
+
return {
|
|
342
|
+
type: 'Identifier',
|
|
343
|
+
instanceId: node.instanceid,
|
|
344
|
+
};
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
else if (isRelationsRule(node)) {
|
|
348
|
+
// Build a LogicalExpression node
|
|
349
|
+
return {
|
|
350
|
+
type: 'LogicalExpression',
|
|
351
|
+
operator: node.operator,
|
|
352
|
+
left: traverse(node.left),
|
|
353
|
+
right: traverse(node.right),
|
|
354
|
+
};
|
|
355
|
+
}
|
|
356
|
+
else {
|
|
357
|
+
throw new Error('Unknown node type in filter relations rules.');
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
return traverse(filterRelationRules);
|
|
361
|
+
}
|
|
362
|
+
exports.filterRelationRulesToFilterRelationsModel = filterRelationRulesToFilterRelationsModel;
|
|
363
|
+
/**
|
|
364
|
+
* @internal
|
|
365
|
+
*/
|
|
366
|
+
function findFilterByGuid(filters, guid) {
|
|
367
|
+
return filters.find((filter) => filter.config.guid === guid);
|
|
368
|
+
}
|
|
369
|
+
exports.findFilterByGuid = findFilterByGuid;
|
|
370
|
+
/**
|
|
371
|
+
* Error thrown when an unknown node type is encountered in filter relations.
|
|
372
|
+
* @internal
|
|
373
|
+
*/
|
|
374
|
+
class UnknownRelationsNodeError extends Error {
|
|
375
|
+
constructor() {
|
|
376
|
+
super('Broken filter relations. Unknown node type.');
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
exports.UnknownRelationsNodeError = UnknownRelationsNodeError;
|
|
380
|
+
/**
|
|
381
|
+
* @internal
|
|
382
|
+
*/
|
|
383
|
+
function isOpenBracketDescriptionNode(node) {
|
|
384
|
+
return node.nodeType === 'openBracket';
|
|
385
|
+
}
|
|
386
|
+
exports.isOpenBracketDescriptionNode = isOpenBracketDescriptionNode;
|
|
387
|
+
/**
|
|
388
|
+
* @internal
|
|
389
|
+
*/
|
|
390
|
+
function isCloseBracketDescriptionNode(node) {
|
|
391
|
+
return node.nodeType === 'closeBracket';
|
|
392
|
+
}
|
|
393
|
+
exports.isCloseBracketDescriptionNode = isCloseBracketDescriptionNode;
|
|
394
|
+
/**
|
|
395
|
+
* @internal
|
|
396
|
+
*/
|
|
397
|
+
function isAttributeDescriptionNode(node) {
|
|
398
|
+
return node.nodeType === 'attribute';
|
|
399
|
+
}
|
|
400
|
+
exports.isAttributeDescriptionNode = isAttributeDescriptionNode;
|
|
401
|
+
/**
|
|
402
|
+
* @internal
|
|
403
|
+
*/
|
|
404
|
+
function isOperatorDescriptionNode(node) {
|
|
405
|
+
return node.nodeType === 'operator';
|
|
406
|
+
}
|
|
407
|
+
exports.isOperatorDescriptionNode = isOperatorDescriptionNode;
|
|
408
|
+
/**
|
|
409
|
+
* Gets a unique identifier for a filter, combining its attribute expression and granularity if available.
|
|
410
|
+
*
|
|
411
|
+
* @param {Filter} filter - The filter object to generate the unique identifier for.
|
|
412
|
+
* @returns {string} - The unique identifier for the filter.
|
|
413
|
+
* @internal
|
|
414
|
+
*/
|
|
415
|
+
function getFilterCompareId(filter) {
|
|
416
|
+
if ((0, index_js_1.isCascadingFilter)(filter)) {
|
|
417
|
+
return filter.filters.map(getFilterCompareId).join('-');
|
|
418
|
+
}
|
|
419
|
+
// TODO: remove fallback on 'filter.jaql()' after removing temporal 'jaql()' workaround from filter translation layer
|
|
420
|
+
const { attribute: filterAttribute } = filter;
|
|
421
|
+
const filterJaql = filter.jaql().jaql;
|
|
422
|
+
const expression = filterAttribute.expression || filterJaql.dim;
|
|
423
|
+
const granularity = filterAttribute.granularity ||
|
|
424
|
+
((filterJaql === null || filterJaql === void 0 ? void 0 : filterJaql.datatype) === 'datetime'
|
|
425
|
+
? index_js_1.DimensionalLevelAttribute.translateJaqlToGranularity(filterJaql)
|
|
426
|
+
: '');
|
|
427
|
+
return `${expression}${granularity}`;
|
|
428
|
+
}
|
|
429
|
+
exports.getFilterCompareId = getFilterCompareId;
|
|
430
|
+
/**
|
|
431
|
+
* Merges two arrays of filter objects, prioritizing 'targetFilters' over 'sourceFilters',
|
|
432
|
+
* and removes duplicates based on filter compare id.
|
|
433
|
+
*
|
|
434
|
+
* Saves the 'sourceFilters' filters order, while adds new filters to the end of the array.
|
|
435
|
+
*
|
|
436
|
+
* @param {Filter[]} [sourceFilters=[]] - The source array of filter objects.
|
|
437
|
+
* @param {Filter[]} [targetFilters=[]] - The target array of filter objects.
|
|
438
|
+
* @returns {Filter[]} - The merged array of filter objects.
|
|
439
|
+
* @internal
|
|
440
|
+
*/
|
|
441
|
+
function mergeFilters(sourceFilters = [], targetFilters = []) {
|
|
442
|
+
const filters = [...sourceFilters];
|
|
443
|
+
targetFilters.forEach((filter) => {
|
|
444
|
+
const existingFilterIndex = filters.findIndex((existingFilter) => getFilterCompareId(filter) === getFilterCompareId(existingFilter));
|
|
445
|
+
const isFilterAlreadyExist = existingFilterIndex !== -1;
|
|
446
|
+
if (isFilterAlreadyExist) {
|
|
447
|
+
filters[existingFilterIndex] = filter;
|
|
448
|
+
}
|
|
449
|
+
else {
|
|
450
|
+
filters.push(filter);
|
|
451
|
+
}
|
|
452
|
+
});
|
|
453
|
+
return filters;
|
|
454
|
+
}
|
|
455
|
+
exports.mergeFilters = mergeFilters;
|
|
456
|
+
/**
|
|
457
|
+
* Replaces nodes of filter reations tree with fetched filters by instance id.
|
|
458
|
+
*
|
|
459
|
+
* @param filters - The filters.
|
|
460
|
+
* @param highlights - The highlights
|
|
461
|
+
* @param filterRelations - Fetched filter relations.
|
|
462
|
+
* @returns Filter relations with filters in nodes.
|
|
463
|
+
* @internal
|
|
464
|
+
*/
|
|
465
|
+
/* eslint-disable-next-line sonarjs/cognitive-complexity */
|
|
466
|
+
function getFilterRelationsFromJaql(filters, highlights, filterRelations) {
|
|
467
|
+
if (!filterRelations) {
|
|
468
|
+
return filters;
|
|
469
|
+
}
|
|
470
|
+
// If highlights are present, nodes in filter relations reference both filters and highlights
|
|
471
|
+
// and thus cannot be replaced with filters. Return filters in this case.
|
|
472
|
+
if (highlights.length) {
|
|
473
|
+
return filters;
|
|
474
|
+
}
|
|
475
|
+
const mergedFilterRelations = (0, lodash_es_1.cloneDeep)(filterRelations);
|
|
476
|
+
function traverse(node) {
|
|
477
|
+
if ('instanceid' in node) {
|
|
478
|
+
const filter = filters.find((filter) => filter.config.guid === node.instanceid);
|
|
479
|
+
if (!filter) {
|
|
480
|
+
throw new translatable_error_js_1.TranslatableError('errors.unknownFilterInFilterRelations');
|
|
481
|
+
}
|
|
482
|
+
return filter;
|
|
483
|
+
}
|
|
484
|
+
if ('operator' in node) {
|
|
485
|
+
const newNode = { operator: node.operator };
|
|
486
|
+
if ('left' in node) {
|
|
487
|
+
newNode.left = traverse(node.left);
|
|
488
|
+
}
|
|
489
|
+
if ('right' in node) {
|
|
490
|
+
newNode.right = traverse(node.right);
|
|
491
|
+
}
|
|
492
|
+
return newNode;
|
|
493
|
+
}
|
|
494
|
+
return node;
|
|
495
|
+
}
|
|
496
|
+
return traverse(mergedFilterRelations);
|
|
497
|
+
}
|
|
498
|
+
exports.getFilterRelationsFromJaql = getFilterRelationsFromJaql;
|
|
499
|
+
/**
|
|
500
|
+
* Converts filter relations model to filter relations jaql.
|
|
501
|
+
*
|
|
502
|
+
* @param filterRelations - Filter relations model.
|
|
503
|
+
* @returns Filter relations jaql.
|
|
504
|
+
* @internal
|
|
505
|
+
*/
|
|
506
|
+
function convertFilterRelationsModelToJaql(filterRelations) {
|
|
507
|
+
if (!filterRelations) {
|
|
508
|
+
return filterRelations;
|
|
509
|
+
}
|
|
510
|
+
const convertedFilterRelations = (0, lodash_es_1.cloneDeep)(filterRelations);
|
|
511
|
+
function traverse(node) {
|
|
512
|
+
if ('instanceId' in node) {
|
|
513
|
+
return { instanceid: node.instanceId };
|
|
514
|
+
}
|
|
515
|
+
if ('value' in node) {
|
|
516
|
+
return traverse(node.value);
|
|
517
|
+
}
|
|
518
|
+
if ('operator' in node) {
|
|
519
|
+
const newNode = { operator: node.operator };
|
|
520
|
+
if ('left' in node) {
|
|
521
|
+
newNode.left = traverse(node.left);
|
|
522
|
+
}
|
|
523
|
+
if ('right' in node) {
|
|
524
|
+
newNode.right = traverse(node.right);
|
|
525
|
+
}
|
|
526
|
+
return newNode;
|
|
527
|
+
}
|
|
528
|
+
return node;
|
|
529
|
+
}
|
|
530
|
+
return traverse(convertedFilterRelations);
|
|
531
|
+
}
|
|
532
|
+
exports.convertFilterRelationsModelToJaql = convertFilterRelationsModelToJaql;
|
|
@@ -166,12 +166,12 @@ export declare class MembersFilter extends AbstractFilter {
|
|
|
166
166
|
* @internal
|
|
167
167
|
*/
|
|
168
168
|
export declare class CascadingFilter extends AbstractFilter {
|
|
169
|
-
readonly
|
|
169
|
+
readonly _filters: Filter[];
|
|
170
170
|
constructor(filters: Filter[], config?: BaseFilterConfig);
|
|
171
171
|
/**
|
|
172
|
-
*
|
|
172
|
+
* Returns the level filters with the root config applied.
|
|
173
173
|
*/
|
|
174
|
-
|
|
174
|
+
get filters(): Filter[];
|
|
175
175
|
/**
|
|
176
176
|
* gets the element's ID
|
|
177
177
|
*/
|
|
@@ -250,24 +250,23 @@ exports.MembersFilter = MembersFilter;
|
|
|
250
250
|
class CascadingFilter extends AbstractFilter {
|
|
251
251
|
constructor(filters, config) {
|
|
252
252
|
super(filters[0].attribute, exports.FilterTypes.cascading, config);
|
|
253
|
-
this.
|
|
254
|
-
this.propagateConfig();
|
|
253
|
+
this._filters = filters;
|
|
255
254
|
}
|
|
256
255
|
/**
|
|
257
|
-
*
|
|
256
|
+
* Returns the level filters with the root config applied.
|
|
258
257
|
*/
|
|
259
|
-
|
|
258
|
+
get filters() {
|
|
260
259
|
const { disabled, locked } = this.config;
|
|
261
|
-
this.
|
|
262
|
-
|
|
263
|
-
|
|
260
|
+
return this._filters.map((filter) => {
|
|
261
|
+
filter.config = Object.assign(Object.assign({}, filter.config), { disabled, locked });
|
|
262
|
+
return filter;
|
|
264
263
|
});
|
|
265
264
|
}
|
|
266
265
|
/**
|
|
267
266
|
* gets the element's ID
|
|
268
267
|
*/
|
|
269
268
|
get id() {
|
|
270
|
-
return `${this.filterType}_${this.
|
|
269
|
+
return `${this.filterType}_${this._filters.map((f) => f.id).join()}`;
|
|
271
270
|
}
|
|
272
271
|
/**
|
|
273
272
|
* Gets a serializable representation of the element
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
import { Filter, FilterRelations } from '../../index.js';
|
|
2
|
+
/**
|
|
3
|
+
* Returns a function that adds a filter to existing filters or filter relations.
|
|
4
|
+
*
|
|
5
|
+
* @param filter - The filter to add.
|
|
6
|
+
* @returns A function that takes existing filters or filter relations and returns updated filters or filter relations with the new filter added.
|
|
7
|
+
* @group Filter Utilities
|
|
8
|
+
* @example
|
|
9
|
+
* ```ts
|
|
10
|
+
* // Using with an array of filters
|
|
11
|
+
* const originalFilters = [filterByAgeRange];
|
|
12
|
+
* const updatedFilters = withAddedFilter(filterByCost)(originalFilters);
|
|
13
|
+
* // [filterByAgeRange, filterByCost]
|
|
14
|
+
*
|
|
15
|
+
* // Using with filter relations
|
|
16
|
+
* const originalFilterRelations = filterFactory.logic.or(filterByAgeRange, filterByRevenue);
|
|
17
|
+
* const updatedFilterRelations = withAddedFilter(filterByCost)(originalFilterRelations);
|
|
18
|
+
* // (filterByAgeRange OR filterByRevenue) AND filterByCost
|
|
19
|
+
* ```
|
|
20
|
+
*/
|
|
21
|
+
export declare function withAddedFilter(filter: Filter): (filters: Filter[] | FilterRelations | undefined) => Filter[] | FilterRelations;
|
|
22
|
+
/**
|
|
23
|
+
* Returns a function that adds multiple filters to existing filters or filter relations.
|
|
24
|
+
*
|
|
25
|
+
* @param filtersToAdd - An array of filters to add.
|
|
26
|
+
* @returns A function that takes existing filters or filter relations and returns updated filters or filter relations with the new filters added.
|
|
27
|
+
* @group Filter Utilities
|
|
28
|
+
* @example
|
|
29
|
+
* ```ts
|
|
30
|
+
* // Using with an array of filters
|
|
31
|
+
* const originalFilters = [filterByAgeRange];
|
|
32
|
+
* const updatedFilters = withAddedFilters([filterByCost, filterByRevenue])(originalFilters);
|
|
33
|
+
* // [filterByAgeRange, filterByCost, filterByRevenue]
|
|
34
|
+
*
|
|
35
|
+
* // Using with filter relations
|
|
36
|
+
* const originalFilterRelations = filterFactory.logic.or(filterByAgeRange, filterByRevenue);
|
|
37
|
+
* const updatedFilterRelations = withAddedFilters([filterByCost, filterByRevenue])(originalFilterRelations);
|
|
38
|
+
* // (filterByAgeRange OR filterByRevenue) AND filterByCost AND filterByRevenue
|
|
39
|
+
* ```
|
|
40
|
+
*/
|
|
41
|
+
export declare function withAddedFilters(filtersToAdd: Filter[]): (filters: Filter[] | FilterRelations | undefined) => Filter[] | FilterRelations;
|
|
42
|
+
/**
|
|
43
|
+
* Returns a function that removes a filter from existing filters or filter relations.
|
|
44
|
+
*
|
|
45
|
+
* @param filterToRemove - The filter to remove.
|
|
46
|
+
* @returns A function that takes existing filters or filter relations and returns updated filters or filter relations without the specified filter.
|
|
47
|
+
* @group Filter Utilities
|
|
48
|
+
* @example
|
|
49
|
+
* ```ts
|
|
50
|
+
* // Using with an array of filters
|
|
51
|
+
* const originalFilters = [filterByAgeRange, filterByRevenue, filterByCost];
|
|
52
|
+
* const updatedFilters = withoutFilter(filterByCost)(originalFilters);
|
|
53
|
+
* // [filterByAgeRange, filterByRevenue]
|
|
54
|
+
*
|
|
55
|
+
* // Using with filter relations
|
|
56
|
+
* const originalFilterRelations = filterFactory.logic.or(filterByAgeRange, filterByRevenue);
|
|
57
|
+
* const updatedFiltersRelations = withoutFilter(filterByRevenue)(originalFilterRelations);
|
|
58
|
+
* // filterByAgeRange
|
|
59
|
+
* ```
|
|
60
|
+
*/
|
|
61
|
+
export declare function withoutFilter(filterToRemove: Filter): (filters: Filter[] | FilterRelations | undefined) => Filter[] | FilterRelations;
|
|
62
|
+
/**
|
|
63
|
+
* Returns a function that removes multiple filters from existing filters or filter relations.
|
|
64
|
+
*
|
|
65
|
+
* @param filtersToRemove - An array of filters to remove.
|
|
66
|
+
* @returns A function that takes existing filters or filter relations and returns updated filters or filter relations without the specified filters.
|
|
67
|
+
* @group Filter Utilities
|
|
68
|
+
* @example
|
|
69
|
+
* ```ts
|
|
70
|
+
* // Using with an array of filters
|
|
71
|
+
* const originalFilters = [filterByAgeRange, filterByRevenue, filterByCost];
|
|
72
|
+
* const updatedFilters = withRemovedFilters([filterByRevenue, filterByCost])(originalFilters);
|
|
73
|
+
* // [filterByAgeRange]
|
|
74
|
+
*
|
|
75
|
+
* // Using with filter relations
|
|
76
|
+
* const originalFilterRelations = filterFactory.logic.or(filterByAgeRange, filterByRevenue);
|
|
77
|
+
* const updatedFiltersRelations = withRemovedFilters([filterByRevenue])(originalFilterRelations);
|
|
78
|
+
* // filterByAgeRange
|
|
79
|
+
* ```
|
|
80
|
+
*/
|
|
81
|
+
export declare function withoutFilters(filtersToRemove: Filter[]): (filters: Filter[] | FilterRelations | undefined) => Filter[] | FilterRelations;
|
|
82
|
+
/**
|
|
83
|
+
* Returns a function that replaces a filter with a new filter in existing filters or filter relations.
|
|
84
|
+
*
|
|
85
|
+
* @param filterToReplace - The filter to replace.
|
|
86
|
+
* @param newFilter - The new filter to use as a replacement.
|
|
87
|
+
* @returns A function that takes existing filters or filter relations and returns updated filters or filter relations with the filter replaced.
|
|
88
|
+
* @group Filter Utilities
|
|
89
|
+
* @example
|
|
90
|
+
* ```ts
|
|
91
|
+
* // Using with an array of filters
|
|
92
|
+
* const originalFilters = [filterByAgeRange, filterByRevenue];
|
|
93
|
+
* const updatedFilters = withReplacedFilter(filterByRevenue, filterByCost)(originalFilters);
|
|
94
|
+
* // [filterByAgeRange, filterByCost]
|
|
95
|
+
*
|
|
96
|
+
* // Using with filter relations
|
|
97
|
+
* const originalFilterRelations = filterFactory.logic.or(filterByAgeRange, filterByRevenue);
|
|
98
|
+
* const updatedFilterRelations = withReplacedFilter(filterByRevenue, filterByCost)(originalFilterRelations);
|
|
99
|
+
* // (filterByAgeRange OR filterByCost)
|
|
100
|
+
* ```
|
|
101
|
+
*/
|
|
102
|
+
export declare function withReplacedFilter(filterToReplace: Filter, newFilter: Filter): (filters: Filter[] | FilterRelations | undefined) => Filter[] | FilterRelations;
|
|
103
|
+
/**
|
|
104
|
+
* Finds a filter in an array of filters or filter relations.
|
|
105
|
+
* Returns the first filter that satisfies the provided search function.
|
|
106
|
+
* @group Filter Utilities
|
|
107
|
+
* @param filters - An array of filters or filter relations to search.
|
|
108
|
+
* @param searchFn - A function that takes a filter and returns a boolean indicating whether the filter satisfies the search criteria.
|
|
109
|
+
* @returns The first filter that satisfies the search function, or `undefined` if no filter is found.
|
|
110
|
+
*
|
|
111
|
+
*/
|
|
112
|
+
export declare function findFilter(filters: Filter[] | FilterRelations | undefined, searchFn: (filter: Filter) => boolean): Filter | undefined;
|