@sis-cc/dotstatsuite-components 9.1.2 → 9.2.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (77) hide show
  1. package/lib/rules/src/preparators/enhanceObservations.js +155 -0
  2. package/lib/rules/src/preparators/formatValue.js +77 -0
  3. package/lib/rules/src/preparators/getDimensions.js +55 -0
  4. package/lib/rules/src/preparators/getDisplay.js +32 -0
  5. package/lib/rules/src/preparators/getObservations.js +27 -0
  6. package/lib/rules/src/table/factories/getCells.js +1 -3
  7. package/lib/rules/src/table/factories/getLayoutData.js +118 -159
  8. package/lib/rules/src/table/factories/getSortedLayoutIndexes.js +118 -0
  9. package/lib/rules/src/table/factories/getTableData.js +12 -10
  10. package/lib/rules/src/table/factories/refineLayoutSize.js +210 -0
  11. package/lib/rules/src/table/preparators/prepareData.js +23 -23
  12. package/lib/rules/src/table/units/getAttachmentSeriesIndexes.js +1 -1
  13. package/lib/rules/src/table/units/getUnitsSeries.js +31 -0
  14. package/lib/rules/src/v8-transformer.js +2 -1
  15. package/package.json +2 -2
  16. package/src/rules/src/preparators/enhanceObservations.js +163 -0
  17. package/src/rules/src/preparators/formatValue.js +73 -0
  18. package/src/rules/src/preparators/getDimensions.js +49 -0
  19. package/src/rules/src/preparators/getDisplay.js +20 -0
  20. package/src/rules/src/preparators/getObservations.js +19 -0
  21. package/src/rules/src/table/factories/getCells.js +3 -7
  22. package/src/rules/src/table/factories/getLayoutData.js +150 -184
  23. package/src/rules/src/table/factories/getSortedLayoutIndexes.js +108 -0
  24. package/src/rules/src/table/factories/getTableData.js +10 -10
  25. package/src/rules/src/table/factories/refineLayoutSize.js +224 -0
  26. package/src/rules/src/table/preparators/prepareData.js +23 -32
  27. package/src/rules/src/table/units/getAttachmentSeriesIndexes.js +2 -1
  28. package/src/rules/src/table/units/getUnitsSeries.js +20 -0
  29. package/src/rules/src/v8-transformer.js +2 -1
  30. package/test/appendUnitsInLayoutDataEntry.test.js +3 -3
  31. package/test/enhanceObservations.test.js +270 -0
  32. package/test/getAttachmentSeriesIndexes.test.js +1 -1
  33. package/test/getCells.test.js +4 -39
  34. package/test/getLayoutData.test.js +193 -298
  35. package/test/getOneValueDimensions.test.js +1 -1
  36. package/test/getSortedLayoutIndexes.test.js +80 -0
  37. package/test/getUnitsArtefacts.test.js +1 -1
  38. package/test/getUnitsSeries.test.js +64 -0
  39. package/test/mocks/table-layout-multi-hierarchies--layout.json +621 -0
  40. package/test/mocks/table-layout-multi-hierarchies--layoutData.json +32410 -0
  41. package/test/mocks/table-layout-multi-hierarchies--layoutIndexes.json +2760 -0
  42. package/test/mocks/table-layout-multi-hierarchies--observations.json +30688 -0
  43. package/test/mocks/table-layout-multi-hierarchies--sizedIndexes.json +2761 -0
  44. package/test/mocks/table-layout-truncation1--layout.json +27469 -0
  45. package/test/mocks/table-layout-truncation1--layoutData.json +20357 -0
  46. package/test/mocks/table-layout-truncation1--layoutIndexes.json +7512 -0
  47. package/test/mocks/table-layout-truncation1--observations.json +70002 -0
  48. package/test/mocks/table-layout-truncation1--sizedIndexes.json +3010 -0
  49. package/test/mocks/table-prep-multi-hierarchies--attributes.json +44 -0
  50. package/test/mocks/table-prep-multi-hierarchies--dimensions.json +688 -0
  51. package/test/mocks/table-prep-multi-hierarchies--enhancedObservations.json +19696 -0
  52. package/test/mocks/table-prep-multi-hierarchies--observations.json +8246 -0
  53. package/test/mocks/table-prep-multi-hierarchies--sdmxJson.json +2985 -0
  54. package/test/mocks/table-prep-truncation1--dimensions.json +35057 -0
  55. package/test/mocks/table-prep-truncation1--enhancedObservations.json +70002 -0
  56. package/test/mocks/table-prep-truncation1--observations.json +27502 -0
  57. package/test/mocks/table-prep-truncation1--sdmxJson.json +55103 -0
  58. package/test/mocks/table-prep-units--observations.json +284286 -0
  59. package/test/mocks/table-prep-units--unitsSeries.json +41042 -0
  60. package/test/parseAttributes.test.js +1 -1
  61. package/test/refineLayoutSize.test.js +415 -0
  62. package/test/table-layout-perf.test.js +74 -0
  63. package/test/table-prep-perf.test.js +65 -0
  64. package/lib/rules/src/table/factories/getSortedLayoutData.js +0 -145
  65. package/lib/rules/src/table/factories/refineLayoutHierarchy.js +0 -61
  66. package/lib/rules/src/table/preparators/parseObservations.js +0 -76
  67. package/lib/rules/src/table/units/getUnitsSeriesOccurences.js +0 -39
  68. package/src/rules/src/table/factories/getSortedLayoutData.js +0 -133
  69. package/src/rules/src/table/factories/refineLayoutHierarchy.js +0 -64
  70. package/src/rules/src/table/preparators/parseObservations.js +0 -81
  71. package/src/rules/src/table/units/getUnitsSeriesOccurences.js +0 -51
  72. package/test/appendUnitsInLayoutData.test.js +0 -248
  73. package/test/getSortedLayoutData.test.js +0 -382
  74. package/test/getUnitsSeriesOccurences.test.js +0 -133
  75. package/test/parseObservations.test.js +0 -116
  76. package/test/refineDimSeriesUnits.test.js +0 -24
  77. package/test/refineLayoutHierarchy.test.js +0 -79
@@ -0,0 +1,20 @@
1
+ import * as R from 'ramda';
2
+
3
+ export const getDisplay = ({ noDisplayIndexes = [], notDisplayedCodes = {} }) => {
4
+ const annotationsValidator = R.pipe(
5
+ R.propOr([], 'annotations'),
6
+ R.intersection(noDisplayIndexes),
7
+ R.isEmpty
8
+ );
9
+
10
+ const blacklistValidator = R.ifElse(
11
+ R.has('values'),
12
+ ({ id }) => R.anyPass([
13
+ R.complement(R.has)(id),
14
+ R.hasPath([id, 'values'])
15
+ ])(notDisplayedCodes),
16
+ ({ id, parent }) => R.complement(R.hasPath)([parent, 'values', id], notDisplayedCodes)
17
+ );
18
+
19
+ return R.allPass([annotationsValidator, blacklistValidator]);
20
+ };
@@ -0,0 +1,19 @@
1
+ import * as R from 'ramda';
2
+
3
+ export const getObservations = (sdmxJson) => R.pipe(
4
+ R.pathOr({}, ['data', 'dataSets', 0, 'observations']),
5
+ R.mapObjIndexed(
6
+ (observation, observationKey) => {
7
+ const value = R.head(observation);
8
+ const attrValuesIndexes = R.tail(observation);
9
+ const dimValuesIndexes = R.split(':', observationKey);
10
+
11
+ return ({
12
+ key: observationKey,
13
+ value,
14
+ attrValuesIndexes,
15
+ dimValuesIndexes
16
+ });
17
+ },
18
+ )
19
+ )(sdmxJson);
@@ -1,5 +1,4 @@
1
1
  import * as R from 'ramda';
2
- import { getCellValue } from './getCellValue';
3
2
  import { dimensionValueDisplay } from '../../dimension-utils';
4
3
 
5
4
  const getAttrLabel = (display) => (attribute) => `${display(attribute)}: ${display(R.propOr({}, 'value', attribute))}`;
@@ -82,13 +81,10 @@ export const getCells = (data, display, customAttributes, unitsProps) => R.mapOb
82
81
  R.lensProp('flags'),
83
82
  getFlags(
84
83
  customAttributes, dimensionValueDisplay(display), unitsProps
85
- )(R.pick(['attributes', 'units'], observation))
86
- ),
87
- R.set(R.lensProp('intValue'), R.prop('value')(observation)),
88
- R.set(
89
- R.lensProp('value'),
90
- getCellValue(observation)
84
+ )(observation)
91
85
  ),
86
+ R.set(R.lensProp('intValue'), R.prop('value', observation)),
87
+ R.set(R.lensProp('value'), R.prop('formattedValue', observation)),
92
88
  R.assoc('indexedDimValIds', R.prop('indexedDimValIds', observation))
93
89
  )({}),
94
90
  R.propOr({}, 'observations', data)
@@ -1,203 +1,169 @@
1
1
  import * as R from 'ramda';
2
- import { getSortedLayoutData } from './getSortedLayoutData';
3
- import { getCuratedCells } from './getCuratedCells';
4
2
 
5
- const layoutDataToKey = R.pipe(
6
- R.addIndex(R.map)((entry, index) => ({ ...entry, f: R.path([index, 'value', '__index']) })),
7
- R.map(R.prop('f')),
8
- getters => R.converge((...results) => R.join(':', results), getters),
3
+ const indexesToLayoutData = (dimensions, indexes) => R.addIndex(R.map)(
4
+ (valueIndex, dimensionIndex) => {
5
+ const dimension = R.nth(dimensionIndex, dimensions);
6
+ return ({
7
+ dimension: R.pick(['id', 'name', '__index'], dimension),
8
+ value: R.nth(Number(valueIndex), R.propOr([], 'values', dimension))
9
+ });
10
+ },
11
+ indexes
9
12
  );
10
13
 
11
- export const refineSectionsData = (sectionsData, extractedKeys, curatedData, dataToKey) => R.pipe(
12
- R.map(
13
- (section) => {
14
- const sectionKey = dataToKey.sections(R.head(section));
15
- return R.over(
16
- R.lensIndex(1),
17
- R.filter(
18
- rowData => {
19
- const rowKey = dataToKey.rows(rowData);
20
- return R.pipe(
21
- R.path([sectionKey, rowKey]),
22
- R.omit(extractedKeys),
23
- R.isEmpty,
24
- R.not
25
- )(curatedData);
26
- }
27
- )
28
- )(section);
29
- }
30
- ),
31
- R.filter(
32
- R.pipe(R.nth(1), R.isEmpty, R.not)
33
- )
34
- )(sectionsData);
35
-
36
- export const refineHeaderData = (headerData, extractedKeys, curatedData, dataToKey) => R.filter( // extracted : { [sectionKey]: [...rowKeys] }
37
- (header) => {
38
- const headerKey = dataToKey.header(header);
39
- return R.pipe(
40
- R.prop(headerKey),
41
- (sections) => {
42
- return R.pickBy(
43
- (rows, section) => R.pipe(
44
- R.omit(R.propOr([], section, extractedKeys)),
45
- R.isEmpty,
46
- R.not
47
- )(rows),
48
- sections
49
- );
50
- },
51
- R.isEmpty,
52
- R.not
53
- )(curatedData);
54
- }
55
- )(headerData);
56
-
57
- export const truncateSectionRows = (n, sectionsData, dataToKey) => {
58
- const [rest, extracted] = R.pipe(
59
- R.last, // last section
60
- R.nth(1), // rows
61
- R.splitAt(R.negate(n)) // truncate from the end
62
- )(sectionsData);
63
-
64
- const truncatedData = R.isEmpty(rest)
65
- ? R.dropLast(1, sectionsData) // remove section if no more rows
66
- : R.adjust(-1, R.adjust(1, R.always(rest)), sectionsData)
67
-
68
- const sectionKey = dataToKey.sections(R.pipe(R.last, R.head)(sectionsData));
69
- const rowKeys = R.map(dataToKey.rows, extracted);
70
-
71
- const extractedLength = R.length(extracted);
72
- if (extractedLength < n) {
73
- const { truncated, extractedKeys } = truncateSectionRows(
74
- n - extractedLength,
75
- truncatedData,
76
- dataToKey
77
- );
78
- return ({ truncated, extractedKeys: { ...extractedKeys, [sectionKey]: rowKeys } });
79
- }
80
-
81
- return ({ truncated: truncatedData, extractedKeys: { [sectionKey]: rowKeys } });
14
+ const parseParents = (value, previous) => {
15
+ const previousParents = R.pathOr([], ['value', 'parents'], previous);
16
+ const indexedParents = R.indexBy(R.identity, value.parents);
17
+
18
+ const refinedParents = R.reduce(
19
+ (acc, id) => {
20
+ if (R.has(id, indexedParents)) {
21
+ return R.append(id, acc);
22
+ }
23
+ return acc;
24
+ },
25
+ [],
26
+ R.append(R.path(['value', 'id'], previous), previousParents)
27
+ );
28
+ const lastParent = R.last(refinedParents);
29
+ const missingParents = R.takeLastWhile(id => id !== lastParent, value.parents);
30
+
31
+ return ({ parents: refinedParents, missingIds: missingParents });
82
32
  };
83
33
 
84
- export const truncateHeader = (n, headerData, dataToKey) => {
85
- const [truncated, extracted] = R.splitAt(R.negate(n))(headerData);
86
- return ({ truncated, extractedKeys: R.map(dataToKey.header, extracted) });
87
- };
88
-
89
- const refineLength = length => length === 0 ? 1 : length;
90
-
91
- const truncateLayout = (isVertical) => R.ifElse(
92
- R.always(isVertical),
93
- truncateSectionRows,
94
- truncateHeader,
95
- );
96
-
97
- const refineLayout = (isVertical) => R.ifElse(
98
- R.always(isVertical),
99
- refineHeaderData,
100
- refineSectionsData
101
- )
34
+ const getRowData = (indexes, dimension) => {
35
+ return R.pipe(
36
+ R.propOr([], 'values'),
37
+ R.props(indexes),
38
+ R.reduce(
39
+ ({ data, missingParents }, _value) => {
40
+ const raw = {
41
+ dimension: R.pick(['id', 'name', '__index'], dimension),
42
+ value: _value,
43
+ };
44
+ if (R.isNil(_value.parents) || R.isEmpty(_value.parents)) {
45
+ return ({ data: R.append([raw], data), missingParents: {} });
46
+ }
47
+ const previous = R.head(R.last(data) || []);
48
+ if (R.last(_value.parents) === R.path(['value', 'id'], previous)) { //previous is parent
49
+ const value = R.set(
50
+ R.lensPath(['value', 'parents']),
51
+ R.append(
52
+ R.path(['value', 'id'], previous),
53
+ R.pathOr([], ['value', 'parents'], previous)
54
+ )
55
+ )(raw);
56
+ return ({ data: R.append([value], data), missingParents: {} });
57
+ }
58
+
59
+ const previousParent = R.pipe(R.pathOr([], ['value', 'parents']), R.last)(previous);
60
+ if (R.last(_value.parents) === previousParent) { //previous is bro
61
+ const value = R.set(
62
+ R.lensPath(['value']),
63
+ {
64
+ ..._value,
65
+ name: R.isEmpty(missingParents) ? _value.name : `${missingParents.name} > ${_value.name}`,
66
+ parents: R.pathOr([], ['value', 'parents'], previous)
67
+ }
68
+ )(raw);
69
+ return ({ data: R.append([value], data), missingParents });
70
+ }
71
+ const { parents, missingIds } = parseParents(_value, previous);
72
+ const _missingParents = R.reduce(
73
+ (acc, value) => {
74
+ if (value.id !== R.head(acc.missingIds)) {
75
+ return acc;
76
+ }
77
+ const _missingIds = R.tail(acc.missingIds);
78
+ if (R.isEmpty(acc.name)) {
79
+ return ({ name: value.name, missingIds: _missingIds });
80
+ }
81
+ return ({
82
+ name: `${acc.name} > ${value.name}`,
83
+ missingIds: _missingIds
84
+ });
85
+ },
86
+ { name: '', missingIds },
87
+ dimension.values
88
+ );
102
89
 
103
- const getShape = isVertical => isVertical ? ['header', 'sections', 'rows'] : ['sections', 'rows', 'header'];
90
+ const value = R.set(
91
+ R.lensProp('value'),
92
+ {
93
+ ..._value,
94
+ parents,
95
+ name: R.isEmpty(missingIds) ? _value.name : `${_missingParents.name} > ${_value.name}`,
96
+ }
97
+ )(raw);
104
98
 
105
- const getRefinedLayout = (isVertical, truncated, refined) => R.ifElse(
106
- R.always(isVertical),
107
- R.pipe(R.assoc('sectionsData', truncated), R.assoc('headerData', refined)),
108
- R.pipe(R.assoc('headerData', truncated), R.assoc('sectionsData', refined)),
109
- )({});
99
+ return ({ data: R.append([value], data), missingParents: R.isEmpty(missingIds) ? {} : _missingParents });
100
+ },
101
+ { data: [], missingParents: {} }
102
+ ),
103
+ R.prop('data')
104
+ )(dimension);
105
+ };
110
106
 
111
- const segregateLayout = (isVertical) => R.ifElse(
112
- R.always(isVertical),
113
- R.props(['sectionsData', 'headerData']),
114
- R.props(['headerData', 'sectionsData'])
115
- );
107
+ const getRowsData = (rowsIndexes, dimensions) => {
108
+ const dimension = R.head(dimensions);
116
109
 
117
- export const getLayoutData = ({ layout, observations, limit }) => {
118
- const layoutData = getSortedLayoutData(layout, observations);
119
- const { headerData, sectionsData } = layoutData;
120
- if (R.isNil(limit) || limit === 0 || R.all(R.isEmpty, [headerData, sectionsData])) {
121
- return R.assoc('truncated', false, layoutData);
110
+ if (R.length(dimensions) === 1) {
111
+ return getRowData(R.unnest(rowsIndexes), R.head(dimensions));
122
112
  }
123
113
 
124
- //number of dimensions in header
125
- const headerDimCount = R.pipe(
126
- R.head, // first column
127
- R.when(R.isNil, R.always([])),
128
- R.length // number of dims
129
- )(headerData);
130
-
131
- //number of columns for values
132
- const headerValuesCount = R.pipe(
133
- R.length,
134
- R.when(R.equals(0), R.always(1))
135
- )(headerData);
136
-
137
- //total of cells in header
138
- const headerCellsCount = headerDimCount * (headerValuesCount + 1);
139
-
140
- // number of dimensions in a row
141
- const rowDimCount = R.pipe(
142
- R.head, // firstSection
143
- R.last, // rows,
144
- R.head, // first row
145
- R.length
146
- )(sectionsData);
147
-
148
- // number of cells in a row
149
- const rowCellsCount = rowDimCount + headerValuesCount + 1;
150
-
151
- // number of rows
152
- const rowsCount = R.pipe(
153
- R.map(R.last),
154
- R.unnest,
155
- R.length,
156
- R.add(1)
157
- )(sectionsData);
158
-
159
- // total of cells in all rows
160
- const rowsCellsCount = rowCellsCount * rowsCount;
161
-
162
- // number of sections cells
163
- const sectionsCellsCount = R.ifElse(
164
- R.pipe(R.head, R.head, R.length, R.equals(0)),
165
- R.always(0),
166
- R.length
167
- )(sectionsData);
168
-
169
- const total = rowsCellsCount + sectionsCellsCount + headerCellsCount;
170
-
171
- const excess = total - limit;
172
- if (excess <= 0) {
173
- return R.assoc('truncated', false, layoutData);
174
- }
175
-
176
- // total of cells in one column
177
- const columnCellsCount = headerDimCount + rowsCount;
178
-
179
- const isVertical = columnCellsCount > rowCellsCount
180
-
181
- const [toTruncate, toRefine] = segregateLayout(isVertical)(layoutData);
182
-
183
- const cutLength = R.pipe(
184
- R.ifElse(R.identity, R.always(rowCellsCount), R.always(columnCellsCount)),
185
- R.divide(excess),
186
- Math.ceil
187
- )(isVertical);
114
+ const groupedIndexes = R.reduce(
115
+ (acc, indexes) => {
116
+ const headIndex = R.head(indexes);
117
+ const last = R.last(acc.heads);
118
+ if (last === headIndex) {
119
+ return ({
120
+ ...acc,
121
+ tails: R.over(
122
+ R.lensIndex(-1),
123
+ R.append(R.tail(indexes))
124
+ )(acc.tails)
125
+ });
126
+ }
127
+ return ({
128
+ heads: R.append(headIndex, acc.heads),
129
+ tails: R.append([R.tail(indexes)], acc.tails)
130
+ });
131
+ },
132
+ { heads: [], tails: [] },
133
+ rowsIndexes
134
+ );
135
+
136
+ const headsDatas = getRowData(groupedIndexes.heads, R.head(dimensions));
137
+
138
+ const res = R.addIndex(R.map)(
139
+ (tail, i) => {
140
+ const tailData = getRowsData(tail, R.tail(dimensions));
141
+ return R.map(
142
+ R.prepend(R.head(headsDatas[i])),
143
+ tailData
144
+ );
145
+ },
146
+ groupedIndexes.tails
147
+ );
148
+
149
+ return R.unnest(res);
150
+ };
188
151
 
189
- const dataToKey = R.mapObjIndexed(layoutDataToKey, layout);
152
+ export const getLayoutData = (layoutIndexes, layout) => {
153
+ const { header, sections, truncated } = layoutIndexes;
154
+ const headerData = R.map(i => indexesToLayoutData(layout.header, i), header);
190
155
 
191
- const { truncated, extractedKeys } = truncateLayout(isVertical)(cutLength, toTruncate, dataToKey);
156
+ const sectionsData = R.map(
157
+ ([sectionIndexes, rows]) => {
158
+ const sectionData = indexesToLayoutData(layout.sections, sectionIndexes);
192
159
 
193
- const curatedData = R.pipe(
194
- getShape,
195
- (shape) => getCuratedCells({ layout, observations, shape })
196
- )(isVertical);
197
160
 
198
- const refined = refineLayout(isVertical)(toRefine, extractedKeys, curatedData, dataToKey);
161
+ const rowsData = getRowsData(rows, layout.rows);
199
162
 
200
- const result = getRefinedLayout(isVertical, truncated, refined);
163
+ return [sectionData, rowsData];
164
+ },
165
+ sections
166
+ );
201
167
 
202
- return R.assoc('truncated', true, result);
168
+ return ({ headerData, sectionsData, truncated });
203
169
  };
@@ -0,0 +1,108 @@
1
+ import * as R from 'ramda';
2
+
3
+ /*
4
+
5
+ const layout = {
6
+ header: [
7
+ { ...dim, values: [] } // values already sorted regarding order annotation
8
+ ],
9
+ rows: [],
10
+ sections: []
11
+ };
12
+
13
+ const observations = {
14
+ [obsKey]: {
15
+ ...obs,
16
+ orderedDimIndexes: [sortedValIndex]
17
+ }
18
+ }
19
+
20
+ */
21
+
22
+ const getLayoutPivots = layout => {
23
+ return R.mapObjIndexed(
24
+ dimensions => R.props(R.pluck('__index', dimensions)),
25
+ )(layout);
26
+ };
27
+
28
+ const comparator = size => (a, b) => {
29
+ let i = 0;
30
+ while (a[i] === b[i] && i < size) {
31
+ i++;
32
+ }
33
+ return a[i] - b[i];
34
+ };
35
+
36
+ // simple call to ramda uniq method is very slow regarding performance
37
+ const uniqIndexes = (indexes) => R.pipe(
38
+ R.reduce(
39
+ (acc, i) => {
40
+ const key = R.join(':', i);
41
+ if (R.has(key, acc.keys)) {
42
+ return acc;
43
+ }
44
+ return ({
45
+ indexes: R.append(i, acc.indexes),
46
+ keys: R.assoc(key, key, acc.keys)
47
+ });
48
+ },
49
+ { indexes: [], keys: {} },
50
+ ),
51
+ R.prop('indexes')
52
+ )(indexes);
53
+
54
+ export const getSortedLayoutIndexes = (layout, observations) => {
55
+ const dimIndexes = R.pipe(R.values, R.pluck('orderedDimIndexes'))(observations);
56
+
57
+ const headerLength = R.length(layout.header);
58
+
59
+ const sectionLength = R.length(layout.sections);
60
+ const rowLength = R.length(layout.rows);
61
+
62
+ const layoutPivots = getLayoutPivots(layout);
63
+
64
+ const { header, sections } = R.pipe(
65
+ R.reduce(
66
+ (acc, indexes) => {
67
+ const headerIndexes = layoutPivots.header(indexes);
68
+ const sectionsIndexes = layoutPivots.sections(indexes);
69
+ const rowsIndexes = layoutPivots.rows(indexes);
70
+
71
+ return ({
72
+ header: R.append(headerIndexes, acc.header),
73
+ sections: R.append(
74
+ R.concat(sectionsIndexes, rowsIndexes),
75
+ acc.sections
76
+ )
77
+ });
78
+ },
79
+ { header: [], sections: [] },
80
+ ),
81
+ R.mapObjIndexed(uniqIndexes),
82
+ R.evolve({
83
+ header: R.sort(comparator(headerLength)),
84
+ sections: R.sort(comparator(sectionLength + rowLength))
85
+ }),
86
+ indexes => ({
87
+ ...indexes,
88
+ sections: R.reduce(
89
+ (acc, i) => {
90
+ const [sectionIndexes, rowIndexes] = R.splitAt(sectionLength, i);
91
+ const previousSecIndexes = R.pipe(R.nth(-1), i => R.isNil(i) ? null : R.head(i))(acc);
92
+ if (R.equals(sectionIndexes, previousSecIndexes)) {
93
+ return R.over(
94
+ R.lensIndex(-1),
95
+ R.over(R.lensIndex(1), R.append(rowIndexes))
96
+ )(acc);
97
+ }
98
+
99
+ return R.append([sectionIndexes, [rowIndexes]], acc);
100
+ },
101
+ [],
102
+ indexes.sections
103
+ )
104
+ })
105
+ )(dimIndexes);
106
+
107
+ return ({ header, sections });
108
+ };
@@ -3,15 +3,17 @@ import { withFlatHierarchy, isTimePeriodDimension } from '@sis-cc/dotstatsuite-s
3
3
  import { getCells } from './getCells';
4
4
  import { getConfirmedSeriesAttributesIds } from './getConfirmedSeriesAttributesIds';
5
5
  import { getCuratedCells } from './getCuratedCells';
6
- import { getLayoutData } from './getLayoutData';
7
6
  import { getLayoutDataWithFlags } from './getLayoutWithFlags';
8
- import { refineLayoutHierarchy } from './refineLayoutHierarchy';
9
7
 
10
8
  import { getUnitsInLayout } from '../units/getUnitsinLayout';
11
9
  import { appendUnitsInLayoutData } from '../units/appendUnitsInLayoutData';
12
10
  import { cleanUnitsInLayoutData } from '../units/cleanUnitsInLayoutData';
13
11
 
14
12
 
13
+ import { getSortedLayoutIndexes } from './getSortedLayoutIndexes';
14
+ import { refineLayoutSize } from './refineLayoutSize';
15
+ import { getLayoutData } from './getLayoutData';
16
+
15
17
  export const getTableProps = ({ data, layoutIds, display, customAttributes, limit, isTimeInverted }) => {
16
18
  const seriesAttributes = R.propOr({}, 'seriesAttributes', data);
17
19
 
@@ -59,8 +61,8 @@ export const getTableProps = ({ data, layoutIds, display, customAttributes, limi
59
61
  R.lensProp('values'),
60
62
  R.sortWith([R.ascend(R.prop('__indexPosition')), R.ascend(R.prop('order'))]),
61
63
  )(dim),
62
- R.when( // refine hierarchy on last row
63
- R.pipe(R.prop('id'), R.equals(R.last(R.propOr([], 'rows', layoutIds)))),
64
+ R.when( // refine hierarchy on rows
65
+ R.pipe(R.prop('id'), R.flip(R.includes)(R.propOr([], 'rows', layoutIds))),
64
66
  withFlatHierarchy
65
67
  )
66
68
  ),
@@ -79,11 +81,9 @@ export const getTableProps = ({ data, layoutIds, display, customAttributes, limi
79
81
  )(data);
80
82
 
81
83
  const layoutData = R.pipe(
82
- getLayoutData,
83
- R.over(
84
- R.lensProp('sectionsData'),
85
- sectionsData => refineLayoutHierarchy(sectionsData, R.last(R.prop('rows', layout)))
86
- ),
84
+ getSortedLayoutIndexes,
85
+ refineLayoutSize({ layout, observations: data.observations, limit: R.when(R.isNil, R.always(0))(limit) }),
86
+ indexes => getLayoutData(indexes, layout),
87
87
  appendUnitsInLayoutData({
88
88
  display, unitDimension, unitsDisplay: unitsLevelDisplay, unitsSeries,
89
89
  unitsDefinitionCodes, unitsIndexes: unitsAttachmentIndexesInLayout,
@@ -91,7 +91,7 @@ export const getTableProps = ({ data, layoutIds, display, customAttributes, limi
91
91
  }),
92
92
  getLayoutDataWithFlags(seriesAttributesValues, display, customAttributes),
93
93
  cleanUnitsInLayoutData({ unitsDisplay: unitsLevelDisplay, unitsLayoutIndexes: unitsIndexesInLayout })
94
- )({ layout, observations: cells, limit: R.when(R.isNil, R.always(0))(limit) });
94
+ )(layout, R.propOr({}, 'observations', data));
95
95
  return ({
96
96
  cells: getCuratedCells({ layout, observations: cells, shape: ['header', 'sections', 'rows'] }),
97
97
  layout,