@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.
Files changed (60) hide show
  1. package/dist/cjs/dimensional-model/attributes.d.ts +2 -2
  2. package/dist/cjs/dimensional-model/attributes.js +7 -7
  3. package/dist/cjs/dimensional-model/base.d.ts +7 -1
  4. package/dist/cjs/dimensional-model/base.js +2 -1
  5. package/dist/cjs/dimensional-model/filters/factory.d.ts +23 -0
  6. package/dist/cjs/dimensional-model/filters/factory.js +28 -1
  7. package/dist/cjs/dimensional-model/filters/filter-config-utils.d.ts +4 -0
  8. package/dist/cjs/dimensional-model/filters/filter-config-utils.js +5 -2
  9. package/dist/cjs/dimensional-model/filters/filter-relations.d.ts +187 -0
  10. package/dist/cjs/dimensional-model/filters/filter-relations.js +532 -0
  11. package/dist/cjs/dimensional-model/filters/filters.d.ts +3 -3
  12. package/dist/cjs/dimensional-model/filters/filters.js +7 -8
  13. package/dist/cjs/dimensional-model/filters/helpers.d.ts +112 -0
  14. package/dist/cjs/dimensional-model/filters/helpers.js +178 -0
  15. package/dist/cjs/dimensional-model/filters/index.d.ts +2 -0
  16. package/dist/cjs/dimensional-model/filters/index.js +18 -0
  17. package/dist/cjs/dimensional-model/filters/utils/attribute-measure-util.d.ts +1 -35
  18. package/dist/cjs/dimensional-model/filters/utils/attribute-measure-util.js +37 -101
  19. package/dist/cjs/dimensional-model/interfaces.d.ts +2 -0
  20. package/dist/cjs/dimensional-model/measures/factory.js +1 -32
  21. package/dist/cjs/dimensional-model/measures/measures.d.ts +3 -3
  22. package/dist/cjs/dimensional-model/measures/measures.js +10 -9
  23. package/dist/cjs/index.d.ts +1 -1
  24. package/dist/cjs/index.js +1 -1
  25. package/dist/cjs/interfaces.d.ts +2 -2
  26. package/dist/cjs/utils.d.ts +74 -2
  27. package/dist/cjs/utils.js +138 -3
  28. package/dist/dimensional-model/attributes.d.ts +2 -2
  29. package/dist/dimensional-model/attributes.js +7 -7
  30. package/dist/dimensional-model/base.d.ts +7 -1
  31. package/dist/dimensional-model/base.js +2 -1
  32. package/dist/dimensional-model/filters/factory.d.ts +23 -0
  33. package/dist/dimensional-model/filters/factory.js +27 -1
  34. package/dist/dimensional-model/filters/filter-config-utils.d.ts +4 -0
  35. package/dist/dimensional-model/filters/filter-config-utils.js +5 -2
  36. package/dist/dimensional-model/filters/filter-relations.d.ts +187 -0
  37. package/dist/dimensional-model/filters/filter-relations.js +507 -0
  38. package/dist/dimensional-model/filters/filters.d.ts +3 -3
  39. package/dist/dimensional-model/filters/filters.js +7 -8
  40. package/dist/dimensional-model/filters/helpers.d.ts +112 -0
  41. package/dist/dimensional-model/filters/helpers.js +169 -0
  42. package/dist/dimensional-model/filters/index.d.ts +2 -0
  43. package/dist/dimensional-model/filters/index.js +2 -0
  44. package/dist/dimensional-model/filters/utils/attribute-measure-util.d.ts +1 -35
  45. package/dist/dimensional-model/filters/utils/attribute-measure-util.js +36 -74
  46. package/dist/dimensional-model/interfaces.d.ts +2 -0
  47. package/dist/dimensional-model/measures/factory.js +2 -30
  48. package/dist/dimensional-model/measures/measures.d.ts +3 -3
  49. package/dist/dimensional-model/measures/measures.js +10 -9
  50. package/dist/index.d.ts +1 -1
  51. package/dist/index.js +1 -1
  52. package/dist/interfaces.d.ts +2 -2
  53. package/dist/tsconfig.prod.cjs.tsbuildinfo +1 -1
  54. package/dist/utils.d.ts +74 -2
  55. package/dist/utils.js +133 -2
  56. package/package.json +4 -3
  57. package/dist/cjs/dimensional-model/filter-relations.d.ts +0 -9
  58. package/dist/cjs/dimensional-model/filter-relations.js +0 -18
  59. package/dist/dimensional-model/filter-relations.d.ts +0 -9
  60. 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 filters: Filter[];
169
+ readonly _filters: Filter[];
170
170
  constructor(filters: Filter[], config?: BaseFilterConfig);
171
171
  /**
172
- * Propagates the parent config to all level filters
172
+ * Returns the level filters with the root config applied.
173
173
  */
174
- propagateConfig(): void;
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.filters = filters;
254
- this.propagateConfig();
253
+ this._filters = filters;
255
254
  }
256
255
  /**
257
- * Propagates the parent config to all level filters
256
+ * Returns the level filters with the root config applied.
258
257
  */
259
- propagateConfig() {
258
+ get filters() {
260
259
  const { disabled, locked } = this.config;
261
- this.filters.forEach((f) => {
262
- f.config.disabled = disabled;
263
- f.config.locked = locked;
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.filters.map((f) => f.id).join()}`;
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;