mirror of
https://github.com/qlik-oss/nebula.js.git
synced 2025-12-19 17:58:43 -05:00
chore: add hypercube generic functions - part02 (#1715)
* chore: add hypercube generic functions - part02
This commit is contained in:
committed by
GitHub
parent
6b84132273
commit
445d6949e7
@@ -1,61 +0,0 @@
|
|||||||
import HyperCubeHandler from '../hypercube-handler';
|
|
||||||
|
|
||||||
describe('DataPropertyHandler - getDimensions and getMeasure', () => {
|
|
||||||
let handler;
|
|
||||||
let properties;
|
|
||||||
|
|
||||||
beforeEach(() => {
|
|
||||||
properties = {
|
|
||||||
qHyperCubeDef: {
|
|
||||||
qDimensions: [{ qDef: { cId: 'dim1' } }],
|
|
||||||
qLayoutExclude: {
|
|
||||||
qHyperCubeDef: {
|
|
||||||
qDimensions: [{ qDef: { cId: 'altDim1' } }],
|
|
||||||
qMeasures: [{ qDef: { cId: 'altMeasure1' } }],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
handler = new HyperCubeHandler(properties);
|
|
||||||
});
|
|
||||||
|
|
||||||
afterEach(() => {
|
|
||||||
jest.clearAllMocks();
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('getDimensions()', () => {
|
|
||||||
test('should return null when dimension is undefined', () => {
|
|
||||||
jest.spyOn(handler, 'getDimensions').mockReturnValue([]);
|
|
||||||
const dimension = handler.getDimension(undefined);
|
|
||||||
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');
|
|
||||||
expect(dimension).toEqual({ qDef: { cId: 'dim1' } });
|
|
||||||
const alternativeDimension = handler.getDimension('altDim1');
|
|
||||||
expect(alternativeDimension).toEqual({ qDef: { cId: 'altDim1' } });
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('getMeasure()', () => {
|
|
||||||
test('should return null when both measures and alternative measures are empty', () => {
|
|
||||||
jest.spyOn(handler, 'getMeasures').mockReturnValue([]);
|
|
||||||
const measure = handler.getMeasure(undefined);
|
|
||||||
expect(measure).toBeFalsy();
|
|
||||||
});
|
|
||||||
|
|
||||||
test('should return measure when it exists in getMeasures()', () => {
|
|
||||||
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');
|
|
||||||
expect(measure).toEqual({ qDef: { cId: 'measure1' } });
|
|
||||||
expect(alternativeMeasure).toEqual({ qDef: { cId: 'altMeasure1' } });
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@@ -1,115 +0,0 @@
|
|||||||
import HyperCubeHandler from '../hypercube-handler';
|
|
||||||
|
|
||||||
describe('HyperCube Handlers', () => {
|
|
||||||
let handler;
|
|
||||||
let properties;
|
|
||||||
|
|
||||||
beforeEach(() => {
|
|
||||||
properties = {
|
|
||||||
qHyperCubeDef: {
|
|
||||||
qDimensions: [{ qDef: { cId: 'dim1' } }],
|
|
||||||
qInterColumnSortOrder: [0, 1],
|
|
||||||
qLayoutExclude: {
|
|
||||||
qHyperCubeDef: {
|
|
||||||
qDimensions: [{ qDef: { cId: 'altDim1' } }],
|
|
||||||
qMeasures: [{ qDef: { cId: 'altMeasure1' } }],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
handler = new HyperCubeHandler(properties);
|
|
||||||
});
|
|
||||||
|
|
||||||
afterEach(() => {
|
|
||||||
jest.clearAllMocks();
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('setProperties', () => {
|
|
||||||
test('should return undefined when properties is null or undefined', () => {
|
|
||||||
handler.setProperties(null);
|
|
||||||
expect(handler.hcProperties).toBeUndefined();
|
|
||||||
handler.setProperties({});
|
|
||||||
expect(handler.hcProperties).toBeUndefined();
|
|
||||||
handler.setProperties(undefined);
|
|
||||||
expect(handler.hcProperties).toBeUndefined();
|
|
||||||
});
|
|
||||||
|
|
||||||
test('should set properties when qHyperCubeDef provides defined/undefined values', () => {
|
|
||||||
properties.qHyperCubeDef.qLayoutExclude.qHyperCubeDef.qDimensions = undefined;
|
|
||||||
handler.setProperties(properties);
|
|
||||||
|
|
||||||
expect(handler.hcProperties.qDimensions[0]).toEqual({ qDef: { cId: 'dim1' } });
|
|
||||||
expect(handler.hcProperties.qMeasures).toEqual([]);
|
|
||||||
expect(handler.hcProperties.qInterColumnSortOrder).toEqual([0, 1]);
|
|
||||||
expect(handler.hcProperties.qLayoutExclude).toEqual({
|
|
||||||
qHyperCubeDef: {
|
|
||||||
qDimensions: [],
|
|
||||||
qMeasures: [{ qDef: { cId: 'altMeasure1' } }],
|
|
||||||
},
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
test('should set properties when qLayoutExclude.qHyperCubeDef is undefined', () => {
|
|
||||||
properties.qHyperCubeDef.qLayoutExclude.qHyperCubeDef = undefined;
|
|
||||||
handler.setProperties(properties);
|
|
||||||
|
|
||||||
expect(handler.hcProperties.qLayoutExclude).toEqual({
|
|
||||||
qHyperCubeDef: {
|
|
||||||
qDimensions: [],
|
|
||||||
qMeasures: [],
|
|
||||||
},
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('getDimensions and getAlternativeDimensions', () => {
|
|
||||||
test('should return empty arrays when hcProperties is null', () => {
|
|
||||||
handler.hcProperties = null;
|
|
||||||
|
|
||||||
expect(handler.getDimensions()).toEqual([]);
|
|
||||||
expect(handler.getAlternativeDimensions()).toEqual([]);
|
|
||||||
});
|
|
||||||
|
|
||||||
test('should return empty arrays when qDimensions and qLayoutExclude.qHyperCubeDef.qDimensions are empty', () => {
|
|
||||||
handler.hcProperties = {
|
|
||||||
qDimensions: [],
|
|
||||||
qLayoutExclude: {
|
|
||||||
qHyperCubeDef: {
|
|
||||||
qDimensions: [],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
expect(handler.getDimensions()).toEqual([]);
|
|
||||||
expect(handler.getAlternativeDimensions()).toEqual([]);
|
|
||||||
});
|
|
||||||
|
|
||||||
test('should return qDimensions when qDimensions contains dimensions', () => {
|
|
||||||
handler.hcProperties = {
|
|
||||||
qDimensions: [{ qDef: { cId: 'dim1' } }, { qDef: { cId: 'dim2' } }],
|
|
||||||
qLayoutExclude: {
|
|
||||||
qHyperCubeDef: {
|
|
||||||
qDimensions: [],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
expect(handler.getDimensions()).toEqual([{ qDef: { cId: 'dim1' } }, { qDef: { cId: 'dim2' } }]);
|
|
||||||
expect(handler.getAlternativeDimensions()).toEqual([]);
|
|
||||||
});
|
|
||||||
|
|
||||||
test('should return qLayoutExclude.qHyperCubeDef.qDimensions when it contains alternative dimensions', () => {
|
|
||||||
handler.hcProperties = {
|
|
||||||
qDimensions: [],
|
|
||||||
qLayoutExclude: {
|
|
||||||
qHyperCubeDef: {
|
|
||||||
qDimensions: [{ qDef: { cId: 'altDim1' } }, { qDef: { cId: 'altDim2' } }],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
expect(handler.getDimensions()).toEqual([]);
|
|
||||||
expect(handler.getAlternativeDimensions()).toEqual([{ qDef: { cId: 'altDim1' } }, { qDef: { cId: 'altDim2' } }]);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@@ -0,0 +1,180 @@
|
|||||||
|
import DataPropertyHandler from '../data-property-handler';
|
||||||
|
import HyperCubeHandler from '../hypercube-handler';
|
||||||
|
|
||||||
|
describe('DataPropertyHandler', () => {
|
||||||
|
let handler;
|
||||||
|
let properties;
|
||||||
|
const sortingProperties = [
|
||||||
|
{
|
||||||
|
qSortByLoadOrder: 1,
|
||||||
|
qSortByNumeric: 1,
|
||||||
|
qSortByAscii: 1,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
properties = {
|
||||||
|
qHyperCubeDef: {
|
||||||
|
qDimensions: [{ qDef: { cId: 'dim1' } }],
|
||||||
|
qLayoutExclude: {
|
||||||
|
qHyperCubeDef: {
|
||||||
|
qDimensions: [{ qDef: { cId: 'altDim1' } }],
|
||||||
|
qMeasures: [{ qDef: { cId: 'altMeasure1' } }],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
handler = new HyperCubeHandler(properties);
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(() => {
|
||||||
|
jest.clearAllMocks();
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('getDimensions()', () => {
|
||||||
|
test('should return null when dimension is undefined', () => {
|
||||||
|
jest.spyOn(handler, 'getDimensions').mockReturnValue([]);
|
||||||
|
const dimension = handler.getDimension(undefined);
|
||||||
|
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');
|
||||||
|
expect(dimension).toEqual({ qDef: { cId: 'dim1' } });
|
||||||
|
const alternativeDimension = handler.getDimension('altDim1');
|
||||||
|
expect(alternativeDimension).toEqual({ qDef: { cId: 'altDim1' } });
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('getMeasure()', () => {
|
||||||
|
test('should return null when both measures and alternative measures are empty', () => {
|
||||||
|
jest.spyOn(handler, 'getMeasures').mockReturnValue([]);
|
||||||
|
const measure = handler.getMeasure(undefined);
|
||||||
|
expect(measure).toBeFalsy();
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should return measure when it exists in getMeasures()', () => {
|
||||||
|
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');
|
||||||
|
expect(measure).toEqual({ qDef: { cId: 'measure1' } });
|
||||||
|
expect(alternativeMeasure).toEqual({ qDef: { cId: 'altMeasure1' } });
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('createFieldDimension', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
handler = new DataPropertyHandler({
|
||||||
|
dimensionProperties: { someProperty: 'defaultValue' },
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should create a dimension with default properties when no field is provided', () => {
|
||||||
|
const result = handler.createFieldDimension(null, null, { customDefault: 'value' });
|
||||||
|
|
||||||
|
expect(result.qDef.qFieldDefs).toEqual([null]);
|
||||||
|
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');
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('createLibraryDimension', () => {
|
||||||
|
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');
|
||||||
|
});
|
||||||
|
|
||||||
|
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 dimension with provided field and label', () => {
|
||||||
|
const result = handler.createFieldDimension('fieldName', 'fieldLabel', { customDefault: 'value' });
|
||||||
|
|
||||||
|
expect(result.qDef.qFieldDefs).toEqual(['fieldName']);
|
||||||
|
expect(result.qDef.qFieldLabels).toEqual(['fieldLabel']);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('createExpressionMeasure', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
handler = new DataPropertyHandler({
|
||||||
|
measureProperties: { someProperty: 'defaultValue' },
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should create a measure with provided expression and label', () => {
|
||||||
|
const result = handler.createExpressionMeasure('SUM(Sales)', 'Total Sales', { customDefault: 'value' });
|
||||||
|
|
||||||
|
expect(result.qDef.qDef).toBe('SUM(Sales)');
|
||||||
|
expect(result.qDef.qLabel).toBe('Total Sales');
|
||||||
|
expect(result.qDef.autoSort).toBe(true);
|
||||||
|
expect(result.someProperty).toBe('defaultValue');
|
||||||
|
expect(result.customDefault).toBe('value');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should initialize qDef and qNumFormat if not provided', () => {
|
||||||
|
const result = handler.createExpressionMeasure('SUM(Sales)', 'Total Sales', {});
|
||||||
|
|
||||||
|
expect(result.qDef).toBeDefined();
|
||||||
|
expect(result.qDef.qNumFormat).toBeDefined();
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should handle empty defaults gracefully', () => {
|
||||||
|
const result = handler.createExpressionMeasure('SUM(Sales)', 'Total Sales', null);
|
||||||
|
|
||||||
|
expect(result.qDef.qDef).toBe('SUM(Sales)');
|
||||||
|
expect(result.qDef.qLabel).toBe('Total Sales');
|
||||||
|
expect(result.qDef.autoSort).toBe(true);
|
||||||
|
expect(result.someProperty).toBe('defaultValue');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('createLibraryMeasure', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
handler = new DataPropertyHandler({
|
||||||
|
measureProperties: { someProperty: 'defaultValue' },
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should create a library measure with provided id and defaults', () => {
|
||||||
|
const result = handler.createLibraryMeasure('libraryId', { customDefault: 'value' });
|
||||||
|
|
||||||
|
expect(result.qLibraryId).toBe('libraryId');
|
||||||
|
expect(result.qDef.qNumFormat).toBeDefined();
|
||||||
|
expect(result.qDef.autoSort).toBe(true);
|
||||||
|
expect(result.someProperty).toBe('defaultValue');
|
||||||
|
expect(result.customDefault).toBe('value');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should initialize qDef and qNumFormat if not provided', () => {
|
||||||
|
const result = handler.createLibraryMeasure('libraryId', {});
|
||||||
|
|
||||||
|
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', {});
|
||||||
|
|
||||||
|
expect(result.qDef.qDef).toBeUndefined();
|
||||||
|
expect(result.qDef.qLabel).toBeUndefined();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
291
apis/supernova/src/handler/__tests__/hypercube-handler.test.js
Normal file
291
apis/supernova/src/handler/__tests__/hypercube-handler.test.js
Normal file
@@ -0,0 +1,291 @@
|
|||||||
|
import * as hcHelper from '../utils/hypercube-helper/hypercube-utils';
|
||||||
|
import HyperCubeHandler from '../hypercube-handler';
|
||||||
|
|
||||||
|
describe('HyperCube Handlers', () => {
|
||||||
|
let handler;
|
||||||
|
let properties;
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
properties = {
|
||||||
|
qHyperCubeDef: {
|
||||||
|
qDimensions: [{ qDef: { cId: 'dim1' } }],
|
||||||
|
qMeasures: [],
|
||||||
|
qInterColumnSortOrder: [0, 1],
|
||||||
|
qLayoutExclude: {
|
||||||
|
qHyperCubeDef: {
|
||||||
|
qDimensions: [{ qDef: { cId: 'altDim1' } }],
|
||||||
|
qMeasures: [{ qDef: { cId: 'altMeas1' } }],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
handler = new HyperCubeHandler(properties);
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(() => {
|
||||||
|
handler.hcProperties = undefined;
|
||||||
|
jest.clearAllMocks();
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('setProperties', () => {
|
||||||
|
test('should return undefined when properties is null or undefined', () => {
|
||||||
|
handler.setProperties(null);
|
||||||
|
expect(handler.hcProperties).toBeUndefined();
|
||||||
|
handler.setProperties({});
|
||||||
|
expect(handler.hcProperties).toBeUndefined();
|
||||||
|
handler.setProperties(undefined);
|
||||||
|
expect(handler.hcProperties).toBeUndefined();
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should set properties when qHyperCubeDef provides defined/undefined values', () => {
|
||||||
|
properties.qHyperCubeDef.qLayoutExclude.qHyperCubeDef.qDimensions = undefined;
|
||||||
|
handler.setProperties(properties);
|
||||||
|
|
||||||
|
expect(handler.hcProperties.qDimensions[0]).toEqual({ qDef: { cId: 'dim1' } });
|
||||||
|
expect(handler.hcProperties.qMeasures).toEqual([]);
|
||||||
|
expect(handler.hcProperties.qInterColumnSortOrder).toEqual([0, 1]);
|
||||||
|
expect(handler.hcProperties.qLayoutExclude).toEqual({
|
||||||
|
qHyperCubeDef: {
|
||||||
|
qDimensions: [],
|
||||||
|
qMeasures: [{ qDef: { cId: 'altMeas1' } }],
|
||||||
|
},
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should set properties when qLayoutExclude.qHyperCubeDef is undefined', () => {
|
||||||
|
properties.qHyperCubeDef.qLayoutExclude.qHyperCubeDef = undefined;
|
||||||
|
handler.setProperties(properties);
|
||||||
|
|
||||||
|
expect(handler.hcProperties.qLayoutExclude).toEqual({
|
||||||
|
qHyperCubeDef: {
|
||||||
|
qDimensions: [],
|
||||||
|
qMeasures: [],
|
||||||
|
},
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('getDimensions and getAlternativeDimensions', () => {
|
||||||
|
test('should return empty arrays when hcProperties is null', () => {
|
||||||
|
handler.setProperties(properties);
|
||||||
|
handler.hcProperties = null;
|
||||||
|
|
||||||
|
expect(handler.getDimensions()).toEqual([]);
|
||||||
|
expect(handler.getAlternativeDimensions()).toEqual([]);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should return empty arrays when qDimensions and alternative dimension are empty', () => {
|
||||||
|
handler.setProperties(properties);
|
||||||
|
handler.hcProperties = {
|
||||||
|
qDimensions: [],
|
||||||
|
qLayoutExclude: {
|
||||||
|
qHyperCubeDef: {
|
||||||
|
qDimensions: [],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
expect(handler.getDimensions()).toEqual([]);
|
||||||
|
expect(handler.getAlternativeDimensions()).toEqual([]);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should return alternative dimensions when it has value', () => {
|
||||||
|
handler.setProperties(properties);
|
||||||
|
handler.hcProperties = {
|
||||||
|
qDimensions: [{ qDef: { cId: 'dim1' } }, { qDef: { cId: 'dim2' } }],
|
||||||
|
qLayoutExclude: {
|
||||||
|
qHyperCubeDef: {
|
||||||
|
qDimensions: [{ qDef: { cId: 'altDim1' } }, { qDef: { cId: 'altDim2' } }],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
expect(handler.getDimensions()).toEqual([{ qDef: { cId: 'dim1' } }, { qDef: { cId: 'dim2' } }]);
|
||||||
|
expect(handler.getAlternativeDimensions()).toEqual([{ qDef: { cId: 'altDim1' } }, { qDef: { cId: 'altDim2' } }]);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('addDimensions', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
handler.setProperties(properties);
|
||||||
|
jest.spyOn(hcHelper, 'isTotalDimensionsExceeded').mockReturnValue(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should return an empty array when newDimensions is empty', async () => {
|
||||||
|
const result = await handler.addDimensions([]);
|
||||||
|
expect(result).toEqual([]);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should add dimensions to alternative dimensions when alternative is true', async () => {
|
||||||
|
const newDimensions = [{ qDef: { cId: 'altDim2' } }, { qDef: { cId: 'altDim3' } }];
|
||||||
|
const dimensions = await handler.addDimensions(newDimensions, true);
|
||||||
|
|
||||||
|
expect(dimensions).toEqual([
|
||||||
|
{ qDef: { cId: 'altDim2' }, qOtherTotalSpec: {} },
|
||||||
|
{ qDef: { cId: 'altDim3' }, qOtherTotalSpec: {} },
|
||||||
|
]);
|
||||||
|
expect(handler.hcProperties.qLayoutExclude.qHyperCubeDef.qDimensions).toEqual([
|
||||||
|
{ qDef: { cId: 'altDim1' } },
|
||||||
|
{ qDef: { cId: 'altDim2' }, qOtherTotalSpec: {} },
|
||||||
|
{ qDef: { cId: 'altDim3' }, qOtherTotalSpec: {} },
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should add dimensions to main dimensions when alternative is false', async () => {
|
||||||
|
const newDimensions = [{ qDef: { cId: 'dim2' } }];
|
||||||
|
handler.maxDimensions = jest.fn().mockReturnValue(2);
|
||||||
|
handler.autoSortDimension = jest.fn();
|
||||||
|
|
||||||
|
const dimensions = await handler.addDimensions(newDimensions, false);
|
||||||
|
expect(handler.autoSortDimension).toHaveBeenCalledTimes(1);
|
||||||
|
expect(handler.autoSortDimension).toHaveBeenCalledWith({ qDef: { cId: 'dim2' }, qOtherTotalSpec: {} });
|
||||||
|
|
||||||
|
expect(dimensions).toEqual([{ qDef: { cId: 'dim2' }, qOtherTotalSpec: {} }]);
|
||||||
|
expect(handler.hcProperties.qDimensions).toEqual([
|
||||||
|
{ qDef: { cId: 'dim1' } },
|
||||||
|
{ qDef: { cId: 'dim2' }, qOtherTotalSpec: {} },
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should not add dimensions when isTotalDimensionsExceeded returns true', async () => {
|
||||||
|
jest.spyOn(hcHelper, 'isTotalDimensionsExceeded').mockReturnValue(true);
|
||||||
|
const newDimensions = [{ qDef: { cId: 'dim2' } }];
|
||||||
|
|
||||||
|
const dimensions = await handler.addDimensions(newDimensions);
|
||||||
|
|
||||||
|
expect(dimensions).toEqual([]);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should add dimensions to alternative dimensions when maxDim is exceeded but less than total maxDim', async () => {
|
||||||
|
handler.maxDimensions = jest.fn().mockReturnValue(1);
|
||||||
|
const newDimensions = [{ qDef: { cId: 'dim2' } }];
|
||||||
|
|
||||||
|
const dimension = await handler.addDimensions(newDimensions, false);
|
||||||
|
|
||||||
|
expect(dimension).toEqual([{ qDef: { cId: 'dim2' }, qOtherTotalSpec: {} }]);
|
||||||
|
expect(handler.hcProperties.qDimensions).toEqual([{ qDef: { cId: 'dim1' } }]);
|
||||||
|
expect(handler.hcProperties.qLayoutExclude.qHyperCubeDef.qDimensions).toEqual([
|
||||||
|
{ qDef: { cId: 'altDim1' } },
|
||||||
|
{ qDef: { cId: 'dim2' }, qOtherTotalSpec: {} },
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('getMeasures and getAlternativeMeasures', () => {
|
||||||
|
test('should return empty arrays when hcProperties is null', () => {
|
||||||
|
handler.setProperties(properties);
|
||||||
|
handler.hcProperties = null;
|
||||||
|
|
||||||
|
expect(handler.getMeasures()).toEqual([]);
|
||||||
|
expect(handler.getAlternativeMeasures()).toEqual([]);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should return empty arrays when qMeasures and alternative measures are empty', () => {
|
||||||
|
handler.setProperties(properties);
|
||||||
|
handler.hcProperties = {
|
||||||
|
qMeasures: [],
|
||||||
|
qLayoutExclude: {
|
||||||
|
qHyperCubeDef: {
|
||||||
|
qDimensions: [],
|
||||||
|
qMeasures: [],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
expect(handler.getMeasures()).toEqual([]);
|
||||||
|
expect(handler.getAlternativeMeasures()).toEqual([]);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should return qMeasures when qMeasures has value', () => {
|
||||||
|
handler.setProperties(properties);
|
||||||
|
handler.hcProperties = {
|
||||||
|
qMeasures: [{ qDef: { cId: 'meas1' } }, { qDef: { cId: 'meas2' } }],
|
||||||
|
qLayoutExclude: {
|
||||||
|
qHyperCubeDef: {
|
||||||
|
qMeasures: [{ qDef: { cId: 'altMeas1' } }, { qDef: { cId: 'altMeas2' } }],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
expect(handler.getMeasures()).toEqual([{ qDef: { cId: 'meas1' } }, { qDef: { cId: 'meas2' } }]);
|
||||||
|
expect(handler.getAlternativeMeasures()).toEqual([{ qDef: { cId: 'altMeas1' } }, { qDef: { cId: 'altMeas2' } }]);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('addMeasures', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
properties.qHyperCubeDef.qMeasures = [{ qDef: { cId: 'meas1' } }];
|
||||||
|
handler.setProperties(properties);
|
||||||
|
jest.spyOn(hcHelper, 'isTotalMeasureExceeded').mockReturnValue(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should return an empty array when new measure is empty', () => {
|
||||||
|
const result = handler.addMeasures([]);
|
||||||
|
expect(result).toEqual([]);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should add measures to alternative measures when alternative is true', () => {
|
||||||
|
const newMeasures = [{ qDef: { cId: 'altMeas2' } }, { qDef: { cId: 'altMeas3' } }];
|
||||||
|
const measures = handler.addMeasures(newMeasures, true);
|
||||||
|
|
||||||
|
expect(measures).toEqual([{ qDef: { cId: 'altMeas2' } }, { qDef: { cId: 'altMeas3' } }]);
|
||||||
|
expect(handler.hcProperties.qMeasures).toEqual([{ qDef: { cId: 'meas1' } }]);
|
||||||
|
expect(handler.hcProperties.qLayoutExclude.qHyperCubeDef.qMeasures).toEqual([
|
||||||
|
{ qDef: { cId: 'altMeas1' } },
|
||||||
|
{ qDef: { cId: 'altMeas2' } },
|
||||||
|
{ qDef: { cId: 'altMeas3' } },
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should add measures to main measures when alternative is false', () => {
|
||||||
|
const newMeasures = [{ qDef: { cId: 'meas2' } }];
|
||||||
|
handler.maxMeasures = jest.fn().mockReturnValue(2);
|
||||||
|
handler.autoSortDimension = jest.fn();
|
||||||
|
|
||||||
|
const measures = handler.addMeasures(newMeasures, false);
|
||||||
|
expect(measures).toEqual([
|
||||||
|
{
|
||||||
|
qDef: { cId: 'meas2' },
|
||||||
|
qSortBy: {
|
||||||
|
qSortByLoadOrder: 1,
|
||||||
|
qSortByNumeric: -1,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
expect(handler.hcProperties.qMeasures).toEqual([
|
||||||
|
{ qDef: { cId: 'meas1' } },
|
||||||
|
{
|
||||||
|
qDef: { cId: 'meas2' },
|
||||||
|
qSortBy: {
|
||||||
|
qSortByLoadOrder: 1,
|
||||||
|
qSortByNumeric: -1,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should not add measures when isTotalMeasureExceeded returns true', () => {
|
||||||
|
jest.spyOn(hcHelper, 'isTotalMeasureExceeded').mockReturnValue(true);
|
||||||
|
const newMeasure = [{ qDef: { cId: 'meas2' } }];
|
||||||
|
|
||||||
|
const measure = handler.addMeasures(newMeasure);
|
||||||
|
expect(measure).toEqual([]);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should add measure to alternative measures when maxMeasure is exceeded but less than total', () => {
|
||||||
|
handler.maxMeasures = jest.fn().mockReturnValue(1);
|
||||||
|
const newMeasure = [{ qDef: { cId: 'meas2' } }];
|
||||||
|
|
||||||
|
const measure = handler.addMeasures(newMeasure, false);
|
||||||
|
|
||||||
|
expect(measure).toEqual([{ qDef: { cId: 'meas2' } }]);
|
||||||
|
expect(handler.hcProperties.qMeasures).toEqual([{ qDef: { cId: 'meas1' } }]);
|
||||||
|
expect(handler.hcProperties.qLayoutExclude.qHyperCubeDef.qMeasures).toEqual([
|
||||||
|
{ qDef: { cId: 'altMeas1' } },
|
||||||
|
{
|
||||||
|
qDef: { cId: 'meas2' },
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -1,4 +1,10 @@
|
|||||||
import { getFieldById } from './utils/handler-helper';
|
// eslint-disable-next-line import/no-extraneous-dependencies
|
||||||
|
import { merge } from 'lodash';
|
||||||
|
// eslint-disable-next-line import/no-relative-packages
|
||||||
|
import isEnabled from '../../../nucleus/src/flags/flags';
|
||||||
|
import { findFieldById, initializeField, useMasterNumberFormat } from './utils/field-helper/field-utils';
|
||||||
|
import { INITIAL_SORT_CRITERIAS } from './utils/constants';
|
||||||
|
import { notSupportedError } from './utils/hypercube-helper/hypercube-utils';
|
||||||
|
|
||||||
class DataPropertyHandler {
|
class DataPropertyHandler {
|
||||||
constructor(opts) {
|
constructor(opts) {
|
||||||
@@ -30,7 +36,9 @@ class DataPropertyHandler {
|
|||||||
throw new Error('Must override this method');
|
throw new Error('Must override this method');
|
||||||
}
|
}
|
||||||
|
|
||||||
// ----------------DIMENSION----------------
|
// ---------------------------------------
|
||||||
|
// ---------------DIMENSION---------------
|
||||||
|
// ---------------------------------------
|
||||||
|
|
||||||
static getDimensions() {
|
static getDimensions() {
|
||||||
return [];
|
return [];
|
||||||
@@ -40,26 +48,121 @@ class DataPropertyHandler {
|
|||||||
const dimensions = this.getDimensions();
|
const dimensions = this.getDimensions();
|
||||||
const alternativeDimensions = this.getAlternativeDimensions();
|
const alternativeDimensions = this.getAlternativeDimensions();
|
||||||
|
|
||||||
const dim = getFieldById(dimensions, id);
|
return findFieldById(dimensions, id) ?? findFieldById(alternativeDimensions, id);
|
||||||
const altDim = getFieldById(alternativeDimensions, id);
|
|
||||||
|
|
||||||
return dim ?? altDim;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static getAlternativeDimensions() {
|
static getAlternativeDimensions() {
|
||||||
throw new Error('Method not implemented.');
|
throw new Error('Method not implemented.');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static addDimension() {
|
||||||
|
throw notSupportedError;
|
||||||
|
}
|
||||||
|
|
||||||
|
static addDimensions() {
|
||||||
|
throw notSupportedError;
|
||||||
|
}
|
||||||
|
|
||||||
|
static autoSortDimension() {
|
||||||
|
throw notSupportedError;
|
||||||
|
}
|
||||||
|
|
||||||
|
createLibraryDimension(id, defaults) {
|
||||||
|
let dimension = merge({}, this.dimensionProperties || {}, defaults || {});
|
||||||
|
|
||||||
|
dimension = initializeField(dimension);
|
||||||
|
|
||||||
|
dimension.qLibraryId = id;
|
||||||
|
dimension.qDef.autoSort = true;
|
||||||
|
dimension.qDef.qSortCriterias = INITIAL_SORT_CRITERIAS;
|
||||||
|
|
||||||
|
delete dimension.qDef.qFieldDefs;
|
||||||
|
delete dimension.qDef.qFieldLabels;
|
||||||
|
|
||||||
|
return dimension;
|
||||||
|
}
|
||||||
|
|
||||||
|
createFieldDimension(field, label, defaults) {
|
||||||
|
let dimension = merge({}, this.dimensionProperties || {}, defaults || {});
|
||||||
|
|
||||||
|
dimension = initializeField(dimension);
|
||||||
|
|
||||||
|
if (!field) {
|
||||||
|
dimension.qDef.qFieldDefs = [];
|
||||||
|
dimension.qDef.qFieldLabels = [];
|
||||||
|
dimension.qDef.qSortCriterias = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
dimension.qDef.qFieldDefs = [field];
|
||||||
|
dimension.qDef.qFieldLabels = label ? [label] : [''];
|
||||||
|
dimension.qDef.qSortCriterias = INITIAL_SORT_CRITERIAS;
|
||||||
|
|
||||||
|
dimension.qDef.autoSort = true;
|
||||||
|
|
||||||
|
return dimension;
|
||||||
|
}
|
||||||
|
|
||||||
|
addFieldDimension(field, label, defaults) {
|
||||||
|
const dimension = this.createFieldDimension(field, label, defaults);
|
||||||
|
return this.addDimension(dimension);
|
||||||
|
}
|
||||||
|
|
||||||
|
addFieldDimensions(args) {
|
||||||
|
const dimensions = args.map(({ field, label, defaults }) => this.createFieldDimension(field, label, defaults));
|
||||||
|
return this.addDimensions(dimensions);
|
||||||
|
}
|
||||||
|
|
||||||
|
addLibraryDimension(id, defaults) {
|
||||||
|
const dimension = this.createLibraryDimension(id, defaults);
|
||||||
|
return this.addDimension(dimension);
|
||||||
|
}
|
||||||
|
|
||||||
|
addLibraryDimensions(args) {
|
||||||
|
const dimensions = args.map(({ id, defaults }) => this.createLibraryDimension(id, defaults));
|
||||||
|
const result = this.addDimensions(dimensions);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
async addAltLibraryDimensions(args) {
|
||||||
|
const dimensions = args.map(({ id }) => this.createLibraryDimension(id));
|
||||||
|
return this.addDimensions(dimensions, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
async addAltFieldDimensions(args) {
|
||||||
|
const dimensions = args.map(({ field }) => this.createFieldDimension(field));
|
||||||
|
return this.addDimensions(dimensions, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
addAlternativeFieldDimension(field, label, defaults) {
|
||||||
|
const dimension = this.createFieldDimension(field, label, defaults);
|
||||||
|
return this.addDimension(dimension, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
addAlternativeLibraryDimension(id, defaults) {
|
||||||
|
const dimension = this.createLibraryDimension(id, defaults);
|
||||||
|
return this.addDimension(dimension, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
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];
|
||||||
|
return this.dimensionDefinition.max?.apply(null, dimParams);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Number.isNaN(+this.dimensionDefinition.max) ? 10000 : this.dimensionDefinition.max;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---------------------------------------
|
||||||
// ----------------MEASURE----------------
|
// ----------------MEASURE----------------
|
||||||
|
// ---------------------------------------
|
||||||
|
|
||||||
getMeasure(id) {
|
getMeasure(id) {
|
||||||
const measures = this.getMeasures();
|
const measures = this.getMeasures();
|
||||||
const alternativeMeasures = this.getAlternativeMeasures();
|
const alternativeMeasures = this.getAlternativeMeasures();
|
||||||
|
|
||||||
const meas = getFieldById(measures, id);
|
return findFieldById(measures, id) ?? findFieldById(alternativeMeasures, id);
|
||||||
const altMeas = getFieldById(alternativeMeasures, id);
|
|
||||||
|
|
||||||
return meas ?? altMeas;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static getMeasures() {
|
static getMeasures() {
|
||||||
@@ -69,6 +172,101 @@ class DataPropertyHandler {
|
|||||||
static getAlternativeMeasures() {
|
static getAlternativeMeasures() {
|
||||||
throw new Error('Method not implemented.');
|
throw new Error('Method not implemented.');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static addMeasure() {
|
||||||
|
throw notSupportedError;
|
||||||
|
}
|
||||||
|
|
||||||
|
static addMeasures() {
|
||||||
|
throw notSupportedError;
|
||||||
|
}
|
||||||
|
|
||||||
|
static autoSortMeasure() {
|
||||||
|
throw notSupportedError;
|
||||||
|
}
|
||||||
|
|
||||||
|
createExpressionMeasure(expression, label, defaults) {
|
||||||
|
const measure = merge({}, this.measureProperties || {}, defaults || {});
|
||||||
|
|
||||||
|
measure.qDef = measure.qDef ?? {};
|
||||||
|
measure.qDef.qNumFormat = measure.qDef.qNumFormat ?? {};
|
||||||
|
|
||||||
|
measure.qDef.qDef = expression;
|
||||||
|
measure.qDef.qLabel = label;
|
||||||
|
measure.qDef.autoSort = true;
|
||||||
|
|
||||||
|
return measure;
|
||||||
|
}
|
||||||
|
|
||||||
|
addExpressionMeasure(expression, label, defaults) {
|
||||||
|
const measure = this.createExpressionMeasure(expression, label, defaults);
|
||||||
|
return this.addMeasure(measure);
|
||||||
|
}
|
||||||
|
|
||||||
|
addExpressionMeasures(args) {
|
||||||
|
const measures = args.map(({ expression, label, defaults }) =>
|
||||||
|
this.createExpressionMeasure(expression, label, defaults)
|
||||||
|
);
|
||||||
|
return this.addMeasures(measures);
|
||||||
|
}
|
||||||
|
|
||||||
|
createLibraryMeasure(id, defaults) {
|
||||||
|
const measure = merge({}, this.measureProperties || {}, defaults || {});
|
||||||
|
measure.qDef = measure.qDef ?? {};
|
||||||
|
measure.qDef.qNumFormat = measure.qDef.qNumFormat ?? {};
|
||||||
|
|
||||||
|
if (isEnabled('MASTER_MEASURE_FORMAT')) {
|
||||||
|
useMasterNumberFormat(measure.qDef);
|
||||||
|
}
|
||||||
|
|
||||||
|
measure.qLibraryId = id;
|
||||||
|
measure.qDef.autoSort = true;
|
||||||
|
|
||||||
|
delete measure.qDef.qDef;
|
||||||
|
delete measure.qDef.qLabel;
|
||||||
|
|
||||||
|
return measure;
|
||||||
|
}
|
||||||
|
|
||||||
|
addLibraryMeasure(id, defaults) {
|
||||||
|
const measure = this.createLibraryMeasure(id, defaults);
|
||||||
|
return this.addMeasure(measure);
|
||||||
|
}
|
||||||
|
|
||||||
|
addLibraryMeasures(args) {
|
||||||
|
const measures = args.map(({ id, defaults }) => this.createLibraryMeasure(id, defaults));
|
||||||
|
return this.addMeasures(measures);
|
||||||
|
}
|
||||||
|
|
||||||
|
addAltLibraryMeasures(args) {
|
||||||
|
const measures = args.map(({ id }) => this.createLibraryMeasure(id));
|
||||||
|
return this.addMeasures(measures, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
addAltExpressionMeasures(args) {
|
||||||
|
const measures = args.map(({ expression }) => this.createExpressionMeasure(expression));
|
||||||
|
return this.addMeasures(measures, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
addAlternativeExpressionMeasure(expression, label, defaults) {
|
||||||
|
const measure = this.createExpressionMeasure(expression, label, defaults);
|
||||||
|
return this.addMeasure(measure, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
addAlternativeLibraryMeasure(id, defaults) {
|
||||||
|
const measure = this.createLibraryMeasure(id, defaults);
|
||||||
|
return this.addMeasure(measure, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
maxMeasures(decrement) {
|
||||||
|
const decr = decrement || 0;
|
||||||
|
if (typeof this.measureDefinition.max === 'function') {
|
||||||
|
const dimLength = this.getDimensions().length - decr;
|
||||||
|
const measureParams = isEnabled('PS_21371_ANALYSIS_TYPES') ? [dimLength, this.properties] : [dimLength];
|
||||||
|
return this.measureDefinition.max.apply(null, measureParams);
|
||||||
|
}
|
||||||
|
return Number.isNaN(+this.measureDefinition.max) ? 10000 : this.measureDefinition.max;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default DataPropertyHandler;
|
export default DataPropertyHandler;
|
||||||
|
|||||||
@@ -1,7 +1,12 @@
|
|||||||
// eslint-disable-next-line import/no-relative-packages
|
// eslint-disable-next-line import/no-relative-packages
|
||||||
import utils from '../../../conversion/src/utils';
|
import utils from '../../../conversion/src/utils';
|
||||||
import DataPropertyHandler from './data-property-handler';
|
import DataPropertyHandler from './data-property-handler';
|
||||||
import { getHyperCube, setFieldProperties } from './utils/handler-helper';
|
import * as hcHelper 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 addMainDimension from './utils/hypercube-helper/add-main-dimension';
|
||||||
|
import addMainMeasure from './utils/hypercube-helper/add-main-measure';
|
||||||
|
|
||||||
class HyperCubeHandler extends DataPropertyHandler {
|
class HyperCubeHandler extends DataPropertyHandler {
|
||||||
constructor(opts) {
|
constructor(opts) {
|
||||||
@@ -11,7 +16,7 @@ class HyperCubeHandler extends DataPropertyHandler {
|
|||||||
|
|
||||||
setProperties(properties) {
|
setProperties(properties) {
|
||||||
if (!properties) {
|
if (!properties) {
|
||||||
return;
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
super.setProperties(properties);
|
super.setProperties(properties);
|
||||||
@@ -19,38 +24,17 @@ class HyperCubeHandler extends DataPropertyHandler {
|
|||||||
this.hcProperties = this.path ? utils.getValue(properties, `${this.path}.qHyperCubeDef`) : properties.qHyperCubeDef;
|
this.hcProperties = this.path ? utils.getValue(properties, `${this.path}.qHyperCubeDef`) : properties.qHyperCubeDef;
|
||||||
|
|
||||||
if (!this.hcProperties) {
|
if (!this.hcProperties) {
|
||||||
return;
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set defaults
|
hcHelper.setDefaultProperties(this);
|
||||||
this.hcProperties.qDimensions = this.hcProperties.qDimensions ?? [];
|
hcHelper.setPropForLineChartWithForecast(this);
|
||||||
this.hcProperties.qMeasures = this.hcProperties.qMeasures ?? [];
|
|
||||||
this.hcProperties.qInterColumnSortOrder = this.hcProperties.qInterColumnSortOrder ?? [];
|
|
||||||
this.hcProperties.qLayoutExclude = this.hcProperties.qLayoutExclude ?? {
|
|
||||||
qHyperCubeDef: { qDimensions: [], qMeasures: [] },
|
|
||||||
};
|
|
||||||
this.hcProperties.qLayoutExclude.qHyperCubeDef = this.hcProperties.qLayoutExclude.qHyperCubeDef ?? {
|
|
||||||
qDimensions: [],
|
|
||||||
qMeasures: [],
|
|
||||||
};
|
|
||||||
this.hcProperties.qLayoutExclude.qHyperCubeDef.qDimensions =
|
|
||||||
this.hcProperties.qLayoutExclude.qHyperCubeDef.qDimensions ?? [];
|
|
||||||
this.hcProperties.qLayoutExclude.qHyperCubeDef.qMeasures =
|
|
||||||
this.hcProperties.qLayoutExclude.qHyperCubeDef.qMeasures ?? [];
|
|
||||||
|
|
||||||
if (
|
|
||||||
this.hcProperties.isHCEnabled &&
|
|
||||||
this.hcProperties.qDynamicScript.length === 0 &&
|
|
||||||
this.hcProperties.qMode === 'S'
|
|
||||||
) {
|
|
||||||
// this is only for line chart with forecast
|
|
||||||
this.hcProperties.qDynamicScript = [];
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set auto-sort property (compatibility 0.85 -> 0.9),
|
// Set auto-sort property (compatibility 0.85 -> 0.9),
|
||||||
// can probably be removed in 1.0
|
// can probably be removed in 1.0
|
||||||
this.hcProperties.qDimensions = setFieldProperties(this.hcProperties.qDimensions);
|
this.hcProperties.qDimensions = hcHelper.setFieldProperties(this.hcProperties.qDimensions);
|
||||||
this.hcProperties.qMeasures = setFieldProperties(this.hcProperties.qMeasures);
|
this.hcProperties.qMeasures = hcHelper.setFieldProperties(this.hcProperties.qMeasures);
|
||||||
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
// ----------------------------------
|
// ----------------------------------
|
||||||
@@ -70,10 +54,52 @@ class HyperCubeHandler extends DataPropertyHandler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
getDimensionLayouts() {
|
getDimensionLayouts() {
|
||||||
const hc = getHyperCube(this.layout, this.path);
|
const hc = hcHelper.getHyperCube(this.layout, this.path);
|
||||||
return hc ? hc.qDimensionInfo : [];
|
return hc ? hc.qDimensionInfo : [];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
addDimension(dimension, alternative, idx) {
|
||||||
|
const dim = initializeField(dimension);
|
||||||
|
|
||||||
|
if (hcHelper.isDimensionAlternative(this, dim, alternative)) {
|
||||||
|
return hcHelper.addAlternativeDimension(this, dim, idx);
|
||||||
|
}
|
||||||
|
|
||||||
|
return addMainDimension(this, dim, idx);
|
||||||
|
}
|
||||||
|
|
||||||
|
async addDimensions(dimensions, alternative = false) {
|
||||||
|
const existingDimensions = this.getDimensions();
|
||||||
|
const addedDimensions = [];
|
||||||
|
let addedActive = 0;
|
||||||
|
|
||||||
|
// eslint-disable-next-line no-restricted-syntax
|
||||||
|
for await (const dimension of dimensions) {
|
||||||
|
if (hcHelper.isTotalDimensionsExceeded(this, existingDimensions)) {
|
||||||
|
return addedDimensions;
|
||||||
|
}
|
||||||
|
|
||||||
|
const dim = initializeField(dimension);
|
||||||
|
|
||||||
|
if (hcHelper.isDimensionAlternative(this, alternative)) {
|
||||||
|
const altDim = await hcHelper.addAlternativeDimension(this, dim);
|
||||||
|
addedDimensions.push(altDim);
|
||||||
|
} else if (existingDimensions.length < this.maxDimensions()) {
|
||||||
|
await hcHelper.addActiveDimension(this, dim, existingDimensions, addedDimensions, addedActive);
|
||||||
|
addedActive++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return addedDimensions;
|
||||||
|
}
|
||||||
|
|
||||||
|
autoSortDimension(dimension) {
|
||||||
|
if (dimension.qLibraryId) {
|
||||||
|
return getAutoSortLibraryDimension(this, dimension);
|
||||||
|
}
|
||||||
|
return getAutoSortFieldDimension(this, dimension);
|
||||||
|
}
|
||||||
|
|
||||||
// ----------------------------------
|
// ----------------------------------
|
||||||
// ------------ MEASURES ------------
|
// ------------ MEASURES ------------
|
||||||
// ----------------------------------
|
// ----------------------------------
|
||||||
@@ -87,13 +113,57 @@ class HyperCubeHandler extends DataPropertyHandler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
getMeasureLayouts() {
|
getMeasureLayouts() {
|
||||||
const hc = getHyperCube(this.layout, this.path);
|
const hc = hcHelper.getHyperCube(this.layout, this.path);
|
||||||
return hc ? hc.qMeasureInfo : [];
|
return hc ? hc.qMeasureInfo : [];
|
||||||
}
|
}
|
||||||
|
|
||||||
getMeasureLayout(cId) {
|
getMeasureLayout(cId) {
|
||||||
return this.getMeasureLayouts().filter((item) => cId === item.cId)[0];
|
return this.getMeasureLayouts().filter((item) => cId === item.cId)[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
addMeasure(measure, alternative, idx) {
|
||||||
|
const meas = initializeField(measure);
|
||||||
|
|
||||||
|
if (hcHelper.isMeasureAlternative(this, meas, alternative)) {
|
||||||
|
const hcMeasures = this.hcProperties.qLayoutExclude.qHyperCubeDef.qMeasures;
|
||||||
|
return hcHelper.addAlternativeMeasure(meas, hcMeasures, idx);
|
||||||
|
}
|
||||||
|
|
||||||
|
return addMainMeasure(this, meas, idx);
|
||||||
|
}
|
||||||
|
|
||||||
|
// eslint-disable-next-line class-methods-use-this
|
||||||
|
autoSortMeasure(measure) {
|
||||||
|
const meas = { ...measure };
|
||||||
|
meas.qSortBy = {
|
||||||
|
qSortByLoadOrder: 1,
|
||||||
|
qSortByNumeric: -1,
|
||||||
|
};
|
||||||
|
return Promise.resolve(meas);
|
||||||
|
}
|
||||||
|
|
||||||
|
addMeasures(measures, alternative = false) {
|
||||||
|
const existingMeasures = this.getMeasures();
|
||||||
|
const addedMeasures = [];
|
||||||
|
let addedActive = 0;
|
||||||
|
measures.forEach(async (measure) => {
|
||||||
|
if (hcHelper.isTotalMeasureExceeded(this, existingMeasures)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const meas = initializeId(measure);
|
||||||
|
|
||||||
|
if (hcHelper.isMeasureAlternative(this, existingMeasures, alternative)) {
|
||||||
|
hcHelper.addAlternativeMeasure(this, meas);
|
||||||
|
addedMeasures.push(meas);
|
||||||
|
} else if (existingMeasures.length < this.maxMeasures()) {
|
||||||
|
await hcHelper.addActiveMeasure(this, meas, existingMeasures, addedMeasures, addedActive);
|
||||||
|
addedActive++;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
return addedMeasures;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default HyperCubeHandler;
|
export default HyperCubeHandler;
|
||||||
|
|||||||
14
apis/supernova/src/handler/utils/constants.js
Normal file
14
apis/supernova/src/handler/utils/constants.js
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
export const TOTAL_MAX = {
|
||||||
|
DIMENSIONS: 1000, // Maximum number of active dimensions + disabled dimensions
|
||||||
|
MEASURES: 1000, // Maximum number of active measures + disabled measures
|
||||||
|
};
|
||||||
|
|
||||||
|
export const AUTOCALENDAR_NAME = '.autoCalendar';
|
||||||
|
|
||||||
|
export const INITIAL_SORT_CRITERIAS = [
|
||||||
|
{
|
||||||
|
qSortByLoadOrder: 1,
|
||||||
|
qSortByNumeric: 1,
|
||||||
|
qSortByAscii: 1,
|
||||||
|
},
|
||||||
|
];
|
||||||
@@ -0,0 +1,70 @@
|
|||||||
|
import expandFieldsWithDerivedData from '../expand-field-derived-data';
|
||||||
|
import * as getDataGeoField from '../get-data-geo-field';
|
||||||
|
import * as getDerivedFields from '../get-derived-fields';
|
||||||
|
|
||||||
|
jest.mock('../get-data-geo-field', () => jest.fn());
|
||||||
|
jest.mock('../get-derived-fields', () => jest.fn());
|
||||||
|
|
||||||
|
describe('expandFieldsWithDerivedData', () => {
|
||||||
|
let inputList;
|
||||||
|
let geoField;
|
||||||
|
let derivedFields;
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
inputList = [{ name: 'field1' }];
|
||||||
|
geoField = { name: 'geoField' };
|
||||||
|
derivedFields = [{ name: 'derivedFields' }];
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should expand fields with geo and derived fields', () => {
|
||||||
|
getDataGeoField.mockReturnValue(geoField);
|
||||||
|
getDerivedFields.mockReturnValue(derivedFields);
|
||||||
|
|
||||||
|
const result = expandFieldsWithDerivedData(inputList);
|
||||||
|
|
||||||
|
expect(result).toEqual([geoField, { name: 'derivedFields' }]);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should handle an empty input list', () => {
|
||||||
|
inputList = [];
|
||||||
|
getDataGeoField.mockReturnValue(geoField);
|
||||||
|
getDerivedFields.mockReturnValue(derivedFields);
|
||||||
|
|
||||||
|
const result = expandFieldsWithDerivedData(inputList);
|
||||||
|
|
||||||
|
expect(getDataGeoField.default).not.toHaveBeenCalled();
|
||||||
|
expect(getDerivedFields.default).not.toHaveBeenCalled();
|
||||||
|
expect(result).toEqual([]);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should handle fields with no derived fields', () => {
|
||||||
|
derivedFields = [];
|
||||||
|
getDataGeoField.mockReturnValue(geoField);
|
||||||
|
getDerivedFields.mockReturnValue(derivedFields);
|
||||||
|
|
||||||
|
const result = expandFieldsWithDerivedData(inputList);
|
||||||
|
|
||||||
|
expect(getDataGeoField).toHaveBeenCalledTimes(1);
|
||||||
|
expect(getDataGeoField).toHaveBeenCalledWith({ name: 'field1' });
|
||||||
|
|
||||||
|
expect(getDerivedFields).toHaveBeenCalledTimes(1);
|
||||||
|
expect(getDerivedFields).toHaveBeenCalledWith({ name: 'field1' });
|
||||||
|
|
||||||
|
expect(result).toEqual([geoField]);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should handle fields with no geo field', () => {
|
||||||
|
geoField = [];
|
||||||
|
getDataGeoField.mockReturnValue([]);
|
||||||
|
getDerivedFields.mockReturnValue(derivedFields);
|
||||||
|
|
||||||
|
const result = expandFieldsWithDerivedData(inputList);
|
||||||
|
|
||||||
|
expect(getDataGeoField).toHaveBeenCalledTimes(1);
|
||||||
|
expect(getDataGeoField).toHaveBeenCalledWith({ name: 'field1' });
|
||||||
|
|
||||||
|
expect(getDerivedFields).toHaveBeenCalledTimes(1);
|
||||||
|
expect(getDerivedFields).toHaveBeenCalledWith({ name: 'field1' });
|
||||||
|
expect(result).toEqual([[], ...derivedFields]);
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -0,0 +1,39 @@
|
|||||||
|
import findFieldInExpandedList from '../find-field-in-expandedList';
|
||||||
|
import * as expandFieldsWithDerivedData from '../expand-field-derived-data';
|
||||||
|
|
||||||
|
describe('findFieldInExpandedList', () => {
|
||||||
|
let fieldList;
|
||||||
|
let expandedList;
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
fieldList = [{ qName: 'field1' }, { qName: 'field2' }];
|
||||||
|
expandedList = [{ qName: 'field1' }, { qName: 'field2' }, { qName: 'derivedField' }];
|
||||||
|
});
|
||||||
|
afterEach(() => {
|
||||||
|
jest.clearAllMocks();
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should return the field if it exists in the expanded list', () => {
|
||||||
|
jest.spyOn(expandFieldsWithDerivedData, 'default').mockImplementation(() => expandedList);
|
||||||
|
|
||||||
|
const result = findFieldInExpandedList('field1', fieldList);
|
||||||
|
expect(result).toEqual({ qName: 'field1' });
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should return null if the field does not exist in the expanded list', () => {
|
||||||
|
jest.spyOn(expandFieldsWithDerivedData, 'default').mockImplementation(() => expandedList);
|
||||||
|
|
||||||
|
const result = findFieldInExpandedList('nonExistentField', fieldList);
|
||||||
|
|
||||||
|
expect(result).toBeNull();
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should return null if the expanded list is empty', () => {
|
||||||
|
fieldList = [];
|
||||||
|
expandedList = null;
|
||||||
|
jest.spyOn(expandFieldsWithDerivedData, 'default').mockImplementation(() => expandedList);
|
||||||
|
|
||||||
|
const result = findFieldInExpandedList('field1', fieldList);
|
||||||
|
expect(result).toBeNull();
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
import getDataGeoField from '../get-data-geo-field';
|
||||||
|
import { isDateField, isGeoField } from '../field-utils';
|
||||||
|
|
||||||
|
jest.mock('../field-utils', () => ({
|
||||||
|
isDateField: jest.fn(),
|
||||||
|
isGeoField: jest.fn(),
|
||||||
|
}));
|
||||||
|
|
||||||
|
describe('getDataGeoField', () => {
|
||||||
|
afterEach(() => {
|
||||||
|
jest.clearAllMocks();
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should return field with the correct property values', () => {
|
||||||
|
const field = { name: 'dateField' };
|
||||||
|
isDateField.mockReturnValue(true);
|
||||||
|
isGeoField.mockReturnValue(false);
|
||||||
|
|
||||||
|
const result = getDataGeoField(field);
|
||||||
|
|
||||||
|
expect(result.isDateField).toBe(true);
|
||||||
|
expect(result.isGeoField).toBe(false);
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -0,0 +1,131 @@
|
|||||||
|
import getDerivedFields from '../get-derived-fields';
|
||||||
|
import { trimAutoCalendarName } from '../field-utils';
|
||||||
|
|
||||||
|
jest.mock('../field-utils', () => ({
|
||||||
|
trimAutoCalendarName: jest.fn((name) => `trimmed_${name}`),
|
||||||
|
}));
|
||||||
|
|
||||||
|
describe('getDerivedFields', () => {
|
||||||
|
let field;
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
field = {
|
||||||
|
qName: 'field1',
|
||||||
|
qSrcTables: ['table1'],
|
||||||
|
isDateField: true,
|
||||||
|
qDerivedFieldData: {
|
||||||
|
qDerivedFieldLists: [
|
||||||
|
{
|
||||||
|
qDerivedDefinitionName: 'DerivedDef1',
|
||||||
|
qFieldDefs: [
|
||||||
|
{
|
||||||
|
qName: 'derivedField1',
|
||||||
|
qTags: ['tag1'],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
};
|
||||||
|
});
|
||||||
|
afterEach(() => {
|
||||||
|
jest.clearAllMocks();
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should return an empty array if derived field data is undefined', () => {
|
||||||
|
field = { qName: 'field1' };
|
||||||
|
|
||||||
|
const result = getDerivedFields(field);
|
||||||
|
|
||||||
|
expect(result).toEqual([]);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should return an empty array if derived field data list is empty', () => {
|
||||||
|
field = {
|
||||||
|
qName: 'field1',
|
||||||
|
qDerivedFieldData: {
|
||||||
|
qDerivedFieldLists: [],
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const result = getDerivedFields(field);
|
||||||
|
|
||||||
|
expect(result).toEqual([]);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should return derived fields with correct properties', () => {
|
||||||
|
const result = getDerivedFields(field);
|
||||||
|
|
||||||
|
expect(trimAutoCalendarName).toHaveBeenCalledWith('derivedField1');
|
||||||
|
expect(result).toEqual([
|
||||||
|
{
|
||||||
|
qName: 'derivedField1',
|
||||||
|
displayName: 'trimmed_derivedField1',
|
||||||
|
qSrcTables: ['table1'],
|
||||||
|
qTags: ['tag1'],
|
||||||
|
isDerived: true,
|
||||||
|
isDerivedFromDate: true,
|
||||||
|
sourceField: 'field1',
|
||||||
|
derivedDefinitionName: 'DerivedDef1',
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should set isDerivedFromDate to false if field.isDateField is false', () => {
|
||||||
|
field.isDateField = false;
|
||||||
|
|
||||||
|
const result = getDerivedFields(field);
|
||||||
|
|
||||||
|
expect(result[0].isDerivedFromDate).toBe(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should handle multiple derived fields', () => {
|
||||||
|
field = {
|
||||||
|
qName: 'field1',
|
||||||
|
qSrcTables: ['table1'],
|
||||||
|
isDateField: true,
|
||||||
|
qDerivedFieldData: {
|
||||||
|
qDerivedFieldLists: [
|
||||||
|
{
|
||||||
|
qDerivedDefinitionName: 'DerivedDef1',
|
||||||
|
qFieldDefs: [
|
||||||
|
{
|
||||||
|
qName: 'derivedField1',
|
||||||
|
qTags: ['tag1'],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
qName: 'derivedField2',
|
||||||
|
qTags: ['tag2'],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const result = getDerivedFields(field);
|
||||||
|
|
||||||
|
expect(result).toEqual([
|
||||||
|
{
|
||||||
|
qName: 'derivedField1',
|
||||||
|
displayName: 'trimmed_derivedField1',
|
||||||
|
qSrcTables: ['table1'],
|
||||||
|
qTags: ['tag1'],
|
||||||
|
isDerived: true,
|
||||||
|
isDerivedFromDate: true,
|
||||||
|
sourceField: 'field1',
|
||||||
|
derivedDefinitionName: 'DerivedDef1',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
qName: 'derivedField2',
|
||||||
|
displayName: 'trimmed_derivedField2',
|
||||||
|
qSrcTables: ['table1'],
|
||||||
|
qTags: ['tag2'],
|
||||||
|
isDerived: true,
|
||||||
|
isDerivedFromDate: true,
|
||||||
|
sourceField: 'field1',
|
||||||
|
derivedDefinitionName: 'DerivedDef1',
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -0,0 +1,80 @@
|
|||||||
|
import getAutoSortFieldDimension from '../get-sorted-field';
|
||||||
|
import findFieldInExpandedList from '../find-field-in-expandedList';
|
||||||
|
import { setAutoSort } from '../field-utils';
|
||||||
|
|
||||||
|
jest.mock('../find-field-in-expandedList', () => jest.fn());
|
||||||
|
jest.mock('../field-utils', () => ({
|
||||||
|
setAutoSort: jest.fn(),
|
||||||
|
}));
|
||||||
|
|
||||||
|
describe('getAutoSortFieldDimension', () => {
|
||||||
|
let self;
|
||||||
|
let dimension;
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
self = {
|
||||||
|
app: {
|
||||||
|
getFieldList: jest.fn(),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
dimension = {
|
||||||
|
qDef: {
|
||||||
|
qFieldDefs: ['field1'],
|
||||||
|
},
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(() => {
|
||||||
|
jest.clearAllMocks();
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should call findFieldInExpandedList with correct arguments', async () => {
|
||||||
|
const fieldList = [{ qName: 'field1' }];
|
||||||
|
self.app.getFieldList.mockResolvedValue(fieldList);
|
||||||
|
|
||||||
|
const result = await getAutoSortFieldDimension(self, dimension);
|
||||||
|
|
||||||
|
expect(self.app.getFieldList).toHaveBeenCalled();
|
||||||
|
expect(findFieldInExpandedList).toHaveBeenCalledWith('field1', fieldList);
|
||||||
|
expect(result).toBe(dimension);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should call setAutoSort if a field is found', async () => {
|
||||||
|
const fieldList = [{ qName: 'field1' }];
|
||||||
|
const field = { qName: 'field1' };
|
||||||
|
self.app.getFieldList.mockResolvedValue(fieldList);
|
||||||
|
findFieldInExpandedList.mockReturnValue(field);
|
||||||
|
|
||||||
|
await getAutoSortFieldDimension(self, dimension);
|
||||||
|
|
||||||
|
expect(setAutoSort).toHaveBeenCalledWith([field], dimension, self);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should not call setAutoSort if no field is found', async () => {
|
||||||
|
self.app.getFieldList.mockResolvedValue([]);
|
||||||
|
findFieldInExpandedList.mockReturnValue(null);
|
||||||
|
|
||||||
|
await getAutoSortFieldDimension(self, dimension);
|
||||||
|
|
||||||
|
expect(setAutoSort).not.toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should handle empty field list', async () => {
|
||||||
|
self.app.getFieldList.mockResolvedValue([]);
|
||||||
|
|
||||||
|
const result = await getAutoSortFieldDimension(self, dimension);
|
||||||
|
|
||||||
|
expect(result).toBe(dimension);
|
||||||
|
expect(setAutoSort).not.toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should handle missing qFieldDefs', async () => {
|
||||||
|
dimension.qDef.qFieldDefs = undefined;
|
||||||
|
self.app.getFieldList.mockResolvedValue([]);
|
||||||
|
|
||||||
|
const result = await getAutoSortFieldDimension(self, dimension);
|
||||||
|
|
||||||
|
expect(result).toBe(dimension);
|
||||||
|
expect(setAutoSort).not.toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -0,0 +1,77 @@
|
|||||||
|
import getAutoSortLibraryDimension from '../get-sorted-library-field';
|
||||||
|
import { findLibraryItem, setAutoSort } from '../field-utils';
|
||||||
|
|
||||||
|
jest.mock('../field-utils', () => ({
|
||||||
|
findLibraryItem: jest.fn(),
|
||||||
|
setAutoSort: jest.fn(),
|
||||||
|
}));
|
||||||
|
|
||||||
|
describe('getAutoSortLibraryDimension', () => {
|
||||||
|
let self;
|
||||||
|
let dimension;
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
self = {
|
||||||
|
app: {
|
||||||
|
getDimensionList: jest.fn(),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
dimension = {
|
||||||
|
qLibraryId: 'libDim1',
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(() => {
|
||||||
|
jest.clearAllMocks();
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should call findLibraryItem with correct arguments', async () => {
|
||||||
|
const dimensionList = [{ qInfo: { qId: 'libDim1' }, qData: { info: ['field1'] } }];
|
||||||
|
const libDim = dimensionList[0];
|
||||||
|
self.app.getDimensionList.mockResolvedValue(dimensionList);
|
||||||
|
findLibraryItem.mockReturnValue(libDim);
|
||||||
|
|
||||||
|
const result = await getAutoSortLibraryDimension(self, dimension);
|
||||||
|
|
||||||
|
expect(findLibraryItem).toHaveBeenCalledWith('libDim1', dimensionList);
|
||||||
|
expect(result).toBe(dimension);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should call setAutoSort if a library dimension is found', async () => {
|
||||||
|
const dimensionList = [{ qInfo: { qId: 'libDim1' }, qData: { info: ['field1'] } }];
|
||||||
|
const libDim = dimensionList[0];
|
||||||
|
self.app.getDimensionList.mockResolvedValue(dimensionList);
|
||||||
|
|
||||||
|
await getAutoSortLibraryDimension(self, dimension);
|
||||||
|
|
||||||
|
expect(setAutoSort).toHaveBeenCalledWith(libDim.qData.info, dimension, self);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should not call setAutoSort if no library dimension is found', async () => {
|
||||||
|
self.app.getDimensionList.mockResolvedValue([]);
|
||||||
|
findLibraryItem.mockReturnValue(null);
|
||||||
|
|
||||||
|
await getAutoSortLibraryDimension(self, dimension);
|
||||||
|
|
||||||
|
expect(setAutoSort).not.toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should handle empty dimension list', async () => {
|
||||||
|
self.app.getDimensionList.mockResolvedValue([]);
|
||||||
|
|
||||||
|
const result = await getAutoSortLibraryDimension(self, dimension);
|
||||||
|
|
||||||
|
expect(result).toBe(dimension);
|
||||||
|
expect(setAutoSort).not.toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should handle missing dimension list', async () => {
|
||||||
|
dimension = undefined;
|
||||||
|
self.app.getDimensionList.mockResolvedValue([]);
|
||||||
|
|
||||||
|
const result = await getAutoSortLibraryDimension(self, dimension);
|
||||||
|
|
||||||
|
expect(result).toBe(dimension);
|
||||||
|
expect(setAutoSort).not.toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -0,0 +1,65 @@
|
|||||||
|
import { isDateField } from '../field-utils';
|
||||||
|
|
||||||
|
describe('isDateField', () => {
|
||||||
|
test('should return true if field has $date tag', () => {
|
||||||
|
const field01 = {
|
||||||
|
qDerivedFieldData: {},
|
||||||
|
qTags: ['$date', 'otherTag'],
|
||||||
|
};
|
||||||
|
|
||||||
|
const field02 = {
|
||||||
|
qDerivedFieldData: {},
|
||||||
|
qTags: ['otherTag', '$timestamp'],
|
||||||
|
};
|
||||||
|
|
||||||
|
const result01 = isDateField(field01);
|
||||||
|
expect(result01).toBe(true);
|
||||||
|
|
||||||
|
const result02 = isDateField(field02);
|
||||||
|
expect(result02).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should return false if field does not have $date or $timestamp tag', () => {
|
||||||
|
const field = {
|
||||||
|
qDerivedFieldData: {},
|
||||||
|
qTags: ['otherTag'],
|
||||||
|
};
|
||||||
|
|
||||||
|
const result = isDateField(field);
|
||||||
|
expect(result).toBeFalsy();
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should return false if qDerivedFieldData is missing', () => {
|
||||||
|
const field = {
|
||||||
|
qTags: ['$date'],
|
||||||
|
};
|
||||||
|
|
||||||
|
const result = isDateField(field);
|
||||||
|
expect(result).toBeFalsy();
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should return false if qTags is empty', () => {
|
||||||
|
const field = {
|
||||||
|
qDerivedFieldData: {},
|
||||||
|
qTags: [],
|
||||||
|
};
|
||||||
|
|
||||||
|
const result = isDateField(field);
|
||||||
|
expect(result).toBeFalsy();
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should return false if field is null or undefined', () => {
|
||||||
|
expect(isDateField([])).toBeFalsy();
|
||||||
|
expect(isDateField(undefined)).toBeFalsy();
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should return false if qTags is not an array', () => {
|
||||||
|
const field = {
|
||||||
|
qDerivedFieldData: {},
|
||||||
|
qTags: null,
|
||||||
|
};
|
||||||
|
|
||||||
|
const result = isDateField(field);
|
||||||
|
expect(result).toBeFalsy();
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
import getDataGeoField from './get-data-geo-field';
|
||||||
|
import getDerivedFields from './get-derived-fields';
|
||||||
|
|
||||||
|
const expandFieldsWithDerivedData = (list) => {
|
||||||
|
const fieldList = [];
|
||||||
|
list.forEach((field) => {
|
||||||
|
fieldList.push(getDataGeoField(field));
|
||||||
|
|
||||||
|
const derivedFields = getDerivedFields(field);
|
||||||
|
fieldList.push(...derivedFields);
|
||||||
|
});
|
||||||
|
|
||||||
|
return fieldList;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default expandFieldsWithDerivedData;
|
||||||
85
apis/supernova/src/handler/utils/field-helper/field-utils.js
Normal file
85
apis/supernova/src/handler/utils/field-helper/field-utils.js
Normal file
@@ -0,0 +1,85 @@
|
|||||||
|
// eslint-disable-next-line import/no-relative-packages
|
||||||
|
import uid from '../../../../../nucleus/src/object/uid';
|
||||||
|
import { AUTOCALENDAR_NAME } from '../constants';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the field name from the expression.
|
||||||
|
* @param {string} expression
|
||||||
|
* @returns the field
|
||||||
|
*/
|
||||||
|
export const getField = (expression) => {
|
||||||
|
let exp = expression;
|
||||||
|
exp = exp.trim();
|
||||||
|
if (exp.charAt(0) === '=') {
|
||||||
|
exp = exp.substring(1);
|
||||||
|
exp = exp.trim();
|
||||||
|
}
|
||||||
|
const lastIndex = exp.length - 1;
|
||||||
|
if (exp.charAt(0) === '[' && exp.charAt(lastIndex) === ']') {
|
||||||
|
exp = exp.substring(1, lastIndex);
|
||||||
|
exp = exp.trim();
|
||||||
|
}
|
||||||
|
return exp;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const findFieldById = (fields, id) => (fields && fields.find((field) => field.qDef?.cId === id)) || null;
|
||||||
|
|
||||||
|
export const findLibraryItem = (id, masterItemList) =>
|
||||||
|
(masterItemList && masterItemList.find((item) => item.qInfo.qId === id)) || null;
|
||||||
|
|
||||||
|
export const findFieldByName = (name, fieldList) =>
|
||||||
|
(fieldList && fieldList.find((field) => field.qName === name)) || null;
|
||||||
|
|
||||||
|
export const initializeId = (field) => ({
|
||||||
|
...field,
|
||||||
|
qDef: {
|
||||||
|
...field.qDef,
|
||||||
|
cId: field.qDef?.cId ?? uid(),
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
export const initializeField = (field) => ({
|
||||||
|
...initializeId(field),
|
||||||
|
qOtherTotalSpec: field.qOtherTotalSpec ?? {},
|
||||||
|
});
|
||||||
|
|
||||||
|
export const setAutoSort = (fields, dimension, self) => {
|
||||||
|
const dim = dimension;
|
||||||
|
fields.forEach((field, index) => {
|
||||||
|
const tags = field.qTags;
|
||||||
|
const sortCriterias = {
|
||||||
|
qSortByLoadOrder: 1,
|
||||||
|
};
|
||||||
|
|
||||||
|
if (typeof self.dimensionDefinition.autoSort === 'function') {
|
||||||
|
self.dimensionDefinition.autoSort(dim, self.properties, tags, sortCriterias, self);
|
||||||
|
} else {
|
||||||
|
// Default auto sorting
|
||||||
|
sortCriterias.qSortByNumeric = 1;
|
||||||
|
sortCriterias.qSortByAscii = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!dim.qDef.qSortCriterias) {
|
||||||
|
dim.qDef.qSortCriterias = [sortCriterias];
|
||||||
|
} else {
|
||||||
|
dim.qDef.qSortCriterias[index] = sortCriterias;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export const useMasterNumberFormat = (formatting) => {
|
||||||
|
const format = formatting;
|
||||||
|
format.quarantine = {
|
||||||
|
qNumFormat: format.qNumFormat || {},
|
||||||
|
isCustomFormatted: format.isCustomFormatted || false,
|
||||||
|
};
|
||||||
|
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('') : '');
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
import expandFieldsWithDerivedData from './expand-field-derived-data';
|
||||||
|
import { findFieldByName, getField } from './field-utils';
|
||||||
|
|
||||||
|
const findFieldInExpandedList = (name, fieldList) => {
|
||||||
|
const expandedList = expandFieldsWithDerivedData(fieldList.slice(0));
|
||||||
|
const fieldName = getField(name);
|
||||||
|
return (expandedList && findFieldByName(fieldName, expandedList)) || null;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default findFieldInExpandedList;
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
import { isDateField, isGeoField } from './field-utils';
|
||||||
|
|
||||||
|
const getDataGeoField = (field) => {
|
||||||
|
const item = field;
|
||||||
|
item.isDateField = isDateField(item);
|
||||||
|
item.isGeoField = isGeoField(item);
|
||||||
|
return item;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default getDataGeoField;
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
import { trimAutoCalendarName } from './field-utils';
|
||||||
|
|
||||||
|
const getDerivedFields = (field) => {
|
||||||
|
const derivedFields = [];
|
||||||
|
|
||||||
|
if (!field.qDerivedFieldData) {
|
||||||
|
return derivedFields;
|
||||||
|
}
|
||||||
|
|
||||||
|
field.qDerivedFieldData.qDerivedFieldLists.forEach((derived) => {
|
||||||
|
derived.qFieldDefs.forEach((derivedField) => {
|
||||||
|
derivedFields.push({
|
||||||
|
qName: derivedField.qName,
|
||||||
|
displayName: trimAutoCalendarName(derivedField.qName),
|
||||||
|
qSrcTables: field.qSrcTables,
|
||||||
|
qTags: derivedField.qTags,
|
||||||
|
isDerived: true,
|
||||||
|
isDerivedFromDate: field.isDateField,
|
||||||
|
sourceField: field.qName,
|
||||||
|
derivedDefinitionName: derived.qDerivedDefinitionName,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
return derivedFields;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default getDerivedFields;
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
import findFieldInExpandedList from './find-field-in-expandedList';
|
||||||
|
import { setAutoSort } from './field-utils';
|
||||||
|
|
||||||
|
function getAutoSortFieldDimension(self, dimension) {
|
||||||
|
return self.app.getFieldList().then((fieldList) => {
|
||||||
|
const field = dimension?.qDef?.qFieldDefs && findFieldInExpandedList(dimension.qDef.qFieldDefs[0], fieldList);
|
||||||
|
if (field) {
|
||||||
|
setAutoSort([field], dimension, self);
|
||||||
|
}
|
||||||
|
return dimension;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export default getAutoSortFieldDimension;
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
import { findLibraryItem, setAutoSort } from './field-utils';
|
||||||
|
|
||||||
|
function getAutoSortLibraryDimension(self, dimension) {
|
||||||
|
return self.app.getDimensionList().then((dimensionList) => {
|
||||||
|
const libDim = dimension?.qLibraryId && findLibraryItem(dimension.qLibraryId, dimensionList);
|
||||||
|
if (libDim) {
|
||||||
|
setAutoSort(libDim.qData.info, dimension, self);
|
||||||
|
}
|
||||||
|
return dimension;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export default getAutoSortLibraryDimension;
|
||||||
@@ -1,32 +0,0 @@
|
|||||||
// eslint-disable-next-line import/no-relative-packages
|
|
||||||
import getValue from '../../../../conversion/src/utils';
|
|
||||||
|
|
||||||
export const getFieldById = (fields, id) => fields.find((field) => field.qDef?.cId === id) || null;
|
|
||||||
|
|
||||||
export const setFieldProperties = (hcFieldProperties) => {
|
|
||||||
if (!hcFieldProperties) {
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
const updatedProperties = [...hcFieldProperties];
|
|
||||||
|
|
||||||
return updatedProperties.map((field) => {
|
|
||||||
if (field.qDef?.autoSort && field.autoSort !== undefined) {
|
|
||||||
return {
|
|
||||||
...field,
|
|
||||||
qDef: {
|
|
||||||
...field.qDef,
|
|
||||||
autoSort: field.autoSort,
|
|
||||||
},
|
|
||||||
autoSort: undefined,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
return field;
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
export const getHyperCube = (layout, path) => {
|
|
||||||
if (!layout) {
|
|
||||||
return undefined;
|
|
||||||
}
|
|
||||||
return path && getValue(layout, path) ? getValue(layout, path).qHyperCube : layout.qHyperCube;
|
|
||||||
};
|
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
import { insertMainDimension } from './hypercube-utils';
|
||||||
|
|
||||||
|
export default function addMainDimension(self, dimension, index) {
|
||||||
|
const dimensions = self.getDimensions();
|
||||||
|
const idx = index ?? dimensions.length;
|
||||||
|
|
||||||
|
if (dimensions.length < self.maxDimensions()) {
|
||||||
|
return insertMainDimension(self, dimension, dimensions, idx);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Promise.resolve();
|
||||||
|
}
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
import { insertMainMeasure } from './hypercube-utils';
|
||||||
|
|
||||||
|
export default function addMainMeasure(self, measure, index) {
|
||||||
|
const measures = self.getMeasures();
|
||||||
|
const idx = index ?? measures.length;
|
||||||
|
|
||||||
|
if (measures.length < self.maxMeasures()) {
|
||||||
|
insertMainMeasure(measure, measures, idx);
|
||||||
|
}
|
||||||
|
|
||||||
|
return measure;
|
||||||
|
}
|
||||||
@@ -0,0 +1,182 @@
|
|||||||
|
// 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';
|
||||||
|
|
||||||
|
export const notSupportedError = new Error('Not supported in this object, need to implement in subclass.');
|
||||||
|
|
||||||
|
export const setFieldProperties = (hcFieldProperties) => {
|
||||||
|
if (!hcFieldProperties) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
const updatedProperties = [...hcFieldProperties];
|
||||||
|
|
||||||
|
return updatedProperties.map((field) => {
|
||||||
|
if (field.qDef?.autoSort && field.autoSort !== undefined) {
|
||||||
|
return {
|
||||||
|
...field,
|
||||||
|
qDef: {
|
||||||
|
...field.qDef,
|
||||||
|
autoSort: field.autoSort,
|
||||||
|
},
|
||||||
|
autoSort: undefined,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return field;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export const getHyperCube = (layout, path) => {
|
||||||
|
if (!layout) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
return path && getValue(layout, path) ? getValue(layout, path).qHyperCube : layout.qHyperCube;
|
||||||
|
};
|
||||||
|
|
||||||
|
export function setDefaultProperties(self) {
|
||||||
|
const current = self;
|
||||||
|
current.hcProperties.qDimensions = current.hcProperties.qDimensions ?? [];
|
||||||
|
current.hcProperties.qMeasures = current.hcProperties.qMeasures ?? [];
|
||||||
|
current.hcProperties.qInterColumnSortOrder = current.hcProperties.qInterColumnSortOrder ?? [];
|
||||||
|
current.hcProperties.qLayoutExclude = current.hcProperties.qLayoutExclude ?? {
|
||||||
|
qHyperCubeDef: { qDimensions: [], qMeasures: [] },
|
||||||
|
};
|
||||||
|
current.hcProperties.qLayoutExclude.qHyperCubeDef = current.hcProperties.qLayoutExclude.qHyperCubeDef ?? {
|
||||||
|
qDimensions: [],
|
||||||
|
qMeasures: [],
|
||||||
|
};
|
||||||
|
current.hcProperties.qLayoutExclude.qHyperCubeDef.qDimensions =
|
||||||
|
current.hcProperties.qLayoutExclude.qHyperCubeDef.qDimensions ?? [];
|
||||||
|
current.hcProperties.qLayoutExclude.qHyperCubeDef.qMeasures =
|
||||||
|
current.hcProperties.qLayoutExclude.qHyperCubeDef.qMeasures ?? [];
|
||||||
|
}
|
||||||
|
|
||||||
|
export function setPropForLineChartWithForecast(self) {
|
||||||
|
const current = self;
|
||||||
|
if (
|
||||||
|
current.hcProperties.isHCEnabled &&
|
||||||
|
current.hcProperties.qDynamicScript.length === 0 &&
|
||||||
|
current.hcProperties.qMode === 'S'
|
||||||
|
) {
|
||||||
|
current.hcProperties.qDynamicScript = [];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----------------------------------
|
||||||
|
// ----------- DIMENSIONS -----------
|
||||||
|
// ----------------------------------
|
||||||
|
|
||||||
|
export function addAlternativeDimension(self, dimension, index = undefined) {
|
||||||
|
const dimensions = self.hcProperties.qLayoutExclude.qHyperCubeDef.qDimensions;
|
||||||
|
const idx = index ?? dimensions.length;
|
||||||
|
dimensions.splice(idx, 0, dimension);
|
||||||
|
return Promise.resolve(dimension);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function insertMainDimension(self, dimension, dimensions, idx) {
|
||||||
|
dimensions.splice(idx, 0, dimension);
|
||||||
|
|
||||||
|
return self.autoSortDimension(dimension).then(() => {
|
||||||
|
arrayUtil.indexAdded(self.hcProperties.qInterColumnSortOrder, self.getDimensions().length + dimension.length - 1);
|
||||||
|
|
||||||
|
if (typeof self.dimensionDefinition.add === 'function') {
|
||||||
|
return Promise.resolve(self.dimensionDefinition.add.call(null, dimension, self.properties, self));
|
||||||
|
}
|
||||||
|
|
||||||
|
return dimension;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export function addSortedDimension(self, dimension, dimensions, idx) {
|
||||||
|
const dimIdx = idx ?? dimensions.length;
|
||||||
|
dimensions.splice(dimIdx, 0, dimension);
|
||||||
|
|
||||||
|
return self.autoSortDimension(dimension).then(() => {
|
||||||
|
arrayUtil.indexAdded(self.hcProperties.qInterColumnSortOrder, dimIdx ?? dimensions.length - 1);
|
||||||
|
|
||||||
|
return self.dimensionDefinition.add?.call(self, dimension, self.properties, self) || Promise.resolve(dimension);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export function isTotalDimensionsExceeded(self, dimensions) {
|
||||||
|
const altDimensions = self.getAlternativeDimensions();
|
||||||
|
return altDimensions.length + dimensions.length >= TOTAL_MAX.DIMENSIONS;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function isDimensionAlternative(self, alternative) {
|
||||||
|
const dimensions = self.hcProperties.qLayoutExclude.qHyperCubeDef.qDimensions;
|
||||||
|
return alternative || (self.maxDimensions() <= dimensions.length && dimensions.length < TOTAL_MAX.DIMENSIONS);
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function addActiveDimension(self, dimension, existingDimensions, addedDimensions, addedActive) {
|
||||||
|
const initialLength = existingDimensions.length;
|
||||||
|
await self.autoSortDimension(dimension);
|
||||||
|
|
||||||
|
// Update sorting order
|
||||||
|
arrayUtil.indexAdded(self.hcProperties.qInterColumnSortOrder, initialLength + addedActive);
|
||||||
|
|
||||||
|
existingDimensions.push(dimension);
|
||||||
|
addedDimensions.push(dimension);
|
||||||
|
|
||||||
|
if (typeof self.dimensionDefinition.add === 'function') {
|
||||||
|
self.dimensionDefinition.add.call(self, dimension, self.properties, self);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----------------------------------
|
||||||
|
// ------------ MEASURES ------------
|
||||||
|
// ----------------------------------
|
||||||
|
|
||||||
|
export function addAlternativeMeasure(self, measure, index = undefined) {
|
||||||
|
const measures = self.hcProperties.qLayoutExclude.qHyperCubeDef.qMeasures;
|
||||||
|
const idx = index ?? measures.length;
|
||||||
|
measures.splice(idx, 0, measure);
|
||||||
|
return Promise.resolve(measure);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function insertMainMeasure(self, measure, measures, idx) {
|
||||||
|
measures.splice(idx, 0, measure);
|
||||||
|
|
||||||
|
return self.autoSortMeasure(measure).then(() => {
|
||||||
|
arrayUtil.indexAdded(self.hcProperties.qInterColumnSortOrder, self.getDimensions().length + measure.length - 1);
|
||||||
|
|
||||||
|
if (typeof self.measureDefinition.add === 'function') {
|
||||||
|
return Promise.resolve(self.measureDefinition.add.call(null, measure, self.properties, self));
|
||||||
|
}
|
||||||
|
|
||||||
|
return measure;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export function isTotalMeasureExceeded(self, measures) {
|
||||||
|
// Adding more measures than TOTAL_MAX_MEASURES is not allowed and we expect this.maxMeasures() to always be <= TOTAL_MAX_MEASURES
|
||||||
|
const altMeasures = self.getAlternativeMeasures();
|
||||||
|
return altMeasures.length + measures.length >= TOTAL_MAX.MEASURES;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function isMeasureAlternative(self, measures, alternative) {
|
||||||
|
return alternative || (self.maxMeasures() <= measures.length && measures.length < TOTAL_MAX.MEASURES);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function addActiveMeasure(self, measure, existingMeasures, addedMeasures, addedActive) {
|
||||||
|
const dimensions = self.getDimensions();
|
||||||
|
const meas = { ...measure };
|
||||||
|
meas.qSortBy = {
|
||||||
|
qSortByLoadOrder: 1,
|
||||||
|
qSortByNumeric: -1,
|
||||||
|
};
|
||||||
|
|
||||||
|
arrayUtil.indexAdded(
|
||||||
|
self.hcProperties.qInterColumnSortOrder,
|
||||||
|
dimensions.length + existingMeasures.length + addedActive
|
||||||
|
);
|
||||||
|
existingMeasures.push(meas);
|
||||||
|
addedMeasures.push(meas);
|
||||||
|
|
||||||
|
if (typeof self.measureDefinition.add === 'function') {
|
||||||
|
self.measureDefinition.add.call(null, meas, self.properties, self);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Promise.resolve(addedMeasures);
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user