@sisense/sdk-data 2.19.0 → 2.21.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.js +5 -2
- package/dist/cjs/dimensional-model/base.d.ts +29 -0
- package/dist/cjs/dimensional-model/base.js +39 -1
- package/dist/cjs/dimensional-model/dimensions/dimensions.js +2 -1
- package/dist/cjs/dimensional-model/filters/filter-relations.js +3 -1
- package/dist/cjs/dimensional-model/filters/utils/condition-filter-util.js +2 -0
- package/dist/cjs/dimensional-model/filters/utils/filter-from-jaql-util.js +2 -0
- package/dist/cjs/dimensional-model/interfaces.d.ts +7 -1
- package/dist/cjs/dimensional-model/interfaces.js +9 -1
- package/dist/cjs/dimensional-model/measures/factory.d.ts +3 -1
- package/dist/cjs/dimensional-model/measures/factory.js +4 -2
- package/dist/cjs/dimensional-model/measures/measures.js +9 -5
- package/dist/cjs/dimensional-model/types.d.ts +1 -0
- package/dist/cjs/translation/resources/en.d.ts +1 -2
- package/dist/cjs/translation/resources/en.js +8 -9
- package/dist/cjs/translation/resources/index.d.ts +2 -4
- package/dist/cjs/translation/resources/uk.js +7 -8
- package/dist/cjs/utils.d.ts +19 -0
- package/dist/cjs/utils.js +46 -2
- package/dist/dimensional-model/attributes.js +6 -3
- package/dist/dimensional-model/base.d.ts +29 -0
- package/dist/dimensional-model/base.js +36 -0
- package/dist/dimensional-model/dimensions/dimensions.js +4 -3
- package/dist/dimensional-model/filters/filter-relations.js +3 -1
- package/dist/dimensional-model/filters/utils/condition-filter-util.js +2 -0
- package/dist/dimensional-model/filters/utils/filter-from-jaql-util.js +2 -0
- package/dist/dimensional-model/interfaces.d.ts +7 -1
- package/dist/dimensional-model/interfaces.js +7 -0
- package/dist/dimensional-model/measures/factory.d.ts +3 -1
- package/dist/dimensional-model/measures/factory.js +4 -2
- package/dist/dimensional-model/measures/measures.js +9 -5
- package/dist/dimensional-model/types.d.ts +1 -0
- package/dist/translation/resources/en.d.ts +1 -2
- package/dist/translation/resources/en.js +8 -9
- package/dist/translation/resources/index.d.ts +2 -4
- package/dist/translation/resources/uk.js +7 -8
- package/dist/tsconfig.prod.cjs.tsbuildinfo +1 -1
- package/dist/utils.d.ts +19 -0
- package/dist/utils.js +43 -1
- package/package.json +2 -2
|
@@ -30,9 +30,10 @@ class DimensionalAttribute extends base_js_1.DimensionalElement {
|
|
|
30
30
|
this._sort = types_js_1.Sort.None;
|
|
31
31
|
this.expression = expression;
|
|
32
32
|
// if composeCode is not explicitly set by the caller, extract it from expression
|
|
33
|
+
// Use [[delimiters]] to preserve original names that need normalization
|
|
33
34
|
if (!composeCode && expression) {
|
|
34
35
|
const { table, column } = (0, utils_js_1.parseExpression)(expression);
|
|
35
|
-
this.composeCode =
|
|
36
|
+
this.composeCode = `${consts_js_1.DATA_MODEL_MODULE_NAME}.${(0, base_js_1.wrapIfNeedsNormalization)(table)}.${(0, base_js_1.wrapIfNeedsNormalization)(column)}`;
|
|
36
37
|
}
|
|
37
38
|
// panel is not needed in most cases, this is to support break by columns functionality
|
|
38
39
|
if (panel === 'columns') {
|
|
@@ -117,9 +118,11 @@ class DimensionalLevelAttribute extends DimensionalAttribute {
|
|
|
117
118
|
this._format = format;
|
|
118
119
|
this.granularity = granularity;
|
|
119
120
|
// if composeCode is not explicitly set by the caller, extract it from expression and granularity
|
|
121
|
+
// Use [[delimiters]] to preserve original names that need normalization
|
|
120
122
|
if (!composeCode && expression) {
|
|
121
123
|
const { table, column } = (0, utils_js_1.parseExpression)(expression);
|
|
122
|
-
|
|
124
|
+
const granularityPart = granularity ? `.${granularity}` : '';
|
|
125
|
+
this.composeCode = `${consts_js_1.DATA_MODEL_MODULE_NAME}.${(0, base_js_1.wrapIfNeedsNormalization)(table)}.${(0, base_js_1.wrapIfNeedsNormalization)(column)}${granularityPart}`;
|
|
123
126
|
}
|
|
124
127
|
// panel is not needed in most cases, this is to support break by columns functionality
|
|
125
128
|
if (panel === 'columns') {
|
|
@@ -74,3 +74,32 @@ export declare abstract class DimensionalElement implements Element {
|
|
|
74
74
|
* @internal
|
|
75
75
|
*/
|
|
76
76
|
export declare function normalizeName(name: string): string;
|
|
77
|
+
/**
|
|
78
|
+
* Checks if a name contains characters that would be modified by normalizeName().
|
|
79
|
+
* Includes: spaces, special chars (!@#$%^&*), dots, brackets, or starts with number.
|
|
80
|
+
*
|
|
81
|
+
* @example
|
|
82
|
+
* needsNormalization("Age Range") // true (space)
|
|
83
|
+
* needsNormalization("Cost ($)") // true (special chars)
|
|
84
|
+
* needsNormalization("Rev.2024") // true (dot)
|
|
85
|
+
* needsNormalization("2024Data") // true (starts with number)
|
|
86
|
+
* needsNormalization("Revenue") // false
|
|
87
|
+
*
|
|
88
|
+
* @param name - The name to check
|
|
89
|
+
* @returns true if the name would be modified by normalizeName()
|
|
90
|
+
* @internal
|
|
91
|
+
*/
|
|
92
|
+
export declare function needsNormalization(name: string): boolean;
|
|
93
|
+
/**
|
|
94
|
+
* Wraps name in [[delimiters]] if it would be modified by normalizeName().
|
|
95
|
+
* Used to preserve original names in composeCode while marking them for transformation.
|
|
96
|
+
*
|
|
97
|
+
* @example
|
|
98
|
+
* wrapIfNeedsNormalization("Age Range") // "[[Age Range]]"
|
|
99
|
+
* wrapIfNeedsNormalization("Revenue") // "Revenue" (unchanged)
|
|
100
|
+
*
|
|
101
|
+
* @param name - The name to potentially wrap
|
|
102
|
+
* @returns The name wrapped in [[]] if it needs normalization, otherwise unchanged
|
|
103
|
+
* @internal
|
|
104
|
+
*/
|
|
105
|
+
export declare function wrapIfNeedsNormalization(name: string): string;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
/* eslint-disable @typescript-eslint/no-unsafe-return */
|
|
3
3
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
-
exports.normalizeName = exports.DimensionalElement = void 0;
|
|
4
|
+
exports.wrapIfNeedsNormalization = exports.needsNormalization = exports.normalizeName = exports.DimensionalElement = void 0;
|
|
5
5
|
/**
|
|
6
6
|
* @internal
|
|
7
7
|
*/
|
|
@@ -91,3 +91,41 @@ function normalizeName(name) {
|
|
|
91
91
|
return normalizedName;
|
|
92
92
|
}
|
|
93
93
|
exports.normalizeName = normalizeName;
|
|
94
|
+
/**
|
|
95
|
+
* Checks if a name contains characters that would be modified by normalizeName().
|
|
96
|
+
* Includes: spaces, special chars (!@#$%^&*), dots, brackets, or starts with number.
|
|
97
|
+
*
|
|
98
|
+
* @example
|
|
99
|
+
* needsNormalization("Age Range") // true (space)
|
|
100
|
+
* needsNormalization("Cost ($)") // true (special chars)
|
|
101
|
+
* needsNormalization("Rev.2024") // true (dot)
|
|
102
|
+
* needsNormalization("2024Data") // true (starts with number)
|
|
103
|
+
* needsNormalization("Revenue") // false
|
|
104
|
+
*
|
|
105
|
+
* @param name - The name to check
|
|
106
|
+
* @returns true if the name would be modified by normalizeName()
|
|
107
|
+
* @internal
|
|
108
|
+
*/
|
|
109
|
+
function needsNormalization(name) {
|
|
110
|
+
// Check for invalid characters (anything not a-zA-Z0-9_)
|
|
111
|
+
// Note: dots are also "invalid" as they get replaced with underscores
|
|
112
|
+
// Check if starts with a number (gets prefixed with _)
|
|
113
|
+
return /[^a-zA-Z0-9_]/.test(name) || /^[0-9]/.test(name);
|
|
114
|
+
}
|
|
115
|
+
exports.needsNormalization = needsNormalization;
|
|
116
|
+
/**
|
|
117
|
+
* Wraps name in [[delimiters]] if it would be modified by normalizeName().
|
|
118
|
+
* Used to preserve original names in composeCode while marking them for transformation.
|
|
119
|
+
*
|
|
120
|
+
* @example
|
|
121
|
+
* wrapIfNeedsNormalization("Age Range") // "[[Age Range]]"
|
|
122
|
+
* wrapIfNeedsNormalization("Revenue") // "Revenue" (unchanged)
|
|
123
|
+
*
|
|
124
|
+
* @param name - The name to potentially wrap
|
|
125
|
+
* @returns The name wrapped in [[]] if it needs normalization, otherwise unchanged
|
|
126
|
+
* @internal
|
|
127
|
+
*/
|
|
128
|
+
function wrapIfNeedsNormalization(name) {
|
|
129
|
+
return needsNormalization(name) ? `[[${name}]]` : name;
|
|
130
|
+
}
|
|
131
|
+
exports.wrapIfNeedsNormalization = wrapIfNeedsNormalization;
|
|
@@ -23,9 +23,10 @@ class DimensionalDimension extends base_js_1.DimensionalElement {
|
|
|
23
23
|
this._attributes = [];
|
|
24
24
|
this._sort = types_js_1.Sort.None;
|
|
25
25
|
// if composeCode is not explicitly set by the caller, extract it from expression
|
|
26
|
+
// Use [[delimiters]] to preserve original names that need normalization
|
|
26
27
|
if (!composeCode && expression) {
|
|
27
28
|
const { table, column } = (0, utils_js_1.parseExpression)(expression);
|
|
28
|
-
this.composeCode = (0,
|
|
29
|
+
this.composeCode = `${consts_js_1.DATA_MODEL_MODULE_NAME}.${(0, base_js_1.wrapIfNeedsNormalization)(table)}.${(0, base_js_1.wrapIfNeedsNormalization)(column)}`;
|
|
29
30
|
}
|
|
30
31
|
this._sort = sort || types_js_1.Sort.None;
|
|
31
32
|
this._expression = expression;
|
|
@@ -514,7 +514,9 @@ function getFilterRelationsFromJaql(filters, highlights, filterRelations) {
|
|
|
514
514
|
if ('instanceid' in node) {
|
|
515
515
|
const filter = filters.find((filter) => filter.config.guid === node.instanceid);
|
|
516
516
|
if (!filter) {
|
|
517
|
-
throw new translatable_error_js_1.TranslatableError('errors.unknownFilterInFilterRelations'
|
|
517
|
+
throw new translatable_error_js_1.TranslatableError('errors.unknownFilterInFilterRelations', {
|
|
518
|
+
filterGuid: node.instanceid,
|
|
519
|
+
});
|
|
518
520
|
}
|
|
519
521
|
return filter;
|
|
520
522
|
}
|
|
@@ -180,6 +180,7 @@ const createAttributeFilterFromConditionFilterJaql = (attribute, conditionFilter
|
|
|
180
180
|
}
|
|
181
181
|
throw new translatable_error_js_1.TranslatableError('errors.filter.unsupportedConditionFilter', {
|
|
182
182
|
filter: JSON.stringify(conditionFilterJaql),
|
|
183
|
+
attributeName: attribute.name,
|
|
183
184
|
});
|
|
184
185
|
};
|
|
185
186
|
exports.createAttributeFilterFromConditionFilterJaql = createAttributeFilterFromConditionFilterJaql;
|
|
@@ -216,6 +217,7 @@ const createMeasureFilterFromConditionFilterJaql = (measure, conditionFilterJaql
|
|
|
216
217
|
}
|
|
217
218
|
throw new translatable_error_js_1.TranslatableError('errors.filter.unsupportedConditionFilter', {
|
|
218
219
|
filter: JSON.stringify(conditionFilterJaql),
|
|
220
|
+
attributeName: measure.name,
|
|
219
221
|
});
|
|
220
222
|
};
|
|
221
223
|
exports.createMeasureFilterFromConditionFilterJaql = createMeasureFilterFromConditionFilterJaql;
|
|
@@ -163,11 +163,13 @@ exports.createFilterFromCustomFilterJaql = createFilterFromCustomFilterJaql;
|
|
|
163
163
|
* @returns Filter object.
|
|
164
164
|
*/
|
|
165
165
|
const createFilterFromJaqlInternal = (jaql, guid) => {
|
|
166
|
+
var _a, _b;
|
|
166
167
|
try {
|
|
167
168
|
if ('formula' in jaql) {
|
|
168
169
|
// generic pass-through JAQL filter will be used instead
|
|
169
170
|
throw new translatable_error_js_1.TranslatableError('errors.filter.formulaFiltersNotSupported', {
|
|
170
171
|
filter: JSON.stringify(jaql),
|
|
172
|
+
attributeName: (_b = (_a = jaql.title) !== null && _a !== void 0 ? _a : jaql.column) !== null && _b !== void 0 ? _b : jaql.dim,
|
|
171
173
|
});
|
|
172
174
|
}
|
|
173
175
|
const filterJaqlWrapperWithType = (0, filter_types_util_js_1.extractFilterTypeFromFilterJaql)(jaql, jaql.datatype);
|
|
@@ -639,8 +639,14 @@ export declare type FilterRelationsModelCascadeNode = {
|
|
|
639
639
|
type: 'CascadingIdentifier';
|
|
640
640
|
levels: FilterRelationsModelIdNode[];
|
|
641
641
|
};
|
|
642
|
-
/**
|
|
642
|
+
/**
|
|
643
|
+
* Sorting direction, either in Ascending order, Descending order, or None
|
|
644
|
+
*/
|
|
643
645
|
export declare type SortDirection = 'sortAsc' | 'sortDesc' | 'sortNone';
|
|
646
|
+
/**
|
|
647
|
+
* @internal
|
|
648
|
+
*/
|
|
649
|
+
export declare function isSortDirection(sortDirection: unknown): sortDirection is SortDirection;
|
|
644
650
|
/**
|
|
645
651
|
* Sorting configuration for pivot "rows".
|
|
646
652
|
*
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.DEFAULT_PIVOT_GRAND_TOTALS = exports.isPivotMeasure = exports.isPivotAttribute = exports.isLevelAttribute = void 0;
|
|
3
|
+
exports.isSortDirection = exports.DEFAULT_PIVOT_GRAND_TOTALS = exports.isPivotMeasure = exports.isPivotAttribute = exports.isLevelAttribute = void 0;
|
|
4
4
|
/**
|
|
5
5
|
* Runs type guard check for LevelAttribute.
|
|
6
6
|
*
|
|
@@ -38,3 +38,11 @@ exports.DEFAULT_PIVOT_GRAND_TOTALS = {
|
|
|
38
38
|
rows: false,
|
|
39
39
|
columns: false,
|
|
40
40
|
};
|
|
41
|
+
/**
|
|
42
|
+
* @internal
|
|
43
|
+
*/
|
|
44
|
+
function isSortDirection(sortDirection) {
|
|
45
|
+
const SORT_DIRECTIONS = ['sortAsc', 'sortDesc', 'sortNone'];
|
|
46
|
+
return (typeof sortDirection === 'string' && SORT_DIRECTIONS.includes(sortDirection));
|
|
47
|
+
}
|
|
48
|
+
exports.isSortDirection = isSortDirection;
|
|
@@ -81,10 +81,12 @@ export declare const RankingSortTypes: {
|
|
|
81
81
|
* @param title - Title of the measure to be displayed in legend
|
|
82
82
|
* @param formula - Formula to be used for the measure
|
|
83
83
|
* @param context - Formula context as a map of strings to attributes, measures, or filters
|
|
84
|
+
* @param format - Optional format string for the measure
|
|
85
|
+
* @param description - Optional description of the measure
|
|
84
86
|
* @returns A calculated measure instance
|
|
85
87
|
* @group Advanced Analytics
|
|
86
88
|
*/
|
|
87
|
-
export declare const customFormula: (title: string, formula: string, context: CustomFormulaContext) => CalculatedMeasure;
|
|
89
|
+
export declare const customFormula: (title: string, formula: string, context: CustomFormulaContext, format?: string, description?: string) => CalculatedMeasure;
|
|
88
90
|
/**
|
|
89
91
|
* Creates an aggregated measure.
|
|
90
92
|
*
|
|
@@ -124,13 +124,15 @@ function measureFunction(measure, name, func, options) {
|
|
|
124
124
|
* @param title - Title of the measure to be displayed in legend
|
|
125
125
|
* @param formula - Formula to be used for the measure
|
|
126
126
|
* @param context - Formula context as a map of strings to attributes, measures, or filters
|
|
127
|
+
* @param format - Optional format string for the measure
|
|
128
|
+
* @param description - Optional description of the measure
|
|
127
129
|
* @returns A calculated measure instance
|
|
128
130
|
* @group Advanced Analytics
|
|
129
131
|
*/
|
|
130
|
-
exports.customFormula = (0, compose_code_utils_js_1.withComposeCodeForMeasure)((title, formula, context) => {
|
|
132
|
+
exports.customFormula = (0, compose_code_utils_js_1.withComposeCodeForMeasure)((title, formula, context, format, description) => {
|
|
131
133
|
// context keys must be in brackets
|
|
132
134
|
const newContext = Object.fromEntries(Object.entries(context).map(([key, val]) => [key.startsWith('[') ? key : `[${key}]`, val]));
|
|
133
|
-
return new measures_js_1.DimensionalCalculatedMeasure(title, formula, newContext);
|
|
135
|
+
return new measures_js_1.DimensionalCalculatedMeasure(title, formula, newContext, format, description);
|
|
134
136
|
}, 'customFormula');
|
|
135
137
|
function arithmetic(operand1, operator, operand2, name, withParentheses) {
|
|
136
138
|
const builder = [];
|
|
@@ -424,7 +424,9 @@ function createMeasure(json) {
|
|
|
424
424
|
}
|
|
425
425
|
if (types_js_1.MetadataTypes.isCalculatedMeasure(json)) {
|
|
426
426
|
if (json.context === undefined) {
|
|
427
|
-
throw new translatable_error_js_1.TranslatableError('errors.measure.dimensionalCalculatedMeasure.noContext'
|
|
427
|
+
throw new translatable_error_js_1.TranslatableError('errors.measure.dimensionalCalculatedMeasure.noContext', {
|
|
428
|
+
measureName: name,
|
|
429
|
+
});
|
|
428
430
|
}
|
|
429
431
|
const context = {};
|
|
430
432
|
Object.getOwnPropertyNames(json.context).forEach((pname) => {
|
|
@@ -434,20 +436,22 @@ function createMeasure(json) {
|
|
|
434
436
|
}
|
|
435
437
|
else if (types_js_1.MetadataTypes.isMeasureTemplate(json)) {
|
|
436
438
|
if (att === undefined) {
|
|
437
|
-
throw new translatable_error_js_1.TranslatableError('errors.measure.dimensionalBaseMeasure.noAttributeDimExpression');
|
|
439
|
+
throw new translatable_error_js_1.TranslatableError('errors.measure.dimensionalBaseMeasure.noAttributeDimExpression', { measureName: name });
|
|
438
440
|
}
|
|
439
441
|
return new DimensionalMeasureTemplate(name, att, format, desc, sort);
|
|
440
442
|
}
|
|
441
443
|
else if (types_js_1.MetadataTypes.isBaseMeasure(json)) {
|
|
442
444
|
if (att === undefined) {
|
|
443
|
-
throw new translatable_error_js_1.TranslatableError('errors.measure.dimensionalBaseMeasure.noAttributeDimExpression');
|
|
445
|
+
throw new translatable_error_js_1.TranslatableError('errors.measure.dimensionalBaseMeasure.noAttributeDimExpression', { measureName: name });
|
|
444
446
|
}
|
|
445
447
|
const agg = json.agg || json.aggregation;
|
|
446
448
|
if (!agg) {
|
|
447
|
-
throw new translatable_error_js_1.TranslatableError('errors.measure.dimensionalBaseMeasure.noAggAggregation'
|
|
449
|
+
throw new translatable_error_js_1.TranslatableError('errors.measure.dimensionalBaseMeasure.noAggAggregation', {
|
|
450
|
+
measureName: name,
|
|
451
|
+
});
|
|
448
452
|
}
|
|
449
453
|
return new DimensionalBaseMeasure(name, att, agg, format, desc, sort);
|
|
450
454
|
}
|
|
451
|
-
throw new translatable_error_js_1.TranslatableError('errors.measure.unsupportedType');
|
|
455
|
+
throw new translatable_error_js_1.TranslatableError('errors.measure.unsupportedType', { measureName: name });
|
|
452
456
|
}
|
|
453
457
|
exports.createMeasure = createMeasure;
|
|
@@ -217,6 +217,7 @@ export declare type FormulaJaql = {
|
|
|
217
217
|
formula: string;
|
|
218
218
|
context?: Record<FormulaID, FormulaContext>;
|
|
219
219
|
datasource?: JaqlDataSource;
|
|
220
|
+
description?: string;
|
|
220
221
|
};
|
|
221
222
|
/** @internal */
|
|
222
223
|
export declare type BaseFilterJaql = IncludeAllFilterJaql | IncludeMembersFilterJaql | ExcludeMembersFilterJaql | NumericFilterJaql | ConditionFilterJaql | AndFilterJaql<NumericFilterJaql | ConditionFilterJaql> | OrFilterJaql<NumericFilterJaql | ConditionFilterJaql>;
|
|
@@ -7,26 +7,25 @@ exports.translation = void 0;
|
|
|
7
7
|
exports.translation = {
|
|
8
8
|
errors: {
|
|
9
9
|
measure: {
|
|
10
|
-
unsupportedType: 'Unsupported measure type',
|
|
10
|
+
unsupportedType: 'Unsupported measure type for measure: {{measureName}}',
|
|
11
11
|
dimensionalCalculatedMeasure: {
|
|
12
|
-
noContext: "DimensionalCalculatedMeasure must have 'context' property",
|
|
12
|
+
noContext: "DimensionalCalculatedMeasure {{measureName}} must have 'context' property",
|
|
13
13
|
},
|
|
14
14
|
dimensionalBaseMeasure: {
|
|
15
|
-
noAttributeDimExpression: "DimensionalBaseMeasure must have 'attribute'/'dim'/'expression' property",
|
|
16
|
-
noAggAggregation: "DimensionalBaseMeasure must have 'agg' or 'aggregation' property",
|
|
15
|
+
noAttributeDimExpression: "DimensionalBaseMeasure {{measureName}} must have 'attribute'/'dim'/'expression' property",
|
|
16
|
+
noAggAggregation: "DimensionalBaseMeasure {{measureName}} must have 'agg' or 'aggregation' property",
|
|
17
17
|
},
|
|
18
|
-
notAFormula: 'Jaql is not a formula',
|
|
19
18
|
},
|
|
20
|
-
|
|
19
|
+
dataModel: {
|
|
21
20
|
noName: "'name' must be specified in config for DataModel",
|
|
22
21
|
noMetadata: "'metadata' must be specified in config for DataModel",
|
|
23
22
|
},
|
|
24
23
|
filter: {
|
|
25
24
|
unsupportedType: 'Unsupported filter type: {{filterType}}',
|
|
26
|
-
unsupportedDatetimeLevel: 'Filters do not support the
|
|
25
|
+
unsupportedDatetimeLevel: 'Filters do not support the following "datetime" levels: Hours, MinutesRoundTo30, MinutesRoundTo15, Minutes, Seconds',
|
|
27
26
|
membersFilterNullMember: 'MembersFilter of {{attributeId}} - member cannot be null',
|
|
28
|
-
unsupportedConditionFilter: 'Jaql contains unsupported condition filter: {{filter}}',
|
|
29
|
-
formulaFiltersNotSupported: 'Formula-based filter not supported yet: {{filter}}',
|
|
27
|
+
unsupportedConditionFilter: 'Jaql for {{attributeName}} contains unsupported condition filter: {{filter}}',
|
|
28
|
+
formulaFiltersNotSupported: 'Formula-based filter for {{attributeName}} not supported yet: {{filter}}',
|
|
30
29
|
},
|
|
31
30
|
unsupportedDimensionalElement: 'Unsupported dimensional element type',
|
|
32
31
|
},
|
|
@@ -19,9 +19,8 @@ export declare const resources: {
|
|
|
19
19
|
noAttributeDimExpression: string;
|
|
20
20
|
noAggAggregation: string;
|
|
21
21
|
};
|
|
22
|
-
notAFormula: string;
|
|
23
22
|
};
|
|
24
|
-
|
|
23
|
+
dataModel: {
|
|
25
24
|
noName: string;
|
|
26
25
|
noMetadata: string;
|
|
27
26
|
};
|
|
@@ -46,9 +45,8 @@ export declare const resources: {
|
|
|
46
45
|
noAttributeDimExpression: string;
|
|
47
46
|
noAggAggregation: string;
|
|
48
47
|
};
|
|
49
|
-
notAFormula: string;
|
|
50
48
|
};
|
|
51
|
-
|
|
49
|
+
dataModel: {
|
|
52
50
|
noName: string;
|
|
53
51
|
noMetadata: string;
|
|
54
52
|
};
|
|
@@ -7,17 +7,16 @@ exports.translation = void 0;
|
|
|
7
7
|
exports.translation = {
|
|
8
8
|
errors: {
|
|
9
9
|
measure: {
|
|
10
|
-
unsupportedType: 'Непідтримуваний тип measure',
|
|
10
|
+
unsupportedType: 'Непідтримуваний тип measure: {{measureName}}',
|
|
11
11
|
dimensionalCalculatedMeasure: {
|
|
12
|
-
noContext: "DimensionalCalculatedMeasure має мати властивість 'context'",
|
|
12
|
+
noContext: "DimensionalCalculatedMeasure {{measureName}} має мати властивість 'context'",
|
|
13
13
|
},
|
|
14
14
|
dimensionalBaseMeasure: {
|
|
15
|
-
noAttributeDimExpression: "DimensionalBaseMeasure має мати властивість 'attribute'/'dim'/'expression'",
|
|
16
|
-
noAggAggregation: "DimensionalBaseMeasure має мати властивість 'agg' або 'aggregation'",
|
|
15
|
+
noAttributeDimExpression: "DimensionalBaseMeasure {{measureName}} має мати властивість 'attribute'/'dim'/'expression'",
|
|
16
|
+
noAggAggregation: "DimensionalBaseMeasure {{measureName}} має мати властивість 'agg' або 'aggregation'",
|
|
17
17
|
},
|
|
18
|
-
notAFormula: 'Jaql не формула',
|
|
19
18
|
},
|
|
20
|
-
|
|
19
|
+
dataModel: {
|
|
21
20
|
noName: "'name' має бути вказано в конфігурації для DataModel",
|
|
22
21
|
noMetadata: "'metadata' має бути вказано в конфігурації для DataModel",
|
|
23
22
|
},
|
|
@@ -25,8 +24,8 @@ exports.translation = {
|
|
|
25
24
|
unsupportedType: 'Непідтримуваний тип фільтра: {{filterType}}',
|
|
26
25
|
unsupportedDatetimeLevel: 'Фільтри не підтримують наступні рівні "datetime": Hours, MinutesRoundTo30, MinutesRoundTo15, Minutes, Seconds',
|
|
27
26
|
membersFilterNullMember: 'MembersFilter у {{attributeId}} - member не може бути нульовим',
|
|
28
|
-
unsupportedConditionFilter: 'Jaql містить непідтримуваний condition фільтр: {{filter}}',
|
|
29
|
-
formulaFiltersNotSupported: 'Фільтри, що містять формули наразі не підтримуються: {{filter}}',
|
|
27
|
+
unsupportedConditionFilter: 'Jaql для {{attributeName}} містить непідтримуваний condition фільтр: {{filter}}',
|
|
28
|
+
formulaFiltersNotSupported: 'Фільтри, що містять формули для {{attributeName}} наразі не підтримуються: {{filter}}',
|
|
30
29
|
},
|
|
31
30
|
unsupportedDimensionalElement: 'Непідтримуваний тип елемента',
|
|
32
31
|
},
|
package/dist/cjs/utils.d.ts
CHANGED
|
@@ -72,6 +72,14 @@ export declare function convertSort(sort?: string): Sort;
|
|
|
72
72
|
* @internal
|
|
73
73
|
*/
|
|
74
74
|
export declare function convertSortDirectionToSort(sortDirection: SortDirection): Sort;
|
|
75
|
+
/**
|
|
76
|
+
* Converts Sort enum to SortDirection string.
|
|
77
|
+
*
|
|
78
|
+
* @param sort - Sort enum value
|
|
79
|
+
* @returns SortDirection string
|
|
80
|
+
* @internal
|
|
81
|
+
*/
|
|
82
|
+
export declare function convertSortToSortDirection(sort: Sort): SortDirection;
|
|
75
83
|
/**
|
|
76
84
|
* Creates a filter from a JAQL object.
|
|
77
85
|
*
|
|
@@ -184,3 +192,14 @@ export declare function createDimensionalElementFromJaql(jaql: Jaql, datetimeFor
|
|
|
184
192
|
* @internal
|
|
185
193
|
*/
|
|
186
194
|
export declare function getGranularityFromJaql(jaql: BaseJaql | FilterJaql | FilterJaqlInternal | RankingFilterJaql | MetadataItemJaql): string | undefined;
|
|
195
|
+
/**
|
|
196
|
+
* Translates Fusion FormulaJaql structures to CSDK CalculatedMeasure array.
|
|
197
|
+
*
|
|
198
|
+
* This is a pure Node.js function that converts Fusion structures to CSDK structures.
|
|
199
|
+
*
|
|
200
|
+
* @param formulas - Array of Fusion FormulaJaql structures
|
|
201
|
+
* @returns Array of CSDK CalculatedMeasure objects
|
|
202
|
+
* @throws Error if any formula cannot be converted (includes formula title in error message)
|
|
203
|
+
* @internal
|
|
204
|
+
*/
|
|
205
|
+
export declare function translateSharedFormulas(formulas: FormulaJaql[]): CalculatedMeasure[];
|
package/dist/cjs/utils.js
CHANGED
|
@@ -26,7 +26,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
26
26
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
27
27
|
};
|
|
28
28
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
29
|
-
exports.getGranularityFromJaql = exports.createDimensionalElementFromJaql = exports.createCalculatedMeasureHelper = exports.createMeasureHelper = exports.createAttributeHelper = exports.getSortType = exports.getColumnNameFromAttribute = exports.getTableNameFromAttribute = exports.parseExpression = exports.createFilterFromJaql = exports.convertSortDirectionToSort = exports.convertSort = exports.convertJaqlDataSourceForDto = exports.convertJaqlDataSource = exports.convertDataSource = exports.isDataSourceInfo = exports.getDataSourceName = exports.getFilterListAndRelationsJaql = exports.guidFast = exports.secureRandom = void 0;
|
|
29
|
+
exports.translateSharedFormulas = exports.getGranularityFromJaql = exports.createDimensionalElementFromJaql = exports.createCalculatedMeasureHelper = exports.createMeasureHelper = exports.createAttributeHelper = exports.getSortType = exports.getColumnNameFromAttribute = exports.getTableNameFromAttribute = exports.parseExpression = exports.createFilterFromJaql = exports.convertSortToSortDirection = exports.convertSortDirectionToSort = exports.convertSort = exports.convertJaqlDataSourceForDto = exports.convertJaqlDataSource = exports.convertDataSource = exports.isDataSourceInfo = exports.getDataSourceName = exports.getFilterListAndRelationsJaql = exports.guidFast = exports.secureRandom = void 0;
|
|
30
30
|
const cloneDeep_js_1 = __importDefault(require("lodash-es/cloneDeep.js"));
|
|
31
31
|
const mapValues_js_1 = __importDefault(require("lodash-es/mapValues.js"));
|
|
32
32
|
const attributes_js_1 = require("./dimensional-model/attributes.js");
|
|
@@ -242,6 +242,24 @@ function convertSortDirectionToSort(sortDirection) {
|
|
|
242
242
|
}
|
|
243
243
|
}
|
|
244
244
|
exports.convertSortDirectionToSort = convertSortDirectionToSort;
|
|
245
|
+
/**
|
|
246
|
+
* Converts Sort enum to SortDirection string.
|
|
247
|
+
*
|
|
248
|
+
* @param sort - Sort enum value
|
|
249
|
+
* @returns SortDirection string
|
|
250
|
+
* @internal
|
|
251
|
+
*/
|
|
252
|
+
function convertSortToSortDirection(sort) {
|
|
253
|
+
switch (sort) {
|
|
254
|
+
case types_js_1.Sort.Ascending:
|
|
255
|
+
return 'sortAsc';
|
|
256
|
+
case types_js_1.Sort.Descending:
|
|
257
|
+
return 'sortDesc';
|
|
258
|
+
default:
|
|
259
|
+
return 'sortNone';
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
exports.convertSortToSortDirection = convertSortToSortDirection;
|
|
245
263
|
/**
|
|
246
264
|
* Creates a filter from a JAQL object.
|
|
247
265
|
*
|
|
@@ -399,7 +417,7 @@ const createCalculatedMeasureHelper = (jaql) => {
|
|
|
399
417
|
}
|
|
400
418
|
return jaqlContextValue && createDimensionalElementFromJaql(jaqlContextValue);
|
|
401
419
|
});
|
|
402
|
-
const measure = measureFactory.customFormula(jaql.title, jaql.formula, context);
|
|
420
|
+
const measure = measureFactory.customFormula(jaql.title, jaql.formula, context, undefined, jaql.description);
|
|
403
421
|
// Apply sort if present in the JAQL
|
|
404
422
|
if (jaql.sort) {
|
|
405
423
|
const sortEnum = convertSort(jaql.sort);
|
|
@@ -464,3 +482,29 @@ function getGranularityFromJaql(jaql) {
|
|
|
464
482
|
: undefined;
|
|
465
483
|
}
|
|
466
484
|
exports.getGranularityFromJaql = getGranularityFromJaql;
|
|
485
|
+
/**
|
|
486
|
+
* Translates Fusion FormulaJaql structures to CSDK CalculatedMeasure array.
|
|
487
|
+
*
|
|
488
|
+
* This is a pure Node.js function that converts Fusion structures to CSDK structures.
|
|
489
|
+
*
|
|
490
|
+
* @param formulas - Array of Fusion FormulaJaql structures
|
|
491
|
+
* @returns Array of CSDK CalculatedMeasure objects
|
|
492
|
+
* @throws Error if any formula cannot be converted (includes formula title in error message)
|
|
493
|
+
* @internal
|
|
494
|
+
*/
|
|
495
|
+
function translateSharedFormulas(formulas) {
|
|
496
|
+
return formulas.map((formula) => {
|
|
497
|
+
try {
|
|
498
|
+
const result = createDimensionalElementFromJaql(formula);
|
|
499
|
+
if (!('expression' in result && 'context' in result)) {
|
|
500
|
+
throw new Error(`Expected CalculatedMeasure but got ${result.__serializable || 'unknown type'}`);
|
|
501
|
+
}
|
|
502
|
+
return result;
|
|
503
|
+
}
|
|
504
|
+
catch (error) {
|
|
505
|
+
const msg = error instanceof Error ? error.message : 'Unknown error';
|
|
506
|
+
throw new Error(`Failed to translate shared formula "${formula.title}": ${msg}`);
|
|
507
|
+
}
|
|
508
|
+
});
|
|
509
|
+
}
|
|
510
|
+
exports.translateSharedFormulas = translateSharedFormulas;
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
/* eslint-disable @typescript-eslint/no-unsafe-argument */
|
|
6
6
|
/* eslint-disable sonarjs/no-nested-switch */
|
|
7
7
|
import { parseExpression } from '../utils.js';
|
|
8
|
-
import { DimensionalElement, normalizeName } from './base.js';
|
|
8
|
+
import { DimensionalElement, normalizeName, wrapIfNeedsNormalization } from './base.js';
|
|
9
9
|
import { DATA_MODEL_MODULE_NAME } from './consts.js';
|
|
10
10
|
import { simpleColumnType } from './simple-column-types.js';
|
|
11
11
|
import { DateLevels, MetadataTypes, Sort, } from './types.js';
|
|
@@ -26,9 +26,10 @@ export class DimensionalAttribute extends DimensionalElement {
|
|
|
26
26
|
this._sort = Sort.None;
|
|
27
27
|
this.expression = expression;
|
|
28
28
|
// if composeCode is not explicitly set by the caller, extract it from expression
|
|
29
|
+
// Use [[delimiters]] to preserve original names that need normalization
|
|
29
30
|
if (!composeCode && expression) {
|
|
30
31
|
const { table, column } = parseExpression(expression);
|
|
31
|
-
this.composeCode =
|
|
32
|
+
this.composeCode = `${DATA_MODEL_MODULE_NAME}.${wrapIfNeedsNormalization(table)}.${wrapIfNeedsNormalization(column)}`;
|
|
32
33
|
}
|
|
33
34
|
// panel is not needed in most cases, this is to support break by columns functionality
|
|
34
35
|
if (panel === 'columns') {
|
|
@@ -111,9 +112,11 @@ export class DimensionalLevelAttribute extends DimensionalAttribute {
|
|
|
111
112
|
this._format = format;
|
|
112
113
|
this.granularity = granularity;
|
|
113
114
|
// if composeCode is not explicitly set by the caller, extract it from expression and granularity
|
|
115
|
+
// Use [[delimiters]] to preserve original names that need normalization
|
|
114
116
|
if (!composeCode && expression) {
|
|
115
117
|
const { table, column } = parseExpression(expression);
|
|
116
|
-
|
|
118
|
+
const granularityPart = granularity ? `.${granularity}` : '';
|
|
119
|
+
this.composeCode = `${DATA_MODEL_MODULE_NAME}.${wrapIfNeedsNormalization(table)}.${wrapIfNeedsNormalization(column)}${granularityPart}`;
|
|
117
120
|
}
|
|
118
121
|
// panel is not needed in most cases, this is to support break by columns functionality
|
|
119
122
|
if (panel === 'columns') {
|
|
@@ -74,3 +74,32 @@ export declare abstract class DimensionalElement implements Element {
|
|
|
74
74
|
* @internal
|
|
75
75
|
*/
|
|
76
76
|
export declare function normalizeName(name: string): string;
|
|
77
|
+
/**
|
|
78
|
+
* Checks if a name contains characters that would be modified by normalizeName().
|
|
79
|
+
* Includes: spaces, special chars (!@#$%^&*), dots, brackets, or starts with number.
|
|
80
|
+
*
|
|
81
|
+
* @example
|
|
82
|
+
* needsNormalization("Age Range") // true (space)
|
|
83
|
+
* needsNormalization("Cost ($)") // true (special chars)
|
|
84
|
+
* needsNormalization("Rev.2024") // true (dot)
|
|
85
|
+
* needsNormalization("2024Data") // true (starts with number)
|
|
86
|
+
* needsNormalization("Revenue") // false
|
|
87
|
+
*
|
|
88
|
+
* @param name - The name to check
|
|
89
|
+
* @returns true if the name would be modified by normalizeName()
|
|
90
|
+
* @internal
|
|
91
|
+
*/
|
|
92
|
+
export declare function needsNormalization(name: string): boolean;
|
|
93
|
+
/**
|
|
94
|
+
* Wraps name in [[delimiters]] if it would be modified by normalizeName().
|
|
95
|
+
* Used to preserve original names in composeCode while marking them for transformation.
|
|
96
|
+
*
|
|
97
|
+
* @example
|
|
98
|
+
* wrapIfNeedsNormalization("Age Range") // "[[Age Range]]"
|
|
99
|
+
* wrapIfNeedsNormalization("Revenue") // "Revenue" (unchanged)
|
|
100
|
+
*
|
|
101
|
+
* @param name - The name to potentially wrap
|
|
102
|
+
* @returns The name wrapped in [[]] if it needs normalization, otherwise unchanged
|
|
103
|
+
* @internal
|
|
104
|
+
*/
|
|
105
|
+
export declare function wrapIfNeedsNormalization(name: string): string;
|
|
@@ -86,3 +86,39 @@ export function normalizeName(name) {
|
|
|
86
86
|
}
|
|
87
87
|
return normalizedName;
|
|
88
88
|
}
|
|
89
|
+
/**
|
|
90
|
+
* Checks if a name contains characters that would be modified by normalizeName().
|
|
91
|
+
* Includes: spaces, special chars (!@#$%^&*), dots, brackets, or starts with number.
|
|
92
|
+
*
|
|
93
|
+
* @example
|
|
94
|
+
* needsNormalization("Age Range") // true (space)
|
|
95
|
+
* needsNormalization("Cost ($)") // true (special chars)
|
|
96
|
+
* needsNormalization("Rev.2024") // true (dot)
|
|
97
|
+
* needsNormalization("2024Data") // true (starts with number)
|
|
98
|
+
* needsNormalization("Revenue") // false
|
|
99
|
+
*
|
|
100
|
+
* @param name - The name to check
|
|
101
|
+
* @returns true if the name would be modified by normalizeName()
|
|
102
|
+
* @internal
|
|
103
|
+
*/
|
|
104
|
+
export function needsNormalization(name) {
|
|
105
|
+
// Check for invalid characters (anything not a-zA-Z0-9_)
|
|
106
|
+
// Note: dots are also "invalid" as they get replaced with underscores
|
|
107
|
+
// Check if starts with a number (gets prefixed with _)
|
|
108
|
+
return /[^a-zA-Z0-9_]/.test(name) || /^[0-9]/.test(name);
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* Wraps name in [[delimiters]] if it would be modified by normalizeName().
|
|
112
|
+
* Used to preserve original names in composeCode while marking them for transformation.
|
|
113
|
+
*
|
|
114
|
+
* @example
|
|
115
|
+
* wrapIfNeedsNormalization("Age Range") // "[[Age Range]]"
|
|
116
|
+
* wrapIfNeedsNormalization("Revenue") // "Revenue" (unchanged)
|
|
117
|
+
*
|
|
118
|
+
* @param name - The name to potentially wrap
|
|
119
|
+
* @returns The name wrapped in [[]] if it needs normalization, otherwise unchanged
|
|
120
|
+
* @internal
|
|
121
|
+
*/
|
|
122
|
+
export function wrapIfNeedsNormalization(name) {
|
|
123
|
+
return needsNormalization(name) ? `[[${name}]]` : name;
|
|
124
|
+
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/* eslint-disable sonarjs/no-duplicate-string */
|
|
2
2
|
import { parseExpression } from '../../utils.js';
|
|
3
|
-
import { DimensionalAttribute, DimensionalLevelAttribute, jaqlSimpleColumnType,
|
|
4
|
-
import { DimensionalElement, normalizeName } from '../base.js';
|
|
3
|
+
import { DimensionalAttribute, DimensionalLevelAttribute, jaqlSimpleColumnType, } from '../attributes.js';
|
|
4
|
+
import { DimensionalElement, normalizeName, wrapIfNeedsNormalization } from '../base.js';
|
|
5
5
|
import { DATA_MODEL_MODULE_NAME } from '../consts.js';
|
|
6
6
|
import { DateLevels, MetadataTypes, Sort, } from '../types.js';
|
|
7
7
|
/**
|
|
@@ -20,9 +20,10 @@ export class DimensionalDimension extends DimensionalElement {
|
|
|
20
20
|
this._attributes = [];
|
|
21
21
|
this._sort = Sort.None;
|
|
22
22
|
// if composeCode is not explicitly set by the caller, extract it from expression
|
|
23
|
+
// Use [[delimiters]] to preserve original names that need normalization
|
|
23
24
|
if (!composeCode && expression) {
|
|
24
25
|
const { table, column } = parseExpression(expression);
|
|
25
|
-
this.composeCode =
|
|
26
|
+
this.composeCode = `${DATA_MODEL_MODULE_NAME}.${wrapIfNeedsNormalization(table)}.${wrapIfNeedsNormalization(column)}`;
|
|
26
27
|
}
|
|
27
28
|
this._sort = sort || Sort.None;
|
|
28
29
|
this._expression = expression;
|
|
@@ -465,7 +465,9 @@ export function getFilterRelationsFromJaql(filters, highlights, filterRelations)
|
|
|
465
465
|
if ('instanceid' in node) {
|
|
466
466
|
const filter = filters.find((filter) => filter.config.guid === node.instanceid);
|
|
467
467
|
if (!filter) {
|
|
468
|
-
throw new TranslatableError('errors.unknownFilterInFilterRelations'
|
|
468
|
+
throw new TranslatableError('errors.unknownFilterInFilterRelations', {
|
|
469
|
+
filterGuid: node.instanceid,
|
|
470
|
+
});
|
|
469
471
|
}
|
|
470
472
|
return filter;
|
|
471
473
|
}
|