mirror of
https://github.com/qlik-oss/nebula.js.git
synced 2025-12-19 17:58:43 -05:00
chore: update types and export HyperCubeHandler (#1779)
* chore: updating types index.d.ts for HyperCubeHanlder * chore: fix dependencies * chore: remove nudleus dependecies and fixing comments * chore: disable no-relative-package import * chore: fix comments * chore: update types for data-property and hypercube-handler * chore: convert more types in data-property-handler to object * chore: fix more comments * chore: make all types private * chore: update lockfile * chore: make a correction * chore: fix the classes example import path --------- Co-authored-by: caele <tsm@qlik.com>
This commit is contained in:
committed by
GitHub
parent
af5566f40c
commit
ccf66ebc50
@@ -1,6 +1,7 @@
|
||||
import hypercube from './hypercube';
|
||||
import utils from './utils';
|
||||
import helpers from './helpers';
|
||||
import arrayUtil from './array-util';
|
||||
|
||||
const getType = async ({ halo, name, version }) => {
|
||||
const { types } = halo;
|
||||
@@ -118,4 +119,7 @@ const conversion = {
|
||||
*/
|
||||
hypercube,
|
||||
};
|
||||
|
||||
export { utils, arrayUtil };
|
||||
|
||||
export default conversion;
|
||||
|
||||
@@ -42,6 +42,8 @@ export {
|
||||
useEmitter,
|
||||
onTakeSnapshot,
|
||||
onContextMenu,
|
||||
HyperCubeHandler,
|
||||
DataPropertyHandler,
|
||||
} from '@nebula.js/supernova';
|
||||
|
||||
// component internals
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
"version": "6.0.0-alpha.2",
|
||||
"main": "src/index.js",
|
||||
"devDependencies": {
|
||||
"@nebula.js/conversion": "^6.0.0-alpha.2",
|
||||
"extend": "3.0.2",
|
||||
"node-event-emitter": "0.0.1"
|
||||
}
|
||||
|
||||
@@ -34,17 +34,16 @@ describe('DataPropertyHandler', () => {
|
||||
describe('getDimensions()', () => {
|
||||
test('should return null when dimension is undefined', () => {
|
||||
jest.spyOn(handler, 'getDimensions').mockReturnValue([]);
|
||||
const dimension = handler.getDimension(undefined);
|
||||
const dimension = handler.getDimension({});
|
||||
expect(dimension).toBeFalsy();
|
||||
});
|
||||
|
||||
test('should return dimension when it exists in getDimensions()', () => {
|
||||
jest.spyOn(handler, 'getDimensions').mockReturnValue([{ qDef: { cId: 'dim1' } }]);
|
||||
jest.spyOn(handler, 'getAlternativeDimensions').mockReturnValue([{ qDef: { cId: 'altDim1' } }]);
|
||||
|
||||
const dimension = handler.getDimension('dim1');
|
||||
const dimension = handler.getDimension({ id: 'dim1' });
|
||||
expect(dimension).toEqual({ qDef: { cId: 'dim1' } });
|
||||
const alternativeDimension = handler.getDimension('altDim1');
|
||||
const alternativeDimension = handler.getDimension({ id: 'altDim1' });
|
||||
expect(alternativeDimension).toEqual({ qDef: { cId: 'altDim1' } });
|
||||
});
|
||||
});
|
||||
@@ -52,7 +51,7 @@ describe('DataPropertyHandler', () => {
|
||||
describe('getMeasure()', () => {
|
||||
test('should return null when both measures and alternative measures are empty', () => {
|
||||
jest.spyOn(handler, 'getMeasures').mockReturnValue([]);
|
||||
const measure = handler.getMeasure(undefined);
|
||||
const measure = handler.getMeasure({});
|
||||
expect(measure).toBeFalsy();
|
||||
});
|
||||
|
||||
@@ -60,8 +59,8 @@ describe('DataPropertyHandler', () => {
|
||||
jest.spyOn(handler, 'getMeasures').mockReturnValue([{ qDef: { cId: 'measure1' } }]);
|
||||
jest.spyOn(handler, 'getAlternativeMeasures').mockReturnValue([{ qDef: { cId: 'altMeasure1' } }]);
|
||||
|
||||
const measure = handler.getMeasure('measure1');
|
||||
const alternativeMeasure = handler.getMeasure('altMeasure1');
|
||||
const measure = handler.getMeasure({ id: 'measure1' });
|
||||
const alternativeMeasure = handler.getMeasure({ id: 'altMeasure1' });
|
||||
expect(measure).toEqual({ qDef: { cId: 'measure1' } });
|
||||
expect(alternativeMeasure).toEqual({ qDef: { cId: 'altMeasure1' } });
|
||||
});
|
||||
@@ -75,31 +74,26 @@ describe('DataPropertyHandler', () => {
|
||||
});
|
||||
|
||||
test('should create a dimension with default properties when no field is provided', () => {
|
||||
const result = handler.createFieldDimension(null, null, { customDefault: 'value' });
|
||||
const fieldDimension = { field: '', label: '', defaults: { customDefault: 'value' } };
|
||||
const result = handler.createFieldDimension(fieldDimension);
|
||||
|
||||
expect(result.qDef.qFieldDefs).toEqual([null]);
|
||||
expect(result.qDef.qFieldDefs).toEqual(['']);
|
||||
expect(result.qDef.qFieldLabels).toEqual(['']);
|
||||
expect(result.qDef.qSortCriterias).toEqual(sortingProperties);
|
||||
expect(result.qDef.autoSort).toBe(true);
|
||||
expect(result.someProperty).toBe('defaultValue');
|
||||
expect(result.customDefault).toBe('value');
|
||||
});
|
||||
|
||||
test('should create a library dimension with default properties', () => {
|
||||
const result = handler.createLibraryDimension('libraryId', { customDefault: 'value' });
|
||||
|
||||
expect(result.qLibraryId).toBe('libraryId');
|
||||
expect(result.qDef.qSortCriterias).toEqual(sortingProperties);
|
||||
expect(result.qDef.autoSort).toBe(true);
|
||||
expect(result.someProperty).toBe('defaultValue');
|
||||
expect(result.customDefault).toBe('value');
|
||||
expect(result.qOtherTotalSpec).toEqual({});
|
||||
});
|
||||
|
||||
test('should create a dimension with provided field and label', () => {
|
||||
const result = handler.createFieldDimension('fieldName', 'fieldLabel', { customDefault: 'value' });
|
||||
const fieldDimension = { field: 'fieldName', label: 'fieldLabel' };
|
||||
const result = handler.createFieldDimension(fieldDimension);
|
||||
|
||||
expect(result.qDef.qFieldDefs).toEqual(['fieldName']);
|
||||
expect(result.qDef.qFieldLabels).toEqual(['fieldLabel']);
|
||||
expect(result.qDef.qSortCriterias).toEqual(sortingProperties);
|
||||
expect(result.qDef.autoSort).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -110,21 +104,17 @@ describe('DataPropertyHandler', () => {
|
||||
});
|
||||
});
|
||||
|
||||
test('should delete qFieldDefs and qFieldLabels from the dimension', () => {
|
||||
const result = handler.createLibraryDimension('libraryId', {});
|
||||
|
||||
expect(result.qDef.qFieldDefs).toBeUndefined();
|
||||
expect(result.qDef.qFieldLabels).toBeUndefined();
|
||||
});
|
||||
|
||||
test('should create a library dimension with default properties', () => {
|
||||
const result = handler.createLibraryDimension('libraryId', { customDefault: 'value' });
|
||||
test('should create dimension and delete qFieldDefs and qFieldLabels from it', () => {
|
||||
const libraryDimension = { id: 'libraryId', defaults: { customDefault: 'value' } };
|
||||
const result = handler.createLibraryDimension(libraryDimension);
|
||||
|
||||
expect(result.qLibraryId).toBe('libraryId');
|
||||
expect(result.qDef.qSortCriterias).toEqual(sortingProperties);
|
||||
expect(result.qDef.autoSort).toBe(true);
|
||||
expect(result.someProperty).toBe('defaultValue');
|
||||
expect(result.customDefault).toBe('value');
|
||||
expect(result.qDef.autoSort).toBe(true);
|
||||
expect(result.qDef.qFieldDefs).toBeUndefined();
|
||||
expect(result.qDef.qFieldLabels).toBeUndefined();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -136,7 +126,12 @@ describe('DataPropertyHandler', () => {
|
||||
});
|
||||
|
||||
test('should create a measure with provided expression and label', () => {
|
||||
const result = handler.createExpressionMeasure('SUM(Sales)', 'Total Sales', { customDefault: 'value' });
|
||||
const expressionMeasure = {
|
||||
expression: 'SUM(Sales)',
|
||||
label: 'Total Sales',
|
||||
defaults: { customDefault: 'value' },
|
||||
};
|
||||
const result = handler.createExpressionMeasure(expressionMeasure);
|
||||
|
||||
expect(result.qDef.qDef).toBe('SUM(Sales)');
|
||||
expect(result.qDef.qLabel).toBe('Total Sales');
|
||||
@@ -146,14 +141,16 @@ describe('DataPropertyHandler', () => {
|
||||
});
|
||||
|
||||
test('should initialize qDef and qNumFormat if not provided', () => {
|
||||
const result = handler.createExpressionMeasure('SUM(Sales)', 'Total Sales', {});
|
||||
const expressionMeasure = { expression: 'SUM(Sales)', label: 'Total Sales', defaults: {} };
|
||||
const result = handler.createExpressionMeasure(expressionMeasure);
|
||||
|
||||
expect(result.qDef).toBeDefined();
|
||||
expect(result.qDef.qNumFormat).toBeDefined();
|
||||
});
|
||||
|
||||
test('should handle empty defaults gracefully', () => {
|
||||
const result = handler.createExpressionMeasure('SUM(Sales)', 'Total Sales', null);
|
||||
const expressionMeasure = { expression: 'SUM(Sales)', label: 'Total Sales' };
|
||||
const result = handler.createExpressionMeasure(expressionMeasure);
|
||||
|
||||
expect(result.qDef.qDef).toBe('SUM(Sales)');
|
||||
expect(result.qDef.qLabel).toBe('Total Sales');
|
||||
@@ -170,7 +167,8 @@ describe('DataPropertyHandler', () => {
|
||||
});
|
||||
|
||||
test('should create a library measure with provided id and defaults', () => {
|
||||
const result = handler.createLibraryMeasure('libraryId', { customDefault: 'value' });
|
||||
const libraryMeasure = { id: 'libraryId', defaults: { customDefault: 'value' } };
|
||||
const result = handler.createLibraryMeasure(libraryMeasure);
|
||||
|
||||
expect(result.qLibraryId).toBe('libraryId');
|
||||
expect(result.qDef.qNumFormat).toBeDefined();
|
||||
@@ -180,14 +178,16 @@ describe('DataPropertyHandler', () => {
|
||||
});
|
||||
|
||||
test('should initialize qDef and qNumFormat if not provided', () => {
|
||||
const result = handler.createLibraryMeasure('libraryId', {});
|
||||
const libraryMeasure = { id: 'libraryId', defaults: {} };
|
||||
const result = handler.createLibraryMeasure(libraryMeasure);
|
||||
|
||||
expect(result.qDef).toBeDefined();
|
||||
expect(result.qDef.qNumFormat).toBeDefined();
|
||||
});
|
||||
|
||||
test('should delete qDef.qDef and qDef.qLabel from the measure', () => {
|
||||
const result = handler.createLibraryMeasure('libraryId', {});
|
||||
const libraryMeasure = { id: 'libraryId', defaults: {} };
|
||||
const result = handler.createLibraryMeasure(libraryMeasure);
|
||||
|
||||
expect(result.qDef.qDef).toBeUndefined();
|
||||
expect(result.qDef.qLabel).toBeUndefined();
|
||||
@@ -195,14 +195,7 @@ describe('DataPropertyHandler', () => {
|
||||
});
|
||||
|
||||
describe('maxMeasures', () => {
|
||||
let galaxy;
|
||||
|
||||
beforeEach(() => {
|
||||
galaxy = {
|
||||
flags: {
|
||||
isEnabled: jest.fn().mockReturnValue(false),
|
||||
},
|
||||
};
|
||||
handler = new HyperCubeHandler({
|
||||
measureDefinition: { max: 0 },
|
||||
dimensionDefinition: { max: 0 },
|
||||
@@ -221,15 +214,6 @@ describe('DataPropertyHandler', () => {
|
||||
expect(result).toBe(5);
|
||||
});
|
||||
|
||||
test('should pass properties to measureDefinition.max when feature flag is enabled', () => {
|
||||
handler.measureDefinition.max = jest.fn().mockReturnValue(5);
|
||||
galaxy.flags.isEnabled.mockReturnValue(true);
|
||||
handler.properties = { someProperty: 'value' };
|
||||
|
||||
const result = handler.maxMeasures();
|
||||
expect(result).toBe(5);
|
||||
});
|
||||
|
||||
test('should return measureDefinition.max when it is a valid number', () => {
|
||||
handler.measureDefinition.max = 8;
|
||||
|
||||
@@ -260,14 +244,7 @@ describe('DataPropertyHandler', () => {
|
||||
});
|
||||
|
||||
describe('maxDimensions', () => {
|
||||
let galaxy;
|
||||
|
||||
beforeEach(() => {
|
||||
galaxy = {
|
||||
flags: {
|
||||
isEnabled: jest.fn().mockReturnValue(false),
|
||||
},
|
||||
};
|
||||
handler = new HyperCubeHandler({
|
||||
measureDefinition: { max: 0 },
|
||||
dimensionDefinition: { max: 0 },
|
||||
@@ -282,15 +259,6 @@ describe('DataPropertyHandler', () => {
|
||||
expect(result).toBe(5);
|
||||
});
|
||||
|
||||
test('should pass properties to dimensionDefinition.max when feature flag is enabled', () => {
|
||||
handler.dimensionDefinition.max = jest.fn().mockReturnValue(10);
|
||||
galaxy.flags.isEnabled.mockReturnValue(true);
|
||||
handler.properties = { someProperty: 'value' };
|
||||
|
||||
const result = handler.maxDimensions();
|
||||
expect(result).toBe(10);
|
||||
});
|
||||
|
||||
test('should return dimensionDefinition.max when it is a valid number', () => {
|
||||
handler.dimensionDefinition.max = 8;
|
||||
|
||||
|
||||
@@ -1,10 +1,38 @@
|
||||
import extend from 'extend';
|
||||
// eslint-disable-next-line import/no-relative-packages
|
||||
import isEnabled from '../../../nucleus/src/flags/flags';
|
||||
import { findFieldById, useMasterNumberFormat } from './utils/field-helper/field-utils';
|
||||
import { findFieldById, initializeDim, useMasterNumberFormat } from './utils/field-helper/field-utils';
|
||||
import { INITIAL_SORT_CRITERIAS } from './utils/constants';
|
||||
import { notSupportedError } from './utils/hypercube-helper/hypercube-utils';
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @class DataPropertyHandler
|
||||
* @description A class to handle data properties for dimensions and measures in a data model.
|
||||
* @param {object} opts - Parameters to add a hypercube handlers
|
||||
* @param {qix.Doc} opts.app
|
||||
* @param {object} opts.dimensionDefinition
|
||||
* @param {object} opts.measureDefinition
|
||||
* @param {object} opts.dimensionProperties
|
||||
* @param {object} opts.measureProperties
|
||||
* @param {object} opts.globalChangeListeners
|
||||
* @entry
|
||||
* @export
|
||||
* @example
|
||||
* import DataPropertyHandler from '@nebula.js/stardust';
|
||||
*
|
||||
* class PivotHyperCubeHandler extends DataPropertyHandler {
|
||||
*
|
||||
* addDimensionAsFirstRow: (hypercube: HyperCubeDef, dimension: NxDimension) => {
|
||||
* const dimensions = this.getDimensions().length;
|
||||
* const { qInterColumnSortOrder } = hypercube;
|
||||
*
|
||||
* if(dimensions !== 0 && dimensions < this.maxDimensions()) {
|
||||
* hypercube.qNoOfLeftDims = 1;
|
||||
* qInterColumnSortOrder?.unshift(dimensions);
|
||||
* dimensions.splice(0, 0, dimension);
|
||||
* }
|
||||
* }
|
||||
* }
|
||||
*/
|
||||
class DataPropertyHandler {
|
||||
constructor(opts) {
|
||||
const options = opts || {};
|
||||
@@ -18,20 +46,85 @@ class DataPropertyHandler {
|
||||
this.app = options.app;
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @typeof {object} LibraryDimension
|
||||
* @property {string} id
|
||||
* @property {qix.NxDimension=} defaults
|
||||
*/
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @typeof {object} FieldDimension
|
||||
* @property {string} field
|
||||
* @property {string=} label
|
||||
* @property {qix.NxDimension=} defaults
|
||||
*/
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @typeof {object} LibraryMeasure
|
||||
* @property {string} id
|
||||
* @property {qix.NxMeasure=} defaults
|
||||
*/
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @typeof {object} ExpressionMeasure
|
||||
* @property {string} expression
|
||||
* @property {string=} label
|
||||
* @property {qix.NxMeasure=} defaults
|
||||
*/
|
||||
|
||||
/**
|
||||
* Sets the properties for the handler.
|
||||
* @private
|
||||
* @param {object=} properties - The properties object to set.
|
||||
* @description Updates the handler's properties and analysis type flag.
|
||||
* @memberof DataPropertyHandler
|
||||
* @example
|
||||
* handler.setProperties({ metaData: { isAnalysisType: true } });
|
||||
*/
|
||||
setProperties(properties) {
|
||||
this.properties = properties;
|
||||
this.isAnalysisType = this.properties?.metaData?.isAnalysisType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the global change listeners.
|
||||
* @private
|
||||
* @param {Function[]} arr - Array of listener functions.
|
||||
* @description Assigns global change listeners to the handler.
|
||||
* @memberof DataPropertyHandler
|
||||
* @example
|
||||
* handler.setGlobalChangeListeners([listener1, listener2]);
|
||||
*/
|
||||
setGlobalChangeListeners(arr) {
|
||||
this.globalChangeListeners = arr;
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @param {object=} layout - The layout object to set.
|
||||
* @description Sets the layout for the handler.
|
||||
* @memberof DataPropertyHandler
|
||||
* @example
|
||||
* handler.setLayout(layoutObj);
|
||||
*/
|
||||
setLayout(layout) {
|
||||
this.layout = layout;
|
||||
}
|
||||
|
||||
static type() {
|
||||
/**
|
||||
* @private
|
||||
* @throws {Error}
|
||||
* @description Throws an error indicating the method must be overridden.
|
||||
* @memberof DataPropertyHandler
|
||||
* @example
|
||||
* DataPropertyHandler.type(); // Throws error
|
||||
*/
|
||||
// eslint-disable-next-line class-methods-use-this
|
||||
type() {
|
||||
throw new Error('Must override this method');
|
||||
}
|
||||
|
||||
@@ -39,56 +132,138 @@ class DataPropertyHandler {
|
||||
// ---------------DIMENSION---------------
|
||||
// ---------------------------------------
|
||||
|
||||
static getDimensions() {
|
||||
/**
|
||||
* @private
|
||||
* @returns {Array} Empty array.
|
||||
* @description Returns the default dimension array.
|
||||
* @memberof DataPropertyHandler
|
||||
*/
|
||||
// eslint-disable-next-line class-methods-use-this
|
||||
getDimensions() {
|
||||
return [];
|
||||
}
|
||||
|
||||
getDimension(id) {
|
||||
/**
|
||||
* Gets a dimension by id from dimensions or alternative dimensions.
|
||||
* @private
|
||||
* @param {LibraryDimension} libraryDimension
|
||||
* @returns {qix.NxDimension} - The found dimension.
|
||||
* @description Searches for a dimension by id in both main and alternative dimensions.
|
||||
* @memberof DataPropertyHandler
|
||||
* @example
|
||||
* const dim = handler.getDimension({ id: 'dimId' });
|
||||
*/
|
||||
getDimension(libraryDimension) {
|
||||
const dimensions = this.getDimensions();
|
||||
const alternativeDimensions = this.getAlternativeDimensions();
|
||||
|
||||
return findFieldById(dimensions, id) ?? findFieldById(alternativeDimensions, id);
|
||||
return findFieldById(dimensions, libraryDimension.id) ?? findFieldById(alternativeDimensions, libraryDimension.id);
|
||||
}
|
||||
|
||||
static getAlternativeDimensions() {
|
||||
/**
|
||||
* Throws an error indicating the method must be implemented in subclasses.
|
||||
* @private
|
||||
* @throws {Error}
|
||||
* @memberof DataPropertyHandler
|
||||
*/
|
||||
// eslint-disable-next-line class-methods-use-this
|
||||
getAlternativeDimensions() {
|
||||
throw new Error('Method not implemented.');
|
||||
}
|
||||
|
||||
static addDimension() {
|
||||
/**
|
||||
* Throws an error indicating addDimension is not supported in the base class.
|
||||
* @private
|
||||
* @throws {Error}
|
||||
* @memberof DataPropertyHandler
|
||||
*/
|
||||
// eslint-disable-next-line class-methods-use-this
|
||||
addDimension() {
|
||||
throw notSupportedError;
|
||||
}
|
||||
|
||||
static addDimensions() {
|
||||
/**
|
||||
* Throws an error indicating addDimensions is not supported in the base class.
|
||||
* @private
|
||||
* @throws {Error}
|
||||
* @memberof DataPropertyHandler
|
||||
*/
|
||||
// eslint-disable-next-line class-methods-use-this
|
||||
addDimensions() {
|
||||
throw notSupportedError;
|
||||
}
|
||||
|
||||
static removeDimension() {
|
||||
/**
|
||||
* Throws an error indicating removeDimension is not supported in the base class.
|
||||
* @private
|
||||
* @throws {Error}
|
||||
* @memberof DataPropertyHandler
|
||||
*/
|
||||
// eslint-disable-next-line class-methods-use-this
|
||||
removeDimension() {
|
||||
throw notSupportedError;
|
||||
}
|
||||
|
||||
static removeDimensions() {
|
||||
/**
|
||||
* Throws an error indicating removeDimensions is not supported in the base class.
|
||||
* @private
|
||||
* @throws {Error}
|
||||
* @memberof DataPropertyHandler
|
||||
*/
|
||||
// eslint-disable-next-line class-methods-use-this
|
||||
removeDimensions() {
|
||||
throw notSupportedError;
|
||||
}
|
||||
|
||||
static autoSortDimension() {
|
||||
/**
|
||||
* Throws an error indicating autoSortDimension is not supported in the base class.
|
||||
* @private
|
||||
* @throws {Error}
|
||||
* @memberof DataPropertyHandler
|
||||
*/
|
||||
// eslint-disable-next-line class-methods-use-this
|
||||
autoSortDimension() {
|
||||
throw notSupportedError;
|
||||
}
|
||||
|
||||
static replaceDimension() {
|
||||
/**
|
||||
* Throws an error indicating replaceDimension is not supported in the base class.
|
||||
* @private
|
||||
* @throws {Error}
|
||||
* @memberof DataPropertyHandler
|
||||
*/
|
||||
// eslint-disable-next-line class-methods-use-this
|
||||
replaceDimension() {
|
||||
throw notSupportedError;
|
||||
}
|
||||
|
||||
static getSorting() {
|
||||
/**
|
||||
* Throws an error indicating getSorting is not supported in the base class.
|
||||
* @private
|
||||
* @throws {Error}
|
||||
* @memberof DataPropertyHandler
|
||||
*/
|
||||
// eslint-disable-next-line class-methods-use-this
|
||||
getSorting() {
|
||||
throw notSupportedError;
|
||||
}
|
||||
|
||||
createLibraryDimension(id, defaults) {
|
||||
const dimension = extend(true, {}, this.dimensionProperties || {}, defaults || {});
|
||||
/**
|
||||
* Creates a type of library dimension with a field definition.
|
||||
* @private
|
||||
* @param {LibraryDimension} libraryDimension
|
||||
* @returns {qix.NxDimension} The created dimension object.
|
||||
* @description Initializes a dimension and applying default properties and sort criteria.
|
||||
* @memberof DataPropertyHandler
|
||||
* @example
|
||||
* const dim = handler.createLibraryDimension({ id:'dimId', { qDef: { cId: 'dim1' } }});
|
||||
*/
|
||||
createLibraryDimension(libraryDimension) {
|
||||
let dimension = extend(true, {}, this.dimensionProperties || {}, libraryDimension.defaults || {});
|
||||
|
||||
dimension.qDef = dimension.qDef ?? {};
|
||||
dimension.qOtherTotalSpec = dimension.qOtherTotalSpec ?? {};
|
||||
dimension = initializeDim(dimension);
|
||||
|
||||
dimension.qLibraryId = id;
|
||||
dimension.qLibraryId = libraryDimension.id;
|
||||
dimension.qDef.autoSort = true;
|
||||
dimension.qDef.qSortCriterias = INITIAL_SORT_CRITERIAS;
|
||||
|
||||
@@ -98,87 +273,201 @@ class DataPropertyHandler {
|
||||
return dimension;
|
||||
}
|
||||
|
||||
createFieldDimension(field, label, defaults) {
|
||||
const dimension = extend(true, {}, this.dimensionProperties || {}, defaults || {});
|
||||
/**
|
||||
* Creates a type of field dimension with a field definition.
|
||||
* @private
|
||||
* @param {FieldDimension} fieldDimension
|
||||
* @returns {qix.NxDimension} The created dimension object.
|
||||
* @description Initializes a dimension with field definitions, labels, and default properties.
|
||||
* @memberof DataPropertyHandler
|
||||
* @example
|
||||
* handler.createFieldDimension({field: 'currentField', label: 'label'});
|
||||
*/
|
||||
createFieldDimension(fieldDimension) {
|
||||
let dimension = extend(true, {}, this.dimensionProperties || {}, fieldDimension.defaults || {});
|
||||
|
||||
dimension.qDef = dimension.qDef ?? {};
|
||||
dimension.qOtherTotalSpec = dimension.qOtherTotalSpec ?? {};
|
||||
dimension = initializeDim(dimension);
|
||||
|
||||
if (!field) {
|
||||
if (!fieldDimension.field) {
|
||||
dimension.qDef.qFieldDefs = [];
|
||||
dimension.qDef.qFieldLabels = [];
|
||||
dimension.qDef.qSortCriterias = [];
|
||||
}
|
||||
|
||||
dimension.qDef.qFieldDefs = [field];
|
||||
dimension.qDef.qFieldLabels = label ? [label] : [''];
|
||||
dimension.qDef.qFieldDefs = [fieldDimension.field];
|
||||
dimension.qDef.qFieldLabels = fieldDimension.label ? [fieldDimension.label] : [''];
|
||||
dimension.qDef.qSortCriterias = INITIAL_SORT_CRITERIAS;
|
||||
|
||||
dimension.qDef.autoSort = true;
|
||||
|
||||
return dimension;
|
||||
}
|
||||
|
||||
addFieldDimension(field, label, defaults) {
|
||||
const dimension = this.createFieldDimension(field, label, defaults);
|
||||
/**
|
||||
* Adds a field dimension to the handler.
|
||||
* @private
|
||||
* @param {FieldDimension} fieldDimension
|
||||
* @returns {Promise<qix.NxDimension=>} The result of addDimension.
|
||||
* @description Creates and adds a field dimension.
|
||||
* @memberof DataPropertyHandler
|
||||
* @example
|
||||
* handler.addFieldDimension({field: 'currentField', label: 'label'});
|
||||
*/
|
||||
addFieldDimension(fieldDimension) {
|
||||
const dimension = this.createFieldDimension(fieldDimension);
|
||||
return this.addDimension(dimension);
|
||||
}
|
||||
|
||||
addFieldDimensions(args) {
|
||||
const dimensions = args.map(({ field, label, defaults }) => this.createFieldDimension(field, label, defaults));
|
||||
/**
|
||||
* @private
|
||||
* @param {FieldDimension[]} fieldDimensions - Array of field dimension.
|
||||
* @returns {Promise<qix.NxDimension[]>} The result of addDimensions.
|
||||
* @description Creates and adds multiple field dimensions.
|
||||
* @memberof DataPropertyHandler
|
||||
* @example
|
||||
* handler.addFieldDimensions([{ field: 'A', label: 'AA' }, { field: 'B', label: 'BB' }]);
|
||||
*/
|
||||
addFieldDimensions(fieldDimensions) {
|
||||
const dimensions = fieldDimensions.map((fieldDimension) => this.createFieldDimension(fieldDimension));
|
||||
return this.addDimensions(dimensions);
|
||||
}
|
||||
|
||||
addLibraryDimension(id, defaults) {
|
||||
const dimension = this.createLibraryDimension(id, defaults);
|
||||
/**
|
||||
* Adds a library dimension to the handler.
|
||||
* @private
|
||||
* @param {LibraryDimension} libraryDimension
|
||||
* @returns {Promise<qix.NxDimension=>} The result of addDimension.
|
||||
* @description Creates and adds a library dimension.
|
||||
* @memberof DataPropertyHandler
|
||||
* @example
|
||||
* handler.addLibraryDimension({ id: 'A'});
|
||||
*/
|
||||
addLibraryDimension(libraryDimension) {
|
||||
const dimension = this.createLibraryDimension(libraryDimension);
|
||||
return this.addDimension(dimension);
|
||||
}
|
||||
|
||||
addLibraryDimensions(args) {
|
||||
const dimensions = args.map(({ id, defaults }) => this.createLibraryDimension(id, defaults));
|
||||
/**
|
||||
* Adds multiple library dimensions to the handler.
|
||||
* @private
|
||||
* @param {LibraryDimension[]} libraryDimensions - Array of library dimension.
|
||||
* @returns {Promise<qix.NxDimension[]>} The result of addDimensions.
|
||||
* @description Creates and adds multiple library dimensions.
|
||||
* @memberof DataPropertyHandler
|
||||
* @example
|
||||
* handler.addLibraryDimensions([{ id: 'A' }, { id: 'B', defaults: { ... } }]);
|
||||
*/
|
||||
addLibraryDimensions(libraryDimensions) {
|
||||
const dimensions = libraryDimensions.map((libraryDimension) => this.createLibraryDimension(libraryDimension));
|
||||
const result = this.addDimensions(dimensions);
|
||||
return result;
|
||||
}
|
||||
|
||||
async addAltLibraryDimensions(args) {
|
||||
const dimensions = args.map(({ id }) => this.createLibraryDimension(id));
|
||||
/**
|
||||
* Adds multiple alternative library dimensions to the handler.
|
||||
* @private
|
||||
* @param {LibraryDimension[]} libraryDimensions - Array of library dimension.
|
||||
* @returns {Promise<qix.NxDimension[]>} The result of addDimensions.
|
||||
* @description Creates and adds multiple alternative library dimensions.
|
||||
* @memberof DataPropertyHandler
|
||||
* @example
|
||||
* await handler.addAltLibraryDimensions([{ id: 'A' }, { id: 'B', defaults: { ... } }]);
|
||||
*/
|
||||
async addAltLibraryDimensions(libraryDimensions) {
|
||||
const dimensions = libraryDimensions.map((libraryDimension) => this.createLibraryDimension(libraryDimension));
|
||||
return this.addDimensions(dimensions, true);
|
||||
}
|
||||
|
||||
async addAltFieldDimensions(args) {
|
||||
const dimensions = args.map(({ field }) => this.createFieldDimension(field));
|
||||
/**
|
||||
* Adds multiple alternative field dimensions to the handler.
|
||||
* @private
|
||||
* @param {FieldDimension[]} fieldDimensions - Array of field dimension.
|
||||
* @returns {Promise<qix.NxDimension[]>} The result of addDimensions.
|
||||
* @description Creates and adds multiple alternative field dimensions.
|
||||
* @memberof DataPropertyHandler
|
||||
* @example
|
||||
* await handler.addAltFieldDimensions([{ field: 'A', label: 'Label A' }, { field: 'B', label: 'Label B' }]);
|
||||
*/
|
||||
async addAltFieldDimensions(fieldDimensions) {
|
||||
const dimensions = fieldDimensions.map((fieldDimension) => this.createFieldDimension(fieldDimension));
|
||||
return this.addDimensions(dimensions, true);
|
||||
}
|
||||
|
||||
addAlternativeFieldDimension(field, label, defaults) {
|
||||
const dimension = this.createFieldDimension(field, label, defaults);
|
||||
/**
|
||||
* Adds an alternative field dimension to the handler.
|
||||
* @private
|
||||
* @param {FieldDimension} fieldDimension
|
||||
* @returns {Promise<qix.NxDimension=>} The result of addDimension.
|
||||
* @description Creates and adds an alternative field dimension.
|
||||
* @memberof DataPropertyHandler
|
||||
* @example
|
||||
* handler.addAlternativeFieldDimension({ field: 'A', label: 'Label A' });
|
||||
*/
|
||||
addAlternativeFieldDimension(fieldDimension) {
|
||||
const dimension = this.createFieldDimension(fieldDimension);
|
||||
return this.addDimension(dimension, true);
|
||||
}
|
||||
|
||||
addAlternativeLibraryDimension(id, defaults) {
|
||||
const dimension = this.createLibraryDimension(id, defaults);
|
||||
/**
|
||||
* Adds an alternative library dimension to the handler.
|
||||
* @private
|
||||
* @param {LibraryDimension} libraryDimension
|
||||
* @returns {Promise<qix.NxDimension=>} The result of addDimension.
|
||||
* @description Creates and adds an alternative library dimension.
|
||||
* @memberof DataPropertyHandler
|
||||
* @example
|
||||
* handler.addAlternativeLibraryDimension([{ id: 'A' }, { id: 'B', defaults: { ... } }]);
|
||||
*/
|
||||
addAlternativeLibraryDimension(libraryDimension) {
|
||||
const dimension = this.createLibraryDimension(libraryDimension);
|
||||
return this.addDimension(dimension, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the minimum number of dimensions allowed.
|
||||
* @private
|
||||
* @returns {number} The minimum number of dimensions.
|
||||
* @description Returns the minimum number of dimensions allowed by the handler.
|
||||
* @memberof DataPropertyHandler
|
||||
* @example
|
||||
* const min = handler.minDimensions();
|
||||
*/
|
||||
minDimensions() {
|
||||
if (typeof this.dimensionDefinition.min === 'function') {
|
||||
return this.dimensionDefinition.min.call(null, this.properties, this);
|
||||
}
|
||||
|
||||
return this.dimensionDefinition.min || 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the maximum number of dimensions allowed.
|
||||
* @private
|
||||
* @param {number} [decrement=0] - The number to decrement from the current number of measures.
|
||||
* @returns {number} The maximum number of dimensions allowed.
|
||||
* @description Checks if the max property is a function and calls it with the current number of measures, or returns a default value.
|
||||
* @memberof DataPropertyHandler
|
||||
* @example
|
||||
* const max = handler.maxDimensions();
|
||||
*/
|
||||
maxDimensions(decrement = 0) {
|
||||
const measureLength = this.getMeasures().length - decrement;
|
||||
|
||||
if (typeof this.dimensionDefinition.max === 'function') {
|
||||
const dimParams = isEnabled('PS_21371_ANALYSIS_TYPES') ? [measureLength, this.properties] : [measureLength];
|
||||
const dimParams = [measureLength];
|
||||
return this.dimensionDefinition.max?.apply(null, dimParams);
|
||||
}
|
||||
|
||||
return Number.isNaN(+this.dimensionDefinition.max) ? 10000 : this.dimensionDefinition.max;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if a new dimension can be added.
|
||||
* @private
|
||||
* @returns {boolean} True if a new dimension can be added, false otherwise.
|
||||
* @description Returns whether the handler can add another dimension.
|
||||
* @memberof DataPropertyHandler
|
||||
* @example
|
||||
* if (handler.canAddDimension()) { handler.addFieldDimension('A'); }
|
||||
*/
|
||||
canAddDimension() {
|
||||
return this.getDimensions().length < this.maxDimensions();
|
||||
}
|
||||
@@ -187,80 +476,183 @@ class DataPropertyHandler {
|
||||
// ----------------MEASURE----------------
|
||||
// ---------------------------------------
|
||||
|
||||
getMeasure(id) {
|
||||
const measures = this.getMeasures();
|
||||
const alternativeMeasures = this.getAlternativeMeasures();
|
||||
|
||||
return findFieldById(measures, id) ?? findFieldById(alternativeMeasures, id);
|
||||
}
|
||||
|
||||
static getMeasures() {
|
||||
/**
|
||||
* @private
|
||||
* @returns {Array} Empty array.
|
||||
* @description Returns the default measure array.
|
||||
* @memberof DataPropertyHandler
|
||||
*/
|
||||
// eslint-disable-next-line class-methods-use-this
|
||||
getMeasures() {
|
||||
return [];
|
||||
}
|
||||
|
||||
static getAlternativeMeasures() {
|
||||
/**
|
||||
* Throws an error indicating the method must be implemented in subclasses.
|
||||
* @private
|
||||
* @throws {Error}
|
||||
* @memberof DataPropertyHandler
|
||||
*/
|
||||
// eslint-disable-next-line class-methods-use-this
|
||||
getAlternativeMeasures() {
|
||||
throw new Error('Method not implemented.');
|
||||
}
|
||||
|
||||
static addMeasure() {
|
||||
/**
|
||||
* Throws an error indicating addMeasure is not supported in the base class.
|
||||
* @private
|
||||
* @throws {Error}
|
||||
* @memberof DataPropertyHandler
|
||||
*/
|
||||
// eslint-disable-next-line class-methods-use-this
|
||||
addMeasure() {
|
||||
throw notSupportedError;
|
||||
}
|
||||
|
||||
static addMeasures() {
|
||||
/**
|
||||
* Throws an error indicating addMeasures is not supported in the base class.
|
||||
* @private
|
||||
* @throws {Error}
|
||||
* @memberof DataPropertyHandler
|
||||
*/
|
||||
// eslint-disable-next-line class-methods-use-this
|
||||
addMeasures() {
|
||||
throw notSupportedError;
|
||||
}
|
||||
|
||||
static removeMeasure() {
|
||||
/**
|
||||
* Throws an error indicating removeMeasure is not supported in the base class.
|
||||
* @private
|
||||
* @throws {Error}
|
||||
* @memberof DataPropertyHandler
|
||||
*/
|
||||
// eslint-disable-next-line class-methods-use-this
|
||||
removeMeasure() {
|
||||
throw notSupportedError;
|
||||
}
|
||||
|
||||
static removeMeasures() {
|
||||
/**
|
||||
* Throws an error indicating removeMeasures is not supported in the base class.
|
||||
* @private
|
||||
* @throws {Error}
|
||||
* @memberof DataPropertyHandler
|
||||
*/
|
||||
// eslint-disable-next-line class-methods-use-this
|
||||
removeMeasures() {
|
||||
throw notSupportedError;
|
||||
}
|
||||
|
||||
static autoSortMeasure() {
|
||||
/**
|
||||
* Throws an error indicating autoSortMeasure is not supported in the base class.
|
||||
* @private
|
||||
* @throws {Error}
|
||||
* @memberof DataPropertyHandler
|
||||
*/
|
||||
// eslint-disable-next-line class-methods-use-this
|
||||
autoSortMeasure() {
|
||||
throw notSupportedError;
|
||||
}
|
||||
|
||||
static replaceMeasure() {
|
||||
/**
|
||||
* Throws an error indicating replaceMeasure is not supported in the base class.
|
||||
* @private
|
||||
* @throws {Error}
|
||||
* @memberof DataPropertyHandler
|
||||
*/
|
||||
// eslint-disable-next-line class-methods-use-this
|
||||
replaceMeasure() {
|
||||
throw notSupportedError;
|
||||
}
|
||||
|
||||
createExpressionMeasure(expression, label, defaults) {
|
||||
const measure = extend(true, {}, this.measureProperties || {}, defaults || {});
|
||||
/**
|
||||
* Gets a measure by id from measures or alternative measures.
|
||||
* @private
|
||||
* @param {string} libraryDimension - The measure id to find.
|
||||
* @returns {qix.NxMeasure} The found measure or undefined.
|
||||
* @description Searches for a measure by id in both main and alternative measures.
|
||||
* @memberof DataPropertyHandler
|
||||
* @example
|
||||
* const measure = handler.getMeasure('measId');
|
||||
*/
|
||||
getMeasure(libraryDimension) {
|
||||
const measures = this.getMeasures();
|
||||
const alternativeMeasures = this.getAlternativeMeasures();
|
||||
|
||||
return findFieldById(measures, libraryDimension.id) ?? findFieldById(alternativeMeasures, libraryDimension.id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an expression measure.
|
||||
* @private
|
||||
* @param {ExpressionMeasure} expressionMeasure
|
||||
* @returns {Promise<qix.NxMeasure=>} The created measure object.
|
||||
* @description Initializes a measure with an expression, label, and default properties.
|
||||
* @memberof DataPropertyHandler
|
||||
* @example
|
||||
* const meas = handler.createExpressionMeasure({ expression: 'Sum(Sales)', label: 'Total Sales' });
|
||||
*/
|
||||
createExpressionMeasure(expressionMeasure) {
|
||||
const measure = extend(true, {}, this.measureProperties || {}, expressionMeasure.defaults || {});
|
||||
|
||||
measure.qDef = measure.qDef ?? {};
|
||||
measure.qDef.qNumFormat = measure.qDef.qNumFormat ?? {};
|
||||
|
||||
measure.qDef.qDef = expression;
|
||||
measure.qDef.qLabel = label;
|
||||
measure.qDef.qDef = expressionMeasure.expression;
|
||||
measure.qDef.qLabel = expressionMeasure.label;
|
||||
measure.qDef.autoSort = true;
|
||||
|
||||
return measure;
|
||||
}
|
||||
|
||||
addExpressionMeasure(expression, label, defaults) {
|
||||
const measure = this.createExpressionMeasure(expression, label, defaults);
|
||||
/**
|
||||
* Adds an expression measure to the handler.
|
||||
* @private
|
||||
* @param {ExpressionMeasure} expressionMeasure
|
||||
* @returns {Promise<qix.NxMeasure=>} The result of addMeasure.
|
||||
* @description Creates and adds an expression measure.
|
||||
* @memberof DataPropertyHandler
|
||||
* @example
|
||||
* handler.addExpressionMeasure({ expression: 'Sum(Sales)', label: 'Total Sales' });
|
||||
*/
|
||||
addExpressionMeasure(expressionMeasure) {
|
||||
const measure = this.createExpressionMeasure(expressionMeasure);
|
||||
return this.addMeasure(measure);
|
||||
}
|
||||
|
||||
addExpressionMeasures(args) {
|
||||
const measures = args.map(({ expression, label, defaults }) =>
|
||||
this.createExpressionMeasure(expression, label, defaults)
|
||||
);
|
||||
/**
|
||||
* Adds multiple expression measures to the handler.
|
||||
* @private
|
||||
* @param {ExpressionMeasure[]} expressionMeasures - Array of expression measure.
|
||||
* @returns {Promise<qix.NxMeasure[]>} The result of addMeasures.
|
||||
* @description Creates and adds multiple expression measures.
|
||||
* @memberof DataPropertyHandler
|
||||
* @example
|
||||
* handler.addExpressionMeasures([{ expression: 'Sum(A)' }, { expression: 'Sum(B)', label: 'B' }]);
|
||||
*/
|
||||
addExpressionMeasures(expressionMeasures) {
|
||||
const measures = expressionMeasures.map((expressionMeasure) => this.createExpressionMeasure(expressionMeasure));
|
||||
return this.addMeasures(measures);
|
||||
}
|
||||
|
||||
createLibraryMeasure(id, defaults) {
|
||||
const measure = extend(true, {}, this.measureProperties || {}, defaults || {});
|
||||
/**
|
||||
* Creates a library measure.
|
||||
* @private
|
||||
* @param {LibraryMeasure} libraryMeasure
|
||||
* @returns {qix.NxMeasure} The created measure object.
|
||||
* @description Initializes a library measure with default properties.
|
||||
* @memberof DataPropertyHandler
|
||||
* @example
|
||||
* const meas = handler.createLibraryMeasure({ id: 'measId', defaults: { qDef: { ... } } });
|
||||
*/
|
||||
createLibraryMeasure(libraryMeasure) {
|
||||
const measure = extend(true, {}, this.measureProperties || {}, libraryMeasure.defaults || {});
|
||||
|
||||
measure.qDef = measure.qDef ?? {};
|
||||
measure.qDef.qNumFormat = measure.qDef.qNumFormat ?? {};
|
||||
|
||||
if (isEnabled('MASTER_MEASURE_FORMAT')) {
|
||||
useMasterNumberFormat(measure.qDef);
|
||||
}
|
||||
useMasterNumberFormat(measure.qDef);
|
||||
|
||||
measure.qLibraryId = id;
|
||||
measure.qLibraryId = libraryMeasure.id;
|
||||
measure.qDef.autoSort = true;
|
||||
|
||||
delete measure.qDef.qDef;
|
||||
@@ -269,36 +661,105 @@ class DataPropertyHandler {
|
||||
return measure;
|
||||
}
|
||||
|
||||
addLibraryMeasure(id, defaults) {
|
||||
const measure = this.createLibraryMeasure(id, defaults);
|
||||
/**
|
||||
* Adds a library measure to the handler.
|
||||
* @private
|
||||
* @param {LibraryMeasure} libraryMeasure
|
||||
* @returns {Promise<qix.NxMeasure=>} The result of addMeasure.
|
||||
* @description Creates and adds a library measure.
|
||||
* @memberof DataPropertyHandler
|
||||
* @example
|
||||
* handler.addLibraryMeasure({ id: 'measId', defaults: { qDef: { ... } } });
|
||||
*/
|
||||
addLibraryMeasure(libraryMeasure) {
|
||||
const measure = this.createLibraryMeasure(libraryMeasure);
|
||||
return this.addMeasure(measure);
|
||||
}
|
||||
|
||||
addLibraryMeasures(args) {
|
||||
const measures = args.map(({ id, defaults }) => this.createLibraryMeasure(id, defaults));
|
||||
/**
|
||||
* Adds multiple library measures to the handler.
|
||||
* @private
|
||||
* @param {LibraryMeasure[]} libraryMeasures - Array of library measure.
|
||||
* @returns {Promise<qix.NxMeasure[]>} The result of addMeasures.
|
||||
* @description Creates and adds multiple library measures.
|
||||
* @memberof DataPropertyHandler
|
||||
* @example
|
||||
* handler.addLibraryMeasures([{ id: 'A' }, { id: 'B', defaults: { qDef: { ... } } }]);
|
||||
*/
|
||||
addLibraryMeasures(libraryMeasures) {
|
||||
const measures = libraryMeasures.map((libraryMeasure) => this.createLibraryMeasure(libraryMeasure));
|
||||
return this.addMeasures(measures);
|
||||
}
|
||||
|
||||
addAltLibraryMeasures(args) {
|
||||
const measures = args.map(({ id }) => this.createLibraryMeasure(id));
|
||||
/**
|
||||
* Adds multiple alternative library measures to the handler.
|
||||
* @private
|
||||
* @param {LibraryMeasure[]} libraryMeasures - Array of library measure.
|
||||
* @returns {Promise<qix.NxMeasure[]>} The result of addMeasures.
|
||||
* @description Creates and adds multiple alternative library measures.
|
||||
* @memberof DataPropertyHandler
|
||||
* @example
|
||||
* handler.addAltLibraryMeasures([{ id: 'A' }, { id: 'B' }]);
|
||||
*/
|
||||
addAltLibraryMeasures(libraryMeasures) {
|
||||
const measures = libraryMeasures.map((libraryMeasure) => this.createLibraryMeasure(libraryMeasure));
|
||||
return this.addMeasures(measures, true);
|
||||
}
|
||||
|
||||
addAltExpressionMeasures(args) {
|
||||
const measures = args.map(({ expression }) => this.createExpressionMeasure(expression));
|
||||
/**
|
||||
* Adds multiple alternative expression measures to the handler.
|
||||
* @private
|
||||
* @param {ExpressionMeasure[]} expressionMeasures - Array of expression measure.
|
||||
* @returns {Promise<qix.NxMeasure[]>} The result of addMeasures.
|
||||
* @description Creates and adds multiple alternative expression measures.
|
||||
* @memberof DataPropertyHandler
|
||||
* @example
|
||||
* handler.addAltExpressionMeasures([{ expression: 'Sum(A)' }, { expression: 'Sum(B)' }]);
|
||||
*/
|
||||
addAltExpressionMeasures(libraryMeasures) {
|
||||
const measures = libraryMeasures.map((expressionMeasure) => this.createExpressionMeasure(expressionMeasure));
|
||||
return this.addMeasures(measures, true);
|
||||
}
|
||||
|
||||
addAlternativeExpressionMeasure(expression, label, defaults) {
|
||||
const measure = this.createExpressionMeasure(expression, label, defaults);
|
||||
/**
|
||||
* Adds an alternative expression measure to the handler.
|
||||
* @private
|
||||
* @param {ExpressionMeasure} expressionMeasure
|
||||
* @returns {Promise<qix.NxMeasure=>} The result of addMeasure.
|
||||
* @description Creates and adds an alternative expression measure.
|
||||
* @memberof DataPropertyHandler
|
||||
* @example
|
||||
* handler.addAlternativeExpressionMeasure({ expression: 'Sum(Sales)', label: 'Total Sales'});
|
||||
*/
|
||||
addAlternativeExpressionMeasure(expressionMeasure) {
|
||||
const measure = this.createExpressionMeasure(expressionMeasure);
|
||||
return this.addMeasure(measure, true);
|
||||
}
|
||||
|
||||
addAlternativeLibraryMeasure(id, defaults) {
|
||||
const measure = this.createLibraryMeasure(id, defaults);
|
||||
/**
|
||||
* Adds an alternative library measure to the handler.
|
||||
* @private
|
||||
* @param {LibraryMeasure} libraryMeasure
|
||||
* @returns {qix.NxMeasure=} The result of addMeasure.
|
||||
* @description Creates and adds an alternative library measure.
|
||||
* @memberof DataPropertyHandler
|
||||
* @example
|
||||
* handler.addAlternativeLibraryMeasure({ id: 'measId', defaults: { qDef: { ... } } });
|
||||
*/
|
||||
addAlternativeLibraryMeasure(libraryMeasure) {
|
||||
const measure = this.createLibraryMeasure(libraryMeasure);
|
||||
return this.addMeasure(measure, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the minimum number of measures allowed.
|
||||
* @private
|
||||
* @returns {number} The minimum number of measures.
|
||||
* @description Returns the minimum number of measures allowed by the handler.
|
||||
* @memberof DataPropertyHandler
|
||||
* @example
|
||||
* const min = handler.minMeasures();
|
||||
*/
|
||||
minMeasures() {
|
||||
if (typeof this.measureDefinition.min === 'function') {
|
||||
return this.measureDefinition.min.call(null, this.properties, this);
|
||||
@@ -306,24 +767,51 @@ class DataPropertyHandler {
|
||||
return this.measureDefinition.min || 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the maximum number of measures allowed.
|
||||
* @private
|
||||
* @param {number} [decrement=0] - The number to decrement from the current number of dimensions.
|
||||
* @returns {number} The maximum number of measures allowed.
|
||||
* @description Checks if the max property is a function and calls it with the current number of dimensions, or returns a default value.
|
||||
* @memberof DataPropertyHandler
|
||||
* @example
|
||||
* const max = handler.maxMeasures();
|
||||
*/
|
||||
maxMeasures(decrement = 0) {
|
||||
if (typeof this.measureDefinition.max === 'function') {
|
||||
const dimLength = this.getDimensions().length - decrement;
|
||||
const measureParams = isEnabled('PS_21371_ANALYSIS_TYPES') ? [dimLength, this.properties] : [dimLength];
|
||||
const measureParams = [dimLength];
|
||||
return this.measureDefinition.max.apply(null, measureParams);
|
||||
}
|
||||
return Number.isNaN(+this.measureDefinition.max) ? 10000 : this.measureDefinition.max;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if a new measure can be added.
|
||||
* @private
|
||||
* @returns {boolean} True if a new measure can be added, false otherwise.
|
||||
* @description Returns whether the handler can add another measure.
|
||||
* @memberof DataPropertyHandler
|
||||
* @example
|
||||
* if (handler.canAddMeasure()) { handler.addExpressionMeasure('Sum(A)'); }
|
||||
*/
|
||||
canAddMeasure() {
|
||||
return this.getMeasures().length < this.maxMeasures();
|
||||
// return this.getMeasures().length < 10000;
|
||||
}
|
||||
|
||||
// ---------------------------------------
|
||||
// ---------------OTHERS------------------
|
||||
// ---------------------------------------
|
||||
|
||||
/**
|
||||
* Calls all global change listeners with the current properties, handler, and layout.
|
||||
* @private
|
||||
* @param {object} layout - The layout object to pass to listeners.
|
||||
* @description Invokes all registered global change listeners.
|
||||
* @memberof DataPropertyHandler
|
||||
* @example
|
||||
* handler.updateGlobalChangeListeners(layoutObj);
|
||||
*/
|
||||
updateGlobalChangeListeners(layout) {
|
||||
if (this.globalChangeListeners) {
|
||||
(this.globalChangeListeners || []).forEach((func) => {
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
// eslint-disable-next-line import/no-relative-packages
|
||||
import utils from '../../../conversion/src/utils';
|
||||
import { utils, arrayUtil } from '@nebula.js/conversion';
|
||||
import DataPropertyHandler from './data-property-handler';
|
||||
import * as hcUtils from './utils/hypercube-helper/hypercube-utils';
|
||||
import getAutoSortLibraryDimension from './utils/field-helper/get-sorted-library-field';
|
||||
import getAutoSortFieldDimension from './utils/field-helper/get-sorted-field';
|
||||
import { initializeField, initializeId } from './utils/field-helper/field-utils';
|
||||
import getAutoSortDimension from './utils/field-helper/get-sorted-field';
|
||||
import { initializeDim, initializeId } from './utils/field-helper/field-utils';
|
||||
import addMainDimension from './utils/hypercube-helper/add-main-dimension';
|
||||
import addMainMeasure from './utils/hypercube-helper/add-main-measure';
|
||||
import removeMainDimension from './utils/hypercube-helper/remove-main-dimension';
|
||||
@@ -13,18 +12,55 @@ import removeMainMeasure from './utils/hypercube-helper/remove-main-measure';
|
||||
import removeAlternativeDimension from './utils/hypercube-helper/remove-alternative-dimension';
|
||||
import reinsertMainDimension from './utils/hypercube-helper/reinsert-main-dimension';
|
||||
import reinsertMainMeasure from './utils/hypercube-helper/reinsert-main-measure';
|
||||
// eslint-disable-next-line import/no-relative-packages
|
||||
import arrayUtil from '../../../conversion/src/array-util';
|
||||
|
||||
/**
|
||||
* HyperCubeHandler for managing hypercube data structure.
|
||||
* @private
|
||||
* @class HyperCubeHandler
|
||||
* @description This class provides methods to handle hypercube properties, dimensions, and measures.
|
||||
* @param {object} opts Parameters to add a hypercube handlers
|
||||
* @param {qix.Doc} opts.app
|
||||
* @param {object} opts.dimensionDefinition
|
||||
* @param {object} opts.measureDefinition
|
||||
* @param {object} opts.dimensionProperties
|
||||
* @param {object} opts.measureProperties
|
||||
* @param {object} opts.globalChangeListeners
|
||||
* @param {object} opts.path
|
||||
* @entry
|
||||
* @export
|
||||
* @example
|
||||
* import { HyperCubeHandler } from '@nebula.js/stardust';
|
||||
*
|
||||
* class PivotHyperCubeHandler extends HyperCubeHandler {
|
||||
*
|
||||
* adjustPseudoDimOrder: (pseudoIdx?: number) => {
|
||||
* const numberOfDims = this.getDimensions().length;
|
||||
* const interColumnSortOrder = this.hcProperties.qInterColumnSortOrder;
|
||||
*
|
||||
* if (!interColumnSortOrder) {
|
||||
* return;
|
||||
* }
|
||||
*
|
||||
* interColumnSortOrder.splice(pseudoIdx || 0, 1);
|
||||
* interColumnSortOrder.push(numberOfDims);
|
||||
* interColumnSortOrder.splice((pseudoIdx || -1) + 1, 0, -1);
|
||||
* };
|
||||
* }
|
||||
*/
|
||||
class HyperCubeHandler extends DataPropertyHandler {
|
||||
constructor(opts) {
|
||||
super(opts);
|
||||
this.path = opts.path;
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @param {object=} properties
|
||||
* @returns early return if properties is falsy
|
||||
*/
|
||||
setProperties(properties) {
|
||||
if (!properties) {
|
||||
return {};
|
||||
return;
|
||||
}
|
||||
|
||||
super.setProperties(properties);
|
||||
@@ -32,7 +68,7 @@ class HyperCubeHandler extends DataPropertyHandler {
|
||||
this.hcProperties = this.path ? utils.getValue(properties, `${this.path}.qHyperCubeDef`) : properties.qHyperCubeDef;
|
||||
|
||||
if (!this.hcProperties) {
|
||||
return {};
|
||||
return;
|
||||
}
|
||||
|
||||
hcUtils.setDefaultProperties(this);
|
||||
@@ -41,32 +77,76 @@ class HyperCubeHandler extends DataPropertyHandler {
|
||||
// Set auto-sort property (compatibility 0.85 -> 0.9), can probably be removed in 1.0
|
||||
this.hcProperties.qDimensions = hcUtils.setFieldProperties(this.hcProperties.qDimensions);
|
||||
this.hcProperties.qMeasures = hcUtils.setFieldProperties(this.hcProperties.qMeasures);
|
||||
return {};
|
||||
}
|
||||
|
||||
// ----------------------------------
|
||||
// ----------- DIMENSIONS -----------
|
||||
// ----------------------------------
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @returns {qix.NxDimension[]} dimensions
|
||||
* @description Returns the dimensions of the hypercube.
|
||||
* @memberof HyperCubeHandler
|
||||
* @example
|
||||
* const dimensions = hyperCubeHandler.getDimensions();
|
||||
*/
|
||||
getDimensions() {
|
||||
return this.hcProperties ? this.hcProperties.qDimensions : [];
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @returns {qix.NxDimension[]} alternative dimensions
|
||||
* @description Returns the alternative dimensions of the hypercube.
|
||||
* @memberof HyperCubeHandler
|
||||
* @example
|
||||
* const alternativeDimensions = hyperCubeHandler.getAlternativeDimensions();
|
||||
*/
|
||||
getAlternativeDimensions() {
|
||||
return this.hcProperties?.qLayoutExclude?.qHyperCubeDef?.qDimensions ?? [];
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @param {string} cId
|
||||
* @returns {qix.NxDimensionInfo} dimension layout
|
||||
* @description Returns the dimension layout of the hypercube for a given cId.
|
||||
* @memberof HyperCubeHandler
|
||||
* @example
|
||||
* const dimensionLayout = hyperCubeHandler.getDimensionLayout(cId);
|
||||
*/
|
||||
getDimensionLayout(cId) {
|
||||
return this.getDimensionLayouts().filter((item) => cId === item.cId)[0];
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @returns {qix.NxDimensionInfo[]} dimension layouts
|
||||
* @description Returns the dimension layouts of the hypercube.
|
||||
* @memberof HyperCubeHandler
|
||||
* @example
|
||||
* const dimensionLayouts = hyperCubeHandler.getDimensionLayouts();
|
||||
*/
|
||||
getDimensionLayouts() {
|
||||
const hc = hcUtils.getHyperCube(this.layout, this.path);
|
||||
return hc ? hc.qDimensionInfo : [];
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @param {qix.NxDimension} dimension
|
||||
* @param {boolean} alternative
|
||||
* @param {number=} idx
|
||||
* @returns {qix.NxDimension} dimension
|
||||
* @description Adds a dimension to the hypercube and updates the orders of the dimensions.
|
||||
* If the dimension is an alternative, it will be added to the alternative dimensions.
|
||||
* @memberof HyperCubeHandler
|
||||
* @example
|
||||
* const dimension = hyperCubeHandler.addDimension(dimension, alternative, idx);
|
||||
*/
|
||||
addDimension(dimension, alternative, idx) {
|
||||
const dim = initializeField(dimension);
|
||||
const dim = initializeDim(dimension);
|
||||
|
||||
if (hcUtils.isDimensionAlternative(this, alternative)) {
|
||||
return hcUtils.addAlternativeDimension(this, dim, idx);
|
||||
@@ -75,6 +155,18 @@ class HyperCubeHandler extends DataPropertyHandler {
|
||||
return addMainDimension(this, dim, idx);
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @param {qix.NxDimension[]} dimensions
|
||||
* @param {boolean} alternative
|
||||
* @returns {qix.NxDimension[]} added dimensions
|
||||
* @description Adds multiple dimensions to the hypercube.
|
||||
* If the dimensions are alternatives, they will be added to the alternative dimensions.
|
||||
* If the total number of dimensions exceeds the limit, it will stop adding dimensions.
|
||||
* @memberof HyperCubeHandler
|
||||
* @example
|
||||
* const addedDimensions = await hyperCubeHandler.addDimensions(dimensions, alternative);
|
||||
*/
|
||||
async addDimensions(dimensions, alternative = false) {
|
||||
const existingDimensions = this.getDimensions();
|
||||
const initialLength = existingDimensions.length;
|
||||
@@ -87,7 +179,7 @@ class HyperCubeHandler extends DataPropertyHandler {
|
||||
return addedDimensions;
|
||||
}
|
||||
|
||||
const dim = initializeField(dimension);
|
||||
const dim = initializeDim(dimension);
|
||||
|
||||
if (hcUtils.isDimensionAlternative(this, alternative)) {
|
||||
const altDim = await hcUtils.addAlternativeDimension(this, dim);
|
||||
@@ -101,6 +193,16 @@ class HyperCubeHandler extends DataPropertyHandler {
|
||||
return addedDimensions;
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @param {number} idx
|
||||
* @param {boolean} alternative
|
||||
* @description Removes a dimension from the hypercube by index.
|
||||
* If the dimension is an alternative, it will be removed from the alternative dimensions.
|
||||
* @memberof HyperCubeHandler
|
||||
* @example
|
||||
* hyperCubeHandler.removeDimension(idx, alternative);
|
||||
*/
|
||||
removeDimension(idx, alternative) {
|
||||
if (alternative) {
|
||||
removeAlternativeDimension(this, idx);
|
||||
@@ -109,6 +211,18 @@ class HyperCubeHandler extends DataPropertyHandler {
|
||||
removeMainDimension(this, idx);
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @param {number[]} indexes
|
||||
* @param {boolean} alternative
|
||||
* @returns {qix.NxDimension[]} deleted dimensions
|
||||
* @description Removes multiple dimensions from the hypercube by indexes.
|
||||
* If the dimensions are alternatives, they will be removed from the alternative dimensions.
|
||||
* If the indexes are empty, it will return an empty array.
|
||||
* @memberof HyperCubeHandler
|
||||
* @example
|
||||
* const deletedDimensions = await hyperCubeHandler.removeDimensions(indexes, alternative);
|
||||
*/
|
||||
async removeDimensions(indexes, alternative) {
|
||||
const altDimensions = this.getAlternativeDimensions();
|
||||
const dimensions = this.getDimensions();
|
||||
@@ -137,10 +251,31 @@ class HyperCubeHandler extends DataPropertyHandler {
|
||||
return deletedDimensions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Replaces a dimension in the hypercube.
|
||||
* @private
|
||||
* @param {number} index - The index of the dimension to replace.
|
||||
* @param {qix.NxDimension} dimension - The new dimension to replace the old one.
|
||||
* @returns {Promise<qix.NxDimension>} replaced dimension.
|
||||
* @memberof HyperCubeHandler
|
||||
* @example
|
||||
* const replacedDimension = await hyperCubeHandler.replaceDimension(index, newDimension);
|
||||
*/
|
||||
replaceDimension(index, dimension) {
|
||||
return this.autoSortDimension(dimension).then(() => hcUtils.replaceDimensionOrder(this, index, dimension));
|
||||
}
|
||||
|
||||
/**
|
||||
* Reinserts a dimension into the hypercube.
|
||||
* @private
|
||||
* @param {qix.NxDimension} dimension - The dimension to reinsert.
|
||||
* @param {boolean} alternative - Whether the dimension is an alternative.
|
||||
* @param {number} idx - The index to insert the dimension at.
|
||||
* @returns {Promise<qix.NxDimension>} The reinserted dimension.
|
||||
* @memberof HyperCubeHandler
|
||||
* @example
|
||||
* await hyperCubeHandler.reinsertDimension(dimension, alternative, idx);
|
||||
*/
|
||||
reinsertDimension(dimension, alternative, idx) {
|
||||
const dim = initializeId(dimension);
|
||||
|
||||
@@ -153,19 +288,26 @@ class HyperCubeHandler extends DataPropertyHandler {
|
||||
return reinsertMainDimension(this, dim, idx);
|
||||
}
|
||||
|
||||
/**
|
||||
* Moves a dimension within the hypercube.
|
||||
* @private
|
||||
* @param {number} fromIndex - The current index of the dimension.
|
||||
* @param {number} toIndex - The new index of the dimension.
|
||||
* @returns {Promise<qix.NxDimension[]>} updated dimensions.
|
||||
* @memberof HyperCubeHandler
|
||||
* @example
|
||||
* await hyperCubeHandler.moveDimension(fromIndex, toIndex);
|
||||
*/
|
||||
moveDimension(fromIndex, toIndex) {
|
||||
const dimensions = this.getDimensions();
|
||||
const altDimensions = this.getAlternativeDimensions();
|
||||
|
||||
if (fromIndex < dimensions.length && toIndex < dimensions.length) {
|
||||
// Move within main dimensions
|
||||
return Promise.resolve(arrayUtil.move(dimensions, fromIndex, toIndex));
|
||||
}
|
||||
|
||||
if (fromIndex < dimensions.length && toIndex >= dimensions.length) {
|
||||
return hcUtils.moveDimensionFromMainToAlternative(fromIndex, toIndex, dimensions, altDimensions);
|
||||
}
|
||||
|
||||
if (fromIndex >= dimensions.length && toIndex < dimensions.length) {
|
||||
return Promise.resolve(hcUtils.moveMeasureFromAlternativeToMain(fromIndex, toIndex, dimensions, altDimensions));
|
||||
}
|
||||
@@ -173,45 +315,112 @@ class HyperCubeHandler extends DataPropertyHandler {
|
||||
return Promise.resolve(hcUtils.moveDimensionWithinAlternative(fromIndex, toIndex, dimensions, altDimensions));
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @param {qix.NxDimension} dimension
|
||||
* @returns {qix.NxDimension} dimension with auto-sort properties
|
||||
* @description Automatically sorts the dimension based on its properties.
|
||||
* If the dimension has a qLibraryId, it will use the library dimension auto-sort.
|
||||
* Otherwise, it will use the field dimension auto-sort.
|
||||
* @memberof HyperCubeHandler
|
||||
* @example
|
||||
* const sortedDimension = hyperCubeHandler.autoSortDimension(dimension);
|
||||
*/
|
||||
autoSortDimension(dimension) {
|
||||
if (dimension.qLibraryId) {
|
||||
return getAutoSortLibraryDimension(this, dimension);
|
||||
}
|
||||
return getAutoSortFieldDimension(this, dimension);
|
||||
return getAutoSortDimension(this, dimension);
|
||||
}
|
||||
|
||||
// ----------------------------------
|
||||
// ------------ MEASURES ------------
|
||||
// ----------------------------------
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @returns {qix.NxMeasure[]} measures
|
||||
* @description Returns the measures of the hypercube.
|
||||
* @memberof HyperCubeHandler
|
||||
* @example
|
||||
* const measures = hyperCubeHandler.getMeasures();
|
||||
*/
|
||||
getMeasures() {
|
||||
return this.hcProperties ? this.hcProperties.qMeasures : [];
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @returns {qix.NxMeasure[]} alternative measures
|
||||
* @description Returns the alternative measures of the hypercube.
|
||||
* @memberof HyperCubeHandler
|
||||
* @example
|
||||
* const alternativeMeasures = hyperCubeHandler.getAlternativeMeasures();
|
||||
*/
|
||||
getAlternativeMeasures() {
|
||||
return this.hcProperties?.qLayoutExclude?.qHyperCubeDef?.qMeasures ?? [];
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @returns {qix.NxMeasureInfo[]} measure layouts
|
||||
* @description Returns the measure layouts of the hypercube.
|
||||
* @memberof HyperCubeHandler
|
||||
* @example
|
||||
* const measureLayouts = hyperCubeHandler.getMeasureLayouts();
|
||||
*/
|
||||
getMeasureLayouts() {
|
||||
const hc = hcUtils.getHyperCube(this.layout, this.path);
|
||||
return hc ? hc.qMeasureInfo : [];
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @param {string} cId
|
||||
* @returns {object} measure layout
|
||||
* @description Returns the measure layout of the hypercube for a given cId.
|
||||
* @memberof HyperCubeHandler
|
||||
* @example
|
||||
* const measureLayout = hyperCubeHandler.getMeasureLayout(cId);
|
||||
*/
|
||||
getMeasureLayout(cId) {
|
||||
return this.getMeasureLayouts().filter((item) => cId === item.cId)[0];
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @param {qix.NxMeasure} measure
|
||||
* @param {boolean} alternative
|
||||
* @param {number=} idx
|
||||
* @returns {Promise<qix.NxMeasure>} measure
|
||||
* @description Adds a measure to the hypercube.
|
||||
* If the measure is an alternative, it will be added to the alternative measures.
|
||||
* If the total number of measures exceeds the limit, it will stop adding measures.
|
||||
* @memberof HyperCubeHandler
|
||||
* @example
|
||||
* const measure = hyperCubeHandler.addMeasure(measure, alternative, idx);
|
||||
*/
|
||||
addMeasure(measure, alternative, idx) {
|
||||
const measures = this.getAlternativeMeasure();
|
||||
const meas = initializeId(measure);
|
||||
|
||||
if (hcUtils.isMeasureAlternative(this, measures, alternative)) {
|
||||
return hcUtils.addAlternativeMeasure(this, meas, idx);
|
||||
if (hcUtils.isMeasureAlternative(this, alternative)) {
|
||||
const hcMeasures = this.hcProperties.qLayoutExclude.qHyperCubeDef.qMeasures;
|
||||
return hcUtils.addAlternativeMeasure(meas, hcMeasures, idx);
|
||||
}
|
||||
|
||||
return addMainMeasure(this, meas, idx);
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @param {qix.NxMeasure} measure
|
||||
* @returns {Promise<qix.NxMeasure>} measure with auto-sort properties
|
||||
* @description Automatically sorts the measure based on its properties.
|
||||
* It sets the qSortByLoadOrder and qSortByNumeric properties.
|
||||
* @memberof HyperCubeHandler
|
||||
* @example
|
||||
* const sortedMeasure = hyperCubeHandler.autoSortMeasure(measure);
|
||||
*/
|
||||
// eslint-disable-next-line class-methods-use-this
|
||||
autoSortMeasure(measure) {
|
||||
const meas = measure;
|
||||
@@ -222,6 +431,18 @@ class HyperCubeHandler extends DataPropertyHandler {
|
||||
return Promise.resolve(meas);
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @param {qix.NxMeasure[]} measures
|
||||
* @param {boolean} alternative
|
||||
* @returns {qix.NxMeasure[]} added measures
|
||||
* @description Adds multiple measures to the hypercube.
|
||||
* If the measures are alternatives, they will be added to the alternative measures.
|
||||
* If the total number of measures exceeds the limit, it will stop adding measures.
|
||||
* @memberof HyperCubeHandler
|
||||
* @example
|
||||
* const addedMeasures = await hyperCubeHandler.addMeasures(measures, alternative);
|
||||
*/
|
||||
addMeasures(measures, alternative = false) {
|
||||
const existingMeasures = this.getMeasures();
|
||||
const addedMeasures = [];
|
||||
@@ -234,7 +455,7 @@ class HyperCubeHandler extends DataPropertyHandler {
|
||||
|
||||
const meas = initializeId(measure);
|
||||
|
||||
if (hcUtils.isMeasureAlternative(this, existingMeasures, alternative)) {
|
||||
if (hcUtils.isMeasureAlternative(this, alternative)) {
|
||||
hcUtils.addAlternativeMeasure(this, meas);
|
||||
addedMeasures.push(meas);
|
||||
} else if (existingMeasures.length < this.maxMeasures()) {
|
||||
@@ -246,6 +467,16 @@ class HyperCubeHandler extends DataPropertyHandler {
|
||||
return addedMeasures;
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @param {number} idx
|
||||
* @param {boolean} alternative
|
||||
* @description Removes a measure from the hypercube by index.
|
||||
* If the measure is an alternative, it will be removed from the alternative measures.
|
||||
* @memberof HyperCubeHandler
|
||||
* @example
|
||||
* hyperCubeHandler.removeMeasure(idx, alternative);
|
||||
*/
|
||||
removeMeasure(idx, alternative) {
|
||||
if (alternative) {
|
||||
hcUtils.removeAltMeasureByIndex(this, idx);
|
||||
@@ -253,13 +484,25 @@ class HyperCubeHandler extends DataPropertyHandler {
|
||||
removeMainMeasure(this, idx);
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @param {number[]} indexes
|
||||
* @param {boolean} alternative
|
||||
* @returns {Promise<number[]>} deleted measures
|
||||
* @description Removes multiple measures from the hypercube by indexes.
|
||||
* If the measures are alternatives, they will be removed from the alternative measures.
|
||||
* If the indexes are empty, it will return an empty array.
|
||||
* @memberof HyperCubeHandler
|
||||
* @example
|
||||
* const deletedMeasures = await hyperCubeHandler.removeMeasures(indexes, alternative);
|
||||
*/
|
||||
async removeMeasures(indexes, alternative) {
|
||||
const measures = this.getMeasures();
|
||||
const altMeasures = this.getAlternativeMeasures();
|
||||
|
||||
if (indexes.length === 0) return [];
|
||||
let deletedMeasures = [];
|
||||
|
||||
if (indexes.length === 0) return deletedMeasures;
|
||||
|
||||
if (alternative && altMeasures.length > 0) {
|
||||
// Keep the original deleted order
|
||||
deletedMeasures = hcUtils.getDeletedFields(altMeasures, indexes);
|
||||
@@ -278,21 +521,52 @@ class HyperCubeHandler extends DataPropertyHandler {
|
||||
return deletedMeasures;
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @param {number} index
|
||||
* @param {qix.NxMeasure} measure
|
||||
* @returns {Promise<qix.NxMeasure>} replaced measure
|
||||
* @description Replaces a measure in the hypercube.
|
||||
* @memberof HyperCubeHandler
|
||||
* @example
|
||||
* const updatedMeasure = await hyperCubeHandler.replaceMeasure(index, measure);
|
||||
*/
|
||||
replaceMeasure(index, measure) {
|
||||
return this.autoSortMeasure(measure).then(() => hcUtils.replaceMeasureToColumnOrder(this, index, measure));
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @param {qix.NxMeasure} measure
|
||||
* @param {boolean} alternative
|
||||
* @param {number} idx
|
||||
* @returns {Promise<qix.NxMeasure>} reinserted measure
|
||||
* @description Reinserts a measure into the hypercube.
|
||||
* @memberof HyperCubeHandler
|
||||
* @example
|
||||
* const reinsertedMeasure = await hyperCubeHandler.reinsertMeasure(measure, alternative, idx);
|
||||
*/
|
||||
reinsertMeasure(measure, alternative, idx) {
|
||||
const measures = this.getAlternativeMeasures();
|
||||
const meas = initializeId(measure);
|
||||
|
||||
if (hcUtils.isMeasureAlternative(this, measures, alternative)) {
|
||||
if (hcUtils.isMeasureAlternative(this, alternative)) {
|
||||
return hcUtils.addAlternativeMeasure(this, meas, idx);
|
||||
}
|
||||
|
||||
return reinsertMainMeasure(this, meas, idx);
|
||||
}
|
||||
|
||||
/**
|
||||
* Moves a measure within the hypercube.
|
||||
* @private
|
||||
* @param {number} fromIndex
|
||||
* @param {number} toIndex
|
||||
* @returns {Promise<void>}
|
||||
* @description Move measure from one index to another
|
||||
* @memberof HyperCubeHandler
|
||||
* @example
|
||||
* const result = await hyperCubeHandler.moveMeasure(0, 1);
|
||||
*/
|
||||
moveMeasure(fromIndex, toIndex) {
|
||||
const measures = this.getMeasures();
|
||||
const altMeasures = this.getAlternativeMeasures();
|
||||
@@ -317,31 +591,74 @@ class HyperCubeHandler extends DataPropertyHandler {
|
||||
// ------------ OTHERS---- ----------
|
||||
// ----------------------------------
|
||||
|
||||
setSorting(ar) {
|
||||
if (ar && ar.length === this.hcProperties.qInterColumnSortOrder.length) {
|
||||
this.hcProperties.qInterColumnSortOrder = ar;
|
||||
/**
|
||||
* Sets the sorting order for the hypercube.
|
||||
* @private
|
||||
* @param {number[]} arr - The new sorting order.
|
||||
* @memberof HyperCubeHandler
|
||||
* @example
|
||||
* const newSortingOrder = [2, 0, 1];
|
||||
* hyperCubeHandler.setSorting(newSortingOrder);
|
||||
*/
|
||||
setSorting(arr) {
|
||||
if (arr && arr.length === this.hcProperties.qInterColumnSortOrder.length) {
|
||||
this.hcProperties.qInterColumnSortOrder = arr;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the sorting order for the hypercube.
|
||||
* @private
|
||||
* @returns {number[]} The current sorting order.
|
||||
* @memberof HyperCubeHandler
|
||||
* @example
|
||||
* const currentSortingOrder = hyperCubeHandler.getSorting();
|
||||
*/
|
||||
getSorting() {
|
||||
return this.hcProperties.qInterColumnSortOrder;
|
||||
}
|
||||
|
||||
/**
|
||||
* Changes the sorting order for the hypercube.
|
||||
* @private
|
||||
* @param {number} fromIdx - The index to move from.
|
||||
* @param {number} toIdx - The index to move to.
|
||||
* @memberof HyperCubeHandler
|
||||
* @example
|
||||
* const newSortingOrder = hyperCubeHandler.changeSorting(0, 1);
|
||||
*/
|
||||
changeSorting(fromIdx, toIdx) {
|
||||
utils.move(this.hcProperties.qInterColumnSortOrder, fromIdx, toIdx);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the hypercube is in straight mode or pivot mode.
|
||||
* @private
|
||||
* @returns {string} 'S' for straight mode, 'P' for pivot mode
|
||||
* @memberof HyperCubeHandler
|
||||
*/
|
||||
IsHCInStraightMode() {
|
||||
return this.hcProperties.qMode === 'S';
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @param {boolean} value
|
||||
* @description This flag indicates whether we enabled HC modifier and have at least one script
|
||||
* @memberof HyperCubeHandler
|
||||
*/
|
||||
setHCEnabled(value) {
|
||||
// this flag indicate whether we enabled HC modifier and have at least one script
|
||||
if (this.hcProperties) {
|
||||
this.hcProperties.isHCEnabled = value;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the dynamic scripts for the hypercube.
|
||||
* @private
|
||||
* @returns {Array} The dynamic scripts.
|
||||
* @memberof HyperCubeHandler
|
||||
*/
|
||||
getDynamicScripts() {
|
||||
return this.hcProperties?.qDynamicScript || [];
|
||||
}
|
||||
|
||||
@@ -12,3 +12,16 @@ export const INITIAL_SORT_CRITERIAS = [
|
||||
qSortByAscii: 1,
|
||||
},
|
||||
];
|
||||
|
||||
export const uid = () => {
|
||||
const idGen = [
|
||||
[10, 31],
|
||||
[0, 31],
|
||||
[0, 31],
|
||||
[0, 31],
|
||||
[0, 31],
|
||||
[0, 31],
|
||||
];
|
||||
const toChar = ([min, max]) => min + ((Math.random() * (max - min)) | 0).toString(32);
|
||||
return idGen.map(toChar).join('');
|
||||
};
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import getAutoSortFieldDimension from '../get-sorted-field';
|
||||
import getAutoSortDimension from '../get-sorted-field';
|
||||
import findFieldInExpandedList from '../find-field-in-expandedList';
|
||||
import { setAutoSort } from '../field-utils';
|
||||
|
||||
@@ -7,7 +7,7 @@ jest.mock('../field-utils', () => ({
|
||||
setAutoSort: jest.fn(),
|
||||
}));
|
||||
|
||||
describe('getAutoSortFieldDimension', () => {
|
||||
describe('getAutoSortDimension', () => {
|
||||
let self;
|
||||
let dimension;
|
||||
|
||||
@@ -32,7 +32,7 @@ describe('getAutoSortFieldDimension', () => {
|
||||
const fieldList = [{ qName: 'field1' }];
|
||||
self.app.getFieldList.mockResolvedValue(fieldList);
|
||||
|
||||
const result = await getAutoSortFieldDimension(self, dimension);
|
||||
const result = await getAutoSortDimension(self, dimension);
|
||||
|
||||
expect(self.app.getFieldList).toHaveBeenCalled();
|
||||
expect(findFieldInExpandedList).toHaveBeenCalledWith('field1', fieldList);
|
||||
@@ -45,7 +45,7 @@ describe('getAutoSortFieldDimension', () => {
|
||||
self.app.getFieldList.mockResolvedValue(fieldList);
|
||||
findFieldInExpandedList.mockReturnValue(field);
|
||||
|
||||
await getAutoSortFieldDimension(self, dimension);
|
||||
await getAutoSortDimension(self, dimension);
|
||||
|
||||
expect(setAutoSort).toHaveBeenCalledWith([field], dimension, self);
|
||||
});
|
||||
@@ -54,7 +54,7 @@ describe('getAutoSortFieldDimension', () => {
|
||||
self.app.getFieldList.mockResolvedValue([]);
|
||||
findFieldInExpandedList.mockReturnValue(null);
|
||||
|
||||
await getAutoSortFieldDimension(self, dimension);
|
||||
await getAutoSortDimension(self, dimension);
|
||||
|
||||
expect(setAutoSort).not.toHaveBeenCalled();
|
||||
});
|
||||
@@ -62,7 +62,7 @@ describe('getAutoSortFieldDimension', () => {
|
||||
test('should handle empty field list', async () => {
|
||||
self.app.getFieldList.mockResolvedValue([]);
|
||||
|
||||
const result = await getAutoSortFieldDimension(self, dimension);
|
||||
const result = await getAutoSortDimension(self, dimension);
|
||||
|
||||
expect(result).toBe(dimension);
|
||||
expect(setAutoSort).not.toHaveBeenCalled();
|
||||
@@ -72,7 +72,7 @@ describe('getAutoSortFieldDimension', () => {
|
||||
dimension.qDef.qFieldDefs = undefined;
|
||||
self.app.getFieldList.mockResolvedValue([]);
|
||||
|
||||
const result = await getAutoSortFieldDimension(self, dimension);
|
||||
const result = await getAutoSortDimension(self, dimension);
|
||||
|
||||
expect(result).toBe(dimension);
|
||||
expect(setAutoSort).not.toHaveBeenCalled();
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
// eslint-disable-next-line import/no-relative-packages
|
||||
import uid from '../../../../../nucleus/src/object/uid';
|
||||
import { AUTOCALENDAR_NAME } from '../constants';
|
||||
import { AUTOCALENDAR_NAME, uid } from '../constants';
|
||||
|
||||
export const getField = (expression) => {
|
||||
let exp = expression;
|
||||
@@ -33,7 +31,7 @@ export const initializeId = (field) => ({
|
||||
},
|
||||
});
|
||||
|
||||
export const initializeField = (field) => ({
|
||||
export const initializeDim = (field) => ({
|
||||
...initializeId(field),
|
||||
qOtherTotalSpec: field.qOtherTotalSpec ?? {},
|
||||
});
|
||||
@@ -62,6 +60,13 @@ export const setAutoSort = (fields, dimension, self) => {
|
||||
});
|
||||
};
|
||||
|
||||
export const isDateField = (field) =>
|
||||
field?.qDerivedFieldData && (field?.qTags?.indexOf('$date') > -1 || field?.qTags?.indexOf('$timestamp') > -1);
|
||||
|
||||
export const isGeoField = (field) => field.qTags.indexOf('$geoname') > -1;
|
||||
|
||||
export const trimAutoCalendarName = (fieldName) => (fieldName ? fieldName.split(AUTOCALENDAR_NAME).join('') : '');
|
||||
|
||||
export const useMasterNumberFormat = (formatting) => {
|
||||
const format = formatting;
|
||||
format.quarantine = {
|
||||
@@ -71,10 +76,3 @@ export const useMasterNumberFormat = (formatting) => {
|
||||
format.qNumFormat = null;
|
||||
format.isCustomFormatted = undefined;
|
||||
};
|
||||
|
||||
export const isDateField = (field) =>
|
||||
field?.qDerivedFieldData && (field?.qTags?.indexOf('$date') > -1 || field?.qTags?.indexOf('$timestamp') > -1);
|
||||
|
||||
export const isGeoField = (field) => field.qTags.indexOf('$geoname') > -1;
|
||||
|
||||
export const trimAutoCalendarName = (fieldName) => (fieldName ? fieldName.split(AUTOCALENDAR_NAME).join('') : '');
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import findFieldInExpandedList from './find-field-in-expandedList';
|
||||
import { setAutoSort } from './field-utils';
|
||||
|
||||
function getAutoSortFieldDimension(self, dimension) {
|
||||
function getAutoSortDimension(self, dimension) {
|
||||
return self.app.getFieldList().then((fieldList) => {
|
||||
const field = dimension?.qDef?.qFieldDefs && findFieldInExpandedList(dimension.qDef.qFieldDefs[0], fieldList);
|
||||
if (field) {
|
||||
@@ -11,4 +11,4 @@ function getAutoSortFieldDimension(self, dimension) {
|
||||
});
|
||||
}
|
||||
|
||||
export default getAutoSortFieldDimension;
|
||||
export default getAutoSortDimension;
|
||||
|
||||
@@ -44,7 +44,7 @@ describe('addMainMeasure', () => {
|
||||
|
||||
const result = await addMainMeasure(self, newMeasure, index);
|
||||
|
||||
expect(result).toEqual(newMeasure);
|
||||
expect(result).toBeUndefined();
|
||||
expect(self.autoSortMeasure).not.toHaveBeenCalledWith(newMeasure);
|
||||
expect(self.hcProperties.qInterColumnSortOrder).toEqual([1, 0, 2]);
|
||||
});
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
// eslint-disable-next-line import/no-relative-packages
|
||||
import uid from '../../../../../../nucleus/src/object/uid';
|
||||
import { uid } from '../../constants';
|
||||
import * as hcUtils from '../hypercube-utils';
|
||||
|
||||
jest.mock('../../../../../../nucleus/src/object/uid', () => jest.fn());
|
||||
jest.mock('../../constants', () => ({
|
||||
uid: jest.fn(),
|
||||
}));
|
||||
|
||||
describe('replaceDimensionToColumnOrder', () => {
|
||||
let self;
|
||||
|
||||
@@ -9,11 +9,12 @@ function addMainMeasure(self, measure, index) {
|
||||
|
||||
return self.autoSortMeasure(measure).then(() => {
|
||||
addMeasureToColumnSortOrder(self, measures);
|
||||
return addMeasureToColumnOrder(self, measure).then(() => measure);
|
||||
addMeasureToColumnOrder(self, measure).then(() => measure);
|
||||
return measure;
|
||||
});
|
||||
}
|
||||
|
||||
return measure;
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
export default addMainMeasure;
|
||||
|
||||
@@ -1,10 +1,5 @@
|
||||
// eslint-disable-next-line import/no-relative-packages
|
||||
import getValue from '../../../../../conversion/src/utils';
|
||||
// eslint-disable-next-line import/no-relative-packages
|
||||
import arrayUtil from '../../../../../conversion/src/array-util';
|
||||
import { TOTAL_MAX } from '../constants';
|
||||
// eslint-disable-next-line import/no-relative-packages
|
||||
import uid from '../../../../../nucleus/src/object/uid';
|
||||
import { arrayUtil, utils } from '@nebula.js/conversion';
|
||||
import { TOTAL_MAX, uid } from '../constants';
|
||||
|
||||
export const notSupportedError = new Error('Not supported in this object, need to implement in subclass.');
|
||||
|
||||
@@ -33,7 +28,7 @@ export const getHyperCube = (layout, path) => {
|
||||
if (!layout) {
|
||||
return undefined;
|
||||
}
|
||||
return path && getValue(layout, path) ? getValue(layout, path).qHyperCube : layout.qHyperCube;
|
||||
return path && utils.getValue(layout, path) ? utils.getValue(layout, path).qHyperCube : layout.qHyperCube;
|
||||
};
|
||||
|
||||
export function setDefaultProperties(self) {
|
||||
@@ -241,7 +236,8 @@ export function isTotalMeasureExceeded(self, measures) {
|
||||
return altMeasures.length + measures.length >= TOTAL_MAX.MEASURES;
|
||||
}
|
||||
|
||||
export function isMeasureAlternative(self, measures, alternative) {
|
||||
export function isMeasureAlternative(self, alternative) {
|
||||
const measures = self.getMeasures();
|
||||
return alternative || (self.maxMeasures() <= measures.length && measures.length < TOTAL_MAX.MEASURES);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
import generator from './generator';
|
||||
import JSONPatch from './json-patch';
|
||||
|
||||
export { default as HyperCubeHandler } from './handler/hypercube-handler';
|
||||
export { default as DataPropertyHandler } from './handler/data-property-handler';
|
||||
export { generator, JSONPatch };
|
||||
|
||||
// core hooks
|
||||
|
||||
Reference in New Issue
Block a user